@diffexai/diffex 0.3.0 → 0.3.1

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 (54) hide show
  1. package/CHANGELOG.md +17 -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 -0
  7. package/dist/core/agent-session.js +5 -1
  8. package/dist/core/sdk.d.ts +3 -0
  9. package/dist/core/sdk.js +1 -0
  10. package/dist/core/subagents/services.d.ts +2 -0
  11. package/dist/core/subagents/services.js +2 -0
  12. package/dist/core/tools/bash.js +47 -12
  13. package/dist/index.d.ts +1 -0
  14. package/dist/main.js +4 -0
  15. package/dist/modes/print-mode.js +16 -13
  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/providers/data/.manifest.json +1 -1
  20. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/opencode-go.json +1 -1
  21. package/dist/node_modules/@diffexai/diffex-ai/dist/providers/data/openrouter.json +1 -1
  22. package/dist/node_modules/@diffexai/diffex-ai/distribution-components.json +3 -3
  23. package/dist/node_modules/@diffexai/diffex-ai/distribution-files.json +4 -4
  24. package/dist/node_modules/@diffexai/diffex-ai/package.json +1 -1
  25. package/dist/node_modules/@diffexai/diffex-client/distribution-components.json +3 -3
  26. package/dist/node_modules/@diffexai/diffex-client/distribution-files.json +1 -1
  27. package/dist/node_modules/@diffexai/diffex-client/package.json +1 -1
  28. package/dist/node_modules/@diffexai/diffex-harness-state/distribution-components.json +2 -2
  29. package/dist/node_modules/@diffexai/diffex-harness-state/distribution-files.json +1 -1
  30. package/dist/node_modules/@diffexai/diffex-harness-state/package.json +1 -1
  31. package/dist/node_modules/@diffexai/diffex-protocol/distribution-components.json +2 -2
  32. package/dist/node_modules/@diffexai/diffex-protocol/distribution-files.json +1 -1
  33. package/dist/node_modules/@diffexai/diffex-protocol/package.json +1 -1
  34. package/dist/node_modules/@diffexai/diffex-telemetry/distribution-components.json +2 -2
  35. package/dist/node_modules/@diffexai/diffex-telemetry/distribution-files.json +1 -1
  36. package/dist/node_modules/@diffexai/diffex-telemetry/package.json +1 -1
  37. package/dist/node_modules/@diffexai/diffex-tui/distribution-components.json +2 -2
  38. package/dist/node_modules/@diffexai/diffex-tui/distribution-files.json +1 -1
  39. package/dist/node_modules/@diffexai/diffex-tui/package.json +1 -1
  40. package/dist/utils/child-process.d.ts +5 -1
  41. package/dist/utils/child-process.js +9 -1
  42. package/dist/utils/owned-shell-processes.d.ts +23 -2
  43. package/dist/utils/owned-shell-processes.js +149 -39
  44. package/dist/utils/shell-process-identity.d.ts +11 -0
  45. package/dist/utils/shell-process-identity.js +61 -0
  46. package/dist/utils/shell.d.ts +1 -1
  47. package/dist/utils/shell.js +5 -5
  48. package/distribution-components.json +11 -11
  49. package/distribution-files.json +53 -45
  50. package/npm-shrinkwrap.json +2 -2
  51. package/package.json +1 -1
  52. package/release/distribution-manifest.json +4 -4
  53. package/release/install-package-lock.json +5 -5
  54. package/release/install-package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.1] - 2026-09-20
4
+
5
+ ### New Features
6
+
7
+ - Added opt-in background services that survive CLI and subagent exit, with explicit environment ownership.
8
+ See [Background process lifetime](docs/background-processes.md) ([#242](https://github.com/diffexai/diffex/pull/242)).
9
+
10
+ ### Added
11
+
12
+ - Added CLI and SDK options for environment-owned background processes on Linux and macOS, with durable ownership records and inherited policy for child sessions.
13
+ See [Background process lifetime](docs/background-processes.md) ([#242](https://github.com/diffexai/diffex/pull/242)).
14
+
15
+ ### Fixed
16
+
17
+ - Fixed successful background services being terminated after ownership transfers to the environment, including on later failures, interruption, session replacement, and disposal ([#242](https://github.com/diffexai/diffex/pull/242)).
18
+ - Fixed print-mode shutdown to await shared runtime disposal and handle SIGINT cleanup ([#242](https://github.com/diffexai/diffex/pull/242)).
19
+
3
20
  ## [0.3.0] - 2026-09-20
4
21
 
5
22
  ### New Features
@@ -6,6 +6,8 @@ import type { ExtensionFlag } from "../core/extensions/types.ts";
6
6
  import type { TuiMode } from "../core/settings-manager.ts";
7
7
  export type Mode = "text" | "json" | "rpc";
8
8
  export interface Args {
9
+ backgroundProcessLifetime?: "session" | "environment";
10
+ backgroundProcessOwnershipDir?: string;
9
11
  provider?: string;
10
12
  model?: string;
11
13
  apiKey?: string;
package/dist/cli/args.js CHANGED
@@ -28,6 +28,29 @@ export function parseArgs(args) {
28
28
  result.mode = mode;
29
29
  }
30
30
  }
31
+ else if (arg === "--background-process-lifetime" || arg.startsWith("--background-process-lifetime=")) {
32
+ const value = arg.includes("=") ? arg.slice(arg.indexOf("=") + 1) : args[i + 1];
33
+ if (!arg.includes("=") && value !== undefined && !value.startsWith("-"))
34
+ i++;
35
+ if (value === "session" || value === "environment")
36
+ result.backgroundProcessLifetime = value;
37
+ else
38
+ result.diagnostics.push({
39
+ type: "error",
40
+ message: "--background-process-lifetime requires session or environment",
41
+ });
42
+ }
43
+ else if (arg === "--background-process-ownership-dir" ||
44
+ arg.startsWith("--background-process-ownership-dir=")) {
45
+ const value = arg.includes("=") ? arg.slice(arg.indexOf("=") + 1) : args[i + 1];
46
+ if (value && !value.startsWith("-")) {
47
+ result.backgroundProcessOwnershipDir = value;
48
+ if (!arg.includes("="))
49
+ i++;
50
+ }
51
+ else
52
+ result.diagnostics.push({ type: "error", message: "--background-process-ownership-dir requires a path" });
53
+ }
31
54
  else if (arg === "--continue" || arg === "-c") {
32
55
  result.continue = true;
33
56
  }
@@ -213,6 +236,18 @@ export function parseArgs(args) {
213
236
  result.messages.push(arg);
214
237
  }
215
238
  }
239
+ if (result.backgroundProcessLifetime === "environment" && !result.backgroundProcessOwnershipDir) {
240
+ result.diagnostics.push({
241
+ type: "error",
242
+ message: "Environment lifetime requires --background-process-ownership-dir",
243
+ });
244
+ }
245
+ if (result.backgroundProcessOwnershipDir && result.backgroundProcessLifetime !== "environment") {
246
+ result.diagnostics.push({
247
+ type: "error",
248
+ message: "--background-process-ownership-dir requires environment lifetime",
249
+ });
250
+ }
216
251
  return result;
217
252
  }
218
253
  export function printHelp(extensionFlags) {
@@ -248,6 +283,10 @@ ${chalk.bold("Options:")}
248
283
  --append-system-prompt <text> Append text or file contents to the system prompt (can be used multiple times)
249
284
  --mode <mode> Output mode: text (default), json, or rpc
250
285
  --print, -p Non-interactive mode: process prompt and exit
286
+ --background-process-lifetime <session|environment>
287
+ Background shell ownership (default: session)
288
+ --background-process-ownership-dir <path>
289
+ Supervisor handoff records (required for environment lifetime)
251
290
  --continue, -c Continue previous session
252
291
  --resume, -r Select a session to resume
253
292
  --session <path|id> Use specific session file or partial UUID
@@ -46,6 +46,7 @@ export interface CreateAgentSessionServicesOptions {
46
46
  * have been resolved against those services.
47
47
  */
48
48
  export interface CreateAgentSessionFromServicesOptions {
49
+ backgroundProcessPolicy?: CreateAgentSessionOptions["backgroundProcessPolicy"];
49
50
  services: AgentSessionServices;
50
51
  sessionManager: SessionManager;
51
52
  sessionStartEvent?: SessionStartEvent;
@@ -137,6 +137,7 @@ export async function createAgentSessionFromServices(options) {
137
137
  export async function createInternalAgentSessionFromServices(options, internalCustomTools = []) {
138
138
  registerSubagentRuntimeDiagnosticSink(options.sessionManager, options.services.diagnostics);
139
139
  return createInternalAgentSession({
140
+ backgroundProcessPolicy: options.backgroundProcessPolicy,
140
141
  cwd: options.services.cwd,
141
142
  agentDir: options.services.agentDir,
142
143
  modelRuntime: options.services.modelRuntime,
@@ -15,6 +15,7 @@
15
15
  import { type Agent, type AgentEvent, type AgentMessage, type AgentState, type AgentTool, type TelemetryContext, type ThinkingLevel } from "@diffexai/diffex-agent-core";
16
16
  import type { ImageContent, Model, TextContent } from "@diffexai/diffex-ai/compat";
17
17
  import type { HarnessStateStore, HarnessVersion, HarnessVersionBundle, HarnessVersionList, HarnessWorkspaceIdentity } from "@diffexai/diffex-harness-state";
18
+ import { type BackgroundProcessPolicy } from "../utils/owned-shell-processes.ts";
18
19
  import type { AgentSessionLifecycleObserver } from "./agent-session-lifecycle.ts";
19
20
  import { type BashResult } from "./bash-executor.ts";
20
21
  import { CHANGE_COLLABORATION_MODE, type CollaborationMode, type CollaborationModeTransitionResult, GET_COLLABORATION_MODE, IS_COLLABORATION_MODE_BUSY, SUBSCRIBE_PROMPT_ADMISSION } from "./collaboration-mode.ts";
@@ -135,6 +136,8 @@ export type AgentSessionEvent = Exclude<AgentEvent, {
135
136
  /** Listener function for agent session events */
136
137
  export type AgentSessionEventListener = (event: AgentSessionEvent) => void;
137
138
  export interface AgentSessionConfig {
139
+ /** Lifetime of background groups launched by successful local shell commands. */
140
+ backgroundProcessPolicy?: BackgroundProcessPolicy;
138
141
  agent: Agent;
139
142
  sessionManager: SessionManager;
140
143
  settingsManager: SettingsManager;
@@ -565,6 +568,7 @@ export declare class AgentSession {
565
568
  private _abort;
566
569
  /** Stop and verify all shell processes owned by this session, including background jobs. */
567
570
  terminateOwnedShellProcesses(): Promise<void>;
571
+ get backgroundProcessPolicy(): BackgroundProcessPolicy;
568
572
  get ownedShellProcessCount(): number;
569
573
  waitForIdle(): Promise<void>;
570
574
  private _emitModelSelect;
@@ -162,7 +162,7 @@ export class AgentSession {
162
162
  _bashAbortControllers = new Set();
163
163
  _pendingBashMessages = [];
164
164
  _ownedOperations = new Set();
165
- _shellProcesses = new OwnedShellProcesses();
165
+ _shellProcesses;
166
166
  _bashOperations = new Set();
167
167
  // Extension system
168
168
  _extensionRunner;
@@ -220,6 +220,7 @@ export class AgentSession {
220
220
  _agentRunAborted = false;
221
221
  _disposePromise;
222
222
  constructor(config) {
223
+ this._shellProcesses = new OwnedShellProcesses(config.backgroundProcessPolicy);
223
224
  this.agent = config.agent;
224
225
  this.sessionManager = config.sessionManager;
225
226
  this.settingsManager = config.settingsManager;
@@ -2401,6 +2402,9 @@ export class AgentSession {
2401
2402
  async terminateOwnedShellProcesses() {
2402
2403
  await this._shellProcesses.terminateAll();
2403
2404
  }
2405
+ get backgroundProcessPolicy() {
2406
+ return this._shellProcesses.policy;
2407
+ }
2404
2408
  get ownedShellProcessCount() {
2405
2409
  return this._shellProcesses.count;
2406
2410
  }
@@ -1,6 +1,7 @@
1
1
  import { type TelemetryContext, type ThinkingLevel } from "@diffexai/diffex-agent-core";
2
2
  import { type Model } from "@diffexai/diffex-ai/compat";
3
3
  import type { HarnessStateStore, HarnessVersionBundle } from "@diffexai/diffex-harness-state";
4
+ import type { BackgroundProcessPolicy } from "../utils/owned-shell-processes.ts";
4
5
  import { AgentSession } from "./agent-session.ts";
5
6
  import type { AgentSessionLifecycleObserver } from "./agent-session-lifecycle.ts";
6
7
  import type { LoadExtensionsResult, SessionStartEvent, ToolDefinition } from "./extensions/index.ts";
@@ -15,6 +16,8 @@ export interface SubagentOptions extends SubagentSupervisionOptions {
15
16
  maxConcurrent?: number;
16
17
  }
17
18
  export interface CreateAgentSessionOptions {
19
+ /** Local shell background lifetime. Defaults to session-owned cleanup. */
20
+ backgroundProcessPolicy?: BackgroundProcessPolicy;
18
21
  /** Working directory for project-local discovery. Default: process.cwd() */
19
22
  cwd?: string;
20
23
  /** Global config directory. Default: ~/.diffex/agent */
package/dist/core/sdk.js CHANGED
@@ -436,6 +436,7 @@ export async function createInternalAgentSession(options = {}, internalCustomToo
436
436
  sessionManager.appendThinkingLevelChange(thinkingLevel);
437
437
  }
438
438
  const session = new AgentSession({
439
+ backgroundProcessPolicy: options.backgroundProcessPolicy,
439
440
  agent,
440
441
  sessionManager,
441
442
  settingsManager,
@@ -1,6 +1,7 @@
1
1
  import type { TelemetryContext, ThinkingLevel } from "@diffexai/diffex-agent-core";
2
2
  import type { Model } from "@diffexai/diffex-ai";
3
3
  import type { HarnessStateStore, HarnessVersionBundle } from "@diffexai/diffex-harness-state";
4
+ import type { BackgroundProcessPolicy } from "../../utils/owned-shell-processes.ts";
4
5
  import type { AgentSession } from "../agent-session.ts";
5
6
  import { type AgentSessionServices } from "../agent-session-services.ts";
6
7
  import type { ModelRuntime } from "../model-runtime.ts";
@@ -19,6 +20,7 @@ export interface CreateSubagentServicesOptions {
19
20
  telemetryContext?: TelemetryContext;
20
21
  }
21
22
  export interface SubagentSessionConfig {
23
+ readonly backgroundProcessPolicy?: BackgroundProcessPolicy;
22
24
  readonly cwd: string;
23
25
  readonly agentDir: string;
24
26
  readonly modelRuntime: ModelRuntime;
@@ -39,6 +39,7 @@ export function captureSubagentSessionConfig(parent, agentDir) {
39
39
  .getActiveToolNames()
40
40
  .filter((name) => allToolNames.has(name) && toolsByName.get(name)?.sourceInfo.source === "builtin"));
41
41
  return Object.freeze({
42
+ backgroundProcessPolicy: parent.backgroundProcessPolicy,
42
43
  cwd: parent.sessionManager.getCwd(),
43
44
  agentDir,
44
45
  modelRuntime: parent.modelRuntime,
@@ -133,6 +134,7 @@ export async function createSubagentSession(config, options = {}) {
133
134
  markFixedHarnessSubagentSession(sessionManager);
134
135
  const { session } = await createInternalAgentSessionFromServices({
135
136
  services,
137
+ backgroundProcessPolicy: config.backgroundProcessPolicy,
136
138
  sessionManager,
137
139
  model: config.model,
138
140
  thinkingLevel: config.thinkingLevel,
@@ -1,3 +1,4 @@
1
+ import { randomUUID } from "node:crypto";
1
2
  import { constants } from "node:fs";
2
3
  import { access as fsAccess } from "node:fs/promises";
3
4
  import { Container, Text, truncateToWidth } from "@diffexai/diffex-tui";
@@ -8,6 +9,7 @@ import { truncateToVisualLines } from "../../modes/interactive/components/visual
8
9
  import { theme } from "../../modes/interactive/theme/theme.js";
9
10
  import { waitForChildProcess } from "../../utils/child-process.js";
10
11
  import { getShellConfig, getShellEnv, killProcessTree, trackDetachedChildPid, untrackDetachedChildPid, } from "../../utils/shell.js";
12
+ import { SHELL_EXECUTION_ID_ENV } from "../../utils/shell-process-identity.js";
11
13
  import { OutputAccumulator } from "./output-accumulator.js";
12
14
  import { getTextOutput, invalidArgText, str } from "./render-utils.js";
13
15
  import { wrapToolDefinition } from "./tool-definition-wrapper.js";
@@ -56,10 +58,11 @@ export function createLocalBashOperations(options) {
56
58
  }
57
59
  signal?.throwIfAborted();
58
60
  const commandFromStdin = shellConfig.commandTransport === "stdin";
61
+ const executionId = randomUUID();
59
62
  const child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {
60
63
  cwd,
61
64
  detached: process.platform !== "win32",
62
- env: env ?? getShellEnv(),
65
+ env: { ...(env ?? getShellEnv()), [SHELL_EXECUTION_ID_ENV]: executionId },
63
66
  stdio: [commandFromStdin ? "pipe" : "ignore", "pipe", "pipe"],
64
67
  windowsHide: true,
65
68
  });
@@ -67,25 +70,52 @@ export function createLocalBashOperations(options) {
67
70
  child.stdin?.on("error", () => { });
68
71
  child.stdin?.end(command);
69
72
  }
70
- if (child.pid) {
71
- if (options?.owner)
72
- options.owner.track(child.pid);
73
- else
74
- trackDetachedChildPid(child.pid);
75
- }
76
73
  let timedOut = false;
74
+ const environmentLifetime = options?.owner?.policy.lifetime === "environment";
75
+ let completed = false;
76
+ let completionError;
77
77
  let timeoutHandle;
78
78
  const onAbort = () => {
79
- if (child.pid)
80
- killProcessTree(child.pid);
79
+ if (child.pid) {
80
+ if (options?.owner)
81
+ options.owner.terminate(child.pid);
82
+ else
83
+ killProcessTree(child.pid);
84
+ }
81
85
  };
86
+ const onExit = (code) => {
87
+ completed = true;
88
+ if (environmentLifetime && timeoutHandle)
89
+ clearTimeout(timeoutHandle);
90
+ try {
91
+ if (child.pid)
92
+ options?.owner?.complete(child.pid, code === 0 && !timedOut && !signal?.aborted);
93
+ }
94
+ catch (error) {
95
+ completionError = error;
96
+ try {
97
+ onAbort();
98
+ }
99
+ catch (cleanupError) {
100
+ completionError = new AggregateError([error, cleanupError], "Shell ownership handoff failed");
101
+ }
102
+ }
103
+ };
104
+ child.once("exit", onExit);
82
105
  try {
106
+ if (child.pid) {
107
+ if (options?.owner)
108
+ options.owner.track(child.pid, executionId);
109
+ else
110
+ trackDetachedChildPid(child.pid);
111
+ }
83
112
  // Set timeout if provided.
84
113
  if (timeoutMs !== undefined) {
85
114
  timeoutHandle = setTimeout(() => {
115
+ if (environmentLifetime && completed)
116
+ return;
86
117
  timedOut = true;
87
- if (child.pid)
88
- killProcessTree(child.pid);
118
+ onAbort();
89
119
  }, timeoutMs);
90
120
  }
91
121
  // Stream stdout and stderr.
@@ -100,7 +130,11 @@ export function createLocalBashOperations(options) {
100
130
  }
101
131
  // Handle shell spawn errors and wait for the process to terminate without hanging
102
132
  // on inherited stdio handles held by detached descendants.
103
- const exitCode = await waitForChildProcess(child);
133
+ const exitCode = await waitForChildProcess(child, {
134
+ maxPostExitMs: environmentLifetime ? 100 : undefined,
135
+ });
136
+ if (completionError)
137
+ throw completionError;
104
138
  if (signal?.aborted) {
105
139
  throw new Error("aborted");
106
140
  }
@@ -110,6 +144,7 @@ export function createLocalBashOperations(options) {
110
144
  return { exitCode };
111
145
  }
112
146
  finally {
147
+ child.removeListener("exit", onExit);
113
148
  if (child.pid) {
114
149
  if (options?.owner)
115
150
  options.owner.releaseIfExited(child.pid);
package/dist/index.d.ts CHANGED
@@ -33,4 +33,5 @@ export { copyToClipboard } from "./utils/clipboard.ts";
33
33
  export { parseFrontmatter, stripFrontmatter } from "./utils/frontmatter.ts";
34
34
  export { convertToPng } from "./utils/image-convert.ts";
35
35
  export { formatDimensionNote, type ResizedImage, resizeImage } from "./utils/image-resize.ts";
36
+ export type { BackgroundProcessPolicy, ShellOwnershipRecord } from "./utils/owned-shell-processes.ts";
36
37
  export { getShellConfig } from "./utils/shell.ts";
package/dist/main.js CHANGED
@@ -439,6 +439,9 @@ export async function main(args, options) {
439
439
  : undefined;
440
440
  const trustPromptMode = parsed.help || parsed.listModels !== undefined ? "print" : appMode;
441
441
  const projectTrustByCwd = new Map();
442
+ const backgroundProcessPolicy = parsed.backgroundProcessLifetime === "environment"
443
+ ? { lifetime: "environment", ownershipDirectory: resolvePath(parsed.backgroundProcessOwnershipDir, cwd) }
444
+ : { lifetime: "session" };
442
445
  const resolvedExtensionPaths = resolveCliPaths(cwd, parsed.extensions);
443
446
  const resolvedSkillPaths = resolveCliPaths(cwd, parsed.skills);
444
447
  const resolvedPromptTemplatePaths = resolveCliPaths(cwd, parsed.promptTemplates);
@@ -530,6 +533,7 @@ export async function main(args, options) {
530
533
  }
531
534
  }
532
535
  const created = await createAgentSessionFromServices({
536
+ backgroundProcessPolicy,
533
537
  services,
534
538
  sessionManager,
535
539
  sessionStartEvent,
@@ -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
  }
@@ -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.1",
5
+ "sourceCommit": "9d59a28db4888b6824740505f0a16146667f036b",
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.1",
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.1",
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": "9d59a28db4888b6824740505f0a16146667f036b",
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.3.0",
3
+ "version": "0.3.1",
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-20T21:05:14.234Z","structureHash":"5ae57f6cf495fb2f4ede669bf128fd21195cd00e1fbb2c1e884764da807da5d2","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":"fa6d6737da943fbb9c36487cb4cd5bc152d1f2fd548280bbe9d35d0304e79f11","opencode.json":"43c5d9cc6fab109411e6ac8eebac4b9fb0b00cff844cf0eb6c1559a08586525f","openrouter.json":"a3375b66ad7b4bb61f22d867e132c991d3b9851436c529838c109b9794d59b93","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 +1 @@
1
- {"anthropic-messages":{"minimax-m3":{"id":"minimax-m3","name":"MiniMax-M3","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go","reasoning":true,"input":["text","image"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.47,"cacheRead":0.016,"cacheWrite":0.2},"contextWindow":1000000,"maxTokens":131072}},"openai-completions":{"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.15,"output":0.6,"cacheRead":0.003,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-flash-vision-exp":{"id":"deepseek-v4-flash-vision-exp","name":"DeepSeek V4 Flash Vision Exp","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.6,"cacheRead":0.003,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro (New)","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.66,"output":1.98,"cacheRead":0.022,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4.1-flash":{"id":"deepseek-v4.1-flash","name":"DeepSeek V4.1 Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.6,"cacheRead":0.003,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":202752,"maxTokens":32768},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5.3":{"id":"glm-5.3","name":"GLM-5.3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5.3-flash":{"id":"glm-5.3-flash","name":"GLM-5.3-Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.5,"cacheRead":0.03,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"hy3":{"id":"hy3","name":"Hy3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.14,"output":0.58,"cacheRead":0.035,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":256000,"maxTokens":128000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null}},"hy4-preview":{"id":"hy4-preview","name":"Hy4 preview","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.834,"output":2.501,"cacheRead":0.042,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1024000,"maxTokens":64000,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null}},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.16,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"thinkingFormat":"deepseek","supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},"contextWindow":262144,"maxTokens":65536,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null}},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.19,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":262144,"maxTokens":262144},"kimi-k3":{"id":"kimi-k3","name":"Kimi K3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}},"longcat-2.0":{"id":"longcat-2.0","name":"LongCat-2.0","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.006,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072},"mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo V2.5","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":128000},"mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo V2.5 Pro","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.003625,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":128000},"minimax-m2.7":{"id":"minimax-m2.7","name":"MiniMax-M2.7","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":204800,"maxTokens":131072},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.5,"output":3,"cacheRead":0.05,"cacheWrite":0.625},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"thinkingFormat":"qwen","maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":2.5,"output":7.5,"cacheRead":0.5,"cacheWrite":3.125},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.4,"output":1.6,"cacheRead":0.04,"cacheWrite":0.5},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.25,"cacheWrite":2.5},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null}}},"openai-responses":{"gpt-5.6-luna":{"id":"gpt-5.6-luna","name":"GPT-5.6 Luna","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":1.2,"cacheRead":0.02,"cacheWrite":0.25},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"grok-4.6":{"id":"grok-4.6","name":"Grok 4.6","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.5,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":500000,"maxTokens":500000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"muse-spark-1.2-contributor":{"id":"muse-spark-1.2-contributor","name":"Muse Spark 1.2 Contributor","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.2,"cacheRead":0.002,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"muse-spark-1.3-contributor":{"id":"muse-spark-1.3-contributor","name":"Muse Spark 1.3 Contributor","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.2,"cacheRead":0.002,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}}}}
1
+ {"anthropic-messages":{"minimax-m3":{"id":"minimax-m3","name":"MiniMax-M3","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go","reasoning":true,"input":["text","image"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0},"contextWindow":1000000,"maxTokens":131072},"qwen3.8-flash":{"id":"qwen3.8-flash","name":"Qwen3.8 Flash","api":"anthropic-messages","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.47,"cacheRead":0.016,"cacheWrite":0.2},"contextWindow":1000000,"maxTokens":131072}},"openai-completions":{"deepseek-v4-flash":{"id":"deepseek-v4-flash","name":"DeepSeek V4 Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.15,"output":0.6,"cacheRead":0.003,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-flash-vision-exp":{"id":"deepseek-v4-flash-vision-exp","name":"DeepSeek V4 Flash Vision Exp","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.6,"cacheRead":0.003,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4-pro":{"id":"deepseek-v4-pro","name":"DeepSeek V4 Pro (New)","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.66,"output":1.98,"cacheRead":0.022,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"deepseek-v4.1-flash":{"id":"deepseek-v4.1-flash","name":"DeepSeek V4.1 Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.6,"cacheRead":0.003,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},"contextWindow":1000000,"maxTokens":384000,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}},"glm-5.1":{"id":"glm-5.1","name":"GLM-5.1","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":202752,"maxTokens":32768},"glm-5.2":{"id":"glm-5.2","name":"GLM-5.2","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5.3":{"id":"glm-5.3","name":"GLM-5.3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":1.4,"output":4.4,"cacheRead":0.26,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"glm-5.3-flash":{"id":"glm-5.3-flash","name":"GLM-5.3-Flash","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.15,"output":0.5,"cacheRead":0.03,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}},"hy3":{"id":"hy3","name":"Hy3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.14,"output":0.58,"cacheRead":0.035,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":256000,"maxTokens":128000,"thinkingLevelMap":{"off":"none","minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null}},"hy4-preview":{"id":"hy4-preview","name":"Hy4 preview","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.834,"output":2.501,"cacheRead":0.042,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1024000,"maxTokens":64000,"thinkingLevelMap":{"off":"none","minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null}},"kimi-k2.6":{"id":"kimi-k2.6","name":"Kimi K2.6","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.16,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"thinkingFormat":"deepseek","supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false},"contextWindow":262144,"maxTokens":65536,"thinkingLevelMap":{"minimal":null,"low":null,"medium":null}},"kimi-k2.7-code":{"id":"kimi-k2.7-code","name":"Kimi K2.7 Code","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.95,"output":4,"cacheRead":0.19,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":262144,"maxTokens":262144},"kimi-k3":{"id":"kimi-k3","name":"Kimi K3","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":3,"output":15,"cacheRead":0.3,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}},"longcat-2.0":{"id":"longcat-2.0","name":"LongCat-2.0","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.006,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072},"mimo-v2.5":{"id":"mimo-v2.5","name":"MiMo V2.5","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.14,"output":0.28,"cacheRead":0.0028,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":128000},"mimo-v2.5-pro":{"id":"mimo-v2.5-pro","name":"MiMo V2.5 Pro","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.435,"output":0.87,"cacheRead":0.003625,"cacheWrite":0},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1048576,"maxTokens":128000},"minimax-m2.7":{"id":"minimax-m2.7","name":"MiniMax-M2.7","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":0.3,"output":1.2,"cacheRead":0.06,"cacheWrite":0.375},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":204800,"maxTokens":131072},"qwen3.6-plus":{"id":"qwen3.6-plus","name":"Qwen3.6 Plus","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.5,"output":3,"cacheRead":0.05,"cacheWrite":0.625},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"thinkingFormat":"qwen","maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-max":{"id":"qwen3.7-max","name":"Qwen3.7 Max","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text"],"cost":{"input":2.5,"output":7.5,"cacheRead":0.5,"cacheWrite":3.125},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536},"qwen3.7-plus":{"id":"qwen3.7-plus","name":"Qwen3.7 Plus","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.4,"output":1.6,"cacheRead":0.04,"cacheWrite":0.5},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":65536},"qwen3.8-max":{"id":"qwen3.8-max","name":"Qwen3.8 Max","api":"openai-completions","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.25,"cacheWrite":2.5},"compat":{"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},"contextWindow":1000000,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":null,"xhigh":"xhigh","max":null}}},"openai-responses":{"gpt-5.6-luna":{"id":"gpt-5.6-luna","name":"GPT-5.6 Luna","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.2,"output":1.2,"cacheRead":0.02,"cacheWrite":0.25},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1050000,"maxTokens":128000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}},"grok-4.6":{"id":"grok-4.6","name":"Grok 4.6","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":2,"output":6,"cacheRead":0.5,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":500000,"maxTokens":500000,"thinkingLevelMap":{"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"muse-spark-1.2-contributor":{"id":"muse-spark-1.2-contributor","name":"Muse Spark 1.2 Contributor","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.2,"cacheRead":0.002,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}},"muse-spark-1.3-contributor":{"id":"muse-spark-1.3-contributor","name":"Muse Spark 1.3 Contributor","api":"openai-responses","provider":"opencode-go","baseUrl":"https://opencode.ai/zen/go/v1","reasoning":true,"input":["text","image"],"cost":{"input":0.1,"output":0.2,"cacheRead":0.002,"cacheWrite":0},"compat":{"sessionAffinityFormat":"openai-nosession"},"contextWindow":1048576,"maxTokens":131072,"thinkingLevelMap":{"off":null,"minimal":"minimal","low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":null}}}}