@alvin0/ai-agent-sdk-protocol-responses 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 alvin0 (chaulamdinhai) <chaulamdinhai@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # @alvin0/ai-agent-sdk-protocol-responses
2
+
3
+ Runtime: **Universal** (Edge/Worker, browser, Deno, Bun, and Node).
4
+
5
+ ```sh
6
+ pnpm add @alvin0/ai-agent-sdk-core @alvin0/ai-agent-sdk-protocol-responses
7
+ ```
8
+
9
+ Universal OpenAI Responses/Codex wire schema, request serializer, stream translator, and dialect. It owns no endpoint, credentials, fetch implementation, filesystem access, or Node.js APIs.
10
+
11
+ ```ts
12
+ import { openAiResponsesProtocol } from '@alvin0/ai-agent-sdk-protocol-responses'
13
+ ```
14
+
15
+ Composition: `provider-author.protocol`. Lifecycle: `inert-value`; select it in
16
+ `createRuntimeHttpProvider()` without any startup or cleanup obligation.
17
+
18
+ The only runtime dependency is `@alvin0/ai-agent-sdk-core`.
@@ -0,0 +1,363 @@
1
+ import { GenerateOptions, StreamChunk, UsageCounters } from "@alvin0/ai-agent-sdk-core";
2
+ import { ModelTarget, ResolvedModelInfo } from "@alvin0/ai-agent-sdk-core/provider";
3
+ //#region src/contract.d.ts
4
+ /** The request fields a pure wire protocol is allowed to inspect. */
5
+ interface ProtocolRequest {
6
+ readonly options: GenerateOptions;
7
+ readonly maxTokens: number;
8
+ }
9
+ /** One decoded SSE event, expressed without depending on an HTTP transport. */
10
+ interface ProtocolSseEvent {
11
+ readonly event: string | undefined;
12
+ readonly data: string;
13
+ }
14
+ /** Protocol-internal chunks may carry a partial untrusted usage report. */
15
+ type ProtocolStreamChunk = Exclude<StreamChunk, {
16
+ readonly type: 'usage';
17
+ }> | {
18
+ readonly type: 'usage';
19
+ readonly usage: UsageCounters;
20
+ };
21
+ /** Structural protocol contract implemented without importing provider-http. */
22
+ interface ProtocolDefinition<Dialect> {
23
+ readonly id: string;
24
+ readonly defaultDialect: Dialect;
25
+ endpointPath(request: ProtocolRequest, dialect: Dialect): string;
26
+ protocolHeaders?(dialect: Dialect): Record<string, string>;
27
+ serialize(request: ProtocolRequest, dialect: Dialect): unknown | Promise<unknown>;
28
+ translate(events: AsyncIterable<ProtocolSseEvent>, request: ProtocolRequest, displayName: string): AsyncGenerator<ProtocolStreamChunk>;
29
+ }
30
+ //#endregion
31
+ //#region src/wire.d.ts
32
+ /**
33
+ * The OpenAI Responses API wire shapes, shared by the `openai` and `codex`
34
+ * providers.
35
+ *
36
+ * Both speak the same protocol — Codex's own client dropped Chat Completions
37
+ * entirely (`wire_api = "chat"` is a hard error there now) — so the dialect
38
+ * differences are narrow enough to express as a profile rather than a second
39
+ * implementation. What actually differs is the base URL, the auth headers, and
40
+ * whether sampling knobs are accepted; see {@link ResponsesDialect}.
41
+ *
42
+ * These types never leave this folder.
43
+ *
44
+ * @module ai-agent-sdk/providers/responses/wire
45
+ */
46
+ /** Detail level requested for an input image. */
47
+ type WireImageDetail = 'auto' | 'low' | 'high' | 'original';
48
+ /** One part of a message item's content. */
49
+ type WireContentPart = {
50
+ type: 'input_text';
51
+ text: string;
52
+ } | {
53
+ type: 'input_image';
54
+ image_url: string;
55
+ detail?: WireImageDetail;
56
+ } | {
57
+ type: 'input_image';
58
+ file_id: string;
59
+ detail?: WireImageDetail;
60
+ } | {
61
+ type: 'output_text';
62
+ text: string;
63
+ annotations?: WireTextAnnotation[];
64
+ };
65
+ interface WireTextAnnotation {
66
+ type: 'url_citation';
67
+ url: string;
68
+ title?: string;
69
+ start_index?: number;
70
+ end_index?: number;
71
+ }
72
+ /** One summary paragraph of a reasoning item. */
73
+ interface WireReasoningSummary {
74
+ type: 'summary_text';
75
+ text: string;
76
+ }
77
+ /** One body paragraph of a reasoning item. */
78
+ interface WireReasoningContent {
79
+ type: 'reasoning_text';
80
+ text: string;
81
+ }
82
+ /**
83
+ * An item in the `input` array.
84
+ *
85
+ * Note the shape of the conversation here: this is a FLAT list of items, not a
86
+ * list of messages with nested content. A tool result is its own top-level
87
+ * `function_call_output` item rather than a part inside a user message, and one
88
+ * assistant turn that reasoned, spoke, and called two tools becomes four items.
89
+ * That is the main thing serialization has to get right.
90
+ */
91
+ type WireInputItem = {
92
+ type: 'message';
93
+ role: 'user' | 'assistant' | 'developer' | 'system';
94
+ content: WireContentPart[];
95
+ phase?: 'commentary' | 'final_answer';
96
+ } | {
97
+ type: 'function_call';
98
+ /** Correlates with the matching output item. */
99
+ call_id: string;
100
+ name: string;
101
+ /** JSON-encoded STRING, not an object. */
102
+ arguments: string;
103
+ /** Server-assigned item id, echoed back when known. */
104
+ id?: string;
105
+ } | {
106
+ type: 'function_call_output';
107
+ call_id: string;
108
+ /** Either plain text or structured content items. */
109
+ output: string | WireContentPart[];
110
+ } | {
111
+ type: 'reasoning';
112
+ id?: string;
113
+ summary: WireReasoningSummary[];
114
+ content?: WireReasoningContent[];
115
+ /**
116
+ * Opaque encrypted reasoning, returned when `include` requests it.
117
+ *
118
+ * Echoing it back is what lets the model keep its chain of thought across a
119
+ * tool-use loop; dropping it silently degrades multi-step quality.
120
+ */
121
+ encrypted_content?: string | null;
122
+ } | {
123
+ /** Provider-native web-search item replayed on a later request. */
124
+ type: 'web_search_call';
125
+ id?: string;
126
+ status?: string;
127
+ action?: unknown;
128
+ } | {
129
+ /** Provider-native image-generation item replayed on a later request. */
130
+ type: 'image_generation_call';
131
+ id?: string;
132
+ status?: string;
133
+ result?: string | null;
134
+ };
135
+ /** A function tool, flat rather than nested under a `function` key. */
136
+ interface WireFunctionTool {
137
+ type: 'function';
138
+ name: string;
139
+ description: string;
140
+ strict: boolean;
141
+ parameters: Record<string, unknown>;
142
+ }
143
+ interface WireNativeTool {
144
+ type: string;
145
+ [key: string]: unknown;
146
+ }
147
+ type WireTool = WireFunctionTool | WireNativeTool;
148
+ /** How the model must choose among the offered tools. */
149
+ type WireToolChoice = 'auto' | 'none' | 'required' | {
150
+ type: 'function';
151
+ name: string;
152
+ } | {
153
+ type: string;
154
+ };
155
+ /** Reasoning controls. */
156
+ interface WireReasoning {
157
+ effort?: string;
158
+ summary?: 'auto' | 'concise' | 'detailed' | 'none';
159
+ }
160
+ /** Output text controls. */
161
+ interface WireTextControls {
162
+ format?: WireTextFormat;
163
+ verbosity?: 'low' | 'medium' | 'high';
164
+ }
165
+ type WireTextFormat = {
166
+ type: 'text';
167
+ } | {
168
+ type: 'json_schema';
169
+ name: string;
170
+ schema: Readonly<Record<string, unknown>>;
171
+ strict: true;
172
+ };
173
+ /** The request body. */
174
+ interface WireRequest {
175
+ model: string;
176
+ /** System prompt. Its own field here, not a message item. */
177
+ instructions?: string;
178
+ input: WireInputItem[];
179
+ tools?: WireTool[];
180
+ tool_choice?: WireToolChoice;
181
+ parallel_tool_calls?: boolean;
182
+ reasoning?: WireReasoning;
183
+ text?: WireTextControls;
184
+ /** Whether the provider retains the response server-side. */
185
+ store: boolean;
186
+ stream: boolean;
187
+ /** Extra payloads to include, e.g. `reasoning.encrypted_content`. */
188
+ include?: string[];
189
+ /** Stable key that lets the provider reuse a cached prompt prefix. */
190
+ prompt_cache_key?: string;
191
+ max_output_tokens?: number;
192
+ temperature?: number;
193
+ top_p?: number;
194
+ }
195
+ /** Cached-token breakdown of the input count. */
196
+ interface WireInputTokensDetails {
197
+ /** Portion of `input_tokens` served from cache — a SUBSET, not an addition. */
198
+ cached_tokens?: number;
199
+ /** Codex-backend extension. */
200
+ cache_write_tokens?: number;
201
+ }
202
+ /** Reasoning breakdown of the output count. */
203
+ interface WireOutputTokensDetails {
204
+ reasoning_tokens?: number;
205
+ }
206
+ /** Token accounting as the Responses API reports it. */
207
+ interface WireUsage {
208
+ input_tokens?: number;
209
+ input_tokens_details?: WireInputTokensDetails | null;
210
+ output_tokens?: number;
211
+ output_tokens_details?: WireOutputTokensDetails | null;
212
+ total_tokens?: number;
213
+ }
214
+ /** A completed output item, as `response.output_item.done` delivers it. */
215
+ interface WireOutputItem {
216
+ id?: string;
217
+ type?: string;
218
+ role?: string;
219
+ content?: unknown;
220
+ summary?: unknown;
221
+ encrypted_content?: string | null;
222
+ call_id?: string;
223
+ name?: string;
224
+ arguments?: string;
225
+ phase?: string;
226
+ status?: string;
227
+ action?: unknown;
228
+ result?: string | null;
229
+ }
230
+ /** The error payload in `response.failed` and in HTTP error bodies. */
231
+ interface WireErrorBody {
232
+ type?: string;
233
+ code?: string;
234
+ message?: string;
235
+ }
236
+ /** Why a response stopped short of completion. */
237
+ interface WireIncompleteDetails {
238
+ reason?: string;
239
+ }
240
+ /** The `response` object carried by lifecycle events. */
241
+ interface WireResponse {
242
+ id?: string;
243
+ status?: string;
244
+ usage?: WireUsage | null;
245
+ error?: WireErrorBody | null;
246
+ incomplete_details?: WireIncompleteDetails | null;
247
+ }
248
+ /** One decoded streaming event. */
249
+ interface WireStreamEvent {
250
+ type?: string;
251
+ response?: WireResponse;
252
+ item?: WireOutputItem;
253
+ item_id?: string;
254
+ output_index?: number;
255
+ content_index?: number;
256
+ summary_index?: number;
257
+ delta?: string;
258
+ text?: string;
259
+ partial_image_b64?: string;
260
+ partial_image_index?: number;
261
+ /** Present on a top-level `error` event, which carries its fields inline. */
262
+ code?: string;
263
+ message?: string;
264
+ }
265
+ /**
266
+ * The narrow set of differences between the two endpoints that speak this
267
+ * protocol.
268
+ *
269
+ * Expressed as data rather than as subclasses because the differences are all
270
+ * "send this field or not" — behaviour is identical.
271
+ */
272
+ interface ResponsesDialect {
273
+ /**
274
+ * Whether `temperature` / `top_p` may be sent.
275
+ *
276
+ * The ChatGPT-backed Codex endpoint has no such fields in its request schema,
277
+ * so sending them risks a rejection for no benefit.
278
+ */
279
+ readonly sampling: boolean;
280
+ /** Whether `max_output_tokens` may be sent. */
281
+ readonly maxOutputTokens: boolean;
282
+ /** Whether the endpoint accepts `text.format` JSON Schema controls. */
283
+ readonly structuredOutputs: boolean;
284
+ /** Value for `store`. Codex always sends false. */
285
+ readonly store: boolean;
286
+ /** Values for `include`. */
287
+ readonly include: readonly string[];
288
+ /** Whether to ask for reasoning summaries, and how detailed. */
289
+ readonly reasoningSummary?: 'auto' | 'concise' | 'detailed';
290
+ /** Whether assistant message phase may be replayed on input. */
291
+ readonly messagePhase?: boolean;
292
+ /**
293
+ * Stable key letting the provider reuse a cached prompt prefix across turns.
294
+ *
295
+ * A dialect knob rather than an adapter concern because `prompt_cache_key` is a
296
+ * field of THIS protocol; putting it here means any endpoint speaking Responses
297
+ * gets prefix caching without post-processing the serialized body.
298
+ */
299
+ readonly promptCacheKey?: string;
300
+ }
301
+ //#endregion
302
+ //#region src/protocol.d.ts
303
+ /** Protocol id, usable as a stable string in configuration. */
304
+ declare const OPENAI_RESPONSES_PROTOCOL_ID = "openai-responses";
305
+ interface RuntimeProtocolRequest extends ProtocolRequest {
306
+ readonly model: ResolvedModelInfo;
307
+ readonly connection: {
308
+ readonly baseUrl: string;
309
+ readonly headers: Readonly<Record<string, string>>;
310
+ };
311
+ }
312
+ /** Marker-based runtime view, kept structurally independent from provider-http. */
313
+ interface ResponsesProtocolDefinition {
314
+ readonly kind: 'http-wire-protocol';
315
+ readonly apiVersion: 1;
316
+ readonly id: string;
317
+ readonly defaultDialect: ResponsesDialect;
318
+ readonly exampleModel?: ModelTarget;
319
+ readonly endpointPath: (request: RuntimeProtocolRequest, dialect: ResponsesDialect) => string;
320
+ readonly protocolHeaders?: (dialect: ResponsesDialect) => Readonly<Record<string, string>>;
321
+ readonly serialize: (request: RuntimeProtocolRequest, dialect: ResponsesDialect) => Readonly<Record<string, unknown>>;
322
+ readonly translate: (events: AsyncIterable<ProtocolSseEvent>, request: RuntimeProtocolRequest, displayName: string) => AsyncGenerator<ProtocolStreamChunk>;
323
+ }
324
+ /** The OpenAI Responses wire protocol. */
325
+ declare const openAiResponsesProtocol: ProtocolDefinition<ResponsesDialect> & ResponsesProtocolDefinition;
326
+ //#endregion
327
+ //#region src/serialize.d.ts
328
+ /**
329
+ * Adapter-private state kept on a {@link ReasoningBlock} so a reasoning item can
330
+ * be echoed back byte-identically on the next request of a tool-use loop.
331
+ */
332
+ interface ResponsesReasoningState {
333
+ /** Server-assigned item id. */
334
+ id?: string;
335
+ /** Opaque encrypted chain of thought. */
336
+ encryptedContent?: string;
337
+ /** Summary paragraphs, in order. */
338
+ summary?: readonly string[];
339
+ }
340
+ /**
341
+ * Build the Responses request body.
342
+ * @param request - the resolved request, model, and connection.
343
+ * @param dialect - which optional fields this endpoint accepts.
344
+ * @returns the wire body, ready to serialize.
345
+ */
346
+ declare function serializeResponsesRequest(request: ProtocolRequest, dialect: ResponsesDialect): WireRequest;
347
+ //#endregion
348
+ //#region src/translate.d.ts
349
+ /**
350
+ * Translate one Responses SSE stream.
351
+ *
352
+ * Owns termination. This API sends no `[DONE]` sentinel: the stream ends on
353
+ * `response.completed`, `response.failed`, or `response.incomplete`, and a body
354
+ * that ends without one of those was truncated — which is a failure, not an
355
+ * empty success, because a truncated turn cannot be trusted.
356
+ * @param events - decoded SSE events.
357
+ * @param displayName - provider name, used in diagnostics.
358
+ * @returns the chunk stream.
359
+ */
360
+ declare function translateResponsesStream(events: AsyncIterable<ProtocolSseEvent>, displayName: string, request?: ProtocolRequest): AsyncGenerator<ProtocolStreamChunk>;
361
+ //#endregion
362
+ export { OPENAI_RESPONSES_PROTOCOL_ID, type ProtocolDefinition, type ProtocolRequest, type ProtocolSseEvent, type ProtocolStreamChunk, type ResponsesDialect, type ResponsesProtocolDefinition, type ResponsesReasoningState, type WireContentPart, type WireErrorBody, type WireFunctionTool, type WireImageDetail, type WireIncompleteDetails, type WireInputItem, type WireInputTokensDetails, type WireNativeTool, type WireOutputItem, type WireOutputTokensDetails, type WireReasoning, type WireReasoningContent, type WireReasoningSummary, type WireRequest, type WireResponse, type WireStreamEvent, type WireTextAnnotation, type WireTextControls, type WireTextFormat, type WireTool, type WireToolChoice, type WireUsage, openAiResponsesProtocol, serializeResponsesRequest, translateResponsesStream };
363
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/contract.ts","../src/wire.ts","../src/protocol.ts","../src/serialize.ts","../src/translate.ts"],"mappings":";;;;UAGiB;WACN,SAAS;WACT;;;UAIM;WACN;WACA;;;KAIC,sBACR,QAAQ;WAAwB;;WACrB;WAAwB,OAAO;;;UAG7B,mBAAmB;WACzB;WACA,gBAAgB;EACzB,aAAa,SAAS,iBAAiB,SAAS;EAChD,iBAAiB,SAAS,UAAU;EACpC,UAAU,SAAS,iBAAiB,SAAS,oBAAoB;EACjE,UACE,QAAQ,cAAc,mBACtB,SAAS,iBACT,sBACC,eAAe;;;;;;;;;;;;;;;;;;;KCdR;;KAGA;EACN;EAAoB;;EACpB;EAAqB;EAAmB,SAAS;;EACjD;EAAqB;EAAiB,SAAS;;EAC/C;EAAqB;EAAc,cAAc;;UAEtC;EACf;EACA;EACA;EACA;EACA;;;UAIe;EACf;EACA;;;UAIe;EACf;EACA;;;;;;;;;;;KAYU;EAER;EACA;EACA,SAAS;EACT;;EAGA;;EAEA;EACA;;EAEA;;EAEA;;EAGA;EACA;;EAEA,iBAAiB;;EAGjB;EACA;EACA,SAAS;EACT,UAAU;;;;;;;EAOV;;;EAIA;EACA;EACA;EACA;;;EAIA;EACA;EACA;EACA;;;UAIa;EACf;EACA;EACA;EACA;EACA,YAAY;;UAGG;EACf;GACC;;KAGS,WAAW,mBAAmB;;KAG9B;EAIN;EAAkB;;EAClB;;;UAGW;EACf;EACA;;;UAIe;EACf,SAAS;EACT;;KAGU;EACN;;EAEF;EACA;EACA,QAAQ,SAAS;EACjB;;;UAIa;EACf;;EAEA;EACA,OAAO;EACP,QAAQ;EACR,cAAc;EACd;EACA,YAAY;EACZ,OAAO;;EAEP;EACA;;EAEA;;EAEA;EACA;EACA;EACA;;;UAIe;;EAEf;;EAEA;;;UAIe;EACf;;;UAIe;EACf;EACA,uBAAuB;EACvB;EACA,wBAAwB;EACxB;;;UAIe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;UAIe;EACf;EACA;EACA;;;UAIe;EACf;;;UAIe;EACf;EACA;EACA,QAAQ;EACR,QAAQ;EACR,qBAAqB;;;UAIN;EACf;EACA,WAAW;EACX,OAAO;EACP;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;EACA;;;;;;;;;UAUe;;;;;;;WAON;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;;;;;;;WAQA;;;;;cCvQE;UAmBH,+BAA+B;WAC9B,OAAO;WACP;aACE;aACA,SAAS,SAAS;;;;UAKd;WACN;WACA;WACA;WACA,gBAAgB;WAChB,eAAe;WACf,eAAe,SAAS,wBAAwB,SAAS;WACzD,mBAAmB,SAAS,qBAAqB,SAAS;WAC1D,YACP,SAAS,wBACT,SAAS,qBACN,SAAS;WACL,YACP,QAAQ,cAAc,mBACtB,SAAS,wBACT,wBACG,eAAe;;;cAIT,yBAAyB,mBAAmB,oBACrD;;;;;;;UC/Ba;;EAEf;;EAEA;;EAEA;;;;;;;;iBAoSc,0BACd,SAAS,iBACT,SAAS,mBACR;;;;;;;;;;;;;;iBC9DoB,yBACrB,QAAQ,cAAc,mBACtB,qBACA,UAAU,kBACT,eAAe"}
package/dist/index.js ADDED
@@ -0,0 +1,664 @@
1
+ import { CONTEXT_WINDOW_EXCEEDED_CODE, MODEL_ERROR_CODES, ModelError, QUOTA_EXCEEDED_CODE, ToolCallId, isJsonValue, isNativeToolSchema } from "@alvin0/ai-agent-sdk-core";
2
+
3
+ //#region src/serialize.ts
4
+ /** Read the reasoning state back off a block, tolerating anything unexpected. */
5
+ function reasoningStateOf(value) {
6
+ if (typeof value !== "object" || value === null) return {};
7
+ const state = value;
8
+ return {
9
+ ...typeof state.id === "string" ? { id: state.id } : {},
10
+ ...typeof state.encryptedContent === "string" ? { encryptedContent: state.encryptedContent } : {},
11
+ ...Array.isArray(state.summary) ? { summary: state.summary } : {}
12
+ };
13
+ }
14
+ function textAnnotations$1(block) {
15
+ return block.annotations?.flatMap((annotation) => annotation.type === "url-citation" ? [{
16
+ type: "url_citation",
17
+ url: annotation.url,
18
+ ...annotation.title === void 0 ? {} : { title: annotation.title },
19
+ ...annotation.startIndex === void 0 ? {} : { start_index: annotation.startIndex },
20
+ ...annotation.endIndex === void 0 ? {} : { end_index: annotation.endIndex }
21
+ }] : []);
22
+ }
23
+ function imagePart(block) {
24
+ const detail = block.detail;
25
+ if (block.source.kind === "file") return {
26
+ type: "input_image",
27
+ file_id: block.source.fileId,
28
+ ...detail === void 0 ? {} : { detail }
29
+ };
30
+ return {
31
+ type: "input_image",
32
+ image_url: block.source.kind === "url" ? block.source.url : `data:${block.source.mediaType};base64,${block.source.data}`,
33
+ ...detail === void 0 ? {} : { detail }
34
+ };
35
+ }
36
+ /** Convert one content block to a request-side content part. */
37
+ function contentPart(block, role) {
38
+ if (block.type === "text") {
39
+ if (role !== "assistant") return {
40
+ type: "input_text",
41
+ text: block.text
42
+ };
43
+ const annotations = textAnnotations$1(block);
44
+ return {
45
+ type: "output_text",
46
+ text: block.text,
47
+ ...annotations === void 0 ? {} : { annotations }
48
+ };
49
+ }
50
+ if (block.type === "image") return imagePart(block);
51
+ }
52
+ /** Render a tool result's blocks as the wire's polymorphic `output` value. */
53
+ function toolResultOutput(blocks) {
54
+ if (!blocks.some((block) => block.type === "image")) return blocks.filter((block) => block.type === "text").map((block) => block.text).join("\n");
55
+ return blocks.map((block) => contentPart(block, "user")).filter((part) => part !== void 0);
56
+ }
57
+ /**
58
+ * Expand one message into zero or more wire items, appending them in order.
59
+ *
60
+ * Content parts accumulate into a single message item, which is FLUSHED whenever
61
+ * a block appears that has to become its own top-level item. That flushing is
62
+ * what preserves "spoke, then called a tool, then spoke again" as three items in
63
+ * the right order instead of collapsing it.
64
+ */
65
+ function appendMessage(message, items, dialectMessagePhase) {
66
+ const role = message.role === "assistant" ? "assistant" : "user";
67
+ let parts = [];
68
+ let phase;
69
+ const flush = () => {
70
+ if (parts.length === 0) return;
71
+ items.push({
72
+ type: "message",
73
+ role,
74
+ content: parts,
75
+ ...role === "assistant" && dialectMessagePhase && phase !== void 0 ? { phase: phase === "final-answer" ? "final_answer" : phase } : {}
76
+ });
77
+ parts = [];
78
+ phase = void 0;
79
+ };
80
+ for (const block of message.content) switch (block.type) {
81
+ case "text":
82
+ case "image": {
83
+ if (block.type === "text" && block.phase !== void 0 && phase !== void 0 && phase !== block.phase) flush();
84
+ if (block.type === "text" && block.phase !== void 0) phase = block.phase;
85
+ const part = contentPart(block, role);
86
+ if (part !== void 0) parts.push(part);
87
+ break;
88
+ }
89
+ case "reasoning": {
90
+ flush();
91
+ const state = reasoningStateOf(block.providerState);
92
+ const summary = state.summary !== void 0 && state.summary.length > 0 ? state.summary : block.text.length > 0 ? [block.text] : [];
93
+ items.push({
94
+ type: "reasoning",
95
+ ...state.id === void 0 ? {} : { id: state.id },
96
+ summary: summary.map((text) => ({
97
+ type: "summary_text",
98
+ text
99
+ })),
100
+ ...state.encryptedContent === void 0 ? {} : { encrypted_content: state.encryptedContent }
101
+ });
102
+ break;
103
+ }
104
+ case "tool-call":
105
+ flush();
106
+ items.push({
107
+ type: "function_call",
108
+ call_id: block.id,
109
+ name: block.name,
110
+ arguments: block.arguments.length > 0 ? block.arguments : "{}"
111
+ });
112
+ break;
113
+ case "tool-result":
114
+ flush();
115
+ items.push({
116
+ type: "function_call_output",
117
+ call_id: block.toolCallId,
118
+ output: toolResultOutput(block.content)
119
+ });
120
+ break;
121
+ case "native-tool-call": {
122
+ flush();
123
+ const replay = nativeReplayItem(block.providerState);
124
+ if (replay !== void 0) items.push(replay);
125
+ break;
126
+ }
127
+ }
128
+ flush();
129
+ }
130
+ /** Collect the system prompt from the request plus any system-role messages. */
131
+ function instructionsOf(request) {
132
+ const fromMessages = request.options.messages.filter((message) => message.role === "system").flatMap((message) => message.content).filter((block) => block.type === "text").map((block) => block.text);
133
+ return (request.options.system === void 0 ? fromMessages : [request.options.system, ...fromMessages]).join("\n\n");
134
+ }
135
+ /** Map the neutral tool-choice vocabulary onto this API's. */
136
+ function toolChoiceOf(choice) {
137
+ if (typeof choice === "string") return choice;
138
+ if (choice.type === "native") return { type: nativeWireType(choice.name) };
139
+ return {
140
+ type: "function",
141
+ name: choice.name
142
+ };
143
+ }
144
+ /** Map a tool schema; `strict: false` because caller schemas are not vetted. */
145
+ function functionTool(tool) {
146
+ return {
147
+ type: "function",
148
+ name: tool.name,
149
+ description: tool.description,
150
+ strict: false,
151
+ parameters: tool.parameters
152
+ };
153
+ }
154
+ function nativeWireType(name) {
155
+ if (name === "web-search") return "web_search";
156
+ if (name === "image-generation") return "image_generation";
157
+ return name.replaceAll("-", "_");
158
+ }
159
+ function webSearchTool(tool) {
160
+ if (tool.blockedDomains !== void 0) throw new ModelError("OpenAI Responses web search does not support blockedDomains; use allowedDomains", MODEL_ERROR_CODES.INVALID_REQUEST);
161
+ if (tool.maxUses !== void 0) throw new ModelError("OpenAI Responses web search does not support maxUses", MODEL_ERROR_CODES.INVALID_REQUEST);
162
+ return {
163
+ type: "web_search",
164
+ ...tool.searchContextSize === void 0 ? {} : { search_context_size: tool.searchContextSize },
165
+ ...tool.allowedDomains === void 0 ? {} : { filters: { allowed_domains: [...tool.allowedDomains] } },
166
+ ...tool.userLocation === void 0 ? {} : { user_location: {
167
+ type: "approximate",
168
+ ...tool.userLocation
169
+ } }
170
+ };
171
+ }
172
+ function imageGenerationTool(tool) {
173
+ return {
174
+ type: "image_generation",
175
+ ...tool.size === void 0 ? {} : { size: tool.size },
176
+ ...tool.quality === void 0 ? {} : { quality: tool.quality },
177
+ ...tool.format === void 0 ? {} : { output_format: tool.format },
178
+ ...tool.background === void 0 ? {} : { background: tool.background },
179
+ ...tool.partialImages === void 0 ? {} : { partial_images: tool.partialImages }
180
+ };
181
+ }
182
+ function toolOf(tool) {
183
+ if (!isNativeToolSchema(tool)) return functionTool(tool);
184
+ if (tool.name === "web-search") return webSearchTool(tool);
185
+ return imageGenerationTool(tool);
186
+ }
187
+ function textControls(format, dialect) {
188
+ if (format === void 0) return void 0;
189
+ if (format.type === "text") return dialect.structuredOutputs ? { format: { type: "text" } } : void 0;
190
+ if (!dialect.structuredOutputs) throw new ModelError("This Responses endpoint does not support JSON Schema output", MODEL_ERROR_CODES.INVALID_REQUEST);
191
+ return { format: {
192
+ type: "json_schema",
193
+ name: format.name,
194
+ schema: format.schema,
195
+ strict: true
196
+ } };
197
+ }
198
+ function nativeReplayItem(value) {
199
+ if (typeof value !== "object" || value === null) return void 0;
200
+ const item = value;
201
+ if (item.type === "web_search_call") return {
202
+ type: "web_search_call",
203
+ ...typeof item.id === "string" ? { id: item.id } : {},
204
+ ...typeof item.status === "string" ? { status: item.status } : {},
205
+ ...item.action === void 0 ? {} : { action: structuredClone(item.action) }
206
+ };
207
+ if (item.type === "image_generation_call") return {
208
+ type: "image_generation_call",
209
+ ...typeof item.id === "string" ? { id: item.id } : {},
210
+ ...typeof item.status === "string" ? { status: item.status } : {},
211
+ ...typeof item.result === "string" || item.result === null ? { result: item.result } : {}
212
+ };
213
+ }
214
+ /**
215
+ * Build the Responses request body.
216
+ * @param request - the resolved request, model, and connection.
217
+ * @param dialect - which optional fields this endpoint accepts.
218
+ * @returns the wire body, ready to serialize.
219
+ */
220
+ function serializeResponsesRequest(request, dialect) {
221
+ const { options } = request;
222
+ const input = [];
223
+ for (const message of options.messages) {
224
+ if (message.role === "system") continue;
225
+ appendMessage(message, input, dialect.messagePhase === true);
226
+ }
227
+ const instructions = instructionsOf(request);
228
+ const tools = options.tools === void 0 || options.tools.length === 0 ? void 0 : options.tools.map(toolOf);
229
+ const text = textControls(options.outputFormat, dialect);
230
+ return {
231
+ model: options.model,
232
+ ...instructions.length === 0 ? {} : { instructions },
233
+ input,
234
+ ...tools === void 0 ? {} : { tools },
235
+ ...options.toolChoice === void 0 ? {} : { tool_choice: toolChoiceOf(options.toolChoice) },
236
+ ...tools === void 0 ? {} : { parallel_tool_calls: true },
237
+ ...options.reasoningEffort === void 0 && dialect.reasoningSummary === void 0 ? {} : { reasoning: {
238
+ ...options.reasoningEffort === void 0 ? {} : { effort: String(options.reasoningEffort) },
239
+ ...dialect.reasoningSummary === void 0 ? {} : { summary: dialect.reasoningSummary }
240
+ } },
241
+ ...text === void 0 ? {} : { text },
242
+ store: dialect.store,
243
+ stream: true,
244
+ ...dialect.include.length === 0 ? {} : { include: [...dialect.include] },
245
+ ...dialect.promptCacheKey === void 0 ? {} : { prompt_cache_key: dialect.promptCacheKey },
246
+ ...dialect.maxOutputTokens ? { max_output_tokens: request.maxTokens } : {},
247
+ ...dialect.sampling && options.temperature !== void 0 ? { temperature: options.temperature } : {},
248
+ ...dialect.sampling && options.topP !== void 0 ? { top_p: options.topP } : {}
249
+ };
250
+ }
251
+
252
+ //#endregion
253
+ //#region src/translate.ts
254
+ /**
255
+ * Responses API SSE events to the SDK's chunk protocol.
256
+ *
257
+ * Two design notes worth reading before changing anything here.
258
+ *
259
+ * First, block correlation is keyed on `item_id`, not on the provider's
260
+ * `output_index`. Item ids are stable and present on every delta event, whereas
261
+ * index fields vary by event type, so keying on the id and assigning our OWN
262
+ * indices in first-seen order is both simpler and closer to what our protocol
263
+ * promises.
264
+ *
265
+ * Second, reasoning state is carried on the reasoning BLOCK
266
+ * (`ReasoningBlock.providerState`) rather than in the stream's `replayState`
267
+ * envelope. The envelope has to stay positionally aligned with emitted blocks and
268
+ * is discarded whole when it drifts; attaching the state to the block it belongs
269
+ * to cannot drift, and it survives assembly for free.
270
+ *
271
+ * @module ai-agent-sdk/providers/responses/translate
272
+ */
273
+ function textPhase(value) {
274
+ if (value === "commentary") return "commentary";
275
+ if (value === "final_answer") return "final-answer";
276
+ }
277
+ /** Map an output item's wire type onto one of our block types. */
278
+ function itemKind(type) {
279
+ switch (type) {
280
+ case "message": return "text";
281
+ case "reasoning": return "reasoning";
282
+ case "function_call": return "tool-call";
283
+ case "web_search_call": return "native-tool-call";
284
+ case "image_generation_call": return "native-tool-call";
285
+ default: return;
286
+ }
287
+ }
288
+ function nativeName(type) {
289
+ if (type === "web_search_call") return "web-search";
290
+ if (type === "image_generation_call") return "image-generation";
291
+ return type?.replace(/_call$/, "").replaceAll("_", "-") ?? "native-tool";
292
+ }
293
+ function textAnnotations(item) {
294
+ if (!Array.isArray(item.content)) return [];
295
+ return item.content.flatMap((part) => {
296
+ if (typeof part !== "object" || part === null) return [];
297
+ const annotations = part.annotations;
298
+ if (!Array.isArray(annotations)) return [];
299
+ return annotations.flatMap((annotation) => {
300
+ if (typeof annotation !== "object" || annotation === null) return [];
301
+ const record = annotation;
302
+ if (record.type !== "url_citation" || typeof record.url !== "string") return [];
303
+ return [{
304
+ type: "url-citation",
305
+ url: record.url,
306
+ ...typeof record.title === "string" ? { title: record.title } : {},
307
+ ...typeof record.start_index === "number" ? { startIndex: record.start_index } : {},
308
+ ...typeof record.end_index === "number" ? { endIndex: record.end_index } : {}
309
+ }];
310
+ });
311
+ });
312
+ }
313
+ /** Collect the text of a done item's `content` array. */
314
+ function itemText(item) {
315
+ const content = item.content;
316
+ if (!Array.isArray(content)) return "";
317
+ return content.map((part) => {
318
+ if (typeof part !== "object" || part === null) return "";
319
+ const record = part;
320
+ return typeof record.text === "string" ? record.text : "";
321
+ }).join("");
322
+ }
323
+ /** Collect the summary paragraphs of a done reasoning item. */
324
+ function itemSummary(item) {
325
+ const summary = item.summary;
326
+ if (!Array.isArray(summary)) return [];
327
+ return summary.map((part) => {
328
+ if (typeof part !== "object" || part === null) return "";
329
+ const record = part;
330
+ return typeof record.text === "string" ? record.text : "";
331
+ }).filter((text) => text.length > 0);
332
+ }
333
+ /**
334
+ * Normalize usage, honouring the SDK's disjoint-count convention.
335
+ *
336
+ * This API reports `input_tokens` as the TOTAL input and
337
+ * `input_tokens_details.cached_tokens` as a subset of it. Our convention is that
338
+ * the three input figures are disjoint and sum to what is billed, so the cached
339
+ * portion is subtracted back out here. Skip that and every cost estimate
340
+ * double-counts cache hits.
341
+ */
342
+ function mapUsage(usage) {
343
+ const source = usage;
344
+ const details = recordOrUndefined(source.input_tokens_details);
345
+ const outputDetails = recordOrUndefined(source.output_tokens_details);
346
+ const rawInput = source.input_tokens;
347
+ const outputTokens = source.output_tokens;
348
+ const cacheRead = details?.cached_tokens;
349
+ const cacheWrite = details?.cache_write_tokens;
350
+ const reasoning = outputDetails?.reasoning_tokens;
351
+ const totalTokens = source.total_tokens;
352
+ if (![
353
+ rawInput,
354
+ outputTokens,
355
+ cacheRead,
356
+ cacheWrite,
357
+ reasoning,
358
+ totalTokens
359
+ ].some((value) => value !== void 0)) return void 0;
360
+ const normalized = {
361
+ ...outputTokens === void 0 ? {} : { outputTokens },
362
+ ...totalTokens === void 0 ? {} : { totalTokens },
363
+ ...cacheRead === void 0 || cacheRead === 0 ? {} : { cacheReadTokens: cacheRead },
364
+ ...cacheWrite === void 0 || cacheWrite === 0 ? {} : { cacheWriteTokens: cacheWrite },
365
+ ...reasoning === void 0 || reasoning === 0 ? {} : { reasoningTokens: reasoning }
366
+ };
367
+ if (rawInput !== void 0) normalized.inputTokens = typeof rawInput === "number" && (cacheRead === void 0 || typeof cacheRead === "number") ? rawInput - (cacheRead ?? 0) : rawInput;
368
+ return normalized;
369
+ }
370
+ function recordOrUndefined(value) {
371
+ return typeof value === "object" && value !== null ? value : void 0;
372
+ }
373
+ /** Codes that mean "do not retry this"; everything else stays retryable. */
374
+ const TERMINAL_ERROR_CODES = Object.freeze({
375
+ context_length_exceeded: CONTEXT_WINDOW_EXCEEDED_CODE,
376
+ insufficient_quota: QUOTA_EXCEEDED_CODE,
377
+ invalid_prompt: MODEL_ERROR_CODES.INVALID_REQUEST,
378
+ bio_policy: MODEL_ERROR_CODES.INVALID_REQUEST,
379
+ cyber_policy: MODEL_ERROR_CODES.INVALID_REQUEST,
380
+ misalignment_policy_violation: MODEL_ERROR_CODES.INVALID_REQUEST,
381
+ rate_limit_exceeded: MODEL_ERROR_CODES.RATE_LIMIT
382
+ });
383
+ /** Turn a `response.failed` payload into a typed, correctly classified error. */
384
+ function failedError(response, displayName) {
385
+ const error = response?.error ?? void 0;
386
+ const code = error?.code ?? error?.type;
387
+ const message = error?.message ?? `${displayName} reported a failed response`;
388
+ const mapped = code === void 0 ? void 0 : TERMINAL_ERROR_CODES[code];
389
+ return new ModelError(message, mapped ?? MODEL_ERROR_CODES.SERVER, {});
390
+ }
391
+ /** Build the authoritative block for a completed item. */
392
+ function doneBlock(item, open, imageMediaType) {
393
+ switch (open.kind) {
394
+ case "text": {
395
+ const text = itemText(item);
396
+ const phase = textPhase(item.phase) ?? open.phase;
397
+ return {
398
+ type: "text",
399
+ text: text.length > 0 ? text : open.text,
400
+ ...phase === void 0 ? {} : { phase },
401
+ ...textAnnotations(item).length === 0 ? {} : { annotations: textAnnotations(item) }
402
+ };
403
+ }
404
+ case "reasoning": {
405
+ const summary = itemSummary(item);
406
+ const state = {
407
+ ...typeof item.id === "string" ? { id: item.id } : {},
408
+ ...typeof item.encrypted_content === "string" ? { encryptedContent: item.encrypted_content } : {},
409
+ ...summary.length > 0 ? { summary } : {}
410
+ };
411
+ return {
412
+ type: "reasoning",
413
+ text: summary.length > 0 ? summary.join("\n\n") : open.text,
414
+ providerState: state
415
+ };
416
+ }
417
+ case "tool-call": {
418
+ const args = typeof item.arguments === "string" && item.arguments.length > 0 ? item.arguments : open.args;
419
+ return {
420
+ type: "tool-call",
421
+ id: ToolCallId(item.call_id ?? open.callId),
422
+ name: item.name ?? open.name,
423
+ arguments: args.length > 0 ? args : "{}"
424
+ };
425
+ }
426
+ case "native-tool-call": {
427
+ const content = open.nativeName === "image-generation" && typeof item.result === "string" && item.result.length > 0 ? [{
428
+ type: "image",
429
+ source: {
430
+ kind: "base64",
431
+ mediaType: imageMediaType,
432
+ data: item.result
433
+ }
434
+ }] : [];
435
+ return {
436
+ type: "native-tool-call",
437
+ id: item.id ?? open.callId,
438
+ name: open.nativeName,
439
+ ...typeof item.status === "string" ? { status: item.status } : {},
440
+ ...isJsonValue(item.action) ? { arguments: item.action } : {},
441
+ content,
442
+ providerState: item
443
+ };
444
+ }
445
+ default: return;
446
+ }
447
+ }
448
+ /**
449
+ * Translate one Responses SSE stream.
450
+ *
451
+ * Owns termination. This API sends no `[DONE]` sentinel: the stream ends on
452
+ * `response.completed`, `response.failed`, or `response.incomplete`, and a body
453
+ * that ends without one of those was truncated — which is a failure, not an
454
+ * empty success, because a truncated turn cannot be trusted.
455
+ * @param events - decoded SSE events.
456
+ * @param displayName - provider name, used in diagnostics.
457
+ * @returns the chunk stream.
458
+ */
459
+ async function* translateResponsesStream(events, displayName, request) {
460
+ const open = /* @__PURE__ */ new Map();
461
+ let nextIndex = 0;
462
+ let sawToolCall = false;
463
+ let terminated = false;
464
+ const imageMediaType = requestedImageMediaType(request);
465
+ for await (const raw of events) {
466
+ let event;
467
+ try {
468
+ event = JSON.parse(raw.data);
469
+ } catch (error) {
470
+ throw new ModelError(`${displayName} sent a malformed stream event`, MODEL_ERROR_CODES.MALFORMED_RESPONSE, { cause: error });
471
+ }
472
+ switch (event.type) {
473
+ case "response.output_item.added": {
474
+ const item = event.item;
475
+ const id = item?.id ?? event.item_id;
476
+ const kind = itemKind(item?.type);
477
+ if (item === void 0 || id === void 0 || kind === void 0) break;
478
+ if (open.has(id)) break;
479
+ const entry = {
480
+ index: nextIndex++,
481
+ kind,
482
+ text: "",
483
+ args: "",
484
+ callId: item.call_id ?? id,
485
+ name: item.name ?? "",
486
+ nativeName: nativeName(item.type),
487
+ summaryIndex: void 0,
488
+ phase: textPhase(item.phase)
489
+ };
490
+ open.set(id, entry);
491
+ if (kind === "tool-call") sawToolCall = true;
492
+ yield {
493
+ type: "block-start",
494
+ index: entry.index,
495
+ blockType: kindToBlockType(kind)
496
+ };
497
+ break;
498
+ }
499
+ case "response.output_text.delta": {
500
+ const entry = event.item_id === void 0 ? void 0 : open.get(event.item_id);
501
+ if (entry === void 0 || event.delta === void 0) break;
502
+ entry.text += event.delta;
503
+ yield {
504
+ type: "text-delta",
505
+ index: entry.index,
506
+ text: event.delta,
507
+ ...entry.phase === void 0 ? {} : { phase: entry.phase }
508
+ };
509
+ break;
510
+ }
511
+ case "response.reasoning_summary_text.delta": {
512
+ const entry = event.item_id === void 0 ? void 0 : open.get(event.item_id);
513
+ if (entry === void 0 || event.delta === void 0) break;
514
+ const separator = entry.summaryIndex !== void 0 && event.summary_index !== void 0 && event.summary_index !== entry.summaryIndex ? "\n\n" : "";
515
+ entry.summaryIndex = event.summary_index;
516
+ const text = `${separator}${event.delta}`;
517
+ entry.text += text;
518
+ yield {
519
+ type: "reasoning-delta",
520
+ index: entry.index,
521
+ text
522
+ };
523
+ break;
524
+ }
525
+ case "response.reasoning_text.delta": {
526
+ const entry = event.item_id === void 0 ? void 0 : open.get(event.item_id);
527
+ if (entry === void 0 || event.delta === void 0) break;
528
+ entry.text += event.delta;
529
+ yield {
530
+ type: "reasoning-delta",
531
+ index: entry.index,
532
+ text: event.delta
533
+ };
534
+ break;
535
+ }
536
+ case "response.function_call_arguments.delta": {
537
+ const entry = event.item_id === void 0 ? void 0 : open.get(event.item_id);
538
+ if (entry === void 0 || event.delta === void 0) break;
539
+ entry.args += event.delta;
540
+ yield {
541
+ type: "tool-call-delta",
542
+ index: entry.index,
543
+ id: ToolCallId(entry.callId),
544
+ ...entry.name.length > 0 ? { name: entry.name } : {},
545
+ argumentsDelta: event.delta
546
+ };
547
+ break;
548
+ }
549
+ case "response.image_generation_call.partial_image": {
550
+ const itemId = event.item_id;
551
+ const entry = itemId === void 0 ? void 0 : open.get(itemId);
552
+ if (itemId === void 0 || entry === void 0 || event.partial_image_b64 === void 0) break;
553
+ yield {
554
+ type: "image-delta",
555
+ index: entry.index,
556
+ itemId,
557
+ data: event.partial_image_b64,
558
+ mediaType: imageMediaType,
559
+ ...event.partial_image_index === void 0 ? {} : { partialIndex: event.partial_image_index }
560
+ };
561
+ break;
562
+ }
563
+ case "response.output_item.done": {
564
+ const item = event.item;
565
+ const id = item?.id ?? event.item_id;
566
+ const entry = id === void 0 ? void 0 : open.get(id);
567
+ if (item === void 0 || entry === void 0) break;
568
+ const block = doneBlock(item, entry, imageMediaType);
569
+ if (block !== void 0) yield {
570
+ type: "block-end",
571
+ index: entry.index,
572
+ block
573
+ };
574
+ break;
575
+ }
576
+ case "response.completed": {
577
+ const usage = event.response?.usage ?? void 0;
578
+ const mapped = usage === void 0 ? void 0 : mapUsage(usage);
579
+ if (mapped !== void 0) yield {
580
+ type: "usage",
581
+ usage: mapped
582
+ };
583
+ yield {
584
+ type: "finish",
585
+ reason: sawToolCall ? { kind: "tool-calls" } : { kind: "stop" }
586
+ };
587
+ terminated = true;
588
+ return;
589
+ }
590
+ case "response.incomplete": {
591
+ const usage = event.response?.usage ?? void 0;
592
+ const mapped = usage === void 0 ? void 0 : mapUsage(usage);
593
+ if (mapped !== void 0) yield {
594
+ type: "usage",
595
+ usage: mapped
596
+ };
597
+ const why = event.response?.incomplete_details?.reason;
598
+ if (why === "max_output_tokens") {
599
+ yield {
600
+ type: "finish",
601
+ reason: { kind: "max-tokens" }
602
+ };
603
+ terminated = true;
604
+ return;
605
+ }
606
+ throw new ModelError(`${displayName} returned an incomplete response (${why ?? "unknown reason"})`, MODEL_ERROR_CODES.SERVER);
607
+ }
608
+ case "response.failed": throw failedError(event.response, displayName);
609
+ case "error": throw failedError({ error: {
610
+ ...event.code === void 0 ? {} : { code: event.code },
611
+ ...event.message === void 0 ? {} : { message: event.message }
612
+ } }, displayName);
613
+ }
614
+ }
615
+ if (!terminated) throw new ModelError(`${displayName} stream ended before the response completed`, MODEL_ERROR_CODES.STREAM_CLOSED);
616
+ }
617
+ /** Our block-type tag for one item kind. */
618
+ function kindToBlockType(kind) {
619
+ return kind;
620
+ }
621
+ function requestedImageMediaType(request) {
622
+ const tool = request?.options.tools?.find((candidate) => "type" in candidate && candidate.type === "native" && candidate.name === "image-generation");
623
+ if (tool === void 0 || !("format" in tool)) return "image/png";
624
+ if (tool.format === "jpeg") return "image/jpeg";
625
+ if (tool.format === "webp") return "image/webp";
626
+ return "image/png";
627
+ }
628
+
629
+ //#endregion
630
+ //#region src/protocol.ts
631
+ /** Protocol id, usable as a stable string in configuration. */
632
+ const OPENAI_RESPONSES_PROTOCOL_ID = "openai-responses";
633
+ /**
634
+ * Conservative defaults.
635
+ *
636
+ * `store: false` because retaining prompts server-side should be an explicit
637
+ * decision, not something an SDK turns on for you. `include` carries
638
+ * `reasoning.encrypted_content` because without it a reasoning model loses its
639
+ * chain of thought between a tool call and the tool's result.
640
+ */
641
+ const DEFAULT_DIALECT = Object.freeze({
642
+ sampling: true,
643
+ maxOutputTokens: true,
644
+ structuredOutputs: true,
645
+ store: false,
646
+ include: Object.freeze(["reasoning.encrypted_content"]),
647
+ reasoningSummary: "auto"
648
+ });
649
+ /** The OpenAI Responses wire protocol. */
650
+ const openAiResponsesProtocol = Object.freeze({
651
+ kind: "http-wire-protocol",
652
+ apiVersion: 1,
653
+ id: OPENAI_RESPONSES_PROTOCOL_ID,
654
+ defaultDialect: DEFAULT_DIALECT,
655
+ endpointPath: () => "/responses",
656
+ serialize(request, dialect) {
657
+ return serializeResponsesRequest(request, dialect);
658
+ },
659
+ translate: (events, request, displayName) => translateResponsesStream(events, displayName, request)
660
+ });
661
+
662
+ //#endregion
663
+ export { OPENAI_RESPONSES_PROTOCOL_ID, openAiResponsesProtocol, serializeResponsesRequest, translateResponsesStream };
664
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["textAnnotations"],"sources":["../src/serialize.ts","../src/translate.ts","../src/protocol.ts"],"sourcesContent":["/**\n * Normalized request to Responses API wire JSON.\n *\n * The interesting work is flattening. Our conversation is a list of messages,\n * each holding an ordered list of content blocks; the wire wants a FLAT list of\n * items where a tool result and a tool call are peers of a message rather than\n * parts of one. So one assistant message that reasoned, spoke, and called two\n * tools expands to four items, and their relative order must be preserved\n * because the model reads it as its own prior turn.\n *\n * @module ai-agent-sdk/providers/responses/serialize\n */\n\nimport type { ProtocolRequest } from './contract.ts'\nimport { MODEL_ERROR_CODES, ModelError } from '@alvin0/ai-agent-sdk-core'\nimport type { ContentBlock, ImageBlock, TextBlock } from '@alvin0/ai-agent-sdk-core'\nimport type { Message } from '@alvin0/ai-agent-sdk-core'\nimport {\n isNativeToolSchema,\n type ModelOutputFormat,\n type ModelToolSchema,\n type NativeImageGenerationTool,\n type NativeWebSearchTool,\n type ToolChoice,\n type ToolSchema,\n} from '@alvin0/ai-agent-sdk-core'\nimport type {\n ResponsesDialect,\n WireContentPart,\n WireInputItem,\n WireRequest,\n WireTool,\n WireToolChoice,\n WireTextControls,\n} from './wire.ts'\n\n/**\n * Adapter-private state kept on a {@link ReasoningBlock} so a reasoning item can\n * be echoed back byte-identically on the next request of a tool-use loop.\n */\nexport interface ResponsesReasoningState {\n /** Server-assigned item id. */\n id?: string\n /** Opaque encrypted chain of thought. */\n encryptedContent?: string\n /** Summary paragraphs, in order. */\n summary?: readonly string[]\n}\n\n/** Read the reasoning state back off a block, tolerating anything unexpected. */\nfunction reasoningStateOf(value: unknown): ResponsesReasoningState {\n if (typeof value !== 'object' || value === null) return {}\n const state = value as ResponsesReasoningState\n return {\n ...typeof state.id === 'string' ? { id: state.id } : {},\n ...typeof state.encryptedContent === 'string'\n ? { encryptedContent: state.encryptedContent }\n : {},\n ...Array.isArray(state.summary) ? { summary: state.summary } : {},\n }\n}\n\nfunction textAnnotations(block: TextBlock) {\n return block.annotations?.flatMap(annotation => annotation.type === 'url-citation'\n ? [{\n type: 'url_citation' as const,\n url: annotation.url,\n ...annotation.title === undefined ? {} : { title: annotation.title },\n ...annotation.startIndex === undefined ? {} : { start_index: annotation.startIndex },\n ...annotation.endIndex === undefined ? {} : { end_index: annotation.endIndex },\n }]\n : [])\n}\n\nfunction imagePart(block: ImageBlock): WireContentPart {\n const detail = block.detail\n if (block.source.kind === 'file') {\n return { type: 'input_image', file_id: block.source.fileId, ...detail === undefined ? {} : { detail } }\n }\n const image_url = block.source.kind === 'url'\n ? block.source.url\n : `data:${block.source.mediaType};base64,${block.source.data}`\n return { type: 'input_image', image_url, ...detail === undefined ? {} : { detail } }\n}\n\n/** Convert one content block to a request-side content part. */\nfunction contentPart(block: ContentBlock, role: 'user' | 'assistant'): WireContentPart | undefined {\n if (block.type === 'text') {\n // An assistant turn's own text must come back as `output_text`; sending it as\n // `input_text` would present the model's prior words as if the user said them.\n if (role !== 'assistant') return { type: 'input_text', text: block.text }\n const annotations = textAnnotations(block)\n return {\n type: 'output_text', text: block.text,\n ...annotations === undefined ? {} : { annotations },\n }\n }\n if (block.type === 'image') return imagePart(block)\n return undefined\n}\n\n/** Render a tool result's blocks as the wire's polymorphic `output` value. */\nfunction toolResultOutput(blocks: readonly ContentBlock[]): string | WireContentPart[] {\n const hasImage = blocks.some(block => block.type === 'image')\n if (!hasImage) {\n // The common case. A plain string keeps the payload small and is what the\n // API documents first.\n return blocks\n .filter((block): block is Extract<ContentBlock, { type: 'text' }> => block.type === 'text')\n .map(block => block.text)\n .join('\\n')\n }\n return blocks\n .map(block => contentPart(block, 'user'))\n .filter((part): part is WireContentPart => part !== undefined)\n}\n\n/**\n * Expand one message into zero or more wire items, appending them in order.\n *\n * Content parts accumulate into a single message item, which is FLUSHED whenever\n * a block appears that has to become its own top-level item. That flushing is\n * what preserves \"spoke, then called a tool, then spoke again\" as three items in\n * the right order instead of collapsing it.\n */\nfunction appendMessage(message: Message, items: WireInputItem[], dialectMessagePhase: boolean): void {\n const role = message.role === 'assistant' ? 'assistant' : 'user'\n let parts: WireContentPart[] = []\n let phase: Extract<ContentBlock, { type: 'text' }>['phase']\n\n const flush = (): void => {\n if (parts.length === 0) return\n items.push({\n type: 'message', role, content: parts,\n ...role === 'assistant' && dialectMessagePhase && phase !== undefined\n ? { phase: phase === 'final-answer' ? 'final_answer' as const : phase }\n : {},\n })\n parts = []\n phase = undefined\n }\n\n for (const block of message.content) {\n switch (block.type) {\n case 'text':\n case 'image': {\n if (block.type === 'text' && block.phase !== undefined && phase !== undefined && phase !== block.phase) flush()\n if (block.type === 'text' && block.phase !== undefined) phase = block.phase\n const part = contentPart(block, role)\n if (part !== undefined) parts.push(part)\n break\n }\n case 'reasoning': {\n flush()\n const state = reasoningStateOf(block.providerState)\n // Prefer the recorded summary paragraphs; fall back to the block's text so\n // a hand-built or replayed message still carries something.\n const summary = state.summary !== undefined && state.summary.length > 0\n ? state.summary\n : block.text.length > 0 ? [block.text] : []\n items.push({\n type: 'reasoning',\n ...state.id === undefined ? {} : { id: state.id },\n summary: summary.map(text => ({ type: 'summary_text' as const, text })),\n ...state.encryptedContent === undefined\n ? {}\n : { encrypted_content: state.encryptedContent },\n })\n break\n }\n case 'tool-call': {\n flush()\n items.push({\n type: 'function_call',\n call_id: block.id,\n name: block.name,\n // Empty arguments must still be valid JSON, or the provider rejects it.\n arguments: block.arguments.length > 0 ? block.arguments : '{}',\n })\n break\n }\n case 'tool-result': {\n flush()\n items.push({\n type: 'function_call_output',\n call_id: block.toolCallId,\n output: toolResultOutput(block.content),\n })\n break\n }\n case 'native-tool-call': {\n flush()\n const replay = nativeReplayItem(block.providerState)\n if (replay !== undefined) items.push(replay)\n break\n }\n default:\n // A content block introduced by declaration merging. Skipping is correct:\n // this serializer cannot know its wire form, and inventing one would\n // corrupt the request.\n break\n }\n }\n flush()\n}\n\n/** Collect the system prompt from the request plus any system-role messages. */\nfunction instructionsOf(request: ProtocolRequest): string {\n const fromMessages = request.options.messages\n .filter(message => message.role === 'system')\n .flatMap(message => message.content)\n .filter((block): block is Extract<ContentBlock, { type: 'text' }> => block.type === 'text')\n .map(block => block.text)\n const all = request.options.system === undefined\n ? fromMessages\n : [request.options.system, ...fromMessages]\n return all.join('\\n\\n')\n}\n\n/** Map the neutral tool-choice vocabulary onto this API's. */\nfunction toolChoiceOf(choice: ToolChoice): WireToolChoice {\n if (typeof choice === 'string') return choice\n if (choice.type === 'native') return { type: nativeWireType(choice.name) }\n return { type: 'function', name: choice.name }\n}\n\n/** Map a tool schema; `strict: false` because caller schemas are not vetted. */\nfunction functionTool(tool: ToolSchema): WireTool {\n return {\n type: 'function',\n name: tool.name,\n description: tool.description,\n // Strict mode imposes real JSON-Schema restrictions (no optional fields\n // without null, `additionalProperties: false` required). Opting a caller's\n // schema in silently would turn a working tool into a request rejection.\n strict: false,\n parameters: tool.parameters,\n }\n}\n\nfunction nativeWireType(name: string): string {\n if (name === 'web-search') return 'web_search'\n if (name === 'image-generation') return 'image_generation'\n return name.replaceAll('-', '_')\n}\n\nfunction webSearchTool(tool: NativeWebSearchTool): WireTool {\n if (tool.blockedDomains !== undefined) {\n throw new ModelError(\n 'OpenAI Responses web search does not support blockedDomains; use allowedDomains',\n MODEL_ERROR_CODES.INVALID_REQUEST,\n )\n }\n if (tool.maxUses !== undefined) {\n throw new ModelError(\n 'OpenAI Responses web search does not support maxUses',\n MODEL_ERROR_CODES.INVALID_REQUEST,\n )\n }\n return {\n type: 'web_search',\n ...tool.searchContextSize === undefined ? {} : { search_context_size: tool.searchContextSize },\n ...tool.allowedDomains === undefined ? {} : { filters: { allowed_domains: [...tool.allowedDomains] } },\n ...tool.userLocation === undefined ? {} : {\n user_location: { type: 'approximate', ...tool.userLocation },\n },\n }\n}\n\nfunction imageGenerationTool(tool: NativeImageGenerationTool): WireTool {\n return {\n type: 'image_generation',\n ...tool.size === undefined ? {} : { size: tool.size },\n ...tool.quality === undefined ? {} : { quality: tool.quality },\n ...tool.format === undefined ? {} : { output_format: tool.format },\n ...tool.background === undefined ? {} : { background: tool.background },\n ...tool.partialImages === undefined ? {} : { partial_images: tool.partialImages },\n }\n}\n\nfunction toolOf(tool: ModelToolSchema): WireTool {\n if (!isNativeToolSchema(tool)) return functionTool(tool)\n if (tool.name === 'web-search') return webSearchTool(tool)\n return imageGenerationTool(tool)\n}\n\nfunction textControls(\n format: ModelOutputFormat | undefined,\n dialect: ResponsesDialect,\n): WireTextControls | undefined {\n if (format === undefined) return undefined\n if (format.type === 'text') {\n return dialect.structuredOutputs ? { format: { type: 'text' } } : undefined\n }\n if (!dialect.structuredOutputs) {\n throw new ModelError(\n 'This Responses endpoint does not support JSON Schema output',\n MODEL_ERROR_CODES.INVALID_REQUEST,\n )\n }\n return {\n format: {\n type: 'json_schema',\n name: format.name,\n schema: format.schema,\n strict: true,\n },\n }\n}\n\nfunction nativeReplayItem(value: unknown): WireInputItem | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const item = value as Record<string, unknown>\n if (item.type === 'web_search_call') {\n return {\n type: 'web_search_call',\n ...typeof item.id === 'string' ? { id: item.id } : {},\n ...typeof item.status === 'string' ? { status: item.status } : {},\n ...item.action === undefined ? {} : { action: structuredClone(item.action) },\n }\n }\n if (item.type === 'image_generation_call') {\n return {\n type: 'image_generation_call',\n ...typeof item.id === 'string' ? { id: item.id } : {},\n ...typeof item.status === 'string' ? { status: item.status } : {},\n ...typeof item.result === 'string' || item.result === null ? { result: item.result } : {},\n }\n }\n return undefined\n}\n\n/**\n * Build the Responses request body.\n * @param request - the resolved request, model, and connection.\n * @param dialect - which optional fields this endpoint accepts.\n * @returns the wire body, ready to serialize.\n */\nexport function serializeResponsesRequest(\n request: ProtocolRequest,\n dialect: ResponsesDialect,\n): WireRequest {\n const { options } = request\n const input: WireInputItem[] = []\n for (const message of options.messages) {\n if (message.role === 'system') continue // folded into `instructions`\n appendMessage(message, input, dialect.messagePhase === true)\n }\n\n const instructions = instructionsOf(request)\n const tools = options.tools === undefined || options.tools.length === 0\n ? undefined\n : options.tools.map(toolOf)\n const text = textControls(options.outputFormat, dialect)\n\n return {\n model: options.model,\n ...instructions.length === 0 ? {} : { instructions },\n input,\n ...tools === undefined ? {} : { tools },\n ...options.toolChoice === undefined ? {} : { tool_choice: toolChoiceOf(options.toolChoice) },\n ...tools === undefined ? {} : { parallel_tool_calls: true },\n ...options.reasoningEffort === undefined && dialect.reasoningSummary === undefined\n ? {}\n : {\n reasoning: {\n ...options.reasoningEffort === undefined\n ? {}\n : { effort: String(options.reasoningEffort) },\n ...dialect.reasoningSummary === undefined\n ? {}\n : { summary: dialect.reasoningSummary },\n },\n },\n ...text === undefined ? {} : { text },\n store: dialect.store,\n stream: true,\n ...dialect.include.length === 0 ? {} : { include: [...dialect.include] },\n ...dialect.promptCacheKey === undefined ? {} : { prompt_cache_key: dialect.promptCacheKey },\n ...dialect.maxOutputTokens ? { max_output_tokens: request.maxTokens } : {},\n ...dialect.sampling && options.temperature !== undefined\n ? { temperature: options.temperature }\n : {},\n ...dialect.sampling && options.topP !== undefined ? { top_p: options.topP } : {},\n }\n}\n","/**\n * Responses API SSE events to the SDK's chunk protocol.\n *\n * Two design notes worth reading before changing anything here.\n *\n * First, block correlation is keyed on `item_id`, not on the provider's\n * `output_index`. Item ids are stable and present on every delta event, whereas\n * index fields vary by event type, so keying on the id and assigning our OWN\n * indices in first-seen order is both simpler and closer to what our protocol\n * promises.\n *\n * Second, reasoning state is carried on the reasoning BLOCK\n * (`ReasoningBlock.providerState`) rather than in the stream's `replayState`\n * envelope. The envelope has to stay positionally aligned with emitted blocks and\n * is discarded whole when it drifts; attaching the state to the block it belongs\n * to cannot drift, and it survives assembly for free.\n *\n * @module ai-agent-sdk/providers/responses/translate\n */\n\nimport {\n CONTEXT_WINDOW_EXCEEDED_CODE,\n QUOTA_EXCEEDED_CODE,\n} from '@alvin0/ai-agent-sdk-core'\nimport { MODEL_ERROR_CODES, ModelError } from '@alvin0/ai-agent-sdk-core'\nimport { ToolCallId } from '@alvin0/ai-agent-sdk-core'\nimport { isJsonValue } from '@alvin0/ai-agent-sdk-core'\nimport type {\n AssistantTextPhase,\n ContentBlock,\n ImageMediaType,\n TextAnnotation,\n} from '@alvin0/ai-agent-sdk-core'\nimport type { FinishReason, UsageCounters } from '@alvin0/ai-agent-sdk-core'\nimport type { ProtocolRequest, ProtocolSseEvent, ProtocolStreamChunk } from './contract.ts'\nimport type { ResponsesReasoningState } from './serialize.ts'\nimport type {\n WireErrorBody,\n WireOutputItem,\n WireResponse,\n WireStreamEvent,\n WireUsage,\n} from './wire.ts'\n\n/** Which of our block types one output item maps to. */\ntype ItemKind = 'text' | 'reasoning' | 'tool-call' | 'native-tool-call'\n\ninterface OpenItem {\n readonly index: number\n readonly kind: ItemKind\n text: string\n args: string\n callId: string\n name: string\n nativeName: string\n /** Last `summary_index` seen, so a new paragraph gets a separator. */\n summaryIndex: number | undefined\n phase: AssistantTextPhase | undefined\n}\n\nfunction textPhase(value: string | undefined): AssistantTextPhase | undefined {\n if (value === 'commentary') return 'commentary'\n if (value === 'final_answer') return 'final-answer'\n return undefined\n}\n\n/** Map an output item's wire type onto one of our block types. */\nfunction itemKind(type: string | undefined): ItemKind | undefined {\n switch (type) {\n case 'message': return 'text'\n case 'reasoning': return 'reasoning'\n case 'function_call': return 'tool-call'\n case 'web_search_call': return 'native-tool-call'\n case 'image_generation_call': return 'native-tool-call'\n default: return undefined\n }\n}\n\nfunction nativeName(type: string | undefined): string {\n if (type === 'web_search_call') return 'web-search'\n if (type === 'image_generation_call') return 'image-generation'\n return type?.replace(/_call$/, '').replaceAll('_', '-') ?? 'native-tool'\n}\n\nfunction textAnnotations(item: WireOutputItem): TextAnnotation[] {\n if (!Array.isArray(item.content)) return []\n return item.content.flatMap((part) => {\n if (typeof part !== 'object' || part === null) return []\n const annotations = (part as Record<string, unknown>).annotations\n if (!Array.isArray(annotations)) return []\n return annotations.flatMap((annotation): TextAnnotation[] => {\n if (typeof annotation !== 'object' || annotation === null) return []\n const record = annotation as Record<string, unknown>\n if (record.type !== 'url_citation' || typeof record.url !== 'string') return []\n return [{\n type: 'url-citation',\n url: record.url,\n ...typeof record.title === 'string' ? { title: record.title } : {},\n ...typeof record.start_index === 'number' ? { startIndex: record.start_index } : {},\n ...typeof record.end_index === 'number' ? { endIndex: record.end_index } : {},\n }]\n })\n })\n}\n\n/** Collect the text of a done item's `content` array. */\nfunction itemText(item: WireOutputItem): string {\n const content = item.content\n if (!Array.isArray(content)) return ''\n return content\n .map((part) => {\n if (typeof part !== 'object' || part === null) return ''\n const record = part as Record<string, unknown>\n return typeof record.text === 'string' ? record.text : ''\n })\n .join('')\n}\n\n/** Collect the summary paragraphs of a done reasoning item. */\nfunction itemSummary(item: WireOutputItem): string[] {\n const summary = item.summary\n if (!Array.isArray(summary)) return []\n return summary\n .map((part) => {\n if (typeof part !== 'object' || part === null) return ''\n const record = part as Record<string, unknown>\n return typeof record.text === 'string' ? record.text : ''\n })\n .filter(text => text.length > 0)\n}\n\n/**\n * Normalize usage, honouring the SDK's disjoint-count convention.\n *\n * This API reports `input_tokens` as the TOTAL input and\n * `input_tokens_details.cached_tokens` as a subset of it. Our convention is that\n * the three input figures are disjoint and sum to what is billed, so the cached\n * portion is subtracted back out here. Skip that and every cost estimate\n * double-counts cache hits.\n */\nfunction mapUsage(usage: WireUsage): UsageCounters | undefined {\n const source = usage as unknown as Record<string, unknown>\n const details = recordOrUndefined(source.input_tokens_details)\n const outputDetails = recordOrUndefined(source.output_tokens_details)\n const rawInput = source.input_tokens\n const outputTokens = source.output_tokens\n const cacheRead = details?.cached_tokens\n const cacheWrite = details?.cache_write_tokens\n const reasoning = outputDetails?.reasoning_tokens\n const totalTokens = source.total_tokens\n const hasAny = [rawInput, outputTokens, cacheRead, cacheWrite, reasoning, totalTokens]\n .some(value => value !== undefined)\n if (!hasAny) return undefined\n\n const normalized: Record<string, unknown> = {\n ...outputTokens === undefined ? {} : { outputTokens },\n ...totalTokens === undefined ? {} : { totalTokens },\n // Omitted cache details are authoritative zero for Responses. Present\n // malformed values are retained for the accounting validator.\n ...cacheRead === undefined || cacheRead === 0 ? {} : { cacheReadTokens: cacheRead },\n ...cacheWrite === undefined || cacheWrite === 0 ? {} : { cacheWriteTokens: cacheWrite },\n ...reasoning === undefined || reasoning === 0 ? {} : { reasoningTokens: reasoning },\n }\n if (rawInput !== undefined) {\n normalized.inputTokens = typeof rawInput === 'number'\n && (cacheRead === undefined || typeof cacheRead === 'number')\n ? rawInput - (cacheRead ?? 0)\n : rawInput\n }\n return normalized as UsageCounters\n}\n\nfunction recordOrUndefined(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null ? value as Record<string, unknown> : undefined\n}\n\n/** Codes that mean \"do not retry this\"; everything else stays retryable. */\nconst TERMINAL_ERROR_CODES: Readonly<Record<string, string>> = Object.freeze({\n context_length_exceeded: CONTEXT_WINDOW_EXCEEDED_CODE,\n insufficient_quota: QUOTA_EXCEEDED_CODE,\n invalid_prompt: MODEL_ERROR_CODES.INVALID_REQUEST,\n bio_policy: MODEL_ERROR_CODES.INVALID_REQUEST,\n cyber_policy: MODEL_ERROR_CODES.INVALID_REQUEST,\n misalignment_policy_violation: MODEL_ERROR_CODES.INVALID_REQUEST,\n rate_limit_exceeded: MODEL_ERROR_CODES.RATE_LIMIT,\n})\n\n/** Turn a `response.failed` payload into a typed, correctly classified error. */\nfunction failedError(response: WireResponse | undefined, displayName: string): ModelError {\n const error = response?.error ?? undefined\n const code = error?.code ?? error?.type\n const message = error?.message ?? `${displayName} reported a failed response`\n const mapped = code === undefined ? undefined : TERMINAL_ERROR_CODES[code]\n return new ModelError(\n message,\n // An unrecognized failure defaults to SERVER, which IS in the retryable set:\n // the request produced nothing, so repeating it is safe and often works.\n mapped ?? MODEL_ERROR_CODES.SERVER,\n {},\n )\n}\n\n/** Build the authoritative block for a completed item. */\nfunction doneBlock(\n item: WireOutputItem,\n open: OpenItem,\n imageMediaType: ImageMediaType,\n): ContentBlock | undefined {\n switch (open.kind) {\n case 'text': {\n const text = itemText(item)\n const phase = textPhase(item.phase) ?? open.phase\n return {\n type: 'text',\n text: text.length > 0 ? text : open.text,\n ...phase === undefined ? {} : { phase },\n ...textAnnotations(item).length === 0 ? {} : { annotations: textAnnotations(item) },\n }\n }\n case 'reasoning': {\n const summary = itemSummary(item)\n const state: ResponsesReasoningState = {\n ...typeof item.id === 'string' ? { id: item.id } : {},\n ...typeof item.encrypted_content === 'string'\n ? { encryptedContent: item.encrypted_content }\n : {},\n ...summary.length > 0 ? { summary } : {},\n }\n return {\n type: 'reasoning',\n text: summary.length > 0 ? summary.join('\\n\\n') : open.text,\n providerState: state,\n }\n }\n case 'tool-call': {\n const args = typeof item.arguments === 'string' && item.arguments.length > 0\n ? item.arguments\n : open.args\n return {\n type: 'tool-call',\n id: ToolCallId(item.call_id ?? open.callId),\n name: item.name ?? open.name,\n arguments: args.length > 0 ? args : '{}',\n }\n }\n case 'native-tool-call': {\n const content: ContentBlock[] = open.nativeName === 'image-generation'\n && typeof item.result === 'string' && item.result.length > 0\n ? [{\n type: 'image',\n source: { kind: 'base64', mediaType: imageMediaType, data: item.result },\n }]\n : []\n return {\n type: 'native-tool-call',\n id: item.id ?? open.callId,\n name: open.nativeName,\n ...typeof item.status === 'string' ? { status: item.status } : {},\n ...isJsonValue(item.action) ? { arguments: item.action } : {},\n content,\n providerState: item,\n }\n }\n default:\n return undefined\n }\n}\n\n/**\n * Translate one Responses SSE stream.\n *\n * Owns termination. This API sends no `[DONE]` sentinel: the stream ends on\n * `response.completed`, `response.failed`, or `response.incomplete`, and a body\n * that ends without one of those was truncated — which is a failure, not an\n * empty success, because a truncated turn cannot be trusted.\n * @param events - decoded SSE events.\n * @param displayName - provider name, used in diagnostics.\n * @returns the chunk stream.\n */\nexport async function* translateResponsesStream(\n events: AsyncIterable<ProtocolSseEvent>,\n displayName: string,\n request?: ProtocolRequest,\n): AsyncGenerator<ProtocolStreamChunk> {\n const open = new Map<string, OpenItem>()\n let nextIndex = 0\n let sawToolCall = false\n let terminated = false\n const imageMediaType = requestedImageMediaType(request)\n\n for await (const raw of events) {\n let event: WireStreamEvent\n try {\n event = JSON.parse(raw.data) as WireStreamEvent\n } catch (error: unknown) {\n throw new ModelError(\n `${displayName} sent a malformed stream event`,\n MODEL_ERROR_CODES.MALFORMED_RESPONSE,\n { cause: error },\n )\n }\n\n switch (event.type) {\n case 'response.output_item.added': {\n const item = event.item\n const id = item?.id ?? event.item_id\n const kind = itemKind(item?.type)\n if (item === undefined || id === undefined || kind === undefined) break\n if (open.has(id)) break\n const entry: OpenItem = {\n index: nextIndex++,\n kind,\n text: '',\n args: '',\n callId: item.call_id ?? id,\n name: item.name ?? '',\n nativeName: nativeName(item.type),\n summaryIndex: undefined,\n phase: textPhase(item.phase),\n }\n open.set(id, entry)\n if (kind === 'tool-call') sawToolCall = true\n yield { type: 'block-start', index: entry.index, blockType: kindToBlockType(kind) }\n break\n }\n\n case 'response.output_text.delta': {\n const entry = event.item_id === undefined ? undefined : open.get(event.item_id)\n if (entry === undefined || event.delta === undefined) break\n entry.text += event.delta\n yield {\n type: 'text-delta', index: entry.index, text: event.delta,\n ...entry.phase === undefined ? {} : { phase: entry.phase },\n }\n break\n }\n\n case 'response.reasoning_summary_text.delta': {\n const entry = event.item_id === undefined ? undefined : open.get(event.item_id)\n if (entry === undefined || event.delta === undefined) break\n // A new summary paragraph starts; separate it from the previous one so the\n // assembled text does not run two thoughts together.\n const separator = entry.summaryIndex !== undefined\n && event.summary_index !== undefined\n && event.summary_index !== entry.summaryIndex\n ? '\\n\\n'\n : ''\n entry.summaryIndex = event.summary_index\n const text = `${separator}${event.delta}`\n entry.text += text\n yield { type: 'reasoning-delta', index: entry.index, text }\n break\n }\n\n case 'response.reasoning_text.delta': {\n const entry = event.item_id === undefined ? undefined : open.get(event.item_id)\n if (entry === undefined || event.delta === undefined) break\n entry.text += event.delta\n yield { type: 'reasoning-delta', index: entry.index, text: event.delta }\n break\n }\n\n case 'response.function_call_arguments.delta': {\n const entry = event.item_id === undefined ? undefined : open.get(event.item_id)\n if (entry === undefined || event.delta === undefined) break\n entry.args += event.delta\n yield {\n type: 'tool-call-delta',\n index: entry.index,\n id: ToolCallId(entry.callId),\n ...entry.name.length > 0 ? { name: entry.name } : {},\n argumentsDelta: event.delta,\n }\n break\n }\n\n case 'response.image_generation_call.partial_image': {\n const itemId = event.item_id\n const entry = itemId === undefined ? undefined : open.get(itemId)\n if (itemId === undefined || entry === undefined || event.partial_image_b64 === undefined) break\n yield {\n type: 'image-delta',\n index: entry.index,\n itemId,\n data: event.partial_image_b64,\n mediaType: imageMediaType,\n ...event.partial_image_index === undefined\n ? {}\n : { partialIndex: event.partial_image_index },\n }\n break\n }\n\n case 'response.output_item.done': {\n const item = event.item\n const id = item?.id ?? event.item_id\n const entry = id === undefined ? undefined : open.get(id)\n if (item === undefined || entry === undefined) break\n const block = doneBlock(item, entry, imageMediaType)\n if (block !== undefined) yield { type: 'block-end', index: entry.index, block }\n break\n }\n\n case 'response.completed': {\n const usage = event.response?.usage ?? undefined\n const mapped = usage === undefined ? undefined : mapUsage(usage)\n if (mapped !== undefined) yield { type: 'usage', usage: mapped }\n // This API has no explicit stop reason. Tool calls in the output ARE the\n // signal that the turn expects results back, which is what an agent loop\n // branches on.\n const reason: FinishReason = sawToolCall ? { kind: 'tool-calls' } : { kind: 'stop' }\n yield { type: 'finish', reason }\n terminated = true\n return\n }\n\n case 'response.incomplete': {\n const usage = event.response?.usage ?? undefined\n const mapped = usage === undefined ? undefined : mapUsage(usage)\n if (mapped !== undefined) yield { type: 'usage', usage: mapped }\n const why = event.response?.incomplete_details?.reason\n if (why === 'max_output_tokens') {\n yield { type: 'finish', reason: { kind: 'max-tokens' } }\n terminated = true\n return\n }\n throw new ModelError(\n `${displayName} returned an incomplete response (${why ?? 'unknown reason'})`,\n MODEL_ERROR_CODES.SERVER,\n )\n }\n\n case 'response.failed':\n throw failedError(event.response, displayName)\n\n case 'error': {\n // A top-level error event carries its fields inline rather than under a\n // `response` object, so it is reshaped to reuse the same classifier.\n const inline: WireErrorBody = {\n ...event.code === undefined ? {} : { code: event.code },\n ...event.message === undefined ? {} : { message: event.message },\n }\n throw failedError({ error: inline }, displayName)\n }\n\n default:\n // Every other lifecycle and progress event (`response.created`,\n // `content_part.*`, `*.done` text echoes, `ping`) carries nothing this\n // protocol needs. Falling through is correct and keeps new event types\n // from breaking the stream.\n break\n }\n }\n\n if (!terminated) {\n throw new ModelError(\n `${displayName} stream ended before the response completed`,\n MODEL_ERROR_CODES.STREAM_CLOSED,\n )\n }\n}\n\n/** Our block-type tag for one item kind. */\nfunction kindToBlockType(kind: ItemKind): 'text' | 'reasoning' | 'tool-call' | 'native-tool-call' {\n return kind\n}\n\nfunction requestedImageMediaType(request: ProtocolRequest | undefined): ImageMediaType {\n const tool = request?.options.tools?.find(candidate => 'type' in candidate\n && candidate.type === 'native'\n && candidate.name === 'image-generation')\n if (tool === undefined || !('format' in tool)) return 'image/png'\n if (tool.format === 'jpeg') return 'image/jpeg'\n if (tool.format === 'webp') return 'image/webp'\n return 'image/png'\n}\n","/**\n * The OpenAI Responses protocol, as a reusable {@link WireProtocol}.\n *\n * Spoken by `api.openai.com`, by the ChatGPT-backed Codex endpoint, and by a\n * growing number of compatible gateways. None of them needs its own translation\n * code — they differ only in the dialect knobs below.\n *\n * @module ai-agent-sdk/providers/protocols/openai-responses\n */\n\nimport type {\n ProtocolDefinition,\n ProtocolRequest,\n ProtocolSseEvent,\n ProtocolStreamChunk,\n} from './contract.ts'\nimport type { ModelTarget, ResolvedModelInfo } from '@alvin0/ai-agent-sdk-core/provider'\nimport { serializeResponsesRequest } from './serialize.ts'\nimport { translateResponsesStream } from './translate.ts'\nimport type { ResponsesDialect } from './wire.ts'\n\n/** Protocol id, usable as a stable string in configuration. */\nexport const OPENAI_RESPONSES_PROTOCOL_ID = 'openai-responses'\n\n/**\n * Conservative defaults.\n *\n * `store: false` because retaining prompts server-side should be an explicit\n * decision, not something an SDK turns on for you. `include` carries\n * `reasoning.encrypted_content` because without it a reasoning model loses its\n * chain of thought between a tool call and the tool's result.\n */\nconst DEFAULT_DIALECT: ResponsesDialect = Object.freeze({\n sampling: true,\n maxOutputTokens: true,\n structuredOutputs: true,\n store: false,\n include: Object.freeze(['reasoning.encrypted_content']),\n reasoningSummary: 'auto',\n})\n\ninterface RuntimeProtocolRequest extends ProtocolRequest {\n readonly model: ResolvedModelInfo\n readonly connection: {\n readonly baseUrl: string\n readonly headers: Readonly<Record<string, string>>\n }\n}\n\n/** Marker-based runtime view, kept structurally independent from provider-http. */\nexport interface ResponsesProtocolDefinition {\n readonly kind: 'http-wire-protocol'\n readonly apiVersion: 1\n readonly id: string\n readonly defaultDialect: ResponsesDialect\n readonly exampleModel?: ModelTarget\n readonly endpointPath: (request: RuntimeProtocolRequest, dialect: ResponsesDialect) => string\n readonly protocolHeaders?: (dialect: ResponsesDialect) => Readonly<Record<string, string>>\n readonly serialize: (\n request: RuntimeProtocolRequest,\n dialect: ResponsesDialect,\n ) => Readonly<Record<string, unknown>>\n readonly translate: (\n events: AsyncIterable<ProtocolSseEvent>,\n request: RuntimeProtocolRequest,\n displayName: string,\n ) => AsyncGenerator<ProtocolStreamChunk>\n}\n\n/** The OpenAI Responses wire protocol. */\nexport const openAiResponsesProtocol: ProtocolDefinition<ResponsesDialect>\n & ResponsesProtocolDefinition = Object.freeze({\n kind: 'http-wire-protocol' as const,\n apiVersion: 1 as const,\n id: OPENAI_RESPONSES_PROTOCOL_ID,\n defaultDialect: DEFAULT_DIALECT,\n endpointPath: () => '/responses',\n serialize(request: ProtocolRequest, dialect: ResponsesDialect): Readonly<Record<string, unknown>> {\n return serializeResponsesRequest(request, dialect) as unknown as Readonly<Record<string, unknown>>\n },\n // Params are annotated because `Object.freeze` erases the contextual typing the\n // `WireProtocol` annotation would otherwise supply.\n translate: (\n events: AsyncIterable<ProtocolSseEvent>,\n request: ProtocolRequest,\n displayName: string,\n ): AsyncGenerator<ProtocolStreamChunk> => translateResponsesStream(events, displayName, request),\n})\n\nexport type { ResponsesDialect }\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@alvin0/ai-agent-sdk-protocol-responses",
3
+ "author": {
4
+ "name": "alvin0 - chaulamdinhai",
5
+ "email": "chaulamdinhai@gmail.com"
6
+ },
7
+ "version": "0.1.0",
8
+ "description": "Universal OpenAI Responses and Codex wire schema, serializer, translator, and dialect for ai-agent-sdk",
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/alvin0/ai-agent-sdk.git",
13
+ "directory": "packages/protocol-responses"
14
+ },
15
+ "homepage": "https://github.com/alvin0/ai-agent-sdk/tree/main/packages/protocol-responses#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/alvin0/ai-agent-sdk/issues"
18
+ },
19
+ "type": "module",
20
+ "sideEffects": false,
21
+ "files": [
22
+ "dist",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js",
32
+ "default": "./dist/index.js"
33
+ },
34
+ "./package.json": "./package.json"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public",
38
+ "provenance": true
39
+ },
40
+ "peerDependencies": {
41
+ "@alvin0/ai-agent-sdk-core": "^0.1.0"
42
+ },
43
+ "devDependencies": {
44
+ "@alvin0/ai-agent-sdk-core": "^0.1.0",
45
+ "@arethetypeswrong/cli": "0.18.5",
46
+ "playwright": "1.62.1",
47
+ "publint": "0.3.24",
48
+ "tsdown": "0.22.14",
49
+ "typescript": "7.0.2",
50
+ "vitest": "4.1.11",
51
+ "wrangler": "4.127.1"
52
+ },
53
+ "aiAgentSdk": {
54
+ "runtime": "universal",
55
+ "coreApi": 1,
56
+ "roles": [
57
+ "wire-protocol"
58
+ ]
59
+ },
60
+ "scripts": {
61
+ "build": "tsdown",
62
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true});require('node:fs').rmSync('artifacts',{recursive:true,force:true})\"",
63
+ "typecheck": "tsc --noEmit",
64
+ "test": "vitest run --config vitest.config.ts",
65
+ "pack": "pnpm pack --pack-destination artifacts",
66
+ "test:pack": "node ../../scripts/test-packed-protocol.mts protocol-responses",
67
+ "check:publint": "publint",
68
+ "check:types": "attw --profile esm-only --pack ."
69
+ }
70
+ }