@opencode-ai/ai 0.0.0-dev-17929 → 0.0.0-dev-17944

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.
@@ -8,3 +8,4 @@ export * as OpenAICompatibleResponses from "./openai-compatible-responses.js";
8
8
  export * as OpenAIResponses from "./openai-responses.js";
9
9
  export * as OpenResponses from "./open-responses.js";
10
10
  export * as OpenResponsesChannel from "./open-responses-channel.js";
11
+ export * as XAIResponses from "./xai-responses.js";
@@ -8,3 +8,4 @@ export * as OpenAICompatibleResponses from "./openai-compatible-responses.js";
8
8
  export * as OpenAIResponses from "./openai-responses.js";
9
9
  export * as OpenResponses from "./open-responses.js";
10
10
  export * as OpenResponsesChannel from "./open-responses-channel.js";
11
+ export * as XAIResponses from "./xai-responses.js";
@@ -7,11 +7,6 @@ export interface Options {
7
7
  readonly enabled?: (url: string) => boolean;
8
8
  readonly url?: (url: string) => string;
9
9
  readonly headers?: (headers: Headers.Headers) => Headers.Headers;
10
- readonly driver?: (input: {
11
- readonly request: Readonly<Record<string, unknown>>;
12
- readonly message: string;
13
- readonly base: WebSocketChannelDriver;
14
- }) => WebSocketChannelDriver;
15
10
  }
16
11
  export interface Prepared {
17
12
  readonly http: HttpTransport.HttpPrepared<string>;
@@ -4,6 +4,7 @@ import { Framing } from "../route/framing.js";
4
4
  import { HttpTransport, WebSocketTransport, } from "../route/transport/index.js";
5
5
  import * as ProviderShared from "./shared.js";
6
6
  import { OpenResponses } from "./open-responses.js";
7
+ import { OpenResponsesContinuation } from "./open-responses-continuation.js";
7
8
  const WebSocketResponseCreate = Schema.StructWithRest(Schema.Struct({ type: Schema.tag("response.create") }), [
8
9
  Schema.Record(Schema.String, Schema.Unknown),
9
10
  ]);
@@ -87,7 +88,13 @@ export const transport = (options) => {
87
88
  url: yield* WebSocketTransport.toWebSocketUrl(options.url?.(parts.url) ?? parts.url),
88
89
  headers,
89
90
  rotateAfterMs: options.rotateAfterMs,
90
- driver: options.driver?.({ request: create.request, message: create.message, base }) ?? base,
91
+ driver: OpenResponsesContinuation.driver({
92
+ id: options.id,
93
+ name: options.name,
94
+ request: create.request,
95
+ message: create.message,
96
+ base,
97
+ }),
91
98
  };
92
99
  })
93
100
  : undefined;
@@ -7,6 +7,6 @@ export interface DriverInput {
7
7
  readonly base: WebSocketChannelDriver;
8
8
  }
9
9
  export declare const driver: (input: DriverInput) => WebSocketChannelDriver;
10
- export declare const OpenAIResponsesChannel: {
10
+ export declare const OpenResponsesContinuation: {
11
11
  readonly driver: (input: DriverInput) => WebSocketChannelDriver;
12
12
  };
@@ -2,7 +2,7 @@ import { AIError, TransportReason } from "../schema/index.js";
2
2
  import { Effect, Option, Schema } from "effect";
3
3
  import * as ProviderShared from "./shared.js";
4
4
  import { OpenResponses } from "./open-responses.js";
5
- const PROTOCOL = "openai-responses.websocket.v1";
5
+ const PROTOCOL = "open-responses.websocket.v1";
6
6
  const VERSION = 1;
7
7
  const decodeEvent = Schema.decodeUnknownEffect(OpenResponses.protocol.stream.event);
8
8
  const checkpointValue = (checkpoint) => {
@@ -139,4 +139,4 @@ export const driver = (input) => {
139
139
  }),
140
140
  };
141
141
  };
