@opencode/ai 2.0.26 → 2.0.28

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 (108) hide show
  1. package/README.md +8 -2
  2. package/dist/cache-policy.js +20 -11
  3. package/dist/experimental/system-one.js +1 -1
  4. package/dist/media.d.ts +1 -1
  5. package/dist/media.js +7 -6
  6. package/dist/protocols/alibaba-chat.d.ts +2 -2
  7. package/dist/protocols/alibaba-messages.d.ts +1 -1
  8. package/dist/protocols/anthropic-messages.js +1 -1
  9. package/dist/protocols/bedrock-converse.js +4 -3
  10. package/dist/protocols/bedrock-event-stream.js +4 -3
  11. package/dist/protocols/gemini.d.ts +73 -9
  12. package/dist/protocols/gemini.js +111 -17
  13. package/dist/protocols/meta-responses.js +3 -2
  14. package/dist/protocols/mistral-chat.d.ts +1 -1
  15. package/dist/protocols/mistral-chat.js +4 -2
  16. package/dist/protocols/open-responses-channel.d.ts +1 -1
  17. package/dist/protocols/open-responses-channel.js +7 -2
  18. package/dist/protocols/openai-chat.js +6 -2
  19. package/dist/protocols/openai-responses.d.ts +5 -5
  20. package/dist/protocols/openai-responses.js +4 -3
  21. package/dist/protocols/shared.d.ts +6 -2
  22. package/dist/protocols/shared.js +29 -3
  23. package/dist/protocols/utils/bedrock-auth.js +1 -1
  24. package/dist/protocols/utils/bedrock-media.js +4 -3
  25. package/dist/protocols/utils/fal-queue.d.ts +1 -1
  26. package/dist/protocols/utils/media-input.js +4 -3
  27. package/dist/protocols/utils/responses-compaction.js +6 -1
  28. package/dist/protocols/utils/tool-schema.js +8 -2
  29. package/dist/providers/alibaba.d.ts +5 -5
  30. package/dist/providers/amazon-bedrock-mantle.js +2 -2
  31. package/dist/providers/anthropic-compatible.js +2 -2
  32. package/dist/providers/anthropic.js +2 -2
  33. package/dist/providers/azure.d.ts +2 -2
  34. package/dist/providers/azure.js +3 -3
  35. package/dist/providers/baseten.js +2 -2
  36. package/dist/providers/cerebras.js +2 -2
  37. package/dist/providers/cloudflare-ai-gateway.d.ts +2 -2
  38. package/dist/providers/cloudflare-ai-gateway.js +2 -2
  39. package/dist/providers/cloudflare-workers-ai.js +2 -2
  40. package/dist/providers/cohere/chat.js +1 -1
  41. package/dist/providers/cohere.js +1 -1
  42. package/dist/providers/deepinfra.js +2 -2
  43. package/dist/providers/deepseek.js +2 -2
  44. package/dist/providers/fireworks.js +2 -2
  45. package/dist/providers/google/interactions.js +2 -2
  46. package/dist/providers/google-vertex/interactions.d.ts +2 -0
  47. package/dist/providers/google-vertex/interactions.js +1 -0
  48. package/dist/providers/google-vertex/mistral.d.ts +2 -0
  49. package/dist/providers/google-vertex/mistral.js +1 -0
  50. package/dist/providers/google-vertex-chat.js +3 -3
  51. package/dist/providers/google-vertex-interactions.d.ts +112 -0
  52. package/dist/providers/google-vertex-interactions.js +64 -0
  53. package/dist/providers/google-vertex-messages.js +3 -3
  54. package/dist/providers/google-vertex-mistral.d.ts +124 -0
  55. package/dist/providers/google-vertex-mistral.js +69 -0
  56. package/dist/providers/google-vertex-responses.js +3 -3
  57. package/dist/providers/google-vertex-shared.d.ts +3 -1
  58. package/dist/providers/google-vertex-shared.js +29 -3
  59. package/dist/providers/google-vertex.d.ts +2 -1
  60. package/dist/providers/google-vertex.js +4 -5
  61. package/dist/providers/google.d.ts +2 -1
  62. package/dist/providers/google.js +2 -2
  63. package/dist/providers/groq.js +2 -2
  64. package/dist/providers/index.d.ts +3 -1
  65. package/dist/providers/index.js +3 -1
  66. package/dist/providers/meta.js +1 -1
  67. package/dist/providers/minimax/chat.js +1 -1
  68. package/dist/providers/minimax/responses.js +1 -1
  69. package/dist/providers/minimax.js +1 -1
  70. package/dist/providers/mistral.js +2 -2
  71. package/dist/providers/moonshot/messages.js +1 -1
  72. package/dist/providers/moonshot/responses.js +1 -1
  73. package/dist/providers/moonshot.js +1 -1
  74. package/dist/providers/openai-compatible-responses.js +2 -2
  75. package/dist/providers/openai-compatible.js +2 -2
  76. package/dist/providers/openai.d.ts +1 -1
  77. package/dist/providers/openai.js +2 -2
  78. package/dist/providers/{opencode-zen.d.ts → opencode.d.ts} +1 -1
  79. package/dist/providers/{opencode-zen.js → opencode.js} +2 -2
  80. package/dist/providers/openrouter.js +1 -1
  81. package/dist/providers/togetherai.js +2 -2
  82. package/dist/providers/venice.js +1 -1
  83. package/dist/providers/vercel-ai-gateway.js +2 -2
  84. package/dist/providers/xai.js +1 -1
  85. package/dist/providers/zai-coding-plan/messages.js +1 -1
  86. package/dist/providers/zai-coding-plan/responses.js +1 -1
  87. package/dist/providers/zai-coding-plan.js +1 -1
  88. package/dist/providers/zai.js +1 -1
  89. package/dist/route/auth.d.ts +1 -1
  90. package/dist/route/auth.js +2 -2
  91. package/dist/route/executor-service.d.ts +1 -1
  92. package/dist/route/executor.d.ts +1 -1
  93. package/dist/route/executor.js +1 -1
  94. package/dist/route/framing.js +1 -1
  95. package/dist/route/media-protocol.d.ts +1 -1
  96. package/dist/route/media-protocol.js +1 -1
  97. package/dist/route/media.js +1 -1
  98. package/dist/route/transport/http.d.ts +1 -1
  99. package/dist/route/transport/http.js +5 -4
  100. package/dist/route/transport/websocket-channel.d.ts +1 -1
  101. package/dist/route/transport/websocket.d.ts +4 -4
  102. package/dist/route/transport/websocket.js +4 -9
  103. package/dist/schema/messages.js +9 -8
  104. package/dist/schema/options.d.ts +15 -1
  105. package/dist/schema/options.js +25 -5
  106. package/dist/tool.d.ts +10 -0
  107. package/dist/tool.js +21 -2
  108. package/package.json +5 -5
