Skip to content

sendStream / streaming is buffered, not incremental (anthropic driver) #353

Description

@zmaril

Summary

Session::sendStream in the Python and PHP bindings (and the underlying streaming path) does not stream incrementally. The whole reply is produced, then all deltas are delivered at once after the full generation completes.

Repro (measured)

Python binding, 120-word live generation:

chunks=9  total_chars=784
first chunk at 4.69s, last at 4.69s, spread=0.00s

Nine chunks, all arriving in the same instant after a ~4.7s wait. Same behavior in the PHP binding (10 deltas, 845 chars, all at once). The offline faux path does space its chunks, which masks this in offline testing.

Root cause

Not the bindings — the Rust core buffers the entire HTTP response before parsing SSE. crates/pidgin-ai/src/api/anthropic/driver.rs:

"produces the whole event sequence eagerly from a fully-buffered response body; inter-chunk timing is re-presented at the binding edge."

parse_sse_stream(&response.body, ...) runs only after the full body is in hand, so no binding-level change can make it incremental.

Impact

A chat UI built on sendStream (e.g. the binding demos) shows nothing until the full reply lands, then dumps it — not token-by-token. Purely a UX/latency issue; correctness is fine.

Suggested direction

Make the anthropic driver consume the SSE stream incrementally (feed the parser as bytes arrive) rather than buffering, and surface deltas through the transport seam as they come. Larger than a binding tweak — it's a transport/driver change.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions