@openclaw/codex 2026.9.1-beta.1 → 2026.9.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 (73) hide show
  1. package/dist/api.js +5 -6
  2. package/dist/{attempt-client-cleanup-bfsmcQ6m.js → attempt-client-cleanup-DYHcRQAa.js} +31 -45
  3. package/dist/attempt-context-DmQUNWwT.js +634 -0
  4. package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
  5. package/dist/{binding-connection-BMvPX73o.js → binding-connection-E6uDsPlx.js} +2 -2
  6. package/dist/{bounded-turn-B7iBUcuP.js → bounded-turn-wzJrwKKe.js} +15 -20
  7. package/dist/{capabilities-BRMh0aIq.js → capabilities-dIjNVCYH.js} +1 -1
  8. package/dist/cli-metadata.js +1 -1
  9. package/dist/{command-formatters-DEsIufkt.js → command-formatters-CLHhEB1Q.js} +5 -4
  10. package/dist/{command-handlers-D_-1_qRp.js → command-handlers-CTGb2csu.js} +124 -101
  11. package/dist/{compact-BglNFZrQ.js → compact-_t0HQrUS.js} +38 -29
  12. package/dist/{config-giW8X0QA.js → config-BhmfC1s6.js} +294 -282
  13. package/dist/{context-compaction-activity-BOeJf7yo.js → context-compaction-activity-CMla5FPJ.js} +4 -1
  14. package/dist/{conversation-binding-data-CW2GuupV.js → conversation-binding-data-BiodpIzq.js} +2 -1
  15. package/dist/doctor-contract-api.js +143 -12
  16. package/dist/{dynamic-tools-Dnlfa--w.js → dynamic-tools-BU9tmlYm.js} +599 -655
  17. package/dist/{effective-mcp-catalog-CTeGrnfO.js → effective-mcp-catalog-DzYBW4h1.js} +2 -2
  18. package/dist/{event-projector-assistant-message-C5-Ds8mA.js → event-projector-assistant-message-DHRFXKbS.js} +4 -4
  19. package/dist/{event-projector-usage-Bk1I90Bg.js → event-projector-usage-C5mcrGjp.js} +15 -148
  20. package/dist/{harness-Csz0F-DK.js → harness-DXVZ5II5.js} +42 -52
  21. package/dist/harness.js +1 -1
  22. package/dist/index.js +458 -404
  23. package/dist/{isolated-completion-Cv6FqygM.js → isolated-completion-kg9kv4iH.js} +4 -4
  24. package/dist/launch-args-RXQwn8zV.js +90 -0
  25. package/dist/{managed-binary-DFYK4DWq.js → managed-binary-4-Vjz5GH.js} +14 -9
  26. package/dist/media-understanding-provider.js +1 -1
  27. package/dist/model-catalog-CUM68Hkl.js +101 -0
  28. package/dist/{models-TS3HBU-q.js → models-sYnEc0gd.js} +25 -28
  29. package/dist/{native-subagent-monitor-4Mfq2HDs.js → native-subagent-monitor-CnH147jH.js} +55 -115
  30. package/dist/{node-exec-server.runtime-BpWqJO1V.js → node-exec-server.runtime-CstNHCmC.js} +9 -6
  31. package/dist/{plugin-approval-roundtrip-bUm777tR.js → plugin-approval-roundtrip-CNe-Xrjx.js} +30 -3
  32. package/dist/{plugin-marketplace-discovery-B9DvaAG-.js → plugin-marketplace-discovery-CfFlKqDl.js} +15 -14
  33. package/dist/{plugin-metadata-cache-CTCT3w5L.js → plugin-metadata-cache-BFrPhb2c.js} +6 -6
  34. package/dist/provider-capabilities-DW5p4k9w.js +101 -0
  35. package/dist/{rate-limits-C5_D8Gmb.js → rate-limits-CawQJfUS.js} +3 -2
  36. package/dist/{sandbox-guard-kuWTn9C5.js → request-DYAI5FQE.js} +195 -2
  37. package/dist/{run-attempt-DYc0QCBF.js → run-attempt-D1hJO4fX.js} +828 -2100
  38. package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-C3jVimFn.js} +21 -14
  39. package/dist/{session-binding-Bcynfd-_.js → session-binding-BHuTCRZQ.js} +198 -127
  40. package/dist/{session-catalog-DaLKVtpH.js → session-catalog-yyvTWFOw.js} +564 -408
  41. package/dist/{session-cli-DMc4oS2w.js → session-cli-CmFEXMAM.js} +1 -1
  42. package/dist/session-history-C5J1AKzG.js +87 -0
  43. package/dist/session-initialization-BeWzjGiR.js +74 -0
  44. package/dist/{session-permission-policy-BrNH1bjy.js → session-permission-policy-DeWVTCMj.js} +2 -2
  45. package/dist/session-retirement-BujDjXVF.js +97 -0
  46. package/dist/{session-upstream-marker-BIkusb95.js → session-upstream-marker-C351-5Qw.js} +19 -4
  47. package/dist/settled-turn-context-D3SNWtUn.js +268 -0
  48. package/dist/settled-turn-finalizer-BVJx4yoc.js +104 -0
  49. package/dist/{shared-client-DKz23hHY.js → shared-client-DxcfF9KX.js} +3480 -679
  50. package/dist/{side-question-DjA_jsNe.js → side-question-BTZAII4l.js} +108 -70
  51. package/dist/{thread-lifecycle-L7oEkTlq.js → thread-lifecycle-DAcEJ_Om.js} +2188 -1915
  52. package/dist/{thread-ownership-DZeuKH1j.js → thread-ownership-zGokd8i1.js} +25 -14
  53. package/dist/thread-policy-g4KbJPzp.js +54 -0
  54. package/dist/{plugin-app-cache-key-C1CAdfcP.js → thread-resume-C7pyVKeW.js} +59 -7
  55. package/dist/{transcript-mirror-DsCMWBca.js → transcript-mirror-DTUxFWa_.js} +79 -17
  56. package/dist/transport-stdio-CyPldczm.js +726 -0
  57. package/dist/{upstream-prompt-provenance-CFmsKwr9.js → upstream-prompt-provenance-LphB8slG.js} +8 -4
  58. package/dist/upstream-session-fork-CYlBIGVt.js +966 -0
  59. package/dist/{usage-ROIaW3wo.js → usage-Bj-rrzkR.js} +3 -3
  60. package/dist/{web-search-provider.runtime-ClaNPV7N.js → web-search-provider.runtime-D2FWSK4w.js} +3 -3
  61. package/openclaw.plugin.json +1 -30
  62. package/package.json +6 -6
  63. package/dist/command-rpc-CCeCkf_v.js +0 -90
  64. package/dist/incognito-session-ET_ufDH-.js +0 -2
  65. package/dist/model-catalog-i9rNBthX.js +0 -48
  66. package/dist/protocol-validators-VeJxxJ0U.js +0 -2421
  67. package/dist/request-DXXGHko0.js +0 -157
  68. package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
  69. package/dist/session-retirement-CcNC3YSY.js +0 -36
  70. package/dist/settled-turn-finalizer-Dc3ApjU4.js +0 -328
  71. package/dist/thread-resume-BE9qNEW0.js +0 -30
  72. package/dist/transport-stdio-DhoGy33Z.js +0 -99
  73. package/dist/upstream-session-fork-DlaHxSLC.js +0 -326
@@ -1,58 +1,142 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { S as resolveCodexAppServerUserHomeDir, a as resolveCodexAppServerStartOptionsForAgent, i as resolveCodexAppServerRuntimeOptions, o as resolveCodexComputerUseConfig, t as codexAppServerStartOptionsKey } from "./config-giW8X0QA.js";
3
- import { a as CODEX_APP_SERVER_VERSION, c as resolveMacOSDesktopCodexAppPathCandidates, l as resolveMacOSDesktopCodexBundledMarketplaceCandidates, n as resolveManagedCodexAppServerStartOptions, o as MIN_SUPPORTED_CODEX_APP_SERVER_VERSION, r as resolveManagedCodexNativeCommand, s as resolveFirstExistingMacOSDesktopCodexBundledMarketplacePath, t as isManagedCodexDesktopCommand, u as resolveMacOSDesktopCodexComputerUseServiceAppCandidates } from "./managed-binary-DFYK4DWq.js";
4
- import { o as isCodexAppServerNativeAuthProfile } from "./session-binding-Bcynfd-_.js";
5
- import { n as resolveCodexAppServerSpawnEnv, t as createStdioTransport } from "./transport-stdio-DhoGy33Z.js";
2
+ import { t as isCodexAppServerProxyLaunch } from "./launch-args-RXQwn8zV.js";
3
+ import { F as resolveCodexAppServerHomeDir, I as resolveCodexAppServerLocalHomeDir, L as resolveCodexAppServerUserHomeDir, R as withEphemeralCodexAuthStore, a as resolveCodexAppServerStartOptionsForAgent, i as resolveCodexAppServerRuntimeOptions, o as resolveCodexComputerUseConfig, t as codexAppServerStartOptionsKey } from "./config-BhmfC1s6.js";
4
+ import { c as resolveFirstExistingMacOSDesktopCodexBundledMarketplacePath, d as resolveMacOSDesktopCodexComputerUseServiceAppCandidates, l as resolveMacOSDesktopCodexAppPathCandidates, n as resolveManagedCodexAppServerStartOptions, o as CODEX_APP_SERVER_VERSION, r as resolveManagedCodexNativeCommand, s as MIN_SUPPORTED_CODEX_APP_SERVER_VERSION, t as isManagedCodexDesktopCommand, u as resolveMacOSDesktopCodexBundledMarketplaceCandidates } from "./managed-binary-4-Vjz5GH.js";
5
+ import { o as isCodexAppServerNativeAuthProfile } from "./session-binding-BHuTCRZQ.js";
6
+ import { a as hasCodexAppServerNaturalExit, i as closeCodexAppServerTransportAndWait, n as resolveCodexAppServerSpawnEnv, r as closeCodexAppServerTransport, t as createStdioTransport } from "./transport-stdio-CyPldczm.js";
6
7
  import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
8
  import fs from "node:fs/promises";
8
9
  import path from "node:path";
9
10
  import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
