@opencode/ai 2.0.21 → 2.0.23

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.
Files changed (113) hide show
  1. package/README.md +61 -1
  2. package/dist/cache-policy.js +10 -2
  3. package/dist/llm.d.ts +4 -0
  4. package/dist/promise.d.ts +8 -0
  5. package/dist/protocols/alibaba-chat.d.ts +7 -3
  6. package/dist/protocols/alibaba-chat.js +2 -1
  7. package/dist/protocols/alibaba-responses.d.ts +16 -12
  8. package/dist/protocols/alibaba-responses.js +3 -5
  9. package/dist/protocols/anthropic-messages.js +58 -51
  10. package/dist/protocols/bedrock-converse.js +33 -4
  11. package/dist/protocols/cartesia-speech.js +3 -3
  12. package/dist/protocols/cohere-chat.d.ts +178 -0
  13. package/dist/protocols/cohere-chat.js +299 -0
  14. package/dist/protocols/elevenlabs-speech.js +3 -3
  15. package/dist/protocols/gemini.d.ts +2 -2
  16. package/dist/protocols/gemini.js +3 -3
  17. package/dist/protocols/google-interactions.d.ts +236 -0
  18. package/dist/protocols/google-interactions.js +478 -0
  19. package/dist/protocols/google-speech.js +1 -1
  20. package/dist/protocols/google-transcription.js +1 -1
  21. package/dist/protocols/index.d.ts +2 -0
  22. package/dist/protocols/index.js +2 -0
  23. package/dist/protocols/meta-responses.d.ts +31 -58
  24. package/dist/protocols/meta-responses.js +8 -27
  25. package/dist/protocols/mistral-chat.d.ts +24 -9
  26. package/dist/protocols/mistral-chat.js +22 -10
  27. package/dist/protocols/open-responses.d.ts +410 -91
  28. package/dist/protocols/open-responses.js +25 -15
  29. package/dist/protocols/openai-chat.d.ts +409 -5
  30. package/dist/protocols/openai-chat.js +27 -26
  31. package/dist/protocols/openai-compatible-chat.d.ts +1 -1
  32. package/dist/protocols/openai-compatible-responses.d.ts +16 -4
  33. package/dist/protocols/openai-images.js +2 -2
  34. package/dist/protocols/openai-responses.d.ts +87 -223
  35. package/dist/protocols/openai-responses.js +10 -16
  36. package/dist/protocols/openai-speech.js +1 -1
  37. package/dist/protocols/openai-transcription.js +1 -1
  38. package/dist/protocols/shared.js +2 -2
  39. package/dist/protocols/stability-images.js +1 -1
  40. package/dist/protocols/utils/bedrock-media.js +2 -2
  41. package/dist/protocols/utils/cache.d.ts +5 -0
  42. package/dist/protocols/utils/cache.js +9 -1
  43. package/dist/protocols/utils/responses-checkpoint.js +2 -2
  44. package/dist/protocols/utils/responses-hosted-tools.js +1 -1
  45. package/dist/protocols/utils/tool-stream.d.ts +12 -0
  46. package/dist/protocols/utils/tool-stream.js +15 -7
  47. package/dist/protocols/venice-chat.d.ts +280 -0
  48. package/dist/protocols/venice-chat.js +283 -0
  49. package/dist/protocols/xai-responses.d.ts +18 -21
  50. package/dist/protocols/xai-responses.js +2 -8
  51. package/dist/protocols/zai-chat.d.ts +7 -3
  52. package/dist/protocols/zai-chat.js +6 -3
  53. package/dist/provider-error.js +27 -7
  54. package/dist/providers/alibaba.d.ts +17 -13
  55. package/dist/providers/amazon-bedrock/mantle/messages.d.ts +2 -0
  56. package/dist/providers/amazon-bedrock/mantle/messages.js +1 -0
  57. package/dist/providers/amazon-bedrock-mantle.d.ts +301 -9
  58. package/dist/providers/amazon-bedrock-mantle.js +28 -3
  59. package/dist/providers/azure.d.ts +13 -61
  60. package/dist/providers/baseten.d.ts +2 -2
  61. package/dist/providers/cerebras.d.ts +2 -2
  62. package/dist/providers/cloudflare-ai-gateway.d.ts +14 -62
  63. package/dist/providers/cloudflare-workers-ai.d.ts +2 -2
  64. package/dist/providers/cohere/chat.d.ts +4 -0
  65. package/dist/providers/cohere/chat.js +8 -0
  66. package/dist/providers/cohere.d.ts +395 -0
  67. package/dist/providers/cohere.js +48 -0
  68. package/dist/providers/deepinfra.d.ts +2 -2
  69. package/dist/providers/deepseek.d.ts +2 -2
  70. package/dist/providers/digitalocean.d.ts +469 -0
  71. package/dist/providers/digitalocean.js +53 -0
  72. package/dist/providers/fireworks.d.ts +2 -2
  73. package/dist/providers/google/interactions.d.ts +7 -0
  74. package/dist/providers/google/interactions.js +8 -0
  75. package/dist/providers/google-vertex-chat.d.ts +1 -1
  76. package/dist/providers/google-vertex-messages.js +1 -1
  77. package/dist/providers/google-vertex-responses.d.ts +16 -4
  78. package/dist/providers/google-vertex.d.ts +1 -1
  79. package/dist/providers/google.d.ts +95 -4
  80. package/dist/providers/google.js +8 -1
  81. package/dist/providers/groq.d.ts +8 -4
  82. package/dist/providers/groq.js +1 -1
  83. package/dist/providers/index.d.ts +3 -0
  84. package/dist/providers/index.js +3 -0
  85. package/dist/providers/meta.d.ts +15 -28
  86. package/dist/providers/minimax.d.ts +17 -5
  87. package/dist/providers/mistral.d.ts +10 -4
  88. package/dist/providers/moonshot.d.ts +17 -5
  89. package/dist/providers/openai-compatible-responses.d.ts +16 -4
  90. package/dist/providers/openai-compatible.d.ts +1 -1
  91. package/dist/providers/openai-options.d.ts +1 -1
  92. package/dist/providers/openai.d.ts +7 -31
  93. package/dist/providers/openrouter.d.ts +9 -5
  94. package/dist/providers/openrouter.js +1 -13
  95. package/dist/providers/togetherai.d.ts +2 -2
  96. package/dist/providers/venice.d.ts +183 -0
  97. package/dist/providers/venice.js +38 -0
  98. package/dist/providers/xai.d.ts +1 -1
  99. package/dist/providers/zai-coding-plan.d.ts +17 -5
  100. package/dist/providers/zai.d.ts +1 -1
  101. package/dist/route/client.d.ts +4 -0
  102. package/dist/route/client.js +2 -5
  103. package/dist/route/executor.js +13 -6
  104. package/dist/route/framing.js +23 -23
  105. package/dist/route/transport/http.d.ts +2 -1
  106. package/dist/route/transport/http.js +28 -6
  107. package/dist/schema/events.d.ts +176 -0
  108. package/dist/schema/events.js +4 -0
  109. package/dist/schema/options.d.ts +11 -0
  110. package/dist/schema/options.js +15 -2
  111. package/dist/testing.d.ts +32 -0
  112. package/dist/tool-history.js +17 -3
  113. package/package.json +3 -3
