1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//! The protocol-independent half of the stream pipeline.
//!
//! Both wire protocols decode into their own event type and reassemble it with their own
//! accumulator, but everything between those two facts is identical: append an
//! end-of-transport sentinel, thread the accumulator through the stream, flatten each batch,
//! and yield an accumulator error in band as an `Err` item.
//!
//! Nothing here names either protocol. Each accumulator module implements
//! [`EventAccumulator`] for its own type, so a third protocol is a new module rather than an
//! edit to this one.
//!
//! That machinery is subtle enough to be worth having exactly once. The sentinel in
//! particular is a fix for a real defect — servers that stop sending without ever reporting
//! why would otherwise leave their content stranded in the accumulator's buffers and yield a
//! silently empty response — and a second transcription of it is a second place for that
//! defect to come back.
use Pin;
use ;
use crateResult;
use crateStreamEvent;
/// Reassembles one protocol's streaming events into [`StreamEvent`]s.
///
/// The two implementors are [`StreamAccumulator`](super::StreamAccumulator) for OpenAI chat
/// completions and [`AnthropicAccumulator`](super::AnthropicAccumulator) for Anthropic
/// messages. Both hold the same contract: [`Self::process`] never returns
/// [`StreamEvent::Finish`], and [`Self::finish`] always ends with exactly one.
/// Drives `events` through `accumulator`, yielding the [`StreamEvent`]s it produces.
///
/// The `None` appended after the event stream is the explicit end-of-transport signal, and
/// it is what emits the terminating [`StreamEvent::Finish`], so every stream reports how it
/// ended even when the server never said.
///
/// An accumulator error is yielded as an `Err` item and does not itself close the stream;
/// callers propagate it with `?` and stop pulling, which is what ends the response.