142
- export const OpenAIResponsesChannel = { driver };
142
+ export const OpenResponsesContinuation = { driver };
@@ -13,11 +13,11 @@ declare const MediaInput: Schema.Union<readonly [Schema.Struct<{
13
13
  }>, Schema.Struct<{
14
14
  readonly type: Schema.tag<"input_file">;
15
15
  readonly filename: Schema.String;
16
- readonly file_data: Schema.String;
17
- readonly mime_type: Schema.optional<Schema.String>;
16
+ readonly file_data: Schema.optional<Schema.String>;
17
+ readonly file_url: Schema.optional<Schema.String>;
18
18
  }>]>;
19
19
  export type MediaInput = Schema.Schema.Type<typeof MediaInput>;
20
- export declare const MessagePhase: Schema.Literals<readonly ["commentary", "final_answer"]>;
20
+ export declare const MessagePhase: Schema.NullOr<Schema.Literals<readonly ["commentary", "final_answer"]>>;
21
21
  type MessagePhase = Schema.Schema.Type<typeof MessagePhase>;
22
22
  export declare const InputItem: Schema.Union<readonly [Schema.Struct<{
23
23
  readonly role: Schema.tag<"system">;
@@ -36,8 +36,8 @@ export declare const InputItem: Schema.Union<readonly [Schema.Struct<{
36
36
  }>, Schema.Struct<{
37
37
  readonly type: Schema.tag<"input_file">;
38
38
  readonly filename: Schema.String;
39
- readonly file_data: Schema.String;
40
- readonly mime_type: Schema.optional<Schema.String>;
39
+ readonly file_data: Schema.optional<Schema.String>;
40
+ readonly file_url: Schema.optional<Schema.String>;
41
41
  }>]>]>>;
42
42
  }>, Schema.Struct<{
43
43
  readonly type: Schema.tag<"message">;
@@ -47,7 +47,7 @@ export declare const InputItem: Schema.Union<readonly [Schema.Struct<{
47
47
  readonly type: Schema.tag<"output_text">;
48
48
  readonly text: Schema.String;
49
49
  }>>;
50
- readonly phase: Schema.optionalKey<Schema.Literals<readonly ["commentary", "final_answer"]>>;
50
+ readonly phase: Schema.optionalKey<Schema.NullOr<Schema.Literals<readonly ["commentary", "final_answer"]>>>;
51
51
  }>, Schema.Struct<{
52
52
  readonly type: Schema.tag<"reasoning">;
53
53
  readonly id: Schema.optionalKey<Schema.String>;
@@ -77,8 +77,11 @@ export declare const InputItem: Schema.Union<readonly [Schema.Struct<{
77
77
  }>, Schema.Struct<{
78
78
  readonly type: Schema.tag<"input_file">;
79
79
  readonly filename: Schema.String;
80
- readonly file_data: Schema.String;
81
- readonly mime_type: Schema.optional<Schema.String>;
80
+ readonly file_data: Schema.optional<Schema.String>;
81
+ readonly file_url: Schema.optional<Schema.String>;
82
+ }>, Schema.Struct<{
83
+ readonly type: Schema.tag<"input_video">;
84
+ readonly video_url: Schema.String;
82
85
  }>]>>]>;
83
86
  }>]>;
84
87
  type OpenResponsesInputItem = Schema.Schema.Type<typeof InputItem>;
@@ -129,8 +132,8 @@ export declare const coreFields: {
129
132
  }>, Schema.Struct<{
130
133
  readonly type: Schema.tag<"input_file">;
131
134
  readonly filename: Schema.String;
132
- readonly file_data: Schema.String;
133
- readonly mime_type: Schema.optional<Schema.String>;
135
+ readonly file_data: Schema.optional<Schema.String>;
136
+ readonly file_url: Schema.optional<Schema.String>;
134
137
  }>]>]>>;