@@ -1,5 +1,5 @@
1
1
  import { Effect, Schema, Stream } from "effect";
2
- import { Headers } from "effect/unstable/http";
2
+ import { Headers } from "effect/http";
3
3
  import { Framing } from "../route/framing.js";
4
4
  import { HttpTransport, WebSocketTransport, } from "../route/transport/index.js";
5
5
  import * as ProviderShared from "./shared.js";
@@ -106,7 +106,12 @@ export const transport = (options) => {
106
106
  });
107
107
  return {
108
108
  http: {
109
- request: ProviderShared.jsonPost({ url: parts.url, body: parts.bodyText, headers: parts.headers }),
109
+ request: ProviderShared.jsonPost({
110
+ url: parts.url,
111
+ body: parts.bodyText,
112
+ headers: parts.headers,
113
+ encoding: input.request.http?.encoding,
114
+ }),
110
115
  framing: Framing.sse,
111
116
  middleware: input.middleware,
112
117
  },
@@ -9,6 +9,7 @@ import { Protocol } from "../route/protocol.js";
9
9
  import { AIError, AIErrorReason, InvalidProviderOutputError, LLMEvent, ProviderInternalError, UnknownProviderError, Usage, } from "../schema/index.js";
10
10
  import { classifyProviderFailure } from "../provider-error.js";
11
11
  import { isRecord, JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared.js";
12
+ import { cacheControl } from "./utils/cache.js";
12
13
  import { OpenAIOptions } from "./utils/openai-options.js";
13
14
  import { Lifecycle } from "./utils/lifecycle.js";
14
15
  import { ToolStream } from "./utils/tool-stream.js";
@@ -646,14 +647,15 @@ export const fromRequest = Effect.fn("OpenAIChat.fromRequest")(function* (reques
646
647
  const zaiToolStream = request.model.compatibility?.zaiToolStream ?? detectZaiToolStream(provider, baseURL, request.model.id);
647
648
  const hasHistory = hasToolHistory(request.messages);
648
649
  const hasActiveTools = flattened.tools.length > 0;
650
+ const lowering = { ...options, cacheControl: options.cacheControl ?? declaredCacheControl(request) };
649
651
  return {
650
652
  model: request.model.id,
651
- messages: yield* lowerMessages(flattened.request, options),
653
+ messages: yield* lowerMessages(flattened.request, lowering),
652
654
  tools: flattened.tools.length === 0
653
655
  ? hasHistory
654
656
  ? []
655
657
  : undefined
656
- : flattened.tools.map((tool) => lowerTool(tool, options, supportsStrictMode)),
658
+ : flattened.tools.map((tool) => lowerTool(tool, lowering, supportsStrictMode)),
657
659
  tool_choice: hasActiveTools && request.toolChoice ? yield* lowerToolChoice(request.toolChoice) : undefined,
658
660
  stream: true,
659
661
  ...(supportsUsageInStreaming ? { stream_options: { include_usage: true } } : {}),
@@ -670,6 +672,8 @@ export const fromRequest = Effect.fn("OpenAIChat.fromRequest")(function* (reques
670
672
  ...lowerOptions(request, supportsStore),
671
673
  };
672
674
  });
675
+ // Provider wrappers that pass their own marker writer keep it; otherwise a declared cache format adds one.
676
+ const declaredCacheControl = (request) => request.model.compatibility?.cacheFormat === undefined ? undefined : cacheControl();
673
677
  // =============================================================================
674
678
  // Stream Parsing
675
679
  // =============================================================================
@@ -348,7 +348,7 @@ export declare const protocol: Protocol<{
348
348
  } | {
349
349
  readonly type: "image_generation";
350
350
  readonly size?: string | undefined;
351
- readonly action?: "generate" | "auto" | "edit" | undefined;
351
+ readonly action?: "auto" | "generate" | "edit" | undefined;
352
352
  readonly output_format?: "png" | "jpeg" | "webp" | undefined;
353
353
  readonly quality?: "auto" | "low" | "medium" | "high" | undefined;
354
354
  readonly background?: "auto" | "opaque" | "transparent" | undefined;
@@ -610,7 +610,7 @@ export declare const httpTransport: HttpTransport.HttpJsonTransport<{
610
610
  } | {
611
611
  readonly type: "image_generation";
612
612
  readonly size?: string | undefined;
613
- readonly action?: "generate" | "auto" | "edit" | undefined;
613
+ readonly action?: "auto" | "generate" | "edit" | undefined;
614
614
  readonly output_format?: "png" | "jpeg" | "webp" | undefined;
615
615
  readonly quality?: "auto" | "low" | "medium" | "high" | undefined;
616
616
  readonly background?: "auto" | "opaque" | "transparent" | undefined;
@@ -814,7 +814,7 @@ export declare const channelTransport: (options: import("./open-responses-channe
814
814
  } | {
815
815
  readonly type: "image_generation";
816
816
  readonly size?: string | undefined;
817
- readonly action?: "generate" | "auto" | "edit" | undefined;
817
+ readonly action?: "auto" | "generate" | "edit" | undefined;
818
818
  readonly output_format?: "png" | "jpeg" | "webp" | undefined;
819
819
  readonly quality?: "auto" | "low" | "medium" | "high" | undefined;
820
820
  readonly background?: "auto" | "opaque" | "transparent" | undefined;
@@ -1018,7 +1018,7 @@ export declare const transport: import("../route/transport/index.js").Transport<
1018
1018
  } | {
1019
1019
  readonly type: "image_generation";
1020
1020
  readonly size?: string | undefined;
1021
- readonly action?: "generate" | "auto" | "edit" | undefined;
1021
+ readonly action?: "auto" | "generate" | "edit" | undefined;
1022
1022
  readonly output_format?: "png" | "jpeg" | "webp" | undefined;
1023
1023
  readonly quality?: "auto" | "low" | "medium" | "high" | undefined;
1024
1024
  readonly background?: "auto" | "opaque" | "transparent" | undefined;
@@ -1222,7 +1222,7 @@ export declare const route: Route<{
1222
1222
  } | {
1223
1223
  readonly type: "image_generation";
1224
1224
  readonly size?: string | undefined;
1225
- readonly action?: "generate" | "auto" | "edit" | undefined;
1225
+ readonly action?: "auto" | "generate" | "edit" | undefined;
1226
1226
  readonly output_format?: "png" | "jpeg" | "webp" | undefined;
1227
1227
  readonly quality?: "auto" | "low" | "medium" | "high" | undefined;
1228
1228
  readonly background?: "auto" | "opaque" | "transparent" | undefined;
@@ -1,5 +1,6 @@
1
- import { Effect, Encoding, Schema } from "effect";
2
- import { Headers } from "effect/unstable/http";
1
+ import { Effect, Schema } from "effect";
2
+ import { Base64 } from "effect/encoding";
3
+ import { Headers } from "effect/http";
3
4
  import { Route } from "../route/client.js";
4
5
  import { Auth } from "../route/auth.js";
5
6
  import { Endpoint } from "../route/endpoint.js";
@@ -194,7 +195,7 @@ const checkpointBody = {
194
195
  const hostedToolResult = Effect.fnUntraced(function* (item) {
195
196
  const isError = item.error !== undefined && item.error !== null;
196
197
  if (item.type === "image_generation_call" && item.result) {
197
- yield* Effect.fromResult(Encoding.decodeBase64(item.result)).pipe(Effect.mapError((cause) => ProviderShared.eventError(ADAPTER, "OpenAI Responses returned invalid image base64", undefined, cause)));
198
+ yield* Effect.fromResult(Base64.decode(item.result)).pipe(Effect.mapError((cause) => ProviderShared.eventError(ADAPTER, "OpenAI Responses returned invalid image base64", undefined, cause)));
198
199
  const format = item.output_format ?? "png";
199
200
  return {
200
201
  type: "content",
@@ -1,8 +1,8 @@
1
1
  import { Tool } from "@opencode/schema/tool";
2
2
  import { Effect, Schema } from "effect";
3
- import { Headers, HttpClientRequest } from "effect/unstable/http";
3
+ import { Headers, HttpClientRequest } from "effect/http";
4
4
  import { Media } from "../media.js";
5
- import { AIError, LLMRequest, Message, ToolDefinition, type ContentPart, type MediaPart, type OpenString, type ProviderID, type ToolEntry, type ToolResultPart } from "../schema/index.js";
5
+ import { AIError, LLMRequest, Message, ToolDefinition, type ContentPart, type MediaPart, type OpenString, type ProviderID, type RequestEncoding, type ToolEntry, type ToolResultPart } from "../schema/index.js";
6
6
  import { Json, decodeJson, encodeJson } from "../utils/json.js";
7
7
  import { isRecord } from "../utils/record.js";
8
8
  export { Json, decodeJson, encodeJson, isRecord };
@@ -14,6 +14,7 @@ export declare const lenient: <const S extends Schema.Top>(schema: S) => Schema.
14
14
  /** Provider-defined string enum: known values for autocomplete, any string accepted at runtime. */
15
15
  export declare const knownString: <Known extends string>() => Schema.declare<OpenString<Known>, OpenString<Known>>;
16
16
  export declare const OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;
17
+ export declare const sendsPromptCacheKey: (request: LLMRequest) => boolean;
17
18
  export declare const promptCacheKey: (request: LLMRequest) => string | undefined;
18
19
  /**
19
20
  * Streaming tool-call accumulator. Adapters that build a tool call across
@@ -192,10 +193,13 @@ export declare const validateWith: <A, I, E extends {
192
193
  * send JSON with a stale content type. The body is passed pre-encoded so
193
194
  * routes can choose between
194
195
  * `Schema.encodeSync(payload)` and `ProviderShared.encodeJson(payload)`.
196
+ * A `zstd` or `gzip` encoding compresses the body and sets `content-encoding`;
197
+ * it falls back to plain JSON when the runtime has no zlib.
195
198
  */
196
199
  export declare const jsonPost: (input: {
197
200
  readonly url: string;
198
201
  readonly body: string;
199
202
  readonly headers?: Headers.Input;
203
+ readonly encoding?: RequestEncoding;
200
204
  }) => HttpClientRequest.HttpClientRequest;
201
205
  export * as ProviderShared from "./shared.js";
@@ -1,6 +1,6 @@
1
1
  import { Tool } from "@opencode/schema/tool";
2
2
  import { Effect, Option, Schema } from "effect";
3
- import { Headers, HttpClientRequest } from "effect/unstable/http";
3
+ import { Headers, HttpClientRequest } from "effect/http";
4
4
  import { Media } from "../media.js";
5
5
  import { InvalidProviderOutputError, InvalidRequestError, UnsupportedOperationError, AIError, LLMRequest, Message, ToolDefinition, } from "../schema/index.js";
6
6
  import { Json, decodeJson, encodeJson } from "../utils/json.js";
@@ -17,10 +17,13 @@ export const knownString = () => Schema.declare((value) => typeof value === "str
17
17
  expected: "string",
18
18
  });
19
19
  export const OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH = 64;
20
+ // Body-level `prompt_cache_key` is off when caching is disabled or the model
21
+ // explicitly rejects the field. Header-based affinity is unaffected.
22
+ export const sendsPromptCacheKey = (request) => request.cache !== "none" && request.model.compatibility?.supportsPromptCacheKey !== false;
20
23
  // OpenAI limits `prompt_cache_key` to 64 chars; DeepSeek and Zai inherit the same
21
24
  // limit via their OpenAI-compatible APIs. Clamp with unicode-aware slicing.
22
25
  export const promptCacheKey = (request) => {
23
- if (request.cache === "none" || request.promptCacheKey === undefined)
26
+ if (!sendsPromptCacheKey(request) || request.promptCacheKey === undefined)
24
27
  return undefined;
25
28
  const chars = Array.from(request.promptCacheKey);
26
29
  if (chars.length <= OPENAI_PROMPT_CACHE_KEY_MAX_LENGTH)
@@ -279,6 +282,29 @@ export const validateWith = (decode) => (payload) => decode(payload).pipe(Effect
279
282
  * send JSON with a stale content type. The body is passed pre-encoded so
280
283
  * routes can choose between
281
284
  * `Schema.encodeSync(payload)` and `ProviderShared.encodeJson(payload)`.
285
+ * A `zstd` or `gzip` encoding compresses the body and sets `content-encoding`;
286
+ * it falls back to plain JSON when the runtime has no zlib.
282
287
  */
283
- export const jsonPost = (input) => HttpClientRequest.post(input.url).pipe(HttpClientRequest.setHeaders(Headers.set(Headers.fromInput(input.headers), "content-type", "application/json")), HttpClientRequest.bodyText(input.body, "application/json"));
288
+ export const jsonPost = (input) => {
289
+ const headers = Headers.set(Headers.fromInput(input.headers), "content-type", "application/json");
290
+ const compressed = compressBody(input.body, input.encoding);
291
+ if (!compressed)
292
+ return HttpClientRequest.post(input.url).pipe(HttpClientRequest.setHeaders(headers), HttpClientRequest.bodyText(input.body, "application/json"));
293
+ return HttpClientRequest.post(input.url).pipe(HttpClientRequest.setHeaders(Headers.set(headers, "content-encoding", compressed.encoding)), HttpClientRequest.bodyUint8Array(compressed.body, "application/json"));
294
+ };
295
+ function compressBody(text, encoding) {
296
+ if (encoding === undefined || encoding === "none")
297
+ return undefined;
298
+ // Looked up at call time instead of imported: a runtime without node:zlib or its zstd export
299
+ // (browsers, older Node, some workerd setups) sends plain JSON rather than failing to load this module.
300
+ const zlib = globalThis.process?.getBuiltinModule?.("node:zlib");
301
+ try {
302
+ const body = encoding === "zstd" ? zlib?.zstdCompressSync?.(text) : zlib?.gzipSync(text);
303
+ return body && { encoding, body };
304
+ }
305
+ catch {
306
+ // Compression is an optimization, so a failure sends plain JSON instead of failing the request.
307
+ return undefined;
308
+ }
309
+ }
284
310
  export * as ProviderShared from "./shared.js";
@@ -1,6 +1,6 @@
1
1
  import { AwsV4Signer } from "aws4fetch";
2
2
  import { Effect } from "effect";
3
- import { Headers } from "effect/unstable/http";
3
+ import { Headers } from "effect/http";
4
4
  import { Auth } from "../../route/auth.js";
5
5
  import { AIError, AuthenticationError } from "../../schema/index.js";
6
6
  import { ProviderShared } from "../shared.js";
@@ -1,4 +1,5 @@
1
- import { Effect, Encoding, Schema } from "effect";
1
+ import { Effect, Schema } from "effect";
2
+ import { Base64 } from "effect/encoding";
2
3
  import { ProviderShared } from "../shared.js";
3
4
  // Bedrock Converse accepts image `format` as the file extension and
4
5
  // `source.bytes` as base64 in the JSON wire format.
@@ -63,8 +64,8 @@ function documentName(filename, names) {
63
64
  }
64
65
  const mediaBase64 = Effect.fnUntraced(function* (part) {
65
66
  const media = yield* ProviderShared.requireInlineMedia("Bedrock Converse", part.media);
66
- const bytes = yield* Effect.fromResult(Encoding.decodeBase64(media.base64)).pipe(Effect.mapError((cause) => ProviderShared.invalidRequest("Bedrock Converse media data must be valid base64", cause)));
67
- return Encoding.encodeBase64(bytes);
67
+ const bytes = yield* Effect.fromResult(Base64.decode(media.base64)).pipe(Effect.mapError((cause) => ProviderShared.invalidRequest("Bedrock Converse media data must be valid base64", cause)));
68
+ return Base64.encode(bytes);
68
69
  });
69
70
  // Route by MIME. Known image/document formats lower into a typed block; anything
70
71
  // else fails with a clear error instead of silently degrading to a malformed
@@ -1,5 +1,5 @@
1
1
  import { Effect, Schema } from "effect";
2
- import type { HttpClientResponse } from "effect/unstable/http";
2
+ import type { HttpClientResponse } from "effect/http";
3
3
  import type { Media } from "../../media.js";
4
4
  import { MediaProtocol } from "../../route/media-protocol.js";
5
5
  import type { AIError } from "../../schema/index.js";
@@ -1,4 +1,5 @@
1
- import { Effect, Encoding } from "effect";
1
+ import { Effect } from "effect";
2
+ import { Base64 } from "effect/encoding";
2
3
  import { Media } from "../../media.js";
3
4
  import { mergeJsonRecords } from "../../schema/index.js";
4
5
  import { encodeJson } from "../../utils/json.js";
@@ -10,7 +11,7 @@ export const inlineBytes = (route, asset) => {
10
11
  const inline = asset.inline();
11
12
  if (!inline)
12
13
  return Effect.fail(ProviderShared.inlineRequired(route, asset));
13
- return Effect.fromResult(Encoding.decodeBase64(inline.base64)).pipe(Effect.mapError((cause) => ProviderShared.invalidRequest(`${route} media contains invalid base64 data`, cause)));
14
+ return Effect.fromResult(Base64.decode(inline.base64)).pipe(Effect.mapError((cause) => ProviderShared.invalidRequest(`${route} media contains invalid base64 data`, cause)));
14
15
  };
15
16
  /** Copied because `BlobPart` requires a plain `ArrayBuffer`. */
16
17
  export const blob = (data, mediaType) => {
@@ -33,7 +34,7 @@ export const dimensions = (size) => {
33
34
  /** Provider file handle when the ref belongs to this provider; refs from other providers are never forwarded. */
34
35
  export const refID = (asset, provider) => asset.source.type === "ref" && asset.source.provider === provider ? asset.source.id : undefined;
35
36
  /** Decode a provider's base64 output once into an owned `bytes` asset, sniffing the type when it is not declared. */
36
- export const decodedAsset = (invalid, label, data, mediaType, options) => Effect.fromResult(Encoding.decodeBase64(data)).pipe(Effect.mapError((cause) => invalid(`${label} contains invalid base64 data`, cause)), Effect.map((bytes) => Media.bytes(bytes, mediaType, options)));
37
+ export const decodedAsset = (invalid, label, data, mediaType, options) => Effect.fromResult(Base64.decode(data)).pipe(Effect.mapError((cause) => invalid(`${label} contains invalid base64 data`, cause)), Effect.map((bytes) => Media.bytes(bytes, mediaType, options)));
37
38
  /** One image of an OpenAI-shaped `data` array, which carries either `b64_json` or a `url`. */
38
39
  export const imageOutput = (invalid, label, item, mediaType, options) => {
39
40
  if (item.b64_json)
@@ -87,7 +87,12 @@ export const make = (adapter, lowerTools) => Effect.fn("ResponsesCompaction.exec
87
87
  auth: route.auth,
88
88
  encodeBody: Schema.encodeSync(Schema.fromJsonString(Body)),
89
89
  });
90
- const response = yield* executor.execute(ProviderShared.jsonPost({ url: parts.url, body: parts.bodyText, headers: parts.headers }), options?.http);
90
+ const response = yield* executor.execute(ProviderShared.jsonPost({
91
+ url: parts.url,
92
+ body: parts.bodyText,
93
+ headers: parts.headers,
94
+ encoding: request.http?.encoding,
95
+ }), options?.http);
91
96
  const text = yield* RequestExecutor.responseStream(response).pipe(Stream.decodeText(), Stream.runFold(() => "", (text, chunk) => text + chunk));
92
97
  const invalid = (message, cause) => new AIError({
93
98
  reason: new InvalidProviderOutputError({
@@ -56,9 +56,15 @@ const MODEL_NAMES = [
56
56
  [/kimi/i, "moonshot"],
57
57
  ];
58
58
  // Tool arguments are always a JSON object, and most providers reject a tool schema whose root does not
59
- // declare `type: "object"`, such as `{}` or a bare `properties` map. Effect encodes an empty struct as
60
- // `anyOf` object or array; every object matches its bare object branch, so that `anyOf` is dropped.
59
+ // declare `type: "object"`, such as `{}` or a bare `properties` map. An object root makes Effect's
60
+ // empty-struct markers redundant: `{ not: { type: "null" } }`, and `anyOf` object or array from older
61
+ // releases. Both are dropped so the root is a plain object schema.
61
62
  const objectRoot = (schema) => {
63
+ if ((schema.type === undefined || schema.type === "object") &&
64
+ isRecord(schema.not) &&
65
+ schema.not.type === "null" &&
66
+ Object.keys(schema.not).length === 1)
67
+ return { type: "object", ...Object.fromEntries(Object.entries(schema).filter(([key]) => key !== "not")) };
62
68
  if (schema.type !== undefined)
63
69
  return schema;
64
70
  if (Array.isArray(schema.anyOf) &&
@@ -129,7 +129,7 @@ export declare const routes: (Route<{
129
129
  readonly temperature?: number | undefined;
130
130
  readonly seed?: number | undefined;
131
131
  readonly thinking?: {
132
- readonly type: "disabled" | (string & {}) | "adaptive";
132
+ readonly type: (string & {}) | "disabled" | "adaptive";
133
133
  } | undefined;
134
134
  readonly tool_choice?: "required" | "auto" | "none" | {
135
135
  readonly type: "function";
@@ -611,7 +611,7 @@ export declare const configure: (input: Config) => {
611
611
  id: string & import("effect/Brand").Brand<"AI.ProviderID">;
612
612
  model: (id: string | ModelID) => import("../schema/options.js").LanguageModel<{
613
613
  readonly thinking?: {
614
- readonly type: "disabled" | (string & {}) | "adaptive";
614
+ readonly type: (string & {}) | "disabled" | "adaptive";
615
615
  } | undefined;
616
616
  readonly thinkingBudget?: number | undefined;
617
617
  readonly parallelToolCalls?: boolean | undefined;
@@ -636,7 +636,7 @@ export declare const configure: (input: Config) => {
636
636
  }, import("../route/client.js").CompactionOperations | undefined>;
637
637
  chat: (id: string | ModelID) => import("../schema/options.js").LanguageModel<{
638
638
  readonly thinking?: {
639
- readonly type: "disabled" | (string & {}) | "adaptive";
639
+ readonly type: (string & {}) | "disabled" | "adaptive";
640
640
  } | undefined;
641
641
  readonly thinkingBudget?: number | undefined;
642
642
  readonly parallelToolCalls?: boolean | undefined;
@@ -675,7 +675,7 @@ export declare const provider: {
675
675
  id: string & import("effect/Brand").Brand<"AI.ProviderID">;
676
676
  model: (id: string | ModelID) => import("../schema/options.js").LanguageModel<{
677
677
  readonly thinking?: {
678
- readonly type: "disabled" | (string & {}) | "adaptive";
678
+ readonly type: (string & {}) | "disabled" | "adaptive";
679
679
  } | undefined;
680
680
  readonly thinkingBudget?: number | undefined;
681
681
  readonly parallelToolCalls?: boolean | undefined;
@@ -700,7 +700,7 @@ export declare const provider: {
700
700
  }, import("../route/client.js").CompactionOperations | undefined>;
701
701
  chat: (id: string | ModelID) => import("../schema/options.js").LanguageModel<{
702
702
  readonly thinking?: {
703
- readonly type: "disabled" | (string & {}) | "adaptive";
703
+ readonly type: (string & {}) | "disabled" | "adaptive";
704
704
  } | undefined;
705
705
  readonly thinkingBudget?: number | undefined;
706
706
  readonly parallelToolCalls?: boolean | undefined;
@@ -93,8 +93,8 @@ const fromSettings = ({ apiKey, auth, baseURL, body, credentials, headers, profi
93
93
  baseURL,
94
94
  credentials,
95
95
  generation: topP === undefined ? undefined : { topP },
96
- headers: headers === undefined ? undefined : { ...headers },
97
- http: body === undefined ? undefined : { body: { ...body } },
96
+ headers,
97
+ http: body === undefined ? undefined : { body },
98
98
  profile,
99
99
  providerOptions,
100
100
  region,
@@ -42,8 +42,8 @@ export const model = (modelID, { apiKey, authToken, baseURL, body, headers, prov
42
42
  return configure({
43
43
  ...(authToken === undefined ? { apiKey: apiKey } : { auth: Auth.bearer(authToken) }),
44
44
  baseURL,
45
- headers: headers === undefined ? undefined : { ...headers },
46
- http: body === undefined ? undefined : { body: { ...body } },
45
+ headers,
46
+ http: body === undefined ? undefined : { body },
47
47
  provider,
48
48
  providerOptions,
49
49
  }).model(modelID);
@@ -35,8 +35,8 @@ export const model = (modelID, { apiKey, authToken, baseURL, body, headers, ...p
35
35
  return configure({
36
36
  ...(authToken === undefined ? { apiKey: apiKey } : { auth: Auth.bearer(authToken) }),
37
37
  baseURL,
38
- headers: headers === undefined ? undefined : { ...headers },
39
- http: body === undefined ? undefined : { body: { ...body } },
38
+ headers,
39
+ http: body === undefined ? undefined : { body },
40
40
  providerOptions,
41
41
  }).model(modelID);
42
42
  };
@@ -166,7 +166,7 @@ declare const responsesRoute: Route<{
166
166
  } | {
167
167
  readonly type: "image_generation";
168
168
  readonly size?: string | undefined;
169
- readonly action?: "generate" | "auto" | "edit" | undefined;
169
+ readonly action?: "auto" | "generate" | "edit" | undefined;
170
170
  readonly output_format?: "png" | "jpeg" | "webp" | undefined;
171
171
  readonly quality?: "auto" | "low" | "medium" | "high" | undefined;
172
172
  readonly background?: "auto" | "opaque" | "transparent" | undefined;
@@ -493,7 +493,7 @@ export declare const routes: (Route<{
493
493
  } | {
494
494
  readonly type: "image_generation";
495
495
  readonly size?: string | undefined;
496
- readonly action?: "generate" | "auto" | "edit" | undefined;
496
+ readonly action?: "auto" | "generate" | "edit" | undefined;
497
497
  readonly output_format?: "png" | "jpeg" | "webp" | undefined;
498
498
  readonly quality?: "auto" | "low" | "medium" | "high" | undefined;
499
499
  readonly background?: "auto" | "opaque" | "transparent" | undefined;
@@ -91,10 +91,10 @@ const config = ({ apiKey, apiVersion, baseURL, body, headers, queryParams, resou
91
91
  const common = {
92
92
  apiKey,
93
93
  apiVersion,
94
- headers: headers === undefined ? undefined : { ...headers },
95
- http: body === undefined ? undefined : { body: { ...body } },
94
+ headers,
95
+ http: body === undefined ? undefined : { body },
96
96
  providerOptions,
97
- queryParams: queryParams === undefined ? undefined : { ...queryParams },
97
+ queryParams,
98
98
  useDeploymentBasedUrls,
99
99
  };
100
100
  if (baseURL !== undefined)
@@ -31,8 +31,8 @@ export const provider = configure();
31
31
  export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOptions }) => configure({
32
32
  apiKey,
33
33
  baseURL,
34
- headers: headers === undefined ? undefined : { ...headers },
35
- http: body === undefined ? undefined : { body: { ...body } },
34
+ headers,
35
+ http: body === undefined ? undefined : { body },
36
36
  providerOptions,
37
37
  }).model(modelID);
38
38
  export * as Baseten from "./baseten.js";
@@ -39,7 +39,7 @@ export const provider = configure();
39
39
  export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOptions }) => configure({
40
40
  apiKey,
41
41
  baseURL,
42
- headers: headers === undefined ? undefined : { ...headers },
43
- http: body === undefined ? undefined : { body: { ...body } },
42
+ headers,
43
+ http: body === undefined ? undefined : { body },
44
44
  providerOptions,
45
45
  }).model(modelID);
@@ -172,7 +172,7 @@ export declare const responsesRoute: import("../route/client.js").Route<{
172
172
  } | {
173
173
  readonly type: "image_generation";
174
174
  readonly size?: string | undefined;
175
- readonly action?: "generate" | "auto" | "edit" | undefined;
175
+ readonly action?: "auto" | "generate" | "edit" | undefined;
176
176
  readonly output_format?: "png" | "jpeg" | "webp" | undefined;
177
177
  readonly quality?: "auto" | "low" | "medium" | "high" | undefined;
178
178
  readonly background?: "auto" | "opaque" | "transparent" | undefined;
@@ -1167,7 +1167,7 @@ export declare const routes: (import("../route/client.js").Route<{
1167
1167
  } | {
1168
1168
  readonly type: "image_generation";
1169
1169
  readonly size?: string | undefined;
1170
- readonly action?: "generate" | "auto" | "edit" | undefined;
1170
+ readonly action?: "auto" | "generate" | "edit" | undefined;
1171
1171
  readonly output_format?: "png" | "jpeg" | "webp" | undefined;
1172
1172
  readonly quality?: "auto" | "low" | "medium" | "high" | undefined;
1173
1173
  readonly background?: "auto" | "opaque" | "transparent" | undefined;
@@ -100,8 +100,8 @@ export const model = (modelID, { accountId, apiKey, baseURL: configuredBaseURL,
100
100
  collectLog,
101
101
  gatewayApiKey,
102
102
  gatewayId,
103
- headers: headers === undefined ? undefined : { ...headers },
104
- http: body === undefined ? undefined : { body: { ...body } },
103
+ headers,
104
+ http: body === undefined ? undefined : { body },
105
105
  metadata,
106
106
  providerOptions,
107
107
  skipCache,
@@ -43,8 +43,8 @@ export const model = (modelID, settings) => {
43
43
  return configure({
44
44
  apiKey,
45
45
  baseURL: baseURL(settings),
46
- headers: headers === undefined ? undefined : { ...headers },
47
- http: body === undefined ? undefined : { body: { ...body } },
46
+ headers,
47
+ http: body === undefined ? undefined : { body },
48
48
  providerOptions,
49
49
  }).model(modelID);
50
50
  };
@@ -3,6 +3,6 @@ export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOpti
3
3
  apiKey,
4
4
  baseURL,
5
5
  headers,
6
- http: body === undefined ? undefined : { body: { ...body } },
6
+ http: body === undefined ? undefined : { body },
7
7
  providerOptions,
8
8
  }).chat(modelID);
@@ -42,7 +42,7 @@ export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOpti
42
42
  apiKey,
43
43
  baseURL,
44
44
  headers,
45
- http: body === undefined ? undefined : { body: { ...body } },
45
+ http: body === undefined ? undefined : { body },
46
46
  providerOptions,
47
47
  }).model(modelID);
48
48
  export * as Cohere from "./cohere.js";
@@ -42,7 +42,7 @@ export const provider = configure();
42
42
  export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOptions }) => configure({
43
43
  apiKey,
44
44
  baseURL,
45
- headers: headers === undefined ? undefined : { ...headers },
46
- http: body === undefined ? undefined : { body: { ...body } },
45
+ headers,
46
+ http: body === undefined ? undefined : { body },
47
47
  providerOptions,
48
48
  }).model(modelID);
@@ -34,8 +34,8 @@ export const provider = configure();
34
34
  export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOptions }) => configure({
35
35
  apiKey,
36
36
  baseURL,
37
- headers: headers === undefined ? undefined : { ...headers },
38
- http: body === undefined ? undefined : { body: { ...body } },
37
+ headers,
38
+ http: body === undefined ? undefined : { body },
39
39
  providerOptions,
40
40
  }).model(modelID);
41
41
  export * as DeepSeek from "./deepseek.js";
@@ -31,8 +31,8 @@ export const provider = configure();
31
31
  export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOptions }) => configure({
32
32
  apiKey,
33
33
  baseURL,
34
- headers: headers === undefined ? undefined : { ...headers },
35
- http: body === undefined ? undefined : { body: { ...body } },
34
+ headers,
35
+ http: body === undefined ? undefined : { body },
36
36
  providerOptions,
37
37
  }).model(modelID);
38
38
  export * as Fireworks from "./fireworks.js";
@@ -2,7 +2,7 @@ import { configure } from "../google.js";
2
2
  export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOptions }) => configure({
3
3
  apiKey,
4
4
  baseURL,
5
- headers: headers === undefined ? undefined : { ...headers },
6
- http: body === undefined ? undefined : { body: { ...body } },
5
+ headers,
6
+ http: body === undefined ? undefined : { body },
7
7
  providerOptions,
8
8
  }).interactions(modelID);
@@ -0,0 +1,2 @@
1
+ export { model } from "../google-vertex-interactions.js";
2
+ export type { Settings } from "../google-vertex-interactions.js";
@@ -0,0 +1 @@
1
+ export { model } from "../google-vertex-interactions.js";
@@ -0,0 +1,2 @@
1
+ export { model } from "../google-vertex-mistral.js";
2
+ export type { Settings } from "../google-vertex-mistral.js";
@@ -0,0 +1 @@
1
+ export { model } from "../google-vertex-mistral.js";
@@ -17,7 +17,7 @@ const configuredRoute = (input) => {
17
17
  if ("apiKey" in input && input.apiKey !== undefined)
18
18
  throw new ProviderConfigurationError({ provider: id, message: "Google Vertex Chat does not support API keys" });
19
19
  const { accessToken: _accessToken, auth: _auth, baseURL, location: inputLocation, project: inputProject, ...rest } = input;
20
- const location = GoogleVertexShared.location(inputLocation, "global");
20
+ const location = GoogleVertexShared.location(inputLocation);
21
21
  const project = GoogleVertexShared.project(inputProject);
22
22
  return route.with({
23
23
  ...rest,
@@ -46,8 +46,8 @@ export const model = (modelID, { accessToken, apiKey, baseURL, body, headers, lo
46
46
  return configure({
47
47
  accessToken,
48
48
  baseURL,
49
- headers: headers === undefined ? undefined : { ...headers },
50
- http: body === undefined ? undefined : { body: { ...body } },
49
+ headers,
50
+ http: body === undefined ? undefined : { body },
51
51
  location,
52
52
  project,
53
53
  providerOptions,