Anthropic
anthropic() — Claude provider via @anthropic-ai/sdk. Lazy-loaded peer-dep; install when you use it.
The Anthropic SDK is the production path for Claude. agentfootprint's
anthropic()factory wraps it as anLLMProvider— same interface asmock(), so the rest of your agent code is identical between dev and prod.
Install
npm install @anthropic-ai/sdkThe SDK is a peer dependency declared in peerDependenciesMeta with optional: true — npm doesn't auto-install it. Lazy-required at first call; friendly install hint if missing.
anthropic() is imported from the agentfootprint/providers subpath (the agentfootprint/providers alias also works), NOT the main agentfootprint barrel. Vendor-SDK-backed providers live on that subpath so bundlers walking the main entry never touch the optional peer-dep requires — automatic tree-shaking. (The main barrel only re-exports the zero-peer-dep providers: mock, browserAnthropic, browserOpenai, createProvider.)
Use
import { Agent } from 'agentfootprint';
import { anthropic } from 'agentfootprint/providers';
const provider = anthropic({
apiKey: process.env.ANTHROPIC_API_KEY!,
// defaultModel: 'claude-sonnet-4-5-20250929', // optional, used when Agent doesn't override
});
const agent = Agent.create({
provider,
model: 'claude-sonnet-4-5-20250929',
}).build();Model strings need date suffixes (claude-sonnet-4-5-20250929, claude-haiku-4-5-20251001) — Anthropic's API requires the explicit version for stability.
Tools (native function calling)
Anthropic's Messages API has native tool_use blocks. The provider translates the agent's Tool[] into the API's tool format and round-trips assistant tool_calls via LLMMessage.toolCalls. ReAct correctness preserved across multi-iteration runs.
One tool per reply — parallelToolCalls: false
By default Claude may ask for several tools at once: one assistant message carries many tool_use blocks, and the agent runs them all inside a single loop iteration. That is usually what you want — it is faster and cheaper.
It is not what you want when the shape of the loop is part of what you are measuring. Per-iteration analysis reads one tool source per iteration: localizeContextBug seeds one 'tool' suspect from that iteration's lastToolResult, and removableSources de-duplicates by tool name. So a reply that batched three tools is attributed to the last tool of the batch — the other two never appear as their own influence rows, and you cannot ablate them individually.
Set parallelToolCalls: false to cap the model at one tool per reply:
const provider = anthropic({
apiKey: process.env.ANTHROPIC_API_KEY!,
parallelToolCalls: false, // one tool per reply → one tool per iteration
});On the wire this sends tool_choice: { type: 'auto', disable_parallel_tool_use: true }. auto is deliberate: the model still decides which tool to call, and whether to call one at all — only the count is capped. Nothing is sent on requests that carry no tools (Anthropic rejects tool_choice there), and parallelToolCalls: true sends nothing either, because allowing batches is already Anthropic's default.
Asking for this in the system prompt ("call one tool at a time") is not equivalent — that is a request the model may ignore, this is a request parameter the API enforces. Cost: one extra round trip per tool.
The same option exists on browserAnthropic(), and both adapters put the identical field on the wire.
Streaming
provider.stream(req) uses the SDK's native iterator; chunks land as they arrive. Final chunk carries the full LLMResponse (toolCalls + usage + stopReason) — single round-trip serves UI tokens AND ReAct decisioning.
Production patterns
Wrap with resilience decorators for production:
import { withRetry, withFallback } from 'agentfootprint/resilience';
import { anthropic, openai } from 'agentfootprint/providers';
const provider = withRetry(
withFallback(
anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! }),
openai({ apiKey: process.env.OPENAI_API_KEY! }),
),
{ maxAttempts: 5 },
);See Resilience guide.
Browser variant
For browser environments where the Anthropic Node SDK doesn't bundle cleanly, use BrowserAnthropicProvider — fetch-based, zero peer deps. Requires the anthropic-dangerous-direct-browser-access: true header (which the provider sets automatically). Production browser apps should proxy through a backend.
Limitations
- Multi-modal content (images, video) not supported —
LLMMessage.contentisstring. responseFormat(JSON-Schema-coerced output) not exposed yet — pass schema instructions viasystemPrompt.
Next steps
- Resilience — wrap with
withRetry/withFallback - Streaming — token-by-token UI rendering
Indexing a corpus
agentfootprint/rag — loaders, splitters and the indexing chart. A folder of documents becomes a searchable index, and the run explains itself.
OpenAI
openai() — GPT provider via the openai SDK. Also covers OpenAI-compatible endpoints (Ollama, llama.cpp, vLLM, Together, Groq, LM Studio) via baseURL.
