@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
@@ -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
  }).messages(modelID);
@@ -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
  }).responses(modelID);
@@ -85,7 +85,7 @@ export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOpti
85
85
  apiKey,
86
86
  baseURL,
87
87
  headers,
88
- http: body === undefined ? undefined : { body: { ...body } },
88
+ http: body === undefined ? undefined : { body },
89
89
  providerOptions,
90
90
  }).model(modelID);
91
91
  export * as Moonshot from "./moonshot.js";
@@ -25,8 +25,8 @@ export const provider = {
25
25
  export const model = (modelID, { apiKey, baseURL, body, headers, provider, ...providerOptions }) => configure({
26
26
  apiKey,
27
27
  baseURL,
28
- headers: headers === undefined ? undefined : { ...headers },
29
- http: body === undefined ? undefined : { body: { ...body } },
28
+ headers,
29
+ http: body === undefined ? undefined : { body },
30
30
  provider,
31
31
  providerOptions,
32
32
  }).model(modelID);
@@ -25,8 +25,8 @@ export const provider = {
25
25
  export const model = (modelID, { apiKey, baseURL, body, headers, provider, ...providerOptions }) => configure({
26
26
  apiKey,
27
27
  baseURL,
28
- headers: headers === undefined ? undefined : { ...headers },
29
- http: body === undefined ? undefined : { body: { ...body } },
28
+ headers,
29
+ http: body === undefined ? undefined : { body },
30
30
  provider,
31
31
  providerOptions,
32
32
  }).model(modelID);
@@ -275,7 +275,7 @@ export declare const routes: (Route<{
275
275
  } | {
276
276
  readonly type: "image_generation";
277
277
  readonly size?: string | undefined;
278
- readonly action?: "generate" | "auto" | "edit" | undefined;
278
+ readonly action?: "auto" | "generate" | "edit" | undefined;
279
279
  readonly output_format?: "png" | "jpeg" | "webp" | undefined;
280
280
  readonly quality?: "auto" | "low" | "medium" | "high" | undefined;
281
281
  readonly background?: "auto" | "opaque" | "transparent" | undefined;
@@ -77,9 +77,9 @@ const config = ({ apiKey, baseURL, body, headers: given, organization, project,
77
77
  apiKey,
78
78
  baseURL,
79
79
  headers: Object.keys(headers).length === 0 ? undefined : headers,
80
- http: body === undefined ? undefined : { body: { ...body } },
80
+ http: body === undefined ? undefined : { body },
81
81
  providerOptions,
82
- queryParams: queryParams === undefined ? undefined : { ...queryParams },
82
+ queryParams,
83
83
  };
84
84
  };
85
85
  export const model = (modelID, settings) => {
@@ -29,4 +29,4 @@ export declare const provider: {
29
29
  export declare const experimental: {
30
30
  evaluation: (modelID: string | ModelID) => import("../experimental.js").EvaluationModel<import("../experimental.js").EvaluationOptions>;
31
31
  };
32
- export * as OpenCodeZen from "./opencode-zen.js";
32
+ export * as OpenCode from "./opencode.js";
@@ -2,7 +2,7 @@ import { HttpOptions, ProviderID } from "../schema/index.js";
2
2
  import { AuthOptions } from "../route/auth-options.js";
3
3
  import { SystemOne } from "../experimental/system-one.js";
4
4
  export const id = ProviderID.make("opencode");
5
- const baseURL = "https://opencode.ai/zen/v1";
5
+ const baseURL = "https://opencode.ai/inference/v1";
6
6
  export const configure = (input = {}) => {
7
7
  const evaluation = (modelID) => SystemOne.model({
8
8
  id: modelID,
@@ -17,4 +17,4 @@ export const configure = (input = {}) => {
17
17
  };
18
18
  export const provider = configure();
19
19
  export const experimental = provider.experimental;
20
- export * as OpenCodeZen from "./opencode-zen.js";
20
+ export * as OpenCode from "./opencode.js";
@@ -114,6 +114,6 @@ export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOpti
114
114
  apiKey,
115
115
  baseURL,
116
116
  headers,
117
- http: body === undefined ? undefined : { body: { ...body } },
117
+ http: body === undefined ? undefined : { body },
118
118
  providerOptions,
119
119
  }).model(modelID);
@@ -34,7 +34,7 @@ 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);
@@ -32,7 +32,7 @@ export const model = (modelID, { apiKey, baseURL, queryParams, body, headers, ..
32
32
  baseURL,
33
33
  queryParams,
34
34
  headers,
35
- http: body === undefined ? undefined : { body: { ...body } },
35
+ http: body === undefined ? undefined : { body },
36
36
  providerOptions,
37
37
  }).model(modelID);
38
38
  export * as Venice from "./venice.js";
@@ -1,5 +1,5 @@
1
1
  import { Effect, Schema } from "effect";
2
- import { Headers, HttpClientRequest } from "effect/unstable/http";
2
+ import { Headers, HttpClientRequest } from "effect/http";
3
3
  import { EvaluationAnswer, EvaluationInput, EvaluationModel, EvaluationQuestion, EvaluationResponse, EvaluationRounding, } from "../experimental/evaluation.js";
4
4
  import { AnthropicMessages } from "../protocols/anthropic-messages.js";
5
5
  import { OpenAIChat } from "../protocols/openai-chat.js";
@@ -218,7 +218,7 @@ function fromSettings({ apiKey, baseURL, headers, body, ...providerOptions }) {
218
218
  apiKey,
219
219
  baseURL,
220
220
  headers,
221
- http: body === undefined ? undefined : { body: { ...body } },
221
+ http: body === undefined ? undefined : { body },
222
222
  providerOptions,
223
223
  });
224
224
  }
@@ -77,7 +77,7 @@ export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOpti
77
77
  apiKey,
78
78
  baseURL,
79
79
  headers,
80
- http: body === undefined ? undefined : { body: { ...body } },
80
+ http: body === undefined ? undefined : { body },
81
81
  providerOptions,
82
82
  }).model(modelID);
83
83
  export const responses = provider.responses;
@@ -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
  }).messages(modelID);
