Skip to content

sdk: make Zod the source of truth for agent tool schemas - #81

Draft
thorstenhans wants to merge 1 commit into
mainfrom
client-sdk-tools
Draft

thorstenhans wants to merge 1 commit into
mainfrom
client-sdk-tools

Conversation

@thorstenhans

Copy link
Copy Markdown

Why

Frameworks like the Vercel AI SDK define tools with Zod. Turning the SDK's hand-written JSON Schema (the Anthropic / OpenAI shape) into something those frameworks understand is error-prone and loses validation and types. Going the other way is reliable: Zod 4 generates JSON Schema itself (z.toJSONSchema).

What changes

  • interpreterTool() returns a strict Zod schema as inputSchema. { description, inputSchema } goes straight into the AI SDK's tool(), and execute receives typed arguments.
  • Adapters derive JSON Schema from it: toAnthropicTool(), toOpenAITool(), and the new toToolDefinition(). They still accept hand-written JSON Schema ToolDefinitions (app-builder's create_app is unchanged).
  • Validation for free: inputSchema.safeParse(args) rejects unknown fields such as allowedHosts, kvEnabled, and identity, so the model cannot set execution policy. The ai-code-executor example uses it instead of hand-rolled checks.
  • Types follow the configuration: interpreterTool({ languages: ["python"] }) infers language: "python" with no dependencies, matching the schema.
  • README shows the Interpreter, tool, and execute setup for the Vercel AI SDK ToolLoopAgent and the Anthropic SDK, with the floating-promise rule in the agent system prompt (per AGENTS.md).
  • zod@^4.6.7 is a regular dependency, imported only by the ./tools entry point.

Compatibility

What the model sees is unchanged. For every language configuration, the derived JSON Schema and the description are identical to the previous hand-written output (key order aside). A golden fixture (sdk/test/fixtures/interpreter-tool.json) pins this. While building it, the comparison caught two regressions, both fixed here:

  • input.body had become required.
  • Zod emitted propertyNames: { type: "string" } for string maps; this is now stripped because OpenAI strict mode rejects it.

Breaking (0.1.0): interpreterTool().inputSchema is now a Zod schema. Code that reads JSON Schema from it should use toToolDefinition(tool).inputSchema.

Testing

  • sdk: npm run check (typecheck incl. new compile-time type assertions; 45 tests pass, including the golden test, which I confirmed fails when the body regression is put back)
  • AI SDK and Anthropic SDK compatibility: the README snippets typecheck against ai@7.0.166, @ai-sdk/anthropic@4.0.99, and @anthropic-ai/sdk@1.6.0 (scratch project, not run against a model)
  • Examples: ai-code-executor and app-builder (both providers) and sdk-component build to Wasm; example lockfiles only gain the SDK's zod entry and pass npm ci
  • npm audit gate: sdk is clean. The gate still fails for examples/ai-code-executor/ui and examples/app-builder/ui, which this PR does not touch
  • Not run locally: the spin integration suites (check-imports.mjs, smoke.hurl, run-examples.sh). They cover the sandbox components, which do not depend on the SDK

Open questions for review

  • zod as a regular dependency or a peer dependency (a peer dependency avoids two copies of zod in apps that also use it, but users must install it themselves)
  • Bundle-size impact of zod on the example Wasm components has not been measured

🤖 Generated with Claude Code

interpreterTool() now returns a strict Zod schema as inputSchema, which the
Vercel AI SDK consumes directly. toAnthropicTool(), toOpenAITool(), and the new
toToolDefinition() derive JSON Schema from it with z.toJSONSchema; hand-written
JSON Schema ToolDefinitions are still accepted.

- The derived schema and description are identical to the previous
  hand-written output for every language configuration, pinned by a golden
  fixture test.
- The input type narrows to the configured languages (no `dependencies` for
  Python-only tools).
- inputSchema.safeParse() rejects unknown fields such as allowedHosts,
  replacing hand-rolled argument checks in the ai-code-executor example.
- README documents Interpreter + tool setup for the Vercel AI SDK
  ToolLoopAgent and the Anthropic SDK.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant