@askalf/dario 5.5.86 → 5.5.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  <p><strong>One local endpoint. Every AI tool you own. The subscription you already pay for.</strong></p>
20
20
 
21
- <sub><code>npm i -g @askalf/dario</code> · <strong>0</strong> runtime deps · <a href="https://www.npmjs.com/package/@askalf/dario">SLSA-attested</a> every release · nothing phones home · ~26k lines you can read in a weekend · independent, unofficial, third-party (<a href="DISCLAIMER.md">DISCLAIMER.md</a>)</sub>
21
+ <sub><code>npm i -g @askalf/dario</code> · <strong>0</strong> runtime deps · <a href="https://www.npmjs.com/package/@askalf/dario">SLSA-attested</a> every release · nothing phones home · ~28k lines you can read in a weekend · independent, unofficial, third-party (<a href="DISCLAIMER.md">DISCLAIMER.md</a>)</sub>
22
22
 
23
23
  <sub>Part of <a href="#own-your-stack"><strong>Own Your Stack</strong></a> — 12 open tools for owning your AI infra: <a href="https://github.com/askalf/truecopy">truecopy</a> · <a href="https://github.com/askalf/strongroom">strongroom</a> · <a href="https://github.com/askalf/fieldpass">fieldpass</a> · <a href="https://github.com/askalf/plumbline">plumbline</a> · <a href="#own-your-stack">full family ↓</a></sub>
24
24
 
