@diffexai/diffex 0.2.6 → 0.3.0

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 (52) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/core/agent-session.d.ts +5 -0
  3. package/dist/core/agent-session.js +89 -19
  4. package/dist/core/compaction/compaction.js +3 -1
  5. package/dist/core/model-runtime.js +3 -3
  6. package/dist/core/provider-composer.js +1 -1
  7. package/dist/core/sdk.d.ts +2 -1
  8. package/dist/core/sdk.js +18 -6
  9. package/dist/core/subagents/controller.d.ts +4 -3
  10. package/dist/core/subagents/controller.js +173 -37
  11. package/dist/core/subagents/types.d.ts +13 -0
  12. package/dist/core/tools/bash.d.ts +4 -0
  13. package/dist/core/tools/bash.js +14 -5
  14. package/dist/core/tools/subagents.d.ts +12 -10
  15. package/dist/core/tools/subagents.js +61 -49
  16. package/dist/node_modules/@diffexai/diffex-agent-core/distribution-components.json +4 -4
  17. package/dist/node_modules/@diffexai/diffex-agent-core/distribution-files.json +1 -1
  18. package/dist/node_modules/@diffexai/diffex-agent-core/package.json +1 -1
  19. package/dist/node_modules/@diffexai/diffex-ai/dist/api/lazy.d.ts +1 -1
  20. package/dist/node_modules/@diffexai/diffex-ai/dist/api/lazy.js +8 -8
  21. package/dist/node_modules/@diffexai/diffex-ai/dist/models.js +4 -4
  22. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/.manifest.json +1 -1
  23. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/opencode.json +1 -1
  24. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/openrouter.json +1 -1
  25. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  26. package/dist/node_modules/@diffexai/diffex-ai/distribution-components.json +3 -3
  27. package/dist/node_modules/@diffexai/diffex-ai/distribution-files.json +8 -8
  28. package/dist/node_modules/@diffexai/diffex-ai/package.json +1 -1
  29. package/dist/node_modules/@diffexai/diffex-client/distribution-components.json +3 -3
  30. package/dist/node_modules/@diffexai/diffex-client/distribution-files.json +1 -1
  31. package/dist/node_modules/@diffexai/diffex-client/package.json +1 -1
  32. package/dist/node_modules/@diffexai/diffex-harness-state/distribution-components.json +2 -2
  33. package/dist/node_modules/@diffexai/diffex-harness-state/distribution-files.json +1 -1
  34. package/dist/node_modules/@diffexai/diffex-harness-state/package.json +1 -1
  35. package/dist/node_modules/@diffexai/diffex-protocol/distribution-components.json +2 -2
  36. package/dist/node_modules/@diffexai/diffex-protocol/distribution-files.json +1 -1
  37. package/dist/node_modules/@diffexai/diffex-protocol/package.json +1 -1
  38. package/dist/node_modules/@diffexai/diffex-telemetry/distribution-components.json +2 -2
  39. package/dist/node_modules/@diffexai/diffex-telemetry/distribution-files.json +1 -1
  40. package/dist/node_modules/@diffexai/diffex-telemetry/package.json +1 -1
  41. package/dist/node_modules/@diffexai/diffex-tui/distribution-components.json +2 -2
  42. package/dist/node_modules/@diffexai/diffex-tui/distribution-files.json +1 -1
  43. package/dist/node_modules/@diffexai/diffex-tui/package.json +1 -1
  44. package/dist/utils/owned-shell-processes.d.ts +8 -0
  45. package/dist/utils/owned-shell-processes.js +61 -0
  46. package/distribution-components.json +11 -11
  47. package/distribution-files.json +51 -43
  48. package/npm-shrinkwrap.json +2 -2
  49. package/package.json +1 -1
  50. package/release/distribution-manifest.json +4 -4
  51. package/release/install-package-lock.json +5 -5
  52. package/release/install-package.json +2 -2
@@ -5,11 +5,11 @@ const spawnAgentSchema = Type.Object({
5
5
  description: "Unique lowercase name for the child agent",
6
6
  pattern: SUBAGENT_NAME_PATTERN.source,
7
7
  }),
