This document explains how the WhatsApp bot uses the Claude Agent SDK to respond to messages.
npm install @anthropic-ai/claude-agent-sdkThe SDK uses Claude Code CLI authentication - not an API key. It piggybacks on the existing auth from the claude CLI tool.
To authenticate:
claude loginThis stores credentials locally (typically in ~/.claude/) and the SDK picks them up automatically. No ANTHROPIC_API_KEY needed.
import { query } from "@anthropic-ai/claude-agent-sdk";The SDK's query() function returns an async iterable that streams events:
async function runQueryWithTools(prompt: string, systemPrompt?: string): Promise<QueryResult> {
const q = query({
prompt,
options: {
model: "sonnet", // or "haiku"
systemPrompt: systemPrompt,
maxTurns: 50, // agentic turns allowed
allowedTools: ["WebSearch", "WebFetch", "Read", "Edit", "Write", "Glob", "Grep"],
permissionMode: "acceptEdits",
cwd: WORKSPACE_DIR,
},
});
let result = "";
for await (const msg of q) {
if (msg.type === "result") {
if (msg.subtype === "success") {
result = msg.result;
} else if (msg.subtype === "error") {
throw new Error(msg.error);
}
}
}
return { result };
}| Option | Description |
|---|---|
model |
Model to use: "sonnet", "haiku", "opus" |
systemPrompt |
System prompt for the conversation |
maxTurns |
Maximum agentic turns (API round-trips) |
allowedTools |
Array of tool names the model can use |
permissionMode |
How to handle tool permissions ("acceptEdits", etc.) |
cwd |
Working directory for file operations |
mcpServers |
Custom MCP servers with additional tools |
The SDK provides these tools out of the box:
WebSearch- Search the webWebFetch- Fetch and read web pagesRead- Read filesEdit- Edit filesWrite- Write filesGlob- Find files by patternGrep- Search file contents
The query returns an async iterable. Key event types:
for await (const msg of query) {
switch (msg.type) {
case "assistant":
// Model response, may contain tool_use blocks
break;
case "result":
if (msg.subtype === "success") {
// Final result text
result = msg.result;
} else if (msg.subtype === "error") {
// Error occurred
throw new Error(msg.error);
}
break;
}
}For simple queries without tool use (e.g., moderation):
async function runQuery(prompt: string, systemPrompt?: string): Promise<string> {
const q = query({
prompt,
options: {
model: "haiku",
systemPrompt: systemPrompt,
maxTurns: 1, // Single turn, no tools
},
});
let result = "";
for await (const msg of q) {
if (msg.type === "result" && msg.subtype === "success") {
result = msg.result;
}
}
return result;
}query()takes a prompt and options object- Authentication is automatic via
ANTHROPIC_API_KEYenv var - Streaming: iterate with
for await...ofto receive events - Result: look for
msg.type === "result"withsubtype === "success" - Tools: the SDK handles tool execution automatically during the agentic loop
- Models: use
"haiku"for fast/cheap,"sonnet"for quality responses