diff --git a/backend/windmill-mcp/src/common/schema.rs b/backend/windmill-mcp/src/common/schema.rs index 005b4bde29..f7417ec752 100644 --- a/backend/windmill-mcp/src/common/schema.rs +++ b/backend/windmill-mcp/src/common/schema.rs @@ -235,6 +235,9 @@ fn is_valid_json_schema_type(t: &str) -> bool { /// untyped fields) so the node validates as "any type" /// - Removing `default: null` when the type doesn't include `null` /// - Adding `type: "object"` to property-bearing schemas that have no type +/// - De-duplicating `required` at every depth, and dropping non-string entries +/// (`required` is `uniqueItems`, and a repeat makes a strict client drop the +/// whole tool rather than report an error) pub fn make_schema_compatible(schema: &mut Value) { let Value::Object(obj) = schema else { return }; diff --git a/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts b/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts index eebdfb9695..e04519a121 100644 --- a/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts +++ b/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts @@ -1293,9 +1293,16 @@ export class AIChatManager { typeof this.systemMessage.content === 'string' ? this.systemMessage.content.length / tokenPerCharacter : 0 + // The same set the request carries: registered MCP tools are appended by the + // config getter, and their remote schemas are the largest definitions in the + // list — leaving them out overstates the tail budget compaction may keep. + const sentTools = [ + ...this.tools, + ...(this.mode === AIMode.GLOBAL ? loadedMcpTools(this.mcpOwnerId) : []) + ] const toolTokens = - this.tools.length > 0 - ? JSON.stringify(this.tools.map((t) => t.def)).length / tokenPerCharacter + sentTools.length > 0 + ? JSON.stringify(sentTools.map((t) => t.def)).length / tokenPerCharacter : 0 return systemTokens + toolTokens }