Tool Helpers
Purpose and Scope
Tool helpers are the SDK layer that reduces the amount of application code required when Claude calls tools. A tool is a callable capability described to Claude with a name, description, and input schema; a runner is the helper object that keeps asking the API for the next assistant message, detects tool requests, executes matching local functions, and feeds tool results back into the conversation. In this repository, the public examples show the beta message tool runner used with Zod-backed tool definitions for weather, time, and currency lookup tasks, including parallel tool use and a bounded iteration count.
Sources: examples/tools-helpers-advanced.ts, examples/tools-helpers-advanced-streaming.ts, tests/lib/tools/ToolRunner.test.ts
The helper layer is best understood as a convenience path, not the only way to implement tools. Official Claude guidance positions the Tool Runner as the path for automatic agentic looping, validation, and error wrapping, while manual tool handling remains appropriate when an application needs human approval, custom logging, policy checks, or conditional execution. The TypeScript examples match that intent: they define local tools with schemas and run functions, then let the runner advance the conversation and generate tool responses instead of manually constructing every follow-up message.
Sources: examples/tools-helpers-advanced.ts, examples/tools-helpers-advanced-streaming.ts
Relevant Source Files
- helpers.md — Documents the repository’s message helper surface, especially streaming helper concepts, accumulation behavior, abort behavior, and structured-output helper usage that sit beside tool helpers in the SDK helper family.
- src/helpers/index.ts — Public helper barrel exporting jsonSchemaOutputFormat and zodOutputFormat, showing how helper modules are exposed from the package entry structure.
- examples/tools-helpers-advanced.ts — Runnable non-streaming tool runner example using betaZodTool, three local tools, max_iterations, async iteration over runner messages, and generateToolResponse output inspection.
- examples/tools-helpers-advanced-streaming.ts — Runnable streaming variant of the same tool-runner workflow, showing stream events, content block deltas, finalMessage, and tool response generation after each streamed message.
- tests/lib/helper-client.test.ts — Unit tests for helper client copying, scoped bearer authentication, clearing inherited API key state, preserving custom headers, telemetry header stamping, and parent-client immutability.
- tests/lib/tools/ToolRunner.test.ts — Tool runner tests that define runnable weather and calculator tools, construct tool use and tool result blocks, simulate streamed message events, and exercise runner behavior against mocked fetch responses.
Core Primitives
The most important primitive in the examples is the runnable tool definition created with betaZodTool. Each tool has a stable name that Claude can reference, a human-readable description, an input schema expressed with Zod, and a run function that receives parsed arguments. In the advanced example, getWeather accepts a location, getTime accepts a timezone, and getCurrencyExchangeRate accepts source and target currencies. These tools return strings, which the runner can convert into tool result content for the next API turn.
Sources: examples/tools-helpers-advanced.ts, examples/tools-helpers-advanced-streaming.ts
The second primitive is the beta messages tool runner created from the client. The example passes initial user messages, the tool array, a model name, a token limit, and max_iterations. That iteration limit is important because an automatic agentic loop needs a stop boundary controlled by the application. The runner itself is consumed as an async iterable. In the non-streaming path, each yielded item is a complete assistant message whose content blocks can be inspected for text or tool_use blocks before tool results are generated.
Sources: examples/tools-helpers-advanced.ts, tests/lib/tools/ToolRunner.test.ts
The streaming variant adds a third primitive: each runner iteration yields a message stream rather than a completed message. The example consumes stream events such as message_start, content_block_start, content_block_delta, content_block_stop, and message_stop. Text deltas are written as they arrive, while input JSON deltas reveal the incremental arguments Claude is building for a tool call. After the stream completes, the example calls finalMessage on the stream, then asks the runner to generate the default tool response for any tool_use blocks in that message.
Sources: examples/tools-helpers-advanced-streaming.ts, helpers.md
Execution Flow
A typical helper-driven tool flow starts by constructing an Anthropic client and describing local tools. The application then calls the beta message runner with the same high-level request fields used for a message request, plus the runnable tool implementations and a loop limit. Claude may respond with normal text, one or more tool_use blocks, or both. The application can display or log those blocks, then call generateToolResponse so the runner invokes matching run functions and prepares tool_result blocks associated with the original tool use identifiers.
Sources: examples/tools-helpers-advanced.ts, tests/lib/tools/ToolRunner.test.ts
The tests clarify the data model behind that flow. Test fixtures define a weather tool and calculator tool as runnable tools with type, name, description, input_schema, parse, and run members. Helper functions create BetaContentBlock values for tool_use blocks and BetaToolResultBlockParam values for tool_result blocks, preserving the tool_use_id relationship. This mirrors the protocol obligation that a tool result must be tied to the exact tool call that produced it, which matters when Claude requests multiple tools in one assistant turn.
Sources: tests/lib/tools/ToolRunner.test.ts
Streaming follows the same conceptual loop but exposes a more granular timeline. The helper stream begins with message metadata, then opens content blocks and emits either text deltas or partial JSON for tool inputs. This is useful when a user interface needs to render assistant text immediately or show a tool call being assembled. The repository’s streaming example still waits for the final message before generating tool responses, which keeps execution aligned with completed tool_use blocks rather than partially received input fragments.
Sources: examples/tools-helpers-advanced-streaming.ts, helpers.md
Helper Client Behavior
Some helpers need a scoped client that behaves like the parent client but changes authentication or telemetry for helper-managed work. The helper-client tests document several invariants for copyClientForHelper. A sub-client can receive a bearer auth token, the inherited API key is cleared so requests do not send both X-Api-Key and Authorization, and the x-stainless-helper header records which helper is making requests. The tests also require custom default headers from the parent to survive, so helper use does not silently drop tenant or application headers.
Sources: tests/lib/helper-client.test.ts
The same tests emphasize that helper setup must not mutate the parent client. That matters for long-lived applications where one Anthropic instance may be shared across message requests, runners, pollers, or environment helpers. A helper that rewrote parent authentication would create confusing cross-request failures. Instead, copyClientForHelper produces a scoped sub-client with the helper-specific auth token and telemetry header while leaving the original API key state intact. This behavior is part of the reliability contract for helper code that runs behind higher-level APIs.
Sources: tests/lib/helper-client.test.ts
API Components and Usage Notes
The helper export surface in src/helpers/index.ts currently re-exports structured-output helpers for JSON Schema and Zod. Tool-specific examples import betaZodTool from the beta Zod helper path rather than from that top-level barrel, so callers should use the documented helper module path shown in the examples for beta tool definitions. The package also declares Zod as an optional peer dependency, which means applications using Zod-based helpers should install a compatible Zod version instead of assuming it is always bundled by the SDK.
Sources: src/helpers/index.ts, examples/tools-helpers-advanced.ts, package.json
A compact reference for the visible tool-helper workflow is: create an Anthropic client, define tools with betaZodTool, call client.beta.messages.toolRunner with messages, tools, model, max_tokens, and max_iterations, iterate the runner, inspect text and tool_use content blocks, then call runner.generateToolResponse. For streaming, add stream: true, iterate each yielded message stream, process raw stream events, call finalMessage, and only then generate the tool response. These examples are intentionally small but cover the core control points most applications need.
Sources: examples/tools-helpers-advanced.ts, examples/tools-helpers-advanced-streaming.ts
import Anthropic from '@anthropic-ai/sdk';
import { betaZodTool } from '@anthropic-ai/sdk/helpers/beta/zod';
import { z } from 'zod/v4';
const client = new Anthropic();
const runner = client.beta.messages.toolRunner({
messages: [{ role: 'user', content: 'Use the weather tool for San Francisco.' }],
tools: [
betaZodTool({
name: 'getWeather',
description: 'Get the weather at a specific location',
inputSchema: z.object({ location: z.string() }),
run: ({ location }) => `Sunny in ${location}`,
}),
],
model: 'claude-sonnet-5',
max_tokens: 1024,
max_iterations: 10,
});Testing Signals and Next Steps
The tool runner tests provide useful signals for edge cases a production integration should consider. Tool input should be parsed before run functions receive it, tool result blocks should preserve the requested tool identifier, and streaming tests should account for chunked text and incremental JSON input. The helper-client tests add operational concerns: preserve configured headers, isolate helper credentials, and stamp helper telemetry. Together, these tests suggest validating both the conversation loop and the client configuration layer when wrapping the SDK in a larger application framework.
Sources: tests/lib/tools/ToolRunner.test.ts, tests/lib/helper-client.test.ts
Next, read the broader Tool Use Overview for manual tool-call handling and the Schema and Zod Helpers page for schema construction patterns. If your user interface needs incremental rendering, pair this page with Streaming Responses and Fine-Grained Tool Streaming. If your tools cross a security boundary, prefer a manual loop or add an approval layer around runner.generateToolResponse so that filesystem, shell, network, or payment actions are reviewed before execution.