How to Build a Harness

5. Streaming a Response

Send a prompt, stream text back token-by-token.

The core of talking to Claude: build params, call the streaming API, process SSE events.

File: packages/ai/src/providers/anthropic.ts L216-467

The production code handles thinking blocks, tool call JSON deltas, usage tracking, and error recovery. The minimal version is:

const anthropicStream = await client.messages.stream({
  model: "claude-sonnet-4-20250514",
  max_tokens: 8192,
  system: "You are a coding assistant.",
  messages: convertedMessages,
  tools: convertedTools,
  stream: true,
});

The stream emits these SSE event types (relevant to a minimal harness):

Event Meaning
message_start New response started
content_block_start (type text) Text block starting
content_block_start (type tool_use) Tool call starting
content_block_delta (text_delta) Text chunk
content_block_delta (input_json_delta) Tool arguments streaming
content_block_stop Block finished
message_delta Stop reason revealed

File: packages/ai/src/providers/anthropic.ts L285-441

for await (const event of anthropicStream) {
  if (event.type === "content_block_start") {
    if (event.content_block.type === "text") {
      // New text block
    } else if (event.content_block.type === "tool_use") {
      // New tool call -- capture id and name
    }
  } else if (event.type === "content_block_delta") {
    if (event.delta.type === "text_delta") {
      // Append text chunk to current block
    } else if (event.delta.type === "input_json_delta") {
      // Accumulate tool arguments JSON
    }
  } else if (event.type === "message_delta") {
    if (event.delta.stop_reason) {
      // "end_turn" -> stop, "tool_use" -> execute tools
    }
  }
}

Open this chapter inside the full course