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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//! **The live tail** (yog's `docs/REMOTE.md` §3, §9.7) — the follow-class
//! read's answer, and the one reply whose N is greater than one.
//!
//! **A frame is an APPEND, and the seat holds the accumulation** (REMOTE §5.5,
//! PROTOCOL 2). One rule, with no flag and no case:
//!
//! > Absorb every frame of a read, in order, onto an empty fold. What you hold
//! > after the last frame you have received is what you paint.
//!
//! [`Stream::absorb`] is that operation, and it is the engine's own — the two
//! ends agree by contract (`fold(a).absorb(fold(b)) == fold(a ++ b)` on any
//! line boundary) rather than by coincidence. A read starts holding nothing
//! and the engine's reader opens at byte zero, so the FIRST frame of any read
//! is the whole tail so far: a seat that dropped a connection mid-answer
//! re-asks and is whole on its first frame, with nothing to reconcile. The
//! one-shot answer is the same rule with one frame in it.
//!
//! **The wire spelling did not move, which is the hazard.** The body is still
//! `{"delta", "text", "thinking"}`; what changed is that the two text fields
//! are the *appended* part rather than the accumulated one. Nothing in a field
//! signature can see that, so this paragraph is the record.
//!
//! **The frame carries the tool window beside the prose** (REMOTE §5.5,
//! PROTOCOL 15), by the same rule: concatenate the lists of a read's frames in
//! order. [`window`] holds it, and the one thing to know here is that the two
//! accumulate together — a frame is *what landed*, and what landed is some
//! prose, some window, or both.
//!
//! **Absence is a reading in all three prose fields.** `text` and `thinking` are
//! absent until a delta of that kind has landed — which is not the same claim
//! as an empty string — and `delta` is absent while the stream has produced
//! nothing at all, which under an open response file is exactly *waiting for
//! the API*. A seat that read those as empty strings would paint "the model
//! answered nothing" over "the model has not answered yet".
use ;
use fields;
/// The tool window the fold carries beside the prose.
use Window;
/// This reply's kind token. One word for the query and the reply alike, on the
/// engine's side; this end only ever reads it.
pub const KIND: &str = "follow";
/// What one read of the tail says — every fact off one pass, so they cannot
/// describe two different mid-write states of one file.
/// Accrete `more` onto an accumulator that may not exist yet. **Absent stays
/// absent** — a stream that has said nothing has said nothing, and an empty
/// `Some("")` would read as *it spoke* to every surface downstream, which is
/// the distinction this module's third paragraph exists to keep.
/// Which kind of content the last delta carried.
///
/// **Rung 3, and this is a deliberate divergence from the engine's own
/// reader**, which refuses an unrecognised token here. The two readers are not
/// doing the same job: the engine's decodes bytes the engine wrote, so a
/// mismatch there means its own codec has drifted and refusing is the
/// diagnosis. This one is the last reader of somebody else's answer, and
/// refusing would throw away an entire accumulated turn to avoid painting one
/// word — the silent drop [`super`]'s policy exists to exclude, at the worst
/// possible moment, which is while the operator is watching the tail move.
const TEXT: &str = "text";
const THINKING: &str = "thinking";
/// The key the fold rides under inside the reply envelope.
const STREAM: &str = "stream";
/// Read the reply: the envelope, then the fold inside it.
pub