Skip to content

Commit 2e30ed7

Browse files
committed
Add Chat#on_tool_call callback
This is useful when you want to show to the user tool calls as they are made, particularly when handling streamed output.
1 parent cccefcd commit 2e30ed7

File tree

3 files changed

+236
-1
lines changed

3 files changed

+236
-1
lines changed

lib/ruby_llm/chat.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ def initialize(model: nil, provider: nil, assume_model_exists: false, context: n
2929
@schema = nil
3030
@on = {
3131
new_message: nil,
32-
end_message: nil
32+
end_message: nil,
33+
tool_call: nil
3334
}
3435
end
3536

@@ -112,6 +113,11 @@ def on_end_message(&block)
112113
self
113114
end
114115

116+
def on_tool_call(&block)
117+
@on[:tool_call] = block
118+
self
119+
end
120+
115121
def each(&)
116122
messages.each(&)
117123
end
@@ -181,6 +187,7 @@ def wrap_streaming_block(&block)
181187
def handle_tool_calls(response, &)
182188
response.tool_calls.each_value do |tool_call|
183189
@on[:new_message]&.call
190+
@on[:tool_call]&.call(tool_call)
184191
result = execute_tool tool_call
185192
message = add_message role: :tool, content: result.to_s, tool_call_id: tool_call.id
186193
@on[:end_message]&.call(message)

spec/fixtures/vcr_cassettes/chat_tool_call_callbacks_calls_on_tool_call_callback_when_tools_are_used.yml

Lines changed: 209 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

spec/ruby_llm/chat_tools_spec.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,25 @@ def execute
172172
end
173173
end
174174

175+
describe 'tool call callbacks' do
176+
it 'calls on_tool_call callback when tools are used' do # rubocop:disable RSpec/ExampleLength,RSpec/MultipleExpectations
177+
tool_calls_received = []
178+
179+
chat = RubyLLM.chat
180+
.with_tool(Weather)
181+
.on_tool_call { |tool_call| tool_calls_received << tool_call }
182+
183+
response = chat.ask("What's the weather in Berlin? (52.5200, 13.4050)")
184+
185+
expect(tool_calls_received).not_to be_empty
186+
expect(tool_calls_received.first).to respond_to(:name)
187+
expect(tool_calls_received.first).to respond_to(:arguments)
188+
expect(tool_calls_received.first.name).to eq('weather')
189+
expect(response.content).to include('15')
190+
expect(response.content).to include('10')
191+
end
192+
end
193+
175194
describe 'error handling' do
176195
it 'raises an error when tool execution fails' do # rubocop:disable RSpec/MultipleExpectations
177196
chat = RubyLLM.chat.with_tool(BrokenTool)

0 commit comments

Comments
 (0)