Skip to content

Conversation

kieranklaassen
Copy link
Contributor

@kieranklaassen kieranklaassen commented Mar 31, 2025

I had this issue in Rails:

Loading development environment (Rails 7.2.2.1)
cora-app(dev)> Chat.last.class
  Chat Load (1.2ms)  SELECT "chats".* FROM "chats" ORDER BY "chats"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> Chat(id: integer, model_id: string, account_id: integer, created_at: datetime, updated_at: datetime)
cora-app(dev)> Chat.last.with_tools(StoreMemory).class
  Chat Load (0.8ms)  SELECT "chats".* FROM "chats" ORDER BY "chats"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Message Load (1.0ms)  SELECT "messages".* FROM "messages" WHERE "messages"."chat_id" = $1 ORDER BY "messages"."created_at" ASC  [["chat_id", 17]]
  ToolCall Load (0.7ms)  SELECT "tool_calls".* FROM "tool_calls" WHERE "tool_calls"."message_id" = $1

with_tools does not return the proper class so the messages are not created.

The issue was that  and  methods were returning
the RubyLLM::Chat instance instead of the ActiveRecord model, which
broke the persistence chain when calling .ask() after .with_tools().

This fix:
1. Overrides the with_tool and with_tools methods to return self (the ActiveRecord model)
2. Removes these methods from the delegation list
3. Adds test to verify user messages are persisted when using method chains

Fixes issue where user messages weren't being saved to the database
when using the  method chain.
Extended the fix to apply to all chainable methods:
- with_model
- with_temperature
- on_new_message
- on_end_message

These methods now return the ActiveRecord model instead of the RubyLLM::Chat
instance, ensuring method chains maintain persistence capabilities.

Added comprehensive test case that verifies all chainable methods return
the correct type and properly persist user messages when used in chains.
Refactored the acts_as_chat and acts_as_message methods to improve readability by removing unnecessary comments and ensuring consistent formatting. Updated the on_new_message and on_end_message methods to use shorthand block syntax for better clarity.

Additionally, introduced shared examples in tests to validate chainable methods and callbacks, ensuring they return the correct Chat instance. This enhances the maintainability of the code and improves test coverage for method chaining scenarios.
@kieranklaassen kieranklaassen changed the title fix acts as fix acts_as delegation to return self instead of RubyLLM Mar 31, 2025
@crmne
Copy link
Owner

crmne commented Apr 1, 2025

Hey @kieranklaassen when are the messages not created?

@kieranklaassen
Copy link
Contributor Author

When you do this it won't create user messages:

chat = Chat.first
chat.with_tools(StoreMemory).ask(message) do |chunk|

end

You can see that because the class that with_tools return is a RubyLLM::Chat and not a Chat from active record.

Copy link
Owner

@crmne crmne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can accept it if you can keep the original test as well!

Comment on lines 73 to 82
it 'persists chat history' do # rubocop:disable RSpec/ExampleLength,RSpec/MultipleExpectations
chat = Chat.create!(model_id: 'gpt-4o-mini')
chat.ask("What's your favorite Ruby feature?")

expect(chat.messages.count).to eq(2)
expect(chat.messages.first.role).to eq('user')
expect(chat.messages.last.role).to eq('assistant')
expect(chat.messages.last.content).to be_present
expect(chat.messages.last.input_tokens).to be_positive
expect(chat.messages.last.output_tokens).to be_positive
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why removing this very important test?

Copy link
Contributor Author

@kieranklaassen kieranklaassen Apr 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, adding that back was a mistake. I was moving quickly yesterday.

kieranklaassen and others added 2 commits April 1, 2025 07:40
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@kieranklaassen
Copy link
Contributor Author

@crmne looked it over and should be good to go now. TY

@kieranklaassen kieranklaassen requested a review from crmne April 1, 2025 14:43
Copy link
Owner

@crmne crmne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kieranklaassen
Copy link
Contributor Author

@crmne would you mind guiding me in the failing tests on CI? Locally all pass

@crmne
Copy link
Owner

crmne commented Apr 1, 2025

@kieranklaassen the error message there tells you all you need to know: there are some VCR cassettes missing. I tried it locally and that was the case.

kieranklaassen and others added 2 commits April 1, 2025 12:36
…th tool functionality

Added new VCR cassettes to persist messages and tool calls for ActiveRecord acts_as chainable methods. These cassettes capture interactions with the OpenAI API for arithmetic operations, ensuring accurate testing of user message persistence and tool functionality.

- Created `activerecord_actsas_chainable_methods_persists_messages_after_chaining.yml`
- Created `activerecord_actsas_with_tools_functionality_persists_user_messages.yml`

This addition enhances the test coverage for the integration of tools within the ActiveRecord methods.
@kieranklaassen
Copy link
Contributor Author

@crmne I deleted and added VCR cassettes again. How do I run the CI here?

Copy link

codecov bot commented Apr 2, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 92.27%. Comparing base (81e8d55) to head (07aefd4).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #82      +/-   ##
==========================================
+ Coverage   92.11%   92.27%   +0.15%     
==========================================
  Files          71       71              
  Lines        2588     2640      +52     
  Branches      378      380       +2     
==========================================
+ Hits         2384     2436      +52     
  Misses        204      204              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@crmne crmne merged commit da64c9a into crmne:main Apr 2, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants