@diffexai/diffex 0.3.0 → 0.3.2

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 (96) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/cli/args.d.ts +2 -0
  3. package/dist/cli/args.js +39 -0
  4. package/dist/core/agent-session-services.d.ts +1 -0
  5. package/dist/core/agent-session-services.js +1 -0
  6. package/dist/core/agent-session.d.ts +4 -5
  7. package/dist/core/agent-session.js +11 -62
  8. package/dist/core/compaction/branch-summarization.js +3 -2
  9. package/dist/core/compaction/compaction.js +9 -7
  10. package/dist/core/compaction/utils.d.ts +3 -0
  11. package/dist/core/compaction/utils.js +21 -0
  12. package/dist/core/current-plan-state.d.ts +3 -2
  13. package/dist/core/current-plan-state.js +23 -6
  14. package/dist/core/plan-snapshot.d.ts +3 -0
  15. package/dist/core/plan-snapshot.js +23 -0
  16. package/dist/core/sdk.d.ts +3 -0
  17. package/dist/core/sdk.js +1 -0
  18. package/dist/core/session-manager.js +21 -1
  19. package/dist/core/subagents/services.d.ts +2 -0
  20. package/dist/core/subagents/services.js +2 -0
  21. package/dist/core/tools/bash.js +47 -12
  22. package/dist/core/tools/update-plan.d.ts +27 -6
  23. package/dist/core/tools/update-plan.js +122 -18
  24. package/dist/index.d.ts +1 -0
  25. package/dist/main.js +4 -0
  26. package/dist/modes/interactive/components/footer.js +16 -5
  27. package/dist/modes/interactive/components/tool-group.d.ts +1 -0
  28. package/dist/modes/interactive/components/tool-group.js +26 -7
  29. package/dist/modes/print-mode.js +16 -13
  30. package/dist/node_modules/@diffexai/diffex-agent-core/dist/agent-loop.js +21 -3
  31. package/dist/node_modules/@diffexai/diffex-agent-core/dist/types.d.ts +17 -10
  32. package/dist/node_modules/@diffexai/diffex-agent-core/distribution-components.json +4 -4
  33. package/dist/node_modules/@diffexai/diffex-agent-core/distribution-files.json +3 -3
  34. package/dist/node_modules/@diffexai/diffex-agent-core/package.json +1 -1
  35. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/.manifest.json +1 -1
  36. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/amazon-bedrock.json +1 -1
  37. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/anthropic.json +1 -1
  38. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/azure-openai-responses.json +1 -1
  39. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/cerebras.json +1 -1
  40. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  41. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/cloudflare-workers-ai.json +1 -1
  42. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/fireworks.json +1 -1
  43. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/github-copilot.json +1 -1
  44. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/google-vertex.json +1 -1
  45. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/google.json +1 -1
  46. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/huggingface.json +1 -1
  47. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/minimax-cn.json +1 -1
  48. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/minimax.json +1 -1
  49. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/mistral.json +1 -1
  50. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/moonshotai-cn.json +1 -1
  51. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/moonshotai.json +1 -1
  52. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/nvidia.json +1 -1
  53. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/openai.json +1 -1
  54. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/opencode-go.json +1 -1
  55. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/opencode.json +1 -1
  56. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/openrouter.json +1 -1
  57. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/together.json +1 -1
  58. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  59. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xai.json +1 -1
  60. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  61. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  62. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  63. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/xiaomi.json +1 -1
  64. package/dist/node_modules/@diffexai/diffex-ai/distribution-components.json +3 -3
  65. package/dist/node_modules/@diffexai/diffex-ai/distribution-files.json +30 -30
  66. package/dist/node_modules/@diffexai/diffex-ai/package.json +1 -1
  67. package/dist/node_modules/@diffexai/diffex-client/distribution-components.json +3 -3
  68. package/dist/node_modules/@diffexai/diffex-client/distribution-files.json +1 -1
  69. package/dist/node_modules/@diffexai/diffex-client/package.json +1 -1
  70. package/dist/node_modules/@diffexai/diffex-harness-state/distribution-components.json +2 -2
  71. package/dist/node_modules/@diffexai/diffex-harness-state/distribution-files.json +1 -1
  72. package/dist/node_modules/@diffexai/diffex-harness-state/package.json +1 -1
  73. package/dist/node_modules/@diffexai/diffex-protocol/distribution-components.json +2 -2
  74. package/dist/node_modules/@diffexai/diffex-protocol/distribution-files.json +1 -1
  75. package/dist/node_modules/@diffexai/diffex-protocol/package.json +1 -1
  76. package/dist/node_modules/@diffexai/diffex-telemetry/distribution-components.json +2 -2
  77. package/dist/node_modules/@diffexai/diffex-telemetry/distribution-files.json +1 -1
  78. package/dist/node_modules/@diffexai/diffex-telemetry/package.json +1 -1
  79. package/dist/node_modules/@diffexai/diffex-tui/distribution-components.json +2 -2
  80. package/dist/node_modules/@diffexai/diffex-tui/distribution-files.json +1 -1
  81. package/dist/node_modules/@diffexai/diffex-tui/package.json +1 -1
  82. package/dist/utils/child-process.d.ts +5 -1
  83. package/dist/utils/child-process.js +9 -1
  84. package/dist/utils/owned-shell-processes.d.ts +23 -2
  85. package/dist/utils/owned-shell-processes.js +149 -39
  86. package/dist/utils/shell-process-identity.d.ts +11 -0
  87. package/dist/utils/shell-process-identity.js +61 -0
  88. package/dist/utils/shell.d.ts +1 -1
  89. package/dist/utils/shell.js +5 -5
  90. package/distribution-components.json +11 -11
  91. package/distribution-files.json +101 -85
  92. package/npm-shrinkwrap.json +2 -2
  93. package/package.json +1 -1
  94. package/release/distribution-manifest.json +4 -4
  95. package/release/install-package-lock.json +5 -5
  96. package/release/install-package.json +2 -2