@@ -0,0 +1,522 @@
1
+ /**
2
+ * Anthropic Messages ⇄ OpenAI Responses translator, ported into dario so that a
3
+ * ChatGPT-subscription (codex) account can serve Anthropic-shape `/v1/messages`
4
+ * requests. It was developed and live-probe-validated outside this repo, then
5
+ * copied here with no change to any translation logic. The only port edits: the
6
+ * Anthropic-side types and the reasoning-effort thresholds it used to import
7
+ * from a sibling module are inlined below, making this file self-contained.
8
+ */
9
+ /**
10
+ * Anthropic Messages ⇄ OpenAI *Responses API* translation.
11
+ *
12
+ * Targets the Responses API (not Chat Completions): the ChatGPT Codex
13
+ * backend speaks Responses, and reasoning models reject tools on
14
+ * chat/completions. This
15
+ * module targets the newer `/v1/responses` shape, which is REQUIRED for
16
+ * the reasoning-model + function-tools combination: gpt-5.6-sol (and the
17
+ * o-series) REJECT function tools together with reasoning on
18
+ * `/chat/completions`, but accept both on `/responses`. That combination
19
+ * is exactly Claude Code's case — CC always sends its 30+ tools and often
20
+ * has thinking enabled — so this is the path dario 5.1 needs to drive a
21
+ * reasoning model as a Claude backend.
22
+ *
23
+ * Pure data transforms — no network, no fs, no timers. A later wiring
24
+ * phase will translate an inbound Messages request with
25
+ * `anthropicToResponsesRequest`, POST it to `{baseUrl}/responses`, and
26
+ * translate the reply back with `responsesToAnthropicResponse`
27
+ * (non-streaming) — streaming is deferred (see the P0.6 stub below).
28
+ *
29
+ * The Responses shape is item-array based and sits closer to Anthropic's
30
+ * block model than chat completions does. Field names CONFIRMED against
31
+ * the OpenAI SDK type sources (openai-python `types/responses/*`); the
32
+ * shapes that differ from the chat-completions translator are called out
33
+ * where they occur:
34
+ *
35
+ * - system → top-level `instructions` (a string), NOT a role message.
36
+ * - messages → `input[]` items. User text/images become one message
37
+ * item with `input_text` / `input_image` parts (image_url is a bare
38
+ * string here, not `{url}`). Assistant text replays as a message item
39
+ * with a plain string. Assistant tool_use blocks become top-level
40
+ * `function_call` items; user tool_result blocks become top-level
41
+ * `function_call_output` items. Anthropic `tool_use_id` ↔ Responses
42
+ * `call_id` threads the two.
43
+ * - tools → FLATTENED function tools `{type,name,description,
44
+ * parameters}` (chat nests these under `.function`).
45
+ * - tool_choice forced form → FLATTENED `{type:'function', name}`
46
+ * (chat uses `{type:'function', function:{name}}`).
47
+ * - thinking → `reasoning:{effort}` (+ `summary:'auto'` so a reasoning
48
+ * summary comes back and can round-trip to a thinking block). Unlike
49
+ * chat completions, reasoning + tools together is ALLOWED here — the
50
+ * whole reason this module exists.
51
+ * - max_tokens → `max_output_tokens`; `store:false` (stateless — dario
52
+ * keeps no server-side conversation).
53
+ *
54
+ * Deliberate lossy edges (documented at the relevant function):
55
+ * - `cache_control` is dropped silently (no Responses analog).
56
+ * - Reasoning models reject sampling params: `temperature`/`top_p` are
57
+ * omitted whenever reasoning is enabled.
58
+ * - assistant `thinking` / `redacted_thinking` blocks are dropped from
59
+ * the OUTBOUND request (no faithful inbound slot; encrypted_content
60
+ * round-tripping is a later concern). Reasoning that the model
61
+ * returns IS surfaced (as thinking blocks) on the response side.
62
+ * - Anthropic server tools (entries without `input_schema`) are skipped.
63
+ * - images inside `tool_result` content are dropped
64
+ * (`function_call_output.output` is a string); sibling text survives.
65
+ */
66
+ export interface AnthropicTextBlock {
67
+ type: 'text';
68
+ text: string;
69
+ cache_control?: unknown;
70
+ }
71
+ export interface AnthropicImageBlock {
72
+ type: 'image';
73
+ source: {
74
+ type: 'base64';
75
+ media_type: string;
76
+ data: string;
77
+ } | {
78
+ type: 'url';
79
+ url: string;
80
+ };
81
+ cache_control?: unknown;
82
+ }
83
+ export interface AnthropicToolUseBlock {
84
+ type: 'tool_use';
85
+ id: string;
86
+ name: string;
87
+ input: Record<string, unknown>;
88
+ cache_control?: unknown;
89
+ }
90
+ export interface AnthropicToolResultBlock {
91
+ type: 'tool_result';
92
+ tool_use_id: string;
93
+ content?: string | Array<Record<string, unknown>>;
94
+ is_error?: boolean;
95
+ cache_control?: unknown;
96
+ }
97
+ export type AnthropicContentBlock = AnthropicTextBlock | AnthropicImageBlock | AnthropicToolUseBlock | AnthropicToolResultBlock | {
98
+ type: string;
99
+ [key: string]: unknown;
100
+ };
101
+ export interface AnthropicMessage {
102
+ role: 'user' | 'assistant';
103
+ content: string | AnthropicContentBlock[];
104
+ }
105
+ export interface AnthropicTool {
106
+ name: string;
107
+ description?: string;
108
+ input_schema?: Record<string, unknown>;
109
+ /** Server-tool discriminator (`bash_20250124`, …). Untranslatable. */
110
+ type?: string;
111
+ cache_control?: unknown;
112
+ }
113
+ export interface AnthropicToolChoice {
114
+ type: 'auto' | 'any' | 'tool' | 'none';
115
+ name?: string;
116
+ disable_parallel_tool_use?: boolean;
117
+ }
118
+ export interface AnthropicThinkingConfig {
119
+ type: 'enabled' | 'disabled';
120
+ budget_tokens?: number;
121
+ }
122
+ export interface AnthropicRequest {
123
+ model: string;
124
+ system?: string | AnthropicTextBlock[];
125
+ messages: AnthropicMessage[];
126
+ tools?: AnthropicTool[];
127
+ tool_choice?: AnthropicToolChoice;
128
+ max_tokens?: number;
129
+ temperature?: number;
130
+ top_p?: number;
131
+ stop_sequences?: string[];
132
+ stream?: boolean;
133
+ thinking?: AnthropicThinkingConfig;
134
+ metadata?: {
135
+ user_id?: string | null;
136
+ };
137
+ }
138
+ export type AnthropicStopReason = 'end_turn' | 'max_tokens' | 'tool_use' | 'stop_sequence';
139
+ export interface AnthropicUsage {
140
+ input_tokens: number;
141
+ output_tokens: number;
142
+ }
143
+ export interface AnthropicResponse {
144
+ id: string;
145
+ type: 'message';
146
+ role: 'assistant';
147
+ model: string;
148
+ content: Array<AnthropicTextBlock | AnthropicToolUseBlock>;
149
+ stop_reason: AnthropicStopReason | null;
150
+ stop_sequence: string | null;
151
+ usage: AnthropicUsage;
152
+ }
153
+ /**
154
+ * Thinking-budget → reasoning_effort thresholds. Claude Code's thinking
155
+ * tiers land at ~4k ("think"), ~10k ("think hard") and 31999
156
+ * ("ultrathink") budget_tokens, so the cut points sit between those
157
+ * tiers:
158
+ *
159
+ * budget_tokens ≤ 4096 → 'low'
160
+ * 4096 < budget_tokens ≤ 16384 → 'medium'
161
+ * budget_tokens > 16384 → 'high'
162
+ *
163
+ * `thinking` absent, disabled, or without a positive budget → no
164
+ * `reasoning_effort` in the output (upstream default applies).
165
+ */
166
+ export declare const REASONING_EFFORT_LOW_MAX = 4096;
167
+ export declare const REASONING_EFFORT_MEDIUM_MAX = 16384;
168
+ export interface AnthropicThinkingBlock {
169
+ type: 'thinking';
170
+ thinking: string;
171
+ }
172
+ export type ResponsesAnthropicContentBlock = AnthropicTextBlock | AnthropicToolUseBlock | AnthropicThinkingBlock;
173
+ /** AnthropicResponse but with a content union that admits thinking blocks. */
174
+ export type AnthropicResponseWithThinking = Omit<AnthropicResponse, 'content'> & {
175
+ content: ResponsesAnthropicContentBlock[];
176
+ };
177
+ export interface ResponsesInputText {
178
+ type: 'input_text';
179
+ text: string;
180
+ }
181
+ /** Responses `input_image`: image_url is a bare string (URL or data URI). */
182
+ export interface ResponsesInputImage {
183
+ type: 'input_image';
184
+ image_url: string;
185
+ detail?: 'auto' | 'low' | 'high';
186
+ }
187
+ export type ResponsesInputContentPart = ResponsesInputText | ResponsesInputImage;
188
+ /** A role message input item (the "EasyInputMessage" form). */
189
+ export interface ResponsesInputMessage {
190
+ role: 'user' | 'assistant' | 'system' | 'developer';
191
+ content: string | ResponsesInputContentPart[];
192
+ }
193
+ /** Assistant tool call, replayed as a top-level input item. */
194
+ export interface ResponsesFunctionCallItem {
195
+ type: 'function_call';
196
+ call_id: string;
197
+ name: string;
198
+ arguments: string;
199
+ id?: string;
200
+ }
201
+ /** Tool result, fed back as a top-level input item (output is a string). */
202
+ export interface ResponsesFunctionCallOutputItem {
203
+ type: 'function_call_output';
204
+ call_id: string;
205
+ output: string;
206
+ }
207
+ export type ResponsesInputItem = ResponsesInputMessage | ResponsesFunctionCallItem | ResponsesFunctionCallOutputItem;
208
+ /** Flattened function tool — NOT nested under `.function` like chat. */
209
+ export interface ResponsesFunctionTool {
210
+ type: 'function';
211
+ name: string;
212
+ description?: string;
213
+ parameters: Record<string, unknown>;
214
+ strict?: boolean | null;
215
+ }
216
+ export type ResponsesToolChoice = 'auto' | 'none' | 'required' | {
217
+ type: 'function';
218
+ name: string;
219
+ };
220
+ export interface ResponsesReasoningConfig {
221
+ effort?: 'low' | 'medium' | 'high';
222
+ summary?: 'auto' | 'concise' | 'detailed';
223
+ }
224
+ export interface ResponsesRequest {
225
+ model: string;
226
+ input: ResponsesInputItem[];
227
+ instructions?: string;
228
+ tools?: ResponsesFunctionTool[];
229
+ tool_choice?: ResponsesToolChoice;
230
+ parallel_tool_calls?: boolean;
231
+ reasoning?: ResponsesReasoningConfig;
232
+ max_output_tokens?: number;
233
+ temperature?: number;
234
+ top_p?: number;
235
+ stream?: boolean;
236
+ store?: boolean;
237
+ }
238
+ export interface ResponsesOutputText {
239
+ type: 'output_text';
240
+ text: string;
241
+ annotations?: unknown[];
242
+ }
243
+ export interface ResponsesRefusal {
244
+ type: 'refusal';
245
+ refusal: string;
246
+ }
247
+ export type ResponsesMessageContentPart = ResponsesOutputText | ResponsesRefusal | {
248
+ type: string;
249
+ [key: string]: unknown;
250
+ };
251
+ export interface ResponsesMessageItem {
252
+ type: 'message';
253
+ id?: string;
254
+ role: 'assistant';
255
+ status?: string;
256
+ content?: ResponsesMessageContentPart[];
257
+ }
258
+ /** Response-side function_call: carries BOTH `id` (item id) and `call_id`. */
259
+ export interface ResponsesResponseFunctionCall {
260
+ type: 'function_call';
261
+ id?: string;
262
+ call_id?: string;
263
+ name?: string;
264
+ arguments?: string;
265
+ status?: string;
266
+ }
267
+ export interface ResponsesReasoningSummaryPart {
268
+ type: 'summary_text';
269
+ text: string;
270
+ }
271
+ export interface ResponsesReasoningContentPart {
272
+ type: 'reasoning_text';
273
+ text: string;
274
+ }
275
+ export interface ResponsesReasoningItem {
276
+ type: 'reasoning';
277
+ id?: string;
278
+ summary?: ResponsesReasoningSummaryPart[];
279
+ content?: ResponsesReasoningContentPart[];
280
+ encrypted_content?: string | null;
281
+ status?: string;
282
+ }
283
+ export type ResponsesOutputItem = ResponsesMessageItem | ResponsesResponseFunctionCall | ResponsesReasoningItem | {
284
+ type: string;
285
+ [key: string]: unknown;
286
+ };
287
+ export interface ResponsesUsage {
288
+ input_tokens?: number;
289
+ input_tokens_details?: {
290
+ cached_tokens?: number;
291
+ cache_write_tokens?: number;
292
+ };
293
+ output_tokens?: number;
294
+ output_tokens_details?: {
295
+ reasoning_tokens?: number;
296
+ };
297
+ total_tokens?: number;
298
+ }
299
+ export interface ResponsesResponse {
300
+ id?: string;
301
+ object?: string;
302
+ model?: string;
303
+ /** completed | failed | in_progress | cancelled | queued | incomplete (Azure also: requires_action). */
304
+ status?: string;
305
+ output?: ResponsesOutputItem[];
306
+ output_text?: string;
307
+ incomplete_details?: {
308
+ reason?: string;
309
+ } | null;
310
+ error?: {
311
+ code?: string;
312
+ message?: string;
313
+ } | null;
314
+ usage?: ResponsesUsage | null;
315
+ }
316
+ /**
317
+ * Extra max_output_tokens reserved for reasoning tokens, by effort, so the
318
+ * client's intended visible-output budget survives on a reasoning model
319
+ * (max_output_tokens caps reasoning + output combined on the Responses API).
320
+ */
321
+ export declare const REASONING_HEADROOM: {
322
+ readonly low: 12000;
323
+ readonly medium: 25000;
324
+ readonly high: 50000;
325
+ };
326
+ /** gpt-5.x / o-series output ceiling (tokens). */
327
+ export declare const RESPONSES_MAX_OUTPUT_CAP = 128000;
328
+ export interface AnthropicToResponsesOptions {
329
+ /**
330
+ * `reasoning.summary` value when reasoning is enabled. Default 'auto':
331
+ * without a summary, the reasoning items come back with an empty
332
+ * `summary[]` and there is nothing to round-trip into a thinking block.
333
+ * Pass `null` to omit `summary` entirely.
334
+ */
335
+ reasoningSummary?: 'auto' | 'concise' | 'detailed' | null;
336
+ /**
337
+ * `store`. Default false — dario is stateless and keeps no server-side
338
+ * conversation. Set true only if a caller wants OpenAI-side retention.
339
+ */
340
+ store?: boolean;
341
+ }
342
+ /**
343
+ * Translate an Anthropic Messages request into an OpenAI Responses
344
+ * request body for `{baseUrl}/responses`.
345
+ *
346
+ * Anthropic `input_schema` is already JSON Schema, which is what the
347
+ * Responses `parameters` field expects — it passes through unchanged.
348
+ * Tool entries without an `input_schema` (Anthropic server tools such as
349
+ * `web_search_20250305`) have no function-tool equivalent and are
350
+ * skipped. `cache_control` is dropped wherever it appears.
351
+ */
352
+ export declare function anthropicToResponsesRequest(body: AnthropicRequest, targetModel: string, options?: AnthropicToResponsesOptions): ResponsesRequest;
353
+ /**
354
+ * Translate a non-streaming Responses reply into an Anthropic Messages
355
+ * response. `requestModel` is echoed back as `model` so the client sees
356
+ * the model it asked for, not the upstream alias. Output items are walked
357
+ * in order:
358
+ * - message → its `output_text` parts become text blocks; a
359
+ * `refusal` part surfaces as a text block so the client
360
+ * sees why the turn produced no content.
361
+ * - function_call → a tool_use block, id = `call_id` (Anthropic threads
362
+ * the tool_result back on this id), input = parsed
363
+ * `arguments` (bad JSON → `{}`).
364
+ * - reasoning → a thinking block IF it carries summary/reasoning
365
+ * text; an empty reasoning item is dropped.
366
+ * Other item types (web_search_call, code_interpreter_call, …) are
367
+ * dropped. If nothing produced content but `output_text` is present, it
368
+ * is used as a single text block fallback.
369
+ */
370
+ export declare function responsesToAnthropicResponse(resp: ResponsesResponse, requestModel: string): AnthropicResponseWithThinking;
371
+ /**
372
+ * Anthropic SSE event objects this translator emits. A superset of
373
+ * The Anthropic stream-event shape: content blocks and deltas
374
+ * also admit `thinking` / `thinking_delta` (the Responses API can stream
375
+ * reasoning, which chat completions cannot).
376
+ */
377
+ export type ResponsesAnthropicStreamEvent = {
378
+ type: 'message_start';
379
+ message: AnthropicResponseWithThinking;
380
+ } | {
381
+ type: 'content_block_start';
382
+ index: number;
383
+ content_block: {
384
+ type: 'text';
385
+ text: string;
386
+ } | {
387
+ type: 'thinking';
388
+ thinking: string;
389
+ } | {
390
+ type: 'tool_use';
391
+ id: string;
392
+ name: string;
393
+ input: Record<string, unknown>;
394
+ };
395
+ } | {
396
+ type: 'content_block_delta';
397
+ index: number;
398
+ delta: {
399
+ type: 'text_delta';
400
+ text: string;
401
+ } | {
402
+ type: 'thinking_delta';
403
+ thinking: string;
404
+ } | {
405
+ type: 'input_json_delta';
406
+ partial_json: string;
407
+ };
408
+ } | {
409
+ type: 'content_block_stop';
410
+ index: number;
411
+ } | {
412
+ type: 'message_delta';
413
+ delta: {
414
+ stop_reason: AnthropicStopReason;
415
+ stop_sequence: null;
416
+ };
417
+ usage: {
418
+ output_tokens: number;
419
+ input_tokens?: number;
420
+ };
421
+ } | {
422
+ type: 'message_stop';
423
+ };
424
+ /**
425
+ * One parsed Responses SSE event — a typed superset of the fields this
426
+ * translator consumes. Every event carries a `type`; the rest are present
427
+ * only on the events that use them.
428
+ */
429
+ export interface ResponsesStreamEvent {
430
+ type: string;
431
+ sequence_number?: number;
432
+ /** created | in_progress | completed | incomplete | failed carry a full response. */
433
+ response?: ResponsesResponse;
434
+ /** output_item.added | output_item.done carry the item. */
435
+ item?: ResponsesOutputItem;
436
+ /** Index of the item within `response.output` — the field is `output_index`. */
437
+ output_index?: number;
438
+ item_id?: string;
439
+ content_index?: number;
440
+ summary_index?: number;
441
+ /** Text / argument / reasoning fragment on `*.delta` events. */
442
+ delta?: string;
443
+ /** error event fields. */
444
+ code?: string | null;
445
+ message?: string;
446
+ param?: string | null;
447
+ [key: string]: unknown;
448
+ }
449
+ export interface ResponsesStreamTranslatorOptions {
450
+ /** Model echoed in message_start. Defaults to the created event's `response.model`. */
451
+ requestModel?: string;
452
+ }
453
+ export interface ResponsesStreamTranslator {
454
+ /** Feed one parsed Responses event; returns the Anthropic events it produced. */
455
+ push(event: ResponsesStreamEvent): ResponsesAnthropicStreamEvent[];
456
+ /** Signal end-of-stream; returns the closing events. Idempotent. */
457
+ end(): ResponsesAnthropicStreamEvent[];
458
+ }
459
+ /**
460
+ * Build a streaming translator from parsed OpenAI Responses events to
461
+ * Anthropic SSE event objects. Same interface + discipline as
462
+ * `openAIStreamToAnthropicSSE`: `push(event)` / `end()`, exactly one
463
+ * content block open at a time, strictly increasing indices, event name
464
+ * === data.type. Callers parse the upstream SSE themselves
465
+ * (`parseResponsesSSEEvent` / `createResponsesSSEParser`), push each
466
+ * event, and serialize the returned events (`formatResponsesAnthropicSSE`
467
+ * produces the wire framing).
468
+ *
469
+ * - message_start fires once, on the first event, with an empty-content
470
+ * envelope and usage 0/0 (usage is known only at response.completed).
471
+ * - A `function_call` item opens a tool_use block on
472
+ * output_item.added; a `reasoning` item opens a thinking block there
473
+ * (eager, so block order matches upstream item order even before the
474
+ * first summary fragment — a reasoning item that streams no text thus
475
+ * yields an empty thinking block bracketed by start/stop, which
476
+ * Anthropic clients tolerate). A `message` item opens its text block
477
+ * lazily on the first output_text.delta.
478
+ * - output_item.done closes that item's block; response.completed (or
479
+ * .incomplete / .failed, or a stream `error`) closes any open block
480
+ * and emits message_delta (stop_reason + usage) + message_stop, then
481
+ * marks the stream ended.
482
+ * - `end()` repeats the closing sequence only if no terminal event was
483
+ * seen (a cut-off stream), and is otherwise idempotent — so callers
484
+ * can always call it safely.
485
+ *
486
+ * stop_reason: a tool call anywhere → 'tool_use'; else an `incomplete`
487
+ * status → 'max_tokens' (content-filter incompletion → 'end_turn'); else
488
+ * 'end_turn' (via the shared deriveStopReason).
489
+ */
490
+ export declare function responsesStreamToAnthropicSSE(options?: ResponsesStreamTranslatorOptions): ResponsesStreamTranslator;
491
+ /**
492
+ * Serialize one emitted Anthropic stream event into SSE wire framing:
493
+ * `event: <type>\ndata: <json>\n\n` — the same `event:`/`data:` pairing
494
+ * dario's streaming path produces. Structural twin of
495
+ * Anthropic SSE formatting, widened to this module's
496
+ * thinking-aware event union.
497
+ */
498
+ export declare function formatResponsesAnthropicSSE(event: ResponsesAnthropicStreamEvent): string;
499
+ /**
500
+ * Parse one Responses SSE record's `event:` and `data:` lines into an
501
+ * event object. Unlike chat completions (data-only), Responses SSE pairs
502
+ * an `event: <type>` line with a `data: <json>` line; the JSON already
503
+ * carries a matching `type`, so `dataLine` alone is usually enough — the
504
+ * `eventLine` is used only to backfill `type` if the JSON somehow omits
505
+ * it. Returns null for keep-alive/comment lines, `data: [DONE]`, and
506
+ * unparseable payloads. Callers that own real SSE framing (multi-line
507
+ * buffering, CRLF, cross-chunk boundaries) should use
508
+ * `createResponsesSSEParser` instead.
509
+ */
510
+ export declare function parseResponsesSSEEvent(eventLine: string | undefined, dataLine: string): ResponsesStreamEvent | null;
511
+ /**
512
+ * Buffered Responses SSE parser: feed raw stream chunks (which do NOT
513
+ * align to event boundaries), get back the complete events decoded so
514
+ * far. Records are separated by a blank line (`\n\n` or `\r\n\r\n`);
515
+ * multiple `data:` lines in one record join with `\n` per the SSE spec.
516
+ * Call `flush()` at end-of-stream to parse any trailing record that was
517
+ * not blank-line terminated. Pure and offline-testable.
518
+ */
519
+ export declare function createResponsesSSEParser(): {
520
+ push(chunk: string): ResponsesStreamEvent[];
521
+ flush(): ResponsesStreamEvent[];
522
+ };