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

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;
@@ -547,8 +555,8 @@ export declare const fromRequest: (request: LLMRequest) => Effect.Effect<{
547
555
  } | {
548
556
  readonly type: "input_file";
549
557
  readonly filename: string;
550
- readonly file_data: string;
551
- readonly mime_type?: string | undefined;
558
+ readonly file_data?: string | undefined;
559
+ readonly file_url?: string | undefined;
552
560
  } | {
553
561
  readonly type: "input_text";
554
562
  readonly text: string;
@@ -561,7 +569,7 @@ export declare const fromRequest: (request: LLMRequest) => Effect.Effect<{
561
569
  }[];
562
570
  readonly role: "assistant";
563
571
  readonly id?: string | undefined;
564
- readonly phase?: "commentary" | "final_answer" | undefined;
572
+ readonly phase?: "commentary" | "final_answer" | null | undefined;
565
573
  } | {
566
574
  readonly type: "function_call";
567
575
  readonly name: string;
@@ -577,11 +585,14 @@ export declare const fromRequest: (request: LLMRequest) => Effect.Effect<{
577
585
  } | {
578
586
  readonly type: "input_file";
579
587
  readonly filename: string;
580
- readonly file_data: string;
581
- readonly mime_type?: string | undefined;
588
+ readonly file_data?: string | undefined;
589
+ readonly file_url?: string | undefined;
582
590
  } | {
583
591
  readonly type: "input_text";
584
592
  readonly text: string;
593
+ } | {
594
+ readonly type: "input_video";
595
+ readonly video_url: string;
585
596
  })[];
586
597
  })[];
587
598
  readonly model: string;
@@ -854,8 +865,8 @@ export declare const protocol: Protocol<{
854
865
  } | {
855
866
  readonly type: "input_file";
856
867
  readonly filename: string;
857
- readonly file_data: string;
858
- readonly mime_type?: string | undefined;
868
+ readonly file_data?: string | undefined;
869
+ readonly file_url?: string | undefined;
859
870
  } | {
860
871
  readonly type: "input_text";
861
872
  readonly text: string;
@@ -868,7 +879,7 @@ export declare const protocol: Protocol<{
868
879
  }[];
869
880
  readonly role: "assistant";
870
881
  readonly id?: string | undefined;
871
- readonly phase?: "commentary" | "final_answer" | undefined;
882
+ readonly phase?: "commentary" | "final_answer" | null | undefined;
872
883
  } | {
873
884
  readonly type: "function_call";
874
885
  readonly name: string;
@@ -884,11 +895,14 @@ export declare const protocol: Protocol<{
884
895
  } | {
885
896
  readonly type: "input_file";
886
897
  readonly filename: string;
887
- readonly file_data: string;
888
- readonly mime_type?: string | undefined;
898
+ readonly file_data?: string | undefined;
899
+ readonly file_url?: string | undefined;
889
900
  } | {
890
901
  readonly type: "input_text";
891
902
  readonly text: string;
903
+ } | {
904
+ readonly type: "input_video";
905
+ readonly video_url: string;
892
906
  })[];
893
907
  })[];
894
908
  readonly model: string;
@@ -1022,8 +1036,8 @@ export declare const httpTransport: HttpTransport.HttpJsonTransport<{
1022
1036
  } | {
1023
1037
  readonly type: "input_file";
1024
1038
  readonly filename: string;
1025
- readonly file_data: string;
1026
- readonly mime_type?: string | undefined;
1039
+ readonly file_data?: string | undefined;
1040
+ readonly file_url?: string | undefined;
1027
1041
  } | {
1028
1042
  readonly type: "input_text";
1029
1043
  readonly text: string;
@@ -1036,7 +1050,7 @@ export declare const httpTransport: HttpTransport.HttpJsonTransport<{
1036
1050
  }[];
1037
1051
  readonly role: "assistant";
1038
1052
  readonly id?: string | undefined;
1039
- readonly phase?: "commentary" | "final_answer" | undefined;
1053
+ readonly phase?: "commentary" | "final_answer" | null | undefined;
1040
1054
  } | {
1041
1055
  readonly type: "function_call";
1042
1056
  readonly name: string;
@@ -1052,11 +1066,14 @@ export declare const httpTransport: HttpTransport.HttpJsonTransport<{
1052
1066
  } | {
1053
1067
  readonly type: "input_file";
1054
1068
  readonly filename: string;
1055
- readonly file_data: string;
1056
- readonly mime_type?: string | undefined;
1069
+ readonly file_data?: string | undefined;
1070
+ readonly file_url?: string | undefined;
1057
1071
  } | {
1058
1072
  readonly type: "input_text";
1059
1073
  readonly text: string;
1074
+ } | {
1075
+ readonly type: "input_video";
1076
+ readonly video_url: string;
1060
1077
  })[];
1061
1078
  })[];
1062
1079
  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,7 @@ 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"]));
