-
Notifications
You must be signed in to change notification settings - Fork 13
Description
I noticed that Runner#restore_conversation_history only restores user and assistant messages, but completely ignores tool messages. I'm trying to understand if this is an intentional design decision or a potential bug.
Current Behavior
When a conversation is saved and then restored (for continuation across sessions or process boundaries), the system:
- ✅ Saves all message types including tool messages via
MessageExtractor.extract_messages(message_extractor.rb:43-54) - ❌ Restores only user and assistant messages, skipping tool messages (runner.rb:273-276)
Code Reference
Saving (includes tool messages):
# lib/agents/helpers/message_extractor.rb
def extract_messages(chat, current_agent)
chat.messages.filter_map do |msg|
case msg.role
when :user, :assistant
extract_user_or_assistant_message(msg, current_agent)
when :tool
extract_tool_message(msg) # ✅ Tool messages ARE saved
end
end
endRestoring (skips tool messages):
# lib/agents/runner.rb:270-288
def restore_conversation_history(chat, context_wrapper)
history = context_wrapper.context[:conversation_history] || []
history.each do |msg|
# Only restore user and assistant messages with content
next unless %i[user assistant].include?(msg[:role].to_sym) # ⚠️ Tool messages skipped
next unless msg[:content] && !Helpers::MessageExtractor.content_empty?(msg[:content])
content = RubyLLM::Content.new(msg[:content])
message = RubyLLM::Message.new(role: msg[:role].to_sym, content: content)
chat.add_message(message)
end
endExample Scenario
# Turn 1: User asks for account information
runner = Agents::Runner.with_agents(support_agent)
result1 = runner.run("What's my account balance?")
# Agent calls lookup_account_tool, gets balance: $500
# Conversation history saved:
# - user: "What's my account balance?"
# - assistant: [tool_calls: lookup_account]
# - tool: {result: "Balance: $500"}
# - assistant: "Your balance is $500"
# Turn 2: Continue conversation in new process/session
result2 = runner.run("Can I afford a $400 purchase?", context: result1.context)
# Conversation history restored:
# - user: "What's my account balance?"
# - assistant: "Your balance is $500"
# ⚠️ Tool call and tool result messages NOT restored!
# Potential issue: LLM has no memory that it looked up the balance via a tool.
# It only sees it said "$500" but doesn't know how it got that information.Potential Impacts
If this is unintentional, it could lead to:
- Repeated tool calls: LLM doesn't "remember" it already fetched data, may call the same tool again
- Lost context: LLM loses the reasoning chain of how it obtained information
- Inconsistent behavior: First conversation turn has full context, subsequent turns don't
- Wasted resources: Redundant API calls and tool executions
Questions for Maintainers
-
Is this intentional? Are there specific reasons why tool messages should not be restored?
- Performance considerations?
- RubyLLM compatibility constraints?
- Context window management?
-
If intentional, what's the recommended pattern for maintaining tool execution context across conversation turns?
-
If unintentional, I'm happy to submit a PR to restore tool messages along with the necessary tests.
Environment
- Gem Version: 0.7.0
- RubyLLM Version: ~> 1.8.2
- Ruby Version: 3.1+
Additional Context
This asymmetry (saving tool messages but not restoring them) suggests it might be unintentional, but I wanted to check before assuming it's a bug. The SDK's emphasis on "Shared Context: Maintaining state and conversation history across agent interactions with full persistence support" made me think complete message history restoration would be expected.
Thank you for clarifying!