Using the SDK Tool Runner Instead of Writing the Agent Loop

A
Author
15 Aug, 2026 1 min read 312 views

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.

Leave a comment

Comments are reviewed before they appear.