@opencode/ai 2.0.20 → 2.0.22

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 (59) hide show
  1. package/dist/cache-policy.js +22 -3
  2. package/dist/llm.d.ts +4 -0
  3. package/dist/promise.d.ts +8 -0
  4. package/dist/protocols/alibaba-chat.d.ts +20 -10
  5. package/dist/protocols/alibaba-chat.js +2 -1
  6. package/dist/protocols/anthropic-messages.js +14 -12
  7. package/dist/protocols/bedrock-converse.js +30 -1
  8. package/dist/protocols/open-responses.d.ts +4 -0
  9. package/dist/protocols/openai-chat.d.ts +122 -71
  10. package/dist/protocols/openai-chat.js +40 -37
  11. package/dist/protocols/openai-compatible-chat.d.ts +16 -10
  12. package/dist/protocols/openai-responses.js +4 -3
  13. package/dist/protocols/utils/cache.d.ts +5 -0
  14. package/dist/protocols/utils/cache.js +9 -1
  15. package/dist/protocols/utils/tool-stream.d.ts +12 -0
  16. package/dist/protocols/zai-chat.d.ts +20 -10
  17. package/dist/protocols/zai-chat.js +6 -3
  18. package/dist/provider-error.js +24 -6
  19. package/dist/providers/alibaba.d.ts +16 -10
  20. package/dist/providers/amazon-bedrock-mantle.d.ts +16 -10
  21. package/dist/providers/azure.d.ts +16 -10
  22. package/dist/providers/baseten.d.ts +32 -20
  23. package/dist/providers/cerebras.d.ts +32 -20
  24. package/dist/providers/cloudflare-ai-gateway.d.ts +32 -20
  25. package/dist/providers/cloudflare-ai-gateway.js +43 -35
  26. package/dist/providers/cloudflare-workers-ai.d.ts +32 -20
  27. package/dist/providers/deepinfra.d.ts +32 -20
  28. package/dist/providers/deepseek.d.ts +32 -20
  29. package/dist/providers/digitalocean.d.ts +469 -0
  30. package/dist/providers/digitalocean.js +53 -0
  31. package/dist/providers/fireworks.d.ts +32 -20
  32. package/dist/providers/google-vertex-chat.d.ts +16 -10
  33. package/dist/providers/google-vertex-messages.js +1 -1
  34. package/dist/providers/groq.d.ts +36 -20
  35. package/dist/providers/groq.js +1 -1
  36. package/dist/providers/index.d.ts +1 -0
  37. package/dist/providers/index.js +1 -0
  38. package/dist/providers/meta.d.ts +16 -10
  39. package/dist/providers/minimax.d.ts +16 -10
  40. package/dist/providers/moonshot.d.ts +16 -10
  41. package/dist/providers/openai-compatible.d.ts +16 -10
  42. package/dist/providers/openai.d.ts +16 -10
  43. package/dist/providers/openrouter.d.ts +68 -40
  44. package/dist/providers/openrouter.js +1 -13
  45. package/dist/providers/togetherai.d.ts +32 -20
  46. package/dist/providers/xai.d.ts +16 -10
  47. package/dist/providers/zai-coding-plan.d.ts +16 -10
  48. package/dist/providers/zai.d.ts +16 -10
  49. package/dist/route/client.d.ts +4 -0
  50. package/dist/route/executor.js +13 -6
  51. package/dist/route/transport/http.d.ts +2 -1
  52. package/dist/route/transport/http.js +28 -6
  53. package/dist/schema/events.d.ts +176 -0
  54. package/dist/schema/events.js +4 -0
  55. package/dist/schema/options.d.ts +11 -0
  56. package/dist/schema/options.js +15 -2
  57. package/dist/testing.d.ts +32 -0
  58. package/dist/tool-history.js +17 -3
  59. package/package.json +3 -3
