Skip to content

Commit df5db3d

Browse files
committed
fix messages
1 parent 80907ca commit df5db3d

1 file changed

Lines changed: 67 additions & 13 deletions

File tree

core/src/agent/core.rs

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ impl AgentCore {
323323
if response.message.has_tool_use() {
324324
let tool_uses = response.message.get_tool_uses();
325325

326-
for tool_use in tool_uses {
326+
for tool_use in &tool_uses {
327327
if let crate::llm::ContentBlock::ToolUse { id, name, input } = tool_use {
328328
// Display tool execution based on output mode
329329
let tool_call = crate::tools::ToolCall {
@@ -730,6 +730,53 @@ impl AgentCore {
730730
.push(LlmMessage::system(self.get_system_prompt(project_path)));
731731
}
732732

733+
// Check if the last message was an assistant message with tool calls
734+
// If so, we need to ensure there's a corresponding tool result
735+
let needs_synthetic_results = if let Some(last_msg) = self.conversation_history.last() {
736+
matches!(last_msg.role, crate::llm::MessageRole::Assistant) && last_msg.has_tool_use()
737+
} else {
738+
false
739+
};
740+
741+
if needs_synthetic_results {
742+
// Clone the last message to avoid borrow issues
743+
let last_msg = self.conversation_history.last().unwrap().clone();
744+
745+
// The last assistant message has tool calls without results
746+
// This can happen if the previous task was interrupted or failed
747+
// Add a synthetic error result to maintain conversation validity
748+
let tool_uses = last_msg.get_tool_uses();
749+
let mut error_results = Vec::new();
750+
751+
for tool_use in &tool_uses {
752+
if let crate::llm::ContentBlock::ToolUse { id, .. } = tool_use {
753+
let error_result = LlmMessage {
754+
role: crate::llm::MessageRole::Tool,
755+
content: crate::llm::MessageContent::MultiModal(vec![
756+
crate::llm::ContentBlock::ToolResult {
757+
tool_use_id: id.clone(),
758+
is_error: Some(true),
759+
content: "Previous task interrupted or incomplete".to_string(),
760+
},
761+
]),
762+
metadata: None,
763+
};
764+
error_results.push(error_result);
765+
}
766+
}
767+
768+
// Now add all error results to the conversation history
769+
for error_result in error_results {
770+
self.conversation_history.push(error_result);
771+
}
772+
773+
if !tool_uses.is_empty() {
774+
tracing::warn!(
775+
"Added synthetic tool results for incomplete tool calls from previous task"
776+
);
777+
}
778+
}
779+
733780
// Add user message with task
734781
let user_message = build_user_message(task);
735782
self.conversation_history
@@ -1068,16 +1115,19 @@ mod tests {
10681115
_options: Option<ChatOptions>,
10691116
) -> Result<LlmResponse> {
10701117
// Check if this is a continuation after tool result
1071-
let has_tool_result = messages.iter().any(|msg| {
1072-
matches!(msg.role, crate::llm::MessageRole::Tool)
1073-
});
1118+
let has_tool_result = messages
1119+
.iter()
1120+
.any(|msg| matches!(msg.role, crate::llm::MessageRole::Tool));
10741121

10751122
// If we have a tool result, return a simple text response
10761123
if has_tool_result {
10771124
Ok(LlmResponse {
10781125
message: LlmMessage {
10791126
role: MessageRole::Assistant,
1080-
content: MessageContent::Text("Understood, the tool execution failed but I can continue.".to_string()),
1127+
content: MessageContent::Text(
1128+
"Understood, the tool execution failed but I can continue."
1129+
.to_string(),
1130+
),
10811131
metadata: None,
10821132
},
10831133
usage: None,
@@ -1092,7 +1142,7 @@ mod tests {
10921142
role: MessageRole::Assistant,
10931143
content: MessageContent::MultiModal(vec![ContentBlock::ToolUse {
10941144
id: "test_id".to_string(),
1095-
name: "bash".to_string(), // Use a real tool that can fail
1145+
name: "bash".to_string(), // Use a real tool that can fail
10961146
input: serde_json::json!({
10971147
"command": "/nonexistent/command/that/will/fail"
10981148
}),
@@ -1119,17 +1169,15 @@ mod tests {
11191169
// Create agent with default tools (including bash)
11201170
let agent_config = AgentConfig {
11211171
max_steps: 5,
1122-
tools: vec!["bash".to_string()], // Enable bash tool
1172+
tools: vec!["bash".to_string()], // Enable bash tool
11231173
..Default::default()
11241174
};
11251175

11261176
let tool_registry = crate::tools::ToolRegistry::default();
11271177
let tool_executor = tool_registry.create_executor(&agent_config.tools);
11281178

1129-
let conversation_manager = ConversationManager::new(
1130-
8192,
1131-
std::sync::Arc::new(ToolCallLlmClient),
1132-
);
1179+
let conversation_manager =
1180+
ConversationManager::new(8192, std::sync::Arc::new(ToolCallLlmClient));
11331181

11341182
let (ac, reg) = crate::agent::AbortController::new();
11351183

@@ -1171,14 +1219,20 @@ mod tests {
11711219
false
11721220
}
11731221
});
1174-
assert!(has_error_tool_result, "Should have error tool result in history");
1222+
assert!(
1223+
has_error_tool_result,
1224+
"Should have error tool result in history"
1225+
);
11751226

11761227
// Execute second task - this should not fail with API error about missing tool results
11771228
let result2 = agent
11781229
.execute_task_with_context("Test task 2", &project_path)
11791230
.await;
11801231

11811232
// Should succeed without API errors about missing tool results
1182-
assert!(result2.is_ok(), "Second task should execute without API errors");
1233+
assert!(
1234+
result2.is_ok(),
1235+
"Second task should execute without API errors"
1236+
);
11831237
}
11841238
}

0 commit comments

Comments
 (0)