@opencode/ai 2.0.23 → 2.0.25

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 (43) hide show
  1. package/README.md +1 -1
  2. package/dist/cache-policy.js +12 -9
  3. package/dist/protocols/alibaba-messages.d.ts +3 -0
  4. package/dist/protocols/alibaba-responses.d.ts +3 -0
  5. package/dist/protocols/anthropic-messages.d.ts +8 -5
  6. package/dist/protocols/anthropic-messages.js +19 -16
  7. package/dist/protocols/bedrock-converse.js +3 -1
  8. package/dist/protocols/google-interactions.d.ts +1 -1
  9. package/dist/protocols/meta-messages.d.ts +4 -1
  10. package/dist/protocols/meta-responses.d.ts +3 -0
  11. package/dist/protocols/open-responses.d.ts +18 -12
  12. package/dist/protocols/open-responses.js +7 -5
  13. package/dist/protocols/openai-responses.d.ts +3 -0
  14. package/dist/protocols/utils/bedrock-auth.js +2 -1
  15. package/dist/protocols/utils/gateway-protocol.d.ts +17 -0
  16. package/dist/protocols/utils/gateway-protocol.js +57 -0
  17. package/dist/protocols/utils/openai-options.d.ts +1 -1
  18. package/dist/protocols/utils/openai-options.js +2 -1
  19. package/dist/protocols/utils/tool-stream.d.ts +1 -1
  20. package/dist/protocols/utils/tool-stream.js +5 -5
  21. package/dist/protocols/xai-responses.d.ts +3 -0
  22. package/dist/protocols/zai-messages.d.ts +3 -0
  23. package/dist/providers/amazon-bedrock-mantle.d.ts +1 -1
  24. package/dist/providers/amazon-bedrock-mantle.js +4 -3
  25. package/dist/providers/anthropic-compatible.d.ts +1 -1
  26. package/dist/providers/anthropic.d.ts +1 -1
  27. package/dist/providers/cloudflare-ai-gateway.d.ts +2 -2
  28. package/dist/providers/google-vertex-messages.d.ts +1 -1
  29. package/dist/providers/google-vertex-messages.js +1 -0
  30. package/dist/providers/google-vertex.js +1 -1
  31. package/dist/providers/google.d.ts +4 -4
  32. package/dist/providers/meta.d.ts +1 -1
  33. package/dist/providers/minimax.d.ts +1 -1
  34. package/dist/providers/moonshot.d.ts +1 -1
  35. package/dist/providers/vercel-ai-gateway/chat.d.ts +2 -0
  36. package/dist/providers/vercel-ai-gateway/chat.js +1 -0
  37. package/dist/providers/vercel-ai-gateway/messages.d.ts +2 -0
  38. package/dist/providers/vercel-ai-gateway/messages.js +1 -0
  39. package/dist/providers/vercel-ai-gateway/responses.d.ts +2 -0
  40. package/dist/providers/vercel-ai-gateway/responses.js +1 -0
  41. package/dist/providers/vercel-ai-gateway.d.ts +91 -9
  42. package/dist/providers/vercel-ai-gateway.js +161 -21
  43. package/package.json +3 -3