@@ -7,6 +7,7 @@ export class ToolGroupComponent {
7
7
  pathOrigin;
8
8
  reusesLeadingGap;
9
9
  settled = false;
10
+ cachedRender;
10
11
  constructor(outputPad = 1, pathOrigin = "standalone", options = {}) {
11
12
  this.outputPad = outputPad;
12
13
  this.pathOrigin = pathOrigin;
@@ -18,13 +19,17 @@ export class ToolGroupComponent {
18
19
  return existing;
19
20
  }
20
21
  this.tools.set(toolCallId, component);
22
+ this.cachedRender = undefined;
21
23
  return component;
22
24
  }
23
25
  getTool(toolCallId) {
24
26
  return this.tools.get(toolCallId);
25
27
  }
26
28
  removeTool(toolCallId) {
27
- return this.tools.delete(toolCallId);
29
+ const removed = this.tools.delete(toolCallId);
30
+ if (removed)
31
+ this.cachedRender = undefined;
32
+ return removed;
28
33
  }
29
34
  replaceTools(tools) {
30
35
  this.tools.clear();
@@ -32,6 +37,7 @@ export class ToolGroupComponent {
32
37
  this.tools.delete(toolCallId);
33
38
  this.tools.set(toolCallId, component);
34
39
  }
40
+ this.cachedRender = undefined;
35
41
  }
36
42
  hasTools() {
37
43
  return this.tools.size > 0;
@@ -42,34 +48,43 @@ export class ToolGroupComponent {
42
48
  setPathOrigin(pathOrigin, options = {}) {
43
49
  this.pathOrigin = pathOrigin;
44
50
  this.reusesLeadingGap = pathOrigin === "standalone" && options.reuseLeadingGap === true;
51
+ this.cachedRender = undefined;
45
52
  }
46
53
  markSettled() {
47
54
  this.settled = true;
55
+ this.cachedRender = undefined;
48
56
  }
49
57
  setOutputPad(padding) {
50
58
  this.outputPad = padding;
59
+ this.cachedRender = undefined;
51
60
  }
52
61
  setExpanded(expanded) {
53
62
  for (const tool of this.tools.values()) {
54
63
  tool.setExpanded(expanded);
55
64
  }
65
+ this.cachedRender = undefined;
56
66
  }
57
67
  setShowImages(show) {
58
68
  for (const tool of this.tools.values()) {
59
69
  tool.setShowImages(show);
60
70
  }
71
+ this.cachedRender = undefined;
61
72
  }
62
73
  setImageWidthCells(width) {
63
74
  for (const tool of this.tools.values()) {
64
75
  tool.setImageWidthCells(width);
65
76
  }
77
+ this.cachedRender = undefined;
66
78
  }
67
79
  invalidate() {
68
80
  for (const tool of this.tools.values()) {
69
81
  tool.invalidate();
70
82
  }
83
+ this.cachedRender = undefined;
71
84
  }
72
85
  render(width) {
86
+ if (this.settled && this.cachedRender?.width === width)
87
+ return this.cachedRender.lines;
73
88
  const safeWidth = Math.max(1, width);
74
89
  const outputPad = Math.min(Math.max(0, this.outputPad), Math.max(0, safeWidth - 1));
75
90
  const outerRailWidth = safeWidth - outputPad > 1 ? 1 : 0;
@@ -87,12 +102,14 @@ export class ToolGroupComponent {
87
102
  }
88
103
  }
89
104
  if (renderedTools.length === 0) {
90
- if (this.pathOrigin !== "continued") {
91
- return [];
92
- }
93
- return this.settled
94
- ? new DiffexPathTerminus(outputPad).render(safeWidth)
95
- : new DiffexPathRail(outputPad).render(safeWidth);
105
+ const lines = this.pathOrigin !== "continued"
106
+ ? []
107
+ : this.settled
108
+ ? new DiffexPathTerminus(outputPad).render(safeWidth)
109
+ : new DiffexPathRail(outputPad).render(safeWidth);
110
+ if (this.settled)
111
+ this.cachedRender = { width, lines };
112
+ return lines;
96
113
  }
97
114
  const label = this.settled ? "Explored" : "Exploring";
98
115
  const continuesPath = this.pathOrigin === "continued";
@@ -118,6 +135,8 @@ export class ToolGroupComponent {
118
135
  result.push(visibleWidth(decoratedLine) > safeWidth ? truncateToWidth(decoratedLine, safeWidth, "") : decoratedLine);
119
136
  }
120
137
  }
138
+ if (this.settled)
139
+ this.cachedRender = { width, lines: result };
121
140
  return result;
122
141
  }
123
142
  }