@@ -211,6 +211,10 @@ export const ToolError = Schema.Struct({
211
211
  export const FinishReasonDetails = Schema.Struct({
212
212
  normalized: FinishReason,
213
213
  raw: Schema.optional(Schema.String),
214
+ /** The provider's policy area for a content-filter finish, such as `cyber`. */
215
+ category: Schema.optional(Schema.String),
216
+ /** The provider's human-readable reason for a content-filter finish. */
217
+ explanation: Schema.optional(Schema.String),
214
218
  }).annotate({ identifier: "LLM.FinishReasonDetails" });
215
219
  export const StepFinish = Schema.Struct({
216
220
  type: Schema.tag("step-finish"),
@@ -9,10 +9,21 @@ export type ProviderOptions = Schema.Schema.Type<typeof ProviderOptions>;
9
9
  export declare const ProviderMetadata: Schema.$Record<Schema.String, Schema.$Record<Schema.String, Schema.Unknown>>;
10
10
  export type ProviderMetadata = Schema.Schema.Type<typeof ProviderMetadata>;
11
11
  export declare const mergeProviderOptions: (...items: ReadonlyArray<ProviderOptions | undefined>) => ProviderOptions | undefined;
12
+ /** Milliseconds for an HTTP timeout, or `false` to disable it. */
13
+ export declare const HttpTimeout: Schema.Union<readonly [Schema.Number, Schema.Literal<false>]>;
14
+ export type HttpTimeout = Schema.Schema.Type<typeof HttpTimeout>;
15
+ /** Applied to `headerTimeout` and `chunkTimeout` when a request leaves them unset. */
16
+ export declare const DEFAULT_HTTP_TIMEOUT_MS = 300000;
12
17
  declare const HttpOptions_base: Schema.Class<HttpOptions, Schema.Struct<{
13
18
  readonly body: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>;
14
19
  readonly headers: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
15
20
  readonly query: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
21
+ /** Time allowed for the whole request, from send until the response completes. Unbounded when unset. */
22
+ readonly timeout: Schema.optional<Schema.Union<readonly [Schema.Number, Schema.Literal<false>]>>;
23
+ /** Time allowed for response headers to arrive. */
24
+ readonly headerTimeout: Schema.optional<Schema.Union<readonly [Schema.Number, Schema.Literal<false>]>>;
25
+ /** Time allowed between streamed response chunks once headers have arrived. */
26
+ readonly chunkTimeout: Schema.optional<Schema.Union<readonly [Schema.Number, Schema.Literal<false>]>>;
16
27
  }>, {}>;
17
28
  export declare class HttpOptions extends HttpOptions_base {
18
29
  }
@@ -32,10 +32,20 @@ export const ProviderMetadata = Schema.Record(Schema.String, Schema.Record(Schem
32
32
  identifier: "LLM.ProviderMetadata",
33
33
  });
34
34
  export const mergeProviderOptions = (...items) => mergeJsonRecords(...items);
35
+ /** Milliseconds for an HTTP timeout, or `false` to disable it. */
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. */
38
+ export const DEFAULT_HTTP_TIMEOUT_MS = 300_000;
35
39
  export class HttpOptions extends Schema.Class("AI.HttpOptions")({
36
40
  body: Schema.optional(JsonSchema),
37
41
  headers: Schema.optional(Schema.Record(Schema.String, Schema.String)),
38
42
  query: Schema.optional(Schema.Record(Schema.String, Schema.String)),
43
+ /** Time allowed for the whole request, from send until the response completes. Unbounded when unset. */
44
+ timeout: Schema.optional(HttpTimeout),
45
+ /** Time allowed for response headers to arrive. */
46
+ headerTimeout: Schema.optional(HttpTimeout),
47
+ /** Time allowed between streamed response chunks once headers have arrived. */
48
+ chunkTimeout: Schema.optional(HttpTimeout),
39
49
  }) {
40
50
  }
41
51
  (function (HttpOptions) {
@@ -50,9 +60,12 @@ export const mergeHttpOptions = (...items) => {
50
60
  const body = mergeJsonRecords(...items.map((item) => item?.body));
51
61
  const headers = mergeStringRecords(...items.map((item) => item?.headers));
52
62
  const query = mergeStringRecords(...items.map((item) => item?.query));
53
- if (!body && !headers && !query)
63
+ const timeout = items.findLast((item) => item?.timeout !== undefined)?.timeout;
64
+ const headerTimeout = items.findLast((item) => item?.headerTimeout !== undefined)?.headerTimeout;
65
+ const chunkTimeout = items.findLast((item) => item?.chunkTimeout !== undefined)?.chunkTimeout;
66
+ if (!body && !headers && !query && timeout === undefined && headerTimeout === undefined && chunkTimeout === undefined)
54
67
  return undefined;
55
- return new HttpOptions({ body, headers, query });
68
+ return new HttpOptions({ body, headers, query, timeout, headerTimeout, chunkTimeout });
56
69
  };
57
70
  export class GenerationOptions extends Schema.Class("LLM.GenerationOptions")({
58
71
  maxTokens: Schema.optional(Schema.Number),
package/dist/testing.d.ts CHANGED
@@ -228,6 +228,8 @@ export declare const complete: (options: {
228
228
  readonly reason: {
229
229
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
230
230
  readonly raw?: string | undefined;
231
+ readonly category?: string | undefined;
232
+ readonly explanation?: string | undefined;
231
233
  };
232
234
  readonly index: number;
233
235
  readonly providerMetadata?: {
@@ -241,6 +243,8 @@ export declare const complete: (options: {
241
243
  readonly reason: {
242
244
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
243
245
  readonly raw?: string | undefined;
246
+ readonly category?: string | undefined;
247
+ readonly explanation?: string | undefined;
244
248
  };
245
249
  readonly providerMetadata?: {
246
250
  readonly [x: string]: {
@@ -440,6 +444,8 @@ export declare const stop: (...events: readonly LLMEvent[]) => (({
440
444
  readonly reason: {
441
445
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
442
446
  readonly raw?: string | undefined;
447
+ readonly category?: string | undefined;
448
+ readonly explanation?: string | undefined;
443
449
  };
444
450
  readonly index: number;
445
451
  readonly providerMetadata?: {
@@ -453,6 +459,8 @@ export declare const stop: (...events: readonly LLMEvent[]) => (({
453
459
  readonly reason: {
454
460
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
455
461
  readonly raw?: string | undefined;
462
+ readonly category?: string | undefined;
463
+ readonly explanation?: string | undefined;
456
464
  };
457
465
  readonly providerMetadata?: {
458
466
  readonly [x: string]: {
@@ -652,6 +660,8 @@ export declare const toolCalls: (...events: readonly LLMEvent[]) => (({
652
660
  readonly reason: {
653
661
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
654
662
  readonly raw?: string | undefined;
663
+ readonly category?: string | undefined;
664
+ readonly explanation?: string | undefined;
655
665
  };
656
666
  readonly index: number;
657
667
  readonly providerMetadata?: {
@@ -665,6 +675,8 @@ export declare const toolCalls: (...events: readonly LLMEvent[]) => (({
665
675
  readonly reason: {
666
676
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
667
677
  readonly raw?: string | undefined;
678
+ readonly category?: string | undefined;
679
+ readonly explanation?: string | undefined;
668
680
  };
669
681
  readonly providerMetadata?: {
670
682
  readonly [x: string]: {
@@ -864,6 +876,8 @@ export declare const text: (value: string, id: string) => (({
864
876
  readonly reason: {
865
877
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
866
878
  readonly raw?: string | undefined;
879
+ readonly category?: string | undefined;
880
+ readonly explanation?: string | undefined;
867
881
  };
868
882
  readonly index: number;
869
883
  readonly providerMetadata?: {
@@ -877,6 +891,8 @@ export declare const text: (value: string, id: string) => (({
877
891
  readonly reason: {
878
892
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
879
893
  readonly raw?: string | undefined;
894
+ readonly category?: string | undefined;
895
+ readonly explanation?: string | undefined;
880
896
  };
881
897
  readonly providerMetadata?: {
882
898
  readonly [x: string]: {
@@ -1076,6 +1092,8 @@ export declare const textWithUsage: (value: string, id: string, inputTokens: num
1076
1092
  readonly reason: {
1077
1093
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
1078
1094
  readonly raw?: string | undefined;
1095
+ readonly category?: string | undefined;
1096
+ readonly explanation?: string | undefined;
1079
1097
  };
1080
1098
  readonly index: number;
1081
1099
  readonly providerMetadata?: {
@@ -1089,6 +1107,8 @@ export declare const textWithUsage: (value: string, id: string, inputTokens: num
1089
1107
  readonly reason: {
1090
1108
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
1091
1109
  readonly raw?: string | undefined;
1110
+ readonly category?: string | undefined;
1111
+ readonly explanation?: string | undefined;
1092
1112
  };
1093
1113
  readonly providerMetadata?: {
1094
1114
  readonly [x: string]: {
@@ -1288,6 +1308,8 @@ export declare const tool: (id: string, name: string, input: unknown) => (({
1288
1308
  readonly reason: {
1289
1309
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
1290
1310
  readonly raw?: string | undefined;
1311
+ readonly category?: string | undefined;
1312
+ readonly explanation?: string | undefined;
1291
1313
  };
1292
1314
  readonly index: number;
1293
1315
  readonly providerMetadata?: {
@@ -1301,6 +1323,8 @@ export declare const tool: (id: string, name: string, input: unknown) => (({
1301
1323
  readonly reason: {
1302
1324
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
1303
1325
  readonly raw?: string | undefined;
1326
+ readonly category?: string | undefined;
1327
+ readonly explanation?: string | undefined;
1304
1328
  };
1305
1329
  readonly providerMetadata?: {
1306
1330
  readonly [x: string]: {
@@ -1500,6 +1524,8 @@ export declare const failAfter: (error: AIError, ...events: readonly LLMEvent[])
1500
1524
  readonly reason: {
1501
1525
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
1502
1526
  readonly raw?: string | undefined;
1527
+ readonly category?: string | undefined;
1528
+ readonly explanation?: string | undefined;
1503
1529
  };
1504
1530
  readonly index: number;
1505
1531
  readonly providerMetadata?: {
@@ -1513,6 +1539,8 @@ export declare const failAfter: (error: AIError, ...events: readonly LLMEvent[])
1513
1539
  readonly reason: {
1514
1540
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
1515
1541
  readonly raw?: string | undefined;
1542
+ readonly category?: string | undefined;
1543
+ readonly explanation?: string | undefined;
1516
1544
  };
1517
1545
  readonly providerMetadata?: {
1518
1546
  readonly [x: string]: {
@@ -1712,6 +1740,8 @@ export declare const hangAfter: (...events: readonly LLMEvent[]) => Stream.Strea
1712
1740
  readonly reason: {
1713
1741
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
1714
1742
  readonly raw?: string | undefined;
1743
+ readonly category?: string | undefined;
1744
+ readonly explanation?: string | undefined;
1715
1745
  };
1716
1746
  readonly index: number;
1717
1747
  readonly providerMetadata?: {
@@ -1725,6 +1755,8 @@ export declare const hangAfter: (...events: readonly LLMEvent[]) => Stream.Strea
1725
1755
  readonly reason: {
1726
1756
  readonly normalized: "length" | "stop" | "tool-calls" | "content-filter" | "error" | "unknown";
1727
1757
  readonly raw?: string | undefined;
1758
+ readonly category?: string | undefined;
1759
+ readonly explanation?: string | undefined;
1728
1760
  };
1729
1761
  readonly providerMetadata?: {
1730
1762
  readonly [x: string]: {
@@ -4,11 +4,19 @@ const MISSING_TOOL_RESULT = "Tool result missing";
4
4
  export function normalizeToolHistory(messages) {
5
5
  const normalized = [];
6
6
  const pending = new Map();
7
- const appendMissingResults = () => {
8
- if (pending.size === 0)
7
+ // System updates cannot sit between a tool call and its results, so they wait until every pending call is answered.
8
+ const held = [];
9
+ const releaseHeld = () => {
10
+ if (pending.size > 0)
9
11
  return;
10
- normalized.push(missingToolResults(pending.values()));
12
+ normalized.push(...held);
13
+ held.length = 0;
14
+ };
15
+ const appendMissingResults = () => {
16
+ if (pending.size > 0)
17
+ normalized.push(missingToolResults(pending.values()));
11
18
  pending.clear();
19
+ releaseHeld();
12
20
  };
13
21
  for (const message of messages) {
14
22
  if (message.role === "user" || message.role === "assistant")
@@ -17,6 +25,11 @@ export function normalizeToolHistory(messages) {
17
25
  const tool = normalizeToolMessage(message, pending);
18
26
  if (tool)
19
27
  normalized.push(tool);
28
+ releaseHeld();
29
+ continue;
30
+ }
31
+ if (message.role === "system" && pending.size > 0) {
32
+ held.push(message);
20
33
  continue;
21
34
  }
22
35
  normalized.push(message);
@@ -27,6 +40,7 @@ export function normalizeToolHistory(messages) {
27
40
  pending.set(part.id, part);
28
41
  }
29
42
  }
43
+ appendMissingResults();
30
44
  return normalized.length === messages.length && normalized.every((message, index) => message === messages[index])
31
45
  ? messages
32
46
  : normalized;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "2.0.20",
3
+ "version": "2.0.22",
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.20",
37
+ "@opencode/http-recorder": "2.0.22",
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.20",
47
+ "@opencode/schema": "2.0.22",
48
48
  "aws4fetch": "1.0.20",
49
49
  "effect": "4.0.0-rc.112",
50
50
  "google-auth-library": "10.5.0"