@opencode-ai/ai 0.0.0-beta-18155 → 0.0.0-beta-18219

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.
@@ -1,7 +1,7 @@
1
1
  import { Context, Effect, Layer } from "effect";
2
2
  import { RequestExecutor } from "./route/executor.js";
3
+ import { type AIError } from "./schema/index.js";
3
4
  import type { ImageOptions, ImageRequestFor, ImageResponse } from "./image.js";
4
- import type { AIError } from "./schema/index.js";
5
5
  export type Execute = RequestExecutor.Interface["execute"];
6
6
  export interface Interface {
7
7
  readonly generate: <Options extends ImageOptions>(request: ImageRequestFor<Options>) => Effect.Effect<ImageResponse, AIError>;
@@ -1,5 +1,7 @@
1
1
  import { Context, Effect, Layer } from "effect";
2
2
  import { RequestExecutor } from "./route/executor.js";
3
+ import { mergeHttpOptions } from "./schema/index.js";
4
+ import { sanitizeSurrogates } from "./utils/sanitize.js";
3
5
  export class Service extends Context.Service()("@opencode/ImageClient") {
4
6
  }
5
7
  export const generate = (request) => Effect.gen(function* () {
@@ -9,7 +11,14 @@ export const generate = (request) => Effect.gen(function* () {
9
11
  export const layer = Layer.effect(Service, Effect.gen(function* () {
10
12
  const executor = yield* RequestExecutor.Service;
11
13
  return Service.of({
12
- generate: (request) => request.model.route.generate(request, executor.execute),
14
+ generate: (request) => request.model.route.generate({
15
+ ...sanitizeSurrogates({
16
+ ...request,
17
+ model: undefined,
18
+ http: mergeHttpOptions(request.model.http, request.http),
19
+ }),
20
+ model: request.model,
21
+ }, executor.execute),
13
22
  });
14
23
  }));
15
24
  export const ImageClient = {
@@ -584,15 +584,7 @@ export declare const protocol: Protocol<{
584
584
  readonly type?: string | undefined;
585
585
  readonly message?: string | undefined;
586
586
  } | undefined;
587
- readonly delta?: {
588
- readonly type?: string | undefined;
589
- readonly text?: string | undefined;
590
- readonly thinking?: string | undefined;
591
- readonly signature?: string | undefined;
592
- readonly partial_json?: string | undefined;
593
- readonly stop_reason?: string | null | undefined;
594
- readonly stop_sequence?: string | null | undefined;
595
- } | undefined;
587
+ readonly delta?: unknown;
596
588
  readonly index?: number | undefined;
597
589
  readonly usage?: {
598
590
  readonly [x: string]: unknown;
@@ -609,18 +601,7 @@ export declare const protocol: Protocol<{
609
601
  readonly thinking_tokens?: number | undefined;
610
602
  } | null | undefined;
611
603
  } | undefined;
612
- readonly content_block?: {
613
- readonly type: string;
614
- readonly id?: string | undefined;
615
- readonly data?: string | undefined;
616
- readonly name?: string | undefined;
617
- readonly input?: unknown;
618
- readonly text?: string | undefined;
619
- readonly content?: unknown;
620
- readonly thinking?: string | undefined;
621
- readonly signature?: string | undefined;
622
- readonly tool_use_id?: string | undefined;
623
- } | undefined;
604
+ readonly content_block?: unknown;
624
605
  }, {
625
606
  tools: Partial<Record<number, ToolStream.PendingTool>>;
626
607
  reasoningSignatures: {};
@@ -1,5 +1,5 @@
1
1
  import { Buffer } from "node:buffer";
2
- import { Effect, Schema } from "effect";
2
+ import { Effect, Option, Schema } from "effect";
3
3
  import { Tool } from "@opencode-ai/schema/tool";
4
4
  import { Route } from "../route/client.js";
5
5
  import { Auth } from "../route/auth.js";
@@ -264,6 +264,7 @@ const AnthropicStreamBlock = Schema.Struct({
264
264
  tool_use_id: Schema.optional(Schema.String),
265
265
  content: Schema.optional(Schema.Unknown),
266
266
  });
267
+ const decodeAnthropicStreamBlock = Schema.decodeUnknownOption(AnthropicStreamBlock);
267
268
  const AnthropicStreamDelta = Schema.Struct({
268
269
  type: Schema.optional(Schema.String),
269
270
  text: Schema.optional(Schema.String),
@@ -273,12 +274,13 @@ const AnthropicStreamDelta = Schema.Struct({
273
274
  stop_reason: optionalNull(Schema.String),
274
275
  stop_sequence: optionalNull(Schema.String),
275
276
  });
277
+ const decodeAnthropicStreamDelta = Schema.decodeUnknownOption(AnthropicStreamDelta);
276
278
  const AnthropicEvent = Schema.Struct({
277
279
  type: Schema.String,
278
280
  index: Schema.optional(Schema.Number),
279
281
  message: Schema.optional(Schema.Struct({ usage: Schema.optional(AnthropicUsage) })),
280
- content_block: Schema.optional(AnthropicStreamBlock),
281
- delta: Schema.optional(AnthropicStreamDelta),
282
+ content_block: Schema.optional(Schema.Unknown),
283
+ delta: Schema.optional(Schema.Unknown),
282
284
  usage: Schema.optional(AnthropicUsage),
283
285
  // `type` and `message` are both required per Anthropic's spec, but
284
286
  // OpenAI-compatible proxies and gateway translations occasionally drop one
@@ -1044,6 +1046,8 @@ const onContentBlockStart = (state, event) => {
1044
1046
  const onContentBlockDelta = Effect.fn("AnthropicMessages.onContentBlockDelta")(function* (state, event) {
1045
1047
  const delta = event.delta;
1046
1048
  if (delta?.type === "text_delta" && delta.text) {
1049
+ if (!state.lifecycle.text.has(`text-${event.index ?? 0}`))
1050
+ return [state, NO_EVENTS];
1047
1051
  const events = [];
1048
1052
  return [
1049
1053
  { ...state, lifecycle: Lifecycle.textDelta(state.lifecycle, events, `text-${event.index ?? 0}`, delta.text) },
@@ -1051,6 +1055,8 @@ const onContentBlockDelta = Effect.fn("AnthropicMessages.onContentBlockDelta")(f
1051
1055
  ];
1052
1056
  }
1053
1057
  if (delta?.type === "thinking_delta" && delta.thinking) {
1058
+ if (!state.lifecycle.reasoning.has(`reasoning-${event.index ?? 0}`))
1059
+ return [state, NO_EVENTS];
1054
1060
  const events = [];
1055
1061
  return [
1056
1062
  {
@@ -1062,6 +1068,8 @@ const onContentBlockDelta = Effect.fn("AnthropicMessages.onContentBlockDelta")(f
1062
1068
  }
1063
1069
  if (delta?.type === "signature_delta" && delta.signature) {
1064
1070
  const index = event.index ?? 0;
1071
+ if (!state.lifecycle.reasoning.has(`reasoning-${index}`))
1072
+ return [state, NO_EVENTS];
1065
1073
  return [
1066
1074
  {
1067
1075
  ...state,
@@ -1148,25 +1156,62 @@ const onError = (event) => Effect.fail(new AIError({
1148
1156
  method: "stream",
1149
1157
  reason: classifyProviderFailure({ message: providerErrorMessage(event), code: event.error?.type }),
1150
1158
  }));
1159
+ const isKnownStreamBlockType = (type) => type === "text" ||
1160
+ type === "thinking" ||
1161
+ type === "redacted_thinking" ||
1162
+ type === "tool_use" ||
1163
+ type === "server_tool_use" ||
1164
+ isServerToolResultType(type);
1165
+ const isKnownStreamDeltaType = (type) => type === "text_delta" || type === "thinking_delta" || type === "signature_delta" || type === "input_json_delta";
1166
+ const invalidStreamEvent = (event) => Effect.fail(ProviderShared.eventError(ADAPTER, "Invalid anthropic/anthropic-messages stream event", ProviderShared.encodeJson(event)));
1151
1167
  const step = (state, event) => {
1168
+ if (!SSE_EVENTS.has(event.type))
1169
+ return Effect.succeed([state, NO_EVENTS]);
1170
+ if (event.type !== "content_block_start" &&
1171
+ event.content_block !== undefined &&
1172
+ Option.isNone(decodeAnthropicStreamBlock(event.content_block)))
1173
+ return invalidStreamEvent(event);
1174
+ if (event.type !== "content_block_delta" &&
1175
+ event.delta !== undefined &&
1176
+ Option.isNone(decodeAnthropicStreamDelta(event.delta)))
1177
+ return invalidStreamEvent(event);
1152
1178
  if (event.type === "message_start")
1153
1179
  return Effect.succeed(onMessageStart(state, event));
1154
1180
  if (event.type === "content_block_start") {
1155
- const block = event.content_block;
1156
- if (block && (block.type === "tool_use" || block.type === "server_tool_use")) {
1181
+ if (!ProviderShared.isRecord(event.content_block) || typeof event.content_block.type !== "string")
1182
+ return invalidStreamEvent(event);
1183
+ if (!isKnownStreamBlockType(event.content_block.type))
1184
+ return Effect.succeed([state, NO_EVENTS]);
1185
+ const decoded = decodeAnthropicStreamBlock(event.content_block);
1186
+ if (Option.isNone(decoded))
1187
+ return invalidStreamEvent(event);
1188
+ const block = decoded.value;
1189
+ if (block.type === "tool_use" || block.type === "server_tool_use") {
1157
1190
  if (event.index === undefined)
1158
1191
  return Effect.fail(ProviderShared.eventError(ADAPTER, `Anthropic ${block.type} missing index`));
1159
1192
  if (!block.id)
1160
1193
  return Effect.fail(ProviderShared.eventError(ADAPTER, `Anthropic tool_use missing id at index ${event.index}`));
1161
1194
  }
1162
- return Effect.succeed(onContentBlockStart(state, event));
1195
+ return Effect.succeed(onContentBlockStart(state, { ...event, content_block: block }));
1196
+ }
1197
+ if (event.type === "content_block_delta") {
1198
+ if (!ProviderShared.isRecord(event.delta))
1199
+ return invalidStreamEvent(event);
1200
+ if (typeof event.delta.type === "string" && !isKnownStreamDeltaType(event.delta.type))
1201
+ return Effect.succeed([state, NO_EVENTS]);
1202
+ const decoded = decodeAnthropicStreamDelta(event.delta);
1203
+ if (Option.isNone(decoded))
1204
+ return invalidStreamEvent(event);
1205
+ return onContentBlockDelta(state, { ...event, delta: decoded.value });
1163
1206
  }
1164
- if (event.type === "content_block_delta")
1165
- return onContentBlockDelta(state, event);
1166
1207
  if (event.type === "content_block_stop")
1167
1208
  return onContentBlockStop(state, event);
1168
- if (event.type === "message_delta")
1169
- return Effect.succeed(onMessageDelta(state, event));
1209
+ if (event.type === "message_delta") {
1210
+ const decoded = decodeAnthropicStreamDelta(event.delta);
1211
+ if (Option.isNone(decoded))
1212
+ return invalidStreamEvent(event);
1213
+ return Effect.succeed(onMessageDelta(state, { ...event, delta: decoded.value }));
1214
+ }
1170
1215
  if (event.type === "message_stop")
1171
1216
  return onMessageStop(state);
1172
1217
  if (event.type === "error")
@@ -273,6 +273,14 @@ export declare const protocol: Protocol<{
273
273
  } | undefined;
274
274
  readonly metrics?: unknown;
275
275
  } | undefined;
276
+ readonly exception?: {
277
+ readonly type: string;
278
+ readonly details: {
279
+ readonly message?: string | undefined;
280
+ readonly originalMessage?: string | undefined;
281
+ readonly originalStatusCode?: number | undefined;
282
+ };
283
+ } | undefined;
276
284
  readonly messageStart?: {
277
285
  readonly role: string;
278
286
  } | undefined;
@@ -307,31 +315,6 @@ export declare const protocol: Protocol<{
307
315
  readonly stopReason: string;
308
316
  readonly additionalModelResponseFields?: unknown;
309
317
  } | undefined;
310
- readonly internalServerException?: {
311
- readonly message?: string | undefined;
312
- readonly originalMessage?: string | undefined;
313
- readonly originalStatusCode?: number | undefined;
314
- } | undefined;
315
- readonly modelStreamErrorException?: {
316
- readonly message?: string | undefined;
317
- readonly originalMessage?: string | undefined;
318
- readonly originalStatusCode?: number | undefined;
319
- } | undefined;
320
- readonly validationException?: {
321
- readonly message?: string | undefined;
322
- readonly originalMessage?: string | undefined;
323
- readonly originalStatusCode?: number | undefined;
324
- } | undefined;
325
- readonly throttlingException?: {
326
- readonly message?: string | undefined;
327
- readonly originalMessage?: string | undefined;
328
- readonly originalStatusCode?: number | undefined;
329
- } | undefined;
330
- readonly serviceUnavailableException?: {
331
- readonly message?: string | undefined;
332
- readonly originalMessage?: string | undefined;
333
- readonly originalStatusCode?: number | undefined;
334
- } | undefined;
335
318
  }, {
336
319
  readonly metadata?: {
337
320
  readonly usage?: {
@@ -343,6 +326,14 @@ export declare const protocol: Protocol<{
343
326
  } | undefined;
344
327
  readonly metrics?: unknown;
345
328
  } | undefined;
329
+ readonly exception?: {
330
+ readonly type: string;
331
+ readonly details: {
332
+ readonly message?: string | undefined;
333
+ readonly originalMessage?: string | undefined;
334
+ readonly originalStatusCode?: number | undefined;
335
+ };
336
+ } | undefined;
346
337
  readonly messageStart?: {
347
338
  readonly role: string;
348
339
  } | undefined;
@@ -377,31 +368,6 @@ export declare const protocol: Protocol<{
377
368
  readonly stopReason: string;
378
369
  readonly additionalModelResponseFields?: unknown;
379
370
  } | undefined;
380
- readonly internalServerException?: {
381
- readonly message?: string | undefined;
382
- readonly originalMessage?: string | undefined;
383
- readonly originalStatusCode?: number | undefined;
384
- } | undefined;
385
- readonly modelStreamErrorException?: {
386
- readonly message?: string | undefined;
387
- readonly originalMessage?: string | undefined;
388
- readonly originalStatusCode?: number | undefined;
389
- } | undefined;
390
- readonly validationException?: {
391
- readonly message?: string | undefined;
392
- readonly originalMessage?: string | undefined;
393
- readonly originalStatusCode?: number | undefined;
394
- } | undefined;
395
- readonly throttlingException?: {
396
- readonly message?: string | undefined;
397
- readonly originalMessage?: string | undefined;
398
- readonly originalStatusCode?: number | undefined;
399
- } | undefined;
400
- readonly serviceUnavailableException?: {
401
- readonly message?: string | undefined;
402
- readonly originalMessage?: string | undefined;
403
- readonly originalStatusCode?: number | undefined;
404
- } | undefined;
405
371
  }, ParserState>;
406
372
  export declare const route: Route<{
407
373
  readonly messages: readonly ({
@@ -149,11 +149,7 @@ const BedrockEvent = Schema.Struct({
149
149
  usage: Schema.optional(BedrockUsageSchema),
150
150
  metrics: Schema.optional(Schema.Unknown),
151
151
  })),
152
- internalServerException: Schema.optional(BedrockStreamException),
153
- modelStreamErrorException: Schema.optional(BedrockStreamException),
154
- validationException: Schema.optional(BedrockStreamException),
155
- throttlingException: Schema.optional(BedrockStreamException),
156
- serviceUnavailableException: Schema.optional(BedrockStreamException),
152
+ exception: Schema.optional(Schema.Struct({ type: Schema.String, details: BedrockStreamException })),
157
153
  });
158
154
  // =============================================================================
159
155
  // Request Lowering
@@ -507,20 +503,13 @@ const step = (state, event) => Effect.gen(function* () {
507
503
  [],
508
504
  ];
509
505
  }
510
- const exception = [
511
- ["internalServerException", event.internalServerException],
512
- ["modelStreamErrorException", event.modelStreamErrorException],
513
- ["serviceUnavailableException", event.serviceUnavailableException],
514
- ["throttlingException", event.throttlingException],
515
- ["validationException", event.validationException],
516
- ].find((entry) => entry[1] !== undefined);
517
- if (exception) {
506
+ if (event.exception) {
518
507
  return yield* new AIError({
519
508
  module: ADAPTER,
520
509
  method: "stream",
521
510
  reason: classifyProviderFailure({
522
- message: exception[1]?.message ?? exception[1]?.originalMessage ?? "Bedrock Converse stream error",
523
- code: exception[0],
511
+ message: event.exception.details.message ?? event.exception.details.originalMessage ?? "Bedrock Converse stream error",
512
+ code: event.exception.type,
524
513
  }),
525
514
  });
526
515
  }
@@ -56,7 +56,7 @@ const consumeFrames = (route) => (state, chunk) => Effect.gen(function* () {
56
56
  // against ad-hoc `JSON.parse` calls.
57
57
  const parsed = (yield* ProviderShared.parseJson(route, payload, "Failed to parse Bedrock Converse event-stream payload"));
58
58
  delete parsed.p;
59
- out.push({ [eventType]: parsed });
59
+ out.push(messageType === "exception" ? { exception: { type: eventType, details: parsed } } : { [eventType]: parsed });
60
60
  }
61
61
  return [cursor, out];
62
62
  });
@@ -133,7 +133,12 @@ export const driver = (input) => {
133
133
  ...observation,
134
134
  checkpoint: {
135
135
  protocol: PROTOCOL,
136
- value: { version: VERSION, responseID, request, output: output.slice() },
136
+ value: {
137
+ version: VERSION,
138
+ responseID,
139
+ request,
140
+ output: event.response?.output ? [...event.response.output] : output.slice(),
141
+ },
137
142
  },
138
143
  };
139
144
  }),
@@ -387,6 +387,7 @@ export declare const Event: Schema.StructWithRest<Schema.Struct<{
387
387
  readonly arguments: Schema.optional<Schema.String>;
388
388
  readonly text: Schema.optional<Schema.String>;
389
389
  readonly item_id: Schema.optional<Schema.String>;
390
+ readonly output_index: Schema.optional<Schema.Number>;
390
391
  readonly summary_index: Schema.optional<Schema.Number>;
391
392
  readonly item: Schema.optional<Schema.StructWithRest<Schema.Struct<{
392
393
  readonly type: Schema.String;
@@ -402,6 +403,14 @@ export declare const Event: Schema.StructWithRest<Schema.Struct<{
402
403
  readonly incomplete_details: Schema.optional<Schema.NullOr<Schema.Struct<{
403
404
  readonly reason: Schema.optional<Schema.String>;
404
405
  }>>>;
406
+ readonly output: Schema.optional<Schema.$Array<Schema.StructWithRest<Schema.Struct<{
407
+ readonly type: Schema.String;
408
+ readonly id: Schema.optional<Schema.String>;
409
+ readonly call_id: Schema.optional<Schema.String>;
410
+ readonly name: Schema.optional<Schema.String>;
411
+ readonly arguments: Schema.optional<Schema.String>;
412
+ readonly encrypted_content: Schema.optional<Schema.NullOr<Schema.String>>;
413
+ }>, readonly [Schema.$Record<Schema.String, Schema.Unknown>]>>>;
405
414
  readonly usage: Schema.optional<Schema.NullOr<Schema.Struct<{
406
415
  readonly input_tokens: Schema.optional<Schema.Number>;
407
416
  readonly input_tokens_details: Schema.optional<Schema.NullOr<Schema.Struct<{
@@ -453,6 +462,7 @@ export interface ParserState {
453
462
  readonly tools: ToolStream.State<string>;
454
463
  readonly hasFunctionCall: boolean;
455
464
  readonly lifecycle: Lifecycle.State;
465
+ readonly outputItems: Readonly<Record<number, string>>;
456
466
  readonly messageItems: ReadonlySet<string>;
457
467
  readonly messagePhases: Readonly<Record<string, MessagePhase | null>>;
458
468
  readonly reasoningItems: Readonly<Record<string, ReasoningStreamItem>>;
@@ -653,10 +663,11 @@ export declare const fromRequest: (request: LLMRequest) => Effect.Effect<{
653
663
  export declare const providerMetadata: (state: ParserState, metadata: Record<string, unknown>) => ProviderMetadata;
654
664
  export type StepResult = readonly [ParserState, ReadonlyArray<LLMEvent>];
655
665
  export declare const terminal: (event: Event) => boolean;
666
+ export declare const outputItemID: (state: ParserState, event: Event) => string | undefined;
656
667
  export declare const onReasoningDelta: (state: ParserState, event: Event, itemID: string) => StepResult;
657
668
  export declare const onReasoningDone: (state: ParserState, event: Event, itemID: string) => StepResult;
658
669
  export declare const providerFailure: (id: string, event: Event, fallback: string) => AIError;
659
- export declare const step: (state: ParserState, event: Event) => AIError | Effect.Effect<StepResult, never, never> | Effect.Effect<[ParserState, readonly ({
670
+ export declare const step: (state: ParserState, input: Event) => AIError | Effect.Effect<[ParserState, readonly ({
660
671
  readonly type: "step-start";
661
672
  readonly index: number;
662
673
  } | {
@@ -838,7 +849,7 @@ export declare const step: (state: ParserState, event: Event) => AIError | Effec
838
849
  };
839
850
  } | undefined;
840
851
  readonly classification?: "context-overflow" | "payload-too-large" | undefined;
841
- })[]], AIError, never>;
852
+ })[]], AIError, never> | Effect.Effect<StepResult, never, never>;
842
853
  /**
843
854
  * The provider-neutral Open Responses protocol. Provider-specific Responses
844
855
  * implementations compose this baseline with their own tools and event variants.
@@ -987,6 +998,15 @@ export declare const protocol: Protocol<{
987
998
  readonly response?: {
988
999
  readonly [x: string]: unknown;
989
1000
  readonly id?: string | undefined;
1001
+ readonly output?: readonly {
1002
+ readonly [x: string]: unknown;
1003
+ readonly type: string;
1004
+ readonly id?: string | undefined;
1005
+ readonly name?: string | undefined;
1006
+ readonly arguments?: string | undefined;
1007
+ readonly encrypted_content?: string | null | undefined;
1008
+ readonly call_id?: string | undefined;
1009
+ }[] | undefined;
990
1010
  readonly error?: {
991
1011
  readonly type?: string | null | undefined;
992
1012
  readonly code?: string | null | undefined;
@@ -1014,6 +1034,7 @@ export declare const protocol: Protocol<{
1014
1034
  readonly param?: string | null | undefined;
1015
1035
  readonly status_code?: unknown;
1016
1036
  readonly item_id?: string | undefined;
1037
+ readonly output_index?: number | undefined;
1017
1038
  readonly summary_index?: number | undefined;
1018
1039
  }, ParserState>;
1019
1040
  export declare const httpTransport: HttpTransport.HttpJsonTransport<{
@@ -207,12 +207,14 @@ export const Event = Schema.StructWithRest(Schema.Struct({
207
207
  arguments: Schema.optional(Schema.String),
208
208
  text: Schema.optional(Schema.String),
209
209
  item_id: Schema.optional(Schema.String),
210
+ output_index: Schema.optional(Schema.Number),
210
211
  summary_index: Schema.optional(Schema.Number),
211
212
  item: Schema.optional(StreamItem),
212
213
  response: Schema.optional(Schema.StructWithRest(Schema.Struct({
213
214
  id: Schema.optional(Schema.String),
214
215
  service_tier: optionalNull(Schema.String),
215
216
  incomplete_details: optionalNull(Schema.Struct({ reason: Schema.optional(Schema.String) })),
217
+ output: Schema.optional(Schema.Array(StreamItem)),
216
218
  usage: optionalNull(OpenResponsesUsage),
217
219
  error: optionalNull(OpenResponsesErrorPayload),
218
220
  }), [Schema.Record(Schema.String, Schema.Unknown)])),
@@ -462,16 +464,11 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
462
464
  });
463
465
  }
464
466
  }
465
- // With store:false, Responses APIs only accept previous reasoning items when the
466
- // complete item has encrypted state. Summary blocks for one item may carry
467
- // that state only on the last block, so filter after they have been joined.
468
- return store === false
469
- ? input.filter((item) => !("type" in item) || item.type !== "reasoning" || typeof item.encrypted_content === "string")
470
- : input;
467
+ return input;
471
468
  });
472
469
  const lowerOptions = (request) => {
473
470
  const options = OpenResponsesOptions.resolve(request);
474
- const cacheKey = ProviderShared.clampPromptCacheKey(request.promptCacheKey);
471
+ const cacheKey = ProviderShared.promptCacheKey(request);
475
472
  const parallelToolCalls = resolveParallelToolCalls(request);
476
473
  return {
477
474
  ...(options.instructions ? { instructions: options.instructions } : {}),
@@ -603,6 +600,7 @@ const onOutputTextDone = (state, event, id) => {
603
600
  const events = [];
604
601
  return [{ ...state, lifecycle: Lifecycle.textEnd(state.lifecycle, events, id) }, events];
605
602
  };
603
+ export const outputItemID = (state, event) => event.output_index === undefined ? event.item_id : (state.outputItems[event.output_index] ?? event.item_id);
606
604
  export const onReasoningDelta = (state, event, itemID) => {
607
605
  const item = state.reasoningItems[itemID];
608
606
  if (!event.delta || !item)
@@ -855,27 +853,37 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
855
853
  return [state, NO_EVENTS];
856
854
  });
857
855
  const onResponseFinish = Effect.fn("OpenResponses.onResponseFinish")(function* (state, event) {
856
+ const reconciled = event.type === "response.completed"
857
+ ? yield* Effect.reduce(event.response?.output ?? [], () => [state, NO_EVENTS], ([current, events], item) => {
858
+ if (!item.id ||
859
+ ((item.type !== "function_call" || !current.tools[item.id]) &&
860
+ (item.type !== "reasoning" || !current.reasoningItems[item.id])))
861
+ return Effect.succeed([current, events]);
862
+ return onOutputItemDone(current, { type: "response.output_item.done", item }).pipe(Effect.map(([next, emitted]) => [next, [...events, ...emitted]]));
863
+ })
864
+ : [state, NO_EVENTS];
865
+ const current = reconciled[0];
858
866
  // Some compatible providers omit output_item.done even after completing the response.
859
867
  const pending = event.type === "response.completed"
860
- ? yield* ToolStream.finishAll(state.id, state.tools)
861
- : { tools: state.tools, events: NO_EVENTS };
862
- const events = [...pending.events];
868
+ ? yield* ToolStream.finishAll(current.id, current.tools)
869
+ : { tools: current.tools, events: NO_EVENTS };
870
+ const events = [...reconciled[1], ...pending.events];
863
871
  const hasFunctionCall = pending.events.some((event) => LLMEvent.is.toolCall(event) || LLMEvent.is.toolInputError(event)) ||
864
- state.hasFunctionCall;
865
- const lifecycle = Lifecycle.finish(state.lifecycle, events, {
872
+ current.hasFunctionCall;
873
+ const lifecycle = Lifecycle.finish(current.lifecycle, events, {
866
874
  reason: {
867
875
  normalized: mapFinishReason(event, hasFunctionCall),
868
876
  raw: event.response?.incomplete_details?.reason,
869
877
  },
870
- usage: mapUsage(event.response?.usage, state.providerMetadataKey),
878
+ usage: mapUsage(event.response?.usage, current.providerMetadataKey),
871
879
  providerMetadata: event.response?.id || event.response?.service_tier
872
- ? providerMetadata(state, {
880
+ ? providerMetadata(current, {
873
881
  responseId: event.response.id,
874
882
  serviceTier: event.response.service_tier,
875
883
  })
876
884
  : undefined,
877
885
  });
878
- return [{ ...state, lifecycle, hasFunctionCall, tools: pending.tools }, events];
886
+ return [{ ...current, lifecycle, hasFunctionCall, tools: pending.tools }, events];
879
887
  });
880
888
  // Build the prettiest summary available from whatever the provider supplied.
881
889
  // When both code and message are present, prefix the code so consumers see
@@ -917,7 +925,10 @@ export const providerFailure = (id, event, fallback) => {
917
925
  });
918
926
  };
919
927
  const providerError = (state, event, fallback) => providerFailure(state.id, event, fallback);
920
- export const step = (state, event) => {
928
+ export const step = (state, input) => {
929
+ const event = input.item_id && outputItemID(state, input) !== input.item_id
930
+ ? { ...input, item_id: outputItemID(state, input) }
931
+ : input;
921
932
  if (event.type === "response.output_text.delta" || event.type === "response.output_text.done") {
922
933
  if (!event.item_id)
923
934
  return ProviderShared.eventError(state.id, `${event.type} is missing item_id`);
@@ -956,7 +967,9 @@ export const step = (state, event) => {
956
967
  if (event.type === "response.output_item.added") {
957
968
  if (event.item?.type === "message" && !event.item.id)
958
969
  return ProviderShared.eventError(state.id, `${event.type} message is missing id`);
959
- return Effect.succeed(onOutputItemAdded(state, event));
970
+ return Effect.succeed(onOutputItemAdded(event.output_index !== undefined && event.item?.id
971
+ ? { ...state, outputItems: { ...state.outputItems, [event.output_index]: event.item.id } }
972
+ : state, event));
960
973
  }
961
974
  if (event.type === "response.function_call_arguments.delta" || event.type === "response.function_call_arguments.done")
962
975
  return event.item_id
@@ -989,6 +1002,7 @@ export const initial = (request, extension = BASE) => ({
989
1002
  hasFunctionCall: false,
990
1003
  tools: ToolStream.empty(),
991
1004
  lifecycle: Lifecycle.initial(),
1005
+ outputItems: {},
992
1006
  messageItems: new Set(),
993
1007
  messagePhases: {},
994
1008
  reasoningItems: {},
@@ -349,13 +349,22 @@ const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request,
349
349
  ]
350
350
  : [{ role: "system", content: ProviderShared.joinText(request.system) }];
351
351
  const messages = [...system];
352
+ const requireAssistantAfterTool = request.model.compatibility?.requireAssistantAfterTool ??
353
+ ["mistral", "devstral", "codestral", "pixtral", "mixtral"].some((family) => request.model.id.toLowerCase().includes(family));
354
+ const bridgeTools = () => {
355
+ if (requireAssistantAfterTool && messages.at(-1)?.role === "tool")
356
+ messages.push({ role: "assistant", content: "Done." });
357
+ };
352
358
  const pendingImages = [];
353
359
  const flushImages = () => {
354
360
  if (pendingImages.length === 0)
355
361
  return;
362
+ bridgeTools();
356
363
  messages.push({ role: "user", content: pendingImages.splice(0) });
357
364
  };
358
365
  for (const message of request.messages) {
366
+ if (message.role === "user")
367
+ bridgeTools();
359
368
  if (message.role === "system") {
360
369
  const part = yield* ProviderShared.wrappedSystemUpdate("OpenAI Chat", message);
361
370
  if (pendingImages.length > 0) {
@@ -396,6 +405,8 @@ const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request,
396
405
  : { role: "user", content: part.text });
397
406
  continue;
398
407
  }
408
+ if (message.role === "assistant" && message.content.every((part) => part.type === "text" && part.text.trim() === ""))
409
+ continue;
399
410
  if (message.role === "tool") {
400
411
  const lowered = yield* lowerToolMessages(message, options);
401
412
  messages.push(...lowered.messages);
@@ -517,7 +528,7 @@ const detectZaiToolStream = (provider, baseURL, modelID) => {
517
528
  };
518
529
  const lowerOptions = (request, supportsStore) => {
519
530
  const options = OpenAIOptions.resolve(request);
520
- const cacheKey = ProviderShared.clampPromptCacheKey(request.promptCacheKey);
531
+ const cacheKey = ProviderShared.promptCacheKey(request);
521
532
  return {
522
533
  ...(supportsStore && options.store !== undefined ? { store: options.store } : {}),
523
534
  // For providers that support `store`, ensure stateless `store:false` is sent
@@ -13,5 +13,6 @@ export const route = Route.make({
13
13
  protocol: OpenResponses.protocol,
14
14
  endpoint: Endpoint.path(OpenResponses.PATH),
15
15
  transport: OpenResponses.httpTransport,
16
+ defaults: { providerOptions: { store: false, include: ["reasoning.encrypted_content"] } },
16
17
  });
17
18
  export * as OpenAICompatibleResponses from "./openai-compatible-responses.js";
@@ -286,6 +286,15 @@ export declare const protocol: Protocol<{
286
286
  readonly response?: {
287
287
  readonly [x: string]: unknown;
288
288
  readonly id?: string | undefined;
289
+ readonly output?: readonly {
290
+ readonly [x: string]: unknown;
291
+ readonly type: string;
292
+ readonly id?: string | undefined;
293
+ readonly name?: string | undefined;
294
+ readonly arguments?: string | undefined;
295
+ readonly encrypted_content?: string | null | undefined;
296
+ readonly call_id?: string | undefined;
297
+ }[] | undefined;
289
298
  readonly error?: {
290
299
  readonly type?: string | null | undefined;
291
300
  readonly code?: string | null | undefined;
@@ -313,6 +322,7 @@ export declare const protocol: Protocol<{
313
322
  readonly param?: string | null | undefined;
314
323
  readonly status_code?: unknown;
315
324
  readonly item_id?: string | undefined;
325
+ readonly output_index?: number | undefined;
316
326
  readonly summary_index?: number | undefined;
317
327
  }, OpenResponses.ParserState>;
318
328
  export declare const httpTransport: HttpTransport.HttpJsonTransport<{
@@ -139,7 +139,7 @@ const HOSTED_TOOLS = {
139
139
  const step = (state, event) => {
140
140
  if (event.type === "response.reasoning_text.delta")
141
141
  return event.item_id
142
- ? Effect.succeed(OpenResponses.onReasoningDelta(state, event, event.item_id))
142
+ ? Effect.succeed(OpenResponses.onReasoningDelta(state, event, OpenResponses.outputItemID(state, event) ?? event.item_id))
143
143
  : ProviderShared.eventError(ADAPTER, `${event.type} is missing item_id`);
144
144
  if (event.type === "response.output_item.done" && event.item && ResponsesHostedTools.isItem(event.item, HOSTED_TOOLS))
145
145
  return ResponsesHostedTools.onDone(state, event.item, HOSTED_TOOLS);
@@ -176,6 +176,6 @@ export const route = Route.make({
176
176
  endpoint,
177
177
  auth,
178
178
  transport,
179
- defaults: { providerOptions: { store: false } },
179
+ defaults: { providerOptions: { store: false, include: ["reasoning.encrypted_content"] } },
180
180
  });
181
181
  export * as OpenAIResponses from "./openai-responses.js";
@@ -11,7 +11,7 @@ export declare const JsonObject: Schema.$Record<Schema.String, Schema.Unknown>;
11
11
  export declare const optionalArray: <const S extends Schema.Top>(schema: S) => Schema.optional<Schema.$Array<S>>;
12
12
  export declare const optionalNull: <const S extends Schema.Top>(schema: S) => Schema.optional<Schema.NullOr<S>>;
13
13
  export declare const OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;
14
- export declare const clampPromptCacheKey: (key: string | undefined) => string | undefined;
14
+ export declare const promptCacheKey: (request: LLMRequest) => string | undefined;
15
15
  /**
16
16
  * Streaming tool-call accumulator. Adapters that build a tool call across
17
17
  * multiple `tool-input-delta` chunks store the partial JSON input string here
@@ -16,12 +16,12 @@ export const optionalNull = (schema) => Schema.optional(Schema.NullOr(schema));
16
16
  export const OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;
17
17
  // OpenAI limits `prompt_cache_key` to 64 chars; DeepSeek and Zai inherit the same
18
18
  // limit via their OpenAI-compatible APIs. Clamp with unicode-aware slicing.
19
- export const clampPromptCacheKey = (key) => {
20
- if (key === undefined)
19
+ export const promptCacheKey = (request) => {
20
+ if (request.cache === "none" || request.promptCacheKey === undefined)
21
21
  return undefined;
22
- const chars = Array.from(key);
22
+ const chars = Array.from(request.promptCacheKey);
23
23
  if (chars.length <= OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH)
24
- return key;
24
+ return request.promptCacheKey;
25
25
  return chars.slice(0, OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH).join("");
26
26
  };
27
27
  /**
@@ -43,8 +43,58 @@ export function parseJSON(jsonString, allowPartial = Allow.ALL) {
43
43
  return decodeJson(input);
44
44
  }
45
45
  catch { }
46
- return _parseJSON(input, allowPartial);
46
+ const repaired = repairJSON(input);
47
+ if (repaired !== input) {
48
+ try {
49
+ return decodeJson(repaired);
50
+ }
51
+ catch { }
52
+ }
53
+ try {
54
+ return _parseJSON(input, allowPartial);
55
+ }
56
+ catch (error) {
57
+ if (repaired !== input)
58
+ return _parseJSON(repaired, allowPartial);
59
+ throw error;
60
+ }
47
61
  }
62
+ const repairJSON = (input) => {
63
+ let repaired = "";
64
+ let quoted = false;
65
+ for (let index = 0; index < input.length; index++) {
66
+ const character = input[index];
67
+ if (!quoted) {
68
+ repaired += character;
69
+ if (character === '"')
70
+ quoted = true;
71
+ continue;
72
+ }
73
+ if (character === '"') {
74
+ repaired += character;
75
+ quoted = false;
76
+ continue;
77
+ }
78
+ if (character === "\\") {
79
+ const next = input[index + 1];
80
+ if (next === "u" && /^[0-9a-fA-F]{4}$/.test(input.slice(index + 2, index + 6))) {
81
+ repaired += input.slice(index, index + 6);
82
+ index += 5;
83
+ continue;
84
+ }
85
+ if (next !== undefined && '"\\/bfnrtu'.includes(next)) {
86
+ repaired += `\\${next}`;
87
+ index++;
88
+ continue;
89
+ }
90
+ repaired += "\\\\";
91
+ continue;
92
+ }
93
+ const code = character.charCodeAt(0);
94
+ repaired += code <= 0x1f ? `\\u${code.toString(16).padStart(4, "0")}` : character;
95
+ }
96
+ return repaired;
97
+ };
48
98
  const _parseJSON = (jsonString, allow) => {
49
99
  const length = jsonString.length;
50
100
  let index = 0;
@@ -138,7 +188,12 @@ const _parseJSON = (jsonString, allow) => {
138
188
  skipBlank();
139
189
  index++;
140
190
  try {
141
- object[key] = parseAny();
191
+ Object.defineProperty(object, key, {
192
+ value: parseAny(),
193
+ enumerable: true,
194
+ configurable: true,
195
+ writable: true,
196
+ });
142
197
  }
143
198
  catch (error) {
144
199
  if (Allow.OBJ & allow)
@@ -61,7 +61,7 @@ export declare const appendOrStart: <K extends StreamKey>(route: string, tools:
61
61
  export declare const appendExisting: <K extends StreamKey>(route: string, tools: State<K>, key: K, text: string, missingToolMessage: string) => AppendOutcome<K> | AIError;
62
62
  /**
63
63
  * Finalize one pending tool call: parse the accumulated raw JSON, remove it
64
- * from state, and return either a call or a non-executable local input error.
64
+ * from state, and recover incomplete local arguments when needed.
65
65
  * Missing keys are a no-op because some providers emit stop events for
66
66
  * non-tool content blocks.
67
67
  */
@@ -19,34 +19,28 @@ const inputStart = (tool) => LLMEvent.toolInputStart({
19
19
  providerExecuted: tool.providerExecuted ? true : undefined,
20
20
  providerMetadata: tool.providerMetadata,
21
21
  });
22
- const inputDelta = (tool, text) => {
23
- const input = parsePartialInput(tool.input);
24
- return LLMEvent.toolInputDelta({
25
- id: tool.id,
26
- name: tool.name,
27
- text,
28
- ...(Option.isSome(input) ? { input: input.value } : {}),
29
- });
30
- };
22
+ const inputDelta = (tool, text) => LLMEvent.toolInputDelta({
23
+ id: tool.id,
24
+ name: tool.name,
25
+ text,
26
+ input: Option.getOrElse(parsePartialInput(tool.input), () => ({})),
27
+ });
31
28
  const toolCall = (route, tool, inputOverride) => {
32
29
  const raw = inputOverride ?? tool.input;
33
- return parseToolInput(route, tool.name, raw).pipe(Effect.map((input) => LLMEvent.toolCall({
30
+ return parseToolInput(route, tool.name, raw).pipe(Effect.catch((error) => tool.providerExecuted
31
+ ? Effect.fail(error)
32
+ : Effect.succeed(Option.getOrElse(Option.map(parsePartialInput(raw), (input) => input ?? {}), () => ({})))), Effect.map((input) => LLMEvent.toolCall({
34
33
  id: tool.id,
35
34
  name: tool.name,
36
35
  input,
37
36
  providerExecuted: tool.providerExecuted ? true : undefined,
38
37
  providerMetadata: tool.providerMetadata,
39
- })), Effect.catch((error) => tool.providerExecuted
40
- ? Effect.fail(error)
41
- : Effect.succeed(LLMEvent.toolInputError({
42
- id: tool.id,
43
- name: tool.name,
44
- raw,
45
- }))));
38
+ })));
46
39
  };
47
- const finishEvents = (tool, event) => event.type === "tool-input-error"
48
- ? [event]
49
- : [LLMEvent.toolInputEnd({ id: tool.id, name: tool.name, providerMetadata: tool.providerMetadata }), event];
40
+ const finishEvents = (tool, event) => [
41
+ LLMEvent.toolInputEnd({ id: tool.id, name: tool.name, providerMetadata: tool.providerMetadata }),
42
+ event,
43
+ ];
50
44
  /** Store the updated tool and produce the optional public delta event. */
51
45
  const appendTool = (tools, key, tool, text) => {
52
46
  const events = [];
@@ -105,7 +99,7 @@ export const appendExisting = (route, tools, key, text, missingToolMessage) => {
105
99
  };
106
100
  /**
107
101
  * Finalize one pending tool call: parse the accumulated raw JSON, remove it
108
- * from state, and return either a call or a non-executable local input error.
102
+ * from state, and recover incomplete local arguments when needed.
109
103
  * Missing keys are a no-op because some providers emit stop events for
110
104
  * non-tool content blocks.
111
105
  */
@@ -143,6 +143,15 @@ export declare const protocol: Protocol<{
143
143
  readonly response?: {
144
144
  readonly [x: string]: unknown;
145
145
  readonly id?: string | undefined;
146
+ readonly output?: readonly {
147
+ readonly [x: string]: unknown;
148
+ readonly type: string;
149
+ readonly id?: string | undefined;
150
+ readonly name?: string | undefined;
151
+ readonly arguments?: string | undefined;
152
+ readonly encrypted_content?: string | null | undefined;
153
+ readonly call_id?: string | undefined;
154
+ }[] | undefined;
146
155
  readonly error?: {
147
156
  readonly type?: string | null | undefined;
148
157
  readonly code?: string | null | undefined;
@@ -170,6 +179,7 @@ export declare const protocol: Protocol<{
170
179
  readonly param?: string | null | undefined;
171
180
  readonly status_code?: unknown;
172
181
  readonly item_id?: string | undefined;
182
+ readonly output_index?: number | undefined;
173
183
  readonly summary_index?: number | undefined;
174
184
  }, OpenResponses.ParserState>;
175
185
  export * as XAIResponses from "./xai-responses.js";
@@ -8,7 +8,7 @@ import { ProviderID } from "../schema/index.js";
8
8
  import * as OpenAICompatibleProfiles from "./openai-compatible-profile.js";
9
9
  import * as OpenAIChat from "../protocols/openai-chat.js";
10
10
  import { newBreakpoints, ttlBucket } from "../protocols/utils/cache.js";
11
- import { isRecord, ProviderShared } from "../protocols/shared.js";
11
+ import { isRecord } from "../protocols/shared.js";
12
12
  export const profile = OpenAICompatibleProfiles.profiles.openrouter;
13
13
  export const id = ProviderID.make(profile.provider);
14
14
  const ADAPTER = "openrouter";
@@ -39,12 +39,10 @@ export const protocol = Protocol.make({
39
39
  reasoning_details: reasoningDetails,
40
40
  };
41
41
  });
42
- const cacheKey = ProviderShared.clampPromptCacheKey(request.promptCacheKey);
43
42
  return {
44
43
  ...body,
45
44
  messages,
46
45
  ...bodyOptions(request.providerOptions),
47
- ...(cacheKey ? { prompt_cache_key: cacheKey } : {}),
48
46
  };
49
47
  })),
50
48
  },
@@ -21,7 +21,7 @@ const responsesRoute = Route.make({
21
21
  name: "xAI Responses",
22
22
  rotateAfterMs: RESPONSES_WEBSOCKET_ROTATE_AFTER_MS,
23
23
  }),
24
- defaults: { providerOptions: { store: false } },
24
+ defaults: { providerOptions: { store: false, include: ["reasoning.encrypted_content"] } },
25
25
  });
26
26
  const chatRoute = Route.make({
27
27
  id: "openai-compatible-chat",
@@ -5,6 +5,7 @@ import { RequestExecutor } from "./executor.js";
5
5
  import { Framing } from "./framing.js";
6
6
  import { HttpTransport } from "./transport/index.js";
7
7
  import { applyCachePolicy } from "../cache-policy.js";
8
+ import { sanitizeSurrogates } from "../utils/sanitize.js";
8
9
  import * as ProviderShared from "../protocols/shared.js";
9
10
  import { AIError, GenerationOptions, HttpOptions, LLMRequest, LLMResponse, LanguageModel, LLMEvent, InvalidProviderOutputReason, ProviderID, mergeGenerationOptions, mergeHttpOptions, mergeProviderOptions, } from "../schema/index.js";
10
11
  const makeRouteLanguageModel = (route, mapped) => {
@@ -159,7 +160,8 @@ export function make(input) {
159
160
  });
160
161
  }
161
162
  const compile = Effect.fn("LLM.compile")(function* (request, options) {
162
- const resolved = applyCachePolicy(resolveRequestOptions(request));
163
+ const original = applyCachePolicy(resolveRequestOptions(request));
164
+ const resolved = LLMRequest.update(original, sanitizeSurrogates({ ...LLMRequest.input(original), model: undefined }));
163
165
  const route = resolved.model.route;
164
166
  const body = yield* route.body
165
167
  .from(resolved)
@@ -74,6 +74,7 @@ declare const LanguageModelCompatibility_base: Schema.Class<LanguageModelCompati
74
74
  readonly reasoningField: Schema.optional<Schema.String>;
75
75
  readonly maxTokensField: Schema.optional<Schema.Literals<readonly ["max_completion_tokens", "max_tokens"]>>;
76
76
  readonly requireFinishReason: Schema.optional<Schema.Boolean>;
77
+ readonly requireAssistantAfterTool: Schema.optional<Schema.Boolean>;
77
78
  readonly supportsStore: Schema.optional<Schema.Boolean>;
78
79
  readonly supportsUsageInStreaming: Schema.optional<Schema.Boolean>;
79
80
  readonly supportsStrictMode: Schema.optional<Schema.Boolean>;
@@ -101,6 +101,7 @@ export class LanguageModelCompatibility extends Schema.Class("LLM.LanguageModelC
101
101
  reasoningField: Schema.optional(Schema.String),
102
102
  maxTokensField: Schema.optional(LanguageModelMaxTokensFieldCompatibility),
103
103
  requireFinishReason: Schema.optional(Schema.Boolean),
104
+ requireAssistantAfterTool: Schema.optional(Schema.Boolean),
104
105
  supportsStore: Schema.optional(Schema.Boolean),
105
106
  supportsUsageInStreaming: Schema.optional(Schema.Boolean),
106
107
  supportsStrictMode: Schema.optional(Schema.Boolean),
@@ -0,0 +1 @@
1
+ export declare const sanitizeSurrogates: <T>(value: T) => T;
@@ -0,0 +1,12 @@
1
+ import { isRecord } from "./record.js";
2
+ export const sanitizeSurrogates = (value) => {
3
+ if (typeof value === "string")
4
+ return value.toWellFormed();
5
+ if (Array.isArray(value))
6
+ return value.map(sanitizeSurrogates);
7
+ if (value instanceof Uint8Array || value instanceof Error)
8
+ return value;
9
+ if (isRecord(value))
10
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key.toWellFormed(), sanitizeSurrogates(entry)]));
11
+ return value;
12
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "0.0.0-beta-18155",
3
+ "version": "0.0.0-beta-18219",
4
4
  "name": "@opencode-ai/ai",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  "devDependencies": {
31
31
  "@clack/prompts": "1.0.0-alpha.1",
32
32
  "@effect/platform-node": "4.0.0-rc.111",
33
- "@opencode-ai/http-recorder": "0.0.0-beta-18155",
33
+ "@opencode-ai/http-recorder": "0.0.0-beta-18219",
34
34
  "@tsconfig/bun": "1.0.9",
35
35
  "@types/bun": "1.3.13",
36
36
  "@typescript/native-preview": "7.0.0-dev.20251207.1",
@@ -39,7 +39,7 @@
39
39
  "dependencies": {
40
40
  "@smithy/eventstream-codec": "4.2.14",
41
41
  "@smithy/util-utf8": "4.2.2",
42
- "@opencode-ai/schema": "0.0.0-beta-18155",
42
+ "@opencode-ai/schema": "0.0.0-beta-18219",
43
43
  "aws4fetch": "1.0.20",
44
44
  "effect": "4.0.0-rc.111",
45
45
  "google-auth-library": "10.5.0"