135
138
  }>, Schema.Struct<{
136
139
  readonly type: Schema.tag<"message">;
@@ -140,7 +143,7 @@ export declare const coreFields: {
140
143
  readonly type: Schema.tag<"output_text">;
141
144
  readonly text: Schema.String;
142
145
  }>>;
143
- readonly phase: Schema.optionalKey<Schema.Literals<readonly ["commentary", "final_answer"]>>;
146
+ readonly phase: Schema.optionalKey<Schema.NullOr<Schema.Literals<readonly ["commentary", "final_answer"]>>>;
144
147
  }>, Schema.Struct<{
145
148
  readonly type: Schema.tag<"reasoning">;
146
149
  readonly id: Schema.optionalKey<Schema.String>;
@@ -170,8 +173,11 @@ export declare const coreFields: {
170
173
  }>, Schema.Struct<{
171
174
  readonly type: Schema.tag<"input_file">;
172
175
  readonly filename: Schema.String;
173
- readonly file_data: Schema.String;
174
- readonly mime_type: Schema.optional<Schema.String>;
176
+ readonly file_data: Schema.optional<Schema.String>;
177
+ readonly file_url: Schema.optional<Schema.String>;
178
+ }>, Schema.Struct<{
179
+ readonly type: Schema.tag<"input_video">;
180
+ readonly video_url: Schema.String;
175
181
  }>]>>]>;
176
182
  }>]>>;
177
183
  instructions: Schema.optional<Schema.String>;
@@ -239,8 +245,8 @@ declare const OpenResponsesBody: Schema.Struct<{
239
245
  }>, Schema.Struct<{
240
246
  readonly type: Schema.tag<"input_file">;
241
247
  readonly filename: Schema.String;
242
- readonly file_data: Schema.String;
243
- readonly mime_type: Schema.optional<Schema.String>;
248
+ readonly file_data: Schema.optional<Schema.String>;
249
+ readonly file_url: Schema.optional<Schema.String>;
244
250
  }>]>]>>;
245
251
  }>, Schema.Struct<{
246
252
  readonly type: Schema.tag<"message">;
@@ -250,7 +256,7 @@ declare const OpenResponsesBody: Schema.Struct<{
250
256
  readonly type: Schema.tag<"output_text">;
251
257
  readonly text: Schema.String;
252
258
  }>>;
253
- readonly phase: Schema.optionalKey<Schema.Literals<readonly ["commentary", "final_answer"]>>;
259
+ readonly phase: Schema.optionalKey<Schema.NullOr<Schema.Literals<readonly ["commentary", "final_answer"]>>>;
254
260
  }>, Schema.Struct<{
255
261
  readonly type: Schema.tag<"reasoning">;
256
262
  readonly id: Schema.optionalKey<Schema.String>;
@@ -280,8 +286,11 @@ declare const OpenResponsesBody: Schema.Struct<{
280
286
  }>, Schema.Struct<{
281
287
  readonly type: Schema.tag<"input_file">;
282
288
  readonly filename: Schema.String;
283
- readonly file_data: Schema.String;
284
- readonly mime_type: Schema.optional<Schema.String>;
289
+ readonly file_data: Schema.optional<Schema.String>;
290
+ readonly file_url: Schema.optional<Schema.String>;
291
+ }>, Schema.Struct<{
292
+ readonly type: Schema.tag<"input_video">;
293
+ readonly video_url: Schema.String;
285
294
  }>]>>]>;
286
295
  }>]>>;
287
296
  readonly instructions: Schema.optional<Schema.String>;
@@ -433,7 +442,6 @@ export interface Extension {
433
442
  readonly media: ProviderShared.NormalizedMedia;
434
443
  readonly request: LLMRequest;
435
444
  }) => MediaInput | undefined;
436
- readonly messagePhase?: (value: unknown) => MessagePhase | null | undefined;
437
445
  }
