/** * Streaming citations with the Node SDK: citations arrive as content_block_delta { delta.type: "citations_delta" } * events; finalMessage() reassembles text blocks with their citations arrays. * STATUS: LIVE_VERIFIED 2026-09-18 (claude-haiku-4-5-20251001): 1 citations_delta (char_location 17-32) (~$0.0007). * Run: node --env-file=.env --experimental-strip-types examples/anthropic/citations/citations_stream.ts */ import Anthropic from "@anthropic-ai/sdk"; import { appendFileSync } from "node:fs"; const MODEL = process.env.ANTHROPIC_MODEL ?? "claude-haiku-4-5-20251001"; const client = new Anthropic({ maxRetries: 1 }); const citations: unknown[] = []; const stream = client.messages.stream({ model: MODEL, max_tokens: 100, messages: [{ role: "user", content: [ { type: "document", source: { type: "text", media_type: "text/plain", data: "The sky is blue. Grass is green." }, title: "Colors", citations: { enabled: true } }, { type: "text", text: "What color is grass? Answer in one sentence and cite." }, ] }], }); stream.on("streamEvent", (ev) => { if (ev.type === "content_block_delta" && ev.delta.type === "citations_delta") citations.push(ev.delta.citation); }); const final = await stream.finalMessage(); console.log("citations_delta events:", citations.length, JSON.stringify(citations[0])); console.log("final text blocks:", final.content.map((b) => (b.type === "text" ? { text: b.text, n: b.citations?.length ?? 0 } : b.type))); appendFileSync("reports/live-requests.jsonl", JSON.stringify({ ts: new Date().toISOString(), provider: "anthropic", method: "POST", path: "/v1/messages", status: 200, est_cost_usd: 0.0007, note: `example citations/citations_stream.ts ${MODEL}` }) + "\n");