From 9512b6dc7955942c84e24611da2388621b95c831 Mon Sep 17 00:00:00 2001 From: Dex Hunter Date: Mon, 13 Jul 2026 02:29:51 +0000 Subject: [PATCH] perf(toolshim): compact tool schema JSON ToolShim includes schemas in text prompts, so pretty-print whitespace scales with every exposed tool. Compact serialization preserves schema semantics while reducing prompt bytes. Related to aaif-goose/goose#1303. --- crates/goose/src/providers/toolshim.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/crates/goose/src/providers/toolshim.rs b/crates/goose/src/providers/toolshim.rs index 1707d629fdc4..0c56167bfa4f 100644 --- a/crates/goose/src/providers/toolshim.rs +++ b/crates/goose/src/providers/toolshim.rs @@ -879,7 +879,7 @@ pub fn format_tool_info(tools: &[Tool]) -> String { tool_info.push_str(&format!( "Tool Name: {}\nSchema: {}\nDescription: {:?}\n\n", tool.name, - serde_json::to_string_pretty(&tool.input_schema).unwrap_or_default(), + serde_json::to_string(&tool.input_schema).unwrap_or_default(), tool.description )); } @@ -1062,6 +1062,25 @@ mod tests { } } + #[test] + fn formats_tool_schemas_as_compact_lossless_json() { + let schema = object( + json!({"type": "object", "properties": {"query": {"type": "string", "description": "café 工"}, "options": {"type": "object", "properties": {}}}}), + ); + let tool = Tool::new("search".to_string(), "Search records".to_string(), schema); + + let output = format_tool_info(std::slice::from_ref(&tool)); + let description = format!("\nDescription: {:?}\n\n", tool.description); + let schema = output + .strip_prefix("Tool Name: search\nSchema: ") + .and_then(|value| value.strip_suffix(&description)) + .unwrap(); + + assert!(!schema.contains('\n')); + let parsed: Value = serde_json::from_str(schema).unwrap(); + assert_eq!(parsed, serde_json::to_value(&tool.input_schema).unwrap()); + } + #[test] fn parses_toolshim_backend_values() { assert_eq!(