@@ -26,11 +26,6 @@ const OpenAIChatCacheControl = Schema.Struct({
26
26
  type: Schema.Literal("ephemeral"),
27
27
  ttl: Schema.optional(Schema.String),
28
28
  });
29
- const OpenAIChatFunction = Schema.Struct({
30
- name: Schema.String,
31
- description: Schema.String,
32
- parameters: JsonObject,
33
- });
34
29
  const OpenAIChatTool = Schema.Struct({
35
30
  type: Schema.tag("function"),
36
31
  function: Schema.Struct({
@@ -48,7 +43,7 @@ const ExtraContent = Schema.Struct({
48
43
  google: Schema.Struct({ thought_signature: Schema.String }),
49
44
  });
50
45
  const decodeExtraContent = (value) => Option.getOrUndefined(Schema.decodeUnknownOption(ExtraContent)(value));
51
- const OpenAIChatAssistantToolCall = Schema.Struct({
46
+ export const OpenAIChatAssistantToolCall = Schema.Struct({
52
47
  id: Schema.String,
53
48
  type: Schema.tag("function"),
54
49
  function: Schema.Struct({
@@ -99,7 +94,7 @@ const OpenAIChatUserContent = Schema.Union([
99
94
  file: Schema.Struct({ filename: Schema.String, file_data: Schema.String }),
100
95
  }),
101
96
  ]);
102
- const OpenAIChatMessage = Schema.Union([
97
+ export const OpenAIChatMessage = Schema.Union([
103
98
  Schema.Struct({
104
99
  role: Schema.Literal("system"),
105
100
  content: Schema.Union([Schema.String, Schema.Array(OpenAIChatUserContent)]),
@@ -157,13 +152,15 @@ const OpenAIChatBody = Schema.Struct(bodyFields);
157
152
  // The event schema is one decoded SSE `data:` payload. `Framing.sse` splits the
158
153
  // byte stream into strings, then `Protocol.jsonEvent` decodes each string into
159
154
  // this provider-native event shape.
160
- const OpenAIChatUsage = Schema.StructWithRest(Schema.Struct({
155
+ export const OpenAIChatUsage = Schema.StructWithRest(Schema.Struct({
161
156
  prompt_tokens: optionalNull(Schema.Number),
162
157
  completion_tokens: optionalNull(Schema.Number),
163
158
  total_tokens: optionalNull(Schema.Number),
164
- // Zai reports cache hits as top-level `cached_tokens`; DeepSeek uses `prompt_cache_hit_tokens`.
159
+ // Provider-specific cache accounting fields.
165
160
  cached_tokens: optionalNull(Schema.Number),
166
161
  prompt_cache_hit_tokens: optionalNull(Schema.Number),
162
+ cache_read_input_tokens: optionalNull(Schema.Number),
163
+ cache_created_input_tokens: optionalNull(Schema.Number),
167
164
  prompt_tokens_details: optionalNull(Schema.StructWithRest(Schema.Struct({
168
165
  cached_tokens: optionalNull(Schema.Number),
169
166
  cache_write_tokens: optionalNull(Schema.Number),
@@ -178,13 +175,13 @@ const OpenAIChatToolCallDeltaFunction = Schema.Struct({
178
175
  name: optionalNull(Schema.String),
179
176
  arguments: optionalNull(Schema.String),
180
177
  });
181
- const OpenAIChatToolCallDelta = Schema.Struct({
178
+ export const OpenAIChatToolCallDelta = Schema.Struct({
182
179
  index: optionalNull(Schema.Number),
183
180
  id: optionalNull(Schema.String),
184
181
  function: optionalNull(OpenAIChatToolCallDeltaFunction),
185
182
  extra_content: optionalNull(Schema.Unknown),
186
183
  });
187
- const OpenAIChatDelta = Schema.StructWithRest(Schema.Struct({
184
+ export const OpenAIChatDelta = Schema.StructWithRest(Schema.Struct({
188
185
  content: optionalNull(Schema.String),
189
186
  refusal: optionalNull(Schema.String),
190
187
  reasoning_content: optionalNull(Schema.String),
@@ -193,7 +190,7 @@ const OpenAIChatDelta = Schema.StructWithRest(Schema.Struct({
193
190
  reasoning_details: optionalNull(Schema.Unknown),
194
191
  tool_calls: optionalNull(Schema.Array(OpenAIChatToolCallDelta)),
195
192
  }), [Schema.Record(Schema.String, Schema.Unknown)]);
196
- const OpenAIChatChoice = Schema.StructWithRest(Schema.Struct({
193
+ export const OpenAIChatChoice = Schema.StructWithRest(Schema.Struct({
197
194
  delta: optionalNull(OpenAIChatDelta),
198
195
  finish_reason: optionalNull(Schema.String),
199
196
  native_finish_reason: optionalNull(Schema.String),
@@ -236,7 +233,7 @@ const lowerToolCall = (part, options) => ({
236
233
  },
237
234
  extra_content: decodeExtraContent(part.providerMetadata?.[options.providerMetadataKey]?.extraContent),
238
235
  });
239
- const lowerMedia = Effect.fn("OpenAIChat.lowerMedia")(function* (part) {
236
+ const lowerMedia = Effect.fnUntraced(function* (part) {
240
237
  // Chat Completions accepts PDFs, and no other documents, as inline `file` parts; file URLs are not supported.
241
238
  if (part.media.mediaType.toLowerCase() === "application/pdf")
242
239
  return {
@@ -276,7 +273,7 @@ const lowerReasoningDetail = (detail) => {
276
273
  return detail;
277
274
  };
278
275
  const isKimiDetail = (detail) => detail.type === "summary" || detail.type === "encrypted";
279
- const lowerUserMessage = Effect.fn("OpenAIChat.lowerUserMessage")(function* (message, options) {
276
+ const lowerUserMessage = Effect.fnUntraced(function* (message, options) {
280
277
  const content = [];
281
278
  for (const part of message.content) {
282
279
  if (part.type === "text") {
@@ -296,7 +293,7 @@ const lowerUserMessage = Effect.fn("OpenAIChat.lowerUserMessage")(function* (mes
296
293
  };
297
294
  return { role: "user", content };
298
295
  });
299
- const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(function* (message, configuredField, requireReasoning, options) {
296
+ const lowerAssistantMessage = Effect.fnUntraced(function* (message, configuredField, requireReasoning, options) {
300
297
  const content = [];
301
298
  const reasoning = [];
302
299
  const toolCalls = [];
@@ -362,7 +359,7 @@ const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(func
362
359
  return result;
363
360
  return { ...result, [field]: reasoningText };
364
361
  });
365
- const lowerToolMessages = Effect.fn("OpenAIChat.lowerToolMessages")(function* (message, options) {
362
+ const lowerToolMessages = Effect.fnUntraced(function* (message, options) {
366
363
  const messages = [];
367
364
  const attachments = [];
368
365
  for (const part of message.content) {
@@ -386,14 +383,16 @@ const toolMessage = (toolCallID, text, cacheControl) => ({
386
383
  tool_call_id: toolCallID,
387
384
  content: cacheControl === undefined ? text : [{ type: "text", text, cache_control: cacheControl }],
388
385
  });
389
- const lowerMessage = Effect.fn("OpenAIChat.lowerMessage")(function* (message, reasoningField, requireReasoning, options) {
386
+ const lowerMessage = Effect.fnUntraced(function* (message, reasoningField, requireReasoning, options) {
390
387
  if (message.role === "user")
391
388
  return [yield* lowerUserMessage(message, options)];
392
- if (message.role === "assistant")
393
- return [yield* lowerAssistantMessage(message, reasoningField, requireReasoning, options)];
389
+ if (message.role === "assistant") {
390
+ const lowered = yield* lowerAssistantMessage(message, reasoningField, requireReasoning, options);
391
+ return [options.assistant?.(message, lowered) ?? lowered];
392
+ }
394
393
  return (yield* lowerToolMessages(message, options)).messages;
395
394
  });
396
- const lowerMessages = Effect.fn("OpenAIChat.lowerMessages")(function* (request, options) {
395
+ const lowerMessages = Effect.fnUntraced(function* (request, options) {
397
396
  const system = request.system.length === 0
398
397
  ? []
399
398
  : request.system.some((part) => part.cache !== undefined) && options.cacheControl !== undefined
@@ -677,7 +676,7 @@ export const fromRequest = Effect.fn("OpenAIChat.fromRequest")(function* (reques
677
676
  // Streaming parsers are small state machines: every event returns a new state
678
677
  // plus the common `LLMEvent`s produced by that event. Tool calls are accumulated
679
678
  // because OpenAI streams JSON arguments across multiple deltas.
680
- const mapFinishReason = Effect.fn("OpenAIChat.mapFinishReason")(function* (event, reason) {
679
+ const mapFinishReason = Effect.fnUntraced(function* (event, reason) {
681
680
  switch (reason) {
682
681
  case "error":
683
682
  return yield* new AIError({
@@ -719,17 +718,19 @@ const mapFinishReason = Effect.fn("OpenAIChat.mapFinishReason")(function* (event
719
718
  // satisfied on both sides.
720
719
  // Providers differ on cache-hit location: OpenAI uses
721
720
  // `prompt_tokens_details.cached_tokens`, DeepSeek uses
722
- // `prompt_cache_hit_tokens`, and Zai uses top-level `cached_tokens`.
721
+ // `prompt_cache_hit_tokens`, Zai uses top-level `cached_tokens`, and
722
+ // DigitalOcean uses top-level `cache_read_input_tokens` / `cache_created_input_tokens`.
723
723
  const mapUsage = (usage, providerMetadataKey) => {
724
724
  if (!usage)
725
725
  return undefined;
726
726
  const input = usage.prompt_tokens ?? undefined;
727
727
  const output = usage.completion_tokens ?? undefined;
728
- const cached = (usage.prompt_tokens_details?.cached_tokens ??
728
+ const cached = usage.prompt_tokens_details?.cached_tokens ??
729
729
  usage.prompt_cache_hit_tokens ??
730
730
  usage.cached_tokens ??
731
- undefined);
732
- const cacheWrite = usage.prompt_tokens_details?.cache_write_tokens ?? undefined;
731
+ usage.cache_read_input_tokens ??
732
+ undefined;
733
+ const cacheWrite = usage.prompt_tokens_details?.cache_write_tokens ?? usage.cache_created_input_tokens ?? undefined;
733
734
  const reasoning = usage.completion_tokens_details?.reasoning_tokens ?? undefined;
734
735
  const nonCached = ProviderShared.subtractTokens(input, ProviderShared.sumTokens(cached, cacheWrite));
735
736
  return new Usage({
@@ -982,7 +983,7 @@ const step = (state, event) => Effect.gen(function* () {
982
983
  events,
983
984
  ];
984
985
  });
985
- const finishEvents = Effect.fn("OpenAIChat.finishEvents")(function* (state) {
986
+ export const finishEvents = Effect.fnUntraced(function* (state) {
986
987
  if (state.finishReason === undefined && state.requireFinishReason)
987
988
  return yield* new AIError({
988
989
  reason: new InvalidProviderOutputError({
@@ -121,9 +121,9 @@ export declare const route: Route<{
121
121
  readonly top_p?: number | undefined;
122
122
  readonly frequency_penalty?: number | undefined;
123
123
  readonly presence_penalty?: number | undefined;
124
+ readonly store?: boolean | undefined;
124
125
  readonly prompt_cache_key?: string | undefined;
125
126
  readonly reasoning_effort?: import("../index.js").ReasoningEffort | undefined;
126
- readonly store?: boolean | undefined;
127
127
  readonly stream_options?: {
128
128
  readonly include_usage: boolean;
129
129
  } | undefined;
@@ -43,6 +43,15 @@ export declare const route: Route<{
43
43
  readonly error?: unknown;
44
44
  readonly arguments?: string | undefined;
45
45
  readonly server_label?: string | undefined;
46
+ } | {
47
+ readonly type: "configuration_update";
48
+ readonly reasoning: {
49
+ readonly effort: import("../index.js").ReasoningEffort;
50
+ };
51
+ } | {
52
+ readonly [x: string]: unknown;
53
+ readonly type: string;
54
+ readonly id: string;
46
55
  } | {
47
56
  readonly type: "reasoning";
48
57
  readonly summary: readonly {
@@ -130,7 +139,10 @@ export declare const route: Route<{
130
139
  readonly summary?: "auto" | "concise" | "detailed" | undefined;
131
140
  readonly effort?: import("../index.js").ReasoningEffort | undefined;
132
141
  } | undefined;
133
- readonly tools?: readonly {
142
+ readonly tools?: readonly ({
143
+ readonly [x: string]: unknown;
144
+ readonly type: string;
145
+ } | {
134
146
  readonly type: "function";
135
147
  readonly description: string;
136
148
  readonly name: string;
@@ -138,7 +150,7 @@ export declare const route: Route<{
138
150
  readonly [x: string]: unknown;
139
151
  };
140
152
  readonly strict?: boolean | undefined;
141
- }[] | undefined;
153
+ })[] | undefined;
142
154
  readonly text?: {
143
155
  readonly verbosity?: import("./utils/open-responses-options.js").TextVerbosity | undefined;
144
156
  } | undefined;
@@ -158,9 +170,10 @@ export declare const route: Route<{
158
170
  readonly top_p?: number | undefined;
159
171
  readonly frequency_penalty?: number | undefined;
160
172
  readonly presence_penalty?: number | undefined;
173
+ readonly store?: boolean | undefined;
174
+ readonly max_output_tokens?: number | undefined;
161
175
  readonly prompt_cache_key?: string | undefined;
162
176
  readonly parallel_tool_calls?: boolean | undefined;
163
- readonly store?: boolean | undefined;
164
177
  readonly include?: readonly import("./utils/open-responses-options.js").ResponseIncludable[] | undefined;
165
178
  readonly truncation?: "auto" | "disabled" | undefined;
166
179
  readonly stream_options?: {
@@ -168,7 +181,6 @@ export declare const route: Route<{
168
181
  } | undefined;
169
182
  readonly safety_identifier?: string | undefined;
170
183
  readonly top_logprobs?: number | undefined;
171
- readonly max_output_tokens?: number | undefined;
172
184
  readonly max_tool_calls?: number | undefined;
173
185
  }, import("../route/transport/http.js").HttpPrepared<string>, import("../route/client.js").CompactionOperations | undefined>;
174
186
  export * as OpenAICompatibleResponses from "./openai-compatible-responses.js";
@@ -126,7 +126,7 @@ const info = (format, size) => {
126
126
  const eventImage = (frame, label, data, format, size) => MediaInput.decodedAsset((message, cause) => route.frameError(message, frame, cause), label, data, `image/${format}`, {
127
127
  info: info(format, size),
128
128
  });
129
- const onEvent = Effect.fn("OpenAIImages.onEvent")(function* (state, frame) {
129
+ const onEvent = Effect.fnUntraced(function* (state, frame) {
130
130
  const event = yield* decodeEvent(frame);
131
131
  const format = event.output_format;
132
132
  if ("partial_image_index" in event) {
@@ -146,7 +146,7 @@ const onEvent = Effect.fn("OpenAIImages.onEvent")(function* (state, frame) {
146
146
  [ImageOutputEvent.make({ index: state.completed, image })],
147
147
  ];
148
148
  });
149
- const onDocument = Effect.fn("OpenAIImages.onDocument")(function* (frame) {
149
+ const onDocument = Effect.fnUntraced(function* (frame) {
150
150
  const invalid = (message, cause) => route.frameError(message, frame.document, cause);
151
151
  const decoded = yield* decodeDocument(frame.document).pipe(Effect.mapError((cause) => invalid(`${route.name} returned an invalid response`, cause)));
152
152
  const format = decoded.output_format ?? frame.requested ?? "png";