diff options
| author | Adam Malczewski <[email protected]> | 2026-05-28 22:51:47 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-05-28 22:51:47 +0900 |
| commit | d6609efd4e14101e77fb35a98ce597a32816862d (patch) | |
| tree | 09ea404ce0a780ca6b8c380fdd93ad1ae9960986 /packages/core/src/tools/registry.ts | |
| parent | 2eeabc95b78f6624c187e1e3892f9413266b4b9a (diff) | |
| download | dispatch-d6609efd4e14101e77fb35a98ce597a32816862d.tar.gz dispatch-d6609efd4e14101e77fb35a98ce597a32816862d.zip | |
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
Diffstat (limited to 'packages/core/src/tools/registry.ts')
| -rw-r--r-- | packages/core/src/tools/registry.ts | 39 |
1 files changed, 38 insertions, 1 deletions
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 @@ -4,6 +4,41 @@ 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<string, unknown>): Record<string, unknown> { + 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<string, unknown>)) { + const prop = (properties as Record<string, unknown>)[key]; + if (prop && typeof prop === "object") { + normalizeForAnthropic(prop as Record<string, unknown>); + } + } + } + + const items = schema.items; + if (items && typeof items === "object") { + normalizeForAnthropic(items as Record<string, unknown>); + } + + 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<string, unknown>; + const normalized = normalizeForAnthropic(raw); return tool({ description: def.description, - inputSchema: jsonSchema(zodToJsonSchema(def.parameters)), + inputSchema: jsonSchema(normalized), }); } |