8
- task: Type.String({ description: "The focused task for the child agent", minLength: 1 }),
8
+ task: Type.String({ description: "Task for the child agent", minLength: 1 }),
9
9
  });
10
10
  const escalateToParentSchema = Type.Object({
11
11
  message: Type.String({
12
- description: "Material blocker, risk, contradiction, or decision requiring parent attention",
12
+ description: "Checkpoint for the parent",
13
13
  minLength: 1,
14
14
  maxLength: 1_000,
15
15
  }),
@@ -20,35 +20,36 @@ const targetSchema = Type.String({
20
20
  });
21
21
  const agentActionSchema = Type.Object({
22
22
  target: targetSchema,
23
+ reason: Type.Optional(Type.String({
24
+ description: "Required for renew: justify against current progress, remaining work, and the goal",
25
+ minLength: 1,
26
+ })),
23
27
  action: Type.Unsafe({
24
28
  type: "string",
25
- enum: ["message", "interrupt"],
29
+ enum: ["message", "interrupt", "renew"],
26
30
  }),
27
31
  message: Type.Optional(Type.String({ description: "Message for the child agent", minLength: 1 })),
28
32
  wake: Type.Optional(Type.Boolean({ default: false })),
33
+ delivery: Type.Optional(Type.Union([Type.Literal("steer"), Type.Literal("follow_up")], {
34
+ description: "steer corrects current work at the next tool boundary (default); follow_up waits until the current work finishes",
35
+ default: "steer",
36
+ })),
29
37
  }, { additionalProperties: false });
30
- const agentsSchema = Type.Object({
31
- timeout_ms: Type.Integer({
32
- description: "Maximum time to wait in milliseconds, or zero to return immediately",
33
- minimum: 0,
34
- }),
38
+ const agentStatusSchema = Type.Object({
35
39
  targets: Type.Optional(Type.Array(targetSchema, {
36
- description: "Child agent names to inspect, frozen when the call starts",
40
+ description: "Child agent names to inspect; omit to inspect all children",
37
41
  minItems: 1,
38
42
  uniqueItems: true,
39
43
  })),
40
- until: Type.Optional(Type.Union([Type.Literal("any"), Type.Literal("all")], {
41
- description: "Wait until any or all selected agents reach a terminal status",
42
- })),
43
44
  }, { additionalProperties: false });
44
45
  export function createEscalateToParentTool(escalate) {
45
46
  return {
46
47
  name: "escalate_to_parent",
47
48
  label: "Escalate to Parent",
48
- description: "Report a material blocker, risk, contradiction, or decision that may require the parent to redirect or interrupt work.",
49
- promptSnippet: "Report blockers, risks, or uncertainties to the parent agent",
49
+ description: "Report blockers, risks, contradictions, decisions, or extension needs to the parent.",
50
+ promptSnippet: "Escalate issues or request an extension",
50
51
  promptGuidelines: [
51
- "Use escalate_to_parent only for material information that could change the parent's plan. Do not send routine progress or tool logs, and still provide a complete final response.",
52
+ "Include current progress, remaining work, the goal, and the decision or extension needed. Escalate only plan-changing information; omit tool logs. Still provide a complete final response.",
52
53
  ],
53
54
  parameters: escalateToParentSchema,
54
55
  executionMode: "parallel",
@@ -67,19 +68,16 @@ export function createEscalateToParentTool(escalate) {
67
68
  },
68
69
  };
69
70
  }
70
- function assertAgentsRequest(request) {
71
+ function assertAgentStatusRequest(request) {
71
72
  if (typeof request !== "object" || request === null || Array.isArray(request)) {
72
- throw new Error("Agents request must be an object");
73
+ throw new Error("Agent status request must be an object");
73
74
  }
74
75
  for (const key of Object.keys(request)) {
75
- if (key !== "timeout_ms" && key !== "targets" && key !== "until") {
76
- throw new Error(`Unknown agents request field: ${key}`);
76
+ if (key !== "targets") {
77
+ throw new Error(`Unknown agent status request field: ${key}`);
77
78
  }
78
79
  }
79
- const { timeout_ms, targets, until } = request;
80
- if (!Number.isInteger(timeout_ms) || timeout_ms === undefined || timeout_ms < 0) {
81
- throw new RangeError("timeout_ms must be a non-negative integer");
82
- }
80
+ const { targets } = request;
83
81
  if (targets !== undefined) {
84
82
  if (!Array.isArray(targets) || targets.length === 0) {
85
83
  throw new Error("targets must be a non-empty array");
@@ -95,19 +93,16 @@ function assertAgentsRequest(request) {
95
93
  uniqueTargets.add(target);
96
94
  }
97
95
  }
98
- if (until !== undefined && until !== "any" && until !== "all") {
99
- throw new Error(`Invalid agents wait condition: ${String(until)}`);
100
- }
101
96
  }
102
97
  export function createSpawnAgentTool(spawn, assertCanSpawn = () => { }) {
103
98
  return {
104
99
  name: "spawn_agent",
105
100
  label: "Spawn Agent",
106
- description: "Start an independent child agent to work on a focused task asynchronously. Returns the child’s name and queued status without waiting for completion.",
107
- promptSnippet: "Delegate a focused task to an independent child agent",
101
+ description: "Start a child on an independent task; return its name and queued status immediately.",
102
+ promptSnippet: "Delegate an independent task",
108
103
  promptGuidelines: [
109
- "Use for focused subtasks that can run independently alongside other work. Request file references and supporting evidence for research or audits, and assign non-overlapping file ownership for edit and write operations.",
110
- "Continue independent work while child agents run. You may end your current response while they are running; the session waits for those children and delivers their results to you automatically before the parent task finishes.",
104
+ "Request file references and evidence for research or audits. Assign non-overlapping file ownership for edits.",
105
+ "Continue independent work while children run. When only needed child work remains, end your response; the runtime keeps the task open and resumes you with child reports or results.",
111
106
  ],
112
107
  parameters: spawnAgentSchema,
113
108
  executionMode: "parallel",
@@ -131,12 +126,12 @@ export function createAgentActionTool(action) {
131
126
  return {
132
127
  name: "agent_action",
133
128
  label: "Agent Action",
134
- description: "Send a message to drive an existing child agent, optionally waking it to resume work, or interrupt its current work.",
135
- promptSnippet: "Message, wake, or interrupt an existing child agent",
129
+ description: "Message, wake, renew, or interrupt an existing child agent.",
130
+ promptSnippet: "Manage an existing child agent",
136
131
  promptGuidelines: [
137
- "Use to provide clarifications or corrections to a child agent. Set wake: true when the message should resume an idle child.",
138
- "Let child agents complete delegated work that is still needed. Interrupt only when the work is no longer needed, is proceeding in the wrong direction, or must stop because of a user request or material risk.",
139
- "When waiting for needed child results, continue independent work or use wait_for_agents to wait. A wait timeout does not mean the child has failed and is not by itself a reason to interrupt it.",
132
+ "Set wake: true to resume an idle child; steering an idle child without it fails.",
133
+ "Use action: 'renew' with a reason to approve an extension. Each approval adds one configured allowance (15 minutes by default) to the existing deadline, capped by the parent deadline. Waiting does not renew it.",
134
+ "Interrupt obsolete or misdirected work, or when a user request or material risk requires stopping. Otherwise let needed work finish.",
140
135
  ],
141
136
  parameters: agentActionSchema,
142
137
  executionMode: "parallel",
@@ -145,13 +140,32 @@ export function createAgentActionTool(action) {
145
140
  throw new Error(`Invalid subagent name: ${request.target}`);
146
141
  }
147
142
  let normalized;
148
- if (request.action === "interrupt") {
149
- if ("message" in request || "wake" in request) {
143
+ if (request.action === "renew") {
144
+ if (!request.reason?.trim())
145
+ throw new Error("Lease renewal requires a justification");
146
+ if ("message" in request || "wake" in request || "delivery" in request)
147
+ throw new Error("Renew actions do not accept message fields");
148
+ normalized = {
149
+ target: request.target,
150
+ action: "renew",
151
+ reason: request.reason,
152
+ };
153
+ }
154
+ else if ("reason" in request) {
155
+ throw new Error("Only renew actions accept a reason");
156
+ }
157
+ else if (request.action === "interrupt") {
158
+ if ("message" in request || "wake" in request || "delivery" in request) {
150
159
  throw new Error("Interrupt actions do not accept message fields");
151
160
  }
152
161
  normalized = { target: request.target, action: request.action };
153
162
  }
154
163
  else {
164
+ if (request.action !== "message")
165
+ throw new Error(`Invalid subagent action: ${String(request.action)}`);
166
+ if (request.delivery !== undefined && request.delivery !== "steer" && request.delivery !== "follow_up") {
167
+ throw new Error("Invalid subagent message delivery");
168
+ }
155
169
  const message = request.message;
156
170
  if (message === undefined || message.trim().length === 0) {
157
171
  throw new Error("Subagent message must be non-empty");
@@ -161,6 +175,7 @@ export function createAgentActionTool(action) {
161
175
  action: request.action,
162
176
  message,
163
177
  wake: request.wake ?? false,
178
+ delivery: request.delivery ?? "steer",
164
179
  };
165
180
  }
166
181
  const details = await action(normalized);
@@ -171,28 +186,25 @@ export function createAgentActionTool(action) {
171
186
  },
172
187
  };
173
188
  }
174
- export function createAgentsTool(query) {
189
+ export function createAgentStatusTool(query) {
175
190
  return {
176
- name: "wait_for_agents",
177
- label: "Wait For Agents",
178
- description: "Check child agent statuses or wait for status changes. Returns statuses and any recorded output or errors.",
179
- promptSnippet: "Wait for delegated work",
191
+ name: "agent_status",
192
+ label: "Agent Status",
193
+ description: "Immediately return child statuses and recorded output or errors.",
194
+ promptSnippet: "Inspect child agent status and results",
180
195
  promptGuidelines: [
181
- "Use wait_for_agents when further progress depends on child results. When waiting for completion, explicitly set until to 'any' or 'all' and select the relevant targets. Without until, the call may return before a child finishes.",
182
- "A wait timeout does not stop child agents or mean they have failed. If their work is still needed, continue other work or wait again rather than interrupting them.",
196
+ "Terminal results returned here are consumed and will not be delivered again automatically.",
197
+ "Do not repeatedly poll for completion.",
183
198
  ],
184
- parameters: agentsSchema,
199
+ parameters: agentStatusSchema,
185
200
  executionMode: "parallel",
186
201
  execute: async (_toolCallId, request, signal) => {
187
- assertAgentsRequest(request);
202
+ assertAgentStatusRequest(request);
188
203
  const result = await query({
189
- timeoutMs: request.timeout_ms,
190
204
  ...(request.targets === undefined ? {} : { targets: request.targets }),
191
- ...(request.until === undefined ? {} : { until: request.until }),
192
205
  ...(signal === undefined ? {} : { signal }),
193
206
  });
194
207
  const details = Object.freeze({
195
- timed_out: result.timedOut,
196
208
  agents: Object.freeze(result.agents.map((agent) => Object.freeze({
197
209
  name: agent.name,
198
210
  status: agent.status,
@@ -1,8 +1,8 @@
1
1
  [
2
2
  {
3
3
  "name": "@diffexai/diffex-agent-core",
4
- "version": "0.2.6",
5
- "sourceCommit": "857f5ef8e47b3371a5a0f97f78dbda2bcba53a64",
4
+ "version": "0.3.0",
5
+ "sourceCommit": "c8cec4d3820393131eaae7b43d56ac5f75d8041a",
6
6
  "license": "Apache-2.0",
7
7
  "portions": "Diffex contributions; Pi-derived portions retain MIT terms in LICENSE",
8
8
  "notice": "LICENSE",
@@ -10,12 +10,12 @@
10
10
  },
11
11
  {
12
12
  "name": "@diffexai/diffex-ai",
13
- "version": "^0.2.6",
13
+ "version": "^0.3.0",
14
14
  "distribution": "resolved separately by package manager; not bundled in this npm tarball"
15
15
  },
16
16
  {
17
17
  "name": "@diffexai/diffex-telemetry",
18
- "version": "^0.2.6",
18
+ "version": "^0.3.0",
19
19
  "distribution": "resolved separately by package manager; not bundled in this npm tarball"
20
20
  },
21
21
  {
@@ -1,5 +1,5 @@
1
1
  {
2
- "sourceCommit": "857f5ef8e47b3371a5a0f97f78dbda2bcba53a64",
2
+ "sourceCommit": "c8cec4d3820393131eaae7b43d56ac5f75d8041a",
3
3
  "algorithm": "sha256",
4
4
  "files": [
5
5
  {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diffexai/diffex-agent-core",
3
- "version": "0.2.6",
3
+ "version": "0.3.0",
4
4
  "description": "General-purpose agent with transport abstraction, state management, and attachment support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -5,7 +5,7 @@ import { AssistantMessageEventStream } from "../utils/event-stream.ts";
5
5
  * lazy module loading) behind it. Setup failures terminate the stream with an
6
6
  * error event.
7
7
  */
8
- export declare function lazyStream(model: Model<Api>, setup: () => Promise<AsyncIterable<AssistantMessageEvent>>): AssistantMessageEventStream;
8
+ export declare function lazyStream(model: Model<Api>, setup: () => Promise<AsyncIterable<AssistantMessageEvent>>, signal?: AbortSignal): AssistantMessageEventStream;
9
9
  /**
10
10
  * Wraps a dynamically imported API implementation module as `ProviderStreams`.
11
11
  * The module loads on first stream call; the host's import cache deduplicates
@@ -1,5 +1,5 @@
1
1
  import { AssistantMessageEventStream } from "../utils/event-stream.js";
2
- function createSetupErrorMessage(model, error) {
2
+ function createSetupErrorMessage(model, error, signal) {
3
3
  return {
4
4
  role: "assistant",
5
5
  content: [],
@@ -14,7 +14,7 @@ function createSetupErrorMessage(model, error) {
14
14
  totalTokens: 0,
15
15
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
16
16
  },
17
- stopReason: "error",
17
+ stopReason: signal?.aborted ? "aborted" : "error",
18
18
  errorMessage: error instanceof Error ? error.message : String(error),
19
19
  timestamp: Date.now(),
20
20
  };
@@ -33,21 +33,21 @@ async function forwardStream(target, source) {
33
33
  * lazy module loading) behind it. Setup failures terminate the stream with an
34
34
  * error event.
35
35
  */
36
- export function lazyStream(model, setup) {
36
+ export function lazyStream(model, setup, signal) {
37
37
  const outer = new AssistantMessageEventStream();
38
38
  setup()
39
39
  .then((inner) => forwardStream(outer, inner))
40
40
  .catch((error) => {
41
- const message = createSetupErrorMessage(model, error);
42
- outer.push({ type: "error", reason: "error", error: message });
41
+ const message = createSetupErrorMessage(model, error, signal);
42
+ outer.push({ type: "error", reason: signal?.aborted ? "aborted" : "error", error: message });
43
43
  outer.end(message);
44
44
  });
45
45
  return outer;
46
46
  }
47
47
  export function lazyApi(load, capabilities) {
48
48
  const api = {
49
- stream: (model, context, options) => lazyStream(model, async () => (await load()).stream(model, context, options)),
50
- streamSimple: (model, context, options) => lazyStream(model, async () => (await load()).streamSimple(model, context, options)),
49
+ stream: (model, context, options) => lazyStream(model, async () => (await load()).stream(model, context, options), options?.signal),
50
+ streamSimple: (model, context, options) => lazyStream(model, async () => (await load()).streamSimple(model, context, options), options?.signal),
51
51
  };
52
52
  if (capabilities?.fetchDeferred) {
53
53
  api.fetchDeferred = (model, handle, options) => lazyStream(model, async () => {
@@ -55,7 +55,7 @@ export function lazyApi(load, capabilities) {
55
55
  if (!implementation.fetchDeferred)
56
56
  throw new Error("API does not support deferred responses");
57
57
  return implementation.fetchDeferred(model, handle, options);
58
- });
58
+ }, options?.signal);
59
59
  }
60
60
  if (capabilities?.cancelDeferred) {
61
61
  api.cancelDeferred = async (model, handle, options) => {
@@ -382,7 +382,7 @@ class ModelsImpl {
382
382
  const provider = this.requireProvider(model);
383
383
  const { requestModel, requestOptions } = await this.applyAuth(model, options);
384
384
  return provider.stream(requestModel, context, requestOptions);
385
- });
385
+ }, options?.signal);
386
386
  }
387
387
  async complete(model, context, options) {
388
388
  return this.stream(model, context, options).result();
@@ -392,7 +392,7 @@ class ModelsImpl {
392
392
  const provider = this.requireProvider(model);
393
393
  const { requestModel, requestOptions } = await this.applyAuth(model, options);
394
394
  return provider.streamSimple(requestModel, context, requestOptions);
395
- });
395
+ }, options?.signal);
396
396
  }
397
397
  async completeSimple(model, context, options) {
398
398
  return this.streamSimple(model, context, options).result();
@@ -405,7 +405,7 @@ class ModelsImpl {
405
405
  }
406
406
  const { requestModel, requestOptions } = await this.applyAuth(model, options);
407
407
  return provider.fetchDeferred(requestModel, handle, requestOptions);
408
- }).result();
408
+ }, options?.signal).result();
409
409
  }
410
410
  async cancelDeferred(model, handle, options) {
411
411
  const provider = this.requireProvider(model);
@@ -498,7 +498,7 @@ export function createProvider(input) {
498
498
  throw new ModelsError("provider", `Provider ${input.id} does not support deferred responses for "${model.api}"`);
499
499
  }
500
500
  return implementation.fetchDeferred(model, handle, options);
501
- });
501
+ }, options?.signal);
502
502
  }
503
503
  if (streams.some((entry) => entry.cancelDeferred !== undefined)) {
504
504
  provider.cancelDeferred = async (model, handle, options) => {
@@ -1 +1 @@
1
- {"schemaVersion":3,"generatedAt":"2026-09-18T05:01:36.902Z","structureHash":"100dd436d3be7491785ad49fcaf0e315a6074db67be6b2256e0e23f64cd68f51","files":{"amazon-bedrock.json":"9d3eed9613b9b56f0c5f202a61b279a7168edf01bae6c3218a7ab28664ff80ea","ant-ling.json":"4979fe79d99ed97382d7ce40170c6132e932e77906de1eb54464c042e7d63633","anthropic.json":"6937a397c6c7cf654990d072734efad023b652b294b04961d43a5835d7d08156","azure-openai-responses.json":"787ba62322c46fbc69bc1fcb7c7cfc100b8f74211c72adf9766b6dbf5eae0c41","baseten.json":"c7cf9a7e7e6bee9c53005acf4706c25f954adaa64a9058535fb7e5b1d6920852","cerebras.json":"9eaa554e1b02f3665f8f63e6432d253bf81351af7c72001054dd8108aa528a52","cloudflare-ai-gateway.json":"356a2892803067a5d042c5abb87051edba46f7209589c625f8bcea8c7c5ce5c9","cloudflare-workers-ai.json":"07ef63208ff7517fd1a80962f18143e21de399640423329490b157f459ccf995","deepseek.json":"0dcc807a4e5827b488c6ceac87884ff6e735e01cf4f2ddfec9dd812e6fde041b","fireworks.json":"4c9055f7a2c5345b808bb561b07b227fc29148e0fb774c0ac50db2b34ab89aaf","github-copilot.json":"37cfc1da3a6814e37e14c565ed0a1e41f2eb513b10aa8f11ac18f27fa392308c","google-vertex.json":"e1631109172dc1f7d7977570420a5bb86258bdd1088427e244a2c51545c4f24d","google.json":"7619bf03edd2a7acb06a2274a14b13c3a61354288abe029a758401d4de36a8fd","groq.json":"e4728fd72e358cd8f25e9a518e9b49a521ef44523d3debe38a7db9e0663c4077","huggingface.json":"a488b6f175b382277ccf7d487f877ef0c698994576bb55d2410838bf9c8c7c41","kimi-coding.json":"9da7ea8e9eb8df5d8f73acc25d3da5b41164f522c0f09b45265b4bf104743ac1","minimax-cn.json":"65d37e55a6d9585855f94b3fb7739308d107fe248ebd9e1001d1c5d4606ad2c4","minimax.json":"c7dc5765995ae77242916430929c7cc9a782589f7e483e13f7e01663190d028e","mistral.json":"be522597b22bceeb0bb9a0ba1781647649ffd19637d0c8e67b056d7b0ec33d52","moonshotai-cn.json":"63f77de8782dce6a8d4649b6075ee04c9732863ae85561e0867871220c558bde","moonshotai.json":"2a8dfb97eb905e991c22081dc09bd4a61c05b7fa9ac0d5c72d6930f601f490f1","nvidia.json":"2ff6862206269af88a694e627c4b54753055357710adaf49ac8518d102c17407","openai-codex.json":"4a73818291987693fcb53e9e61b4be3429ffd78b3f64ea877a34c5f9928c89e1","openai.json":"6fa1954abd6c5b301620a02a57412bd60bbfdf20465b9a3eb4d113f88dfb8f7b","opencode-go.json":"31c4434316c8a1b7fcc637b25f1147dd44da946a0b932ca10fb5ac594261dad7","opencode.json":"aa960b0665d65bf2b441ffdb727dbb640074d5232470c06df237f03b5efeacb0","openrouter.json":"2b89edd669eeedfb0139ff1a9ec26eb980afd43aba93a9dd44a17fe5d0c7e748","qwen-token-plan-cn.json":"a50420854a624ea82155d9621cd88d6cbd7802498d28fb1fd317eb7a1bc26cc7","qwen-token-plan-individual.json":"0e1578a5c0e11d65644bb42d1d6efee5af97a55a4881d0421ab68bd970d4d4ef","qwen-token-plan.json":"24285f68b2350aa1d98ecaeafe0914bce97940fe8798eff20f2a5c6d8c26bd6f","together.json":"927c707d06f2236cdab13f14c870fb58bce0614ba7287bbcd57cc9fd66d191ed","vercel-ai-gateway.json":"e61d139444d16c7900a141d0bc9af874761794e80fb7d3ff4a08a21c3e93231f","xai.json":"282838b0546d63106c81f1703cdf5ed31ebfe0c5f13a4bec0d590472cbbe03f2","xiaomi-token-plan-ams.json":"7ce8ed244672c45737d286ff3ca9c3a2686a5d4b2f0c5f71ab9348c14b14daf3","xiaomi-token-plan-cn.json":"684892b5fe6fa371d6040d2011c0fa33facd650d2eaf19f5dbee8efb33016200","xiaomi-token-plan-sgp.json":"b19e79b82ac4fdcb080e6d220106797504c885ed70b27fc2b3c1aa4810f32963","xiaomi.json":"810368d3828c8bb9498012a0d48639030c0c216b8c13e79da02daa515aa23448","zai-coding-cn.json":"abf4cbc22507b9d545842072b5e34bce230025fc20f7b1cc67db3782c1dc4b56","zai.json":"089af736a622b0a25e417493819f4e174884afba43235c5a1f17814057875627"}}
1
+ {"schemaVersion":3,"generatedAt":"2026-09-20T03:25:28.719Z","structureHash":"b7ce3293a6e78f937e459db51021842a9b6fe649738f23b3eddb7263fe3137ec","files":{"amazon-bedrock.json":"9d3eed9613b9b56f0c5f202a61b279a7168edf01bae6c3218a7ab28664ff80ea","ant-ling.json":"4979fe79d99ed97382d7ce40170c6132e932e77906de1eb54464c042e7d63633","anthropic.json":"6937a397c6c7cf654990d072734efad023b652b294b04961d43a5835d7d08156","azure-openai-responses.json":"787ba62322c46fbc69bc1fcb7c7cfc100b8f74211c72adf9766b6dbf5eae0c41","baseten.json":"c7cf9a7e7e6bee9c53005acf4706c25f954adaa64a9058535fb7e5b1d6920852","cerebras.json":"9eaa554e1b02f3665f8f63e6432d253bf81351af7c72001054dd8108aa528a52","cloudflare-ai-gateway.json":"356a2892803067a5d042c5abb87051edba46f7209589c625f8bcea8c7c5ce5c9","cloudflare-workers-ai.json":"07ef63208ff7517fd1a80962f18143e21de399640423329490b157f459ccf995","deepseek.json":"0dcc807a4e5827b488c6ceac87884ff6e735e01cf4f2ddfec9dd812e6fde041b","fireworks.json":"4c9055f7a2c5345b808bb561b07b227fc29148e0fb774c0ac50db2b34ab89aaf","github-copilot.json":"37cfc1da3a6814e37e14c565ed0a1e41f2eb513b10aa8f11ac18f27fa392308c","google-vertex.json":"e1631109172dc1f7d7977570420a5bb86258bdd1088427e244a2c51545c4f24d","google.json":"7619bf03edd2a7acb06a2274a14b13c3a61354288abe029a758401d4de36a8fd","groq.json":"e4728fd72e358cd8f25e9a518e9b49a521ef44523d3debe38a7db9e0663c4077","huggingface.json":"a488b6f175b382277ccf7d487f877ef0c698994576bb55d2410838bf9c8c7c41","kimi-coding.json":"9da7ea8e9eb8df5d8f73acc25d3da5b41164f522c0f09b45265b4bf104743ac1","minimax-cn.json":"65d37e55a6d9585855f94b3fb7739308d107fe248ebd9e1001d1c5d4606ad2c4","minimax.json":"c7dc5765995ae77242916430929c7cc9a782589f7e483e13f7e01663190d028e","mistral.json":"be522597b22bceeb0bb9a0ba1781647649ffd19637d0c8e67b056d7b0ec33d52","moonshotai-cn.json":"63f77de8782dce6a8d4649b6075ee04c9732863ae85561e0867871220c558bde","moonshotai.json":"2a8dfb97eb905e991c22081dc09bd4a61c05b7fa9ac0d5c72d6930f601f490f1","nvidia.json":"2ff6862206269af88a694e627c4b54753055357710adaf49ac8518d102c17407","openai-codex.json":"4a73818291987693fcb53e9e61b4be3429ffd78b3f64ea877a34c5f9928c89e1","openai.json":"6fa1954abd6c5b301620a02a57412bd60bbfdf20465b9a3eb4d113f88dfb8f7b","opencode-go.json":"31c4434316c8a1b7fcc637b25f1147dd44da946a0b932ca10fb5ac594261dad7","opencode.json":"43c5d9cc6fab109411e6ac8eebac4b9fb0b00cff844cf0eb6c1559a08586525f","openrouter.json":"a6bb9631baf0a19685c1ad0c847c6ddf848ff5c7881d5bc62cc0ffeff45ec932","qwen-token-plan-cn.json":"a50420854a624ea82155d9621cd88d6cbd7802498d28fb1fd317eb7a1bc26cc7","qwen-token-plan-individual.json":"0e1578a5c0e11d65644bb42d1d6efee5af97a55a4881d0421ab68bd970d4d4ef","qwen-token-plan.json":"24285f68b2350aa1d98ecaeafe0914bce97940fe8798eff20f2a5c6d8c26bd6f","together.json":"927c707d06f2236cdab13f14c870fb58bce0614ba7287bbcd57cc9fd66d191ed","vercel-ai-gateway.json":"03b0830a794af1bc921fb504565534bedec660fcc9482adcf56ec5fb27703e60","xai.json":"282838b0546d63106c81f1703cdf5ed31ebfe0c5f13a4bec0d590472cbbe03f2","xiaomi-token-plan-ams.json":"7ce8ed244672c45737d286ff3ca9c3a2686a5d4b2f0c5f71ab9348c14b14daf3","xiaomi-token-plan-cn.json":"684892b5fe6fa371d6040d2011c0fa33facd650d2eaf19f5dbee8efb33016200","xiaomi-token-plan-sgp.json":"b19e79b82ac4fdcb080e6d220106797504c885ed70b27fc2b3c1aa4810f32963","xiaomi.json":"810368d3828c8bb9498012a0d48639030c0c216b8c13e79da02daa515aa23448","zai-coding-cn.json":"abf4cbc22507b9d545842072b5e34bce230025fc20f7b1cc67db3782c1dc4b56","zai.json":"089af736a622b0a25e417493819f4e174884afba43235c5a1f17814057875627"}}