438
446
  export interface ParserState {
439
447
  readonly id: string;
@@ -443,7 +451,6 @@ export interface ParserState {
443
451
  readonly hasFunctionCall: boolean;
444
452
  readonly lifecycle: Lifecycle.State;
445
453
  readonly messageItems: ReadonlySet<string>;
446
- readonly messagePhase: (value: unknown) => MessagePhase | null | undefined;
447
454
  readonly messagePhases: Readonly<Record<string, MessagePhase | null>>;
448
455
  readonly reasoningItems: Readonly<Record<string, ReasoningStreamItem>>;
449
456
  readonly store: boolean | undefined;
@@ -547,8 +554,8 @@ export declare const fromRequest: (request: LLMRequest) => Effect.Effect<{
547
554
  } | {
548
555
  readonly type: "input_file";
549
556
  readonly filename: string;
550
- readonly file_data: string;
551
- readonly mime_type?: string | undefined;
557
+ readonly file_data?: string | undefined;
558
+ readonly file_url?: string | undefined;
552
559
  } | {
553
560
  readonly type: "input_text";
554
561
  readonly text: string;
@@ -561,7 +568,7 @@ export declare const fromRequest: (request: LLMRequest) => Effect.Effect<{
561
568
  }[];
562
569
  readonly role: "assistant";
563
570
  readonly id?: string | undefined;
564
- readonly phase?: "commentary" | "final_answer" | undefined;
571
+ readonly phase?: "commentary" | "final_answer" | null | undefined;
565
572
  } | {
566
573
  readonly type: "function_call";
567
574
  readonly name: string;
@@ -577,11 +584,14 @@ export declare const fromRequest: (request: LLMRequest) => Effect.Effect<{
577
584
  } | {
578
585
  readonly type: "input_file";
579
586
  readonly filename: string;
580
- readonly file_data: string;
581
- readonly mime_type?: string | undefined;
587
+ readonly file_data?: string | undefined;
588
+ readonly file_url?: string | undefined;
582
589
  } | {
583
590
  readonly type: "input_text";
584
591
  readonly text: string;
592
+ } | {
593
+ readonly type: "input_video";
594
+ readonly video_url: string;
585
595
  })[];
586
596
  })[];
587
597
  readonly model: string;
@@ -854,8 +864,8 @@ export declare const protocol: Protocol<{
854
864
  } | {
855
865
  readonly type: "input_file";
856
866
  readonly filename: string;
857
- readonly file_data: string;
858
- readonly mime_type?: string | undefined;
867
+ readonly file_data?: string | undefined;
868
+ readonly file_url?: string | undefined;
859
869
  } | {
860
870
  readonly type: "input_text";
861
871
  readonly text: string;
@@ -868,7 +878,7 @@ export declare const protocol: Protocol<{
868
878
  }[];
869
879
  readonly role: "assistant";
870
880
  readonly id?: string | undefined;
871
- readonly phase?: "commentary" | "final_answer" | undefined;
881
+ readonly phase?: "commentary" | "final_answer" | null | undefined;
872
882
  } | {
873
883
  readonly type: "function_call";
874
884
  readonly name: string;
@@ -884,11 +894,14 @@ export declare const protocol: Protocol<{
884
894
  } | {
885
895
  readonly type: "input_file";
886
896
  readonly filename: string;
887
- readonly file_data: string;
888
- readonly mime_type?: string | undefined;
897
+ readonly file_data?: string | undefined;
898
+ readonly file_url?: string | undefined;
889
899
  } | {
890
900
  readonly type: "input_text";
891
901
  readonly text: string;
902
+ } | {
903
+ readonly type: "input_video";
904
+ readonly video_url: string;
892
905
  })[];
893
906
  })[];
894
907
  readonly model: string;
@@ -1022,8 +1035,8 @@ export declare const httpTransport: HttpTransport.HttpJsonTransport<{
1022
1035
  } | {
1023
1036
  readonly type: "input_file";
1024
1037
  readonly filename: string;
1025
- readonly file_data: string;
1026
- readonly mime_type?: string | undefined;
1038
+ readonly file_data?: string | undefined;
1039
+ readonly file_url?: string | undefined;
1027
1040
  } | {
1028
1041
  readonly type: "input_text";
1029
1042
  readonly text: string;
@@ -1036,7 +1049,7 @@ export declare const httpTransport: HttpTransport.HttpJsonTransport<{
1036
1049
  }[];
1037
1050
  readonly role: "assistant";
1038
1051
  readonly id?: string | undefined;
1039
- readonly phase?: "commentary" | "final_answer" | undefined;
1052
+ readonly phase?: "commentary" | "final_answer" | null | undefined;
1040
1053
  } | {
1041
1054
  readonly type: "function_call";
1042
1055
  readonly name: string;
@@ -1052,11 +1065,14 @@ export declare const httpTransport: HttpTransport.HttpJsonTransport<{
1052
1065
  } | {
1053
1066
  readonly type: "input_file";
1054
1067
  readonly filename: string;
1055
- readonly file_data: string;
1056
- readonly mime_type?: string | undefined;
1068
+ readonly file_data?: string | undefined;
1069
+ readonly file_url?: string | undefined;
1057
1070
  } | {
1058
1071
  readonly type: "input_text";
1059
1072
  readonly text: string;
1073
+ } | {
1074
+ readonly type: "input_video";
1075
+ readonly video_url: string;
1060
1076
  })[];
