agent: Account for tool use messages without any corresponding text (#27917)

This PR makes it so if we receive a tool use from the model without any
corresponding text, we'll insert some placeholder text to keep the
conversation in a well-structured format.

This aims to fix an error that Antonio was seeing:


![image](https://github.com/user-attachments/assets/eeba95ef-9b67-41d7-bce3-afe84bcdc7b1)

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2025-04-02 08:56:50 -04:00 committed by GitHub
parent 5dcd0d37a6
commit 2846c55cde
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -124,6 +124,15 @@ pub enum MessageSegment {
Thinking(String),
}
impl MessageSegment {
pub fn text_mut(&mut self) -> &mut String {
match self {
Self::Text(text) => text,
Self::Thinking(text) => text,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProjectSnapshot {
pub worktree_snapshots: Vec<WorktreeSnapshot>,
@ -1076,18 +1085,32 @@ impl Thread {
}
}
LanguageModelCompletionEvent::ToolUse(tool_use) => {
let last_assistant_message_id = thread
let last_assistant_message = thread
.messages
.iter()
.rfind(|message| message.role == Role::Assistant)
.map(|message| message.id)
.unwrap_or_else(|| {
.iter_mut()
.rfind(|message| message.role == Role::Assistant);
let last_assistant_message_id =
if let Some(message) = last_assistant_message {
if let Some(segment) = message.segments.first_mut() {
let text = segment.text_mut();
if text.is_empty() {
text.push_str("Using tool...");
}
} else {
message.segments.push(MessageSegment::Text(
"Using tool...".to_string(),
));
}
message.id
} else {
thread.insert_message(
Role::Assistant,
vec![MessageSegment::Text("Using tool...".to_string())],
cx,
)
});
};
thread.tool_use.request_tool_use(
last_assistant_message_id,
tool_use,