38
42
  const OpenResponsesReasoningSummaryText = Schema.Struct({
39
43
  type: Schema.tag("summary_text"),
40
44
  text: Schema.String,
@@ -56,6 +60,7 @@ const OpenResponsesFunctionCallOutputContent = Schema.Union([
56
60
  OpenResponsesInputText,
57
61
  OpenResponsesInputImage,
58
62
  OpenResponsesInputFile,
63
+ OpenResponsesInputVideo,
59
64
  ]);
60
65
  const OpenResponsesFunctionCallOutput = Schema.Union([
61
66
  Schema.String,
@@ -282,33 +287,49 @@ const lowerReasoning = (part, providerMetadataKey) => {
282
287
  const hostedToolItemID = (part, providerMetadataKey) => {
283
288
  return itemID(part.providerMetadata, providerMetadataKey);
284
289
  };
285
- const lowerMedia = Effect.fn("OpenResponses.lowerMedia")(function* (part, request, extension) {
290
+ const lowerMedia = Effect.fn("OpenResponses.lowerMedia")(function* (part, request, extension, target) {
286
291
  const media = ProviderShared.normalizeMedia(part);
287
292
  const extended = extension.lowerMedia?.({ part, media, request });
288
293
  if (extended)
289
294
  return extended;
295
+ const url = typeof part.data === "string" && (part.data.startsWith("https://") || part.data.startsWith("http://"))
296
+ ? part.data
297
+ : undefined;
290
298
  if (!media.mime.startsWith("image/")) {
299
+ if (target === "tool-result" && media.mime.startsWith("video/"))
300
+ return { type: "input_video", video_url: url ?? media.dataUrl };
291
301
  return {
292
302
  type: "input_file",
293
303
  filename: part.filename ?? (media.mime === "application/pdf" ? "document.pdf" : "file"),
294
- file_data: media.dataUrl,
304
+ ...(url ? { file_url: url } : { file_data: media.base64 }),
295
305
  };
296
306
  }
297
- return { type: "input_image", image_url: media.dataUrl };
307
+ return { type: "input_image", image_url: url ?? media.dataUrl };
298
308
  });
299
309
  const lowerUserContent = Effect.fnUntraced(function* (part, request, extension) {
300
310
  if (part.type === "text")
301
311
  return { type: "input_text", text: part.text };
302
312
  if (part.type === "media")
303
- return yield* lowerMedia(part, request, extension);
313
+ return yield* lowerMessageMedia(part, request, extension);
304
314
  return yield* ProviderShared.unsupportedContent(extension.name, "user", ["text", "media"]);
305
315
  });
316
+ const lowerMessageMedia = Effect.fnUntraced(function* (part, request, extension) {
317
+ const lowered = yield* lowerMedia(part, request, extension, "message");
318
+ if (lowered.type === "input_video")
319
+ return yield* ProviderShared.invalidRequest(`${extension.name} user messages do not support input_video`);
320
+ return lowered;
321
+ });
306
322
  // Tool results may carry structured text, images, and files. Keep media as provider-native
307
323
  // content instead of JSON-stringifying base64 into a prompt string.
308
324
  const lowerToolResultContentItem = Effect.fnUntraced(function* (item, request, extension) {
309
325
  if (item.type === "text")
310
326
  return { type: "input_text", text: item.text };
311
- return yield* lowerMedia({ type: "media", mediaType: item.mime, data: item.uri, filename: item.name }, request, extension);
327
+ return yield* lowerMedia({ type: "media", mediaType: item.mime, data: item.uri, filename: item.name }, request, extension, "tool-result");
328
+ });
329
+ const lowerHostedToolResultContentItem = Effect.fnUntraced(function* (item, request, extension) {
330
+ if (item.type === "text")
331
+ return { type: "input_text", text: item.text };
332
+ return yield* lowerMessageMedia({ type: "media", mediaType: item.mime, data: item.uri, filename: item.name }, request, extension);
312
333
  });
313
334
  const lowerToolResultOutput = Effect.fnUntraced(function* (part, request, extension) {
314
335
  // Text/json/error results are encoded as a plain string for backward
@@ -350,7 +371,7 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
350
371
  const groups = content.reduce((groups, part) => {
351
372
  const metadata = part.providerMetadata?.[providerMetadataKey];
352
373
  const id = itemID(part.providerMetadata, providerMetadataKey);
353
- const phase = ProviderShared.isRecord(metadata) ? messagePhase(metadata.phase, extension) : undefined;
374
+ const phase = ProviderShared.isRecord(metadata) ? messagePhase(metadata.phase) : undefined;
354
375
  const group = groups.at(-1);
355
376
  if (group && group.id === id && group.phase === phase)
356
377
  group.parts.push(part);
@@ -410,7 +431,7 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
410
431
  const content = part.result.value;
411
432
  input.push({
412
433
  role: "user",
413
- content: yield* Effect.forEach(content, (item) => lowerToolResultContentItem(item, request, extension)),
434
+ content: yield* Effect.forEach(content, (item) => lowerHostedToolResultContentItem(item, request, extension)),
414
435
  });
415
436
  }
416
437
  if (itemID)
@@ -918,15 +939,15 @@ export const initial = (request, extension = BASE) => ({
918
939
  tools: ToolStream.empty(),
919
940
  lifecycle: Lifecycle.initial(),
920
941
  messageItems: new Set(),
921
- messagePhase: (value) => messagePhase(value, extension),
942
+ messagePhase,
922
943
  messagePhases: {},
923
944
  reasoningItems: {},
924
945
  store: OpenResponsesOptions.resolve(request).store,
925
946
  });
926
- const messagePhase = (value, extension) => {
927
- if (value === "commentary" || value === "final_answer")
947
+ const messagePhase = (value) => {
948
+ if (value === null || value === "commentary" || value === "final_answer")
928
949
  return value;
929
- return extension.messagePhase?.(value);
950
+ return undefined;
930
951
  };
931
952
  export const protocol = Protocol.make({
932
953
  id: ADAPTER,
@@ -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;