From b2bc02862aecc5fb5b20782b6dbeef97a5906a7b Mon Sep 17 00:00:00 2001 From: Douwe Osinga Date: Wed, 8 Oct 2025 10:56:47 -0400 Subject: [PATCH] step --- crates/goose/src/conversation/message.rs | 39 ++++++++----------- ui/desktop/openapi.json | 6 +-- .../src/components/ToolCallWithResponse.tsx | 22 ++++++++--- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/crates/goose/src/conversation/message.rs b/crates/goose/src/conversation/message.rs index b5846d9b0f..8b01a438b1 100644 --- a/crates/goose/src/conversation/message.rs +++ b/crates/goose/src/conversation/message.rs @@ -13,6 +13,12 @@ use utoipa::ToSchema; use crate::conversation::tool_result_serde; use crate::utils::sanitize_unicode_tags; +#[derive(ToSchema)] +pub enum ToolCallResult { + Success { value: T }, + Error { error: String }, +} + /// Custom deserializer for MessageContent that sanitizes Unicode Tags in text content fn deserialize_sanitized_content<'de, D>(deserializer: D) -> Result, D::Error> where @@ -39,44 +45,28 @@ where Ok(content) } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)] -#[serde(tag = "status", rename_all = "lowercase")] -pub enum ToolCallResult { - Success { value: T }, - Error { error: String }, -} - -impl From> for ToolCallResult { - fn from(result: ToolResult) -> Self { - match result { - Ok(value) => ToolCallResult::Success { value }, - Err(error) => ToolCallResult::Error { - error: error.to_string(), - }, - } - } -} - #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[derive(ToSchema)] pub struct ToolRequest { pub id: String, - pub tool_call: ToolCallResult, + #[serde(with = "tool_result_serde")] + #[schema(value_type = Object)] + pub tool_call: ToolResult, } impl ToolRequest { pub fn to_readable_string(&self) -> String { match &self.tool_call { - ToolCallResult::Success { value } => { + Ok(tool_call) => { format!( "Tool: {}, Args: {}", - value.name, - serde_json::to_string_pretty(&value.arguments) + tool_call.name, + serde_json::to_string_pretty(&tool_call.arguments) .unwrap_or_else(|_| "<>".to_string()) ) } - ToolCallResult::Error { error } => format!("Invalid tool call: {}", error), + Err(e) => format!("Invalid tool call: {}", e), } } } @@ -87,6 +77,7 @@ impl ToolRequest { pub struct ToolResponse { pub id: String, #[serde(with = "tool_result_serde")] + #[schema(value_type = Object)] pub tool_result: ToolResult>, } @@ -115,6 +106,8 @@ pub struct RedactedThinkingContent { #[serde(rename_all = "camelCase")] pub struct FrontendToolRequest { pub id: String, + #[serde(with = "tool_result_serde")] + #[schema(value_type = Object)] pub tool_call: ToolResult, } diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index ca2674611d..a3e3ae4f9d 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -2843,7 +2843,7 @@ "type": "string" }, "toolCall": { - "$ref": "#/components/schemas/ToolResult" + "type": "object" } } }, @@ -4439,7 +4439,7 @@ "type": "string" }, "toolCall": { - "$ref": "#/components/schemas/ToolResult" + "type": "object" } } }, @@ -4454,7 +4454,7 @@ "type": "string" }, "toolResult": { - "$ref": "#/components/schemas/ToolResult" + "type": "object" } } }, diff --git a/ui/desktop/src/components/ToolCallWithResponse.tsx b/ui/desktop/src/components/ToolCallWithResponse.tsx index a2c5fc3bc6..c2f100e84f 100644 --- a/ui/desktop/src/components/ToolCallWithResponse.tsx +++ b/ui/desktop/src/components/ToolCallWithResponse.tsx @@ -12,7 +12,7 @@ import { ChevronRight, FlaskConical } from 'lucide-react'; import { TooltipWrapper } from './settings/providers/subcomponents/buttons/TooltipWrapper'; import MCPUIResourceRenderer from './MCPUIResourceRenderer'; import { isUIResource } from '@mcp-ui/client'; -import { Content } from '../api'; +import { Content, RawResource } from '../api'; interface ToolCallWithResponseProps { isCancelledMessage: boolean; @@ -23,6 +23,17 @@ interface ToolCallWithResponseProps { append?: (value: string) => void; // Function to append messages to the chat } +function getToolResultValue(toolResult: Record): Content[] | null { + if ('value' in toolResult && Array.isArray(toolResult.value)) { + return toolResult.value as Content[]; + } + return null; +} + +function isRawResource(content: Content): content is RawResource { + return 'uri' in content && 'name' in content; +} + export default function ToolCallWithResponse({ isCancelledMessage, toolRequest, @@ -55,11 +66,10 @@ export default function ToolCallWithResponse({ {/* MCP UI — Inline */} {toolResponse?.toolResult && - Array.isArray((toolResponse.toolResult as any).value) && - (toolResponse.toolResult as any).value.map((content: Content, index: number) => { - if (isUIResource(content)) { + getToolResultValue(toolResponse.toolResult)?.map((content: Content, index: number) => { + if (isRawResource(content) && isUIResource(content)) { return ( -
+
@@ -72,7 +82,7 @@ export default function ToolCallWithResponse({ } else { return null; } - })} + })}{' '} ); }