From c2fc5e054114828c763d59890d3b8609368432ac Mon Sep 17 00:00:00 2001 From: jh-block Date: Tue, 10 Feb 2026 11:17:06 +0100 Subject: [PATCH] Fix duplicated output in Code Mode by filtering content by audience The shell tool returns two Content::text items: one for the assistant and one for the user. For short outputs both contain identical text. The callback in code_execution_extension was joining all text content without filtering by audience, causing the output to appear twice. Filter to only include content targeted at the assistant (or with no audience restriction) before joining text results. --- crates/goose/src/agents/code_execution_extension.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/goose/src/agents/code_execution_extension.rs b/crates/goose/src/agents/code_execution_extension.rs index 2f9371f54bcc..01cd5df06456 100644 --- a/crates/goose/src/agents/code_execution_extension.rs +++ b/crates/goose/src/agents/code_execution_extension.rs @@ -7,7 +7,7 @@ use pctx_code_mode::model::{CallbackConfig, ExecuteInput, GetFunctionDetailsInpu use pctx_code_mode::{CallbackRegistry, CodeMode}; use rmcp::model::{ CallToolRequestParams, CallToolResult, Content, Implementation, InitializeResult, JsonObject, - ListToolsResult, ProtocolVersion, RawContent, ServerCapabilities, Tool as McpTool, + ListToolsResult, ProtocolVersion, RawContent, Role, ServerCapabilities, Tool as McpTool, ToolAnnotations, ToolsCapability, }; use schemars::{schema_for, JsonSchema}; @@ -270,9 +270,16 @@ fn create_tool_callback( if let Some(sc) = &result.structured_content { Ok(serde_json::to_value(sc).unwrap_or(Value::Null)) } else { + // Filter to assistant-audience or no-audience content, + // skipping user-only content to avoid duplicated output let text: String = result .content .iter() + .filter(|c| { + c.audience().is_none_or(|audiences| { + audiences.is_empty() || audiences.contains(&Role::Assistant) + }) + }) .filter_map(|c| match &c.raw { RawContent::Text(t) => Some(t.text.clone()), _ => None,