@@ -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
  }).responses(modelID);
@@ -57,7 +57,7 @@ export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOpti
57
57
  apiKey,
58
58
  baseURL,
59
59
  headers,
60
- http: body === undefined ? undefined : { body: { ...body } },
60
+ http: body === undefined ? undefined : { body },
61
61
  providerOptions,
62
62
  }).model(modelID);
63
63
  export * as ZAICodingPlan from "./zai-coding-plan.js";
@@ -43,7 +43,7 @@ export const model = (modelID, { apiKey, baseURL, body, headers, ...providerOpti
43
43
  apiKey,
44
44
  baseURL,
45
45
  headers,
46
- http: body === undefined ? undefined : { body: { ...body } },
46
+ http: body === undefined ? undefined : { body },
47
47
  providerOptions,
48
48
  }).model(modelID);
49
49
  export * as ZAI from "./zai.js";
@@ -1,5 +1,5 @@
1
1
  import { Config, Effect, Redacted } from "effect";
2
- import { Headers } from "effect/unstable/http";
2
+ import { Headers } from "effect/http";
3
3
  import { AIError, type HttpOptions } from "../schema/index.js";
4
4
  export declare class MissingCredentialError extends Error {
5
5
  readonly source: string;
@@ -1,5 +1,5 @@
1
1
  import { Config, Effect, Option, Redacted } from "effect";
2
- import { Headers } from "effect/unstable/http";
2
+ import { Headers } from "effect/http";
3
3
  import { AuthenticationError, AIError } from "../schema/index.js";
4
4
  export class MissingCredentialError extends Error {
5
5
  source;
@@ -48,7 +48,7 @@ export const optional = (secret, source = "optional value") => secret === undefi
48
48
  ? credential(Effect.fail(new MissingCredentialError(source)))
49
49
  : credentialFromSecret(secret, source);
50
50
  export const config = (name) => credential(Effect.gen(function* () {
51
- const secret = yield* Config.option(Config.redacted(name));
51
+ const secret = yield* Config.option(Config.Redacted(name));
52
52
  if (Option.isSome(secret) && Redacted.value(secret.value) !== "")
53
53
  return secret.value;
54
54
  return yield* Effect.fail(new MissingCredentialError(name, `${name} is not set`));
@@ -1,5 +1,5 @@
1
1
  import { Context, type Effect } from "effect";
2
- import type { HttpClientRequest, HttpClientResponse } from "effect/unstable/http";
2
+ import type { HttpClientRequest, HttpClientResponse } from "effect/http";
3
3
  import type { AIError } from "../schema/errors.js";
4
4
  export interface Interface {
5
5
  readonly execute: (request: HttpClientRequest.HttpClientRequest, middleware?: HttpMiddleware) => Effect.Effect<HttpClientResponse.HttpClientResponse, AIError>;
@@ -1,5 +1,5 @@
1
1
  import { Layer, Stream } from "effect";
2
- import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http";
2
+ import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http";
3
3
  import { HttpContext, AIError } from "../schema/index.js";
4
4
  import { Service, type HttpMiddleware, type Interface } from "./executor-service.js";
5
5
  export { Service } from "./executor-service.js";
@@ -1,5 +1,5 @@
1
1
  import { Cause, Effect, Layer, Option, Schema, Stream } from "effect";
2
- import { FetchHttpClient, Headers, HttpClient, HttpClientError, HttpClientRequest, HttpClientResponse, } from "effect/unstable/http";
2
+ import { FetchHttpClient, Headers, HttpClient, HttpClientError, HttpClientRequest, HttpClientResponse, } from "effect/http";
3
3
  import { HttpContext, HttpRateLimitDetails, AIError, TransportError } from "../schema/index.js";
4
4
  import { classifyProviderFailure, providerErrorMessage } from "../provider-error.js";
5
5
  import { Service } from "./executor-service.js";
@@ -1,5 +1,5 @@
1
1
  import { Effect, Stream } from "effect";
2
- import { makeParser } from "effect/unstable/encoding/Sse";
2
+ import { makeParser } from "effect/encoding/Sse";
3
3
  import { AIError, InvalidProviderOutputError } from "../schema/index.js";
4
4
  /**
5
5
  * `framing` step for Server-Sent Events. Decodes UTF-8, runs the SSE channel
@@ -1,5 +1,5 @@
1
1
  import { Duration, Effect, Schema, type Stream } from "effect";
2
- import { HttpClientResponse } from "effect/unstable/http";
2
+ import { HttpClientResponse } from "effect/http";
3
3
  import type { Snapshot, Status } from "../generation.js";
4
4
  import { Media } from "../media.js";
5
5
  import type { AuthInput } from "./auth.js";
@@ -1,5 +1,5 @@
1
1
  import { Clock, Duration, Effect, Schema } from "effect";
2
- import { HttpClientResponse } from "effect/unstable/http";
2
+ import { HttpClientResponse } from "effect/http";
3
3
  import { Media } from "../media.js";
4
4
  import { AIError, AuthenticationError, ContentPolicyError, HttpContext, InvalidProviderOutputError, InvalidRequestError, ProviderID, ProviderInternalError, RateLimitError, UnsupportedOperationError, } from "../schema/index.js";
5
5
  export const json = (value, query) => ({
@@ -1,5 +1,5 @@
1
1
  import { Duration, Effect, Schedule, Schema, Stream } from "effect";
2
- import { Headers, HttpClientRequest } from "effect/unstable/http";
2
+ import { Headers, HttpClientRequest } from "effect/http";
3
3
  import { Auth } from "./auth.js";
4
4
  import { Endpoint } from "./endpoint.js";
5
5
  import { RequestExecutorService } from "./executor-service.js";
@@ -1,5 +1,5 @@
1
1
  import { Effect } from "effect";
2
- import { Headers, HttpClientRequest } from "effect/unstable/http";
2
+ import { Headers, HttpClientRequest } from "effect/http";
3
3
  import { Framing } from "../framing.js";
4
4
  import type { HttpMiddleware, Transport, TransportPrepareInput } from "./index.js";
5
5
  import { AIError } from "../../schema/index.js";
@@ -1,10 +1,10 @@
1
1
  import { Clock, Duration, Effect, Stream } from "effect";
2
- import { Headers, HttpClientRequest } from "effect/unstable/http";
2
+ import { Headers, HttpClientRequest } from "effect/http";
3
3
  import { Auth } from "../auth.js";
4
4
  import { render as renderEndpoint } from "../endpoint.js";
5
5
  import { Framing } from "../framing.js";
6
6
  import * as ProviderShared from "../../protocols/shared.js";
7
- import { AIError, DEFAULT_HTTP_TIMEOUT_MS, mergeJsonRecords, TransportError, } from "../../schema/index.js";
7
+ import { AIError, DEFAULT_CHUNK_TIMEOUT_MS, DEFAULT_HTTP_TIMEOUT_MS, mergeJsonRecords, TransportError, } from "../../schema/index.js";
8
8
  import { RequestExecutor } from "../executor.js";
9
9
  const applyQuery = (url, query) => {
10
10
  if (!query)
@@ -46,6 +46,7 @@ export const httpJson = (input) => ({
46
46
  url: parts.url,
47
47
  body: parts.bodyText,
48
48
  headers: parts.headers,
49
+ encoding: prepareInput.request.http?.encoding,
49
50
  });
50
51
  return {
51
52
  request,
@@ -75,7 +76,7 @@ export const httpJson = (input) => ({
75
76
  const remaining = Duration.subtract(total, Duration.millis((yield* Clock.currentTimeMillis) - started));
76
77
  return {
77
78
  frames: prepared.framing.frame(RequestExecutor.responseStream(response).pipe(Stream.timeoutOrElse({
78
- duration: timeoutDuration(request.http?.chunkTimeout),
79
+ duration: timeoutDuration(request.http?.chunkTimeout, DEFAULT_CHUNK_TIMEOUT_MS),
79
80
  orElse: () => Stream.fail(timeout("read", "Timed out waiting for response data", http)),
80
81
  }), Stream.interruptWhen(Effect.sleep(remaining).pipe(Effect.andThen(Effect.fail(timeout("read", "Timed out waiting for the response to complete", http))))))),
81
82
  http,
@@ -83,7 +84,7 @@ export const httpJson = (input) => ({
83
84
  };
84
85
  }),
85
86
  });
86
- const timeoutDuration = (value) => value === false ? Duration.infinity : Duration.millis(value ?? DEFAULT_HTTP_TIMEOUT_MS);
87
+ const timeoutDuration = (value, fallback = DEFAULT_HTTP_TIMEOUT_MS) => value === false ? Duration.infinity : Duration.millis(value ?? fallback);
87
88
  export const sseJson = {
88
89
  id: "http-json/sse",
89
90
  with: () => httpJson({ framing: Framing.sse }),
@@ -1,5 +1,5 @@
1
1
  import type { Effect, Scope, Stream } from "effect";
2
- import type { Headers } from "effect/unstable/http";
2
+ import type { Headers } from "effect/http";
3
3
  import type { AIError, HttpContext } from "../../schema/index.js";
4
4
  export interface WebSocketChannelExecutor {
5
5
  readonly execute: (exchange: WebSocketChannelExchange) => Effect.Effect<WebSocketChannelExecution, AIError, Scope.Scope>;
@@ -1,6 +1,6 @@
1
1
  import { Effect, Stream } from "effect";
2
- import { Headers } from "effect/unstable/http";
3
- import { Socket } from "effect/unstable/socket";
2
+ import { Headers } from "effect/http";
3
+ import { Socket } from "effect/socket";
4
4
  import { AIError, type HttpContext } from "../../schema/index.js";
5
5
  import type { Transport } from "./index.js";
6
6
  import type { WebSocketChannelExecutor } from "./websocket-channel.js";
@@ -19,7 +19,7 @@ export interface WebSocketConnector {
19
19
  }
20
20
  export declare const toWebSocketUrl: (value: string) => Effect.Effect<string, AIError, never>;
21
21
  export declare const open: (input: WebSocketRequest) => Effect.Effect<WebSocketConnection, AIError, Socket.WebSocketConstructor>;
22
- export declare const fromWebSocket: (ws: globalThis.WebSocket, input: WebSocketRequest) => Effect.Effect<WebSocketConnection, AIError>;
22
+ export declare const fromWebSocket: (ws: Socket.WebSocketLike, input: WebSocketRequest) => Effect.Effect<WebSocketConnection, AIError>;
23
23
  export declare const messageText: (message: string | Uint8Array, decoder: TextDecoder) => string;
24
24
  export declare const makeDirect: (connector: WebSocketConnector) => WebSocketChannelExecutor;
25
25
  export declare const direct: Effect.Effect<WebSocketChannelExecutor, never, Socket.WebSocketConstructor>;
@@ -50,7 +50,7 @@ export declare const WebSocketTransport: {
50
50
  readonly direct: Effect.Effect<WebSocketChannelExecutor, never, Socket.WebSocketConstructor>;
51
51
  readonly makeDirect: (connector: WebSocketConnector) => WebSocketChannelExecutor;
52
52
  readonly open: (input: WebSocketRequest) => Effect.Effect<WebSocketConnection, AIError, Socket.WebSocketConstructor>;
53
- readonly fromWebSocket: (ws: globalThis.WebSocket, input: WebSocketRequest) => Effect.Effect<WebSocketConnection, AIError>;
53
+ readonly fromWebSocket: (ws: Socket.WebSocketLike, input: WebSocketRequest) => Effect.Effect<WebSocketConnection, AIError>;
54
54
  readonly messageText: (message: string | Uint8Array, decoder: TextDecoder) => string;
55
55
  readonly toWebSocketUrl: (value: string) => Effect.Effect<string, AIError, never>;
56
56
  };
@@ -1,6 +1,6 @@
1
1
  import { Cause, Effect, Queue, Stream } from "effect";
2
- import { Headers } from "effect/unstable/http";
3
- import { Socket } from "effect/unstable/socket";
2
+ import { Headers } from "effect/http";
3
+ import { Socket } from "effect/socket";
4
4
  import { AIError, AIErrorReason, TransportError, } from "../../schema/index.js";
5
5
  import * as HttpTransport from "./http.js";
6
6
  const MAX_FRAME_BYTES = 16 * 1024 * 1024;
@@ -31,7 +31,7 @@ const annotateTransportError = (error, input) => error.reason._tag === "Transpor
31
31
  const eventMessage = (event) => {
32
32
  if ("message" in event && typeof event.message === "string")
33
33
  return event.message;
34
- return event.type;
34
+ return event.type ?? "error";
35
35
  };
36
36
  const binaryMessage = (data) => {
37
37
  if (data instanceof Uint8Array)
@@ -127,12 +127,7 @@ export const toWebSocketUrl = (value) => Effect.try({
127
127
  export const open = (input) => Effect.gen(function* () {
128
128
  const constructor = yield* Socket.WebSocketConstructor;
129
129
  const ws = yield* Effect.try({
130
- try: () =>
131
- // Platform implementations may extend Effect's browser-compatible constructor with handshake options.
132
- // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion
133
- constructor(input.url, {
134
- headers: input.headers,
135
- }),
130
+ try: () => constructor(input.url, { headers: input.headers }),
136
131
  catch: (error) => transportError(error instanceof Error ? error.message : "Failed to construct WebSocket", {
137
132
  cause: error,
138
133
  url: input.url,
@@ -1,4 +1,5 @@
1
1
  import { Schema } from "effect";
2
+ import { withStatics } from "@opencode/schema/schema";
2
3
  import { Tool } from "@opencode/schema/tool";
3
4
  import { CacheHint, CachePolicy, GenerationOptions, HttpOptions, JsonSchema, LanguageModelSchema, ProviderMetadata, ProviderOptions, ReasoningEffort, } from "./options.js";
4
5
  import { ProviderID } from "./ids.js";
@@ -11,7 +12,7 @@ const systemPartSchema = Schema.Struct({
11
12
  metadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
12
13
  }).annotate({ identifier: "LLM.SystemPart" });
13
14
  const makeSystemPart = (text) => ({ type: "text", text });
14
- export const SystemPart = Object.assign(systemPartSchema, {
15
+ export const SystemPart = withStatics(systemPartSchema, {
15
16
  make: makeSystemPart,
16
17
  content: (input) => {
17
18
  if (input === undefined)
@@ -53,7 +54,7 @@ const toolResultValueSchema = Schema.Union([
53
54
  }),
54
55
  ]).annotate({ identifier: "LLM.ToolResult" });
55
56
  const isToolResultValue = Schema.is(toolResultValueSchema);
56
- export const ToolResultValue = Object.assign(toolResultValueSchema, {
57
+ export const ToolResultValue = withStatics(toolResultValueSchema, {
57
58
  is: isToolResultValue,
58
59
  make: (value, type = "json") => {
59
60
  if (isToolResultValue(value))
@@ -63,7 +64,7 @@ export const ToolResultValue = Object.assign(toolResultValueSchema, {
63
64
  return { type, value };
64
65
  },
65
66
  });
66
- export const ToolOutput = Object.assign(Schema.Struct({
67
+ export const ToolOutput = withStatics(Schema.Struct({
67
68
  structured: Schema.Unknown,
68
69
  content: Schema.Array(Tool.Content),
69
70
  }).annotate({ identifier: "LLM.ToolOutput" }), {
@@ -98,7 +99,7 @@ const toolResultText = (value) => {
98
99
  return String(value);
99
100
  }
100
101
  };
101
- export const ToolCallPart = Object.assign(Schema.Struct({
102
+ export const ToolCallPart = withStatics(Schema.Struct({
102
103
  type: Schema.Literal("tool-call"),
103
104
  id: Schema.String,
104
105
  name: Schema.String,
@@ -111,7 +112,7 @@ export const ToolCallPart = Object.assign(Schema.Struct({
111
112
  }).annotate({ identifier: "LLM.Content.ToolCall" }), {
112
113
  make: (input) => ({ type: "tool-call", ...input }),
113
114
  });
114
- export const ToolResultPart = Object.assign(Schema.Struct({
115
+ export const ToolResultPart = withStatics(Schema.Struct({
115
116
  type: Schema.Literal("tool-result"),
116
117
  id: Schema.String,
117
118
  name: Schema.String,
@@ -152,7 +153,7 @@ const compactionPartSchema = Schema.Struct({
152
153
  })
153
154
  .pipe(Schema.refine((part) => (part.encrypted !== undefined) !== (part.text !== undefined), { message: "Compaction requires either encrypted content or a summary" }))
154
155
  .annotate({ identifier: "LLM.Content.Compaction" });
155
- export const CompactionPart = Object.assign(compactionPartSchema, {
156
+ export const CompactionPart = withStatics(compactionPartSchema, {
156
157
  make: (input) => Schema.decodeUnknownSync(compactionPartSchema)({ type: "compaction", ...input }),
157
158
  });
158
159
  /** Reasoning effort changed here, from `previous` to `effort`; `undefined` is the model default. */
@@ -225,7 +226,7 @@ export class ToolDefinition extends Schema.Class("LLM.ToolDefinition")({
225
226
  /** Normalize tool definition input into the canonical `ToolDefinition` class. */
226
227
  ToolDefinition.make = (input) => (input instanceof ToolDefinition ? input : new ToolDefinition(input));
227
228
  })(ToolDefinition || (ToolDefinition = {}));
228
- export const ToolNamespace = Object.assign(Schema.Struct({
229
+ export const ToolNamespace = withStatics(Schema.Struct({
229
230
  type: Schema.Literal("namespace"),
230
231
  name: Schema.String,
231
232
  description: Schema.optional(Schema.UndefinedOr(Schema.String)),
@@ -237,7 +238,7 @@ export const ToolNamespace = Object.assign(Schema.Struct({
237
238
  tools: input.tools.map(ToolEntry.make),
238
239
  }),
239
240
  });
240
- export const ToolEntry = Object.assign(Schema.Union([ToolDefinition, ToolNamespace]).pipe(Schema.toTaggedUnion("type"), Schema.annotate({ identifier: "LLM.ToolEntry" })), {
241
+ export const ToolEntry = withStatics(Schema.Union([ToolDefinition, ToolNamespace]).pipe(Schema.toTaggedUnion("type"), Schema.annotate({ identifier: "LLM.ToolEntry" })), {
241
242
  make: (input) => "type" in input && input.type === "namespace" ? ToolNamespace.make(input) : ToolDefinition.make(input),
242
243
  });
243
244
  export class ToolChoice extends Schema.Class("LLM.ToolChoice")({
@@ -12,8 +12,16 @@ export declare const mergeProviderOptions: (...items: ReadonlyArray<ProviderOpti
12
12
  /** Milliseconds for an HTTP timeout, or `false` to disable it. */
13
13
  export declare const HttpTimeout: Schema.Union<readonly [Schema.Number, Schema.Literal<false>]>;
14
14
  export type HttpTimeout = Schema.Schema.Type<typeof HttpTimeout>;
15
- /** Applied to `headerTimeout` and `chunkTimeout` when a request leaves them unset. */
15
+ /** Applied to `headerTimeout` when a request leaves it unset. */
16
16
  export declare const DEFAULT_HTTP_TIMEOUT_MS = 300000;
17
+ /**
18
+ * Applied to `chunkTimeout` when a request leaves it unset. Some providers, such as DeepSeek, have specifically asked
19
+ * clients to allow at least 15 minutes, because their models can stream nothing for minutes while they reason.
20
+ */
21
+ export declare const DEFAULT_CHUNK_TIMEOUT_MS = 900000;
22
+ /** `Content-Encoding` for JSON request bodies; `none` sends plain JSON. */
23
+ export declare const RequestEncoding: Schema.Literals<readonly ["zstd", "gzip", "none"]>;
24
+ export type RequestEncoding = Schema.Schema.Type<typeof RequestEncoding>;
17
25
  declare const HttpOptions_base: Schema.Class<HttpOptions, Schema.Struct<{
18
26
  readonly body: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>;
19
27
  readonly headers: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
@@ -24,6 +32,8 @@ declare const HttpOptions_base: Schema.Class<HttpOptions, Schema.Struct<{
24
32
  readonly headerTimeout: Schema.optional<Schema.Union<readonly [Schema.Number, Schema.Literal<false>]>>;
25
33
  /** Time allowed between streamed response chunks once headers have arrived. */
26
34
  readonly chunkTimeout: Schema.optional<Schema.Union<readonly [Schema.Number, Schema.Literal<false>]>>;
35
+ /** Compression for JSON request bodies. Only set it for endpoints known to decode it. */
36
+ readonly encoding: Schema.optional<Schema.Literals<readonly ["zstd", "gzip", "none"]>>;
27
37
  }>, {}>;
28
38
  export declare class HttpOptions extends HttpOptions_base {
29
39
  }
@@ -89,6 +99,8 @@ export declare const LanguageModelSanitizerCompatibility: Schema.Literals<readon
89
99
  export type LanguageModelSanitizerCompatibility = Schema.Schema.Type<typeof LanguageModelSanitizerCompatibility>;
90
100
  export declare const LanguageModelMaxTokensFieldCompatibility: Schema.Literals<readonly ["max_completion_tokens", "max_tokens"]>;
91
101
  export type LanguageModelMaxTokensFieldCompatibility = Schema.Schema.Type<typeof LanguageModelMaxTokensFieldCompatibility>;
102
+ export declare const LanguageModelCacheFormatCompatibility: Schema.Literals<readonly ["anthropic", "alibaba"]>;
103
+ export type LanguageModelCacheFormatCompatibility = Schema.Schema.Type<typeof LanguageModelCacheFormatCompatibility>;
92
104
  declare const LanguageModelCompatibility_base: Schema.Class<LanguageModelCompatibility, Schema.Struct<{
93
105
  readonly sanitizer: Schema.optional<Schema.Literals<readonly ["gemini", "moonshot", "none"]>>;
94
106
  readonly reasoningField: Schema.optional<Schema.String>;
@@ -101,6 +113,8 @@ declare const LanguageModelCompatibility_base: Schema.Class<LanguageModelCompati
101
113
  readonly supportsUsageInStreaming: Schema.optional<Schema.Boolean>;
102
114
  readonly supportsStrictMode: Schema.optional<Schema.Boolean>;
103
115
  readonly supportsPromptCacheKey: Schema.optional<Schema.Boolean>;
116
+ /** Prompt-cache marker syntax the endpoint accepts. Overrides the route default; both send `cache_control`, and `alibaba` skips tool definitions. */
117
+ readonly cacheFormat: Schema.optional<Schema.Literals<readonly ["anthropic", "alibaba"]>>;
104
118
  readonly zaiToolStream: Schema.optional<Schema.Boolean>;
105
119
  readonly requireSignature: Schema.optional<Schema.Boolean>;
106
120
  /** Supports Anthropic's thinking-prefix mismatch controls. Overrides model-ID detection. */
@@ -34,8 +34,15 @@ export const ProviderMetadata = Schema.Record(Schema.String, Schema.Record(Schem
34
34
  export const mergeProviderOptions = (...items) => mergeJsonRecords(...items);
35
35
  /** Milliseconds for an HTTP timeout, or `false` to disable it. */
36
36
  export const HttpTimeout = Schema.Union([Schema.Number.check(Schema.isGreaterThan(0)), Schema.Literal(false)]);
37
- /** Applied to `headerTimeout` and `chunkTimeout` when a request leaves them unset. */
37
+ /** Applied to `headerTimeout` when a request leaves it unset. */
38
38
  export const DEFAULT_HTTP_TIMEOUT_MS = 300_000;
39
+ /**
40
+ * Applied to `chunkTimeout` when a request leaves it unset. Some providers, such as DeepSeek, have specifically asked
41
+ * clients to allow at least 15 minutes, because their models can stream nothing for minutes while they reason.
42
+ */
43
+ export const DEFAULT_CHUNK_TIMEOUT_MS = 900_000;
44
+ /** `Content-Encoding` for JSON request bodies; `none` sends plain JSON. */
45
+ export const RequestEncoding = Schema.Literals(["zstd", "gzip", "none"]);
39
46
  export class HttpOptions extends Schema.Class("AI.HttpOptions")({
40
47
  body: Schema.optional(JsonSchema),
41
48
  headers: Schema.optional(Schema.Record(Schema.String, Schema.String)),
@@ -46,6 +53,8 @@ export class HttpOptions extends Schema.Class("AI.HttpOptions")({
46
53
  headerTimeout: Schema.optional(HttpTimeout),
47
54
  /** Time allowed between streamed response chunks once headers have arrived. */
48
55
  chunkTimeout: Schema.optional(HttpTimeout),
56
+ /** Compression for JSON request bodies. Only set it for endpoints known to decode it. */
57
+ encoding: Schema.optional(RequestEncoding),
49
58
  }) {
50
59
  }
51
60
  (function (HttpOptions) {
@@ -63,9 +72,16 @@ export const mergeHttpOptions = (...items) => {
63
72
  const timeout = items.findLast((item) => item?.timeout !== undefined)?.timeout;
64
73
  const headerTimeout = items.findLast((item) => item?.headerTimeout !== undefined)?.headerTimeout;
65
74
  const chunkTimeout = items.findLast((item) => item?.chunkTimeout !== undefined)?.chunkTimeout;
66
- if (!body && !headers && !query && timeout === undefined && headerTimeout === undefined && chunkTimeout === undefined)
75
+ const encoding = items.findLast((item) => item?.encoding !== undefined)?.encoding;
76
+ if (!body &&
77
+ !headers &&
78
+ !query &&
79
+ timeout === undefined &&
80
+ headerTimeout === undefined &&
81
+ chunkTimeout === undefined &&
82
+ encoding === undefined)
67
83
  return undefined;
68
- return new HttpOptions({ body, headers, query, timeout, headerTimeout, chunkTimeout });
84
+ return new HttpOptions({ body, headers, query, timeout, headerTimeout, chunkTimeout, encoding });
69
85
  };
70
86
  export class GenerationOptions extends Schema.Class("LLM.GenerationOptions")({
71
87
  maxTokens: Schema.optional(Schema.Number),
@@ -119,6 +135,7 @@ export const ReasoningEffort = Schema.declare((value) => typeof value === "strin
119
135
  /** Tool schema sanitizer for a model family. `none` opts out of the protocol and model-name defaults. */
120
136
  export const LanguageModelSanitizerCompatibility = Schema.Literals(["gemini", "moonshot", "none"]);
121
137
  export const LanguageModelMaxTokensFieldCompatibility = Schema.Literals(["max_completion_tokens", "max_tokens"]);
138
+ export const LanguageModelCacheFormatCompatibility = Schema.Literals(["anthropic", "alibaba"]);
122
139
  export class LanguageModelCompatibility extends Schema.Class("LLM.LanguageModelCompatibility")({
123
140
  sanitizer: Schema.optional(LanguageModelSanitizerCompatibility),
124
141
  reasoningField: Schema.optional(Schema.String),
@@ -130,9 +147,12 @@ export class LanguageModelCompatibility extends Schema.Class("LLM.LanguageModelC
130
147
  supportsStore: Schema.optional(Schema.Boolean),
131
148
  supportsUsageInStreaming: Schema.optional(Schema.Boolean),
132
149
  supportsStrictMode: Schema.optional(Schema.Boolean),
133
- // Accepts `prompt_cache_key` in the Chat Completions body. Chat omits the
134
- // key unless this is set; session-affinity headers still flow regardless.
150
+ // Accepts `prompt_cache_key` in the request body. Chat omits the key unless
151
+ // this is true; other protocols omit it only when this is false.
152
+ // Session-affinity headers still flow regardless.
135
153
  supportsPromptCacheKey: Schema.optional(Schema.Boolean),
154
+ /** Prompt-cache marker syntax the endpoint accepts. Overrides the route default; both send `cache_control`, and `alibaba` skips tool definitions. */
155
+ cacheFormat: Schema.optional(LanguageModelCacheFormatCompatibility),
136
156
  zaiToolStream: Schema.optional(Schema.Boolean),
137
157
  requireSignature: Schema.optional(Schema.Boolean),
138
158
  /** Supports Anthropic's thinking-prefix mismatch controls. Overrides model-ID detection. */
package/dist/tool.d.ts CHANGED
@@ -132,5 +132,15 @@ export type Tools = Record<string, AnyTool>;
132
132
  * is reused.
133
133
  */
134
134
  export declare const toDefinitions: (tools: Tools) => ReadonlyArray<ToolDefinitionClass>;
135
+ /**
136
+ * Describes a no-argument Effect tool input as an empty object, or returns
137
+ * `undefined` when the input takes arguments.
138
+ *
139
+ * Effect emits `{ not: { type: "null" } }` only for an encoded struct with no
140
+ * properties or index signatures, but providers require tool parameters to
141
+ * describe an object. Annotations are kept; any other keyword, such as a
142
+ * check's `minProperties`, leaves the schema as Effect emitted it.
143
+ */
144
+ export declare const emptyInputJsonSchema: (schema: Schema.Top) => JsonSchema.JsonSchema | undefined;
135
145
  export { ToolFailure };
136
146
  export * as Tool from "./tool.js";