Using the SDK Tool Runner Instead of Writing the Agent Loop
The manual agent loop is always the same: call the model, run the requested tools, send results back, repeat. The Anthropic SDKs include a tool runner (currently in beta) that does this for you, with type-checked tool inputs.
TypeScript with Zod
import Anthropic from '@anthropic-ai/sdk';
import { betaZodTool } from '@anthropic-ai/sdk/helpers/beta/zod';
import { z } from 'zod';
const client = new Anthropic();
const getExchangeRate = betaZodTool({
name: 'get_exchange_rate',
description: 'Get the current exchange rate between two currency codes.',
inputSchema: z.object({
from: z.string().describe('ISO code, e.g. USD'),
to: z.string().describe('ISO code, e.g. INR'),
}),
run: async ({ from, to }) => JSON.stringify(await rates.lookup(from, to)),
});
const finalMessage = await client.beta.messages.toolRunner({
model: 'claude-opus-5-5',
max_tokens: 16000,
tools: [getExchangeRate],
messages: [{ role: 'user', content: 'How many rupees is 250 US dollars?' }],
});
console.log(finalMessage.content);
The Zod schema becomes the tool's JSON Schema, and inputs are validated before run is called.
Python with a decorator
import anthropic
from anthropic import beta_tool
client = anthropic.Anthropic()
@beta_tool
def get_exchange_rate(from_code: str, to_code: str) -> str:
"""Get the current exchange rate between two currencies.
Args:
from_code: ISO currency code, e.g. USD.
to_code: ISO currency code, e.g. INR.
"""
return str(rates.lookup(from_code, to_code))
runner = client.beta.messages.tool_runner(
model="claude-opus-5-5",
max_tokens=16000,
tools=[get_exchange_rate],
messages=[{"role": "user", "content": "How many rupees is 250 US dollars?"}],
)
for message in runner: # one message per model turn
print(message.stop_reason)
The function's type hints and docstring become the tool schema and description, so write the docstring carefully.
When to write the loop yourself
- You need a custom transport or request shape the SDK can't build.
- You want no dependency on a beta API.
- Your control flow doesn't fit the runner (for example, complex multi-agent orchestration).
For approvals or logging you usually don't need a manual loop: put the check inside the tool's run function.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.