@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 +1 -1
- package/dist/anthropic-responses-translate.d.ts +522 -0
- package/dist/anthropic-responses-translate.js +839 -0
- package/dist/codex-backend.d.ts +34 -2
- package/dist/codex-backend.js +141 -15
- package/dist/provider-adapter.d.ts +11 -4
- package/dist/provider-adapter.js +11 -6
- package/dist/proxy.js +2 -2
- package/package.json +1 -1
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 · ~
|
|
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
|
+
};
|