1061
1077
  })[];
1062
1078
  readonly model: string;
@@ -25,8 +25,12 @@ const OpenResponsesInputImage = Schema.Struct({
25
25
  const OpenResponsesInputFile = Schema.Struct({
26
26
  type: Schema.tag("input_file"),
27
27
  filename: Schema.String,
28
- file_data: Schema.String,
29
- mime_type: Schema.optional(Schema.String),
28
+ file_data: Schema.optional(Schema.String),
29
+ file_url: Schema.optional(Schema.String),
30
+ });
31
+ const OpenResponsesInputVideo = Schema.Struct({
32
+ type: Schema.tag("input_video"),
33
+ video_url: Schema.String,
30
34
  });
31
35
  const MediaInput = Schema.Union([OpenResponsesInputImage, OpenResponsesInputFile]);
32
36
  const OpenResponsesInputContent = Schema.Union([OpenResponsesInputText, MediaInput]);
@@ -34,7 +38,12 @@ const OpenResponsesOutputText = Schema.Struct({
34
38
  type: Schema.tag("output_text"),
35
39
  text: Schema.String,
36
40
  });
37
- export const MessagePhase = Schema.Literals(["commentary", "final_answer"]);
41
+ export const MessagePhase = Schema.NullOr(Schema.Literals(["commentary", "final_answer"]));
42
+ const messagePhase = (value) => {
43
+ if (value === null || value === "commentary" || value === "final_answer")
44
+ return value;
45
+ return undefined;
46
+ };
38
47
  const OpenResponsesReasoningSummaryText = Schema.Struct({
39
48
  type: Schema.tag("summary_text"),
40
49
  text: Schema.String,
@@ -56,6 +65,7 @@ const OpenResponsesFunctionCallOutputContent = Schema.Union([
56
65
  OpenResponsesInputText,
57
66
  OpenResponsesInputImage,
58
67
  OpenResponsesInputFile,
68
+ OpenResponsesInputVideo,
59
69
  ]);
60
70
  const OpenResponsesFunctionCallOutput = Schema.Union([
61
71
  Schema.String,
@@ -213,19 +223,6 @@ export const Event = Schema.StructWithRest(Schema.Struct({
213
223
  status_code: Schema.optional(Schema.Unknown),
214
224
  headers: Schema.optional(Schema.Unknown),
215
225
  }), [Schema.Record(Schema.String, Schema.Unknown)]);
216
- const RefusalEvent = Schema.Union([
217
- Schema.Struct({
218
- type: Schema.tag("response.refusal.delta"),
219
- item_id: Schema.String,
220
- delta: Schema.String,
221
- }),
222
- Schema.Struct({
223
- type: Schema.tag("response.refusal.done"),
224
- item_id: Schema.String,
225
- refusal: Schema.String,
226
- }),
227
- ]);
228
- const isRefusalEvent = Schema.is(RefusalEvent);
229
226
  const BASE = { id: ADAPTER, name: NAME };
230
227
  // =============================================================================
231
228
  // Request Lowering
@@ -279,36 +276,49 @@ const lowerReasoning = (part, providerMetadataKey) => {
279
276
  encrypted_content: encryptedContent,
280
277
  };
281
278
  };
282
- const hostedToolItemID = (part, providerMetadataKey) => {
283
- return itemID(part.providerMetadata, providerMetadataKey);
284
- };
285
- const lowerMedia = Effect.fn("OpenResponses.lowerMedia")(function* (part, request, extension) {
279
+ const lowerMedia = Effect.fn("OpenResponses.lowerMedia")(function* (part, request, extension, target) {
286
280
  const media = ProviderShared.normalizeMedia(part);
287
281
  const extended = extension.lowerMedia?.({ part, media, request });
288
282
  if (extended)
289
283
  return extended;
284
+ const url = typeof part.data === "string" && (part.data.startsWith("https://") || part.data.startsWith("http://"))
285
+ ? part.data
286
+ : undefined;
290
287
  if (!media.mime.startsWith("image/")) {
288
+ if (target === "tool-result" && media.mime.startsWith("video/"))
289
+ return { type: "input_video", video_url: url ?? media.dataUrl };
291
290
  return {
292
291
  type: "input_file",
293
292
  filename: part.filename ?? (media.mime === "application/pdf" ? "document.pdf" : "file"),
294
- file_data: media.dataUrl,
293
+ ...(url ? { file_url: url } : { file_data: media.base64 }),
295
294
  };
296
295
  }
297
- return { type: "input_image", image_url: media.dataUrl };
296
+ return { type: "input_image", image_url: url ?? media.dataUrl };
298
297
  });
299
298
  const lowerUserContent = Effect.fnUntraced(function* (part, request, extension) {
300
299
  if (part.type === "text")
301
300
  return { type: "input_text", text: part.text };
302
301
  if (part.type === "media")
303
- return yield* lowerMedia(part, request, extension);
302
+ return yield* lowerMessageMedia(part, request, extension);
304
303
  return yield* ProviderShared.unsupportedContent(extension.name, "user", ["text", "media"]);
305
304
  });
305
+ const lowerMessageMedia = Effect.fnUntraced(function* (part, request, extension) {
306
+ const lowered = yield* lowerMedia(part, request, extension, "message");
307
+ if (lowered.type === "input_video")
308
+ return yield* ProviderShared.invalidRequest(`${extension.name} user messages do not support input_video`);
309
+ return lowered;
310
+ });
306
311
  // Tool results may carry structured text, images, and files. Keep media as provider-native
307
312
  // content instead of JSON-stringifying base64 into a prompt string.
308
313
  const lowerToolResultContentItem = Effect.fnUntraced(function* (item, request, extension) {
309
314
  if (item.type === "text")
310
315
  return { type: "input_text", text: item.text };
311
- return yield* lowerMedia({ type: "media", mediaType: item.mime, data: item.uri, filename: item.name }, request, extension);
316
+ return yield* lowerMedia({ type: "media", mediaType: item.mime, data: item.uri, filename: item.name }, request, extension, "tool-result");
317
+ });
318
+ const lowerHostedToolResultContentItem = Effect.fnUntraced(function* (item, request, extension) {
319
+ if (item.type === "text")
320
+ return { type: "input_text", text: item.text };
321
+ return yield* lowerMessageMedia({ type: "media", mediaType: item.mime, data: item.uri, filename: item.name }, request, extension);
312
322
  });
313
323
  const lowerToolResultOutput = Effect.fnUntraced(function* (part, request, extension) {
314
324
  // Text/json/error results are encoded as a plain string for backward
@@ -350,7 +360,7 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
350
360
  const groups = content.reduce((groups, part) => {
351
361
  const metadata = part.providerMetadata?.[providerMetadataKey];
352
362
  const id = itemID(part.providerMetadata, providerMetadataKey);
353
- const phase = ProviderShared.isRecord(metadata) ? messagePhase(metadata.phase, extension) : undefined;
363
+ const phase = ProviderShared.isRecord(metadata) ? messagePhase(metadata.phase) : undefined;
354
364
  const group = groups.at(-1);
355
365
  if (group && group.id === id && group.phase === phase)
356
366
  group.parts.push(part);
@@ -403,18 +413,18 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
403
413
  }
404
414
  if (part.type === "tool-result" && part.providerExecuted === true) {
405
415
  flushText();
406
- const itemID = hostedToolItemID(part, providerMetadataKey);
407
- if (store !== false && itemID && !hostedToolReferences.has(itemID))
408
- input.push({ type: "item_reference", id: itemID });
416
+ const id = itemID(part.providerMetadata, providerMetadataKey);
417
+ if (store !== false && id && !hostedToolReferences.has(id))
418
+ input.push({ type: "item_reference", id });
409
419
  if (store === false && part.result.type === "content") {
410
420
  const content = part.result.value;
411
421
  input.push({
412
422
  role: "user",
413
- content: yield* Effect.forEach(content, (item) => lowerToolResultContentItem(item, request, extension)),
423
+ content: yield* Effect.forEach(content, (item) => lowerHostedToolResultContentItem(item, request, extension)),
414
424
  });
415
425
  }
416
- if (itemID)
417
- hostedToolReferences.add(itemID);
426
+ if (id)
427
+ hostedToolReferences.add(id);
418
428
  continue;
419
429
  }
420
430
  return yield* ProviderShared.unsupportedContent(extension.name, "assistant", [
@@ -598,18 +608,17 @@ const reasoningMetadata = (state, item) => providerMetadata(state, { itemId: ite
598
608
  // best-effort, not guaranteed.
599
609
  const onOutputItemAdded = (state, event) => {
600
610
  const item = event.item;
601
- if (item?.type === "message" && item.id)
611
+ if (item?.type === "message" && item.id) {
612
+ const phase = messagePhase(item.phase);
602
613
  return [
603
614
  {
604
615
  ...state,
605
616
  messageItems: new Set([...state.messageItems, item.id]),
606
- messagePhases: (() => {
607
- const phase = state.messagePhase(item.phase);
608
- return phase === undefined ? state.messagePhases : { ...state.messagePhases, [item.id]: phase };
609
- })(),
617
+ messagePhases: phase === undefined ? state.messagePhases : { ...state.messagePhases, [item.id]: phase },
610
618
  },
611
619
  NO_EVENTS,
612
620
  ];
621
+ }
613
622
  if (item && isReasoningItem(item)) {
614
623
  const events = [];
615
624
  return [
@@ -731,7 +740,7 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
731
740
  if (!item)
732
741
  return [state, NO_EVENTS];
733
742
  if (item.type === "message" && item.id) {
734
- const itemPhase = state.messagePhase(item.phase);
743
+ const itemPhase = messagePhase(item.phase);
735
744
  const phase = itemPhase === undefined ? state.messagePhases[item.id] : itemPhase;
736
745
  const events = [];
737
746
  const messageItems = new Set(state.messageItems);
@@ -822,22 +831,26 @@ const onResponseFinish = Effect.fn("OpenResponses.onResponseFinish")(function* (
822
831
  });
823
832
  return [{ ...state, lifecycle, hasFunctionCall, tools: pending.tools }, events];
824
833
  });
825
- // Build a single human-readable message from whatever the provider supplied.
834
+ // Build the prettiest summary available from whatever the provider supplied.
826
835
  // When both code and message are present, prefix the code so consumers see
827
836
  // the failure mode (e.g. `rate_limit_exceeded: Slow down`) instead of just
828
837
  // the bare message — production rate limits and context-length failures used
829
- // to be indistinguishable from generic stream drops.
830
- const providerErrorMessage = (event, fallback) => {
831
- const nested = event.error ?? event.response?.error ?? undefined;
838
+ // to be indistinguishable from generic stream drops. Returns undefined when
839
+ // the payload carries no usable summary.
840
+ const providerErrorMessage = (event, nested) => {
832
841
  const message = event.message || nested?.message || undefined;
833
842
  const code = event.code || nested?.code || undefined;
834
843
  if (message && code)
835
844
  return `${code}: ${message}`;
836
- return message || code || fallback;
845
+ return message || code;
837
846
  };
838
847
  export const providerFailure = (id, event, fallback) => {
839
- const code = event.code || event.error?.code || event.response?.error?.code || undefined;
840
- const message = providerErrorMessage(event, fallback);
848
+ const nested = event.error ?? event.response?.error ?? undefined;
849
+ const code = event.code || nested?.code || undefined;
850
+ // Keep the full raw payload on the error even when the message is a summary.
851
+ const body = JSON.stringify(nested ?? event) ?? "";
852
+ const summary = providerErrorMessage(event, nested);
853
+ const message = summary ?? (body === "{}" ? fallback : body);
841
854
  const status = typeof event.status === "number"
842
855
  ? event.status
843
856
  : typeof event.status_code === "number"
@@ -846,7 +859,8 @@ export const providerFailure = (id, event, fallback) => {
846
859
  return new AIError({
847
860
  module: id,
848
861
  method: "stream",
849
- reason: classifyProviderFailure({ message, code, status }),
862
+ body,
863
+ reason: classifyProviderFailure({ message, code, status, rawBody: body }),
850
864
  });
851
865
  };
852
866
  const providerError = (state, event, fallback) => providerFailure(state.id, event, fallback);
@@ -859,22 +873,18 @@ export const step = (state, event) => {
859
873
  : onOutputTextDone(state, event, event.item_id));
860
874
  }
861
875
  if (event.type === "response.refusal.delta" || event.type === "response.refusal.done") {
862
- if (!isRefusalEvent(event))
876
+ const value = event.type === "response.refusal.delta" ? event.delta : event.refusal;
877
+ if (!event.item_id || typeof value !== "string")
863
878
  return ProviderShared.eventError(state.id, `${event.type} is malformed`);
864
879
  return Effect.succeed(event.type === "response.refusal.delta"
865
880
  ? onOutputTextDelta(state, event, event.item_id)
866
- : onOutputTextDone(state, { ...event, text: event.refusal }, event.item_id));
881
+ : onOutputTextDone(state, { ...event, text: value }, event.item_id));
867
882
  }
868
883
  if (event.type === "response.reasoning.delta" || event.type === "response.reasoning_summary_text.delta") {
869
884
  if (!event.item_id)
870
885
  return ProviderShared.eventError(state.id, `${event.type} is missing item_id`);
871
886
  return Effect.succeed(onReasoningDelta(state, event, event.item_id));
872
887
  }
873
- if (event.type === "response.reasoning.done" || event.type === "response.reasoning_summary_text.done") {
874
- if (!event.item_id)
875
- return ProviderShared.eventError(state.id, `${event.type} is missing item_id`);
876
- return Effect.succeed(onReasoningDone(state, event));
877
- }
878
888
  if (event.type === "response.reasoning_summary_part.added")
879
889
  return event.item_id
880
890
  ? Effect.succeed(onReasoningSummaryPartAdded(state, event))
@@ -918,16 +928,10 @@ export const initial = (request, extension = BASE) => ({
918
928
  tools: ToolStream.empty(),
919
929
  lifecycle: Lifecycle.initial(),
920
930
  messageItems: new Set(),
921
- messagePhase: (value) => messagePhase(value, extension),
922
931
  messagePhases: {},
923
932
  reasoningItems: {},
924
933
  store: OpenResponsesOptions.resolve(request).store,
925
934
  });
926
- const messagePhase = (value, extension) => {
927
- if (value === "commentary" || value === "final_answer")
928
- return value;
929
- return extension.messagePhase?.(value);
930
- };
931
935
  export const protocol = Protocol.make({
932
936
  id: ADAPTER,
933
937
  body: {
@@ -31,8 +31,8 @@ export declare const route: Route<{
31
31
  } | {
32
32
  readonly type: "input_file";
33
33
  readonly filename: string;
34
- readonly file_data: string;
35
- readonly mime_type?: string | undefined;
34
+ readonly file_data?: string | undefined;
35
+ readonly file_url?: string | undefined;
36
36
  } | {
37
37
  readonly type: "input_text";
38
38
  readonly text: string;
@@ -45,7 +45,7 @@ export declare const route: Route<{
45
45
  }[];
46
46
  readonly role: "assistant";
47
47
  readonly id?: string | undefined;
48
- readonly phase?: "commentary" | "final_answer" | undefined;
48
+ readonly phase?: "commentary" | "final_answer" | null | undefined;
49
49
  } | {
50
50
  readonly type: "function_call";
51
51
  readonly name: string;
@@ -61,11 +61,14 @@ export declare const route: Route<{
61
61
  } | {
62
62
  readonly type: "input_file";
63
63
  readonly filename: string;
64
- readonly file_data: string;
65
- readonly mime_type?: string | undefined;
64
+ readonly file_data?: string | undefined;
65
+ readonly file_url?: string | undefined;
66
66
  } | {
67
67
  readonly type: "input_text";
68
68
  readonly text: string;
69
+ } | {
70
+ readonly type: "input_video";
71
+ readonly video_url: string;
69
72
  })[];
70
73
  })[];
71
74
  readonly model: string;