Skip to content

Commit 701d5d0

Browse files
committed
Fix message ordering race condition by creating assistant messages on first chunk #2
The previous design created two database records within milliseconds, causing ActionCable to sometimes deliver them out of order. Now we only create the assistant message when actual content arrives from the API.
1 parent b66f8d5 commit 701d5d0

File tree

2 files changed

+23
-13
lines changed

2 files changed

+23
-13
lines changed

lib/ruby_llm/chat.rb

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -93,18 +93,19 @@ def each(&)
9393
end
9494

9595
def complete(&)
96-
@on[:new_message]&.call
9796
response = @provider.complete(
9897
messages,
9998
tools: @tools,
10099
temperature: @temperature,
101100
model: @model.id,
102101
connection: @connection,
103-
&
102+
&wrap_streaming_block(&)
104103
)
105-
@on[:end_message]&.call(response)
106104

105+
@on[:new_message]&.call unless block_given?
107106
add_message response
107+
@on[:end_message]&.call(response)
108+
108109
if response.tool_call?
109110
handle_tool_calls(response, &)
110111
else
@@ -124,11 +125,28 @@ def reset_messages!
124125

125126
private
126127

128+
def wrap_streaming_block(&block)
129+
return nil unless block_given?
130+
131+
first_chunk_received = false
132+
133+
proc do |chunk|
134+
# Create message on first content chunk
135+
unless first_chunk_received
136+
first_chunk_received = true
137+
@on[:new_message]&.call
138+
end
139+
140+
# Pass chunk to user's block
141+
block.call chunk
142+
end
143+
end
144+
127145
def handle_tool_calls(response, &)
128146
response.tool_calls.each_value do |tool_call|
129147
@on[:new_message]&.call
130148
result = execute_tool tool_call
131-
message = add_tool_result tool_call.id, result
149+
message = add_message role: :tool, content: result.to_s, tool_call_id: tool_call.id
132150
@on[:end_message]&.call(message)
133151
end
134152

@@ -140,13 +158,5 @@ def execute_tool(tool_call)
140158
args = tool_call.arguments
141159
tool.call(args)
142160
end
143-
144-
def add_tool_result(tool_use_id, result)
145-
add_message(
146-
role: :tool,
147-
content: result.is_a?(Hash) && result[:error] ? result[:error] : result.to_s,
148-
tool_call_id: tool_use_id
149-
)
150-
end
151161
end
152162
end

lib/ruby_llm/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module RubyLLM
4-
VERSION = '1.3.2'
4+
VERSION = '1.3.2beta1'
55
end

0 commit comments

Comments
 (0)