@@ -18,19 +18,19 @@ export async function runPrintMode(runtimeHost, options) {
18
18
  let session = runtimeHost.session;
19
19
  let unsubscribe;
20
20
  let unsubscribeBackpressure;
21
- let disposed = false;
21
+ let disposePromise;
22
22
  let terminationStatus = "completed";
23
23
  const signalCleanupHandlers = [];
24
24
  const disposeRuntime = async (status = terminationStatus) => {
25
- if (disposed)
26
- return;
27
- disposed = true;
25
+ if (disposePromise)
26
+ return disposePromise;
28
27
  unsubscribe?.();
29
28
  unsubscribeBackpressure?.();
30
- await runtimeHost.dispose(status);
29
+ disposePromise = runtimeHost.dispose(status);
30
+ return disposePromise;
31
31
  };
32
32
  const registerSignalHandlers = () => {
33
- const signals = ["SIGTERM"];
33
+ const signals = ["SIGTERM", "SIGINT"];
34
34
  if (process.platform !== "win32") {
35
35
  signals.push("SIGHUP");
36
36
  }
@@ -39,7 +39,7 @@ export async function runPrintMode(runtimeHost, options) {
39
39
  killTrackedDetachedChildren();
40
40
  terminationStatus = "aborted";
41
41
  void disposeRuntime("aborted").finally(() => {
42
- process.exit(signal === "SIGHUP" ? 129 : 143);
42
+ process.exit(signal === "SIGHUP" ? 129 : signal === "SIGINT" ? 130 : 143);
43
43
  });
44
44
  };
45
45
  process.on(signal, handler);
@@ -133,12 +133,15 @@ export async function runPrintMode(runtimeHost, options) {
133
133
  return 1;
134
134
  }
135
135
  finally {
136
- for (const cleanup of signalCleanupHandlers) {
137
- cleanup();
136
+ try {
137
+ if (exitCode !== 0)
138
+ terminationStatus = "failed";
139
+ await disposeRuntime();
140
+ await flushRawStdout();
141
+ }
142
+ finally {
143
+ for (const cleanup of signalCleanupHandlers)
144
+ cleanup();
138
145
  }
139
- if (exitCode !== 0)
140
- terminationStatus = "failed";
141
- await disposeRuntime();
142
- await flushRawStdout();
143
146
  }
144
147
  }
@@ -460,11 +460,29 @@ async function failToolCallsFromTruncatedMessage(toolCalls, config, signal, emit
460
460
  */
461
461
  async function executeToolCalls(currentContext, assistantMessage, config, signal, emit) {
462
462
  const toolCalls = assistantMessage.content.filter((c) => c.type === "toolCall");
463
- const hasSequentialToolCall = toolCalls.some((tc) => currentContext.tools?.find((t) => t.name === tc.name)?.executionMode === "sequential");
464
- if (config.toolExecution === "sequential" || hasSequentialToolCall) {
463
+ if (config.toolExecution === "sequential") {
465
464
  return executeToolCallsSequential(currentContext, assistantMessage, toolCalls, config, signal, emit);
466
465
  }
467
- return executeToolCallsParallel(currentContext, assistantMessage, toolCalls, config, signal, emit);
466
+ const messages = [];
467
+ let terminate = true;
468
+ for (let index = 0; index < toolCalls.length;) {
469
+ if (signal?.aborted)
470
+ break;
471
+ const sequential = currentContext.tools?.find((tool) => tool.name === toolCalls[index].name)?.executionMode === "sequential";
472
+ let end = index + 1;
473
+ if (!sequential) {
474
+ while (end < toolCalls.length &&
475
+ currentContext.tools?.find((tool) => tool.name === toolCalls[end].name)?.executionMode !== "sequential") {
476
+ end++;
477
+ }
478
+ }
479
+ const executePhase = sequential ? executeToolCallsSequential : executeToolCallsParallel;
480
+ const phase = await executePhase(currentContext, assistantMessage, toolCalls.slice(index, end), config, signal, emit);
481
+ messages.push(...phase.messages);
482
+ terminate = terminate && phase.terminate;
483
+ index = end;
484
+ }
485
+ return { messages, terminate: messages.length > 0 && terminate };
468
486
  }
469
487
  async function executeToolCallsSequential(currentContext, assistantMessage, toolCalls, config, signal, emit) {
470
488
  const finalizedCalls = [];
@@ -16,9 +16,11 @@ export type StreamFn = (model: Model<Api>, context: Context, options?: SimpleStr
16
16
  * Configuration for how tool calls from a single assistant message are executed.
17
17
  *
18
18
  * - "sequential": each tool call is prepared, executed, and finalized before the next one starts.
19
- * - "parallel": tool calls are prepared sequentially, then allowed tools execute concurrently.
20
- * `tool_execution_end` is emitted in tool completion order after each tool is finalized,
21
- * while tool-result message artifacts are emitted later in assistant source order.
19
+ * - "parallel": consecutive parallel-capable calls form groups separated by individual
20
+ * tools declaring `executionMode: "sequential"`. Each group is prepared sequentially,
21
+ * then allowed tools execute concurrently. Completion events follow finalization order;
22
+ * tool-result message events follow assistant source order within each phase.
23
+ * Hooks and awaited events settle before the next phase is prepared.
22
24
  */
23
25
  export type ToolExecutionMode = "sequential" | "parallel";
24
26
  /**
@@ -237,9 +239,9 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
237
239
  /**
238
240
  * Tool execution mode.
239
241
  * - "sequential": execute tool calls one by one
240
- * - "parallel": preflight tool calls sequentially, then execute allowed tools concurrently;
241
- * emit `tool_execution_end` in tool completion order after each tool is finalized,
242
- * then emit tool-result message artifacts later in assistant source order
242
+ * - "parallel": execute consecutive parallel-capable calls concurrently, separated by
243
+ * sequential tool barriers. Preflight each phase sequentially and await execution,
244
+ * result hooks, completion events, and source-ordered result events before the next phase.
243
245
  *
244
246
  * Default: "parallel"
245
247
  */
@@ -250,6 +252,8 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
250
252
  * Return `{ block: true }` to prevent execution. The loop emits an error tool result instead.
251
253
  * A blocked result can also set `terminate: true` to participate in the batch early-termination rule.
252
254
  * The hook receives the agent abort signal and is responsible for honoring it.
255
+ * In parallel mode, preflight runs sequentially within the current phase, after all
256
+ * prior phases have settled. Sibling results within that phase are not yet available.
253
257
  */
254
258
  beforeToolCall?: (context: BeforeToolCallContext, signal?: AbortSignal) => Promise<BeforeToolCallResult | undefined>;
255
259
  /**
@@ -264,6 +268,8 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
264
268
  *
265
269
  * Any omitted fields keep their original values. No deep merge is performed.
266
270
  * The hook receives the agent abort signal and is responsible for honoring it.
271
+ * Parallel siblings can finalize concurrently. All hooks and awaited result events
272
+ * in the current phase settle before preflight begins for the next phase.
267
273
  */
268
274
  afterToolCall?: (context: AfterToolCallContext, signal?: AbortSignal) => Promise<AfterToolCallResult | undefined>;
269
275
  }
@@ -362,11 +368,12 @@ export interface AgentTool<TParameters extends TSchema = TSchema, TDetails = any
362
368
  /** Execute the tool call. Throw on failure instead of encoding errors in `content`. */
363
369
  execute: (toolCallId: string, params: Static<TParameters>, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<TDetails>) => Promise<AgentToolResult<TDetails>>;
364
370
  /**
365
- * Per-tool execution mode override.
366
- * - "sequential": this tool must execute one at a time with other tool calls.
367
- * - "parallel": this tool can execute concurrently with other tool calls.
371
+ * Per-tool scheduling metadata under global parallel execution.
372
+ * - "sequential": this call is an exclusive barrier in assistant source order.
373
+ * - "parallel": this call can execute concurrently within its consecutive group.
368
374
  *
369
- * If omitted, the default execution mode applies.
375
+ * Omitted metadata is parallel-capable. Global sequential execution always runs
376
+ * calls one by one, including tools explicitly declaring "parallel".
370
377
  */
371
378
  executionMode?: ToolExecutionMode;
372
379
  }
@@ -1,8 +1,8 @@
1
1
  [
2
2
  {
3
3
  "name": "@diffexai/diffex-agent-core",
4
- "version": "0.3.0",
5
- "sourceCommit": "c8cec4d3820393131eaae7b43d56ac5f75d8041a",
4
+ "version": "0.3.2",
5
+ "sourceCommit": "57dbba8a810d2e4cc81e48a30a4f5736e0e2d5bf",
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.3.0",
13
+ "version": "^0.3.2",
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.3.0",
18
+ "version": "^0.3.2",
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": "c8cec4d3820393131eaae7b43d56ac5f75d8041a",
2
+ "sourceCommit": "57dbba8a810d2e4cc81e48a30a4f5736e0e2d5bf",
3
3
  "algorithm": "sha256",
4
4
  "files": [
5
5
  {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  {
10
10
  "path": "dist/agent-loop.js",
11
- "sha256": "f9aeefb27c0391e02e3e39de475943b382afe83d948487597595faa8b3889a4d"
11
+ "sha256": "b1b846af2909c11fecd35a06cad1dd79c57a8c2ea8ea7240136d71169b4ecfa8"
12
12
  },
13
13
  {
14
14
  "path": "dist/agent.d.ts",
@@ -380,7 +380,7 @@
380
380
  },
381
381
  {
382
382
  "path": "dist/types.d.ts",
383
- "sha256": "076d88249087ecd918b2111dfa97ea485ac7f2874930f836fa05a9c28f45141a"
383
+ "sha256": "f64317c4ce1d3ccb8284e6eed635b5540f9a27dfbea94ce709eeed18b4625b28"
384
384
  },
385
385
  {
386
386
  "path": "dist/types.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diffexai/diffex-agent-core",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "General-purpose agent with transport abstraction, state management, and attachment support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1 +1 @@
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"}}
1
+ {"schemaVersion":3,"generatedAt":"2026-09-29T21:05:24.416Z","structureHash":"2fd45211a507dbf73974cbe675b576aeb2dfae490b569af9b3b90f9f601d7be5","files":{"amazon-bedrock.json":"1e0b4308b61f51c642616571d53efcca4aada249b20d220ca9068df7e5ea52fd","ant-ling.json":"4979fe79d99ed97382d7ce40170c6132e932e77906de1eb54464c042e7d63633","anthropic.json":"b2976a77dd2a3260d401918df7c523bd2124abae2382f7a67229829e2701d899","azure-openai-responses.json":"dfcc219adb7d04783861274cb94ac503b9a0d9f00a4e77c3637ebfc779ee5eb8","baseten.json":"c7cf9a7e7e6bee9c53005acf4706c25f954adaa64a9058535fb7e5b1d6920852","cerebras.json":"3be228c613905c215c9da3d0b3535e10cc594ff2351b05390744c7c34de89b6c","cloudflare-ai-gateway.json":"fac11bff507133190fcb7cb216656a8ad1b8d3b8c37c1b523a6d85f931b0cbda","cloudflare-workers-ai.json":"6012eb769382a5a9fa96ec5f429f6744848e377327c9063573a15006ef0652ce","deepseek.json":"0dcc807a4e5827b488c6ceac87884ff6e735e01cf4f2ddfec9dd812e6fde041b","fireworks.json":"f3e423850d1509690c0d8cfd4071bdb822f01a05e6d691032c309476edc8a927","github-copilot.json":"418a6da7c705b9043ffecc21597cb7d79bf80b6fb117f95a5a7675b68a032539","google-vertex.json":"97d80ac909d256cc1bf19ac54d9d8131c492e7c0c102ad89f68ade528544e0ad","google.json":"68f6cf6283cc0d69b77b0fa79e9c94774e96524f61ebba616319f05d5c9db56c","groq.json":"e4728fd72e358cd8f25e9a518e9b49a521ef44523d3debe38a7db9e0663c4077","huggingface.json":"2f93082144a7b2a1cbf79148244ce7559e0428d6310c5eb0648bca89b15a8b4b","kimi-coding.json":"9da7ea8e9eb8df5d8f73acc25d3da5b41164f522c0f09b45265b4bf104743ac1","minimax-cn.json":"4f636b47b28a507ad33b5eaba33fc4889e5956504d10f2a0d9c61167ae01ff1d","minimax.json":"9fd1764ffeefebded8579039cf0c48854a43e4c5b724f62361fc2ac54f705aa1","mistral.json":"9da97430d9b86ad7f606b0fc088694e7a04c38bfa8963a33e1205b3141c917eb","moonshotai-cn.json":"c1d6024d0095bb34e33847a3281692e8ddb7ddbb61748a0373cdab45f414d264","moonshotai.json":"08b8a7bbb30aa3a5ed077f02bd59ea5e9d32a1a8257e56d1606be8d722091783","nvidia.json":"6493e09b5db8b8fe9c8fae5bc15dc287645f37f83a4ed3a1ad1181e5830b5ff7","openai-codex.json":"4a73818291987693fcb53e9e61b4be3429ffd78b3f64ea877a34c5f9928c89e1","openai.json":"d8107710ade17d9c177b677135bf1ae88d6b884ee765cd64b74afe501f1f0844","opencode-go.json":"af32bbce67a5b2f705c43cd47e301e9fd4548bd3af03daaebb4b63bca864f9bc","opencode.json":"b3b709db64eb71505560758e36d287458280ce3d361d0d87ab5d616d6d6cf8a3","openrouter.json":"21dbdf7e09616dd36bfbf2121801cee9b8f68b5462e69c009bf1f665a2ba4002","qwen-token-plan-cn.json":"a50420854a624ea82155d9621cd88d6cbd7802498d28fb1fd317eb7a1bc26cc7","qwen-token-plan-individual.json":"0e1578a5c0e11d65644bb42d1d6efee5af97a55a4881d0421ab68bd970d4d4ef","qwen-token-plan.json":"24285f68b2350aa1d98ecaeafe0914bce97940fe8798eff20f2a5c6d8c26bd6f","together.json":"b4971d293e5be6b9acaf7b5d9aa588e6374e5317c116e98437128197c39a2fac","vercel-ai-gateway.json":"79ffb1b0c83cec8d26472ddc519ad6184eeb9cb1c960fd02c7dbf1473dcc5871","xai.json":"d036f5d1ececd7280c09ca1a6249553f39a7a1087ddb129a0d689a427fc944c4","xiaomi-token-plan-ams.json":"9581074003df2c31dbe483221dbbd1891e92d05102fcb816d51cbb22542174cf","xiaomi-token-plan-cn.json":"df9f18cca62ed29398124b3c9f50b157eea83c32167579a40ac129a3a673e4d6","xiaomi-token-plan-sgp.json":"5681a7eed774bc4b4e296cdae1a5028176b856b48af96cbd7776a03ba905aab1","xiaomi.json":"506eef7c189328cabce83768a48ec3e59c3f8a575f840d8ffcefa6966c340562","zai-coding-cn.json":"abf4cbc22507b9d545842072b5e34bce230025fc20f7b1cc67db3782c1dc4b56","zai.json":"089af736a622b0a25e417493819f4e174884afba43235c5a1f17814057875627"}}