@@ -266,8 +266,10 @@ export declare const protocol: Protocol<{
266
266
  readonly top_k?: number | undefined;
267
267
  readonly stop_sequences?: readonly string[] | undefined;
268
268
  }, string, {
269
+ readonly [x: string]: unknown;
269
270
  readonly type: string;
270
271
  readonly message?: {
272
+ readonly [x: string]: unknown;
271
273
  readonly usage?: {
272
274
  readonly [x: string]: unknown;
273
275
  readonly input_tokens?: number | null | undefined;
@@ -300,6 +302,7 @@ export declare const protocol: Protocol<{
300
302
  } | undefined;
301
303
  } | undefined;
302
304
  readonly error?: {
305
+ readonly [x: string]: unknown;
303
306
  readonly type?: string | undefined;
304
307
  readonly message?: string | undefined;
305
308
  } | undefined;
@@ -257,7 +257,7 @@ export declare const routes: (Route<{
257
257
  readonly prefix_mismatch_behavior?: import("../schema/options.js").OpenString<"error" | "drop_block"> | undefined;
258
258
  } | undefined;
259
259
  } | {
260
- readonly type: "disabled";
260
+ readonly type: "disabled" | "between_tools";
261
261
  } | undefined;
262
262
  readonly service_tier?: import("../schema/options.js").OpenString<"auto" | "standard_only"> | undefined;
263
263
  readonly container?: string | {
@@ -30,9 +30,10 @@ const messagesRoute = Route.make({
30
30
  ...AnthropicMessages.protocol,
31
31
  // Mantle rejects mid-conversation `output_config` on Opus 5.0; support starts at 5.1+.
32
32
  supportsEffortUpdates: (request) => {
33
- const override = request.model.compatibility?.supportsEffortUpdates;
34
- if (override !== undefined)
35
- return override;
33
+ if (!(AnthropicMessages.protocol.supportsEffortUpdates?.(request) ?? false))
34
+ return false;
35
+ if (request.model.compatibility?.supportsEffortUpdates !== undefined)
36
+ return true;
36
37
  const version = claudeVersion(request.model.id);
37
38
  return version !== undefined && (version.major > 5 || (version.major === 5 && version.minor >= 1));
38
39
  },
@@ -249,7 +249,7 @@ export declare const routes: import("../route/client.js").Route<{
249
249
  readonly prefix_mismatch_behavior?: import("../schema/options.js").OpenString<"error" | "drop_block"> | undefined;
250
250
  } | undefined;
251
251
  } | {
252
- readonly type: "disabled";
252
+ readonly type: "disabled" | "between_tools";
253
253
  } | undefined;
254
254
  readonly service_tier?: import("../schema/options.js").OpenString<"auto" | "standard_only"> | undefined;
255
255
  readonly container?: string | {
@@ -234,7 +234,7 @@ export declare const routes: import("../route/client.js").Route<{
234
234
  readonly prefix_mismatch_behavior?: import("../schema/options.js").OpenString<"error" | "drop_block"> | undefined;
235
235
  } | undefined;
236
236
  } | {
237
- readonly type: "disabled";
237
+ readonly type: "disabled" | "between_tools";
238
238
  } | undefined;
239
239
  readonly service_tier?: import("../schema/options.js").OpenString<"auto" | "standard_only"> | undefined;
240
240
  readonly container?: string | {
@@ -461,7 +461,7 @@ export declare const messagesRoute: import("../route/client.js").Route<{
461
461
  readonly prefix_mismatch_behavior?: import("../schema/options.js").OpenString<"error" | "drop_block"> | undefined;
462
462
  } | undefined;
463
463
  } | {
464
- readonly type: "disabled";
464
+ readonly type: "disabled" | "between_tools";
465
465
  } | undefined;
466
466
  readonly service_tier?: import("../schema/options.js").OpenString<"auto" | "standard_only"> | undefined;
467
467
  readonly container?: string | {
@@ -856,7 +856,7 @@ export declare const routes: (import("../route/client.js").Route<{
856
856
  readonly prefix_mismatch_behavior?: import("../schema/options.js").OpenString<"error" | "drop_block"> | undefined;
857
857
  } | undefined;
858
858
  } | {
859
- readonly type: "disabled";
859
+ readonly type: "disabled" | "between_tools";
860
860
  } | undefined;
861
861
  readonly service_tier?: import("../schema/options.js").OpenString<"auto" | "standard_only"> | undefined;
862
862
  readonly container?: string | {
@@ -247,7 +247,7 @@ export declare const routes: Route<{
247
247
  readonly prefix_mismatch_behavior?: import("../schema/options.js").OpenString<"error" | "drop_block"> | undefined;
248
248
  } | undefined;
249
249
  } | {
250
- readonly type: "disabled";
250
+ readonly type: "disabled" | "between_tools";
251
251
  } | undefined;
252
252
  service_tier?: import("../schema/options.js").OpenString<"auto" | "standard_only"> | undefined;
253
253
  container?: string | {
@@ -26,6 +26,7 @@ const route = Route.make({
26
26
  }))),
27
27
  },
28
28
  stream: AnthropicMessages.protocol.stream,
29
+ supportsEffortUpdates: AnthropicMessages.protocol.supportsEffortUpdates,
29
30
  }),
30
31
  endpoint: Endpoint.path(({ request }) => `/${request.model.id}:streamRawPredict`),
31
32
  auth: Auth.none,
@@ -49,7 +49,7 @@ const configuredRoute = (input, modelID) => {
49
49
  provider: id,
50
50
  message: "Google Vertex tuned models do not support Express Mode API keys",
51
51
  });
52
- const location = GoogleVertexShared.location(inputLocation, "us-central1");
52
+ const location = GoogleVertexShared.location(inputLocation, "global");
53
53
  const project = GoogleVertexShared.project(inputProject);
54
54
  const endpoint = baseURL ??