10
- import { addTimerTimeoutGraceMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
11
- import { AgentHarnessPreflightError, OPENCLAW_VERSION, embeddedAgentLog, formatErrorMessage } from "openclaw/plugin-sdk/agent-harness-runtime";
11
+ import { addTimerTimeoutGraceMs, parseStrictNonNegativeInteger, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
12
+ import { AgentHarnessPreflightError, OPENCLAW_VERSION, embeddedAgentLog, formatErrorMessage, formatToolExecutionErrorMessage, normalizeQuestionTimeoutSeconds, resolveToolExecutionErrorKind } from "openclaw/plugin-sdk/agent-harness-runtime";
13
+ import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
14
+ import { createZstdDecompress } from "node:zlib";
15
+ import { root } from "openclaw/plugin-sdk/file-access-runtime";
12
16
  import { createHash, randomUUID } from "node:crypto";
13
- import fsSync, { constants, existsSync, watch } from "node:fs";
17
+ import fsSync, { constants as constants$1, existsSync, watch } from "node:fs";
14
18
  import os from "node:os";
15
19
  import { isDeepStrictEqual } from "node:util";
16
- import { ensureAuthProfileStore, findPersistedAuthProfileCredential, loadAuthProfileStoreForSecretsRuntime, refreshOAuthCredentialForRuntime, resolveApiKeyForProfile, resolveAuthProfileOrder, resolveDefaultAgentDir, resolvePersistedAuthProfileOwnerAgentDir, resolveProviderIdForAuth } from "openclaw/plugin-sdk/agent-runtime";
17
- import { hasUsableOAuthCredential, resolveOpenAICodexAuthIdentity } from "openclaw/plugin-sdk/provider-auth";
20
+ import { ensureAuthProfileStore, findPersistedAuthProfileCredential, loadAuthProfileStoreForSecretsRuntime, refreshOAuthCredentialForRuntime, resolveApiKeyForProfile, resolveDefaultAgentDir, resolvePersistedAuthProfileOwnerAgentDir, resolveProviderIdForAuth } from "openclaw/plugin-sdk/agent-runtime";
21
+ import { hasUsableOAuthCredential, resolveAuthProfileOrder, resolveOpenAICodexAuthIdentity } from "openclaw/plugin-sdk/provider-auth";
18
22
  import { readSecretFile } from "openclaw/plugin-sdk/secret-file";
19
23
  import { assertNoSymlinkParents, withTimeout } from "openclaw/plugin-sdk/security-runtime";
20
24
  import { runExec } from "openclaw/plugin-sdk/process-runtime";
21
- import { execFile } from "node:child_process";
25
+ import { EventEmitter } from "node:events";
22
26
  import { createInterface } from "node:readline";
23
27
  import { coerceErrorMessage, toStringifiedError } from "openclaw/plugin-sdk/error-runtime";
24
28
  import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
25
29
  import { parse } from "semver";
26
- import { EventEmitter } from "node:events";
30
+ import { hasPendingInternalDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
31
+ import { Compile } from "typebox/compile";
27
32
  import net from "node:net";
28
33
  import { PassThrough, Writable } from "node:stream";
29
34
  import { StringDecoder } from "node:string_decoder";
30
35
  import WebSocket from "ws";
31
- //#region extensions/codex/src/app-server/auth-start-options.ts
32
- const CODEX_APP_SERVER_HOME_DIRNAME = "codex-home";
33
- const CODEX_EPHEMERAL_AUTH_STORE_OVERRIDE = "cli_auth_credentials_store=\"ephemeral\"";
34
- function resolveCodexAppServerHomeDir(agentDir) {
35
- return path.join(path.resolve(agentDir), CODEX_APP_SERVER_HOME_DIRNAME);
36
- }
37
- /** Resolves the local CODEX_HOME used when starting one app-server connection. */
38
- function resolveCodexAppServerLocalHomeDir(startOptions, agentDir, env = process.env) {
39
- const configured = startOptions.env?.CODEX_HOME;
40
- if (configured?.trim()) return configured;
41
- return startOptions.homeScope === "user" ? resolveCodexAppServerUserHomeDir(env) : resolveCodexAppServerHomeDir(agentDir);
42
- }
43
- /** Forces OpenClaw-owned Codex auth to remain process-local. */
44
- function withEphemeralCodexAuthStore(params) {
45
- const { startOptions } = params;
46
- if (!(startOptions.commandSource === "managed" || startOptions.commandSource === "resolved-managed") || !params.preparedAuth && params.authProfileId === null) return startOptions;
47
- if (startOptions.args.at(-2) === "-c" && startOptions.args.at(-1) === CODEX_EPHEMERAL_AUTH_STORE_OVERRIDE) return startOptions;
48
- return {
49
- ...startOptions,
50
- args: [
51
- ...startOptions.args,
52
- "-c",
53
- CODEX_EPHEMERAL_AUTH_STORE_OVERRIDE
54
- ]
55
- };
36
+ //#region extensions/codex/src/app-server/protocol.ts
37
+ /** Namespace Codex keeps directly model-visible without exposing it to Code Mode guests. */
38
+ const CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE = "openclaw_direct";
39
+ function flattenCodexDynamicToolFunctions(tools) {
40
+ return (tools ?? []).flatMap((tool) => tool.type === "namespace" ? tool.tools : [tool]);
41
+ }
42
+ const CODEX_INTERACTIVE_THREAD_SOURCE_KINDS = ["cli", "vscode"];
43
+ const CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES = ["atlas", "chatgpt"];
44
+ function isJsonObject(value) {
45
+ return isRecord(value);
46
+ }
47
+ function isRpcResponse(message) {
48
+ return "id" in message && !("method" in message);
49
+ }
50
+ //#endregion
51
+ //#region extensions/codex/src/session-catalog-provenance.ts
52
+ const MAX_SESSION_META_BYTES = 1048576;
53
+ const SESSION_META_READ_CHUNK_BYTES = 65536;
54
+ const MAX_PROVENANCE_CACHE_ENTRIES = 2e4;
55
+ const provenanceByPath = /* @__PURE__ */ new Map();
56
+ function cacheProvenance(key, value) {
57
+ provenanceByPath.delete(key);
58
+ provenanceByPath.set(key, value);
59
+ while (provenanceByPath.size > MAX_PROVENANCE_CACHE_ENTRIES) {
60
+ const oldest = provenanceByPath.keys().next().value;
61
+ if (oldest === void 0) break;
62
+ provenanceByPath.delete(oldest);
63
+ }
64
+ }
65
+ /** Undefined means the metadata line is not durable enough to cache yet. */
66
+ async function readCodexSessionMeta(sessionsRoot, rolloutPath, threadId) {
67
+ let safeRoot;
68
+ try {
69
+ safeRoot = await root(sessionsRoot, {
70
+ hardlinks: "reject",
71
+ maxBytes: Number.MAX_SAFE_INTEGER,
72
+ symlinks: "reject"
73
+ });
74
+ } catch {
75
+ return;
76
+ }
77
+ const candidates = rolloutPath.endsWith(".zst") ? [rolloutPath, rolloutPath.slice(0, -4)] : [rolloutPath, `${rolloutPath}.zst`];
78
+ for (const candidate of candidates) {
79
+ let opened;
80
+ try {
81
+ opened = await safeRoot.open(path.relative(sessionsRoot, candidate));
82
+ } catch {
83
+ continue;
84
+ }
85
+ const input = opened.handle.createReadStream({
86
+ autoClose: false,
87
+ highWaterMark: SESSION_META_READ_CHUNK_BYTES
88
+ });
89
+ const reader = candidate.endsWith(".zst") ? input.pipe(createZstdDecompress()) : input;
90
+ try {
91
+ const chunks = [];
92
+ let bytesReadTotal = 0;
93
+ let line;
94
+ for await (const value of reader) {
95
+ const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
96
+ const remaining = MAX_SESSION_META_BYTES - bytesReadTotal;
97
+ if (remaining <= 0) break;
98
+ const bounded = chunk.subarray(0, remaining);
99
+ bytesReadTotal += bounded.length;
100
+ const newline = bounded.indexOf(10);
101
+ chunks.push(newline >= 0 ? bounded.subarray(0, newline) : bounded);
102
+ if (newline >= 0) {
103
+ line = Buffer.concat(chunks).toString("utf8");
104
+ break;
105
+ }
106
+ }
107
+ if (!line) continue;
108
+ let parsed;
109
+ try {
110
+ parsed = JSON.parse(line);
111
+ } catch {
112
+ continue;
113
+ }
114
+ if (!isJsonObject(parsed) || parsed.type !== "session_meta" || !isJsonObject(parsed.payload)) return null;
115
+ const payload = parsed.payload;
116
+ return payload.id === threadId ? payload : null;
117
+ } catch {
118
+ continue;
119
+ } finally {
120
+ reader.destroy();
121
+ input.destroy();
122
+ await opened.handle.close().catch(() => void 0);
123
+ }
124
+ }
125
+ }
126
+ /**
127
+ * Codex 0.147 reports OpenClaw app-server rollouts as `vscode`, so the rollout's
128
+ * immutable session metadata is the authoritative historical provenance.
129
+ */
130
+ async function isOpenClawManagedCodexThread(thread, localSessionsRoot) {
131
+ const rolloutPath = typeof thread.path === "string" ? thread.path.trim() : "";
132
+ if (!localSessionsRoot || !rolloutPath) return false;
133
+ const cacheKey = `${localSessionsRoot}\0${rolloutPath}`;
134
+ const cached = provenanceByPath.get(cacheKey);
135
+ if (cached !== void 0) return cached;
136
+ const metadata = await readCodexSessionMeta(localSessionsRoot, rolloutPath, thread.id);
137
+ const managed = metadata === void 0 ? void 0 : metadata?.originator === "openclaw";
138
+ if (managed !== void 0) cacheProvenance(cacheKey, managed);
139
+ return managed ?? false;
56
140
  }
57
141
  //#endregion
58
142
  //#region extensions/codex/src/app-server/computer-use-service-path.ts
@@ -713,7 +797,7 @@ function identitiesMatch(left, right) {
713
797
  }
714
798
  async function hasExecutableClient(appPath) {
715
799
  try {
716
- await fs.access(path.join(appPath, CLIENT_RELATIVE_PATH), constants.X_OK);
800
+ await fs.access(path.join(appPath, CLIENT_RELATIVE_PATH), constants$1.X_OK);
717
801
  return true;
718
802
  } catch {
719
803
  return false;
@@ -814,21 +898,6 @@ async function copyServiceAppWithDitto(sourcePath, targetPath) {
814
898
  });
815
899
  }
816
900
  //#endregion
817
- //#region extensions/codex/src/app-server/protocol.ts
818
- /** Namespace Codex keeps directly model-visible without exposing it to Code Mode guests. */
819
- const CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE = "openclaw_direct";
820
- function flattenCodexDynamicToolFunctions(tools) {
821
- return (tools ?? []).flatMap((tool) => tool.type === "namespace" ? tool.tools : [tool]);
822
- }
823
- const CODEX_INTERACTIVE_THREAD_SOURCE_KINDS = ["cli", "vscode"];
824
- const CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES = ["atlas", "chatgpt"];
825
- function isJsonObject(value) {
826
- return isRecord(value);
827
- }
828
- function isRpcResponse(message) {
829
- return "id" in message && !("method" in message);
830
- }
831
- //#endregion
832
901
  //#region extensions/codex/src/app-server/auth-bridge.ts
833
902
  const CODEX_APP_SERVER_AUTH_PROVIDER = "openai";
834
903
  const CODEX_APP_SERVER_EXTERNAL_CLI_PROVIDER_IDS = [CODEX_APP_SERVER_AUTH_PROVIDER];
@@ -879,8 +948,7 @@ function assertNoUnimportedAgentCodexAuthFile(params) {
879
948
  if (message) throw new AgentHarnessPreflightError(message);
880
949
  }
881
950
  function resolveUnimportedAgentCodexAuthMessage(params) {
882
- const managedCodexCli = params.startOptions.commandSource === "managed" || params.startOptions.commandSource === "resolved-managed";
883
- if (params.startOptions.transport !== "stdio" || !managedCodexCli || params.startOptions.homeScope === "user") return;
951
+ if (params.startOptions.transport !== "stdio" || params.startOptions.homeScope === "user") return;
884
952
  const codexHome = resolveCodexAppServerHomeDir(params.agentDir);
885
953
  const authPath = path.join(codexHome, CODEX_AUTH_JSON_FILENAME);
886
954
  if (!fsSync.existsSync(authPath)) return;
@@ -1238,36 +1306,21 @@ function withoutClearedCodexHomeEnv(clearEnv) {
1238
1306
  return filtered.length === clearEnv.length ? clearEnv : filtered;
1239
1307
  }
1240
1308
  async function applyCodexAppServerAuthProfile(params) {
1241
- if (params.preparedAuth?.kind === "profile") {
1242
- await params.client.request("account/login/start", params.preparedAuth.snapshot.loginParams);
1243
- return;
1244
- }
1245
- if (params.preparedAuth?.kind === "api-key") {
1246
- await params.client.request("account/login/start", {
1247
- type: "apiKey",
1248
- apiKey: params.preparedAuth.apiKey
1249
- });
1250
- return;
1251
- }
1252
- if (params.authProfileId === null) {
1309
+ if (!params.preparedAuth && params.authProfileId === null) {
1253
1310
  await assertNativeCodexAccountMatchesRoute(params.client, params.authRequirement);
1254
1311
  return;
1255
1312
  }
1256
- let loginParams;
1257
- try {
1258
- loginParams = await resolveCodexAppServerAuthProfileLoginParams({
1259
- agentDir: params.agentDir,
1260
- authProfileId: params.authProfileId,
1261
- authProfileStore: params.authProfileStore,
1262
- config: params.config
1263
- });
1264
- } catch (error) {
1265
- if (params.authRequirement === "subscription" && error instanceof CodexAppServerAuthProfileUnavailableError) throw createCodexAppServerAuthError("Codex subscription auth profile could not produce login credentials.", error);
1266
- throw error;
1267
- }
1268
- if (params.authRequirement === "subscription" && loginParams?.type !== "chatgptAuthTokens") throw createCodexAppServerAuthError("Codex subscription auth profile could not produce login credentials.");
1313
+ const loginParams = params.preparedAuth?.kind === "profile" ? params.preparedAuth.snapshot.loginParams : params.preparedAuth?.kind === "api-key" ? {
1314
+ type: "apiKey",
1315
+ apiKey: params.preparedAuth.apiKey
1316
+ } : await resolveCodexAppServerAuthProfileLoginParams({
1317
+ agentDir: params.agentDir,
1318
+ authProfileId: params.authProfileId ?? void 0,
1319
+ authProfileStore: params.authProfileStore,
1320
+ config: params.config
1321
+ });
1322
+ if (params.authRequirement === "subscription" && loginParams?.type !== "chatgptAuthTokens") throw createCodexAppServerAuthError("Codex subscription auth profile could not produce login credentials. Sign in with `openclaw models auth login --provider openai`, select that profile, then retry.");
1269
1323
  if (!loginParams) {
1270
- if (params.authRequirement === "subscription") throw createCodexAppServerAuthError("Codex subscription auth profile could not produce login credentials.");
1271
1324
  if (params.authRequirement !== "api-key" || params.startOptions?.transport !== "stdio") return;
1272
1325
  const env = resolveCodexAppServerSpawnEnv(params.startOptions, process.env);
1273
1326
  const fallbackLoginParams = await resolveCodexAppServerFallbackApiKeyLoginParams({
@@ -1292,7 +1345,7 @@ async function assertNativeCodexAccountMatchesRoute(client, authRequirement) {
1292
1345
  const response = await client.request("account/read", { refreshToken: false });
1293
1346
  const accountType = isJsonObject(response.account) ? response.account.type : void 0;
1294
1347
  if (authRequirement === "subscription") {
1295
- if (accountType !== "chatgpt") throw createCodexAppServerAuthError("Codex subscription auth profile could not produce login credentials.");
1348
+ if (accountType !== "chatgpt") throw createCodexAppServerAuthError("Codex subscription route requires ChatGPT auth in the native Codex home. Run `codex login` for that home, or use appServer.homeScope=\"agent\" with an OpenClaw OAuth profile, then retry.");
1296
1349
  return;
1297
1350
  }
1298
1351
  if (accountType === "chatgpt") throw createCodexAppServerAuthError("Codex Platform route requires an API-key account, but the native Codex home is signed in with a ChatGPT subscription. Sign that home in with `codex login --with-api-key`, or set appServer.homeScope=\"agent\" so OpenClaw can inject its own key.");
@@ -1301,7 +1354,13 @@ function createCodexAppServerAuthError(message, cause) {
1301
1354
  const error = cause === void 0 ? new Error(message) : new Error(message, { cause });
1302
1355
  return Object.assign(error, { status: 401 });
1303
1356
  }
1304
- var CodexAppServerAuthProfileUnavailableError = class extends Error {};
1357
+ var CodexAppServerAuthProfileUnavailableError = class extends Error {
1358
+ constructor(..._args) {
1359
+ super(..._args);
1360
+ this.status = 401;
1361
+ this.code = "selected_auth_profile_unavailable";
1362
+ }
1363
+ };
1305
1364
  async function resolveCodexAppServerAuthProfileLoginParams(params) {
1306
1365
  const store = resolveCodexAppServerAuthProfileStore(params);
1307
1366
  const profileId = resolveCodexAppServerAuthProfileId({
@@ -1310,7 +1369,7 @@ async function resolveCodexAppServerAuthProfileLoginParams(params) {
1310
1369
  config: params.config
1311
1370
  });
1312
1371
  const profile = profileId ? store.profiles[profileId] : void 0;
1313
- if (profileId && !profile) throw new CodexAppServerAuthProfileUnavailableError(`Codex app-server auth profile "${profileId}" was not found.`);
1372
+ if (profileId && !profile) throw new CodexAppServerAuthProfileUnavailableError(`Codex app-server auth profile "${profileId}" was not found. Select an existing OpenAI profile or sign in again with OpenClaw, then retry.`);
1314
1373
  if (profileId && profile && !isCodexAppServerAuthProfileCredential(profile)) throw new CodexAppServerAuthProfileUnavailableError(`Codex app-server auth profile "${profileId}" must use the canonical OpenAI auth provider; run "openclaw doctor --fix" to migrate legacy provider IDs.`);
1315
1374
  return await resolveCodexAppServerAuthProfileLoginParamsInternal({
1316
1375
  ...params,
@@ -1328,14 +1387,14 @@ async function refreshCodexAppServerAuthTokens(params) {
1328
1387
  });
1329
1388
  const credential = profileId ? store.profiles[profileId] : void 0;
1330
1389
  const selectedAccountId = credential ? resolveExplicitChatgptAccountId(credential) ?? (credential.type === "oauth" ? resolveOpenAICodexAuthIdentity({ access: credential.access }).accountId : void 0) : void 0;
1331
- if (selectedAccountId && selectedAccountId !== previousAccountId) throw new Error("ChatGPT workspace changed before Codex token refresh.");
1390
+ if (selectedAccountId && selectedAccountId !== previousAccountId) throw new Error("ChatGPT workspace changed before Codex token refresh. Retry to start a client for the selected workspace.");
1332
1391
  }
1333
1392
  const loginParams = await resolveCodexAppServerAuthProfileLoginParamsInternal({
1334
1393
  ...params,
1335
1394
  forceOAuthRefresh: true
1336
1395
  });
1337
- if (!loginParams || loginParams.type !== "chatgptAuthTokens") throw new Error("Codex app-server ChatGPT token refresh requires an OAuth auth profile.");
1338
- if (previousAccountId && loginParams.chatgptAccountId !== previousAccountId) throw new Error("ChatGPT workspace changed during Codex token refresh.");
1396
+ if (!loginParams || loginParams.type !== "chatgptAuthTokens") throw new Error("Codex app-server ChatGPT token refresh requires an OAuth auth profile. Sign in with `openclaw models auth login --provider openai`, select that profile, then retry.");
1397
+ if (previousAccountId && loginParams.chatgptAccountId !== previousAccountId) throw new Error("ChatGPT workspace changed during Codex token refresh. Retry to start a client for the selected workspace.");
1339
1398
  return {
1340
1399
  accessToken: loginParams.accessToken,
1341
1400
  chatgptAccountId: loginParams.chatgptAccountId,
@@ -1356,8 +1415,8 @@ async function resolveCodexAppServerAuthProfileLoginParamsInternal(params) {
1356
1415
  });
1357
1416
  if (!profileId) return;
1358
1417
  const credential = store.profiles[profileId];
1359
- if (!credential) throw new Error(`Codex app-server auth profile "${profileId}" was not found.`);
1360
- if (!isCodexAppServerAuthProfileCredential(credential)) throw new Error(`Codex app-server auth profile "${profileId}" must use the canonical OpenAI auth provider; run "openclaw doctor --fix" to migrate legacy provider IDs.`);
1418
+ if (!credential) throw new CodexAppServerAuthProfileUnavailableError(`Codex app-server auth profile "${profileId}" was not found. Select an existing OpenAI profile or sign in again with OpenClaw, then retry.`);
1419
+ if (!isCodexAppServerAuthProfileCredential(credential)) throw new CodexAppServerAuthProfileUnavailableError(`Codex app-server auth profile "${profileId}" must use the canonical OpenAI auth provider; run "openclaw doctor --fix" to migrate legacy provider IDs.`);
1361
1420
  const loginParams = await resolveLoginParamsForCredential(profileId, credential, {
1362
1421
  agentDir: params.agentDir,
1363
1422
  store,
@@ -1365,7 +1424,7 @@ async function resolveCodexAppServerAuthProfileLoginParamsInternal(params) {
1365
1424
  forceOAuthRefresh: params.forceOAuthRefresh === true,
1366
1425
  config: params.config
1367
1426
  });
1368
- if (!loginParams) throw new CodexAppServerAuthProfileUnavailableError(`Codex app-server auth profile "${profileId}" does not contain usable credentials.`);
1427
+ if (!loginParams) throw new CodexAppServerAuthProfileUnavailableError(`Codex app-server auth profile "${profileId}" does not contain usable credentials. Repair or replace the selected OpenAI credential, then retry.`);
1369
1428
  return loginParams;
1370
1429
  }
1371
1430
  async function resolveCodexAppServerFallbackApiKeyLoginParams(params) {
@@ -1479,7 +1538,7 @@ async function resolveOAuthCredentialForCodexAppServer(profileId, credential, pa
1479
1538
  });
1480
1539
  if (params.forceRefresh && !persistedOAuthCredential && overlaidOAuthCredential) {
1481
1540
  const refreshedRuntimeCredential = await refreshOAuthCredentialForRuntime({ credential: overlaidOAuthCredential });
1482
- if (!refreshedRuntimeCredential?.access?.trim()) throw new Error(`Codex app-server auth profile "${profileId}" could not refresh.`);
1541
+ if (!refreshedRuntimeCredential?.access?.trim()) throw new Error(`Codex app-server auth profile "${profileId}" could not refresh. Sign in again with OpenClaw, then retry.`);
1483
1542
  store.profiles[profileId] = refreshedRuntimeCredential;
1484
1543
  return refreshedRuntimeCredential;
1485
1544
  }
@@ -1507,8 +1566,8 @@ function shouldUseScopedOAuthCredential(params) {
1507
1566
  return !isDeepStrictEqual(persisted, params.suppliedCredential) && !hasMatchingOAuthIdentity(persisted, params.suppliedCredential);
1508
1567
  }
1509
1568
  function hasMatchingOAuthIdentity(persisted, supplied) {
1510
- const persistedAccountId = persisted.accountId?.trim();
1511
- const suppliedAccountId = supplied.accountId?.trim();
1569
+ const persistedAccountId = resolveOpenAICodexAuthIdentity(persisted).accountId?.trim();
1570
+ const suppliedAccountId = resolveOpenAICodexAuthIdentity(supplied).accountId?.trim();
1512
1571
  if (persistedAccountId && suppliedAccountId) return persistedAccountId === suppliedAccountId;
1513
1572
  const persistedEmail = persisted.email?.trim().toLowerCase();
1514
1573
  const suppliedEmail = supplied.email?.trim().toLowerCase();
@@ -1525,8 +1584,8 @@ async function resolveScopedOAuthCredential(params) {
1525
1584
  const credential = current?.type === "oauth" ? current : params.credential;
1526
1585
  if (!params.forceRefresh && hasUsableOAuthCredential(credential)) return credential;
1527
1586
  const refreshed = await refreshOAuthCredentialForRuntime({ credential });
1528
- if (!refreshed?.access?.trim()) throw new Error(`Codex app-server auth profile "${params.profileId}" could not refresh.`);
1529
- if (!isDeepStrictEqual(params.store.profiles[params.profileId], credential)) throw new Error(`Codex app-server auth profile "${params.profileId}" changed while refreshing.`);
1587
+ if (!refreshed?.access?.trim()) throw new Error(`Codex app-server auth profile "${params.profileId}" could not refresh. Sign in again with OpenClaw, then retry.`);
1588
+ if (!isDeepStrictEqual(params.store.profiles[params.profileId], credential)) throw new Error(`Codex app-server auth profile "${params.profileId}" changed while refreshing. Retry with the newly selected OpenAI profile.`);
1530
1589
  params.store.profiles[params.profileId] = refreshed;
1531
1590
  return refreshed;
1532
1591
  })();
@@ -1604,7 +1663,7 @@ function resolveExplicitChatgptAccountId(credential) {
1604
1663
  }
1605
1664
  //#endregion
1606
1665
  //#region extensions/codex/src/app-server/rate-limit-cache.ts
1607
- const DEFAULT_CODEX_RATE_LIMIT_CACHE_MAX_AGE_MS = 10 * 6e4;
1666
+ const DEFAULT_CODEX_RATE_LIMIT_CACHE_MAX_AGE_MS = 6e5;
1608
1667
  const SPARSE_ACCOUNT_METADATA_KEYS = [
1609
1668
  "credits",
1610
1669
  "individualLimit",
@@ -1736,7 +1795,7 @@ async function withAbortableTimeout(params) {
1736
1795
  //#region extensions/codex/src/app-server/client-runtime.ts
1737
1796
  /** Client-scoped Codex auth and account observers. */
1738
1797
  /** Match Codex's native grace window without retaining inactive conversations indefinitely. */
1739
- const CODEX_APP_SERVER_LIVE_THREAD_IDLE_TIMEOUT_MS = 30 * 6e4;
1798
+ const CODEX_APP_SERVER_LIVE_THREAD_IDLE_TIMEOUT_MS = 18e5;
1740
1799
  /** Native-child parents are active ownership, so only otherwise-idle threads count against this cap. */
1741
1800
  const CODEX_APP_SERVER_LIVE_THREAD_MAX_IDLE = 64;
1742
1801
  /** Return a deterministic error before Codex cancels its ten-second external-auth request. */
@@ -1749,6 +1808,32 @@ function isCodexAppServerClientRuntimeLive(client) {
1749
1808
  const runtime = configuredClients.get(client);
1750
1809
  return runtime !== void 0 && !runtime.closed;
1751
1810
  }
1811
+ /** Immutable declarations are data owned by this physical client, never retained executors. */
1812
+ async function readCodexClientSessionMeta(client, sessionsRoot, boundRolloutPath, threadId) {
1813
+ let rolloutPath = boundRolloutPath;
1814
+ const runtime = configuredClients.get(client);
1815
+ if (!runtime || runtime.closed) throw new Error("Codex native metadata requires a live selected client");
1816
+ const cached = runtime.sessionMetadata.get(threadId);
1817
+ if (cached && cached.sessionsRoot === sessionsRoot && (!rolloutPath || cached.rolloutPath === rolloutPath)) return structuredClone(cached.metadata);
1818
+ if (!rolloutPath) {
1819
+ const { thread } = await client.request("thread/read", {
1820
+ threadId,
1821
+ includeTurns: false
1822
+ });
1823
+ if (thread.id !== threadId || !thread.path) throw new Error("Codex native metadata has no verified thread path");
1824
+ rolloutPath = thread.path;
1825
+ }
1826
+ const metadata = await readCodexSessionMeta(sessionsRoot, rolloutPath, threadId);
1827
+ if (runtime.closed || !metadata) throw new Error("Codex native metadata is unavailable on the selected client");
1828
+ runtime.sessionMetadata.delete(threadId);
1829
+ runtime.sessionMetadata.set(threadId, {
1830
+ sessionsRoot,
1831
+ rolloutPath,
1832
+ metadata
1833
+ });
1834
+ pruneMapToMaxSize(runtime.sessionMetadata, CODEX_APP_SERVER_LIVE_THREAD_MAX_IDLE);
1835
+ return structuredClone(metadata);
1836
+ }
1752
1837
  /** Installs one auth-refresh handler and one rate-limit observer per physical client. */
1753
1838
  function ensureCodexAppServerClientRuntime(client, context) {
1754
1839
  const existing = configuredClients.get(client);
@@ -1766,7 +1851,8 @@ function ensureCodexAppServerClientRuntime(client, context) {
1766
1851
  retainedThreads: /* @__PURE__ */ new Map(),
1767
1852
  claimedThreads: /* @__PURE__ */ new Map(),
1768
1853
  releasingThreads: /* @__PURE__ */ new Map(),
1769
- protectedThreads: /* @__PURE__ */ new Map()
1854
+ protectedThreads: /* @__PURE__ */ new Map(),
1855
+ sessionMetadata: /* @__PURE__ */ new Map()
1770
1856
  };
1771
1857
  configuredClients.set(client, runtime);
1772
1858
  client.addCloseHandler(() => {
@@ -1778,20 +1864,26 @@ function ensureCodexAppServerClientRuntime(client, context) {
1778
1864
  runtime.retainedThreads.clear();
1779
1865
  runtime.claimedThreads.clear();
1780
1866
  runtime.protectedThreads.clear();
1867
+ runtime.sessionMetadata.clear();
1781
1868
  });
1782
1869
  client.addRequestHandler(async (request) => {
1783
1870
  if (request.method !== "account/chatgptAuthTokens/refresh") return;
1784
1871
  if (runtime.context.authMode === "prepared-api-key") throw new Error("ChatGPT token refresh is unavailable for prepared Codex API-key auth.");
1785
1872
  const previousAccountId = isJsonObject(request.params) && typeof request.params.previousAccountId === "string" ? request.params.previousAccountId.trim() || void 0 : void 0;
1786
- const tokens = await withTimeout$1(refreshCodexAppServerAuthTokens({
1787
- agentDir: runtime.context.agentDir,
1788
- authProfileId: runtime.context.authProfileId,
1789
- ...previousAccountId ? { previousAccountId } : {},
1790
- ...runtime.context.authProfileStore ? { authProfileStore: runtime.context.authProfileStore } : {},
1791
- config: runtime.context.config
1792
- }), CODEX_EXTERNAL_AUTH_REFRESH_TIMEOUT_MS, "Codex app-server ChatGPT token refresh timed out before its external-auth deadline");
1793
- if (previousAccountId && tokens.chatgptAccountId !== previousAccountId) throw new Error("ChatGPT workspace changed during Codex token refresh.");
1794
- return { ...tokens };
1873
+ try {
1874
+ const tokens = await withTimeout$1(refreshCodexAppServerAuthTokens({
1875
+ agentDir: runtime.context.agentDir,
1876
+ authProfileId: runtime.context.authProfileId,
1877
+ ...previousAccountId ? { previousAccountId } : {},
1878
+ ...runtime.context.authProfileStore ? { authProfileStore: runtime.context.authProfileStore } : {},
1879
+ config: runtime.context.config
1880
+ }), CODEX_EXTERNAL_AUTH_REFRESH_TIMEOUT_MS, "Codex app-server ChatGPT token refresh timed out before its external-auth deadline. Retry the request; if it persists, sign in again with OpenClaw.");
1881
+ if (previousAccountId && tokens.chatgptAccountId !== previousAccountId) throw new Error("ChatGPT workspace changed during Codex token refresh. Retry to start a client for the selected workspace.");
1882
+ return { ...tokens };
1883
+ } catch (error) {
1884
+ runtime.context.onAuthRefreshFailure?.();
1885
+ throw error;
1886
+ }
1795
1887
  });
1796
1888
  client.addNotificationHandler((notification) => {
1797
1889
  if (notification.method === "account/rateLimits/updated") {
@@ -1805,6 +1897,7 @@ function ensureCodexAppServerClientRuntime(client, context) {
1805
1897
  if (releasing) releasing.invalidated = true;
1806
1898
  runtime.retainedThreads.delete(threadId);
1807
1899
  runtime.claimedThreads.delete(threadId);
1900
+ runtime.sessionMetadata.delete(threadId);
1808
1901
  scheduleRetainedThreadEviction(client, runtime);
1809
1902
  }
1810
1903
  }
@@ -1827,10 +1920,11 @@ function scheduleRetainedThreadEviction(client, runtime) {
1827
1920
  }, Math.max(0, expiresAt - Date.now()));
1828
1921
  runtime.evictionTimer.unref?.();
1829
1922
  }
1830
- async function releaseRetainedThread(client, runtime, threadId) {
1923
+ async function releaseRetainedThread(client, runtime, threadId, assertCurrent) {
1831
1924
  const pendingRelease = runtime.releasingThreads.get(threadId);
1832
1925
  if (pendingRelease) {
1833
1926
  await pendingRelease.completion;
1927
+ assertCurrent?.();
1834
1928
  return false;
1835
1929
  }
1836
1930
  const retained = runtime.retainedThreads.get(threadId);
@@ -1842,14 +1936,17 @@ async function releaseRetainedThread(client, runtime, threadId) {
1842
1936
  }
1843
1937
  runtime.retainedThreads.delete(threadId);
1844
1938
  scheduleRetainedThreadEviction(client, runtime);
1845
- const transition = { completion: Promise.resolve().then(() => retained.release(threadId)) };
1939
+ const transition = { completion: Promise.resolve().then(() => {
1940
+ assertCurrent?.();
1941
+ return assertCurrent ? retained.release(threadId, assertCurrent) : retained.release(threadId);
1942
+ }) };
1846
1943
  runtime.releasingThreads.set(threadId, transition);
1847
1944
  try {
1848
1945
  await transition.completion;
1849
1946
  return true;
1850
1947
  } catch (error) {
1851
1948
  if (!runtime.closed && !transition.invalidated && runtime.releasingThreads.get(threadId) === transition && !runtime.retainedThreads.has(threadId) && !runtime.claimedThreads.has(threadId)) {
1852
- retained.expiresAt = Date.now() + CODEX_APP_SERVER_LIVE_THREAD_IDLE_TIMEOUT_MS;
1949
+ if (retained.ephemeralPolicy === void 0) retained.expiresAt = Date.now() + CODEX_APP_SERVER_LIVE_THREAD_IDLE_TIMEOUT_MS;
1853
1950
  const newerThreads = [...runtime.retainedThreads.entries()].filter(([candidateThreadId]) => !olderThreadIds.has(candidateThreadId));
1854
1951
  for (const [candidateThreadId] of newerThreads) runtime.retainedThreads.delete(candidateThreadId);
1855
1952
  runtime.retainedThreads.set(threadId, retained);
@@ -1867,14 +1964,15 @@ async function evictExpiredRetainedThreads(client, runtime) {
1867
1964
  scheduleRetainedThreadEviction(client, runtime);
1868
1965
  }
1869
1966
  async function evictExcessIdleThreads(client, runtime) {
1870
- let idleThreadIds = [...runtime.retainedThreads.keys()].filter((threadId) => !runtime.protectedThreads.has(threadId));
1967
+ const idleThreads = () => [...runtime.retainedThreads].filter(([threadId, thread]) => thread.ephemeralPolicy === void 0 && !runtime.protectedThreads.has(threadId));
1968
+ let idleThreadIds = idleThreads();
1871
1969
  while (idleThreadIds.length > CODEX_APP_SERVER_LIVE_THREAD_MAX_IDLE) {
1872
- await releaseRetainedThread(client, runtime, idleThreadIds[0]);
1873
- idleThreadIds = [...runtime.retainedThreads.keys()].filter((threadId) => !runtime.protectedThreads.has(threadId));
1970
+ await releaseRetainedThread(client, runtime, idleThreadIds[0][0]);
1971
+ idleThreadIds = idleThreads();
1874
1972
  }
1875
1973
  }
1876
1974
  /** Retain separately owned Codex subscriptions; completing B must never cold-restart A. */
1877
- async function retainCodexAppServerLiveThread(client, threadId, releaseThread, configFingerprint, serviceTier) {
1975
+ async function retainCodexAppServerLiveThread(client, threadId, releaseThread, configFingerprint, serviceTier, ephemeralPolicy) {
1878
1976
  const runtime = configuredClients.get(client);
1879
1977
  if (!runtime || runtime.closed) return false;
1880
1978
  const claimed = runtime.claimedThreads.get(threadId);
@@ -1882,15 +1980,16 @@ async function retainCodexAppServerLiveThread(client, threadId, releaseThread, c
1882
1980
  const pendingRelease = runtime.releasingThreads.get(threadId);
1883
1981
  if (pendingRelease) {
1884
1982
  await pendingRelease.completion;
1885
- if (runtime.closed || claimed !== void 0 && runtime.claimedThreads.get(threadId) !== claimed) return false;
1983
+ return false;
1886
1984
  }
1887
1985
  runtime.retainedThreads.delete(threadId);
1888
1986
  const retained = {
1889
1987
  configFingerprint,
1988
+ ephemeralPolicy,
1890
1989
  serviceTier,
1891
- expiresAt: Date.now() + CODEX_APP_SERVER_LIVE_THREAD_IDLE_TIMEOUT_MS,
1892
- release: (releaseThread ? physicalThreadReleases.get(releaseThread) ?? releaseThread : void 0) ?? (async (releasedThreadId) => {
1893
- await unsubscribeCodexAppServerLiveThread(client, releasedThreadId, 5e3);
1990
+ expiresAt: ephemeralPolicy === void 0 ? Date.now() + CODEX_APP_SERVER_LIVE_THREAD_IDLE_TIMEOUT_MS : Number.POSITIVE_INFINITY,
1991
+ release: (releaseThread ? physicalThreadReleases.get(releaseThread) ?? releaseThread : void 0) ?? (async (releasedThreadId, assertCurrent) => {
1992
+ await unsubscribeCodexAppServerLiveThread(client, releasedThreadId, 5e3, assertCurrent);
1894
1993
  })
1895
1994
  };
1896
1995
  runtime.retainedThreads.set(threadId, retained);
@@ -1934,8 +2033,8 @@ async function claimCodexAppServerLiveThread(client, threadId) {
1934
2033
  }
1935
2034
  return claimCodexAppServerThreadOwnership(client, runtime, threadId, runtime.retainedThreads.get(threadId) ?? {
1936
2035
  expiresAt: Date.now() + CODEX_APP_SERVER_LIVE_THREAD_IDLE_TIMEOUT_MS,
1937
- release: async (releasedThreadId) => {
1938
- await unsubscribeCodexAppServerLiveThread(client, releasedThreadId, 5e3);
2036
+ release: async (releasedThreadId, assertCurrent) => {
2037
+ await unsubscribeCodexAppServerLiveThread(client, releasedThreadId, 5e3, assertCurrent);
1939
2038
  }
1940
2039
  });
1941
2040
  }
@@ -1944,16 +2043,26 @@ function claimCodexAppServerThreadOwnership(client, runtime, threadId, retained)
1944
2043
  const claimed = Symbol(threadId);
1945
2044
  runtime.claimedThreads.set(threadId, claimed);
1946
2045
  scheduleRetainedThreadEviction(client, runtime);
1947
- const release = async (releasedThreadId) => {
1948
- if (releasedThreadId !== threadId || runtime.claimedThreads.get(threadId) !== claimed) return;
2046
+ const assertCurrent = () => {
2047
+ if (runtime.closed || runtime.claimedThreads.get(threadId) !== claimed) throw new Error(`Codex thread subscription ownership changed: ${threadId}`);
2048
+ };
2049
+ const release = async (releasedThreadId, assertReleaseCurrent) => {
2050
+ if (releasedThreadId !== threadId || runtime.claimedThreads.get(threadId) !== claimed) {
2051
+ assertReleaseCurrent?.();
2052
+ return;
2053
+ }
1949
2054
  const pendingRelease = runtime.releasingThreads.get(threadId);
1950
2055
  if (pendingRelease) {
1951
2056
  await pendingRelease.completion;
1952
2057
  return;
1953
2058
  }
1954
2059
  const transition = { completion: Promise.resolve().then(async () => {
1955
- if (runtime.closed || runtime.claimedThreads.get(threadId) !== claimed) return;
1956
- await retained.release(releasedThreadId);
2060
+ if (runtime.closed || runtime.claimedThreads.get(threadId) !== claimed) {
2061
+ assertReleaseCurrent?.();
2062
+ return;
2063
+ }
2064
+ assertReleaseCurrent?.();
2065
+ await (assertReleaseCurrent ? retained.release(releasedThreadId, assertReleaseCurrent) : retained.release(releasedThreadId));
1957
2066
  }) };
1958
2067
  runtime.releasingThreads.set(threadId, transition);
1959
2068
  try {
@@ -1962,95 +2071,3099 @@ function claimCodexAppServerThreadOwnership(client, runtime, threadId, retained)
1962
2071
  } finally {
1963
2072
  if (runtime.releasingThreads.get(threadId) === transition) runtime.releasingThreads.delete(threadId);
1964
2073
  }
1965
- };
1966
- physicalThreadReleases.set(release, retained.release);
1967
- claimedThreadReleaseTokens.set(release, claimed);
2074
+ };
2075
+ physicalThreadReleases.set(release, retained.release);
2076
+ claimedThreadReleaseTokens.set(release, claimed);
2077
+ return {
2078
+ assertCurrent,
2079
+ configFingerprint: retained.configFingerprint,
2080
+ ephemeralPolicy: retained.ephemeralPolicy,
2081
+ serviceTier: retained.serviceTier,
2082
+ release
2083
+ };
2084
+ }
2085
+ /** Distinguish active claimed ownership from an already-evicted idle subscription. */
2086
+ function hasCodexAppServerLiveThread(client, threadId) {
2087
+ const runtime = configuredClients.get(client);
2088
+ return runtime !== void 0 && !runtime.closed && (runtime.retainedThreads.has(threadId) || runtime.releasingThreads.has(threadId) || runtime.claimedThreads.has(threadId));
2089
+ }
2090
+ function isCodexAppServerLiveThreadClaimed(client, threadId) {
2091
+ const runtime = configuredClients.get(client);
2092
+ return runtime !== void 0 && !runtime.closed && runtime.claimedThreads.has(threadId);
2093
+ }
2094
+ /** Release the exact physical subscription and finish only its observed ownership generation. */
2095
+ async function unsubscribeCodexAppServerLiveThread(client, threadId, timeoutMs, assertCurrent) {
2096
+ const runtime = configuredClients.get(client);
2097
+ const claimed = runtime?.claimedThreads.get(threadId);
2098
+ const retained = runtime?.retainedThreads.get(threadId);
2099
+ let transition = runtime?.releasingThreads.get(threadId);
2100
+ if (transition?.physicalRelease) {
2101
+ await transition.physicalRelease;
2102
+ assertCurrent?.();
2103
+ return;
2104
+ }
2105
+ const physicalRelease = Promise.resolve().then(async () => {
2106
+ if (claimed !== void 0 && runtime?.claimedThreads.get(threadId) !== claimed || retained !== void 0 && runtime?.retainedThreads.get(threadId) !== retained) {
2107
+ assertCurrent?.();
2108
+ return;
2109
+ }
2110
+ assertCurrent?.();
2111
+ await client.request("thread/unsubscribe", { threadId }, {
2112
+ timeoutMs,
2113
+ assertCurrent
2114
+ });
2115
+ assertCurrent?.();
2116
+ });
2117
+ const ownsTransition = runtime !== void 0 && transition === void 0;
2118
+ if (transition) transition.physicalRelease = physicalRelease;
2119
+ else if (runtime) {
2120
+ transition = {
2121
+ completion: physicalRelease,
2122
+ physicalRelease
2123
+ };
2124
+ runtime.releasingThreads.set(threadId, transition);
2125
+ }
2126
+ try {
2127
+ await physicalRelease;
2128
+ if (retained !== void 0 && runtime?.retainedThreads.get(threadId) === retained) {
2129
+ runtime.retainedThreads.delete(threadId);
2130
+ scheduleRetainedThreadEviction(client, runtime);
2131
+ }
2132
+ if (claimed !== void 0 && runtime?.claimedThreads.get(threadId) === claimed) runtime.claimedThreads.delete(threadId);
2133
+ } finally {
2134
+ if (ownsTransition && runtime.releasingThreads.get(threadId) === transition) runtime.releasingThreads.delete(threadId);
2135
+ }
2136
+ }
2137
+ /** Reset/end owns the exact thread; failed generation retirement must never release its successor. */
2138
+ async function releaseCodexAppServerLiveThread(client, threadId, assertCurrent) {
2139
+ const runtime = configuredClients.get(client);
2140
+ return runtime ? await releaseRetainedThread(client, runtime, threadId, assertCurrent) : false;
2141
+ }
2142
+ /** Native child work pins its parent's subscription even after the foreground parent turn ends. */
2143
+ function protectCodexAppServerLiveThread(client, threadId) {
2144
+ const runtime = configuredClients.get(client);
2145
+ if (!runtime || runtime.closed) return () => void 0;
2146
+ runtime.protectedThreads.set(threadId, (runtime.protectedThreads.get(threadId) ?? 0) + 1);
2147
+ scheduleRetainedThreadEviction(client, runtime);
2148
+ let protectedThread = true;
2149
+ return () => {
2150
+ if (!protectedThread) return;
2151
+ protectedThread = false;
2152
+ if (runtime.closed) return;
2153
+ const count = runtime.protectedThreads.get(threadId) ?? 0;
2154
+ if (count <= 1) {
2155
+ runtime.protectedThreads.delete(threadId);
2156
+ const retained = runtime.retainedThreads.get(threadId);
2157
+ if (retained) {
2158
+ if (retained.ephemeralPolicy === void 0) retained.expiresAt = Date.now() + CODEX_APP_SERVER_LIVE_THREAD_IDLE_TIMEOUT_MS;
2159
+ runtime.retainedThreads.delete(threadId);
2160
+ runtime.retainedThreads.set(threadId, retained);
2161
+ }
2162
+ } else runtime.protectedThreads.set(threadId, count - 1);
2163
+ scheduleRetainedThreadEviction(client, runtime);
2164
+ evictExcessIdleThreads(client, runtime).catch((error) => {
2165
+ embeddedAgentLog.warn("codex retained thread unpin eviction failed", {
2166
+ threadId,
2167
+ reason: formatErrorMessage(error)
2168
+ });
2169
+ });
2170
+ };
2171
+ }
2172
+ //#endregion
2173
+ //#region extensions/codex/src/app-server/dynamic-tool-response-state.ts
2174
+ /** Retains the host-owned app preview without adding it to Codex's response payload. */
2175
+ function withDynamicToolTranscriptDetails(response, details) {
2176
+ if (details === void 0) return response;
2177
+ Object.defineProperty(response, "transcriptDetails", {
2178
+ configurable: true,
2179
+ enumerable: false,
2180
+ value: details
2181
+ });
2182
+ return response;
2183
+ }
2184
+ function withDynamicToolTerminalResolution(response, terminalResolution) {
2185
+ if (terminalResolution) {
2186
+ Object.defineProperties(response, {
2187
+ terminalResolution: {
2188
+ configurable: true,
2189
+ enumerable: false,
2190
+ value: terminalResolution
2191
+ },
2192
+ executionStarted: {
2193
+ configurable: true,
2194
+ enumerable: false,
2195
+ value: terminalResolution.executionStarted
2196
+ },
2197
+ ...terminalResolution.executedArguments ? { executedArguments: {
2198
+ configurable: true,
2199
+ enumerable: false,
2200
+ value: terminalResolution.executedArguments
2201
+ } } : {}
2202
+ });
2203
+ withDynamicToolSideEffectEvidence(response, terminalResolution.sideEffectEvidence);
2204
+ }
2205
+ return response;
2206
+ }
2207
+ function withDynamicToolExecutionState(response, state) {
2208
+ Object.defineProperties(response, {
2209
+ executedArguments: {
2210
+ configurable: true,
2211
+ enumerable: false,
2212
+ value: state.executedArguments
2213
+ },
2214
+ executionStarted: {
2215
+ configurable: true,
2216
+ enumerable: false,
2217
+ value: state.executionStarted
2218
+ }
2219
+ });
2220
+ return withDynamicToolSideEffectEvidence(response, state.sideEffectEvidence === true);
2221
+ }
2222
+ function withDynamicToolSideEffectEvidence(response, sideEffectEvidence) {
2223
+ if (!sideEffectEvidence) {
2224
+ delete response.sideEffectEvidence;
2225
+ return response;
2226
+ }
2227
+ Object.defineProperty(response, "sideEffectEvidence", {
2228
+ configurable: true,
2229
+ enumerable: false,
2230
+ value: true
2231
+ });
2232
+ return response;
2233
+ }
2234
+ function createFailedDynamicToolResponse(message, options) {
2235
+ const response = {
2236
+ contentItems: [{
2237
+ type: "inputText",
2238
+ text: message
2239
+ }],
2240
+ success: false
2241
+ };
2242
+ Object.defineProperties(response, {
2243
+ diagnosticTerminalReason: {
2244
+ configurable: true,
2245
+ enumerable: false,
2246
+ value: options?.terminalReason ?? "failed"
2247
+ },
2248
+ diagnosticTerminalType: {
2249
+ configurable: true,
2250
+ enumerable: false,
2251
+ value: "error"
2252
+ }
2253
+ });
2254
+ if (options?.executionStarted !== void 0) Object.defineProperty(response, "executionStarted", {
2255
+ configurable: true,
2256
+ enumerable: false,
2257
+ value: options.executionStarted
2258
+ });
2259
+ if (options?.executedArguments !== void 0) Object.defineProperty(response, "executedArguments", {
2260
+ configurable: true,
2261
+ enumerable: false,
2262
+ value: options.executedArguments
2263
+ });
2264
+ return withDynamicToolSideEffectEvidence(response, options?.sideEffectEvidence === true);
2265
+ }
2266
+ //#endregion
2267
+ //#region extensions/codex/src/app-server/tool-abort-terminal-reason.ts
2268
+ /** Leaf helper shared by native and dynamic tool diagnostics. */
2269
+ const CODEX_TIMEOUT_ABORT_REASONS = /* @__PURE__ */ new Set([
2270
+ "codex_startup_timeout",
2271
+ "turn_completion_idle_timeout",
2272
+ "turn_progress_idle_timeout",
2273
+ "turn_terminal_idle_timeout"
2274
+ ]);
2275
+ /** Preserves timeout provenance when an enclosing run aborts an active tool. */
2276
+ function resolveCodexToolAbortTerminalReason(signal) {
2277
+ try {
2278
+ const reason = signal.reason;
2279
+ if (typeof reason === "string") {
2280
+ if (CODEX_TIMEOUT_ABORT_REASONS.has(reason)) return "timed_out";
2281
+ return reason === "client_closed" ? "failed" : "cancelled";
2282
+ }
2283
+ if (reason && typeof reason === "object") {
2284
+ const record = reason;
2285
+ if (record.name === "TimeoutError" || record.reason === "timeout") return "timed_out";
2286
+ }
2287
+ } catch {
2288
+ return "cancelled";
2289
+ }
2290
+ return "cancelled";
2291
+ }
2292
+ //#endregion
2293
+ //#region extensions/codex/src/app-server/dynamic-tool-execution.ts
2294
+ /**
2295
+ * Timeout, terminal-release, and diagnostic helpers for Codex dynamic tool
2296
+ * calls.
2297
+ */
2298
+ /** Default timeout for Codex dynamic tool calls. */
2299
+ const CODEX_DYNAMIC_TOOL_TIMEOUT_MS = 9e4;
2300
+ /** Hard cap for per-call Codex dynamic tool timeout overrides. */
2301
+ const CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 6e5;
2302
+ const CODEX_DYNAMIC_TOOL_TIMEOUT_SECONDS_GRACE_MS = 3e4;
2303
+ const CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS = 12e4;
2304
+ const CODEX_DYNAMIC_COMPUTER_GATEWAY_TIMEOUT_MS = 3e4;
2305
+ const CODEX_DYNAMIC_COMPUTER_COMPLETION_GRACE_MS = 3e4;
2306
+ /** Timeout for image-understanding style dynamic tool calls. */
2307
+ const CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS = 6e4;
2308
+ /** Timeout for message-delivery dynamic tool calls. */
2309
+ const CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS = 6e5;
2310
+ /** Outer default for collector waits: full swarm budget plus completion grace. */
2311
+ const CODEX_DYNAMIC_AGENTS_WAIT_TOOL_TIMEOUT_MS = 63e4;
2312
+ const LOG_FIELD_MAX_LENGTH = 160;
2313
+ function normalizeLogField(value) {
2314
+ if (typeof value !== "string") return;
2315
+ const normalized = value.replaceAll(String.fromCharCode(27), " ").replaceAll("\r", " ").replaceAll("\n", " ").replaceAll(" ", " ").trim();
2316
+ if (!normalized) return;
2317
+ return normalized.length > LOG_FIELD_MAX_LENGTH ? `${truncateUtf16Safe(normalized, 157)}...` : normalized;
2318
+ }
2319
+ function readNumericTimeoutMs(value) {
2320
+ if (typeof value === "number" && Number.isFinite(value)) return Math.max(0, Math.floor(value));
2321
+ if (typeof value === "string") {
2322
+ const parsed = parseStrictNonNegativeInteger(value);
2323
+ if (parsed !== void 0) return Math.max(0, Math.floor(parsed));
2324
+ }
2325
+ }
2326
+ function formatDynamicToolTimeoutDetails(params) {
2327
+ const tool = normalizeLogField(params.call.tool) ?? "unknown";
2328
+ const baseMeta = {
2329
+ tool: params.call.tool,
2330
+ toolCallId: params.call.callId,
2331
+ threadId: params.call.threadId,
2332
+ turnId: params.call.turnId,
2333
+ timeoutMs: params.timeoutMs,
2334
+ timeoutKind: "codex_dynamic_tool_rpc"
2335
+ };
2336
+ if (tool !== "process" || !isJsonObject(params.call.arguments)) return {
2337
+ responseMessage: `OpenClaw dynamic tool call timed out after ${params.timeoutMs}ms while running tool ${tool}.`,
2338
+ consoleMessage: `codex dynamic tool timeout: tool=${tool} toolTimeoutMs=${params.timeoutMs}; per-tool-call watchdog, not session idle`,
2339
+ meta: baseMeta
2340
+ };
2341
+ const action = normalizeLogField(params.call.arguments.action);
2342
+ const sessionId = normalizeLogField(params.call.arguments.sessionId);
2343
+ const requestedTimeoutMs = readNumericTimeoutMs(params.call.arguments.timeout);
2344
+ const actionPart = action ? ` action=${action}` : "";
2345
+ const sessionPart = sessionId ? ` sessionId=${sessionId}` : "";
2346
+ const requestedPart = requestedTimeoutMs === void 0 ? "" : ` requestedWaitMs=${requestedTimeoutMs}`;
2347
+ const retryHint = action === "poll" ? "; repeated lines usually mean process-poll retry churn, not model progress" : "";
2348
+ const responseTarget = action || sessionId ? ` while waiting for process${actionPart}${sessionPart}` : " while waiting for the process tool";
2349
+ return {
2350
+ responseMessage: `OpenClaw dynamic tool call timed out after ${params.timeoutMs}ms${responseTarget}. This is a tool RPC timeout, not a session idle timeout.`,
2351
+ consoleMessage: `codex process tool timeout:${actionPart}${sessionPart} toolTimeoutMs=${params.timeoutMs}${requestedPart}; per-tool-call watchdog, not session idle${retryHint}`,
2352
+ meta: {
2353
+ ...baseMeta,
2354
+ processAction: action,
2355
+ processSessionId: sessionId,
2356
+ processRequestedTimeoutMs: requestedTimeoutMs
2357
+ }
2358
+ };
2359
+ }
2360
+ /**
2361
+ * Runs a dynamic tool call with run-abort and the budget prepared by
2362
+ * resolveDynamicToolCallTimeoutMs, preserving tool-specific completion grace.
2363
+ */
2364
+ async function handleDynamicToolCallWithTimeout(params) {
2365
+ let didNotifyAgentToolResult = false;
2366
+ const conservativeRaceResponses = /* @__PURE__ */ new WeakSet();
2367
+ const finalizeTerminal = (response) => {
2368
+ const executionSnapshot = params.toolBridge.consumeToolExecutionSnapshot?.(params.call.callId);
2369
+ const ownerKey = params.toolBridge.sideEffectOwnerKeyForTool?.(params.call.tool);
2370
+ const observedExecutionStarted = executionSnapshot?.executionStarted ?? (conservativeRaceResponses.has(response) ? void 0 : response.executionStarted);
2371
+ const terminalResolution = params.observeToolTerminal?.({
2372
+ toolCallId: params.call.callId,
2373
+ toolName: params.call.tool,
2374
+ arguments: response.executedArguments ?? executionSnapshot?.executedArguments ?? params.call.arguments,
2375
+ ...params.toolMeta ? { meta: params.toolMeta } : {},
2376
+ ...ownerKey ? { ownerMutation: { ownerKey } } : {},
2377
+ ...observedExecutionStarted !== void 0 ? { executionStarted: observedExecutionStarted } : {},
2378
+ outcome: response.success ? "success" : "failure",
2379
+ ...!response.success ? { failure: { error: readDynamicToolResponseText(response) } } : {}
2380
+ });
2381
+ return withDynamicToolTerminalResolution(response, terminalResolution);
2382
+ };
2383
+ const createFailedAfterPossibleDispatch = (message, terminalReason) => {
2384
+ const response = createFailedDynamicToolResponse(message, {
2385
+ executionStarted: true,
2386
+ sideEffectEvidence: true,
2387
+ terminalReason
2388
+ });
2389
+ conservativeRaceResponses.add(response);
2390
+ return response;
2391
+ };
2392
+ const notifyAgentToolResult = (event) => {
2393
+ if (didNotifyAgentToolResult) return;
2394
+ didNotifyAgentToolResult = true;
2395
+ try {
2396
+ params.onAgentToolResult?.(event);
2397
+ } catch (error) {
2398
+ embeddedAgentLog.warn(`onAgentToolResult handler failed: tool=${params.call.tool} error=${String(error)}`);
2399
+ }
2400
+ };
2401
+ const notifyFailedToolResult = (message, terminalReason = "failed") => {
2402
+ notifyAgentToolResult({
2403
+ toolName: params.call.tool,
2404
+ result: {
2405
+ content: [{
2406
+ type: "text",
2407
+ text: message
2408
+ }],
2409
+ details: {
2410
+ status: terminalReason,
2411
+ error: message
2412
+ }
2413
+ },
2414
+ isError: true
2415
+ });
2416
+ };
2417
+ if (params.signal.aborted) {
2418
+ const message = "OpenClaw dynamic tool call aborted before execution.";
2419
+ const terminalReason = resolveCodexToolAbortTerminalReason(params.signal);
2420
+ params.onFallbackSelected?.();
2421
+ notifyFailedToolResult(message, terminalReason);
2422
+ return finalizeTerminal(createFailedDynamicToolResponse(message, {
2423
+ executionStarted: false,
2424
+ terminalReason
2425
+ }));
2426
+ }
2427
+ const controller = new AbortController();
2428
+ let timeout;
2429
+ let timedOut = false;
2430
+ let resolveAbort;
2431
+ const abortFromRun = () => {
2432
+ const message = "OpenClaw dynamic tool call aborted.";
2433
+ const terminalReason = resolveCodexToolAbortTerminalReason(params.signal);
2434
+ params.onFallbackSelected?.();
2435
+ controller.abort(params.signal.reason ?? /* @__PURE__ */ new Error(message));
2436
+ notifyFailedToolResult(message, terminalReason);
2437
+ resolveAbort?.(createFailedAfterPossibleDispatch(message, terminalReason));
2438
+ };
2439
+ const abortPromise = new Promise((resolve) => {
2440
+ resolveAbort = resolve;
2441
+ });
2442
+ const timeoutPromise = new Promise((resolve) => {
2443
+ const { timeoutMs } = params;
2444
+ timeout = setTimeout(() => {
2445
+ timedOut = true;
2446
+ const timeoutDetails = formatDynamicToolTimeoutDetails({
2447
+ call: params.call,
2448
+ timeoutMs
2449
+ });
2450
+ params.onFallbackSelected?.();
2451
+ controller.abort(new Error(timeoutDetails.responseMessage));
2452
+ params.onTimeout?.();
2453
+ embeddedAgentLog.warn("codex dynamic tool call timed out", {
2454
+ ...timeoutDetails.meta,
2455
+ consoleMessage: timeoutDetails.consoleMessage
2456
+ });
2457
+ notifyFailedToolResult(timeoutDetails.responseMessage, "timed_out");
2458
+ resolve(createFailedAfterPossibleDispatch(timeoutDetails.responseMessage, "timed_out"));
2459
+ }, timeoutMs);
2460
+ timeout.unref?.();
2461
+ });
2462
+ try {
2463
+ params.signal.addEventListener("abort", abortFromRun, { once: true });
2464
+ if (params.signal.aborted) abortFromRun();
2465
+ const response = await Promise.race([
2466
+ params.toolBridge.handleToolCall(params.call, {
2467
+ signal: controller.signal,
2468
+ onAgentToolResult: notifyAgentToolResult,
2469
+ toolCallOrdinal: params.toolCallOrdinal,
2470
+ retainExecutionSnapshot: true
2471
+ }),
2472
+ abortPromise,
2473
+ timeoutPromise
2474
+ ]);
2475
+ if (!response.success && !didNotifyAgentToolResult) notifyFailedToolResult(readDynamicToolResponseText(response), response.diagnosticTerminalReason ?? "failed");
2476
+ return finalizeTerminal(response);
2477
+ } catch (error) {
2478
+ const terminalReason = params.signal.aborted ? resolveCodexToolAbortTerminalReason(params.signal) : resolveToolExecutionErrorKind(error);
2479
+ const message = formatToolExecutionErrorMessage(error, "OpenClaw dynamic tool call failed.");
2480
+ notifyFailedToolResult(message, terminalReason);
2481
+ return finalizeTerminal(createFailedAfterPossibleDispatch(message, terminalReason));
2482
+ } finally {
2483
+ if (timeout) clearTimeout(timeout);
2484
+ params.signal.removeEventListener("abort", abortFromRun);
2485
+ resolveAbort = void 0;
2486
+ if (!timedOut && !controller.signal.aborted) controller.abort(/* @__PURE__ */ new Error("OpenClaw dynamic tool call finished."));
2487
+ }
2488
+ }
2489
+ function readDynamicToolResponseText(response) {
2490
+ return response.contentItems.flatMap((item) => item.type === "inputText" && typeof item.text === "string" ? [item.text] : []).join("\n").trim() || "OpenClaw dynamic tool call failed.";
2491
+ }
2492
+ /** Strips OpenClaw-only metadata before sending a dynamic tool response to Codex. */
2493
+ function toCodexDynamicToolProtocolResponse(response) {
2494
+ return {
2495
+ contentItems: response.contentItems,
2496
+ success: response.success
2497
+ };
2498
+ }
2499
+ /** Adds async-started progress details when a tool result continues out of band. */
2500
+ function toCodexDynamicToolProgressResponse(response, protocolResponse) {
2501
+ const transcriptDetails = isJsonObject(response.transcriptDetails) ? response.transcriptDetails : void 0;
2502
+ const mcpAppPreview = isJsonObject(transcriptDetails?.mcpAppPreview) ? transcriptDetails.mcpAppPreview : void 0;
2503
+ const progressDetails = mcpAppPreview ? { mcpAppPreview } : void 0;
2504
+ if (response.asyncStarted !== true && progressDetails === void 0) return protocolResponse;
2505
+ return {
2506
+ ...protocolResponse,
2507
+ ...progressDetails ? { details: progressDetails } : {},
2508
+ ...response.asyncStarted === true ? { details: {
2509
+ ...progressDetails,
2510
+ async: true,
2511
+ status: "started"
2512
+ } } : {}
2513
+ };
2514
+ }
2515
+ /** Decides whether a terminal dynamic tool response can release the Codex turn. */
2516
+ function shouldReleaseTurnAfterTerminalDynamicTool(state) {
2517
+ return !state.completed && !state.aborted && state.responseSuccess && !state.currentTurnHadNonTerminalDynamicToolResult && state.activeAppServerTurnRequests === 0 && state.activeTurnItemIdsCount === 0 && state.pendingOpenClawDynamicToolCompletionIdsCount === 0;
2518
+ }
2519
+ /** Returns true when a non-async result should block terminal-release shortcuts. */
2520
+ function shouldBlockTerminalReleaseForNonTerminalDynamicToolResult(response) {
2521
+ return response.asyncStarted !== true;
2522
+ }
2523
+ /** Resolves whether terminal diagnostic state should release, wait, or stay idle. */
2524
+ function resolveTerminalDynamicToolBatchAction(state) {
2525
+ if (state.activeAppServerTurnRequests > 0 || state.activeTurnItemIdsCount > 0 || state.pendingOpenClawDynamicToolCompletionIdsCount > 0) return "wait";
2526
+ if (state.currentTurnHadNonTerminalDynamicToolResult) return "clear-nonterminal-batch";
2527
+ if (state.hasPendingTerminalDynamicToolRelease) return "release-pending-terminal";
2528
+ return "idle";
2529
+ }
2530
+ /** Returns true for diagnostic events that terminate a dynamic tool call. */
2531
+ function isDynamicToolTerminalDiagnosticEvent(event) {
2532
+ return event.type === "tool.execution.completed" || event.type === "tool.execution.error" || event.type === "tool.execution.blocked";
2533
+ }
2534
+ /** Matches terminal diagnostics to a specific dynamic tool call id/name. */
2535
+ function isMatchingDynamicToolTerminalDiagnostic(params) {
2536
+ if (params.event.toolCallId !== params.call.callId || params.event.toolName !== params.call.tool) return false;
2537
+ if (params.runId !== void 0) return params.event.runId === params.runId;
2538
+ if (params.sessionId !== void 0) return params.event.sessionId === params.sessionId;
2539
+ if (params.sessionKey !== void 0) return params.event.sessionKey === params.sessionKey;
2540
+ return params.event.runId === void 0 && params.event.sessionId === void 0 && params.event.sessionKey === void 0;
2541
+ }
2542
+ /** Checks pending diagnostics for a terminal event matching a tool call. */
2543
+ function hasPendingDynamicToolTerminalDiagnostic(params) {
2544
+ return hasPendingInternalDiagnosticEvent((event) => {
2545
+ if (!isDynamicToolTerminalDiagnosticEvent(event)) return false;
2546
+ return isMatchingDynamicToolTerminalDiagnostic({
2547
+ event,
2548
+ call: params.call,
2549
+ runId: params.runId,
2550
+ sessionId: params.sessionId,
2551
+ sessionKey: params.sessionKey
2552
+ });
2553
+ });
2554
+ }
2555
+ /** Resolves per-tool timeout, applying media/message defaults and hard caps. */
2556
+ function resolveDynamicToolCallTimeoutMs(params) {
2557
+ const args = isJsonObject(params.call.arguments) ? params.call.arguments : void 0;
2558
+ if (params.call.tool === "ask_user" || params.call.tool === "secrets" && args?.action === "request") try {
2559
+ return normalizeQuestionTimeoutSeconds(args?.timeoutSeconds) * 1e3 + CODEX_DYNAMIC_TOOL_TIMEOUT_SECONDS_GRACE_MS;
2560
+ } catch {
2561
+ return CODEX_DYNAMIC_TOOL_TIMEOUT_MS;
2562
+ }
2563
+ if (params.call.tool === "computer") return clampDynamicToolTimeoutMs(readComputerToolTimeoutMs(params.call.arguments));
2564
+ if (params.call.tool === "message") return CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS;
2565
+ if (params.call.tool === "agents_wait") {
2566
+ const requestedMs = readDynamicToolCallTimeoutMs(params.call.arguments) ?? readConfiguredDynamicToolTimeoutMs(params.call.tool, params.config) ?? CODEX_DYNAMIC_AGENTS_WAIT_TOOL_TIMEOUT_MS;
2567
+ return Math.max(1, Math.min(63e4, Math.floor(requestedMs)));
2568
+ }
2569
+ return clampDynamicToolTimeoutMs(readDynamicToolCallTimeoutMs(params.call.arguments) ?? readConfiguredDynamicToolTimeoutMs(params.call.tool, params.config) ?? CODEX_DYNAMIC_TOOL_TIMEOUT_MS);
2570
+ }
2571
+ /** Transport guard stays outside the handler's bounded tool wait and completion grace. */
2572
+ function resolveDynamicToolServerRequestTimeoutMs(call) {
2573
+ return Math.max(63e4, call ? resolveDynamicToolCallTimeoutMs({
2574
+ call,
2575
+ config: void 0
2576
+ }) : 0) + CODEX_DYNAMIC_TOOL_TIMEOUT_SECONDS_GRACE_MS;
2577
+ }
2578
+ function readComputerToolTimeoutMs(value) {
2579
+ const args = isJsonObject(value) ? value : void 0;
2580
+ const action = typeof args?.action === "string" ? args.action : void 0;
2581
+ const gatewayTimeoutMs = readPositiveFiniteTimeoutMs(args?.timeoutMs) ?? CODEX_DYNAMIC_COMPUTER_GATEWAY_TIMEOUT_MS;
2582
+ const gatewayCallCount = action === "screenshot" || action === "wait" ? 3 : 4;
2583
+ return (action === "wait" || action === "hold_key" ? Math.max(0, Number(args?.duration) || 0) * 1e3 : 0) + gatewayCallCount * gatewayTimeoutMs + CODEX_DYNAMIC_COMPUTER_COMPLETION_GRACE_MS;
2584
+ }
2585
+ function readDynamicToolCallTimeoutMs(value) {
2586
+ if (!isJsonObject(value)) return;
2587
+ const timeoutMs = readPositiveFiniteTimeoutMs(value.timeoutMs);
2588
+ if (timeoutMs !== void 0) return timeoutMs;
2589
+ const timeoutSecondsMs = readDynamicToolTimeoutSecondsAsMs(value.timeoutSeconds);
2590
+ return timeoutSecondsMs === void 0 ? void 0 : addTimerTimeoutGraceMs(timeoutSecondsMs, CODEX_DYNAMIC_TOOL_TIMEOUT_SECONDS_GRACE_MS);
2591
+ }
2592
+ function readConfiguredDynamicToolTimeoutMs(toolName, config) {
2593
+ if (toolName === "image_generate") {
2594
+ const imageModel = config?.agents?.defaults?.mediaModels?.image;
2595
+ if (!imageModel || typeof imageModel !== "object") return CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS;
2596
+ return readPositiveFiniteTimeoutMs(imageModel.timeoutMs) ?? CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS;
2597
+ }
2598
+ if (toolName === "view_image") {
2599
+ const candidates = (config?.tools?.media?.models ?? []).filter((entry) => !entry.capabilities || entry.capabilities.includes("image"));
2600
+ const capabilityTimeoutMs = readTimeoutSecondsAsMs(config?.tools?.media?.image?.timeoutSeconds);
2601
+ return Math.max(capabilityTimeoutMs ?? CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS, ...candidates.map((entry) => readTimeoutSecondsAsMs(entry.timeoutSeconds) ?? capabilityTimeoutMs ?? CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS));
2602
+ }
2603
+ if (toolName === "message") return CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS;
2604
+ }
2605
+ function readTimeoutSecondsAsMs(value) {
2606
+ const seconds = readPositiveFiniteTimeoutMs(value);
2607
+ return seconds === void 0 ? void 0 : seconds * 1e3;
2608
+ }
2609
+ function readDynamicToolTimeoutSecondsAsMs(value) {
2610
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) return;
2611
+ return value * 1e3;
2612
+ }
2613
+ function readPositiveFiniteTimeoutMs(value) {
2614
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : void 0;
2615
+ }
2616
+ function clampDynamicToolTimeoutMs(timeoutMs) {
2617
+ return Math.max(1, Math.min(CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS, Math.floor(timeoutMs)));
2618
+ }
2619
+ //#endregion
2620
+ //#region extensions/codex/src/app-server/elicitation-response.ts
2621
+ function createCodexElicitationResponse(action, content = null, meta = null) {
2622
+ return {
2623
+ action,
2624
+ content,
2625
+ _meta: meta
2626
+ };
2627
+ }
2628
+ //#endregion
2629
+ //#region extensions/codex/src/app-server/protocol-generated/json/DynamicToolCallParams.json
2630
+ var DynamicToolCallParams_default = {
2631
+ $schema: "http://json-schema.org/draft-07/schema#",
2632
+ properties: {
2633
+ "arguments": true,
2634
+ "callId": { "type": "string" },
2635
+ "namespace": { "type": ["string", "null"] },
2636
+ "threadId": { "type": "string" },
2637
+ "tool": { "type": "string" },
2638
+ "turnId": { "type": "string" }
2639
+ },
2640
+ required: [
2641
+ "arguments",
2642
+ "callId",
2643
+ "threadId",
2644
+ "tool",
2645
+ "turnId"
2646
+ ],
2647
+ title: "DynamicToolCallParams",
2648
+ type: "object"
2649
+ };
2650
+ //#endregion
2651
+ //#region extensions/codex/src/app-server/protocol-generated/json/v2/CodexAppServerProtocolDefinitions.json
2652
+ var definitions = {
2653
+ "AbsolutePathBuf": {
2654
+ "description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
2655
+ "type": "string"
2656
+ },
2657
+ "Account": { "oneOf": [
2658
+ {
2659
+ "properties": { "type": {
2660
+ "enum": ["apiKey"],
2661
+ "title": "ApiKeyAccountType",
2662
+ "type": "string"
2663
+ } },
2664
+ "required": ["type"],
2665
+ "title": "ApiKeyAccount",
2666
+ "type": "object"
2667
+ },
2668
+ {
2669
+ "properties": {
2670
+ "email": { "type": ["string", "null"] },
2671
+ "planType": { "$ref": "#/definitions/PlanType" },
2672
+ "type": {
2673
+ "enum": ["chatgpt"],
2674
+ "title": "ChatgptAccountType",
2675
+ "type": "string"
2676
+ }
2677
+ },
2678
+ "required": [
2679
+ "email",
2680
+ "planType",
2681
+ "type"
2682
+ ],
2683
+ "title": "ChatgptAccount",
2684
+ "type": "object"
2685
+ },
2686
+ {
2687
+ "properties": {
2688
+ "type": {
2689
+ "enum": ["amazonBedrock"],
2690
+ "title": "AmazonBedrockAccountType",
2691
+ "type": "string"
2692
+ },
2693
+ "usesCodexManagedCredentials": {
2694
+ "default": false,
2695
+ "type": "boolean"
2696
+ }
2697
+ },
2698
+ "required": ["type"],
2699
+ "title": "AmazonBedrockAccount",
2700
+ "type": "object"
2701
+ }
2702
+ ] },
2703
+ "ActivePermissionProfile": {
2704
+ "properties": {
2705
+ "extends": {
2706
+ "default": null,
2707
+ "description": "Parent profile identifier from the selected permissions profile's `extends` setting, when present.",
2708
+ "type": ["string", "null"]
2709
+ },
2710
+ "id": {
2711
+ "description": "Identifier from `default_permissions` or the implicit built-in default, such as `:workspace` or a user-defined `[permissions.<id>]` profile.",
2712
+ "type": "string"
2713
+ }
2714
+ },
2715
+ "required": ["id"],
2716
+ "type": "object"
2717
+ },
2718
+ "AgentMessageDelivery": {
2719
+ "enum": ["async"],
2720
+ "type": "string"
2721
+ },
2722
+ "AgentPath": { "type": "string" },
2723
+ "ApprovalsReviewer": {
2724
+ "description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `auto_review` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request. The legacy value `guardian_subagent` is accepted for compatibility.",
2725
+ "enum": [
2726
+ "user",
2727
+ "auto_review",
2728
+ "guardian_subagent"
2729
+ ],
2730
+ "type": "string"
2731
+ },
2732
+ "AskForApproval": { "oneOf": [{
2733
+ "additionalProperties": false,
2734
+ "properties": { "granular": {
2735
+ "properties": {
2736
+ "mcp_elicitations": { "type": "boolean" },
2737
+ "request_permissions": {
2738
+ "default": false,
2739
+ "type": "boolean"
2740
+ },
2741
+ "rules": { "type": "boolean" },
2742
+ "sandbox_approval": { "type": "boolean" },
2743
+ "skill_approval": {
2744
+ "default": false,
2745
+ "type": "boolean"
2746
+ }
2747
+ },
2748
+ "required": [
2749
+ "mcp_elicitations",
2750
+ "rules",
2751
+ "sandbox_approval"
2752
+ ],
2753
+ "type": "object"
2754
+ } },
2755
+ "required": ["granular"],
2756
+ "title": "GranularAskForApproval",
2757
+ "type": "object"
2758
+ }, {
2759
+ "enum": [
2760
+ "untrusted",
2761
+ "on-request",
2762
+ "never"
2763
+ ],
2764
+ "type": "string"
2765
+ }] },
2766
+ "ByteRange": {
2767
+ "properties": {
2768
+ "end": {
2769
+ "format": "uint",
2770
+ "minimum": 0,
2771
+ "type": "integer"
2772
+ },
2773
+ "start": {
2774
+ "format": "uint",
2775
+ "minimum": 0,
2776
+ "type": "integer"
2777
+ }
2778
+ },
2779
+ "required": ["end", "start"],
2780
+ "type": "object"
2781
+ },
2782
+ "CodexErrorInfo": {
2783
+ "description": "This translation layer make sure that we expose codex error code in camel case.\n\nWhen an upstream HTTP status is available (for example, from the Responses API or a provider), it is forwarded in `httpStatusCode` on the relevant `codexErrorInfo` variant.",
2784
+ "oneOf": [
2785
+ {
2786
+ "additionalProperties": false,
2787
+ "properties": { "httpConnectionFailed": {
2788
+ "properties": { "httpStatusCode": {
2789
+ "format": "uint16",
2790
+ "minimum": 0,
2791
+ "type": ["integer", "null"]
2792
+ } },
2793
+ "type": "object"
2794
+ } },
2795
+ "required": ["httpConnectionFailed"],
2796
+ "title": "HttpConnectionFailedCodexErrorInfo",
2797
+ "type": "object"
2798
+ },
2799
+ {
2800
+ "additionalProperties": false,
2801
+ "description": "Failed to connect to the response SSE stream.",
2802
+ "properties": { "responseStreamConnectionFailed": {
2803
+ "properties": { "httpStatusCode": {
2804
+ "format": "uint16",
2805
+ "minimum": 0,
2806
+ "type": ["integer", "null"]
2807
+ } },
2808
+ "type": "object"
2809
+ } },
2810
+ "required": ["responseStreamConnectionFailed"],
2811
+ "title": "ResponseStreamConnectionFailedCodexErrorInfo",
2812
+ "type": "object"
2813
+ },
2814
+ {
2815
+ "additionalProperties": false,
2816
+ "description": "The response SSE stream disconnected in the middle of a turn before completion.",
2817
+ "properties": { "responseStreamDisconnected": {
2818
+ "properties": { "httpStatusCode": {
2819
+ "format": "uint16",
2820
+ "minimum": 0,
2821
+ "type": ["integer", "null"]
2822
+ } },
2823
+ "type": "object"
2824
+ } },
2825
+ "required": ["responseStreamDisconnected"],
2826
+ "title": "ResponseStreamDisconnectedCodexErrorInfo",
2827
+ "type": "object"
2828
+ },
2829
+ {
2830
+ "additionalProperties": false,
2831
+ "description": "Reached the retry limit for responses.",
2832
+ "properties": { "responseTooManyFailedAttempts": {
2833
+ "properties": { "httpStatusCode": {
2834
+ "format": "uint16",
2835
+ "minimum": 0,
2836
+ "type": ["integer", "null"]
2837
+ } },
2838
+ "type": "object"
2839
+ } },
2840
+ "required": ["responseTooManyFailedAttempts"],
2841
+ "title": "ResponseTooManyFailedAttemptsCodexErrorInfo",
2842
+ "type": "object"
2843
+ },
2844
+ {
2845
+ "additionalProperties": false,
2846
+ "description": "Returned when `turn/start` or `turn/steer` is submitted while the current active turn cannot accept same-turn steering, for example `/review` or manual `/compact`.",
2847
+ "properties": { "activeTurnNotSteerable": {
2848
+ "properties": { "turnKind": { "$ref": "#/definitions/NonSteerableTurnKind" } },
2849
+ "required": ["turnKind"],
2850
+ "type": "object"
2851
+ } },
2852
+ "required": ["activeTurnNotSteerable"],
2853
+ "title": "ActiveTurnNotSteerableCodexErrorInfo",
2854
+ "type": "object"
2855
+ },
2856
+ {
2857
+ "enum": [
2858
+ "contextWindowExceeded",
2859
+ "sessionBudgetExceeded",
2860
+ "usageLimitExceeded",
2861
+ "rateLimitExceeded",
2862
+ "serverOverloaded",
2863
+ "cyberPolicy",
2864
+ "misalignmentPolicyViolation",
2865
+ "internalServerError",
2866
+ "unauthorized",
2867
+ "badRequest",
2868
+ "threadRollbackFailed",
2869
+ "sandboxError",
2870
+ "other"
2871
+ ],
2872
+ "type": "string"
2873
+ }
2874
+ ]
2875
+ },
2876
+ "CollabAgentState": {
2877
+ "properties": {
2878
+ "message": { "type": ["string", "null"] },
2879
+ "status": { "$ref": "#/definitions/CollabAgentStatus" }
2880
+ },
2881
+ "required": ["status"],
2882
+ "type": "object"
2883
+ },
2884
+ "CollabAgentStatus": {
2885
+ "enum": [
2886
+ "pendingInit",
2887
+ "running",
2888
+ "interrupted",
2889
+ "completed",
2890
+ "errored",
2891
+ "shutdown",
2892
+ "notFound"
2893
+ ],
2894
+ "type": "string"
2895
+ },
2896
+ "CollabAgentTool": {
2897
+ "enum": [
2898
+ "spawnAgent",
2899
+ "sendInput",
2900
+ "resumeAgent",
2901
+ "wait",
2902
+ "closeAgent",
2903
+ "sendMessage",
2904
+ "followupTask",
2905
+ "interruptAgent",
2906
+ "listAgents"
2907
+ ],
2908
+ "type": "string"
2909
+ },
2910
+ "CollabAgentToolCallStatus": {
2911
+ "enum": [
2912
+ "inProgress",
2913
+ "completed",
2914
+ "failed",
2915
+ "interrupted"
2916
+ ],
2917
+ "type": "string"
2918
+ },
2919
+ "CommandAction": { "oneOf": [
2920
+ {
2921
+ "properties": {
2922
+ "command": { "type": "string" },
2923
+ "name": { "type": "string" },
2924
+ "path": { "$ref": "#/definitions/LegacyAppPathString" },
2925
+ "type": {
2926
+ "enum": ["read"],
2927
+ "title": "ReadCommandActionType",
2928
+ "type": "string"
2929
+ }
2930
+ },
2931
+ "required": [
2932
+ "command",
2933
+ "name",
2934
+ "path",
2935
+ "type"
2936
+ ],
2937
+ "title": "ReadCommandAction",
2938
+ "type": "object"
2939
+ },
2940
+ {
2941
+ "properties": {
2942
+ "command": { "type": "string" },
2943
+ "path": { "type": ["string", "null"] },
2944
+ "type": {
2945
+ "enum": ["listFiles"],
2946
+ "title": "ListFilesCommandActionType",
2947
+ "type": "string"
2948
+ }
2949
+ },
2950
+ "required": ["command", "type"],
2951
+ "title": "ListFilesCommandAction",
2952
+ "type": "object"
2953
+ },
2954
+ {
2955
+ "properties": {
2956
+ "command": { "type": "string" },
2957
+ "path": { "type": ["string", "null"] },
2958
+ "query": { "type": ["string", "null"] },
2959
+ "type": {
2960
+ "enum": ["search"],
2961
+ "title": "SearchCommandActionType",
2962
+ "type": "string"
2963
+ }
2964
+ },
2965
+ "required": ["command", "type"],
2966
+ "title": "SearchCommandAction",
2967
+ "type": "object"
2968
+ },
2969
+ {
2970
+ "properties": {
2971
+ "command": { "type": "string" },
2972
+ "type": {
2973
+ "enum": ["unknown"],
2974
+ "title": "UnknownCommandActionType",
2975
+ "type": "string"
2976
+ }
2977
+ },
2978
+ "required": ["command", "type"],
2979
+ "title": "UnknownCommandAction",
2980
+ "type": "object"
2981
+ }
2982
+ ] },
2983
+ "CommandExecutionSource": {
2984
+ "enum": [
2985
+ "agent",
2986
+ "userShell",
2987
+ "unifiedExecStartup",
2988
+ "unifiedExecInteraction"
2989
+ ],
2990
+ "type": "string"
2991
+ },
2992
+ "CommandExecutionStatus": {
2993
+ "enum": [
2994
+ "inProgress",
2995
+ "completed",
2996
+ "failed",
2997
+ "declined"
2998
+ ],
2999
+ "type": "string"
3000
+ },
3001
+ "DynamicToolCallOutputContentItem": { "oneOf": [
3002
+ {
3003
+ "properties": {
3004
+ "text": { "type": "string" },
3005
+ "type": {
3006
+ "enum": ["inputText"],
3007
+ "title": "InputTextDynamicToolCallOutputContentItemType",
3008
+ "type": "string"
3009
+ }
3010
+ },
3011
+ "required": ["text", "type"],
3012
+ "title": "InputTextDynamicToolCallOutputContentItem",
3013
+ "type": "object"
3014
+ },
3015
+ {
3016
+ "properties": {
3017
+ "imageUrl": { "type": "string" },
3018
+ "type": {
3019
+ "enum": ["inputImage"],
3020
+ "title": "InputImageDynamicToolCallOutputContentItemType",
3021
+ "type": "string"
3022
+ }
3023
+ },
3024
+ "required": ["imageUrl", "type"],
3025
+ "title": "InputImageDynamicToolCallOutputContentItem",
3026
+ "type": "object"
3027
+ },
3028
+ {
3029
+ "properties": {
3030
+ "audioUrl": { "type": "string" },
3031
+ "type": {
3032
+ "enum": ["inputAudio"],
3033
+ "title": "InputAudioDynamicToolCallOutputContentItemType",
3034
+ "type": "string"
3035
+ }
3036
+ },
3037
+ "required": ["audioUrl", "type"],
3038
+ "title": "InputAudioDynamicToolCallOutputContentItem",
3039
+ "type": "object"
3040
+ }
3041
+ ] },
3042
+ "DynamicToolCallStatus": {
3043
+ "enum": [
3044
+ "inProgress",
3045
+ "completed",
3046
+ "failed"
3047
+ ],
3048
+ "type": "string"
3049
+ },
3050
+ "FileUpdateChange": {
3051
+ "properties": {
3052
+ "diff": { "type": "string" },
3053
+ "kind": { "$ref": "#/definitions/PatchChangeKind" },
3054
+ "path": { "type": "string" }
3055
+ },
3056
+ "required": [
3057
+ "diff",
3058
+ "kind",
3059
+ "path"
3060
+ ],
3061
+ "type": "object"
3062
+ },
3063
+ "FunctionCallOutputBody": { "anyOf": [{
3064
+ "items": { "$ref": "#/definitions/FunctionCallOutputContentItem" },
3065
+ "type": "array"
3066
+ }, { "type": "string" }] },
3067
+ "FunctionCallOutputContentItem": {
3068
+ "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
3069
+ "oneOf": [
3070
+ {
3071
+ "properties": {
3072
+ "text": { "type": "string" },
3073
+ "type": {
3074
+ "enum": ["input_text"],
3075
+ "title": "InputTextFunctionCallOutputContentItemType",
3076
+ "type": "string"
3077
+ }
3078
+ },
3079
+ "required": ["text", "type"],
3080
+ "title": "InputTextFunctionCallOutputContentItem",
3081
+ "type": "object"
3082
+ },
3083
+ {
3084
+ "properties": {
3085
+ "detail": { "anyOf": [{ "$ref": "#/definitions/ImageDetail" }, { "type": "null" }] },
3086
+ "image_url": { "type": "string" },
3087
+ "type": {
3088
+ "enum": ["input_image"],
3089
+ "title": "InputImageFunctionCallOutputContentItemType",
3090
+ "type": "string"
3091
+ }
3092
+ },
3093
+ "required": ["image_url", "type"],
3094
+ "title": "InputImageFunctionCallOutputContentItem",
3095
+ "type": "object"
3096
+ },
3097
+ {
3098
+ "properties": {
3099
+ "audio_url": { "type": "string" },
3100
+ "type": {
3101
+ "enum": ["input_audio"],
3102
+ "title": "InputAudioFunctionCallOutputContentItemType",
3103
+ "type": "string"
3104
+ }
3105
+ },
3106
+ "required": ["audio_url", "type"],
3107
+ "title": "InputAudioFunctionCallOutputContentItem",
3108
+ "type": "object"
3109
+ },
3110
+ {
3111
+ "properties": {
3112
+ "encrypted_content": { "type": "string" },
3113
+ "type": {
3114
+ "enum": ["encrypted_content"],
3115
+ "title": "EncryptedContentFunctionCallOutputContentItemType",
3116
+ "type": "string"
3117
+ }
3118
+ },
3119
+ "required": ["encrypted_content", "type"],
3120
+ "title": "EncryptedContentFunctionCallOutputContentItem",
3121
+ "type": "object"
3122
+ }
3123
+ ]
3124
+ },
3125
+ "GitInfo": {
3126
+ "properties": {
3127
+ "branch": { "type": ["string", "null"] },
3128
+ "originUrl": { "type": ["string", "null"] },
3129
+ "sha": { "type": ["string", "null"] }
3130
+ },
3131
+ "type": "object"
3132
+ },
3133
+ "HookPromptFragment": {
3134
+ "properties": {
3135
+ "hookRunId": { "type": "string" },
3136
+ "text": { "type": "string" }
3137
+ },
3138
+ "required": ["hookRunId", "text"],
3139
+ "type": "object"
3140
+ },
3141
+ "ImageDetail": {
3142
+ "enum": [
3143
+ "auto",
3144
+ "low",
3145
+ "high",
3146
+ "original"
3147
+ ],
3148
+ "type": "string"
3149
+ },
3150
+ "ImageGenerationFailure": { "oneOf": [{
3151
+ "properties": {
3152
+ "limitId": { "type": "string" },
3153
+ "resetsAt": {
3154
+ "format": "int64",
3155
+ "type": ["integer", "null"]
3156
+ },
3157
+ "type": {
3158
+ "enum": ["usageLimitExceeded"],
3159
+ "title": "UsageLimitExceededImageGenerationFailureType",
3160
+ "type": "string"
3161
+ }
3162
+ },
3163
+ "required": ["limitId", "type"],
3164
+ "title": "UsageLimitExceededImageGenerationFailure",
3165
+ "type": "object"
3166
+ }] },
3167
+ "InputModality": {
3168
+ "description": "Canonical user-input modality tags advertised by a model.",
3169
+ "oneOf": [
3170
+ {
3171
+ "description": "Plain text turns and tool payloads.",
3172
+ "enum": ["text"],
3173
+ "type": "string"
3174
+ },
3175
+ {
3176
+ "description": "Image attachments included in user turns.",
3177
+ "enum": ["image"],
3178
+ "type": "string"
3179
+ },
3180
+ {
3181
+ "description": "Audio attachments included in user turns.",
3182
+ "enum": ["audio"],
3183
+ "type": "string"
3184
+ }
3185
+ ]
3186
+ },
3187
+ "LegacyAppPathString": { "type": "string" },
3188
+ "McpToolCallAppContext": {
3189
+ "properties": {
3190
+ "actionName": { "type": ["string", "null"] },
3191
+ "appName": { "type": ["string", "null"] },
3192
+ "connectorId": { "type": "string" },
3193
+ "linkId": { "type": ["string", "null"] },
3194
+ "resourceUri": { "type": ["string", "null"] }
3195
+ },
3196
+ "required": ["connectorId"],
3197
+ "type": "object"
3198
+ },
3199
+ "McpToolCallError": {
3200
+ "properties": { "message": { "type": "string" } },
3201
+ "required": ["message"],
3202
+ "type": "object"
3203
+ },
3204
+ "McpToolCallResult": {
3205
+ "properties": {
3206
+ "_meta": true,
3207
+ "content": {
3208
+ "items": true,
3209
+ "type": "array"
3210
+ },
3211
+ "structuredContent": true
3212
+ },
3213
+ "required": ["content"],
3214
+ "type": "object"
3215
+ },
3216
+ "McpToolCallStatus": {
3217
+ "enum": [
3218
+ "inProgress",
3219
+ "completed",
3220
+ "failed"
3221
+ ],
3222
+ "type": "string"
3223
+ },
3224
+ "MemoryCitation": {
3225
+ "properties": {
3226
+ "entries": {
3227
+ "items": { "$ref": "#/definitions/MemoryCitationEntry" },
3228
+ "type": "array"
3229
+ },
3230
+ "threadIds": {
3231
+ "items": { "type": "string" },
3232
+ "type": "array"
3233
+ }
3234
+ },
3235
+ "required": ["entries", "threadIds"],
3236
+ "type": "object"
3237
+ },
3238
+ "MemoryCitationEntry": {
3239
+ "properties": {
3240
+ "lineEnd": {
3241
+ "format": "uint32",
3242
+ "minimum": 0,
3243
+ "type": "integer"
3244
+ },
3245
+ "lineStart": {
3246
+ "format": "uint32",
3247
+ "minimum": 0,
3248
+ "type": "integer"
3249
+ },
3250
+ "note": { "type": "string" },
3251
+ "path": { "type": "string" }
3252
+ },
3253
+ "required": [
3254
+ "lineEnd",
3255
+ "lineStart",
3256
+ "note",
3257
+ "path"
3258
+ ],
3259
+ "type": "object"
3260
+ },
3261
+ "MessagePhase": {
3262
+ "description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
3263
+ "oneOf": [{
3264
+ "description": "Mid-turn assistant text (for example preamble/progress narration).\n\nAdditional tool calls or assistant output may follow before turn completion.",
3265
+ "enum": ["commentary"],
3266
+ "type": "string"
3267
+ }, {
3268
+ "description": "The assistant's terminal answer text for the current turn.",
3269
+ "enum": ["final_answer"],
3270
+ "type": "string"
3271
+ }]
3272
+ },
3273
+ "MisalignmentErrorDetails": {
3274
+ "properties": {
3275
+ "detailedExplanation": {
3276
+ "description": "A substantive localized explanation is required before offering continuation.",
3277
+ "type": ["string", "null"]
3278
+ },
3279
+ "errorType": {
3280
+ "description": "Open-ended classification; clients must accept categories added by Responses.",
3281
+ "type": ["string", "null"]
3282
+ },
3283
+ "steer": {
3284
+ "anyOf": [{ "$ref": "#/definitions/MisalignmentSteer" }, { "type": "null" }],
3285
+ "description": "Instruction to submit as the next turn's user input if continuation is confirmed."
3286
+ }
3287
+ },
3288
+ "type": "object"
3289
+ },
3290
+ "MisalignmentSteer": {
3291
+ "properties": { "message": { "type": "string" } },
3292
+ "required": ["message"],
3293
+ "type": "object"
3294
+ },
3295
+ "Model": {
3296
+ "properties": {
3297
+ "additionalSpeedTiers": {
3298
+ "default": [],
3299
+ "description": "Deprecated: use `serviceTiers` instead.",
3300
+ "items": { "type": "string" },
3301
+ "type": "array"
3302
+ },
3303
+ "availabilityNux": { "anyOf": [{ "$ref": "#/definitions/ModelAvailabilityNux" }, { "type": "null" }] },
3304
+ "defaultReasoningEffort": { "$ref": "#/definitions/ReasoningEffort" },
3305
+ "defaultServiceTier": {
3306
+ "default": null,
3307
+ "description": "Catalog default service tier id for this model, when one is configured.",
3308
+ "type": ["string", "null"]
3309
+ },
3310
+ "description": { "type": "string" },
3311
+ "displayName": { "type": "string" },
3312
+ "hidden": { "type": "boolean" },
3313
+ "id": { "type": "string" },
3314
+ "inputModalities": {
3315
+ "default": ["text", "image"],
3316
+ "items": { "$ref": "#/definitions/InputModality" },
3317
+ "type": "array"
3318
+ },
3319
+ "isDefault": { "type": "boolean" },
3320
+ "model": { "type": "string" },
3321
+ "modelSpecialty": {
3322
+ "default": null,
3323
+ "type": ["string", "null"]
3324
+ },
3325
+ "multiAgentVersion": {
3326
+ "anyOf": [{ "$ref": "#/definitions/MultiAgentVersion" }, { "type": "null" }],
3327
+ "description": "Multi-agent runtime declared by this model, when available."
3328
+ },
3329
+ "serviceTiers": {
3330
+ "default": [],
3331
+ "items": { "$ref": "#/definitions/ModelServiceTier" },
3332
+ "type": "array"
3333
+ },
3334
+ "supportedReasoningEfforts": {
3335
+ "items": { "$ref": "#/definitions/ReasoningEffortOption" },
3336
+ "type": "array"
3337
+ },
3338
+ "supportsPersonality": {
3339
+ "default": false,
3340
+ "type": "boolean"
3341
+ },
3342
+ "upgrade": { "type": ["string", "null"] },
3343
+ "upgradeInfo": { "anyOf": [{ "$ref": "#/definitions/ModelUpgradeInfo" }, { "type": "null" }] }
3344
+ },
3345
+ "required": [
3346
+ "defaultReasoningEffort",
3347
+ "description",
3348
+ "displayName",
3349
+ "hidden",
3350
+ "id",
3351
+ "isDefault",
3352
+ "model",
3353
+ "supportedReasoningEfforts"
3354
+ ],
3355
+ "type": "object"
3356
+ },
3357
+ "ModelAvailabilityNux": {
3358
+ "properties": { "message": { "type": "string" } },
3359
+ "required": ["message"],
3360
+ "type": "object"
3361
+ },
3362
+ "ModelServiceTier": {
3363
+ "properties": {
3364
+ "description": { "type": "string" },
3365
+ "id": { "type": "string" },
3366
+ "name": { "type": "string" }
3367
+ },
3368
+ "required": [
3369
+ "description",
3370
+ "id",
3371
+ "name"
3372
+ ],
3373
+ "type": "object"
3374
+ },
3375
+ "ModelUpgradeInfo": {
3376
+ "properties": {
3377
+ "migrationMarkdown": { "type": ["string", "null"] },
3378
+ "model": { "type": "string" },
3379
+ "modelLink": { "type": ["string", "null"] },
3380
+ "retirementAt": {
3381
+ "description": "Informational Unix timestamp for this upgrade's scheduled retirement, if known.",
3382
+ "format": "int64",
3383
+ "type": ["integer", "null"]
3384
+ },
3385
+ "upgradeCopy": { "type": ["string", "null"] }
3386
+ },
3387
+ "required": ["model"],
3388
+ "type": "object"
3389
+ },
3390
+ "MultiAgentMode": {
3391
+ "description": "Controls the effective multi-agent delegation instructions for a turn. `custom` means the configured mode hint defines the policy instead of a built-in policy.",
3392
+ "oneOf": [{
3393
+ "additionalProperties": false,
3394
+ "properties": { "custom": { "type": "string" } },
3395
+ "required": ["custom"],
3396
+ "title": "CustomMultiAgentMode",
3397
+ "type": "object"
3398
+ }, {
3399
+ "enum": ["explicitRequestOnly", "proactive"],
3400
+ "type": "string"
3401
+ }]
3402
+ },
3403
+ "MultiAgentVersion": {
3404
+ "description": "Multi-agent runtime supported by a model.",
3405
+ "enum": [
3406
+ "disabled",
3407
+ "v1",
3408
+ "v2"
3409
+ ],
3410
+ "type": "string"
3411
+ },
3412
+ "NetworkAccess": {
3413
+ "enum": ["restricted", "enabled"],
3414
+ "type": "string"
3415
+ },
3416
+ "NonSteerableTurnKind": {
3417
+ "enum": ["review", "compact"],
3418
+ "type": "string"
3419
+ },
3420
+ "PatchApplyStatus": {
3421
+ "enum": [
3422
+ "inProgress",
3423
+ "completed",
3424
+ "failed",
3425
+ "declined"
3426
+ ],
3427
+ "type": "string"
3428
+ },
3429
+ "PatchChangeKind": { "oneOf": [
3430
+ {
3431
+ "properties": { "type": {
3432
+ "enum": ["add"],
3433
+ "title": "AddPatchChangeKindType",
3434
+ "type": "string"
3435
+ } },
3436
+ "required": ["type"],
3437
+ "title": "AddPatchChangeKind",
3438
+ "type": "object"
3439
+ },
3440
+ {
3441
+ "properties": { "type": {
3442
+ "enum": ["delete"],
3443
+ "title": "DeletePatchChangeKindType",
3444
+ "type": "string"
3445
+ } },
3446
+ "required": ["type"],
3447
+ "title": "DeletePatchChangeKind",
3448
+ "type": "object"
3449
+ },
3450
+ {
3451
+ "properties": {
3452
+ "move_path": { "type": ["string", "null"] },
3453
+ "type": {
3454
+ "enum": ["update"],
3455
+ "title": "UpdatePatchChangeKindType",
3456
+ "type": "string"
3457
+ }
3458
+ },
3459
+ "required": ["type"],
3460
+ "title": "UpdatePatchChangeKind",
3461
+ "type": "object"
3462
+ }
3463
+ ] },
3464
+ "PlanType": {
3465
+ "enum": [
3466
+ "free",
3467
+ "go",
3468
+ "plus",
3469
+ "pro",
3470
+ "prolite",
3471
+ "team",
3472
+ "self_serve_business_prolite",
3473
+ "self_serve_business_usage_based",
3474
+ "business",
3475
+ "ent26",
3476
+ "enterprise_cbp_automation",
3477
+ "enterprise_cbp_usage_based",
3478
+ "enterprise",
3479
+ "edu",
3480
+ "edu_plus",
3481
+ "edu_pro",
3482
+ "unknown"
3483
+ ],
3484
+ "type": "string"
3485
+ },
3486
+ "ReasoningEffort": {
3487
+ "description": "A non-empty reasoning effort value advertised by the model.",
3488
+ "minLength": 1,
3489
+ "type": "string"
3490
+ },
3491
+ "ReasoningEffortOption": {
3492
+ "properties": {
3493
+ "description": { "type": "string" },
3494
+ "reasoningEffort": { "$ref": "#/definitions/ReasoningEffort" }
3495
+ },
3496
+ "required": ["description", "reasoningEffort"],
3497
+ "type": "object"
3498
+ },
3499
+ "SandboxPolicy": { "oneOf": [
3500
+ {
3501
+ "properties": { "type": {
3502
+ "enum": ["dangerFullAccess"],
3503
+ "title": "DangerFullAccessSandboxPolicyType",
3504
+ "type": "string"
3505
+ } },
3506
+ "required": ["type"],
3507
+ "title": "DangerFullAccessSandboxPolicy",
3508
+ "type": "object"
3509
+ },
3510
+ {
3511
+ "properties": {
3512
+ "networkAccess": {
3513
+ "default": false,
3514
+ "type": "boolean"
3515
+ },
3516
+ "type": {
3517
+ "enum": ["readOnly"],
3518
+ "title": "ReadOnlySandboxPolicyType",
3519
+ "type": "string"
3520
+ }
3521
+ },
3522
+ "required": ["type"],
3523
+ "title": "ReadOnlySandboxPolicy",
3524
+ "type": "object"
3525
+ },
3526
+ {
3527
+ "properties": {
3528
+ "networkAccess": {
3529
+ "allOf": [{ "$ref": "#/definitions/NetworkAccess" }],
3530
+ "default": "restricted"
3531
+ },
3532
+ "type": {
3533
+ "enum": ["externalSandbox"],
3534
+ "title": "ExternalSandboxSandboxPolicyType",
3535
+ "type": "string"
3536
+ }
3537
+ },
3538
+ "required": ["type"],
3539
+ "title": "ExternalSandboxSandboxPolicy",
3540
+ "type": "object"
3541
+ },
3542
+ {
3543
+ "properties": {
3544
+ "excludeSlashTmp": {
3545
+ "default": false,
3546
+ "type": "boolean"
3547
+ },
3548
+ "excludeTmpdirEnvVar": {
3549
+ "default": false,
3550
+ "type": "boolean"
3551
+ },
3552
+ "networkAccess": {
3553
+ "default": false,
3554
+ "type": "boolean"
3555
+ },
3556
+ "type": {
3557
+ "enum": ["workspaceWrite"],
3558
+ "title": "WorkspaceWriteSandboxPolicyType",
3559
+ "type": "string"
3560
+ },
3561
+ "writableRoots": {
3562
+ "default": [],
3563
+ "items": { "$ref": "#/definitions/AbsolutePathBuf" },
3564
+ "type": "array"
3565
+ }
3566
+ },
3567
+ "required": ["type"],
3568
+ "title": "WorkspaceWriteSandboxPolicy",
3569
+ "type": "object"
3570
+ }
3571
+ ] },
3572
+ "SessionSource": { "oneOf": [
3573
+ {
3574
+ "additionalProperties": false,
3575
+ "properties": { "custom": { "type": "string" } },
3576
+ "required": ["custom"],
3577
+ "title": "CustomSessionSource",
3578
+ "type": "object"
3579
+ },
3580
+ {
3581
+ "additionalProperties": false,
3582
+ "properties": { "subAgent": { "$ref": "#/definitions/SubAgentSource" } },
3583
+ "required": ["subAgent"],
3584
+ "title": "SubAgentSessionSource",
3585
+ "type": "object"
3586
+ },
3587
+ {
3588
+ "enum": [
3589
+ "cli",
3590
+ "vscode",
3591
+ "exec",
3592
+ "appServer",
3593
+ "unknown"
3594
+ ],
3595
+ "type": "string"
3596
+ }
3597
+ ] },
3598
+ "SubAgentActivityKind": {
3599
+ "enum": [
3600
+ "started",
3601
+ "interacted",
3602
+ "interrupted",
3603
+ "completed"
3604
+ ],
3605
+ "type": "string"
3606
+ },
3607
+ "SubAgentSource": { "oneOf": [
3608
+ {
3609
+ "additionalProperties": false,
3610
+ "properties": { "thread_spawn": {
3611
+ "properties": {
3612
+ "agent_nickname": {
3613
+ "default": null,
3614
+ "type": ["string", "null"]
3615
+ },
3616
+ "agent_path": {
3617
+ "anyOf": [{ "$ref": "#/definitions/AgentPath" }, { "type": "null" }],
3618
+ "default": null
3619
+ },
3620
+ "agent_role": {
3621
+ "default": null,
3622
+ "type": ["string", "null"]
3623
+ },
3624
+ "depth": {
3625
+ "format": "int32",
3626
+ "type": "integer"
3627
+ },
3628
+ "parent_thread_id": { "$ref": "#/definitions/ThreadId" }
3629
+ },
3630
+ "required": ["depth", "parent_thread_id"],
3631
+ "type": "object"
3632
+ } },
3633
+ "required": ["thread_spawn"],
3634
+ "title": "ThreadSpawnSubAgentSource",
3635
+ "type": "object"
3636
+ },
3637
+ {
3638
+ "additionalProperties": false,
3639
+ "properties": { "other": { "type": "string" } },
3640
+ "required": ["other"],
3641
+ "title": "OtherSubAgentSource",
3642
+ "type": "object"
3643
+ },
3644
+ {
3645
+ "enum": [
3646
+ "review",
3647
+ "compact",
3648
+ "memory_consolidation"
3649
+ ],
3650
+ "type": "string"
3651
+ }
3652
+ ] },
3653
+ "TextElement": {
3654
+ "properties": {
3655
+ "byteRange": {
3656
+ "allOf": [{ "$ref": "#/definitions/ByteRange" }],
3657
+ "description": "Byte range in the parent `text` buffer that this element occupies."
3658
+ },
3659
+ "placeholder": {
3660
+ "description": "Optional human-readable placeholder for the element, displayed in the UI.",
3661
+ "type": ["string", "null"]
3662
+ }
3663
+ },
3664
+ "required": ["byteRange"],
3665
+ "type": "object"
3666
+ },
3667
+ "Thread": {
3668
+ "properties": {
3669
+ "agentNickname": {
3670
+ "description": "Optional random unique nickname assigned to an AgentControl-spawned sub-agent.",
3671
+ "type": ["string", "null"]
3672
+ },
3673
+ "agentRole": {
3674
+ "description": "Optional role (agent_role) assigned to an AgentControl-spawned sub-agent.",
3675
+ "type": ["string", "null"]
3676
+ },
3677
+ "canAcceptDirectInput": {
3678
+ "description": "Whether the app server accepts direct turn input for this loaded thread. `None` means the capability is unavailable, such as for an unloaded stored thread.",
3679
+ "type": ["boolean", "null"]
3680
+ },
3681
+ "cliVersion": {
3682
+ "description": "Version of the CLI that created the thread.",
3683
+ "type": "string"
3684
+ },
3685
+ "createdAt": {
3686
+ "description": "Unix timestamp (in seconds) when the thread was created.",
3687
+ "format": "int64",
3688
+ "type": "integer"
3689
+ },
3690
+ "cwd": {
3691
+ "allOf": [{ "$ref": "#/definitions/AbsolutePathBuf" }],
3692
+ "description": "Working directory captured for the thread."
3693
+ },
3694
+ "ephemeral": {
3695
+ "description": "Whether the thread is ephemeral and should not be materialized on disk.",
3696
+ "type": "boolean"
3697
+ },
3698
+ "extra": {
3699
+ "anyOf": [{ "$ref": "#/definitions/ThreadExtra" }, { "type": "null" }],
3700
+ "description": "Optional implementation-specific thread data."
3701
+ },
3702
+ "forkedFromId": {
3703
+ "description": "Source thread id when this thread was created by forking another thread.",
3704
+ "type": ["string", "null"]
3705
+ },
3706
+ "gitInfo": {
3707
+ "anyOf": [{ "$ref": "#/definitions/GitInfo" }, { "type": "null" }],
3708
+ "description": "Optional Git metadata captured when the thread was created."
3709
+ },
3710
+ "historyMode": {
3711
+ "allOf": [{ "$ref": "#/definitions/ThreadHistoryMode" }],
3712
+ "default": "legacy",
3713
+ "description": "Persisted thread history contract selected when this thread was created."
3714
+ },
3715
+ "id": {
3716
+ "description": "Identifier for this thread. Codex-generated thread IDs are UUIDv7.",
3717
+ "type": "string"
3718
+ },
3719
+ "modelProvider": {
3720
+ "description": "Model provider used for this thread (for example, 'openai').",
3721
+ "type": "string"
3722
+ },
3723
+ "name": {
3724
+ "description": "Optional user-facing thread title.",
3725
+ "type": ["string", "null"]
3726
+ },
3727
+ "parentThreadId": {
3728
+ "description": "The ID of the parent thread. This will only be set if this thread is a subagent.",
3729
+ "type": ["string", "null"]
3730
+ },
3731
+ "path": {
3732
+ "description": "[UNSTABLE] Path to the thread on disk.",
3733
+ "type": ["string", "null"]
3734
+ },
3735
+ "preview": {
3736
+ "description": "Usually the first user message in the thread, if available.",
3737
+ "type": "string"
3738
+ },
3739
+ "projectId": {
3740
+ "description": "Canonical project assignment owned by app-server, if any.",
3741
+ "type": ["string", "null"]
3742
+ },
3743
+ "recencyAt": {
3744
+ "description": "Unix timestamp (in seconds) used for thread recency ordering.",
3745
+ "format": "int64",
3746
+ "type": ["integer", "null"]
3747
+ },
3748
+ "section": {
3749
+ "anyOf": [{ "$ref": "#/definitions/ThreadSection" }, { "type": "null" }],
3750
+ "default": null,
3751
+ "description": "The independently persisted section selected for this thread, if any."
3752
+ },
3753
+ "sectionEnteredAt": {
3754
+ "default": null,
3755
+ "description": "Unix timestamp in seconds when the thread entered its current section.",
3756
+ "format": "int64",
3757
+ "type": ["integer", "null"]
3758
+ },
3759
+ "sessionId": {
3760
+ "description": "Session id shared by threads that belong to the same session tree.",
3761
+ "type": "string"
3762
+ },
3763
+ "source": {
3764
+ "allOf": [{ "$ref": "#/definitions/SessionSource" }],
3765
+ "description": "Origin of the thread (CLI, VSCode, codex exec, codex app-server, etc.)."
3766
+ },
3767
+ "status": {
3768
+ "allOf": [{ "$ref": "#/definitions/ThreadStatus" }],
3769
+ "description": "Current runtime status for the thread."
3770
+ },
3771
+ "threadSource": {
3772
+ "anyOf": [{ "$ref": "#/definitions/ThreadSource" }, { "type": "null" }],
3773
+ "description": "Optional analytics source classification for this thread."
3774
+ },
3775
+ "turns": {
3776
+ "description": "Only populated on `thread/resume`, `thread/rollback`, `thread/fork`, and `thread/read` (when `includeTurns` is true) responses. For all other responses and notifications returning a Thread, the turns field will be an empty list.",
3777
+ "items": { "$ref": "#/definitions/Turn" },
3778
+ "type": "array"
3779
+ },
3780
+ "updatedAt": {
3781
+ "description": "Unix timestamp (in seconds) when the thread was last updated.",
3782
+ "format": "int64",
3783
+ "type": "integer"
3784
+ }
3785
+ },
3786
+ "required": [
3787
+ "cliVersion",
3788
+ "createdAt",
3789
+ "cwd",
3790
+ "ephemeral",
3791
+ "id",
3792
+ "modelProvider",
3793
+ "preview",
3794
+ "projectId",
3795
+ "sessionId",
3796
+ "source",
3797
+ "status",
3798
+ "turns",
3799
+ "updatedAt"
3800
+ ],
3801
+ "type": "object"
3802
+ },
3803
+ "ThreadActiveFlag": {
3804
+ "enum": ["waitingOnApproval", "waitingOnUserInput"],
3805
+ "type": "string"
3806
+ },
3807
+ "ThreadExtra": {
3808
+ "description": "Extra app-server data for a thread.",
3809
+ "type": "object"
3810
+ },
3811
+ "ThreadHistoryMode": {
3812
+ "enum": ["legacy", "paginated"],
3813
+ "type": "string"
3814
+ },
3815
+ "ThreadId": { "type": "string" },
3816
+ "ThreadItem": { "oneOf": [
3817
+ {
3818
+ "properties": {
3819
+ "clientId": { "type": ["string", "null"] },
3820
+ "content": {
3821
+ "items": { "$ref": "#/definitions/UserInput" },
3822
+ "type": "array"
3823
+ },
3824
+ "id": { "type": "string" },
3825
+ "type": {
3826
+ "enum": ["userMessage"],
3827
+ "title": "UserMessageThreadItemType",
3828
+ "type": "string"
3829
+ }
3830
+ },
3831
+ "required": [
3832
+ "content",
3833
+ "id",
3834
+ "type"
3835
+ ],
3836
+ "title": "UserMessageThreadItem",
3837
+ "type": "object"
3838
+ },
3839
+ {
3840
+ "properties": {
3841
+ "fragments": {
3842
+ "items": { "$ref": "#/definitions/HookPromptFragment" },
3843
+ "type": "array"
3844
+ },
3845
+ "id": { "type": "string" },
3846
+ "type": {
3847
+ "enum": ["hookPrompt"],
3848
+ "title": "HookPromptThreadItemType",
3849
+ "type": "string"
3850
+ }
3851
+ },
3852
+ "required": [
3853
+ "fragments",
3854
+ "id",
3855
+ "type"
3856
+ ],
3857
+ "title": "HookPromptThreadItem",
3858
+ "type": "object"
3859
+ },
3860
+ {
3861
+ "properties": {
3862
+ "delivery": {
3863
+ "anyOf": [{ "$ref": "#/definitions/AgentMessageDelivery" }, { "type": "null" }],
3864
+ "default": null
3865
+ },
3866
+ "id": { "type": "string" },
3867
+ "memoryCitation": {
3868
+ "anyOf": [{ "$ref": "#/definitions/MemoryCitation" }, { "type": "null" }],
3869
+ "default": null
3870
+ },
3871
+ "phase": {
3872
+ "anyOf": [{ "$ref": "#/definitions/MessagePhase" }, { "type": "null" }],
3873
+ "default": null
3874
+ },
3875
+ "text": { "type": "string" },
3876
+ "type": {
3877
+ "enum": ["agentMessage"],
3878
+ "title": "AgentMessageThreadItemType",
3879
+ "type": "string"
3880
+ }
3881
+ },
3882
+ "required": [
3883
+ "id",
3884
+ "text",
3885
+ "type"
3886
+ ],
3887
+ "title": "AgentMessageThreadItem",
3888
+ "type": "object"
3889
+ },
3890
+ {
3891
+ "properties": {
3892
+ "id": { "type": "string" },
3893
+ "name": { "type": "string" },
3894
+ "namespace": { "type": ["string", "null"] },
3895
+ "output": { "$ref": "#/definitions/FunctionCallOutputBody" },
3896
+ "type": {
3897
+ "enum": ["functionCallOutput"],
3898
+ "title": "FunctionCallOutputThreadItemType",
3899
+ "type": "string"
3900
+ }
3901
+ },
3902
+ "required": [
3903
+ "id",
3904
+ "name",
3905
+ "output",
3906
+ "type"
3907
+ ],
3908
+ "title": "FunctionCallOutputThreadItem",
3909
+ "type": "object"
3910
+ },
3911
+ {
3912
+ "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
3913
+ "properties": {
3914
+ "id": { "type": "string" },
3915
+ "text": { "type": "string" },
3916
+ "type": {
3917
+ "enum": ["plan"],
3918
+ "title": "PlanThreadItemType",
3919
+ "type": "string"
3920
+ }
3921
+ },
3922
+ "required": [
3923
+ "id",
3924
+ "text",
3925
+ "type"
3926
+ ],
3927
+ "title": "PlanThreadItem",
3928
+ "type": "object"
3929
+ },
3930
+ {
3931
+ "properties": {
3932
+ "content": {
3933
+ "default": [],
3934
+ "items": { "type": "string" },
3935
+ "type": "array"
3936
+ },
3937
+ "id": { "type": "string" },
3938
+ "summary": {
3939
+ "default": [],
3940
+ "items": { "type": "string" },
3941
+ "type": "array"
3942
+ },
3943
+ "type": {
3944
+ "enum": ["reasoning"],
3945
+ "title": "ReasoningThreadItemType",
3946
+ "type": "string"
3947
+ }
3948
+ },
3949
+ "required": ["id", "type"],
3950
+ "title": "ReasoningThreadItem",
3951
+ "type": "object"
3952
+ },
3953
+ {
3954
+ "properties": {
3955
+ "aggregatedOutput": {
3956
+ "description": "The command's output, aggregated from stdout and stderr.",
3957
+ "type": ["string", "null"]
3958
+ },
3959
+ "command": {
3960
+ "description": "The command to be executed.",
3961
+ "type": "string"
3962
+ },
3963
+ "commandActions": {
3964
+ "description": "A best-effort parsing of the command to understand the action(s) it will perform. This returns a list of CommandAction objects because a single shell command may be composed of many commands piped together.",
3965
+ "items": { "$ref": "#/definitions/CommandAction" },
3966
+ "type": "array"
3967
+ },
3968
+ "cwd": {
3969
+ "allOf": [{ "$ref": "#/definitions/LegacyAppPathString" }],
3970
+ "description": "The command's working directory."
3971
+ },
3972
+ "durationMs": {
3973
+ "description": "The duration of the command execution in milliseconds.",
3974
+ "format": "int64",
3975
+ "type": ["integer", "null"]
3976
+ },
3977
+ "exitCode": {
3978
+ "description": "The command's exit code.",
3979
+ "format": "int32",
3980
+ "type": ["integer", "null"]
3981
+ },
3982
+ "id": { "type": "string" },
3983
+ "pluginId": {
3984
+ "default": null,
3985
+ "description": "Trusted first-party plugin id when this command resolves to one plugin script.",
3986
+ "type": ["string", "null"]
3987
+ },
3988
+ "processId": {
3989
+ "description": "Identifier for the underlying PTY process (when available).",
3990
+ "type": ["string", "null"]
3991
+ },
3992
+ "scriptPath": {
3993
+ "default": null,
3994
+ "description": "Safe plugin-relative path when this command resolves to one plugin script.",
3995
+ "type": ["string", "null"]
3996
+ },
3997
+ "source": {
3998
+ "allOf": [{ "$ref": "#/definitions/CommandExecutionSource" }],
3999
+ "default": "agent"
4000
+ },
4001
+ "status": { "$ref": "#/definitions/CommandExecutionStatus" },
4002
+ "type": {
4003
+ "enum": ["commandExecution"],
4004
+ "title": "CommandExecutionThreadItemType",
4005
+ "type": "string"
4006
+ }
4007
+ },
4008
+ "required": [
4009
+ "command",
4010
+ "commandActions",
4011
+ "cwd",
4012
+ "id",
4013
+ "status",
4014
+ "type"
4015
+ ],
4016
+ "title": "CommandExecutionThreadItem",
4017
+ "type": "object"
4018
+ },
4019
+ {
4020
+ "properties": {
4021
+ "changes": {
4022
+ "items": { "$ref": "#/definitions/FileUpdateChange" },
4023
+ "type": "array"
4024
+ },
4025
+ "id": { "type": "string" },
4026
+ "status": { "$ref": "#/definitions/PatchApplyStatus" },
4027
+ "type": {
4028
+ "enum": ["fileChange"],
4029
+ "title": "FileChangeThreadItemType",
4030
+ "type": "string"
4031
+ }
4032
+ },
4033
+ "required": [
4034
+ "changes",
4035
+ "id",
4036
+ "status",
4037
+ "type"
4038
+ ],
4039
+ "title": "FileChangeThreadItem",
4040
+ "type": "object"
4041
+ },
4042
+ {
4043
+ "properties": {
4044
+ "appContext": { "anyOf": [{ "$ref": "#/definitions/McpToolCallAppContext" }, { "type": "null" }] },
4045
+ "arguments": true,
4046
+ "durationMs": {
4047
+ "description": "The duration of the MCP tool call in milliseconds.",
4048
+ "format": "int64",
4049
+ "type": ["integer", "null"]
4050
+ },
4051
+ "error": { "anyOf": [{ "$ref": "#/definitions/McpToolCallError" }, { "type": "null" }] },
4052
+ "id": { "type": "string" },
4053
+ "mcpAppResourceUri": {
4054
+ "description": "Deprecated: use `appContext.resourceUri` instead.",
4055
+ "type": ["string", "null"]
4056
+ },
4057
+ "pluginId": { "type": ["string", "null"] },
4058
+ "readOnlyHint": { "type": ["boolean", "null"] },
4059
+ "result": { "anyOf": [{ "$ref": "#/definitions/McpToolCallResult" }, { "type": "null" }] },
4060
+ "server": { "type": "string" },
4061
+ "status": { "$ref": "#/definitions/McpToolCallStatus" },
4062
+ "tool": { "type": "string" },
4063
+ "type": {
4064
+ "enum": ["mcpToolCall"],
4065
+ "title": "McpToolCallThreadItemType",
4066
+ "type": "string"
4067
+ }
4068
+ },
4069
+ "required": [
4070
+ "arguments",
4071
+ "id",
4072
+ "server",
4073
+ "status",
4074
+ "tool",
4075
+ "type"
4076
+ ],
4077
+ "title": "McpToolCallThreadItem",
4078
+ "type": "object"
4079
+ },
4080
+ {
4081
+ "properties": {
4082
+ "arguments": true,
4083
+ "contentItems": {
4084
+ "items": { "$ref": "#/definitions/DynamicToolCallOutputContentItem" },
4085
+ "type": ["array", "null"]
4086
+ },
4087
+ "durationMs": {
4088
+ "description": "The duration of the dynamic tool call in milliseconds.",
4089
+ "format": "int64",
4090
+ "type": ["integer", "null"]
4091
+ },
4092
+ "id": { "type": "string" },
4093
+ "namespace": { "type": ["string", "null"] },
4094
+ "status": { "$ref": "#/definitions/DynamicToolCallStatus" },
4095
+ "success": { "type": ["boolean", "null"] },
4096
+ "tool": { "type": "string" },
4097
+ "type": {
4098
+ "enum": ["dynamicToolCall"],
4099
+ "title": "DynamicToolCallThreadItemType",
4100
+ "type": "string"
4101
+ }
4102
+ },
4103
+ "required": [
4104
+ "arguments",
4105
+ "id",
4106
+ "status",
4107
+ "tool",
4108
+ "type"
4109
+ ],
4110
+ "title": "DynamicToolCallThreadItem",
4111
+ "type": "object"
4112
+ },
4113
+ {
4114
+ "properties": {
4115
+ "agentsStates": {
4116
+ "additionalProperties": { "$ref": "#/definitions/CollabAgentState" },
4117
+ "description": "Last known status of the target agents, when available.",
4118
+ "type": "object"
4119
+ },
4120
+ "id": {
4121
+ "description": "Unique identifier for this collab tool call.",
4122
+ "type": "string"
4123
+ },
4124
+ "model": {
4125
+ "description": "Model requested for the spawned agent, when applicable.",
4126
+ "type": ["string", "null"]
4127
+ },
4128
+ "prompt": {
4129
+ "description": "Prompt text sent as part of the collab tool call, when available.",
4130
+ "type": ["string", "null"]
4131
+ },
4132
+ "reasoningEffort": {
4133
+ "anyOf": [{ "$ref": "#/definitions/ReasoningEffort" }, { "type": "null" }],
4134
+ "description": "Reasoning effort requested for the spawned agent, when applicable."
4135
+ },
4136
+ "receiverThreadIds": {
4137
+ "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.",
4138
+ "items": { "type": "string" },
4139
+ "type": "array"
4140
+ },
4141
+ "senderThreadId": {
4142
+ "description": "Thread ID of the agent issuing the collab request.",
4143
+ "type": "string"
4144
+ },
4145
+ "status": {
4146
+ "allOf": [{ "$ref": "#/definitions/CollabAgentToolCallStatus" }],
4147
+ "description": "Current status of the collab tool call."
4148
+ },
4149
+ "tool": {
4150
+ "allOf": [{ "$ref": "#/definitions/CollabAgentTool" }],
4151
+ "description": "Name of the collab tool that was invoked."
4152
+ },
4153
+ "type": {
4154
+ "enum": ["collabAgentToolCall"],
4155
+ "title": "CollabAgentToolCallThreadItemType",
4156
+ "type": "string"
4157
+ }
4158
+ },
4159
+ "required": [
4160
+ "agentsStates",
4161
+ "id",
4162
+ "receiverThreadIds",
4163
+ "senderThreadId",
4164
+ "status",
4165
+ "tool",
4166
+ "type"
4167
+ ],
4168
+ "title": "CollabAgentToolCallThreadItem",
4169
+ "type": "object"
4170
+ },
4171
+ {
4172
+ "properties": {
4173
+ "agentPath": { "type": "string" },
4174
+ "agentThreadId": { "type": "string" },
4175
+ "id": { "type": "string" },
4176
+ "kind": { "$ref": "#/definitions/SubAgentActivityKind" },
4177
+ "type": {
4178
+ "enum": ["subAgentActivity"],
4179
+ "title": "SubAgentActivityThreadItemType",
4180
+ "type": "string"
4181
+ }
4182
+ },
4183
+ "required": [
4184
+ "agentPath",
4185
+ "agentThreadId",
4186
+ "id",
4187
+ "kind",
4188
+ "type"
4189
+ ],
4190
+ "title": "SubAgentActivityThreadItem",
4191
+ "type": "object"
4192
+ },
4193
+ {
4194
+ "properties": {
4195
+ "action": { "anyOf": [{ "$ref": "#/definitions/WebSearchAction" }, { "type": "null" }] },
4196
+ "id": { "type": "string" },
4197
+ "query": { "type": "string" },
4198
+ "results": {
4199
+ "default": null,
4200
+ "description": "Structured search results returned out-of-band by standalone web search.\n\nThese stay as opaque JSON at the extension/app-server boundary so new result fields and result types can pass through without a Codex release.",
4201
+ "items": true,
4202
+ "type": ["array", "null"]
4203
+ },
4204
+ "type": {
4205
+ "enum": ["webSearch"],
4206
+ "title": "WebSearchThreadItemType",
4207
+ "type": "string"
4208
+ }
4209
+ },
4210
+ "required": [
4211
+ "id",
4212
+ "query",
4213
+ "type"
4214
+ ],
4215
+ "title": "WebSearchThreadItem",
4216
+ "type": "object"
4217
+ },
4218
+ {
4219
+ "properties": {
4220
+ "id": { "type": "string" },
4221
+ "path": { "$ref": "#/definitions/LegacyAppPathString" },
4222
+ "type": {
4223
+ "enum": ["imageView"],
4224
+ "title": "ImageViewThreadItemType",
4225
+ "type": "string"
4226
+ }
4227
+ },
4228
+ "required": [
4229
+ "id",
4230
+ "path",
4231
+ "type"
4232
+ ],
4233
+ "title": "ImageViewThreadItem",
4234
+ "type": "object"
4235
+ },
4236
+ {
4237
+ "description": "Display item emitted by the interruptible `clock.sleep` tool.",
4238
+ "properties": {
4239
+ "durationMs": {
4240
+ "format": "uint64",
4241
+ "minimum": 0,
4242
+ "type": "integer"
4243
+ },
4244
+ "id": { "type": "string" },
4245
+ "type": {
4246
+ "enum": ["sleep"],
4247
+ "title": "SleepThreadItemType",
4248
+ "type": "string"
4249
+ }
4250
+ },
4251
+ "required": [
4252
+ "durationMs",
4253
+ "id",
4254
+ "type"
4255
+ ],
4256
+ "title": "SleepThreadItem",
4257
+ "type": "object"
4258
+ },
4259
+ {
4260
+ "properties": {
4261
+ "failure": {
4262
+ "anyOf": [{ "$ref": "#/definitions/ImageGenerationFailure" }, { "type": "null" }],
4263
+ "default": null
4264
+ },
4265
+ "id": { "type": "string" },
4266
+ "result": { "type": "string" },
4267
+ "revisedPrompt": { "type": ["string", "null"] },
4268
+ "savedPath": { "anyOf": [{ "$ref": "#/definitions/AbsolutePathBuf" }, { "type": "null" }] },
4269
+ "status": { "type": "string" },
4270
+ "transparentBackground": {
4271
+ "default": null,
4272
+ "type": ["boolean", "null"]
4273
+ },
4274
+ "type": {
4275
+ "enum": ["imageGeneration"],
4276
+ "title": "ImageGenerationThreadItemType",
4277
+ "type": "string"
4278
+ }
4279
+ },
4280
+ "required": [
4281
+ "id",
4282
+ "result",
4283
+ "status",
4284
+ "type"
4285
+ ],
4286
+ "title": "ImageGenerationThreadItem",
4287
+ "type": "object"
4288
+ },
4289
+ {
4290
+ "properties": {
4291
+ "id": { "type": "string" },
4292
+ "review": { "type": "string" },
4293
+ "type": {
4294
+ "enum": ["enteredReviewMode"],
4295
+ "title": "EnteredReviewModeThreadItemType",
4296
+ "type": "string"
4297
+ }
4298
+ },
4299
+ "required": [
4300
+ "id",
4301
+ "review",
4302
+ "type"
4303
+ ],
4304
+ "title": "EnteredReviewModeThreadItem",
4305
+ "type": "object"
4306
+ },
4307
+ {
4308
+ "properties": {
4309
+ "id": { "type": "string" },
4310
+ "review": { "type": "string" },
4311
+ "type": {
4312
+ "enum": ["exitedReviewMode"],
4313
+ "title": "ExitedReviewModeThreadItemType",
4314
+ "type": "string"
4315
+ }
4316
+ },
4317
+ "required": [
4318
+ "id",
4319
+ "review",
4320
+ "type"
4321
+ ],
4322
+ "title": "ExitedReviewModeThreadItem",
4323
+ "type": "object"
4324
+ },
4325
+ {
4326
+ "properties": {
4327
+ "id": { "type": "string" },
4328
+ "type": {
4329
+ "enum": ["contextCompaction"],
4330
+ "title": "ContextCompactionThreadItemType",
4331
+ "type": "string"
4332
+ }
4333
+ },
4334
+ "required": ["id", "type"],
4335
+ "title": "ContextCompactionThreadItem",
4336
+ "type": "object"
4337
+ }
4338
+ ] },
4339
+ "ThreadSection": {
4340
+ "description": "An independently persisted, user-visible thread section.",
4341
+ "properties": {
4342
+ "appearance": {
4343
+ "anyOf": [{ "$ref": "#/definitions/ThreadSectionAppearance" }, { "type": "null" }],
4344
+ "default": null,
4345
+ "description": "Optional appearance synchronized across clients."
4346
+ },
4347
+ "id": {
4348
+ "description": "Opaque UUIDv7 identity that remains stable when the section is renamed.",
4349
+ "type": "string"
4350
+ },
4351
+ "name": {
4352
+ "description": "The current user-visible section name.",
4353
+ "type": "string"
4354
+ }
4355
+ },
4356
+ "required": ["id", "name"],
4357
+ "type": "object"
4358
+ },
4359
+ "ThreadSectionAppearance": {
4360
+ "description": "Extensible visual presentation for a custom thread section.",
4361
+ "properties": {
4362
+ "color": { "type": ["string", "null"] },
4363
+ "icon": { "type": ["string", "null"] }
4364
+ },
4365
+ "type": "object"
4366
+ },
4367
+ "ThreadSource": { "type": "string" },
4368
+ "ThreadStatus": { "oneOf": [
4369
+ {
4370
+ "properties": { "type": {
4371
+ "enum": ["notLoaded"],
4372
+ "title": "NotLoadedThreadStatusType",
4373
+ "type": "string"
4374
+ } },
4375
+ "required": ["type"],
4376
+ "title": "NotLoadedThreadStatus",
4377
+ "type": "object"
4378
+ },
4379
+ {
4380
+ "properties": { "type": {
4381
+ "enum": ["idle"],
4382
+ "title": "IdleThreadStatusType",
4383
+ "type": "string"
4384
+ } },
4385
+ "required": ["type"],
4386
+ "title": "IdleThreadStatus",
4387
+ "type": "object"
4388
+ },
4389
+ {
4390
+ "properties": { "type": {
4391
+ "enum": ["systemError"],
4392
+ "title": "SystemErrorThreadStatusType",
4393
+ "type": "string"
4394
+ } },
4395
+ "required": ["type"],
4396
+ "title": "SystemErrorThreadStatus",
4397
+ "type": "object"
4398
+ },
4399
+ {
4400
+ "properties": {
4401
+ "activeFlags": {
4402
+ "items": { "$ref": "#/definitions/ThreadActiveFlag" },
4403
+ "type": "array"
4404
+ },
4405
+ "type": {
4406
+ "enum": ["active"],
4407
+ "title": "ActiveThreadStatusType",
4408
+ "type": "string"
4409
+ }
4410
+ },
4411
+ "required": ["activeFlags", "type"],
4412
+ "title": "ActiveThreadStatus",
4413
+ "type": "object"
4414
+ }
4415
+ ] },
4416
+ "Turn": {
4417
+ "properties": {
4418
+ "completedAt": {
4419
+ "description": "Unix timestamp (in seconds) when the turn completed.",
4420
+ "format": "int64",
4421
+ "type": ["integer", "null"]
4422
+ },
4423
+ "durationMs": {
4424
+ "description": "Duration between turn start and completion in milliseconds, if known.",
4425
+ "format": "int64",
4426
+ "type": ["integer", "null"]
4427
+ },
4428
+ "error": {
4429
+ "anyOf": [{ "$ref": "#/definitions/TurnError" }, { "type": "null" }],
4430
+ "description": "Only populated when the Turn's status is failed."
4431
+ },
4432
+ "id": {
4433
+ "description": "Identifier for this turn. Codex-generated turn IDs are UUIDv7.",
4434
+ "type": "string"
4435
+ },
4436
+ "items": {
4437
+ "description": "Thread items currently included in this turn payload.",
4438
+ "items": { "$ref": "#/definitions/ThreadItem" },
4439
+ "type": "array"
4440
+ },
4441
+ "itemsView": {
4442
+ "allOf": [{ "$ref": "#/definitions/TurnItemsView" }],
4443
+ "default": "full",
4444
+ "description": "Describes how much of `items` has been loaded for this turn."
4445
+ },
4446
+ "startedAt": {
4447
+ "description": "Unix timestamp (in seconds) when the turn started.",
4448
+ "format": "int64",
4449
+ "type": ["integer", "null"]
4450
+ },
4451
+ "status": { "$ref": "#/definitions/TurnStatus" }
4452
+ },
4453
+ "required": [
4454
+ "id",
4455
+ "items",
4456
+ "status"
4457
+ ],
4458
+ "type": "object"
4459
+ },
4460
+ "TurnError": {
4461
+ "properties": {
4462
+ "additionalDetails": {
4463
+ "default": null,
4464
+ "type": ["string", "null"]
4465
+ },
4466
+ "codexErrorInfo": { "anyOf": [{ "$ref": "#/definitions/CodexErrorInfo" }, { "type": "null" }] },
4467
+ "message": { "type": "string" },
4468
+ "misalignment": {
4469
+ "anyOf": [{ "$ref": "#/definitions/MisalignmentErrorDetails" }, { "type": "null" }],
4470
+ "default": null,
4471
+ "description": "Optional public explanation and continuation instruction for a misalignment block."
4472
+ }
4473
+ },
4474
+ "required": ["message"],
4475
+ "type": "object"
4476
+ },
4477
+ "TurnItemsView": { "oneOf": [
4478
+ {
4479
+ "description": "`items` was not loaded for this turn. The field is intentionally empty.",
4480
+ "enum": ["notLoaded"],
4481
+ "type": "string"
4482
+ },
4483
+ {
4484
+ "description": "`items` contains only a display summary for this turn.",
4485
+ "enum": ["summary"],
4486
+ "type": "string"
4487
+ },
4488
+ {
4489
+ "description": "`items` contains every ThreadItem available from persisted app-server history for this turn.",
4490
+ "enum": ["full"],
4491
+ "type": "string"
4492
+ }
4493
+ ] },
4494
+ "TurnStatus": {
4495
+ "enum": [
4496
+ "completed",
4497
+ "interrupted",
4498
+ "failed",
4499
+ "inProgress"
4500
+ ],
4501
+ "type": "string"
4502
+ },
4503
+ "TurnsPage": {
4504
+ "properties": {
4505
+ "backwardsCursor": { "type": ["string", "null"] },
4506
+ "data": {
4507
+ "items": { "$ref": "#/definitions/Turn" },
4508
+ "type": "array"
4509
+ },
4510
+ "nextCursor": { "type": ["string", "null"] }
4511
+ },
4512
+ "required": ["data"],
4513
+ "type": "object"
4514
+ },
4515
+ "UserInput": { "oneOf": [
4516
+ {
4517
+ "properties": {
4518
+ "text": { "type": "string" },
4519
+ "text_elements": {
4520
+ "default": [],
4521
+ "description": "UI-defined spans within `text` used to render or persist special elements.",
4522
+ "items": { "$ref": "#/definitions/TextElement" },
4523
+ "type": "array"
4524
+ },
4525
+ "type": {
4526
+ "enum": ["text"],
4527
+ "title": "TextUserInputType",
4528
+ "type": "string"
4529
+ }
4530
+ },
4531
+ "required": ["text", "type"],
4532
+ "title": "TextUserInput",
4533
+ "type": "object"
4534
+ },
4535
+ {
4536
+ "properties": {
4537
+ "detail": {
4538
+ "anyOf": [{ "$ref": "#/definitions/ImageDetail" }, { "type": "null" }],
4539
+ "default": null
4540
+ },
4541
+ "type": {
4542
+ "enum": ["image"],
4543
+ "title": "ImageUserInputType",
4544
+ "type": "string"
4545
+ },
4546
+ "url": { "type": "string" }
4547
+ },
4548
+ "required": ["type", "url"],
4549
+ "title": "ImageUserInput",
4550
+ "type": "object"
4551
+ },
4552
+ {
4553
+ "properties": {
4554
+ "detail": {
4555
+ "anyOf": [{ "$ref": "#/definitions/ImageDetail" }, { "type": "null" }],
4556
+ "default": null
4557
+ },
4558
+ "path": { "type": "string" },
4559
+ "type": {
4560
+ "enum": ["localImage"],
4561
+ "title": "LocalImageUserInputType",
4562
+ "type": "string"
4563
+ }
4564
+ },
4565
+ "required": ["path", "type"],
4566
+ "title": "LocalImageUserInput",
4567
+ "type": "object"
4568
+ },
4569
+ {
4570
+ "properties": {
4571
+ "type": {
4572
+ "enum": ["audio"],
4573
+ "title": "AudioUserInputType",
4574
+ "type": "string"
4575
+ },
4576
+ "url": { "type": "string" }
4577
+ },
4578
+ "required": ["type", "url"],
4579
+ "title": "AudioUserInput",
4580
+ "type": "object"
4581
+ },
4582
+ {
4583
+ "properties": {
4584
+ "path": { "type": "string" },
4585
+ "type": {
4586
+ "enum": ["localAudio"],
4587
+ "title": "LocalAudioUserInputType",
4588
+ "type": "string"
4589
+ }
4590
+ },
4591
+ "required": ["path", "type"],
4592
+ "title": "LocalAudioUserInput",
4593
+ "type": "object"
4594
+ },
4595
+ {
4596
+ "properties": {
4597
+ "name": { "type": "string" },
4598
+ "path": { "type": "string" },
4599
+ "type": {
4600
+ "enum": ["skill"],
4601
+ "title": "SkillUserInputType",
4602
+ "type": "string"
4603
+ }
4604
+ },
4605
+ "required": [
4606
+ "name",
4607
+ "path",
4608
+ "type"
4609
+ ],
4610
+ "title": "SkillUserInput",
4611
+ "type": "object"
4612
+ },
4613
+ {
4614
+ "properties": {
4615
+ "name": { "type": "string" },
4616
+ "path": { "type": "string" },
4617
+ "type": {
4618
+ "enum": ["mention"],
4619
+ "title": "MentionUserInputType",
4620
+ "type": "string"
4621
+ }
4622
+ },
4623
+ "required": [
4624
+ "name",
4625
+ "path",
4626
+ "type"
4627
+ ],
4628
+ "title": "MentionUserInput",
4629
+ "type": "object"
4630
+ }
4631
+ ] },
4632
+ "WebSearchAction": { "oneOf": [
4633
+ {
4634
+ "properties": {
4635
+ "queries": {
4636
+ "items": { "type": "string" },
4637
+ "type": ["array", "null"]
4638
+ },
4639
+ "query": { "type": ["string", "null"] },
4640
+ "type": {
4641
+ "enum": ["search"],
4642
+ "title": "SearchWebSearchActionType",
4643
+ "type": "string"
4644
+ }
4645
+ },
4646
+ "required": ["type"],
4647
+ "title": "SearchWebSearchAction",
4648
+ "type": "object"
4649
+ },
4650
+ {
4651
+ "properties": {
4652
+ "type": {
4653
+ "enum": ["openPage"],
4654
+ "title": "OpenPageWebSearchActionType",
4655
+ "type": "string"
4656
+ },
4657
+ "url": { "type": ["string", "null"] }
4658
+ },
4659
+ "required": ["type"],
4660
+ "title": "OpenPageWebSearchAction",
4661
+ "type": "object"
4662
+ },
4663
+ {
4664
+ "properties": {
4665
+ "pattern": { "type": ["string", "null"] },
4666
+ "type": {
4667
+ "enum": ["findInPage"],
4668
+ "title": "FindInPageWebSearchActionType",
4669
+ "type": "string"
4670
+ },
4671
+ "url": { "type": ["string", "null"] }
4672
+ },
4673
+ "required": ["type"],
4674
+ "title": "FindInPageWebSearchAction",
4675
+ "type": "object"
4676
+ },
4677
+ {
4678
+ "properties": { "type": {
4679
+ "enum": ["other"],
4680
+ "title": "OtherWebSearchActionType",
4681
+ "type": "string"
4682
+ } },
4683
+ "required": ["type"],
4684
+ "title": "OtherWebSearchAction",
4685
+ "type": "object"
4686
+ }
4687
+ ] }
4688
+ };
4689
+ //#endregion
4690
+ //#region extensions/codex/src/app-server/protocol-generated/json/v2/ErrorNotification.json
4691
+ var ErrorNotification_default = {
4692
+ $schema: "http://json-schema.org/draft-07/schema#",
4693
+ properties: {
4694
+ "error": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/TurnError" },
4695
+ "threadId": { "type": "string" },
4696
+ "turnId": { "type": "string" },
4697
+ "willRetry": { "type": "boolean" }
4698
+ },
4699
+ required: [
4700
+ "error",
4701
+ "threadId",
4702
+ "turnId",
4703
+ "willRetry"
4704
+ ],
4705
+ title: "ErrorNotification",
4706
+ type: "object"
4707
+ };
4708
+ //#endregion
4709
+ //#region extensions/codex/src/app-server/protocol-generated/json/v2/ModelListResponse.json
4710
+ var ModelListResponse_default = {
4711
+ $schema: "http://json-schema.org/draft-07/schema#",
4712
+ properties: {
4713
+ "data": {
4714
+ "items": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/Model" },
4715
+ "type": "array"
4716
+ },
4717
+ "nextCursor": {
4718
+ "description": "Opaque cursor to pass to the next call to continue after the last item. If None, there are no more items to return.",
4719
+ "type": ["string", "null"]
4720
+ }
4721
+ },
4722
+ required: ["data"],
4723
+ title: "ModelListResponse",
4724
+ type: "object"
4725
+ };
4726
+ //#endregion
4727
+ //#region extensions/codex/src/app-server/protocol-generated/json/v2/ThreadResumeResponse.json
4728
+ var ThreadResumeResponse_default = {
4729
+ $schema: "http://json-schema.org/draft-07/schema#",
4730
+ properties: {
4731
+ "activePermissionProfile": {
4732
+ "anyOf": [{ "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/ActivePermissionProfile" }, { "type": "null" }],
4733
+ "default": null,
4734
+ "description": "Named or implicit built-in profile that produced the active permissions, when known."
4735
+ },
4736
+ "approvalPolicy": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/AskForApproval" },
4737
+ "approvalsReviewer": {
4738
+ "allOf": [{ "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/ApprovalsReviewer" }],
4739
+ "description": "Reviewer currently used for approval requests on this thread."
4740
+ },
4741
+ "cwd": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/AbsolutePathBuf" },
4742
+ "initialTurnsPage": {
4743
+ "anyOf": [{ "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/TurnsPage" }, { "type": "null" }],
4744
+ "default": null,
4745
+ "description": "`thread/turns/list` page returned when requested by `initialTurnsPage`."
4746
+ },
4747
+ "instructionSources": {
4748
+ "default": [],
4749
+ "description": "Environment-native paths to instruction source files currently loaded for this thread.",
4750
+ "items": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/LegacyAppPathString" },
4751
+ "type": "array"
4752
+ },
4753
+ "itemsBackwardsCursor": {
4754
+ "default": null,
4755
+ "description": "Opaque cursor for hydrating paginated items backwards.\n\nPass this as `cursor` to `thread/items/list` with `sortDirection: \"desc\"`. The first page includes the item identified by the cursor.",
4756
+ "type": ["string", "null"]
4757
+ },
4758
+ "model": { "type": "string" },
4759
+ "modelProvider": { "type": "string" },
4760
+ "multiAgentMode": {
4761
+ "allOf": [{ "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/MultiAgentMode" }],
4762
+ "default": "explicitRequestOnly",
4763
+ "description": "@deprecated Always `explicitRequestOnly`. Use `reasoningEffort` for Ultra behavior."
4764
+ },
4765
+ "reasoningEffort": { "anyOf": [{ "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/ReasoningEffort" }, { "type": "null" }] },
4766
+ "runtimeWorkspaceRoots": {
4767
+ "default": [],
4768
+ "description": "Thread-scoped runtime workspace roots used to materialize `:workspace_roots`.",
4769
+ "items": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/AbsolutePathBuf" },
4770
+ "type": "array"
4771
+ },
4772
+ "sandbox": {
4773
+ "allOf": [{ "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/SandboxPolicy" }],
4774
+ "description": "Legacy sandbox policy retained for compatibility. Experimental clients should prefer `activePermissionProfile` for profile provenance."
4775
+ },
4776
+ "serviceTier": { "type": ["string", "null"] },
4777
+ "thread": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/Thread" },
4778
+ "turnsBackwardsCursor": {
4779
+ "default": null,
4780
+ "description": "Opaque cursor for hydrating paginated turns backwards.\n\nPass this as `cursor` to `thread/turns/list` with `sortDirection: \"desc\"`. The first page includes the turn identified by the cursor.",
4781
+ "type": ["string", "null"]
4782
+ }
4783
+ },
4784
+ required: [
4785
+ "approvalPolicy",
4786
+ "approvalsReviewer",
4787
+ "cwd",
4788
+ "model",
4789
+ "modelProvider",
4790
+ "sandbox",
4791
+ "thread"
4792
+ ],
4793
+ title: "ThreadResumeResponse",
4794
+ type: "object"
4795
+ };
4796
+ //#endregion
4797
+ //#region extensions/codex/src/app-server/protocol-generated/json/v2/ThreadStartResponse.json
4798
+ var ThreadStartResponse_default = {
4799
+ $schema: "http://json-schema.org/draft-07/schema#",
4800
+ properties: {
4801
+ "activePermissionProfile": {
4802
+ "anyOf": [{ "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/ActivePermissionProfile" }, { "type": "null" }],
4803
+ "default": null,
4804
+ "description": "Named or implicit built-in profile that produced the active permissions, when known."
4805
+ },
4806
+ "approvalPolicy": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/AskForApproval" },
4807
+ "approvalsReviewer": {
4808
+ "allOf": [{ "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/ApprovalsReviewer" }],
4809
+ "description": "Reviewer currently used for approval requests on this thread."
4810
+ },
4811
+ "cwd": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/AbsolutePathBuf" },
4812
+ "instructionSources": {
4813
+ "default": [],
4814
+ "description": "Environment-native paths to instruction source files currently loaded for this thread.",
4815
+ "items": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/LegacyAppPathString" },
4816
+ "type": "array"
4817
+ },
4818
+ "model": { "type": "string" },
4819
+ "modelProvider": { "type": "string" },
4820
+ "multiAgentMode": {
4821
+ "allOf": [{ "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/MultiAgentMode" }],
4822
+ "default": "explicitRequestOnly",
4823
+ "description": "@deprecated Always `explicitRequestOnly`. Use `reasoningEffort` for Ultra behavior."
4824
+ },
4825
+ "reasoningEffort": { "anyOf": [{ "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/ReasoningEffort" }, { "type": "null" }] },
4826
+ "runtimeWorkspaceRoots": {
4827
+ "default": [],
4828
+ "description": "Thread-scoped runtime workspace roots used to materialize `:workspace_roots`.",
4829
+ "items": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/AbsolutePathBuf" },
4830
+ "type": "array"
4831
+ },
4832
+ "sandbox": {
4833
+ "allOf": [{ "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/SandboxPolicy" }],
4834
+ "description": "Legacy sandbox policy retained for compatibility. Experimental clients should prefer `activePermissionProfile` for profile provenance."
4835
+ },
4836
+ "serviceTier": { "type": ["string", "null"] },
4837
+ "thread": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/Thread" }
4838
+ },
4839
+ required: [
4840
+ "approvalPolicy",
4841
+ "approvalsReviewer",
4842
+ "cwd",
4843
+ "model",
4844
+ "modelProvider",
4845
+ "sandbox",
4846
+ "thread"
4847
+ ],
4848
+ title: "ThreadStartResponse",
4849
+ type: "object"
4850
+ };
4851
+ //#endregion
4852
+ //#region extensions/codex/src/app-server/protocol-generated/json/v2/TurnCompletedNotification.json
4853
+ var TurnCompletedNotification_default = {
4854
+ $schema: "http://json-schema.org/draft-07/schema#",
4855
+ properties: {
4856
+ "threadId": { "type": "string" },
4857
+ "turn": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/Turn" }
4858
+ },
4859
+ required: ["threadId", "turn"],
4860
+ title: "TurnCompletedNotification",
4861
+ type: "object"
4862
+ };
4863
+ //#endregion
4864
+ //#region extensions/codex/src/app-server/protocol-generated/json/v2/TurnStartResponse.json
4865
+ var TurnStartResponse_default = {
4866
+ $schema: "http://json-schema.org/draft-07/schema#",
4867
+ properties: { "turn": { "$ref": "./CodexAppServerProtocolDefinitions.json#/definitions/Turn" } },
4868
+ required: ["turn"],
4869
+ title: "TurnStartResponse",
4870
+ type: "object"
4871
+ };
4872
+ //#endregion
4873
+ //#region extensions/codex/src/app-server/protocol-validators.ts
4874
+ /**
4875
+ * Runtime validators for Codex app-server protocol payloads, including schema
4876
+ * normalization for generated JSON Schema before TypeBox compilation.
4877
+ */
4878
+ const externalDefinitionRefPrefix = "./CodexAppServerProtocolDefinitions.json#/definitions/";
4879
+ const rootExternalDefinitionRefPrefix = "./v2/CodexAppServerProtocolDefinitions.json#/definitions/";
4880
+ const localDefinitionRefPrefix = "#/definitions/";
4881
+ function materializeCodexSchema(schema, externalRefPrefix = externalDefinitionRefPrefix) {
4882
+ const sharedDefinitions = definitions;
4883
+ if (!isRecord(schema) || !isRecord(sharedDefinitions)) return schema;
4884
+ const reachable = collectDefinitionRefs(schema, externalRefPrefix);
4885
+ const pending = [...reachable];
4886
+ while (pending.length > 0) {
4887
+ const name = pending.pop();
4888
+ if (name === void 0) continue;
4889
+ const definition = sharedDefinitions[name];
4890
+ if (definition === void 0) throw new Error(`Missing generated Codex schema definition: ${name}`);
4891
+ for (const dependency of collectDefinitionRefs(definition, localDefinitionRefPrefix)) if (!reachable.has(dependency)) {
4892
+ reachable.add(dependency);
4893
+ pending.push(dependency);
4894
+ }
4895
+ }
4896
+ if (reachable.size === 0) return schema;
4897
+ const definitions$1 = Object.fromEntries(Object.entries(sharedDefinitions).filter(([name]) => reachable.has(name)));
4898
+ return rewriteDefinitionRefs({
4899
+ ...schema,
4900
+ definitions: definitions$1
4901
+ }, externalRefPrefix);
4902
+ }
4903
+ function collectDefinitionRefs(value, prefix, names = /* @__PURE__ */ new Set()) {
4904
+ if (Array.isArray(value)) for (const entry of value) collectDefinitionRefs(entry, prefix, names);
4905
+ else if (isRecord(value)) {
4906
+ if (typeof value.$ref === "string" && value.$ref.startsWith(prefix)) {
4907
+ const name = value.$ref.slice(prefix.length).split("/", 1)[0];
4908
+ if (name) names.add(name.replaceAll("~1", "/").replaceAll("~0", "~"));
4909
+ }
4910
+ for (const entry of Object.values(value)) collectDefinitionRefs(entry, prefix, names);
4911
+ }
4912
+ return names;
4913
+ }
4914
+ function rewriteDefinitionRefs(value, externalRefPrefix) {
4915
+ if (Array.isArray(value)) return value.map((entry) => rewriteDefinitionRefs(entry, externalRefPrefix));
4916
+ if (!isRecord(value)) return value;
4917
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, key === "$ref" && typeof entry === "string" && entry.startsWith(externalRefPrefix) ? `${localDefinitionRefPrefix}${entry.slice(externalRefPrefix.length)}` : rewriteDefinitionRefs(entry, externalRefPrefix)]));
4918
+ }
4919
+ const dynamicToolCallParamsSchema = materializeCodexSchema(DynamicToolCallParams_default, rootExternalDefinitionRefPrefix);
4920
+ const errorNotificationSchema = materializeCodexSchema(ErrorNotification_default);
4921
+ const modelListResponseSchema = materializeCodexSchema(ModelListResponse_default);
4922
+ const threadResumeResponseSchema = materializeCodexSchema(ThreadResumeResponse_default);
4923
+ const threadStartResponseSchema = materializeCodexSchema(ThreadStartResponse_default);
4924
+ const turnCompletedNotificationSchema = materializeCodexSchema(TurnCompletedNotification_default);
4925
+ const turnStartResponseSchema = materializeCodexSchema(TurnStartResponse_default);
4926
+ function compileCodexSchema(schema) {
4927
+ const validator = Compile(normalizeJsonSchemaNode(schema));
1968
4928
  return {
1969
- configFingerprint: retained.configFingerprint,
1970
- serviceTier: retained.serviceTier,
1971
- release
4929
+ check: (value) => validator.Check(value),
4930
+ errors: (value) => [...validator.Errors(value)]
1972
4931
  };
1973
4932
  }
1974
- /** Distinguish active claimed ownership from an already-evicted idle subscription. */
1975
- function isCodexAppServerLiveThreadClaimed(client, threadId) {
1976
- const runtime = configuredClients.get(client);
1977
- return runtime !== void 0 && !runtime.closed && runtime.claimedThreads.has(threadId);
4933
+ const schemaMapKeywords = /* @__PURE__ */ new Set([
4934
+ "$defs",
4935
+ "definitions",
4936
+ "dependentSchemas",
4937
+ "patternProperties",
4938
+ "properties"
4939
+ ]);
4940
+ const schemaValueKeywords = /* @__PURE__ */ new Set([
4941
+ "additionalItems",
4942
+ "additionalProperties",
4943
+ "contains",
4944
+ "else",
4945
+ "if",
4946
+ "items",
4947
+ "not",
4948
+ "propertyNames",
4949
+ "then",
4950
+ "unevaluatedItems",
4951
+ "unevaluatedProperties"
4952
+ ]);
4953
+ const schemaArrayKeywords = /* @__PURE__ */ new Set([
4954
+ "allOf",
4955
+ "anyOf",
4956
+ "oneOf",
4957
+ "prefixItems"
4958
+ ]);
4959
+ function schemaTypeIncludes(schema, type) {
4960
+ return schema.type === type || Array.isArray(schema.type) && schema.type.includes(type);
4961
+ }
4962
+ function normalizeSchemaMap(value) {
4963
+ if (!isRecord(value)) return value;
4964
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, normalizeJsonSchemaNode(entry)]));
4965
+ }
4966
+ function expandJsonSchemaTypeArray(schema) {
4967
+ const { type, ...rest } = schema;
4968
+ if (!Array.isArray(type)) return schema;
4969
+ return { anyOf: type.map((entry) => Object.assign({}, rest, { type: entry })) };
4970
+ }
4971
+ function normalizeJsonSchemaNode(schema) {
4972
+ if (Array.isArray(schema)) return schema.map((entry) => normalizeJsonSchemaNode(entry));
4973
+ if (!isRecord(schema)) return schema;
4974
+ const normalizedSchema = expandJsonSchemaTypeArray(schema);
4975
+ return Object.fromEntries(Object.entries(normalizedSchema).map(([key, value]) => {
4976
+ if (schemaMapKeywords.has(key)) return [key, normalizeSchemaMap(value)];
4977
+ if (schemaValueKeywords.has(key) || schemaArrayKeywords.has(key)) return [key, normalizeJsonSchemaNode(value)];
4978
+ return [key, value];
4979
+ }));
1978
4980
  }
1979
- /** Release the exact physical subscription and finish only its observed claim generation. */
1980
- async function unsubscribeCodexAppServerLiveThread(client, threadId, timeoutMs) {
1981
- const runtime = configuredClients.get(client);
1982
- const claimed = runtime?.claimedThreads.get(threadId);
1983
- let transition = runtime?.releasingThreads.get(threadId);
1984
- if (transition?.physicalRelease) {
1985
- await transition.physicalRelease;
1986
- return;
4981
+ function readDefault(schema) {
4982
+ if (!isRecord(schema) || !Object.hasOwn(schema, "default")) return;
4983
+ return structuredClone(schema.default);
4984
+ }
4985
+ function decodePointerSegment(segment) {
4986
+ return segment.replace(/~1/g, "/").replace(/~0/g, "~");
4987
+ }
4988
+ function resolveLocalRef(root, ref) {
4989
+ if (ref === "#") return root;
4990
+ if (!ref.startsWith("#/")) return;
4991
+ let current = root;
4992
+ for (const segment of ref.slice(2).split("/").map(decodePointerSegment)) {
4993
+ if (!isRecord(current)) return;
4994
+ current = current[segment];
4995
+ }
4996
+ return current;
4997
+ }
4998
+ function applySchemaDefaults(schema, value, root = schema, resolvingRefs = /* @__PURE__ */ new Set()) {
4999
+ if (value === void 0) {
5000
+ const defaultValue = readDefault(schema);
5001
+ if (defaultValue !== void 0) return defaultValue;
5002
+ }
5003
+ if (!isRecord(schema)) return value;
5004
+ let nextValue = value;
5005
+ if (typeof schema.$ref === "string" && !resolvingRefs.has(schema.$ref)) {
5006
+ const target = resolveLocalRef(root, schema.$ref);
5007
+ if (target !== void 0) {
5008
+ resolvingRefs.add(schema.$ref);
5009
+ nextValue = applySchemaDefaults(target, nextValue, root, resolvingRefs);
5010
+ resolvingRefs.delete(schema.$ref);
5011
+ }
1987
5012
  }
1988
- const physicalRelease = Promise.resolve().then(async () => {
1989
- if (claimed !== void 0 && runtime?.claimedThreads.get(threadId) !== claimed) return;
1990
- await client.request("thread/unsubscribe", { threadId }, { timeoutMs });
1991
- });
1992
- const ownsTransition = runtime !== void 0 && transition === void 0;
1993
- if (transition) transition.physicalRelease = physicalRelease;
1994
- else if (runtime) {
1995
- transition = {
1996
- completion: physicalRelease,
1997
- physicalRelease
1998
- };
1999
- runtime.releasingThreads.set(threadId, transition);
5013
+ for (const key of ["allOf"]) {
5014
+ const branches = schema[key];
5015
+ if (Array.isArray(branches)) for (const branch of branches) nextValue = applySchemaDefaults(branch, nextValue, root, resolvingRefs);
2000
5016
  }
2001
- try {
2002
- await physicalRelease;
2003
- if (claimed !== void 0 && runtime?.claimedThreads.get(threadId) === claimed) runtime.claimedThreads.delete(threadId);
2004
- } finally {
2005
- if (ownsTransition && runtime.releasingThreads.get(threadId) === transition) runtime.releasingThreads.delete(threadId);
5017
+ if (schemaTypeIncludes(schema, "object") && isRecord(nextValue) && isRecord(schema.properties)) {
5018
+ for (const [key, propertySchema] of Object.entries(schema.properties)) {
5019
+ const currentValue = nextValue[key];
5020
+ const defaultedValue = applySchemaDefaults(propertySchema, currentValue, root, resolvingRefs);
5021
+ if (defaultedValue !== void 0 && defaultedValue !== currentValue) nextValue[key] = defaultedValue;
5022
+ }
5023
+ if (isRecord(schema.additionalProperties)) for (const key of Object.keys(nextValue)) {
5024
+ if (Object.hasOwn(schema.properties, key)) continue;
5025
+ nextValue[key] = applySchemaDefaults(schema.additionalProperties, nextValue[key], root, resolvingRefs);
5026
+ }
2006
5027
  }
5028
+ if (schemaTypeIncludes(schema, "array") && Array.isArray(nextValue) && isRecord(schema.items)) return nextValue.map((entry) => applySchemaDefaults(schema.items, entry, root, resolvingRefs));
5029
+ return nextValue;
5030
+ }
5031
+ function normalizeWithDefaults(schema, value) {
5032
+ if (value === void 0 || value === null) return value;
5033
+ return applySchemaDefaults(schema, structuredClone(value));
5034
+ }
5035
+ const validateDynamicToolCallParams = compileCodexSchema(dynamicToolCallParamsSchema);
5036
+ const validateErrorNotification = compileCodexSchema(errorNotificationSchema);
5037
+ const validateModelListResponse = compileCodexSchema(modelListResponseSchema);
5038
+ const validateThreadResumeResponse = compileCodexSchema(threadResumeResponseSchema);
5039
+ const validateThreadStartResponse = compileCodexSchema(threadStartResponseSchema);
5040
+ const validateTurnCompletedNotification = compileCodexSchema(turnCompletedNotificationSchema);
5041
+ const validateTurnStartResponse = compileCodexSchema(turnStartResponseSchema);
5042
+ /** Asserts and normalizes a Codex thread/start response. */
5043
+ function assertCodexThreadStartResponse(value) {
5044
+ const normalized = normalizeWithDefaults(threadStartResponseSchema, value);
5045
+ return assertCodexShape(validateThreadStartResponse, normalized, "thread/start response");
5046
+ }
5047
+ /** Asserts and normalizes a Codex thread/fork response. */
5048
+ function assertCodexThreadForkResponse(value) {
5049
+ const normalized = normalizeWithDefaults(threadStartResponseSchema, value);
5050
+ return assertCodexShape(validateThreadStartResponse, normalized, "thread/fork response");
5051
+ }
5052
+ /** Asserts the experimental beforeTurnId request field before it crosses the app-server boundary. */
5053
+ function assertCodexThreadForkParams(value) {
5054
+ if (!isRecord(value) || typeof value.threadId !== "string" || !value.threadId.trim() || value.beforeTurnId !== void 0 && value.beforeTurnId !== null && typeof value.beforeTurnId !== "string") throw new Error("Invalid Codex app-server thread/fork params");
5055
+ return value;
2007
5056
  }
2008
- /** Reset/end owns the exact thread; failed generation retirement must never release its successor. */
2009
- async function releaseCodexAppServerLiveThread(client, threadId) {
2010
- const runtime = configuredClients.get(client);
2011
- return runtime ? await releaseRetainedThread(client, runtime, threadId) : false;
5057
+ /** Asserts and normalizes a Codex thread/resume response. */
5058
+ function assertCodexThreadResumeResponse(value) {
5059
+ const normalized = normalizeWithDefaults(threadResumeResponseSchema, value);
5060
+ return assertCodexShape(validateThreadResumeResponse, normalized, "thread/resume response");
2012
5061
  }
2013
- /** Native child work pins its parent's subscription even after the foreground parent turn ends. */
2014
- function protectCodexAppServerLiveThread(client, threadId) {
2015
- const runtime = configuredClients.get(client);
2016
- if (!runtime || runtime.closed) return () => void 0;
2017
- runtime.protectedThreads.set(threadId, (runtime.protectedThreads.get(threadId) ?? 0) + 1);
2018
- scheduleRetainedThreadEviction(client, runtime);
2019
- let protectedThread = true;
2020
- return () => {
2021
- if (!protectedThread) return;
2022
- protectedThread = false;
2023
- if (runtime.closed) return;
2024
- const count = runtime.protectedThreads.get(threadId) ?? 0;
2025
- if (count <= 1) {
2026
- runtime.protectedThreads.delete(threadId);
2027
- const retained = runtime.retainedThreads.get(threadId);
2028
- if (retained) {
2029
- runtime.retainedThreads.delete(threadId);
2030
- runtime.retainedThreads.set(threadId, {
2031
- ...retained,
2032
- expiresAt: Date.now() + CODEX_APP_SERVER_LIVE_THREAD_IDLE_TIMEOUT_MS
2033
- });
2034
- }
2035
- } else runtime.protectedThreads.set(threadId, count - 1);
2036
- scheduleRetainedThreadEviction(client, runtime);
2037
- evictExcessIdleThreads(client, runtime).catch((error) => {
2038
- embeddedAgentLog.warn("codex retained thread unpin eviction failed", {
2039
- threadId,
2040
- reason: formatErrorMessage(error)
2041
- });
2042
- });
5062
+ var CodexThreadDirectInputError = class extends Error {
5063
+ constructor(threadId) {
5064
+ super(`Codex thread ${threadId} is controlled by its parent and cannot accept direct input. Continue its parent thread, or use /new for a separate OpenClaw session.`);
5065
+ this.name = "CodexThreadDirectInputError";
5066
+ }
5067
+ };
5068
+ /** Native V2 children allow observation, but only their parent may supply turn input. */
5069
+ function assertCodexThreadAcceptsDirectInput(thread) {
5070
+ if (thread.canAcceptDirectInput === false) throw new CodexThreadDirectInputError(thread.id);
5071
+ }
5072
+ /** Asserts and normalizes a Codex turn/start response. */
5073
+ function assertCodexTurnStartResponse(value) {
5074
+ const normalized = normalizeWithDefaults(turnStartResponseSchema, normalizeTurnStartResponse(value));
5075
+ return assertCodexShape(validateTurnStartResponse, normalized, "turn/start response");
5076
+ }
5077
+ /** Reads Codex dynamic-tool call params, returning undefined for invalid payloads. */
5078
+ function readCodexDynamicToolCallParams(value) {
5079
+ return readCodexShape(validateDynamicToolCallParams, normalizeWithDefaults(dynamicToolCallParamsSchema, value));
5080
+ }
5081
+ /** Reads a Codex error notification payload if it matches the protocol schema. */
5082
+ function readCodexErrorNotification(value) {
5083
+ return readCodexShape(validateErrorNotification, normalizeWithDefaults(errorNotificationSchema, value));
5084
+ }
5085
+ /** Asserts and normalizes a Codex model/list response. */
5086
+ function assertCodexModelListResponse(value) {
5087
+ return assertCodexShape(validateModelListResponse, normalizeWithDefaults(modelListResponseSchema, value), "model/list response");
5088
+ }
5089
+ /** Reads and normalizes a Codex turn object. */
5090
+ function readCodexTurn(value) {
5091
+ return readCodexShape(validateTurnStartResponse, normalizeWithDefaults(turnStartResponseSchema, { turn: normalizeTurn(value) }))?.turn;
5092
+ }
5093
+ /** Reads a Codex turn/completed notification payload if it matches the protocol schema. */
5094
+ function readCodexTurnCompletedNotification(value) {
5095
+ return readCodexShape(validateTurnCompletedNotification, normalizeWithDefaults(turnCompletedNotificationSchema, normalizeTurnCompletedNotification(value)));
5096
+ }
5097
+ function assertCodexShape(validate, value, label) {
5098
+ if (validate.check(value)) return value;
5099
+ throw new Error(`Invalid Codex app-server ${label}: ${formatValidationErrors(validate, value)}`);
5100
+ }
5101
+ function readCodexShape(validate, value) {
5102
+ return validate.check(value) ? value : void 0;
5103
+ }
5104
+ function normalizeTurn(value) {
5105
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
5106
+ return {
5107
+ error: null,
5108
+ startedAt: null,
5109
+ completedAt: null,
5110
+ durationMs: null,
5111
+ ...value,
5112
+ items: Array.isArray(value.items) ? value.items.map(normalizeThreadItem) : []
2043
5113
  };
2044
5114
  }
2045
- //#endregion
2046
- //#region extensions/codex/src/app-server/elicitation-response.ts
2047
- function createCodexElicitationResponse(action, content = null, meta = null) {
5115
+ function normalizeThreadItem(value) {
5116
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
5117
+ switch (value.type) {
5118
+ case "agentMessage": return {
5119
+ phase: null,
5120
+ delivery: null,
5121
+ memoryCitation: null,
5122
+ ...value
5123
+ };
5124
+ case "plan": return {
5125
+ text: "",
5126
+ ...value
5127
+ };
5128
+ case "reasoning": return {
5129
+ summary: [],
5130
+ content: [],
5131
+ ...value
5132
+ };
5133
+ case "dynamicToolCall": return {
5134
+ namespace: null,
5135
+ arguments: null,
5136
+ status: "completed",
5137
+ contentItems: null,
5138
+ success: null,
5139
+ durationMs: null,
5140
+ ...value
5141
+ };
5142
+ default: return value;
5143
+ }
5144
+ }
5145
+ function normalizeTurnStartResponse(value) {
5146
+ if (!value || typeof value !== "object" || Array.isArray(value) || !("turn" in value)) return value;
2048
5147
  return {
2049
- action,
2050
- content,
2051
- _meta: meta
5148
+ ...value,
5149
+ turn: normalizeTurn(value.turn)
5150
+ };
5151
+ }
5152
+ function normalizeTurnCompletedNotification(value) {
5153
+ if (!value || typeof value !== "object" || Array.isArray(value) || !("turn" in value)) return value;
5154
+ return {
5155
+ ...value,
5156
+ turn: normalizeTurn(value.turn)
2052
5157
  };
2053
5158
  }
5159
+ function formatValidationErrors(validate, value) {
5160
+ const errors = validate.errors(value);
5161
+ if (!errors || errors.length === 0) return "schema validation failed";
5162
+ return errors.map((error) => {
5163
+ const message = error.message?.trim() || "schema validation failed";
5164
+ return error.instancePath ? `${error.instancePath} ${message}` : message;
5165
+ }).join("; ");
5166
+ }
2054
5167
  //#endregion
2055
5168
  //#region extensions/codex/src/app-server/rpc-error.ts
2056
5169
  /** RPC error wrapper that preserves app-server error code and data. */
@@ -2248,339 +5361,14 @@ function websocketFrameToText(data) {
2248
5361
  return Buffer.from(data).toString("utf8");
2249
5362
  }
2250
5363
  //#endregion
2251
- //#region extensions/codex/src/app-server/transport-process-containment.ts
2252
- const PROCESS_COLUMNS = "pid=,ppid=,pgid=,stat=,lstart=";
2253
- const MAX_CONTAINED_PROCESSES = 512;
2254
- const MAX_PROCESS_CONTAINMENT_MS = 2e3;
2255
- const MAX_PROCESS_QUIESCE_PASSES = 16;
2256
- const PROCESS_INSPECTION_MAX_BYTES = 8 * 1024 * 1024;
2257
- async function terminateCodexAppServerDescendants(child) {
2258
- const rootPid = child.pid;
2259
- if (process.platform === "win32" || !rootPid || !child.kill || hasExited(child)) return;
2260
- const deadline = Date.now() + MAX_PROCESS_CONTAINMENT_MS;
2261
- const snapshot = await readProcessSnapshot(deadline);
2262
- if (!snapshot || Date.now() >= deadline) return;
2263
- const root = snapshot.find((row) => row.pid === rootPid);
2264
- if (!root || !isSameLiveRoot(root, root)) return;
2265
- const initialDescendants = collectDescendants(snapshot, [rootPid]);
2266
- if (initialDescendants.length > MAX_CONTAINED_PROCESSES) return;
2267
- const stoppedDescendants = /* @__PURE__ */ new Map();
2268
- if (!await signalSameRoot(root, "SIGSTOP", deadline)) return;
2269
- let resumeRootOnUnwind = true;
2270
- try {
2271
- const descendants = await quiesceDescendants(root, initialDescendants, stoppedDescendants, deadline);
2272
- if (!descendants) return;
2273
- for (const descendant of descendants.toReversed()) {
2274
- if (Date.now() >= deadline) return;
2275
- if (!descendant.state.startsWith("Z")) {
2276
- if (!await signalSameProcess(descendant, "SIGKILL", deadline) || Date.now() >= deadline) return;
2277
- }
2278
- }
2279
- resumeRootOnUnwind = false;
2280
- let resumed = false;
2281
- return () => {
2282
- if (resumed) return;
2283
- resumed = true;
2284
- resumeTransportRoot(child, root, false);
2285
- };
2286
- } finally {
2287
- if (resumeRootOnUnwind) {
2288
- for (const descendant of stoppedDescendants.values()) signalProcess(descendant.pid, "SIGCONT");
2289
- resumeTransportRoot(child, root, true);
2290
- }
2291
- }
2292
- }
2293
- async function quiesceDescendants(root, initialDescendants, stopped, deadline) {
2294
- const provenByPid = new Map(initialDescendants.map((descendant) => [descendant.pid, descendant]));
2295
- const stopFailures = /* @__PURE__ */ new Map();
2296
- for (let pass = 0; pass < MAX_PROCESS_QUIESCE_PASSES; pass += 1) {
2297
- if (Date.now() >= deadline) return;
2298
- const snapshot = await readProcessSnapshot(deadline);
2299
- if (!snapshot || Date.now() >= deadline) return;
2300
- const currentRoot = snapshot.find((row) => row.pid === root.pid);
2301
- if (!currentRoot || !isSameLiveRoot(currentRoot, root)) return;
2302
- if (!isSameLiveRoot(currentRoot, root, true)) {
2303
- if (!await signalSameRoot(root, "SIGSTOP", deadline) || Date.now() >= deadline) return;
2304
- continue;
2305
- }
2306
- const snapshotByPid = new Map(snapshot.map((process) => [process.pid, process]));
2307
- const liveProven = [];
2308
- for (const proven of provenByPid.values()) {
2309
- const current = snapshotByPid.get(proven.pid);
2310
- if (!current) {
2311
- provenByPid.delete(proven.pid);
2312
- stopped.delete(identityKey(proven));
2313
- continue;
2314
- }
2315
- if (!hasSameIdentity(proven, current)) return;
2316
- provenByPid.set(current.pid, current);
2317
- const key = identityKey(current);
2318
- if (stopped.has(key)) stopped.set(key, current);
2319
- liveProven.push(current);
2320
- }
2321
- const descendants = collectDescendants(snapshot, [root.pid, ...liveProven.map(({ pid }) => pid)]);
2322
- for (const descendant of descendants) {
2323
- const proven = provenByPid.get(descendant.pid);
2324
- if (proven && !hasSameIdentity(proven, descendant)) return;
2325
- provenByPid.set(descendant.pid, descendant);
2326
- }
2327
- if (provenByPid.size > MAX_CONTAINED_PROCESSES) return;
2328
- const quiescenceTargets = new Map(liveProven.map((process) => [process.pid, process]));
2329
- for (const descendant of descendants) quiescenceTargets.set(descendant.pid, descendant);
2330
- let allStopped = true;
2331
- for (const descendant of quiescenceTargets.values()) {
2332
- if (Date.now() >= deadline) return;
2333
- if (isStoppedState(descendant.state)) continue;
2334
- const stopQueued = await signalSameProcess(descendant, "SIGSTOP", deadline);
2335
- if (Date.now() >= deadline) return;
2336
- if (stopQueued) {
2337
- stopFailures.delete(identityKey(descendant));
2338
- stopped.set(identityKey(descendant), descendant);
2339
- } else {
2340
- const key = identityKey(descendant);
2341
- const failures = (stopFailures.get(key) ?? 0) + 1;
2342
- if (failures >= 2) return;
2343
- stopFailures.set(key, failures);
2344
- }
2345
- if (!isUninterruptibleState(descendant.state) || !stopQueued) allStopped = false;
2346
- }
2347
- if (allStopped) return [...provenByPid.values()];
2348
- }
2349
- }
2350
- async function readProcessSnapshot(deadline) {
2351
- return await readProcesses(["-axo", PROCESS_COLUMNS], deadline);
2352
- }
2353
- async function readProcess(pid, deadline) {
2354
- return (await readProcesses([
2355
- "-o",
2356
- PROCESS_COLUMNS,
2357
- "-p",
2358
- String(pid)
2359
- ], deadline))?.find((row) => row.pid === pid);
2360
- }
2361
- async function readProcesses(args, deadline) {
2362
- const remainingMs = deadline - Date.now();
2363
- if (remainingMs <= 0) return;
2364
- return await new Promise((resolve) => {
2365
- let settled = false;
2366
- const settle = (processes) => {
2367
- if (settled) return;
2368
- settled = true;
2369
- clearTimeout(timer);
2370
- resolve(processes);
2371
- };
2372
- const inspector = execFile("ps", args, {
2373
- encoding: "utf8",
2374
- maxBuffer: PROCESS_INSPECTION_MAX_BYTES
2375
- }, (error, stdout) => {
2376
- settle(error ? void 0 : parseProcesses(stdout));
2377
- });
2378
- const timer = setTimeout(() => {
2379
- settle(void 0);
2380
- inspector.stdout?.destroy();
2381
- inspector.stderr?.destroy();
2382
- inspector.kill("SIGKILL");
2383
- inspector.unref();
2384
- }, Math.max(1, remainingMs));
2385
- timer.unref?.();
2386
- });
2387
- }
2388
- function parseProcesses(output) {
2389
- const rows = [];
2390
- for (const line of output.split("\n")) {
2391
- const match = /^\s*(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(.+?)\s*$/.exec(line);
2392
- if (!match) continue;
2393
- const pid = Number(match[1] ?? "");
2394
- const ppid = Number(match[2] ?? "");
2395
- const pgid = Number(match[3] ?? "");
2396
- const startedAt = (match[5] ?? "").trim().replace(/\s+/g, " ");
2397
- if (![
2398
- pid,
2399
- ppid,
2400
- pgid
2401
- ].every(Number.isSafeInteger) || pid <= 0 || ppid < 0 || pgid <= 0 || !startedAt) continue;
2402
- rows.push({
2403
- pid,
2404
- ppid,
2405
- pgid,
2406
- state: match[4] ?? "",
2407
- startedAt
2408
- });
2409
- }
2410
- return rows;
2411
- }
2412
- function collectDescendants(snapshot, rootPids) {
2413
- const childrenByParent = /* @__PURE__ */ new Map();
2414
- for (const row of snapshot) {
2415
- const children = childrenByParent.get(row.ppid) ?? [];
2416
- children.push(row);
2417
- childrenByParent.set(row.ppid, children);
2418
- }
2419
- const descendants = [];
2420
- const pending = [...new Set(rootPids)];
2421
- const seen = new Set(pending);
2422
- for (const parentPid of pending) for (const child of childrenByParent.get(parentPid) ?? []) {
2423
- if (seen.has(child.pid)) continue;
2424
- seen.add(child.pid);
2425
- descendants.push(child);
2426
- pending.push(child.pid);
2427
- }
2428
- return descendants;
2429
- }
2430
- function isStoppedState(state) {
2431
- return state.startsWith("T") || state.startsWith("t") || state.startsWith("Z");
2432
- }
2433
- function isQuiescedState(state) {
2434
- return isStoppedState(state) || isUninterruptibleState(state);
2435
- }
2436
- function isUninterruptibleState(state) {
2437
- return state.startsWith("D") || state.startsWith("U");
2438
- }
2439
- function isSameLiveProcess(current, expected) {
2440
- return current.pgid === expected.pgid && !current.state.startsWith("Z") && hasSameIdentity(current, expected);
2441
- }
2442
- function isSameLiveRoot(current, expected, requireStopped = false) {
2443
- return current.ppid === process.pid && (!requireStopped || isQuiescedState(current.state)) && isSameLiveProcess(current, expected);
2444
- }
2445
- async function signalSameRoot(root, signal, deadline) {
2446
- const current = await readProcess(root.pid, deadline);
2447
- return Boolean(current && isSameLiveRoot(current, root) && signalProcess(current.pid, signal));
2448
- }
2449
- function resumeTransportRoot(child, root, allowSynchronousPidFallback) {
2450
- try {
2451
- if (child.kill) {
2452
- child.kill("SIGCONT");
2453
- return;
2454
- }
2455
- } catch {
2456
- if (!allowSynchronousPidFallback) return;
2457
- }
2458
- if (allowSynchronousPidFallback) signalProcess(root.pid, "SIGCONT");
2459
- }
2460
- async function signalSameProcess(expected, signal, deadline) {
2461
- const current = await readProcess(expected.pid, deadline);
2462
- return Boolean(current && isSameLiveProcess(current, expected) && signalProcess(current.pid, signal));
2463
- }
2464
- function hasSameIdentity(left, right) {
2465
- return identityKey(left) === identityKey(right);
2466
- }
2467
- function identityKey(row) {
2468
- return `${row.pid}\0${row.startedAt}`;
2469
- }
2470
- function hasExited(child) {
2471
- return child.exitCode != null || child.signalCode != null;
2472
- }
2473
- function signalProcess(pid, signal) {
2474
- try {
2475
- process.kill(pid, signal);
2476
- return true;
2477
- } catch {
2478
- return false;
2479
- }
2480
- }
2481
- //#endregion
2482
- //#region extensions/codex/src/app-server/transport.ts
2483
- /**
2484
- * Shared transport lifecycle helpers for stdio and WebSocket Codex app-server
2485
- * connections.
2486
- */
2487
- const CODEX_APP_SERVER_TRANSPORT_CLOSES = /* @__PURE__ */ new WeakMap();
2488
- /** Starts graceful transport shutdown and schedules a force kill fallback. */
2489
- function closeCodexAppServerTransport(child, options = {}) {
2490
- beginCodexAppServerTransportClose(child, options);
2491
- }
2492
- function beginCodexAppServerTransportClose(child, options) {
2493
- const current = CODEX_APP_SERVER_TRANSPORT_CLOSES.get(child);
2494
- if (current) return current;
2495
- if (process.platform === "win32" || !child.pid || !child.kill || hasCodexAppServerTransportExited(child)) {
2496
- finishCodexAppServerTransportClose(child, options);
2497
- const completed = Promise.resolve();
2498
- CODEX_APP_SERVER_TRANSPORT_CLOSES.set(child, completed);
2499
- return completed;
2500
- }
2501
- const closing = (async () => {
2502
- let resumeRoot;
2503
- try {
2504
- resumeRoot = await terminateCodexAppServerDescendants(child);
2505
- } catch {
2506
- resumeRoot = void 0;
2507
- }
2508
- try {
2509
- finishCodexAppServerTransportClose(child, options, resumeRoot);
2510
- } catch {
2511
- signalCodexAppServerTransport(child, "SIGKILL");
2512
- }
2513
- })();
2514
- CODEX_APP_SERVER_TRANSPORT_CLOSES.set(child, closing);
2515
- return closing;
2516
- }
2517
- function finishCodexAppServerTransportClose(child, options, resumeRoot) {
2518
- const forceKillDelayMs = options.forceKillDelayMs ?? 1e3;
2519
- const forceKill = setTimeout(() => {
2520
- if (hasCodexAppServerTransportExited(child)) return;
2521
- signalCodexAppServerTransport(child, "SIGKILL");
2522
- }, Math.max(1, forceKillDelayMs));
2523
- forceKill.unref?.();
2524
- child.once("exit", () => {
2525
- clearTimeout(forceKill);
2526
- child.stdout.destroy?.();
2527
- child.stderr.destroy?.();
2528
- });
2529
- try {
2530
- child.stdin.end?.();
2531
- child.stdin.destroy?.();
2532
- } finally {
2533
- resumeRoot?.();
2534
- }
2535
- child.unref?.();
2536
- child.stdout.unref?.();
2537
- child.stderr.unref?.();
2538
- child.stdin.unref?.();
2539
- }
2540
- /** Closes a transport and waits briefly for an exit event. */
2541
- async function closeCodexAppServerTransportAndWait(child, options = {}) {
2542
- if (!hasCodexAppServerTransportExited(child)) await beginCodexAppServerTransportClose(child, options);
2543
- return await waitForCodexAppServerTransportExit(child, options.exitTimeoutMs ?? 2e3);
2544
- }
2545
- function hasCodexAppServerTransportExited(child) {
2546
- return child.exitCode !== null && child.exitCode !== void 0 ? true : child.signalCode !== null && child.signalCode !== void 0;
2547
- }
2548
- async function waitForCodexAppServerTransportExit(child, timeoutMs) {
2549
- if (hasCodexAppServerTransportExited(child)) return true;
2550
- return await new Promise((resolve) => {
2551
- let settled = false;
2552
- const onExit = () => {
2553
- if (settled) return;
2554
- settled = true;
2555
- clearTimeout(timeout);
2556
- resolve(true);
2557
- };
2558
- const timeout = setTimeout(() => {
2559
- if (settled) return;
2560
- settled = true;
2561
- child.off?.("exit", onExit);
2562
- resolve(false);
2563
- }, Math.max(1, timeoutMs));
2564
- child.once("exit", onExit);
2565
- });
2566
- }
2567
- function signalCodexAppServerTransport(child, signal) {
2568
- if (child.pid && process.platform !== "win32") try {
2569
- process.kill(-child.pid, signal);
2570
- return;
2571
- } catch {}
2572
- child.kill?.(signal);
2573
- }
2574
- //#endregion
2575
5364
  //#region extensions/codex/src/app-server/client.ts
2576
5365
  /**
2577
5366
  * JSON-RPC client for Codex app-server transports, including request/response
2578
5367
  * routing, notification fanout, server request handlers, and version checks.
2579
5368
  */
2580
5369
  const CODEX_APP_SERVER_PARSE_LOG_MAX = 500;
2581
- const CODEX_APP_SERVER_PARSE_BUFFER_MAX = 8 * 1024 * 1024;
5370
+ const CODEX_APP_SERVER_PARSE_BUFFER_MAX = 8388608;
2582
5371
  const CODEX_APP_SERVER_PARSE_BUFFER_MAX_LINES = 1e3;
2583
- const CODEX_DYNAMIC_TOOL_SERVER_REQUEST_TIMEOUT_MS = 66e4;
2584
5372
  const CODEX_APP_SERVER_STDERR_TAIL_MAX = 2e3;
2585
5373
  const CODEX_APP_SERVER_OVERLOADED_ERROR_CODE = -32001;
2586
5374
  const CODEX_APP_SERVER_OVERLOAD_MAX_RETRIES = 3;
@@ -2599,6 +5387,10 @@ function getCodexAppServerClientInstanceId(client) {
2599
5387
  function resolveCodexAppServerClientInstanceId(client) {
2600
5388
  return client.getInstanceId?.call(client) ?? getCodexAppServerClientInstanceId(client);
2601
5389
  }
5390
+ /** Codex rejects this exact code before enqueueing, including mutating requests. */
5391
+ function isCodexAppServerOverloadError(error) {
5392
+ return error instanceof CodexAppServerRpcError && error.code === CODEX_APP_SERVER_OVERLOADED_ERROR_CODE;
5393
+ }
2602
5394
  var CodexAppServerLocalRequestCancellationError = class extends Error {
2603
5395
  constructor(method, reason, mayHaveWritten) {
2604
5396
  super(`${method} ${reason}`);
@@ -2658,6 +5450,7 @@ var CodexAppServerClient = class CodexAppServerClient {
2658
5450
  this.closeHandlers = /* @__PURE__ */ new Set();
2659
5451
  this.nextId = 1;
2660
5452
  this.initialized = false;
5453
+ this.modelCatalogRevision = 0;
2661
5454
  this.closed = false;
2662
5455
  this.transportExited = false;
2663
5456
  this.stderrTail = "";
@@ -2683,7 +5476,7 @@ var CodexAppServerClient = class CodexAppServerClient {
2683
5476
  child.stdin.on?.("error", (error) => this.closeWithError(toStringifiedError(error)));
2684
5477
  }
2685
5478
  /** Starts a new app-server client using resolved runtime start options. */
2686
- static start(options) {
5479
+ static async start(options, assertCurrent) {
2687
5480
  const defaults = resolveCodexAppServerRuntimeOptions().start;
2688
5481
  const startOptions = {
2689
5482
  ...defaults,
@@ -2692,7 +5485,18 @@ var CodexAppServerClient = class CodexAppServerClient {
2692
5485
  };
2693
5486
  if (startOptions.transport === "stdio" && startOptions.commandSource === "managed") throw new Error("Managed Codex app-server start options must be resolved before spawn.");
2694
5487
  if (startOptions.transport === "websocket" || startOptions.transport === "unix") return new CodexAppServerClient(createWebSocketTransport(startOptions));
2695
- return new CodexAppServerClient(createStdioTransport(startOptions));
5488
+ let client;
5489
+ try {
5490
+ await createStdioTransport(startOptions, process.env, assertCurrent, (child) => {
5491
+ client = new CodexAppServerClient(child);
5492
+ });
5493
+ return client;
5494
+ } catch (error) {
5495
+ assertCurrent?.();
5496
+ if (client?.transportExited && hasCodexAppServerNaturalExit(client.child)) throw buildCodexAppServerExitError(client.child.exitCode, client.child.signalCode, client.stderrTail);
5497
+ const stderr = client?.getStderrDiagnostic();
5498
+ throw stderr ? new Error(`${coerceErrorMessage(error)}; stderr=${JSON.stringify(stderr)}`, { cause: error }) : error;
5499
+ }
2696
5500
  }
2697
5501
  /** Builds a client around a fake transport for tests. */
2698
5502
  static fromTransportForTests(child) {
@@ -2741,6 +5545,10 @@ var CodexAppServerClient = class CodexAppServerClient {
2741
5545
  getInstanceId() {
2742
5546
  return this.instanceId;
2743
5547
  }
5548
+ /** Account/config observations become stale before a mutation can enter the wire. */
5549
+ getModelCatalogRevision() {
5550
+ return this.modelCatalogRevision;
5551
+ }
2744
5552
  /** Installs the spawn-owner check run before config-loading thread requests. */
2745
5553
  setThreadSessionRequestGuard(guard) {
2746
5554
  this.threadSessionRequestGuard = guard;
@@ -2750,8 +5558,7 @@ var CodexAppServerClient = class CodexAppServerClient {
2750
5558
  return this.child.pid;
2751
5559
  }
2752
5560
  request(method, params, optionsInput) {
2753
- let options = optionsInput;
2754
- options ??= {};
5561
+ const options = optionsInput ?? {};
2755
5562
  if (this.closed) return Promise.reject(this.closeError ?? /* @__PURE__ */ new Error("codex app-server client is closed"));
2756
5563
  if (options.signal?.aborted) return Promise.reject(new CodexAppServerLocalRequestCancellationError(method, "aborted", false));
2757
5564
  const guard = method === "thread/start" || method === "thread/resume" || method === "thread/fork" ? this.threadSessionRequestGuard : void 0;
@@ -2786,11 +5593,11 @@ var CodexAppServerClient = class CodexAppServerClient {
2786
5593
  const elapsedMs = Date.now() - guardStartedAt;
2787
5594
  const remainingTimeoutMs = options.timeoutMs === void 0 ? void 0 : options.timeoutMs - elapsedMs;
2788
5595
  if (remainingTimeoutMs !== void 0 && remainingTimeoutMs <= 0) throw new CodexAppServerLocalRequestCancellationError(method, "timed out", false);
2789
- return await this.requestWithoutThreadSessionGuard(method, params, {
5596
+ return await this.requestWithOverloadRetry(method, params, {
2790
5597
  ...options,
2791
5598
  ...remainingTimeoutMs !== void 0 ? { timeoutMs: remainingTimeoutMs } : {}
2792
- }, () => {
2793
- requestMayHaveWritten = true;
5599
+ }, (mayHaveWritten) => {
5600
+ requestMayHaveWritten = mayHaveWritten;
2794
5601
  });
2795
5602
  } catch (error) {
2796
5603
  if (requestMayHaveWritten && !(error instanceof CodexAppServerRpcError)) {
@@ -2803,12 +5610,9 @@ var CodexAppServerClient = class CodexAppServerClient {
2803
5610
  }
2804
5611
  })();
2805
5612
  }
2806
- return this.requestWithoutThreadSessionGuard(method, params, options);
5613
+ return this.requestWithOverloadRetry(method, params, options);
2807
5614
  }
2808
- requestWithoutThreadSessionGuard(method, params, options, onWriteAttempt) {
2809
- return this.requestWithOverloadRetry(method, params, options, onWriteAttempt);
2810
- }
2811
- async requestWithOverloadRetry(method, params, options, onWriteAttempt) {
5615
+ async requestWithOverloadRetry(method, params, options, onWriteStateChange) {
2812
5616
  const deadline = options.timeoutMs !== void 0 && Number.isFinite(options.timeoutMs) ? Date.now() + options.timeoutMs : void 0;
2813
5617
  for (let retry = 0;; retry += 1) {
2814
5618
  if (options.signal?.aborted) throw new CodexAppServerLocalRequestCancellationError(method, "aborted", false);
@@ -2818,9 +5622,10 @@ var CodexAppServerClient = class CodexAppServerClient {
2818
5622
  return await this.requestOnce(method, params, {
2819
5623
  ...options,
2820
5624
  ...remainingTimeoutMs !== void 0 ? { timeoutMs: remainingTimeoutMs } : {}
2821
- }, onWriteAttempt);
5625
+ }, onWriteStateChange);
2822
5626
  } catch (error) {
2823
- if (!(error instanceof CodexAppServerRpcError) || error.code !== CODEX_APP_SERVER_OVERLOADED_ERROR_CODE || retry >= CODEX_APP_SERVER_OVERLOAD_MAX_RETRIES) throw error;
5627
+ if (!isCodexAppServerOverloadError(error) || retry >= CODEX_APP_SERVER_OVERLOAD_MAX_RETRIES) throw error;
5628
+ onWriteStateChange?.(false);
2824
5629
  const backoffMs = Math.round(CODEX_APP_SERVER_OVERLOAD_RETRY_BASE_MS * 2 ** retry * (.75 + Math.random() * .5));
2825
5630
  await this.waitForOverloadRetry(method, backoffMs, deadline, options.signal);
2826
5631
  }
@@ -2849,10 +5654,11 @@ var CodexAppServerClient = class CodexAppServerClient {
2849
5654
  if (signal?.aborted) abortListener();
2850
5655
  });
2851
5656
  }
2852
- requestOnce(method, params, options, onWriteAttempt) {
5657
+ requestOnce(method, params, options, onWriteStateChange) {
2853
5658
  if (this.closed) return Promise.reject(this.closeError ?? /* @__PURE__ */ new Error("codex app-server client is closed"));
2854
5659
  if (options.signal?.aborted) return Promise.reject(new CodexAppServerLocalRequestCancellationError(method, "aborted", false));
2855
5660
  const id = this.nextId++;
5661
+ if (method === "account/login/start" || method === "account/logout" || method === "config/value/write" || method === "config/batchWrite") this.modelCatalogRevision += 1;
2856
5662
  const message = {
2857
5663
  id,
2858
5664
  method,
@@ -2902,8 +5708,9 @@ var CodexAppServerClient = class CodexAppServerClient {
2902
5708
  return;
2903
5709
  }
2904
5710
  try {
5711
+ options.assertCurrent?.();
2905
5712
  mayHaveWritten = true;
2906
- onWriteAttempt?.();
5713
+ onWriteStateChange?.(true);
2907
5714
  this.writeMessage(message, (error) => rejectPending(error));
2908
5715
  } catch (error) {
2909
5716
  rejectPending(toStringifiedError(error));
@@ -3105,8 +5912,9 @@ var CodexAppServerClient = class CodexAppServerClient {
3105
5912
  }
3106
5913
  async runServerRequestHandlers(request) {
3107
5914
  const controller = new AbortController();
3108
- const timeoutResponse = timeoutServerRequestResponse(request);
3109
- if (!timeoutResponse) return await this.runServerRequestHandlersWithoutTimeout(request, controller.signal);
5915
+ if (request.method !== "item/tool/call") return await this.runServerRequestHandlersWithoutTimeout(request, controller.signal);
5916
+ const timeoutMs = resolveDynamicToolServerRequestTimeoutMs(readCodexDynamicToolCallParams(request.params));
5917
+ const timeoutResponse = timeoutServerRequestResponse(timeoutMs);
3110
5918
  let timeout;
3111
5919
  try {
3112
5920
  return await Promise.race([this.runServerRequestHandlersWithoutTimeout(request, controller.signal), new Promise((resolve) => {
@@ -3114,11 +5922,11 @@ var CodexAppServerClient = class CodexAppServerClient {
3114
5922
  embeddedAgentLog.warn("codex app-server server request timed out", {
3115
5923
  id: request.id,
3116
5924
  method: request.method,
3117
- timeoutMs: CODEX_DYNAMIC_TOOL_SERVER_REQUEST_TIMEOUT_MS
5925
+ timeoutMs
3118
5926
  });
3119
5927
  controller.abort(/* @__PURE__ */ new Error("codex app-server server request timed out"));
3120
5928
  resolve(timeoutResponse);
3121
- }, CODEX_DYNAMIC_TOOL_SERVER_REQUEST_TIMEOUT_MS);
5929
+ }, timeoutMs);
3122
5930
  timeout.unref?.();
3123
5931
  })]);
3124
5932
  } finally {
@@ -3133,6 +5941,7 @@ var CodexAppServerClient = class CodexAppServerClient {
3133
5941
  }
3134
5942
  }
3135
5943
  handleNotification(notification) {
5944
+ if (notification.method === "account/updated") this.modelCatalogRevision += 1;
3136
5945
  if (this.notificationHandlers.size === 0 && notification.method === "configWarning") {
3137
5946
  if (this.pendingStartupWarnings.length === CODEX_APP_SERVER_PENDING_STARTUP_WARNINGS_MAX) this.pendingStartupWarnings.shift();
3138
5947
  this.pendingStartupWarnings.push(notification);
@@ -3186,12 +5995,11 @@ function defaultServerRequestResponse(request) {
3186
5995
  function stringifyCodexAppServerMessage(message) {
3187
5996
  return JSON.stringify(message, (_key, value) => typeof value === "string" ? value.replace(UNPAIRED_SURROGATE_RE, "") : value) ?? "null";
3188
5997
  }
3189
- function timeoutServerRequestResponse(request) {
3190
- if (request.method !== "item/tool/call") return;
5998
+ function timeoutServerRequestResponse(timeoutMs) {
3191
5999
  return {
3192
6000
  contentItems: [{
3193
6001
  type: "inputText",
3194
- text: `OpenClaw dynamic tool call timed out after ${CODEX_DYNAMIC_TOOL_SERVER_REQUEST_TIMEOUT_MS}ms before sending a response to Codex.`
6002
+ text: `OpenClaw dynamic tool call timed out after ${timeoutMs}ms before sending a response to Codex.`
3195
6003
  }],
3196
6004
  success: false
3197
6005
  };
@@ -3210,7 +6018,7 @@ function assertSupportedCodexAppServerVersion(response) {
3210
6018
  if (!detectedVersion) throw new CodexAppServerVersionError(detectedVersion);
3211
6019
  const detected = parse(detectedVersion);
3212
6020
  if (!detected || detected.compare("0.149.0") < 0) throw new CodexAppServerVersionError(detectedVersion);
3213
- if (detected.compare("0.150.1") > 0) embeddedAgentLog.warn("codex app-server is newer than OpenClaw's managed runtime; continuing with normal startup validation", {
6021
+ if (detected.compare("0.152.1") > 0) embeddedAgentLog.warn("codex app-server is newer than OpenClaw's managed runtime; continuing with normal startup validation", {
3214
6022
  detectedVersion,
3215
6023
  validatedVersion: CODEX_APP_SERVER_VERSION
3216
6024
  });
@@ -3287,15 +6095,8 @@ function formatExitValue(value) {
3287
6095
  */
3288
6096
  /** Minimum startup timeout accepted by the Codex app-server harness. */
3289
6097
  const CODEX_APP_SERVER_STARTUP_TIMEOUT_FLOOR_MS = 100;
3290
- /** Default idle timeout while waiting for app-server turn completion. */
3291
- const CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS = 6e4;
3292
- /** Short guard after apparent assistant completion. */
3293
- const CODEX_TURN_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS = 1e4;
3294
- const CODEX_POST_TOOL_RAW_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS = 5 * 6e4;
3295
- /** Guard after reasoning/commentary progress when no tool handoff occurred. */
3296
- const CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS = 5 * 6e4;
3297
- /** Long terminal idle watch for app-server turns that never send completion. */
3298
- const CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS = 30 * 6e4;
6098
+ const TURN_TERMINAL_SETTLEMENT_TIMEOUT_MS = 12e4;
6099
+ const TURN_FINALIZE_DRAIN_ABORT_GRACE_MS = 5e3;
3299
6100
  var CodexAppServerStartupError = class extends Error {
3300
6101
  constructor(reason, message = reason === "timed_out" ? "codex app-server startup timed out" : "codex app-server startup aborted") {
3301
6102
  super(message);
@@ -3308,7 +6109,8 @@ function isCodexAppServerStartupError(error, reason) {
3308
6109
  return error instanceof Error && "code" in error && error.code === "CODEX_APP_SERVER_STARTUP_CANCELLED" && "reason" in error && (error.reason === "aborted" || error.reason === "timed_out") && (reason === void 0 || error.reason === reason);
3309
6110
  }
3310
6111
  function resolvePositiveIntegerTimeoutMs(value, fallbackMs) {
3311
- return resolveTimerTimeoutMs(value, resolveTimerTimeoutMs(fallbackMs, 1));
6112
+ const fallback = resolveTimerTimeoutMs(fallbackMs, 1);
6113
+ return resolveTimerTimeoutMs(value, fallback);
3312
6114
  }
3313
6115
  /** Runs startup work with abort and timeout handling plus optional cleanup. */
3314
6116
  async function withCodexStartupTimeout(params) {
@@ -3354,27 +6156,11 @@ function resolveCodexStartupTimeoutMs(params) {
3354
6156
  const timeoutMs = resolvePositiveIntegerTimeoutMs(params.timeoutMs, timeoutFloorMs);
3355
6157
  return Math.max(timeoutFloorMs, timeoutMs);
3356
6158
  }
3357
- /** Resolves the completion-idle timeout for an active turn. */
3358
- function resolveCodexTurnCompletionIdleTimeoutMs(value) {
3359
- return resolvePositiveIntegerTimeoutMs(value, CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS);
3360
- }
3361
- /** Resolves the short assistant-completion release timeout. */
3362
- function resolveCodexTurnAssistantCompletionIdleTimeoutMs(value) {
3363
- return resolvePositiveIntegerTimeoutMs(value, CODEX_TURN_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS);
3364
- }
3365
- /** Resolves the conservative post-tool raw assistant guard timeout. */
3366
- function resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs(value, fallbackMs) {
3367
- return resolvePositiveIntegerTimeoutMs(value, Math.max(resolvePositiveIntegerTimeoutMs(void 0, fallbackMs), CODEX_POST_TOOL_RAW_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS));
3368
- }
3369
- /** Resolves the long terminal turn idle timeout. */
3370
- function resolveCodexTurnTerminalIdleTimeoutMs(value, runTimeoutOverrideMs) {
3371
- const explicitRunBudgetMs = resolvePositiveIntegerTimeoutMs(runTimeoutOverrideMs, CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS);
3372
- return resolvePositiveIntegerTimeoutMs(value, Math.max(CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS, explicitRunBudgetMs));
3373
- }
3374
6159
  /** Adds gateway grace time to a caller timeout without overflowing invalid values. */
3375
6160
  function resolveCodexGatewayTimeoutWithGraceMs(timeoutMs, graceMs = 1e4) {
3376
6161
  const timeout = resolvePositiveIntegerTimeoutMs(timeoutMs, 1);
3377
- return addTimerTimeoutGraceMs(timeout, resolveTimerTimeoutMs(graceMs, 0, 0)) ?? timeout;
6162
+ const grace = resolveTimerTimeoutMs(graceMs, 0, 0);
6163
+ return addTimerTimeoutGraceMs(timeout, grace) ?? timeout;
3378
6164
  }
3379
6165
  //#endregion
3380
6166
  //#region extensions/codex/src/app-server/desktop-generation-fingerprint.ts
@@ -3459,8 +6245,8 @@ async function statFingerprint(filePath) {
3459
6245
  }
3460
6246
  }
3461
6247
  async function readFileFingerprint(filePath, expected, followsSymlink) {
3462
- const noFollow = followsSymlink ? 0 : constants.O_NOFOLLOW ?? 0;
3463
- const handle = await fs.open(filePath, constants.O_RDONLY | noFollow);
6248
+ const noFollow = followsSymlink ? 0 : constants$1.O_NOFOLLOW ?? 0;
6249
+ const handle = await fs.open(filePath, constants$1.O_RDONLY | noFollow);
3464
6250
  try {
3465
6251
  const before = await handle.stat({ bigint: true });
3466
6252
  if (!sameStat(before, expected)) throw new Error(`Codex desktop artifact changed while fingerprinting: ${filePath}`);
@@ -3757,6 +6543,26 @@ async function waitForPreviousFence(previous, options) {
3757
6543
  });
3758
6544
  }
3759
6545
  //#endregion
6546
+ //#region extensions/codex/src/app-server/thread-lifecycle-errors.ts
6547
+ var CodexThreadStartRequestError = class extends Error {
6548
+ constructor(cause) {
6549
+ super(`thread/start: ${formatErrorMessage(cause)}`, { cause });
6550
+ this.name = "CodexThreadStartRequestError";
6551
+ }
6552
+ };
6553
+ var CodexThreadBindingConflictError = class extends Error {
6554
+ constructor(threadId, operation) {
6555
+ super(`Codex thread binding changed while ${operation}: ${threadId}`);
6556
+ this.name = "CodexThreadBindingConflictError";
6557
+ }
6558
+ };
6559
+ var CodexAdoptedThreadActiveError = class extends AgentHarnessPreflightError {
6560
+ constructor(message = "Codex session became active in another runner; wait for it to finish before continuing") {
6561
+ super(message);
6562
+ this.name = "CodexAdoptedThreadActiveError";
6563
+ }
6564
+ };
6565
+ //#endregion
3760
6566
  //#region extensions/codex/src/app-server/shared-client.ts
3761
6567
  /**
3762
6568
  * Owns shared and isolated Codex app-server client startup, auth application,
@@ -3764,6 +6570,8 @@ async function waitForPreviousFence(previous, options) {
3764
6570
  */
3765
6571
  var shared_client_exports = /* @__PURE__ */ __exportAll({
3766
6572
  assertCodexAppServerClientStartSelectionCurrent: () => assertCodexAppServerClientStartSelectionCurrent,
6573
+ captureCodexAppServerClientLifetime: () => captureCodexAppServerClientLifetime,
6574
+ captureSharedCodexAppServerCatalogLifetime: () => captureSharedCodexAppServerCatalogLifetime,
3767
6575
  clearSharedCodexAppServerClientAndWait: () => clearSharedCodexAppServerClientAndWait,
3768
6576
  clearSharedCodexAppServerClientIfCurrent: () => clearSharedCodexAppServerClientIfCurrent,
3769
6577
  clearSharedCodexAppServerClientIfCurrentAndUnclaimed: () => clearSharedCodexAppServerClientIfCurrentAndUnclaimed,
@@ -3902,7 +6710,7 @@ async function resolveCodexAppServerClientStartContext(options) {
3902
6710
  const preparedAuth = options?.preparedAuth;
3903
6711
  const preparedApiKey = preparedAuth?.kind === "api-key" ? preparedAuth.apiKey.trim() : void 0;
3904
6712
  if (preparedAuth && options?.authProfileId !== void 0) throw new Error("Prepared Codex auth cannot also select a legacy auth profile.");
3905
- if (preparedAuth?.kind === "profile" && !preparedAuth.store.profiles[preparedAuth.profileId]) throw new Error(`Prepared Codex auth profile "${preparedAuth.profileId}" was not found.`);
6713
+ if (preparedAuth?.kind === "profile" && !preparedAuth.store.profiles[preparedAuth.profileId]) throw new Error(`Prepared Codex auth profile "${preparedAuth.profileId}" was not found. Select an existing OpenAI profile or sign in again with OpenClaw, then retry.`);
3906
6714
  if (preparedAuth?.kind === "api-key" && !preparedApiKey) throw new Error("Prepared Codex API-key auth is missing its resolved key.");
3907
6715
  if (preparedAuth && requestedStartOptions.homeScope === "user") throw new Error("Prepared Codex auth requires an isolated app-server home.");
3908
6716
  const preparedAuthRequirement = inferAuthRequirement(preparedAuth);
@@ -3910,11 +6718,11 @@ async function resolveCodexAppServerClientStartContext(options) {
3910
6718
  const authRequirement = options?.authRequirement ?? preparedAuthRequirement;
3911
6719
  const usesNativeAuth = !preparedAuth && (options?.authProfileId === null || requestedStartOptions.homeScope === "user");
3912
6720
  const requestedAuthProfileId = preparedAuth?.kind === "profile" ? preparedAuth.profileId : options?.authProfileId ?? void 0;
3913
- const authProfileStore = preparedAuth?.kind === "profile" ? preparedAuth.store : !usesNativeAuth && options?.authProfileStore ? resolveCodexAppServerAuthProfileStore({
6721
+ const authProfileStore = preparedAuth?.kind === "profile" ? preparedAuth.store : !usesNativeAuth && preparedAuth?.kind !== "api-key" ? resolveCodexAppServerAuthProfileStore({
3914
6722
  agentDir,
3915
6723
  authProfileId: requestedAuthProfileId,
3916
- authProfileStore: options.authProfileStore,
3917
- config: options.config
6724
+ authProfileStore: options?.authProfileStore,
6725
+ config: options?.config
3918
6726
  }) : options?.authProfileStore;
3919
6727
  const authProfileId = preparedAuth?.kind === "profile" ? preparedAuth.profileId : usesNativeAuth || preparedAuth?.kind === "api-key" ? void 0 : resolveCodexAppServerAuthProfileIdForAgent({
3920
6728
  authProfileId: requestedAuthProfileId,
@@ -3922,20 +6730,26 @@ async function resolveCodexAppServerClientStartContext(options) {
3922
6730
  config: options?.config,
3923
6731
  ...authProfileStore ? { authProfileStore } : {}
3924
6732
  });
3925
- const preparedAuthProfileSnapshot = preparedAuth?.kind === "profile" ? preparedAuth.snapshot ?? await resolveCodexAppServerPreparedAuthProfileSnapshot({
6733
+ const preparedAuthProfileSnapshot = !usesNativeAuth && authProfileId ? (preparedAuth?.kind === "profile" ? preparedAuth.snapshot : void 0) ?? await resolveCodexAppServerPreparedAuthProfileSnapshot({
3926
6734
  authProfileId,
3927
6735
  authProfileStore,
3928
6736
  agentDir,
3929
6737
  config: options?.config
3930
6738
  }) : void 0;
3931
- if (preparedAuth?.kind === "profile" && !preparedAuthProfileSnapshot) throw new Error(`Prepared Codex auth profile "${preparedAuth.profileId}" is unusable.`);
6739
+ if (preparedAuth?.kind === "profile" && !preparedAuthProfileSnapshot) throw new Error(`Prepared Codex auth profile "${preparedAuth.profileId}" is unusable. Repair or replace the selected OpenAI profile, then retry.`);
3932
6740
  const resolvedPreparedAuth = preparedAuth?.kind === "api-key" ? {
3933
6741
  kind: "api-key",
3934
6742
  apiKey: preparedApiKey
3935
- } : preparedAuth?.kind === "profile" ? {
3936
- ...preparedAuth,
6743
+ } : preparedAuthProfileSnapshot && authProfileId && authProfileStore ? {
6744
+ kind: "profile",
6745
+ profileId: authProfileId,
6746
+ store: authProfileStore,
3937
6747
  snapshot: preparedAuthProfileSnapshot
3938
6748
  } : void 0;
6749
+ const agentStartOptions = resolveCodexAppServerStartOptionsForAgent({
6750
+ startOptions: requestedStartOptions,
6751
+ agentDir
6752
+ });
3939
6753
  return {
3940
6754
  agentDir,
3941
6755
  usesNativeAuth,
@@ -3945,14 +6759,11 @@ async function resolveCodexAppServerClientStartContext(options) {
3945
6759
  preparedAuth: resolvedPreparedAuth,
3946
6760
  authRequirement,
3947
6761
  startOptions: await bridgeCodexAppServerStartOptions({
3948
- startOptions: await resolveManagedCodexAppServerStartOptions(resolveCodexAppServerStartOptionsForAgent({
3949
- startOptions: requestedStartOptions,
3950
- agentDir
3951
- })),
6762
+ startOptions: await resolveManagedCodexAppServerStartOptions(agentStartOptions),
3952
6763
  agentId: options?.agentId,
3953
6764
  agentDir,
3954
6765
  authProfileId: usesNativeAuth || preparedAuth?.kind === "api-key" ? null : authProfileId,
3955
- ...resolvedPreparedAuth ? { preparedAuth: resolvedPreparedAuth } : {},
6766
+ ...preparedAuth && resolvedPreparedAuth ? { preparedAuth: resolvedPreparedAuth } : {},
3956
6767
  authRequirement,
3957
6768
  config: options?.config,
3958
6769
  pluginConfig: options?.pluginConfig,
@@ -3967,44 +6778,6 @@ function shouldTrackDesktopGeneration(startOptions, pluginConfig) {
3967
6778
  if (resolveCodexComputerUseConfig({ pluginConfig }).enabled && (startOptions.commandSource === "managed" || startOptions.commandSource === "resolved-managed")) return true;
3968
6779
  return startOptions.commandSource === "managed" && (startOptions.managedCommandOrder ?? "package-first") === "desktop-first";
3969
6780
  }
3970
- function resolveWarmSharedCodexAppServerClientIdentity(options) {
3971
- if (!options?.config || typeof options.config !== "object" || !options.startOptions || options.pluginConfig !== void 0 || options.authProfileStore !== void 0 || options.preparedAuth !== void 0 || options.runtimeArtifactMode !== void 0 || options.expectedRuntimeArtifact !== void 0) return;
3972
- const authProfileSelector = options.authProfileId === null ? ["native"] : options.authProfileId === void 0 ? ["implicit"] : ["profile", options.authProfileId];
3973
- return {
3974
- config: options.config,
3975
- startOptions: options.startOptions,
3976
- selectorKey: JSON.stringify([
3977
- options.agentDir ?? resolveDefaultAgentDir(options.config),
3978
- authProfileSelector,
3979
- options.authBindingFingerprint ?? null,
3980
- options.authRequirement ?? null
3981
- ])
3982
- };
3983
- }
3984
- function readWarmSharedCodexAppServerClient(state, identity) {
3985
- const aliases = state.warmClientsByConfig?.get(identity.config)?.get(identity.startOptions);
3986
- const warm = aliases?.get(identity.selectorKey);
3987
- if (!warm) return;
3988
- if (state.clients.get(warm.key) !== warm.entry || warm.entry.client !== warm.client || warm.entry.closeWhenIdle || warm.entry.closeError) {
3989
- aliases?.delete(identity.selectorKey);
3990
- return;
3991
- }
3992
- return warm;
3993
- }
3994
- function rememberWarmSharedCodexAppServerClient(state, identity, warm) {
3995
- state.warmClientsByConfig ??= /* @__PURE__ */ new WeakMap();
3996
- let byStartOptions = state.warmClientsByConfig.get(identity.config);
3997
- if (!byStartOptions) {
3998
- byStartOptions = /* @__PURE__ */ new WeakMap();
3999
- state.warmClientsByConfig.set(identity.config, byStartOptions);
4000
- }
4001
- let aliases = byStartOptions.get(identity.startOptions);
4002
- if (!aliases) {
4003
- aliases = /* @__PURE__ */ new Map();
4004
- byStartOptions.set(identity.startOptions, aliases);
4005
- }
4006
- aliases.set(identity.selectorKey, warm);
4007
- }
4008
6781
  /** Gets or starts a shared Codex app-server client without retaining a lease. */
4009
6782
  async function getSharedCodexAppServerClient(options) {
4010
6783
  return (await acquireSharedCodexAppServerClient(options)).client;
@@ -4035,7 +6808,7 @@ function releaseCodexAppServerClientLease(lease) {
4035
6808
  lease.client = void 0;
4036
6809
  return client ? releaseLeasedSharedCodexAppServerClient(client) : false;
4037
6810
  }
4038
- /** Retries one config-loading request after moving its lease to the current owner. */
6811
+ /** Retries one config-loading operation with a shared deadline and current client lease. */
4039
6812
  async function withLeasedCodexAppServerClientStartSelectionRetry(params) {
4040
6813
  let client = params.lease.client;
4041
6814
  if (!client) throw new Error("Codex app-server selection retry requires an active client lease");
@@ -4051,24 +6824,40 @@ async function withLeasedCodexAppServerClientStartSelectionRetry(params) {
4051
6824
  ...signal ? { signal } : {}
4052
6825
  };
4053
6826
  };
4054
- for (let attempt = 0; attempt < 2; attempt += 1) try {
4055
- return await params.run(client, requestOptions());
4056
- } catch (error) {
4057
- if (!isCodexAppServerStartSelectionChangedError(error) || attempt > 0) throw error;
4058
- retireSharedCodexAppServerClientIfCurrent(client);
4059
- params.lease.client = void 0;
4060
- if (!releaseLeasedSharedCodexAppServerClient(client)) {
4061
- client.close();
4062
- throw new Error("Codex app-server selection retry requires a leased shared client", { cause: error });
6827
+ for (let attempt = 0; attempt < 2; attempt += 1) {
6828
+ const attemptClient = client;
6829
+ let scopeActive = true;
6830
+ const assertCurrent = () => {
6831
+ if (!scopeActive || params.lease.client !== attemptClient) throw new CodexAppServerStartupError("aborted", "Codex app-server request scope is closed");
6832
+ };
6833
+ try {
6834
+ requestOptions();
6835
+ return await params.run(client, () => {
6836
+ assertCurrent();
6837
+ return {
6838
+ ...requestOptions(),
6839
+ assertCurrent
6840
+ };
6841
+ });
6842
+ } catch (error) {
6843
+ if (!isCodexAppServerStartSelectionChangedError(error) || attempt > 0) throw error;
6844
+ retireSharedCodexAppServerClientIfCurrent(client);
6845
+ params.lease.client = void 0;
6846
+ if (!releaseLeasedSharedCodexAppServerClient(client)) {
6847
+ client.close();
6848
+ throw new Error("Codex app-server selection retry requires a leased shared client", { cause: error });
6849
+ }
6850
+ const replacementOptions = requestOptions();
6851
+ client = await getLeasedSharedCodexAppServerClient({
6852
+ ...params.options,
6853
+ timeoutMs: replacementOptions.timeoutMs,
6854
+ ...signal ? { abandonSignal: signal } : {}
6855
+ });
6856
+ params.lease.client = client;
6857
+ params.onClientChange?.(client);
6858
+ } finally {
6859
+ scopeActive = false;
4063
6860
  }
4064
- const replacementOptions = requestOptions();
4065
- client = await getLeasedSharedCodexAppServerClient({
4066
- ...params.options,
4067
- timeoutMs: replacementOptions.timeoutMs,
4068
- ...signal ? { abandonSignal: signal } : {}
4069
- });
4070
- params.lease.client = client;
4071
- params.onClientChange(client);
4072
6861
  }
4073
6862
  throw new Error("Codex app-server selection retry loop exited unexpectedly");
4074
6863
  }
@@ -4077,24 +6866,6 @@ async function acquireSharedCodexAppServerClient(options, leaseOptions) {
4077
6866
  const acquireStartedAt = Date.now();
4078
6867
  const timeoutMs = options?.timeoutMs ?? 0;
4079
6868
  const state = getSharedCodexAppServerClientState();
4080
- const warmIdentity = resolveWarmSharedCodexAppServerClientIdentity(options);
4081
- let warmClient = warmIdentity ? readWarmSharedCodexAppServerClient(state, warmIdentity) : void 0;
4082
- const warmGeneration = warmClient ? getCodexAppServerClientStartMetadata().get(warmClient.client)?.desktopGeneration : void 0;
4083
- if (warmClient && warmGeneration && !isCodexDesktopGenerationCurrent(warmGeneration)) {
4084
- await withCodexAppServerAcquireDeadline(resolveRemainingAcquireTimeout(timeoutMs, acquireStartedAt), waitForCodexDesktopGeneration(), options?.abandonSignal);
4085
- if (!isCodexDesktopGenerationCurrent(warmGeneration)) {
4086
- retireSharedCodexAppServerClientIfCurrent(warmClient.client);
4087
- warmClient = void 0;
4088
- }
4089
- }
4090
- if (warmClient) {
4091
- options?.onStartedClient?.(warmClient.client);
4092
- const release = leaseOptions?.leased ? retainSharedClientEntry(warmClient.entry) : void 0;
4093
- return release ? {
4094
- client: warmClient.client,
4095
- release
4096
- } : { client: warmClient.client };
4097
- }
4098
6869
  const { agentDir, usesNativeAuth, authProfileId, authProfileStore, preparedAuth, authRequirement, requestedStartOptions, startOptions, desktopGeneration, pluginConfig } = await withCodexAppServerAcquireDeadline(timeoutMs, resolveCodexAppServerClientStartContext(options), options?.abandonSignal);
4099
6870
  const remainingTimeoutMs = resolveRemainingAcquireTimeout(timeoutMs, acquireStartedAt);
4100
6871
  const authIdentityCacheKey = preparedAuth?.kind === "api-key" ? resolveCodexAppServerPreparedApiKeyCacheKey(preparedAuth.apiKey) : preparedAuth?.snapshot.secretFreeCacheKey ?? (authRequirement === "api-key" && !authProfileId ? resolveCodexAppServerFallbackApiKeyCacheKey({ startOptions }) : void 0);
@@ -4166,11 +6937,6 @@ async function acquireSharedCodexAppServerClient(options, leaseOptions) {
4166
6937
  config: options?.config
4167
6938
  });
4168
6939
  const release = leaseOptions?.leased ? retainSharedClientEntry(entry) : void 0;
4169
- if (warmIdentity) rememberWarmSharedCodexAppServerClient(state, warmIdentity, {
4170
- key,
4171
- entry,
4172
- client
4173
- });
4174
6940
  return release ? {
4175
6941
  client,
4176
6942
  release
@@ -4328,11 +7094,10 @@ async function startInitializedCodexAppServerClient(params) {
4328
7094
  } finally {
4329
7095
  artifactDrain?.cancel();
4330
7096
  }
4331
- const runtimeArtifactModule = params.runtimeArtifactMode ? await import("./runtime-artifact-BvyT1uyd.js") : void 0;
4332
- const nativeCommandBeforeStart = startOptions.commandSource === "resolved-managed" ? resolveManagedCodexNativeCommand(startOptions.command) : void 0;
7097
+ const runtimeArtifactModule = params.runtimeArtifactMode ? await import("./runtime-artifact-C3jVimFn.js") : void 0;
4333
7098
  const runtimeArtifactBeforeStart = runtimeArtifactModule ? await runtimeArtifactModule.captureCodexAppServerRuntimeArtifactBeforeStart({
4334
7099
  startOptions,
4335
- spawnIdentity: resolveCodexAppServerSpawnIdentity(startOptions, nativeCommandBeforeStart),
7100
+ spawnIdentity: resolveCodexAppServerSpawnIdentity(startOptions),
4336
7101
  signal: params.runtimeArtifactSignal
4337
7102
  }) : void 0;
4338
7103
  if (runtimeArtifactModule && runtimeArtifactBeforeStart && params.expectedRuntimeArtifact && !runtimeArtifactModule.validateCodexAppServerRuntimeArtifactCapture(params.expectedRuntimeArtifact, runtimeArtifactBeforeStart)) {
@@ -4340,7 +7105,17 @@ async function startInitializedCodexAppServerClient(params) {
4340
7105
  throw new Error("Codex app-server runtime artifact does not match verified inference");
4341
7106
  }
4342
7107
  assertDesktopGenerationCurrent();
4343
- const client = CodexAppServerClient.start(startOptions);
7108
+ let starting;
7109
+ let client;
7110
+ try {
7111
+ client = await withCodexAppServerAcquireDeadline(resolveRemainingAcquireTimeout(timeoutMs, acquireStartedAt), starting = CodexAppServerClient.start(startOptions, () => {
7112
+ assertDesktopGenerationCurrent();
7113
+ resolveRemainingAcquireTimeout(timeoutMs, acquireStartedAt);
7114
+ }), params.abandonSignal);
7115
+ } catch (error) {
7116
+ starting?.then((lateClient) => lateClient.close(), () => {});
7117
+ throw error;
7118
+ }
4344
7119
  const nativeCommandAtStart = startOptions.commandSource === "resolved-managed" ? resolveManagedCodexNativeCommand(startOptions.command) : void 0;
4345
7120
  getCodexAppServerClientStartMetadata().set(client, {
4346
7121
  requestedStartOptions: params.requestedStartOptions,
@@ -4369,11 +7144,10 @@ async function startInitializedCodexAppServerClient(params) {
4369
7144
  let runtimeArtifact;
4370
7145
  try {
4371
7146
  if (runtimeArtifactModule && runtimeArtifactBeforeStart) {
4372
- const nativeCommand = startOptions.commandSource === "resolved-managed" ? resolveManagedCodexNativeCommand(startOptions.command) : void 0;
4373
7147
  runtimeArtifact = await runtimeArtifactModule.finalizeCodexAppServerRuntimeArtifact({
4374
7148
  before: runtimeArtifactBeforeStart,
4375
7149
  startOptions,
4376
- spawnIdentity: resolveCodexAppServerSpawnIdentity(startOptions, nativeCommand),
7150
+ spawnIdentity: resolveCodexAppServerSpawnIdentity(startOptions),
4377
7151
  runtimeIdentity: client.getRuntimeIdentity(),
4378
7152
  signal: params.runtimeArtifactSignal
4379
7153
  });
@@ -4388,7 +7162,8 @@ async function startInitializedCodexAppServerClient(params) {
4388
7162
  authProfileId: params.authProfileId ?? void 0,
4389
7163
  authMode: params.preparedAuth?.kind === "api-key" ? "prepared-api-key" : "profile",
4390
7164
  ...params.authProfileStore ? { authProfileStore: params.authProfileStore } : {},
4391
- config: params.config
7165
+ config: params.config,
7166
+ onAuthRefreshFailure: () => retireSharedCodexAppServerClientIfCurrent(client)
4392
7167
  });
4393
7168
  try {
4394
7169
  assertDesktopGenerationCurrent();
@@ -4455,6 +7230,20 @@ function clearSharedCodexAppServerClientIfCurrent(client) {
4455
7230
  }
4456
7231
  return false;
4457
7232
  }
7233
+ /** Captures a revocable observation of the exact shared client and native account/config. */
7234
+ function captureSharedCodexAppServerCatalogLifetime(client) {
7235
+ const isCurrent = captureSharedClientRegistration(client);
7236
+ const revision = client.getModelCatalogRevision();
7237
+ return () => isCurrent() && client.getModelCatalogRevision() === revision;
7238
+ }
7239
+ /** Registration ends on retirement even when sibling leases keep the process alive. */
7240
+ function captureSharedClientRegistration(client) {
7241
+ const state = getSharedCodexAppServerClientState();
7242
+ const entry = state.entriesByClient.get(client);
7243
+ const key = [...state.clients].find(([, candidate]) => candidate === entry)?.[0];
7244
+ const generation = readCodexAppServerClientDesktopGeneration(client);
7245
+ return () => key !== void 0 && state.clients.get(key) === entry && entry?.client === client && !entry.closeWhenIdle && !entry.closeError && !client.getCloseError() && (!generation || isCodexDesktopGenerationCurrent(generation));
7246
+ }
4458
7247
  /** Retains the matching shared client and returns a release callback. */
4459
7248
  function retainSharedCodexAppServerClientIfCurrent(client) {
4460
7249
  if (!client) return;
@@ -4474,6 +7263,19 @@ function retainSharedCodexAppServerClientByInstanceId(clientId) {
4474
7263
  };
4475
7264
  }
4476
7265
  }
7266
+ /** Captures physical ownership, independently of unrelated thread and reader leases. */
7267
+ function captureCodexAppServerClientLifetime(client, requiredOwnership) {
7268
+ const state = getSharedCodexAppServerClientState();
7269
+ const start = getCodexAppServerClientStartMetadata().get(client)?.startOptions;
7270
+ if (requiredOwnership === "native-process" && (start?.transport !== "stdio" || isCodexAppServerProxyLaunch(start.args))) throw new AgentHarnessPreflightError("Codex ordinary configuration refresh requires an OpenClaw-managed local stdio process, not an external socket or app-server proxy. No turn was sent; reconnect through managed local stdio before continuing.");
7271
+ const isCurrent = requiredOwnership === "native-process" && state.isolatedClients.has(client) ? () => state.isolatedClients.has(client) && !client.getCloseError() : captureSharedClientRegistration(client);
7272
+ const assertCurrent = () => {
7273
+ if (!isCurrent()) throw new CodexAdoptedThreadActiveError("Codex app-server connection changed during thread preparation; reconnect before continuing");
7274
+ assertCodexAppServerClientStartSelectionCurrent({ client });
7275
+ };
7276
+ assertCurrent();
7277
+ return assertCurrent;
7278
+ }
4477
7279
  /**
4478
7280
  * Retires a matching shared client. Default is graceful: detach from the map
4479
7281
  * (future acquisitions get a fresh client) and close once leases drain.
@@ -4589,7 +7391,6 @@ async function clearSharedCodexAppServerClientAndWait(options) {
4589
7391
  const state = getSharedCodexAppServerClientState();
4590
7392
  const clients = collectSharedClients(state);
4591
7393
  state.clients.clear();
4592
- state.warmClientsByConfig = /* @__PURE__ */ new WeakMap();
4593
7394
  await Promise.all(clients.map((client) => client.closeAndWait(options)));
4594
7395
  }
4595
7396
  globalThis[SHARED_CODEX_APP_SERVER_CLIENT_DISPOSER] = clearSharedCodexAppServerClientAndWait;
@@ -4690,4 +7491,4 @@ function collectSharedClients(state) {
4690
7491
  return [...state.liveClients];
4691
7492
  }
4692
7493
  //#endregion
4693
- export { releaseCodexAppServerLiveThread as $, resolveCodexTurnAssistantCompletionIdleTimeoutMs as A, isCodexAppServerPrewriteRequestCancellationError as B, createCodexDesktopGenerationService as C, resolveCodexGatewayTimeoutWithGraceMs as D, isCodexAppServerStartupError as E, isCodexAppServerApprovalRequest as F, CodexAppServerRpcError as G, isUnsupportedCodexAppServerVersionError as H, isCodexAppServerBrokenPipeError as I, consumeCodexAppServerLiveThread as J, createCodexElicitationResponse as K, isCodexAppServerConnectionClosedError as L, resolveCodexTurnTerminalIdleTimeoutMs as M, withCodexStartupTimeout as N, resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs as O, getCodexAppServerClientInstanceId as P, protectCodexAppServerLiveThread as Q, isCodexAppServerIndeterminateRequestCancellationError as R, acquireCodexNativeConfigFence as S, resolveCodexAppServerLocalHomeDir as St, CodexAppServerStartupError as T, resolveCodexAppServerClientInstanceId as U, isCodexAppServerRequestTimeoutError as V, closeCodexAppServerTransportAndWait as W, isCodexAppServerClientRuntimeLive as X, ensureCodexAppServerClientRuntime as Y, isCodexAppServerLiveThreadClaimed as Z, retireSharedCodexAppServerClientIfCurrent as _, flattenCodexDynamicToolFunctions as _t, createIsolatedCodexAppServerClient as a, readRecentCodexRateLimits as at, waitForCodexAppServerClientDesktopGenerationDrain as b, assertNotSymlink as bt, isCodexAppServerStartSelectionChangedError as c, resolveCodexAppServerAuthAccountCacheKey as ct, readCodexAppServerClientProcessIdentity as d, resolveCodexAppServerFallbackApiKeyCacheKey as dt, retainCodexAppServerLiveThread as et, releaseCodexAppServerClientLease as f, resolveCodexAppServerPreparedApiKeyCacheKey as ft, retainSharedCodexAppServerClientIfCurrent as g, CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE as gt, retainSharedCodexAppServerClientByInstanceId as h, CODEX_INTERACTIVE_THREAD_SOURCE_KINDS as ht, clearSharedCodexAppServerClientIfCurrentAndWait as i, readCodexRateLimitsRevision as it, resolveCodexTurnCompletionIdleTimeoutMs as j, resolveCodexStartupTimeoutMs as k, readCodexAppServerClientDesktopGeneration as l, resolveCodexAppServerAuthProfileId as lt, resolveCodexNativeConfigFenceKey as m, CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES as mt, clearSharedCodexAppServerClientIfCurrent as n, withAbortableTimeout as nt, getLeasedSharedCodexAppServerClient as o, rememberCodexRateLimitsRead as ot, releaseLeasedSharedCodexAppServerClient as p, resolveCodexAppServerPreparedAuthHandoff as pt, claimCodexAppServerLiveThread as q, clearSharedCodexAppServerClientIfCurrentAndUnclaimed as r, withTimeout$1 as rt, getSharedCodexAppServerClient as s, reconcileCodexComputerUseStartArtifacts as st, assertCodexAppServerClientStartSelectionCurrent as t, unsubscribeCodexAppServerLiveThread as tt, readCodexAppServerClientDesktopGenerationFingerprint as u, resolveCodexAppServerAuthProfileIdForAgent as ut, retireSharedCodexAppServerClientsBeforeDesktopGeneration as v, isJsonObject as vt, CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS as w, withLeasedCodexAppServerClientStartSelectionRetry as x, resolveCodexAppServerHomeDir as xt, shared_client_exports as y, resolveCodexManagedBundledMarketplacePath as yt, isCodexAppServerIndeterminateTransportError as z };
7494
+ export { assertCodexThreadResumeResponse as $, isJsonObject as $t, TURN_FINALIZE_DRAIN_ABORT_GRACE_MS as A, retainCodexAppServerLiveThread as At, isCodexAppServerIndeterminateRequestCancellationError as B, resolveCodexAppServerAuthProfileIdForAgent as Bt, withLeasedCodexAppServerClientStartSelectionRetry as C, ensureCodexAppServerClientRuntime as Ct, acquireCodexNativeConfigFence as D, protectCodexAppServerLiveThread as Dt, CodexThreadStartRequestError as E, isCodexAppServerLiveThreadClaimed as Et, withCodexStartupTimeout as F, readRecentCodexRateLimits as Ft, isUnsupportedCodexAppServerVersionError as G, resolveCodexManagedBundledMarketplacePath as Gt, isCodexAppServerOverloadError as H, resolveCodexAppServerFallbackApiKeyCacheKey as Ht, getCodexAppServerClientInstanceId as I, rememberCodexRateLimitsRead as It, CodexThreadDirectInputError as J, readCodexSessionMeta as Jt, resolveCodexAppServerClientInstanceId as K, assertNotSymlink as Kt, isCodexAppServerApprovalRequest as L, reconcileCodexComputerUseStartArtifacts as Lt, isCodexAppServerStartupError as M, withAbortableTimeout as Mt, resolveCodexGatewayTimeoutWithGraceMs as N, withTimeout$1 as Nt, createCodexDesktopGenerationService as O, readCodexClientSessionMeta as Ot, resolveCodexStartupTimeoutMs as P, readCodexRateLimitsRevision as Pt, assertCodexThreadForkResponse as Q, flattenCodexDynamicToolFunctions as Qt, isCodexAppServerBrokenPipeError as R, resolveCodexAppServerAuthAccountCacheKey as Rt, waitForCodexAppServerClientDesktopGenerationDrain as S, consumeCodexAppServerLiveThread as St, CodexThreadBindingConflictError as T, isCodexAppServerClientRuntimeLive as Tt, isCodexAppServerPrewriteRequestCancellationError as U, resolveCodexAppServerPreparedApiKeyCacheKey as Ut, isCodexAppServerIndeterminateTransportError as V, resolveCodexAppServerAuthProfileStore as Vt, isCodexAppServerRequestTimeoutError as W, resolveCodexAppServerPreparedAuthHandoff as Wt, assertCodexThreadAcceptsDirectInput as X, CODEX_INTERACTIVE_THREAD_SOURCE_KINDS as Xt, assertCodexModelListResponse as Y, CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES as Yt, assertCodexThreadForkParams as Z, CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE as Zt, retainSharedCodexAppServerClientByInstanceId as _, resolveCodexToolAbortTerminalReason as _t, clearSharedCodexAppServerClientIfCurrentAndUnclaimed as a, readCodexTurnCompletedNotification as at, retireSharedCodexAppServerClientsBeforeDesktopGeneration as b, withDynamicToolTranscriptDetails as bt, getLeasedSharedCodexAppServerClient as c, hasPendingDynamicToolTerminalDiagnostic as ct, readCodexAppServerClientDesktopGeneration as d, resolveDynamicToolCallTimeoutMs as dt, assertCodexThreadStartResponse as et, readCodexAppServerClientDesktopGenerationFingerprint as f, resolveTerminalDynamicToolBatchAction as ft, resolveCodexNativeConfigFenceKey as g, toCodexDynamicToolProtocolResponse as gt, releaseLeasedSharedCodexAppServerClient as h, toCodexDynamicToolProgressResponse as ht, clearSharedCodexAppServerClientIfCurrent as i, readCodexTurn as it, TURN_TERMINAL_SETTLEMENT_TIMEOUT_MS as j, unsubscribeCodexAppServerLiveThread as jt, CodexAppServerStartupError as k, releaseCodexAppServerLiveThread as kt, getSharedCodexAppServerClient as l, isDynamicToolTerminalDiagnosticEvent as lt, releaseCodexAppServerClientLease as m, shouldReleaseTurnAfterTerminalDynamicTool as mt, captureCodexAppServerClientLifetime as n, readCodexDynamicToolCallParams as nt, clearSharedCodexAppServerClientIfCurrentAndWait as o, createCodexElicitationResponse as ot, readCodexAppServerClientProcessIdentity as p, shouldBlockTerminalReleaseForNonTerminalDynamicToolResult as pt, CodexAppServerRpcError as q, isOpenClawManagedCodexThread as qt, captureSharedCodexAppServerCatalogLifetime as r, readCodexErrorNotification as rt, createIsolatedCodexAppServerClient as s, handleDynamicToolCallWithTimeout as st, assertCodexAppServerClientStartSelectionCurrent as t, assertCodexTurnStartResponse as tt, isCodexAppServerStartSelectionChangedError as u, isMatchingDynamicToolTerminalDiagnostic as ut, retainSharedCodexAppServerClientIfCurrent as v, createFailedDynamicToolResponse as vt, CodexAdoptedThreadActiveError as w, hasCodexAppServerLiveThread as wt, shared_client_exports as x, claimCodexAppServerLiveThread as xt, retireSharedCodexAppServerClientIfCurrent as y, withDynamicToolExecutionState as yt, isCodexAppServerConnectionClosedError as z, resolveCodexAppServerAuthProfileId as zt };