claude-stream 0.1.0

Parse Anthropic's Server-Sent Events stream into typed events. No SDK dependency — feed it bytes, get back message_start, content_block_delta, etc.
Documentation

claude-stream

crates.io docs.rs License: MIT

Parse Anthropic's Server-Sent Events stream into typed events. No SDK dependency, no async runtime lock-in — feed it bytes, drain typed events.

[dependencies]
claude-stream = "0.1"

Why

There is no official Rust SDK for Anthropic. Community SDKs exist but couple you to a particular HTTP client + async runtime. claude-stream is the smallest possible primitive: an incremental SSE parser that knows the Anthropic event vocabulary (message_start, content_block_delta, tool_use, thinking, ping, …) and produces a typed Event enum. Wire it to whatever transport you already have.

Quick start

use claude_stream::{Event, EventParser, Delta};

let mut parser = EventParser::new();

// As bytes arrive (sync or async — your call):
loop {
    let chunk: &[u8] = your_transport_read().await;
    if chunk.is_empty() { break; }
    parser.feed(chunk);

    while let Some(event) = parser.next_event().unwrap() {
        match event {
            Event::MessageStart { message } => println!("started {}", message.id),
            Event::ContentBlockDelta { delta: Delta::TextDelta { text }, .. } => {
                print!("{text}");  // streaming text
            }
            Event::MessageStop => break,
            _ => {}
        }
    }
}
# fn your_transport_read() -> std::pin::Pin<Box<dyn std::future::Future<Output = &'static [u8]> + Send>> { Box::pin(async { &[][..] }) }

For the simple "I have the full body in a String" case:

use claude_stream::{Event, EventParser};

let body: &str = /* full SSE response */ "";
let events = EventParser::parse_all(body);

Events covered

  • message_start — message shell + initial usage
  • content_block_start — text / tool_use / thinking / server_tool_use
  • content_block_delta — text_delta / input_json_delta / thinking_delta / signature_delta
  • content_block_stop
  • message_delta — stop_reason, cumulative usage
  • message_stop
  • ping
  • error

Unknown event types fall through to Event::Unknown so the parser never panics on a new variant Anthropic adds.

What it doesn't do

  • Doesn't make HTTP requests. Use reqwest, hyper, or whatever you have.
  • Doesn't reassemble streaming tool_use.input partial JSON into a final serde_json::Value. Concatenate the partial_json strings yourself, then serde_json::from_str once the block stops.
  • Doesn't validate against any schema. Forward-compat over strictness.

License

MIT