55
55
  (apiKey
@@ -170,7 +170,7 @@ export declare const configure: (input?: Config) => {
170
170
  id: string & import("effect/Brand").Brand<"AI.ProviderID">;
171
171
  model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<Gemini.OptionsInput, import("../route/client.js").CompactionOperations | undefined>;
172
172
  interactions: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<{
173
- readonly serviceTier?: import("../schema/options.js").OpenString<"standard" | "flex" | "priority"> | undefined;
173
+ readonly serviceTier?: import("../schema/options.js").OpenString<"standard" | "flex" | "priority" | "deferred"> | undefined;
174
174
  readonly thinkingLevel?: import("../schema/options.js").OpenString<"minimal" | "low" | "medium" | "high"> | undefined;
175
175
  readonly previousInteractionId?: string | undefined;
176
176
  readonly store?: boolean | undefined;
@@ -186,7 +186,7 @@ export declare const provider: {
186
186
  id: string & import("effect/Brand").Brand<"AI.ProviderID">;
187
187
  model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<Gemini.OptionsInput, import("../route/client.js").CompactionOperations | undefined>;
188
188
  interactions: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<{
189
- readonly serviceTier?: import("../schema/options.js").OpenString<"standard" | "flex" | "priority"> | undefined;
189
+ readonly serviceTier?: import("../schema/options.js").OpenString<"standard" | "flex" | "priority" | "deferred"> | undefined;
190
190
  readonly thinkingLevel?: import("../schema/options.js").OpenString<"minimal" | "low" | "medium" | "high"> | undefined;
191
191
  readonly previousInteractionId?: string | undefined;
192
192
  readonly store?: boolean | undefined;
@@ -200,7 +200,7 @@ export declare const provider: {
200
200
  id: string & import("effect/Brand").Brand<"AI.ProviderID">;
201
201
  model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<Gemini.OptionsInput, import("../route/client.js").CompactionOperations | undefined>;
202
202
  interactions: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<{
203
- readonly serviceTier?: import("../schema/options.js").OpenString<"standard" | "flex" | "priority"> | undefined;
203
+ readonly serviceTier?: import("../schema/options.js").OpenString<"standard" | "flex" | "priority" | "deferred"> | undefined;
204
204
  readonly thinkingLevel?: import("../schema/options.js").OpenString<"minimal" | "low" | "medium" | "high"> | undefined;
205
205
  readonly previousInteractionId?: string | undefined;
206
206
  readonly store?: boolean | undefined;
@@ -216,7 +216,7 @@ export declare const provider: {
216
216
  export declare const model: ProviderPackage.Definition<Settings, Gemini.ProviderOptionsInput>["model"];
217
217
  export declare const image: (modelID: string | ModelID) => import("../image.js").ImageModel<import("../protocols/google-images.js").GoogleImageOptions>;
218
218
  export declare const interactions: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<{
219
- readonly serviceTier?: import("../schema/options.js").OpenString<"standard" | "flex" | "priority"> | undefined;
219
+ readonly serviceTier?: import("../schema/options.js").OpenString<"standard" | "flex" | "priority" | "deferred"> | undefined;
220
220
  readonly thinkingLevel?: import("../schema/options.js").OpenString<"minimal" | "low" | "medium" | "high"> | undefined;
221
221
  readonly previousInteractionId?: string | undefined;
222
222
  readonly store?: boolean | undefined;
@@ -573,7 +573,7 @@ export declare const routes: (Route<{
573
573
  readonly prefix_mismatch_behavior?: OpenString<"error" | "drop_block"> | undefined;
574
574
  } | undefined;
575
575
  } | {
576
- readonly type: "disabled";
576
+ readonly type: "disabled" | "between_tools";
577
577
  } | undefined;
578
578
  readonly service_tier?: OpenString<"auto" | "standard_only"> | undefined;
579
579
  readonly container?: string | {
@@ -260,7 +260,7 @@ export declare const routes: (Route<{
260
260
  readonly prefix_mismatch_behavior?: import("../schema/options.js").OpenString<"error" | "drop_block"> | undefined;
261
261
  } | undefined;
262
262
  } | {
263
- readonly type: "disabled";
263
+ readonly type: "disabled" | "between_tools";
264
264
  } | undefined;
265
265
  readonly service_tier?: import("../schema/options.js").OpenString<"auto" | "standard_only"> | undefined;
266
266
  readonly container?: string | {
@@ -258,7 +258,7 @@ export declare const routes: (Route<{
258
258
  readonly prefix_mismatch_behavior?: import("../schema/options.js").OpenString<"error" | "drop_block"> | undefined;
259
259
  } | undefined;
260
260
  } | {
261
- readonly type: "disabled";
261
+ readonly type: "disabled" | "between_tools";
262
262
  } | undefined;
263
263
  readonly service_tier?: import("../schema/options.js").OpenString<"auto" | "standard_only"> | undefined;
264
264
  readonly container?: string | {
@@ -0,0 +1,2 @@
1
+ export { chatModel as model } from "../vercel-ai-gateway.js";
2
+ export type { Settings } from "../vercel-ai-gateway.js";
@@ -0,0 +1 @@
1
+ export { chatModel as model } from "../vercel-ai-gateway.js";
@@ -0,0 +1,2 @@
1
+ export { messagesModel as model } from "../vercel-ai-gateway.js";
2
+ export type { Settings } from "../vercel-ai-gateway.js";
@@ -0,0 +1 @@
1
+ export { messagesModel as model } from "../vercel-ai-gateway.js";
@@ -0,0 +1,2 @@
1
+ export { responsesModel as model } from "../vercel-ai-gateway.js";
2
+ export type { Settings } from "../vercel-ai-gateway.js";
@@ -0,0 +1 @@
1
+ export { responsesModel as model } from "../vercel-ai-gateway.js";
@@ -1,22 +1,89 @@
1
1
  import { EvaluationModel } from "../experimental/evaluation.js";
2
+ import { AnthropicMessages } from "../protocols/anthropic-messages.js";
3
+ import type { ProviderPackage } from "../provider-package.js";
2
4
  import { type ProviderAuthOption } from "../route/auth-options.js";
3
- import { HttpOptions, ModelID } from "../schema/index.js";
5
+ import { Route, type RouteDefaultsInput } from "../route/client.js";
6
+ import { ModelID } from "../schema/index.js";
7
+ import type { OpenResponsesProviderOptionsInput } from "./open-responses-options.js";
4
8
  export declare const id: string & import("effect/Brand").Brand<"AI.ProviderID">;
5
- export interface EvaluationOptions {
9
+ export interface GatewayOptions {
10
+ /** Service-owned options added by the Gateway without requiring an SDK update. */
6
11
  readonly [key: string]: unknown;
7
- readonly gateway?: Readonly<{
12
+ /** Enables Gateway automatic prompt-cache breakpoint injection (`"auto"`). */
13
+ readonly caching?: "auto" | (string & {});
14
+ /** Provider slugs that are the only ones allowed to serve the request (e.g. `["anthropic", "vertex"]`). */
15
+ readonly only?: ReadonlyArray<string>;
16
+ /** Provider slugs specifying the order in which providers are tried (e.g. `["bedrock", "anthropic"]`). */
17
+ readonly order?: ReadonlyArray<string>;
18
+ /** Sort candidate providers by cost (`"cost"`), throughput (`"tps"`), or time-to-first-token (`"ttft"`). */
19
+ readonly sort?: "cost" | "tps" | "ttft" | (string & {});
20
+ /** Fallback models to try in order, or a conditional `{ model, when }` entry on evaluation requests. */
21
+ readonly models?: ReadonlyArray<string | Readonly<Record<string, unknown>>>;
22
+ /** Restrict routing to providers with zero data retention agreements. */
23
+ readonly zeroDataRetention?: boolean;
24
+ /** Restrict routing to providers that do not train on prompt data. */
25
+ readonly disallowPromptTraining?: boolean;
26
+ /**
27
+ * Restrict routing to provider models that satisfy every entry: capability
28
+ * tags (`"implicit-caching"`, `"reasoning"`, `"structured-output"`,
29
+ * `"tool-use"`, `"vision"`) or weight-format filters (`"quantization:fp8"`,
30
+ * `"!quantization:fp8"`).
31
+ */
32
+ readonly has?: ReadonlyArray<"implicit-caching" | "reasoning" | "structured-output" | "tool-use" | "vision" | `quantization:${string}` | `!quantization:${string}` | (string & {})>;
33
+ /** Entity identifier against which Gateway quota is tracked. */
34
+ readonly quotaEntityId?: string;
35
+ /** Unified service tier intent (`"flex"` or `"priority"`). */
36
+ readonly serviceTier?: "flex" | "priority" | (string & {});
37
+ /** End-user identifier for spend tracking and attribution. */
38
+ readonly user?: string;
39
+ /** User-specified tags for reporting and filtering usage. */
40
+ readonly tags?: ReadonlyArray<string>;
41
+ /** Request-scoped BYOK credentials keyed by provider slug, used instead of cached workspace credentials. */
42
+ readonly byok?: Readonly<Record<string, ReadonlyArray<Readonly<Record<string, unknown>>>>>;
43
+ /** Preferred inference region for upstream provider routing. */
44
+ readonly inferenceRegion?: string;
45
+ /** Per-provider timeouts in milliseconds (e.g. `{ byok: { anthropic: 3000 } }`). */
46
+ readonly providerTimeouts?: {
8
47
  readonly [key: string]: unknown;
9
- readonly zeroDataRetention?: boolean;
10
- readonly only?: ReadonlyArray<string>;
11
- }>;
48
+ readonly byok?: Readonly<Record<string, number>>;
49
+ };
50
+ }
51
+ export type ProviderOptionsInput = OpenResponsesProviderOptionsInput & Omit<AnthropicMessages.OptionsInput, "thinking"> & {
52
+ /** Reasoning configuration for Messages (`thinking`) or Chat (`reasoning.enabled` + `reasoning.max_tokens`). */
53
+ readonly thinking?: AnthropicMessages.OptionsInput["thinking"] | {
54
+ readonly type: "enabled" | "adaptive" | "disabled" | (string & {});
55
+ readonly budgetTokens?: number;
56
+ readonly budget_tokens?: number;
57
+ };
58
+ /** Gateway routing, fallback, BYOK, compliance, and attribution options sent under `body.providerOptions.gateway`. */
59
+ readonly gateway?: GatewayOptions;
60
+ /** Provider-specific options forwarded under their upstream namespace in `body.providerOptions` (e.g. `{ anthropic: { ... } }`). */
61
+ readonly upstream?: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
62
+ /** Responses API automatic-cache lifetime (`"5m"` or `"1h"`), sent as top-level `cache_ttl`. */
63
+ readonly cacheTTL?: "5m" | "1h" | (string & {});
64
+ /** Responses API count of stable input items to anchor for caching, sent as top-level `cache_anchor_items`. */
65
+ readonly cacheAnchorItems?: number;
66
+ };
67
+ export interface EvaluationOptions {
68
+ readonly [key: string]: unknown;
69
+ readonly gateway?: GatewayOptions;
12
70
  }
13
- export type Options = ProviderAuthOption<"optional"> & {
71
+ export type Options = Omit<RouteDefaultsInput, "providerOptions"> & ProviderAuthOption<"optional"> & {
14
72
  readonly baseURL?: string;
15
- readonly headers?: Record<string, string>;
16
- readonly http?: HttpOptions.Input;
73
+ readonly providerOptions?: ProviderOptionsInput;
74
+ };
75
+ export type Settings = ProviderPackage.Settings & ProviderOptionsInput & {
76
+ readonly apiKey?: string;
17
77
  };
78
+ export declare const routes: Route<{
79
+ readonly [x: string]: unknown;
80
+ }, import("../route/transport/http.js").HttpPrepared<string>, import("../route/client.js").CompactionOperations | undefined>[];
18
81
  export declare const configure: (input?: Options) => {
19
82
  id: string & import("effect/Brand").Brand<"AI.ProviderID">;
83
+ model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
84
+ messages: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
85
+ responses: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
86
+ chat: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
20
87
  experimental: {
21
88
  evaluation: (modelID: string | ModelID) => EvaluationModel<EvaluationOptions>;
22
89
  };
@@ -24,11 +91,19 @@ export declare const configure: (input?: Options) => {
24
91
  };
25
92
  export declare const provider: {
26
93
  id: string & import("effect/Brand").Brand<"AI.ProviderID">;
94
+ model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
95
+ messages: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
96
+ responses: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
97
+ chat: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
27
98
  experimental: {
28
99
  evaluation: (modelID: string | ModelID) => EvaluationModel<EvaluationOptions>;
29
100
  };
30
101
  configure: (input?: Options) => {
31
102
  id: string & import("effect/Brand").Brand<"AI.ProviderID">;
103
+ model: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
104
+ messages: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
105
+ responses: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
106
+ chat: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
32
107
  experimental: {
33
108
  evaluation: (modelID: string | ModelID) => EvaluationModel<EvaluationOptions>;
34
109
  };
@@ -38,4 +113,11 @@ export declare const provider: {
38
113
  export declare const experimental: {
39
114
  evaluation: (modelID: string | ModelID) => EvaluationModel<EvaluationOptions>;
40
115
  };
116
+ export declare const messages: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
117
+ export declare const responses: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
118
+ export declare const chat: (modelID: string | ModelID) => import("../schema/options.js").LanguageModel<ProviderOptionsInput, import("../route/client.js").CompactionOperations | undefined>;
119
+ export declare const model: ProviderPackage.Definition<Settings, ProviderOptionsInput>["model"];
120
+ export declare const messagesModel: ProviderPackage.Definition<Settings, ProviderOptionsInput>["model"];
121
+ export declare const responsesModel: ProviderPackage.Definition<Settings, ProviderOptionsInput>["model"];
122
+ export declare const chatModel: ProviderPackage.Definition<Settings, ProviderOptionsInput>["model"];
41
123
  export * as VercelAIGateway from "./vercel-ai-gateway.js";
@@ -1,11 +1,111 @@
1
1
  import { Effect, Schema } from "effect";
2
2
  import { Headers, HttpClientRequest } from "effect/unstable/http";
3
3
  import { EvaluationAnswer, EvaluationInput, EvaluationModel, EvaluationQuestion, EvaluationResponse, EvaluationRounding, } from "../experimental/evaluation.js";
4
+ import { AnthropicMessages } from "../protocols/anthropic-messages.js";
5
+ import { OpenAIChat } from "../protocols/openai-chat.js";
6
+ import { OpenResponses } from "../protocols/open-responses.js";
7
+ import { optionalNull, ProviderShared } from "../protocols/shared.js";
8
+ import { gatewayProtocol } from "../protocols/utils/gateway-protocol.js";
4
9
  import { Auth } from "../route/auth.js";
5
10
  import { AuthOptions } from "../route/auth-options.js";
6
- import { AIError, HttpContext, HttpOptions, InvalidProviderOutputError, InvalidRequestError, ModelID, ProviderID, ProviderMetadata, Usage, } from "../schema/index.js";
11
+ import { Route } from "../route/client.js";
12
+ import { Endpoint } from "../route/endpoint.js";
13
+ import { Framing } from "../route/framing.js";
14
+ import { AIError, HttpContext, HttpOptions, InvalidProviderOutputError, InvalidRequestError, LLMRequest, ModelID, ProviderID, ProviderMetadata, ReasoningEffort, Usage, } from "../schema/index.js";
7
15
  export const id = ProviderID.make("vercel-ai-gateway");
8
16
  const baseURL = "https://ai-gateway.vercel.sh/v1";
17
+ const GatewayOptionsSchema = Schema.Struct({
18
+ gateway: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
19
+ upstream: Schema.optional(Schema.Record(Schema.String, Schema.Record(Schema.String, Schema.Unknown))),
20
+ reasoningEffort: Schema.optional(ReasoningEffort),
21
+ thinking: Schema.optional(Schema.Struct({
22
+ type: Schema.String,
23
+ budgetTokens: Schema.optional(Schema.Number),
24
+ budget_tokens: Schema.optional(Schema.Number),
25
+ })),
26
+ cacheTTL: Schema.optional(Schema.String),
27
+ cacheAnchorItems: Schema.optional(Schema.Number),
28
+ });
29
+ const decodeOptions = ProviderShared.validateWith(Schema.decodeUnknownEffect(GatewayOptionsSchema));
30
+ const prepare = (api) => Effect.fnUntraced(function* (request) {
31
+ const options = yield* decodeOptions(request.providerOptions ?? {});
32
+ const providerOptions = (() => {
33
+ if (!options.upstream && !options.gateway)
34
+ return undefined;
35
+ if (!options.gateway)
36
+ return options.upstream;
37
+ return { ...options.upstream, gateway: options.gateway };
38
+ })();
39
+ switch (api) {
40
+ case "messages": {
41
+ const effort = options.reasoningEffort;
42
+ if (effort === undefined)
43
+ return { request, body: { providerOptions } };
44
+ const enabled = effort !== "none";
45
+ const thinking = request.providerOptions?.thinking ?? { type: enabled ? "adaptive" : "disabled" };
46
+ const next = LLMRequest.update(request, {
47
+ providerOptions: {
48
+ ...request.providerOptions,
49
+ effort: enabled ? effort : undefined,
50
+ thinking,
51
+ },
52
+ });
53
+ return { request: next, body: { providerOptions } };
54
+ }
55
+ case "responses":
56
+ return {
57
+ request,
58
+ body: {
59
+ providerOptions,
60
+ cache_ttl: options.cacheTTL,
61
+ cache_anchor_items: options.cacheAnchorItems,
62
+ },
63
+ };
64
+ case "chat": {
65
+ if (!options.thinking)
66
+ return { request, body: { providerOptions } };
67
+ const reasoning = {
68
+ enabled: options.thinking.type !== "disabled",
69
+ max_tokens: options.thinking.budgetTokens ?? options.thinking.budget_tokens,
70
+ };
71
+ return { request, body: { providerOptions, reasoning } };
72
+ }
73
+ }
74
+ });
75
+ const route = (input) => Route.make({
76
+ id: input.id,
77
+ provider: id,
78
+ providerMetadataKey: id,
79
+ protocol: gatewayProtocol(input.protocol, { id: input.id, prepare: prepare(input.api) }),
80
+ endpoint: Endpoint.path(input.path, { baseURL }),
81
+ framing: input.framing,
82
+ headers: ({ request }) => request.promptCacheKey ? { "x-session-affinity": request.promptCacheKey } : {},
83
+ defaults: input.defaults,
84
+ });
85
+ const messagesRoute = route({
86
+ id: "vercel-ai-gateway-messages",
87
+ protocol: AnthropicMessages.protocol,
88
+ api: "messages",
89
+ path: "/messages",
90
+ framing: AnthropicMessages.framing,
91
+ defaults: { headers: { "anthropic-version": "2023-06-01" } },
92
+ });
93
+ const responsesRoute = route({
94
+ id: "vercel-ai-gateway-responses",
95
+ protocol: OpenResponses.protocol,
96
+ api: "responses",
97
+ path: "/responses",
98
+ framing: Framing.sse,
99
+ defaults: { providerOptions: { store: false, include: ["reasoning.encrypted_content"] } },
100
+ });
101
+ const chatRoute = route({
102
+ id: "vercel-ai-gateway-chat",
103
+ protocol: OpenAIChat.protocol,
104
+ api: "chat",
105
+ path: "/chat/completions",
106
+ framing: OpenAIChat.framing,
107
+ });
108
+ export const routes = [messagesRoute, responsesRoute, chatRoute];
9
109
  const Request = Schema.StructWithRest(Schema.Struct({
10
110
  model: Schema.String,
11
111
  state: EvaluationInput,
@@ -13,16 +113,39 @@ const Request = Schema.StructWithRest(Schema.Struct({
13
113
  providerOptions: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
14
114
  }), [Schema.Record(Schema.String, Schema.Any)]);
15
115
  const Response = Schema.Struct({
16
- model: Schema.optional(Schema.String),
116
+ model: optionalNull(Schema.String),
17
117
  answers: Schema.Record(Schema.String, EvaluationAnswer),
18
- usage: Schema.optional(Schema.Struct({
19
- inputTokens: Schema.optional(Schema.Number),
20
- outputTokens: Schema.optional(Schema.Number),
118
+ usage: optionalNull(Schema.Struct({
119
+ inputTokens: optionalNull(Schema.Number),
120
+ outputTokens: optionalNull(Schema.Number),
21
121
  })),
22
- rounding: Schema.optional(EvaluationRounding),
23
- providerMetadata: Schema.optional(ProviderMetadata),
122
+ rounding: optionalNull(EvaluationRounding),
123
+ providerMetadata: optionalNull(ProviderMetadata),
24
124
  });
25
125
  export const configure = (input = {}) => {
126
+ const { apiKey: _apiKey, auth: _auth, baseURL: endpoint, ...defaults } = input;
127
+ const configured = {
128
+ ...defaults,
129
+ endpoint: { baseURL: endpoint ?? baseURL },
130
+ auth: AuthOptions.bearer(input, ["AI_GATEWAY_API_KEY", "VERCEL_OIDC_TOKEN"]),
131
+ };
132
+ const messages = (modelID) => messagesRoute.with(configured).model({
133
+ id: modelID,
134
+ // Recorded Gateway translations for non-Claude models return thinking with empty signatures.
135
+ compatibility: { requireSignature: modelID.startsWith("anthropic/") },
136
+ });
137
+ const responses = (modelID) => responsesRoute.with(configured).model({ id: modelID });
138
+ const chat = (modelID) => chatRoute
139
+ .with(configured)
140
+ .model({ id: modelID, compatibility: { reasoningField: "reasoning" } });
141
+ // Each family uses the API whose Gateway translation carries its reasoning state across turns.
142
+ const model = (modelID) => {
143
+ if (/^(openai\/gpt-|spacexai\/grok-)/.test(modelID))
144
+ return responses(modelID);
145
+ if (modelID.startsWith("meta/muse-"))
146
+ return chat(modelID);
147
+ return messages(modelID);
148
+ };
26
149
  const evaluation = (modelID) => EvaluationModel.make({
27
150
  id: modelID,
28
151
  provider: id,
@@ -39,7 +162,7 @@ export const configure = (input = {}) => {
39
162
  questions: req.questions,
40
163
  providerOptions: req.options,
41
164
  }).pipe(Effect.mapError((cause) => new AIError({ reason: new InvalidRequestError({ message: cause.message, cause }) })));
42
- const headers = yield* Auth.toEffect(AuthOptions.bearer(input, ["AI_GATEWAY_API_KEY", "VERCEL_OIDC_TOKEN"]))({
165
+ const headers = yield* Auth.toEffect(configured.auth)({
43
166
  request: req,
44
167
  method: "POST",
45
168
  url: url.toString(),
@@ -59,27 +182,44 @@ export const configure = (input = {}) => {
59
182
  });
60
183
  const text = yield* res.text.pipe(Effect.mapError((cause) => fail("Failed to read the Vercel AI Gateway evaluation response", cause)));
61
184
  const data = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Response))(text).pipe(Effect.mapError((cause) => fail("Vercel AI Gateway returned an invalid evaluation response", cause, text)));
185
+ const inputTokens = data.usage?.inputTokens ?? undefined;
186
+ const outputTokens = data.usage?.outputTokens ?? undefined;
187
+ const usage = data.usage
188
+ ? new Usage({
189
+ inputTokens,
190
+ outputTokens,
191
+ totalTokens: ProviderShared.totalTokens(inputTokens, outputTokens, undefined),
192
+ providerMetadata: { gateway: data.usage },
193
+ })
194
+ : undefined;
62
195
  return new EvaluationResponse({
63
196
  model: ModelID.make(data.model ?? req.model.id),
64
197
  answers: data.answers,
65
- usage: data.usage
66
- ? new Usage({
67
- inputTokens: data.usage.inputTokens,
68
- outputTokens: data.usage.outputTokens,
69
- totalTokens: data.usage.inputTokens === undefined && data.usage.outputTokens === undefined
70
- ? undefined
71
- : (data.usage.inputTokens ?? 0) + (data.usage.outputTokens ?? 0),
72
- providerMetadata: { gateway: data.usage },
73
- })
74
- : undefined,
75
- rounding: data.rounding,
76
- providerMetadata: data.providerMetadata,
198
+ usage,
199
+ rounding: data.rounding ?? undefined,
200
+ providerMetadata: data.providerMetadata ?? undefined,
77
201
  });
78
202
  }),
79
203
  },
80
204
  });
81
- return { id, experimental: { evaluation }, configure };
205
+ return { id, model, messages, responses, chat, experimental: { evaluation }, configure };
82
206
  };
83
207
  export const provider = configure();
84
208
  export const experimental = provider.experimental;
209
+ export const messages = provider.messages;
210
+ export const responses = provider.responses;
211
+ export const chat = provider.chat;
212
+ export const model = (modelID, settings) => fromSettings(settings).model(modelID);
213
+ export const messagesModel = (modelID, settings) => fromSettings(settings).messages(modelID);
214
+ export const responsesModel = (modelID, settings) => fromSettings(settings).responses(modelID);
215
+ export const chatModel = (modelID, settings) => fromSettings(settings).chat(modelID);
216
+ function fromSettings({ apiKey, baseURL, headers, body, ...providerOptions }) {
217
+ return configure({
218
+ apiKey,
219
+ baseURL,
220
+ headers,
221
+ http: body === undefined ? undefined : { body: { ...body } },
222
+ providerOptions,
223
+ });
224
+ }
85
225
  export * as VercelAIGateway from "./vercel-ai-gateway.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "2.0.23",
3
+ "version": "2.0.25",
4
4
  "name": "@opencode/ai",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "devDependencies": {
35
35
  "@clack/prompts": "1.0.0-alpha.1",
36
36
  "@effect/platform-node": "4.0.0-rc.112",
37
- "@opencode/http-recorder": "2.0.23",
37
+ "@opencode/http-recorder": "2.0.25",
38
38
  "@tsconfig/bun": "1.0.9",
39
39
  "@types/bun": "1.4.0",
40
40
  "@typescript/native-preview": "7.0.0-dev.20251207.1",
@@ -44,7 +44,7 @@
44
44
  "@aws-sdk/credential-providers": "3.1057.0",
45
45
  "@smithy/eventstream-codec": "4.2.14",
46
46
  "@smithy/util-utf8": "4.2.2",
47
- "@opencode/schema": "2.0.23",
47
+ "@opencode/schema": "2.0.25",
48
48
  "aws4fetch": "1.0.20",
49
49
  "effect": "4.0.0-rc.112",
50
50
  "google-auth-library": "10.5.0"