From d6609efd4e14101e77fb35a98ce597a32816862d Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Thu, 28 May 2026 22:51:47 +0900 Subject: fix(core): normalize tool schemas for Anthropic, add toolChoice=auto; feat(summon): agent definition support; docs: cc/ research findings - registry.ts: add normalizeForAnthropic() to strip , additionalProperties, default, nullable from zodToJsonSchema output so Anthropic doesn't silently reject tool definitions - agent.ts: add toolChoice=auto for Claude OAuth to prevent Opus thinking forever without calling tools - summon.ts: add agentSlug parameter, build agents catalog in description, add toAvailableAgents helper - agent-manager.ts: wire agent definition loading into spawnChildAgent, agent model fallback - loader.ts: export loadAgent, expandAgentToolNames, getAgentDirPaths; add getAgentDirPaths for permission gate - agent.ts: auto-allow read-only tools in agent definition directories - packaging/PKGBUILD: exclude ARM64 prebuilds from x86_64 package - cc/: research findings on Claude Opus tool calling issues - tests: loader tests, summon tool tests --- packages/core/src/tools/registry.ts | 39 ++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'packages/core/src/tools/registry.ts') diff --git a/packages/core/src/tools/registry.ts b/packages/core/src/tools/registry.ts index a09535e..ff6f4d1 100644 --- a/packages/core/src/tools/registry.ts +++ b/packages/core/src/tools/registry.ts @@ -3,6 +3,41 @@ import { jsonSchema, tool } from "ai"; import { zodToJsonSchema } from "zod-to-json-schema"; import type { ToolDefinition } from "../types/index.js"; +/** + * Strip JSON Schema fields that Anthropic's API does not accept from a + * `zodToJsonSchema()` output. The Anthropic `/messages` API rejects (or + * silently ignores) tools whose `input_schema` contains `$schema`, + * `additionalProperties`, `default`, or `nullable` — when this happens + * Claude never sees the tool and the model "thinks forever" instead of + * calling it. + * + * The stripped fields are also harmless to remove for OpenAI-compatible + * endpoints, so we apply this unconditionally. + */ +function normalizeForAnthropic(schema: Record): Record { + delete schema.$schema; + delete schema.additionalProperties; + delete schema.default; + delete schema.nullable; + + const properties = schema.properties; + if (properties && typeof properties === "object") { + for (const key of Object.keys(properties as Record)) { + const prop = (properties as Record)[key]; + if (prop && typeof prop === "object") { + normalizeForAnthropic(prop as Record); + } + } + } + + const items = schema.items; + if (items && typeof items === "object") { + normalizeForAnthropic(items as Record); + } + + return schema; +} + /** * Convert an internal `ToolDefinition` (Zod-parameterised) to an AI SDK v6 * `Tool` object. @@ -14,9 +49,11 @@ import type { ToolDefinition } from "../types/index.js"; * `fullStream` that agent.ts collects and dispatches. */ function toAISDKTool(def: ToolDefinition): Tool { + const raw = zodToJsonSchema(def.parameters) as Record; + const normalized = normalizeForAnthropic(raw); return tool({ description: def.description, - inputSchema: jsonSchema(zodToJsonSchema(def.parameters)), + inputSchema: jsonSchema(normalized), }); } -- cgit v1.2.3