@@ -9,7 +9,6 @@ use fig_api_client::model::{
99use tracing:: {
1010 error,
1111 trace,
12- warn,
1312} ;
1413
1514use super :: tools:: serde_value_to_document;
@@ -57,6 +56,9 @@ pub struct ResponseParser {
5756 buffered_line : Option < String > ,
5857 /// Short circuit and return early since we simply need to clear our buffered line
5958 short_circuit : bool ,
59+ /// Whether or not we are currently receiving tool use delta events. Tuple of
60+ /// `Some((tool_use_id, name))` if true, [None] otherwise.
61+ parsing_tool_use : Option < ( String , String ) > ,
6062}
6163
6264impl ResponseParser {
@@ -69,6 +71,7 @@ impl ResponseParser {
6971 tool_uses : Vec :: new ( ) ,
7072 buffered_line : None ,
7173 short_circuit : false ,
74+ parsing_tool_use : None ,
7275 }
7376 }
7477
@@ -87,6 +90,12 @@ impl ResponseParser {
8790 return Ok ( ResponseEvent :: EndStream { message } ) ;
8891 }
8992
93+ if let Some ( ( id, name) ) = self . parsing_tool_use . take ( ) {
94+ let tool_use = self . parse_tool_use ( id, name) . await ?;
95+ self . tool_uses . push ( tool_use. clone ( ) ) ;
96+ return Ok ( ResponseEvent :: ToolUse ( tool_use) ) ;
97+ }
98+
9099 loop {
91100 match self . next ( ) . await {
92101 Ok ( Some ( output) ) => match output {
@@ -121,9 +130,13 @@ impl ResponseParser {
121130 input,
122131 stop,
123132 } => {
124- let tool_use = self . parse_tool_use ( tool_use_id, name, input, stop) . await ?;
125- self . tool_uses . push ( tool_use. clone ( ) ) ;
126- return Ok ( ResponseEvent :: ToolUse ( tool_use) ) ;
133+ debug_assert ! ( input. is_none( ) , "Unexpected initial content in first tool use event" ) ;
134+ debug_assert ! (
135+ stop. is_none_or( |v| !v) ,
136+ "Unexpected immediate stop in first tool use event"
137+ ) ;
138+ self . parsing_tool_use = Some ( ( tool_use_id. clone ( ) , name. clone ( ) ) ) ;
139+ return Ok ( ResponseEvent :: ToolUseStart { name } ) ;
127140 } ,
128141 _ => { } ,
129142 } ,
@@ -152,18 +165,8 @@ impl ResponseParser {
152165 /// Consumes the response stream until a valid [ToolUse] is parsed.
153166 ///
154167 /// The arguments are the fields from the first [ChatResponseStream::ToolUseEvent] consumed.
155- async fn parse_tool_use (
156- & mut self ,
157- tool_use_id : String ,
158- tool_name : String ,
159- input : Option < String > ,
160- stop : Option < bool > ,
161- ) -> Result < ToolUse > {
162- if input. is_some ( ) {
163- warn ! ( ?input, "Unexpected initial content in input" ) ;
164- }
165- assert ! ( stop. is_none_or( |v| !v) ) ;
166- let mut tool_string = input. unwrap_or_default ( ) ;
168+ async fn parse_tool_use ( & mut self , id : String , name : String ) -> Result < ToolUse > {
169+ let mut tool_string = String :: new ( ) ;
167170 while let Some ( ChatResponseStream :: ToolUseEvent { .. } ) = self . peek ( ) . await ? {
168171 if let Some ( ChatResponseStream :: ToolUseEvent { input, stop, .. } ) = self . next ( ) . await ? {
169172 if let Some ( i) = input {
@@ -175,11 +178,7 @@ impl ResponseParser {
175178 }
176179 }
177180 let args = serde_json:: from_str ( & tool_string) ?;
178- Ok ( ToolUse {
179- id : tool_use_id,
180- name : tool_name,
181- args,
182- } )
181+ Ok ( ToolUse { id, name, args } )
183182 }
184183
185184 /// Returns the next event in the [SendMessageOutput] without consuming it.
@@ -214,6 +213,8 @@ pub enum ResponseEvent {
214213 ConversationId ( String ) ,
215214 /// Text returned by the assistant. This should be displayed to the user as it is received.
216215 AssistantText ( String ) ,
216+ /// Notification that a tool use is being received.
217+ ToolUseStart { name : String } ,
217218 /// A tool use requested by the assistant. This should be displayed to the user as it is
218219 /// received.
219220 ToolUse ( ToolUse ) ,
0 commit comments