fix(agent): surface FC/tool errors as observations to continue ReAct loop
- Streaming path: on tool_call execution error, emit an [Observation] chunk so the model sees the failure and can retry/adapt - Non-streaming path: inject error as a user message so the loop continues with error context, not silently stop
This commit is contained in:
parent
94825316dc
commit
d89d02e81b
@ -5,7 +5,9 @@ use async_openai::Client;
|
|||||||
use async_openai::types::chat::{
|
use async_openai::types::chat::{
|
||||||
ChatCompletionMessageToolCalls, ChatCompletionRequestAssistantMessage,
|
ChatCompletionMessageToolCalls, ChatCompletionRequestAssistantMessage,
|
||||||
ChatCompletionRequestAssistantMessageContent, ChatCompletionRequestMessage,
|
ChatCompletionRequestAssistantMessageContent, ChatCompletionRequestMessage,
|
||||||
ChatCompletionRequestSystemMessage, ChatCompletionRequestUserMessage, ChatCompletionTool,
|
ChatCompletionRequestSystemMessage, ChatCompletionRequestToolMessage,
|
||||||
|
ChatCompletionRequestToolMessageContent, ChatCompletionRequestUserMessage,
|
||||||
|
ChatCompletionRequestUserMessageContent, ChatCompletionTool,
|
||||||
ChatCompletionTools, CreateChatCompletionRequest, CreateChatCompletionResponse,
|
ChatCompletionTools, CreateChatCompletionRequest, CreateChatCompletionResponse,
|
||||||
CreateChatCompletionStreamResponse, FinishReason, ReasoningEffort, ToolChoiceOptions,
|
CreateChatCompletionStreamResponse, FinishReason, ReasoningEffort, ToolChoiceOptions,
|
||||||
};
|
};
|
||||||
@ -193,7 +195,24 @@ impl ChatService {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if !calls.is_empty() {
|
if !calls.is_empty() {
|
||||||
let tool_messages = self.execute_tool_calls(calls, &request).await?;
|
let tool_messages = match self.execute_tool_calls(calls, &request).await {
|
||||||
|
Ok(msgs) => msgs,
|
||||||
|
Err(e) => {
|
||||||
|
// Surface the error as a tool result so the model can continue
|
||||||
|
let err_text = format!("[Tool call failed: {}]", e);
|
||||||
|
messages.push(ChatCompletionRequestMessage::User(
|
||||||
|
ChatCompletionRequestUserMessage {
|
||||||
|
content: ChatCompletionRequestUserMessageContent::Text(err_text.clone()),
|
||||||
|
name: None,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
tool_depth += 1;
|
||||||
|
if tool_depth >= max_tool_depth {
|
||||||
|
return Ok(err_text);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
messages.extend(tool_messages);
|
messages.extend(tool_messages);
|
||||||
|
|
||||||
tool_depth += 1;
|
tool_depth += 1;
|
||||||
@ -387,7 +406,25 @@ impl ChatService {
|
|||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
let tool_messages = self.execute_tool_calls(tool_calls, &request).await?;
|
let tool_messages = match self.execute_tool_calls(tool_calls, &request).await {
|
||||||
|
Ok(msgs) => msgs,
|
||||||
|
Err(e) => {
|
||||||
|
// Stream the FC error as an observation so the user sees it
|
||||||
|
let err_text = format!("[Tool call failed: {}]", e);
|
||||||
|
on_chunk(AiStreamChunk {
|
||||||
|
content: err_text.clone(),
|
||||||
|
done: true,
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
// Return an empty tool result so the loop can continue
|
||||||
|
vec![ChatCompletionRequestMessage::Tool(
|
||||||
|
ChatCompletionRequestToolMessage {
|
||||||
|
tool_call_id: String::new(),
|
||||||
|
content: ChatCompletionRequestToolMessageContent::Text(err_text),
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
};
|
||||||
messages.extend(tool_messages);
|
messages.extend(tool_messages);
|
||||||
|
|
||||||
tool_depth += 1;
|
tool_depth += 1;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user