diff --git a/crates/goose/Cargo.toml b/crates/goose/Cargo.toml index e19400754..053f55ab3 100644 --- a/crates/goose/Cargo.toml +++ b/crates/goose/Cargo.toml @@ -59,6 +59,7 @@ paste = "1.0" serde_yaml = "0.9.34" once_cell = "1.20.2" dirs = "6.0.0" +rand = "0.8.5" [dev-dependencies] criterion = "0.5" diff --git a/crates/goose/src/providers/formats/google.rs b/crates/goose/src/providers/formats/google.rs index 01060f70d..65e949525 100644 --- a/crates/goose/src/providers/formats/google.rs +++ b/crates/goose/src/providers/formats/google.rs @@ -6,6 +6,7 @@ use anyhow::Result; use mcp_core::content::Content; use mcp_core::role::Role; use mcp_core::tool::{Tool, ToolCall}; +use rand::{distributions::Alphanumeric, Rng}; use serde_json::{json, Map, Value}; /// Convert internal Message format to Google's API message specification @@ -198,14 +199,16 @@ pub fn response_to_message(response: Value) -> Result { .and_then(|content| content.get("parts")) .and_then(|parts| parts.as_array()) .unwrap_or(&binding); + for part in parts { if let Some(text) = part.get("text").and_then(|v| v.as_str()) { content.push(MessageContent::text(text.to_string())); } else if let Some(function_call) = part.get("functionCall") { - let id = function_call["name"] - .as_str() - .unwrap_or_default() - .to_string(); + let id: String = rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(8) + .map(char::from) + .collect(); let name = function_call["name"] .as_str() .unwrap_or_default() diff --git a/ui/desktop/src/ai-sdk-fork/process-custom-chat-response.ts b/ui/desktop/src/ai-sdk-fork/process-custom-chat-response.ts index 01f4c1573..b1cc4d531 100644 --- a/ui/desktop/src/ai-sdk-fork/process-custom-chat-response.ts +++ b/ui/desktop/src/ai-sdk-fork/process-custom-chat-response.ts @@ -89,8 +89,18 @@ export async function processCustomChatResponse({ onTextPart(value) { // If the last event wasn't text, or we don't have a current message, create a new one if (lastEventType !== 'text' || currentMessage == null) { - archiveCurrentMessage(); - currentMessage = createNewMessage(); + // Only archive if there are no tool invocations in 'call' state + const hasPendingToolCalls = + currentMessage?.toolInvocations?.some((invocation) => invocation.state === 'call') ?? + false; + + if (!hasPendingToolCalls) { + archiveCurrentMessage(); + } + + if (!currentMessage) { + currentMessage = createNewMessage(); + } currentMessage.content = value; } else { // Concatenate with the existing message