@@ -6,12 +6,10 @@ class StreamAccumulator
66 attr_reader :content , :model_id , :tool_calls
77
88 def initialize
9- @content = + ''
9+ @content = nil
1010 @tool_calls = { }
1111 @input_tokens = 0
1212 @output_tokens = 0
13- @cached_tokens = 0
14- @cache_creation_tokens = 0
1513 @latest_tool_call_id = nil
1614 end
1715
@@ -22,7 +20,7 @@ def add(chunk)
2220 if chunk . tool_call?
2321 accumulate_tool_calls chunk . tool_calls
2422 else
25- @content << ( chunk . content || '' )
23+ accumulate_content ( chunk . content )
2624 end
2725
2826 count_tokens chunk
@@ -32,19 +30,64 @@ def add(chunk)
3230 def to_message ( response )
3331 Message . new (
3432 role : :assistant ,
35- content : content . empty? ? nil : content ,
33+ content : final_content ,
3634 model_id : model_id ,
3735 tool_calls : tool_calls_from_stream ,
3836 input_tokens : @input_tokens . positive? ? @input_tokens : nil ,
3937 output_tokens : @output_tokens . positive? ? @output_tokens : nil ,
40- cached_tokens : @cached_tokens . positive? ? @cached_tokens : nil ,
41- cache_creation_tokens : @cache_creation_tokens . positive? ? @cache_creation_tokens : nil ,
4238 raw : response
4339 )
4440 end
4541
4642 private
4743
44+ def accumulate_content ( new_content )
45+ return unless new_content
46+
47+ if @content . nil?
48+ @content = new_content . is_a? ( String ) ? +new_content : new_content
49+ else
50+ case [ @content . class , new_content . class ]
51+ when [ String , String ]
52+ @content << new_content
53+ when [ String , Content ]
54+ # Convert accumulated string to Content and merge
55+ @content = Content . new ( @content )
56+ merge_content ( new_content )
57+ when [ Content , String ]
58+ # Append string to existing Content's text
59+ @content . instance_variable_set ( :@text , ( @content . text || '' ) + new_content )
60+ when [ Content , Content ]
61+ merge_content ( new_content )
62+ end
63+ end
64+ end
65+
66+ def merge_content ( new_content )
67+ # Merge text
68+ current_text = @content . text || ''
69+ new_text = new_content . text || ''
70+ @content . instance_variable_set ( :@text , current_text + new_text )
71+
72+ # Merge attachments
73+ new_content . attachments . each do |attachment |
74+ @content . attach ( attachment )
75+ end
76+ end
77+
78+ def final_content
79+ case @content
80+ when nil
81+ nil
82+ when String
83+ @content . empty? ? nil : @content
84+ when Content
85+ @content . text . nil? && @content . attachments . empty? ? nil : @content
86+ else
87+ @content
88+ end
89+ end
90+
4891 def tool_calls_from_stream
4992 tool_calls . transform_values do |tc |
5093 arguments = if tc . arguments . is_a? ( String ) && !tc . arguments . empty?
@@ -94,8 +137,6 @@ def find_tool_call(tool_call_id)
94137 def count_tokens ( chunk )
95138 @input_tokens = chunk . input_tokens if chunk . input_tokens
96139 @output_tokens = chunk . output_tokens if chunk . output_tokens
97- @cached_tokens = chunk . cached_tokens if chunk . cached_tokens
98- @cache_creation_tokens = chunk . cache_creation_tokens if chunk . cache_creation_tokens
99140 end
100141 end
101142end
0 commit comments