Claude Agent SDK
Claude Agent SDK · Claude Agent SDK WhatsApp · Claude agent Telegram bot · Claude iMessage agent · Anthropic agent WhatsApp API · connect Claude to WhatsAppRun a Claude agent for each message and deliver its streamed answer.
Run a Claude agent for each incoming message and deliver its answer as chat bubbles. Your agent keeps its tools; Flow handles the channel connection.
// npm install @flow-engineer/messaging @anthropic-ai/claude-agent-sdkimport { query } from "@anthropic-ai/claude-agent-sdk";import { FlowMessaging, contentText } from "@flow-engineer/messaging";
const flow = new FlowMessaging();
for await (const event of flow.events.stream({ types: ["message.received"] })) { const run = query({ prompt: contentText(event.data.message.content), options: { systemPrompt: "You are the assistant for Asha's Bakery. Answer customers in short messages.", tools: [], // no built-in tools (Bash, file access); list the ones your agent may use includePartialMessages: true, // stream text as it is written }, }); await event.conversation.reply(run); // sends the agent's text, skips tool and system messages}# pip install claude-agent-sdk requests# Plain HTTP, no Flow SDK; the Python SDK (pip install flow-messaging) wraps the same calls. This calls the HTTP API.import os, requestsfrom claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, TextBlock
API = "https://api.flow.engineer"HEADERS = {"Authorization": f"Bearer {os.environ['FLOW_MESSAGING_KEY']}"}
async def answer(event: dict): conversation = event["conversation"]["id"] text = event["data"]["message"]["content"].get("text", "") options = ClaudeAgentOptions( system_prompt="You are the assistant for Asha's Bakery. Answer in short messages.", tools=[], # no built-in tools; list the ones your agent may use ) i = 0 async for message in query(prompt=text, options=options): if isinstance(message, AssistantMessage): for block in message.content: if isinstance(block, TextBlock) and block.text.strip(): requests.post( f"{API}/v0/conversations/{conversation}/basic", headers={**HEADERS, "Idempotency-Key": f"{event['id']}:{i}"}, json={"text": block.text}, # sent exactly as written: no markdown is rendered timeout=30, ) i += 1How it fits
Section titled “How it fits”reply()reads thequery()iterator: withincludePartialMessagesit sends text as it streams, otherwise each assistant message’s text. Tool calls, results and system messages are not sent to the person.- Each assistant turn becomes its own bubble, which reads naturally in chat (“Let me check that…” then the answer).
tools: []turns off Claude Code’s built-in tools, which a customer-facing agent should not have by default;allowedToolsonly pre-approves tools and does not restrict them.- Keep one Claude session per Flow conversation (
conversation.id) to carry context between messages: remember each run’ssession_idand pass it asresumenext time (the full example does this). - Your production agent talks to Flow through the SDK or HTTP. The hosted MCP server is a separate build-time tool for coding agents; whether a project adds it is the project owner’s decision.
- To see each turn’s model and tool calls and get every reply graded, send this agent’s traces to Flow Observe: Traces from agent frameworks.
Full example
Section titled “Full example”examples/claude-agent-sdk on GitHub.
Was this page helpful?
Thanks, we read every comment.