SDKs & Developer Experience

Building a Tool-Calling Loop in TypeScript

The agentic loop is the same in every language — but TypeScript adds a compiler that catches malformed tool plumbing before it ever bills a token.

Claude 3P 101 · Updated July 2026 · Unofficial guide

If you have read the Python version of this pattern, the TypeScript story will feel familiar: call the model with tool definitions, look for tool_use blocks in the response, execute the requested tools in your own code, inject the results back into the conversation, and repeat until the model answers without requesting a tool. What TypeScript changes is how much of that plumbing the compiler can verify for you.

The foundation is the official SDK, @anthropic-ai/sdk (npm install @anthropic-ai/sdk), whose basic call shape is:

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  apiKey: process.env['ANTHROPIC_API_KEY'],
});

const message = await client.messages.create({
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Hello, Claude' }],
  model: 'claude-opus-4-8',
});

The loop wraps that call in a bounded while, exactly as in Python. The SDK's type definitions (see the TypeScript SDK repository for the current type names) model message content as a discriminated union of block types, which is what makes the TypeScript version pleasant: narrowing on block.type === 'tool_use' gives you a fully typed tool-call object, and forgetting to handle a block kind is a compile-time error rather than a 2 a.m. page.

Typed tool definitions

A tool definition is a name, a description, and an input schema expressed in JSON Schema (covered in depth in defining tool schemas). In TypeScript, teams typically define each tool's input type once and derive both artifacts from it: the JSON Schema sent to the API, and the parameter type of the implementing function. Schema-validation libraries that infer static types from runtime schemas make this a one-liner per tool, and the payoff is real — the schema the model sees and the function your loop dispatches to can never silently drift apart. Whichever approach you take, validate the model's arguments at runtime against the schema before executing; the type system protects your code paths, not the network payload.

Result injection

When tools finish, results are injected back as the next user-role message, one tool-result block per requested call, each matched to the request it answers. Two rules keep this correct. First, append the assistant's turn unmodified before the results: on reasoning-enabled models the tool-requesting turn can include a thinking block that must be returned exactly as received — thinking blocks are signature-verified and modified ones are rejected. Second, encode tool failures as results ("the API returned 404") rather than throwing: the model can often route around a failed call, and your loop lives to iterate again.

Termination strategies

The loop's natural exit is a response with no tool_use blocks. Production code adds defense in depth:

StrategyWhat it protects against
Iteration cap (for example, max 10 turns)Runaway loops from erroring tools or open-ended tasks
Wall-clock deadline via AbortControllerSlow tools stacking into unbounded latency
Cumulative token budget tracked from each response's usageCost blowouts invisible to an iteration count
Task budgets (beta)Server-side enforcement of a total token budget

On the last row: newer Opus-line models support a beta task-budget parameter for agentic loops — output_config: {task_budget: {type: "tokens", total: 128000}} with the beta header task-budgets-2026-03-13 and a documented minimum of 20,000 tokens — letting the platform enforce a ceiling across the whole task rather than per request. It is beta on the first-party API and Claude Platform on AWS, and should be assumed unsupported on Bedrock, Vertex AI, and Foundry; a client-side budget check is the portable fallback.

Rule of thumb: treat "hit the cap" as a first-class outcome with its own logging and user messaging — not as an error, and never as silent success with a half-finished task.

Platform portability

Tool use is available on all four third-party platforms, and the loop's logic is identical everywhere. For Claude Platform on AWS there is a dedicated beta client — npm install @anthropic-ai/aws-sdk, then new AnthropicAws() — which handles SigV4 signing and workspace headers. For Bedrock, Vertex AI, and Foundry from TypeScript, consult each platform's official documentation for the integration path.

Where to go next

Continue with orchestrating multiple tools, or see mocking Claude API calls for how to test a loop without burning tokens.

Sources