@openclaw/codex 2026.8.1-beta.3 → 2026.8.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 (64) hide show
  1. package/dist/api.js +4 -5
  2. package/dist/{attempt-client-cleanup-URjUlCHg.js → attempt-client-cleanup-CVPvp9dL.js} +47 -5
  3. package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
  4. package/dist/{binding-connection-DAvZwp96.js → binding-connection-CCQFs8lf.js} +2 -2
  5. package/dist/{bounded-turn-4BjrZEwW.js → bounded-turn-rq5tiSXk.js} +13 -18
  6. package/dist/{capabilities-CH3K57v4.js → capabilities-CGm_94eL.js} +1 -1
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-D0nZ3qtd.js → command-formatters-C54Yg3eA.js} +2 -2
  9. package/dist/{command-handlers-DC86lgT4.js → command-handlers-BvOAHTrA.js} +89 -62
  10. package/dist/{compact-COqgBRny.js → compact-Hd7SAc0N.js} +8 -9
  11. package/dist/{config-CpNeo5AE.js → config-Cxw3Cl3k.js} +346 -286
  12. package/dist/doctor-contract-api.js +115 -14
  13. package/dist/{dynamic-tools-fJZhl4CE.js → dynamic-tools-BFoUcRdx.js} +147 -903
  14. package/dist/{effective-mcp-catalog-4YKn51aG.js → effective-mcp-catalog-BTJHnDSx.js} +2 -2
  15. package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
  16. package/dist/{event-projector-usage-CLwNEJqW.js → event-projector-usage-D3PHFFXh.js} +3 -3
  17. package/dist/{harness-DoKQcF8n.js → harness-DVfUQBlQ.js} +42 -52
  18. package/dist/harness.js +1 -1
  19. package/dist/index.js +278 -295
  20. package/dist/{isolated-completion-DPMtlH9r.js → isolated-completion-Cbbx_5Ed.js} +4 -4
  21. package/dist/launch-args-sXOAg0SX.js +84 -0
  22. package/dist/{managed-binary-By4FZC6i.js → managed-binary-ZkGodW19.js} +43 -7
  23. package/dist/media-understanding-provider.js +1 -1
  24. package/dist/model-catalog-o6Cgjoss.js +101 -0
  25. package/dist/{models-CZw1wClT.js → models-DgFWSuxA.js} +25 -28
  26. package/dist/{native-subagent-monitor-GGq3RnOo.js → native-subagent-monitor-CwFyoylz.js} +207 -30
  27. package/dist/{node-exec-server.runtime-Bsu1LdFZ.js → node-exec-server.runtime-DXrqpw1c.js} +8 -5
  28. package/dist/{plugin-approval-roundtrip-C75Yiiwc.js → plugin-approval-roundtrip-D80UZiJ_.js} +1 -1
  29. package/dist/{plugin-marketplace-discovery-CSWDkMrP.js → plugin-marketplace-discovery-mdmScYOj.js} +30 -39
  30. package/dist/{plugin-metadata-cache-BXH5NF-4.js → plugin-metadata-cache-CulOABwu.js} +162 -135
  31. package/dist/{protocol-validators-VAVyEnDp.js → protocol-validators-Bg5rpNxk.js} +148 -5
  32. package/dist/{rate-limits-BI1dMHDG.js → rate-limits-hFtzt2Up.js} +1 -1
  33. package/dist/{sandbox-guard-C1qEeZ5C.js → request-CCm4LaED.js} +183 -2
  34. package/dist/{run-attempt-BV3HzuCf.js → run-attempt-BwNQDH2u.js} +599 -361
  35. package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-DeBvleJw.js} +1 -1
  36. package/dist/{session-binding-BTrLf9Qm.js → session-binding-q2WSTVmC.js} +195 -122
  37. package/dist/{session-catalog-ezP_UcRM.js → session-catalog-C2Tae4rI.js} +229 -122
  38. package/dist/session-catalog-home-id-DAKUrm3C.js +112 -0
  39. package/dist/{session-cli-B1hKvfkI.js → session-cli-BuDjm5Ou.js} +1 -1
  40. package/dist/session-permission-policy-gLm40Vtq.js +160 -0
  41. package/dist/session-retirement-CdkI0bvb.js +90 -0
  42. package/dist/{session-upstream-marker-D_2npHlA.js → session-upstream-marker-Bcy33kam.js} +2 -3
  43. package/dist/{settled-turn-finalizer-Dx1onIqg.js → settled-turn-finalizer-B8JJcxCi.js} +7 -6
  44. package/dist/{shared-client-Dw-rzii0.js → shared-client-kNkljY-R.js} +1720 -786
  45. package/dist/{side-question-DbXkJZzg.js → side-question-GwD73tX6.js} +69 -39
  46. package/dist/{thread-lifecycle-DKdrnTMX.js → thread-lifecycle-Ss-uwnC4.js} +852 -359
  47. package/dist/{thread-ownership-i2NBwDUL.js → thread-ownership-CeYBqg_4.js} +18 -8
  48. package/dist/{plugin-app-cache-key-DMNQ8Zi8.js → thread-resume-DF54hagX.js} +52 -6
  49. package/dist/{transcript-mirror-BU0_LKAL.js → transcript-mirror-CkEQIna-.js} +112 -13
  50. package/dist/transport-stdio-C7-s9TLG.js +708 -0
  51. package/dist/{upstream-session-fork-BDVJCLAD.js → upstream-session-fork-BACGlOFa.js} +78 -86
  52. package/dist/{usage-9dKJCgcy.js → usage-C2l8Mils.js} +3 -3
  53. package/dist/{web-search-provider.runtime-DCdx4DGu.js → web-search-provider.runtime-B2XgRdFv.js} +3 -3
  54. package/openclaw.plugin.json +19 -1
  55. package/package.json +8 -8
  56. package/dist/app-server-policy-bg5QPSVP.js +0 -25
  57. package/dist/command-rpc-xUIIonsO.js +0 -90
  58. package/dist/incognito-session-ET_ufDH-.js +0 -2
  59. package/dist/model-catalog-CmGoqVKB.js +0 -48
  60. package/dist/request-DSK0W6YI.js +0 -157
  61. package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
  62. package/dist/session-retirement-CE4iMiLh.js +0 -36
  63. package/dist/thread-resume-CdJk2Ehf.js +0 -30
  64. package/dist/transport-stdio-DhoGy33Z.js +0 -99
@@ -1,33 +1,38 @@
1
- import { _ as CODEX_PLUGINS_MARKETPLACE_NAME, g as resolveCodexPluginsPolicy, n as codexSandboxPolicyForTurn, v as CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME } from "./config-CpNeo5AE.js";
2
- import { B as CodexAppServerRpcError, M as isCodexAppServerConnectionClosedError, R as resolveCodexAppServerClientInstanceId, U as consumeCodexAppServerLiveThread, d as retainSharedCodexAppServerClientByInstanceId, k as getCodexAppServerClientInstanceId, lt as flattenCodexDynamicToolFunctions, pt as resolveCodexAppServerLocalHomeDir, s as isCodexAppServerStartSelectionChangedError, ut as isJsonObject } from "./shared-client-Dw-rzii0.js";
3
- import { a as hashCodexAppServerBindingFingerprint, c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, i as createCodexSessionGenerationSupersededError, n as assertCodexBindingMayBeReplaced, o as isCodexAppServerNativeAuthProfile, s as normalizeCodexAppServerBindingModelProvider } from "./session-binding-BTrLf9Qm.js";
4
- import { a as closeCodexStartupClientBestEffort, c as isCodexAppServerUnsafeSubscriptionError, d as unsubscribeCodexThreadBestEffort, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-URjUlCHg.js";
5
- import { a as assertCodexThreadStartResponse, r as assertCodexThreadForkResponse } from "./protocol-validators-VAVyEnDp.js";
6
- import { o as defaultCodexAppInventoryCache, s as serializeCodexAppInventoryError, t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-DMNQ8Zi8.js";
7
- import { t as isIncognitoSessionKey } from "./incognito-session-ET_ufDH-.js";
8
- import { n as codexCatalogHomeId } from "./session-catalog-home-id-BNwAJ9D7.js";
9
- import { t as resumeCodexAppServerThread } from "./thread-resume-CdJk2Ehf.js";
10
- import { u as projectBoundedCodexThreadHistory } from "./transcript-mirror-BU0_LKAL.js";
1
+ import { E as resolveCodexPluginsPolicy, F as resolveCodexAppServerLocalHomeDir, M as CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME, P as resolveCodexAppServerHomeDir, f as assertCodexModelBackedReviewerEffectiveConfig, j as CODEX_PLUGINS_MARKETPLACE_NAME, n as codexSandboxPolicyForTurn } from "./config-Cxw3Cl3k.js";
2
+ import { $ as CodexAppServerRpcError, D as CodexThreadStartRequestError, E as CodexThreadBindingConflictError, H as getCodexAppServerClientInstanceId, Ht as isJsonObject, J as isCodexAppServerOverloadError, Q as resolveCodexAppServerClientInstanceId, St as releaseCodexAppServerLiveThread, T as CodexRestrictedToolSurfaceAttestationError, Vt as flattenCodexDynamicToolFunctions, _ as retainSharedCodexAppServerClientByInstanceId, bt as isCodexAppServerLiveThreadClaimed, dt as resolveCodexToolAbortTerminalReason, gt as consumeCodexAppServerLiveThread, n as captureExclusiveSharedCodexAppServerClient, w as CodexAdoptedThreadActiveError, wt as unsubscribeCodexAppServerLiveThread } from "./shared-client-kNkljY-R.js";
3
+ import { a as hashCodexAppServerBindingFingerprint, c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, i as createCodexSessionGenerationSupersededError, n as assertCodexBindingMayBeReplaced, o as isCodexAppServerNativeAuthProfile, s as normalizeCodexAppServerBindingModelProvider } from "./session-binding-q2WSTVmC.js";
4
+ import { a as assertCodexThreadForkResponse, r as assertCodexThreadAcceptsDirectInput, s as assertCodexThreadStartResponse, t as CodexThreadDirectInputError } from "./protocol-validators-Bg5rpNxk.js";
5
+ import { a as closeCodexStartupClientBestEffort, c as isCodexAppServerUnsafeSubscriptionError, f as unsubscribeCodexThreadBestEffort, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-CVPvp9dL.js";
6
+ import { c as serializeCodexAppInventoryError, n as buildCodexAppServerConnectionFingerprint, s as defaultCodexAppInventoryCache, t as resumeCodexAppServerThread } from "./thread-resume-DF54hagX.js";
7
+ import { c as withExclusiveCodexAppServerThread, l as isIncognitoSessionKey } from "./thread-ownership-CeYBqg_4.js";
8
+ import { i as readCodexSessionMeta, n as codexCatalogHomeId } from "./session-catalog-home-id-DAKUrm3C.js";
9
+ import { d as projectBoundedCodexThreadHistory } from "./transcript-mirror-CkEQIna-.js";
11
10
  import { r as sanitizeInlineImageDataUrl, t as invalidInlineImageText } from "./image-payload-sanitizer-CnfoUPCE.js";
12
11
  import { asOptionalRecord, isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
13
12
  import fs from "node:fs/promises";
14
13
  import path from "node:path";
15
- import { SKILL_WORKSHOP_TOOL_NAME, TRANSCRIPT_CREDENTIAL_SAFETY_PROMPT, buildDelegationGuidanceSection, buildHarnessVisibleReplyGuidance, buildSkillWorkshopPromptSection, embeddedAgentLog, formatErrorMessage, isActiveHarnessContextEngine, isHostScopedAgentToolActive, resolveMainSessionDelegationMode } from "openclaw/plugin-sdk/agent-harness-runtime";
14
+ import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
15
+ import { addTimerTimeoutGraceMs, finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
16
+ import { SKILL_WORKSHOP_TOOL_NAME, buildCredentialSafetyPrompt, buildDelegationGuidanceSection, buildHarnessVisibleReplyGuidance, buildSkillWorkshopPromptSection, embeddedAgentLog, formatErrorMessage, isActiveHarnessContextEngine, isHostScopedAgentToolActive, resolveMainSessionDelegationMode } from "openclaw/plugin-sdk/agent-harness-runtime";
16
17
  import * as crypto$1 from "node:crypto";
17
18
  import crypto, { createHash } from "node:crypto";
18
19
  import os from "node:os";
19
- import { resolveAgentDir as resolveAgentDir$1, resolveSessionAgentIds as resolveSessionAgentIds$1 } from "openclaw/plugin-sdk/agent-runtime";
20
+ import { isDeepStrictEqual } from "node:util";
21
+ import { resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
22
+ import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
20
23
  import { z } from "zod";
21
24
  import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
22
25
  import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
26
+ import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
27
+ import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
23
28
  import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
24
29
  import { isPathInside } from "openclaw/plugin-sdk/file-access-runtime";
25
30
  import { resolveRequiredHomeDir, resolveStateDir } from "openclaw/plugin-sdk/state-paths";
26
31
  import { listRegisteredPluginAgentPromptGuidance } from "openclaw/plugin-sdk/plugin-runtime";
27
32
  import { buildHostnameAllowlistPolicyFromSuffixAllowlist } from "openclaw/plugin-sdk/ssrf-policy";
28
- import { buildCodexUserMcpServersThreadConfigPatchForRuntime } from "openclaw/plugin-sdk/codex-mcp-projection";
29
- import { isDiagnosticFlagEnabled } from "openclaw/plugin-sdk/diagnostic-runtime";
30
- import { GPT5_HEARTBEAT_PROMPT_OVERLAY } from "openclaw/plugin-sdk/provider-model-shared";
33
+ import { buildCodexUserMcpServersThreadConfigPatchForRun } from "openclaw/plugin-sdk/codex-mcp-projection";
34
+ import { registerRetainedNativeHookRelayForBundledRuntime } from "openclaw/plugin-sdk/native-hook-relay-runtime";
35
+ import { isDiagnosticFlagEnabled } from "openclaw/plugin-sdk/diagnostic-flags";
31
36
  //#region extensions/codex/src/app-server/plugin-inventory.ts
32
37
  /**
33
38
  * Reads Codex plugin marketplace state and app inventory to decide which
@@ -270,15 +275,39 @@ function resolveOwnedApps(params) {
270
275
  enabled: false,
271
276
  needsAuth: true
272
277
  };
273
- return {
278
+ return Object.assign({
274
279
  id: app.id,
275
280
  name: app.name,
276
281
  accessible: info.isAccessible,
277
282
  enabled: info.isEnabled,
278
283
  needsAuth: !info.isAccessible
279
- };
284
+ }, resolveOwnedAppReadOnlyToolConfigKeys(info));
280
285
  }).toSorted((left, right) => left.id.localeCompare(right.id));
281
286
  }
287
+ /** Returns the config keys that Codex metadata proves belong to read-only tools. */
288
+ function resolveOwnedAppReadOnlyToolConfigKeys(app) {
289
+ const appName = app.name.trim();
290
+ const appNameLower = appName.toLowerCase();
291
+ const tools = app.toolSummaries ?? [];
292
+ const writableToolConfigKeys = new Set(tools.filter((tool) => !tool.isReadOnly).flatMap((tool) => resolveAppToolConfigKeys({
293
+ appName,
294
+ appNameLower,
295
+ tool
296
+ })));
297
+ const keys = tools.filter((tool) => tool.isReadOnly).flatMap((tool) => resolveAppToolConfigKeys({
298
+ appName,
299
+ appNameLower,
300
+ tool
301
+ })).filter((key) => !writableToolConfigKeys.has(key));
302
+ return keys.length > 0 ? { readOnlyToolConfigKeys: Array.from(new Set(keys)).toSorted() } : {};
303
+ }
304
+ function resolveAppToolConfigKeys(params) {
305
+ const keys = [params.tool.name];
306
+ if (params.tool.title) keys.push(params.tool.title);
307
+ if (params.appName) keys.push(`${params.appName}_${params.tool.name}`);
308
+ if (params.appNameLower && params.appNameLower !== params.appName) keys.push(`${params.appNameLower}_${params.tool.name}`);
309
+ return keys;
310
+ }
282
311
  function findPluginSummary(marketplace, pluginName) {
283
312
  const exact = marketplace.plugins.find((plugin) => plugin.id === pluginName || plugin.id === `${pluginName}@${marketplace.name}`);
284
313
  if (exact) return exact;
@@ -457,12 +486,21 @@ function activationFailure(identity, reason, diagnostic, extraDiagnostics = [])
457
486
  }
458
487
  //#endregion
459
488
  //#region extensions/codex/src/app-server/plugin-thread-app-admission.ts
489
+ function resolveCodexPluginThreadAppCacheKey(params) {
490
+ return params.threadId ? `${params.appCacheKey}:thread:${encodeURIComponent(params.threadId)}` : params.appCacheKey;
491
+ }
492
+ function createCodexPluginThreadAppInventoryRequest(params) {
493
+ return async (method, requestParams) => await params.request(method, (method === "app/installed" || method === "app/read") && params.threadId ? {
494
+ ...requestParams,
495
+ threadId: params.threadId
496
+ } : requestParams);
497
+ }
460
498
  async function refreshCodexPluginAppInventory(params, appCache, options = {}) {
461
499
  if (!params.appCacheKey) return;
462
- const request = async (method, requestParams) => await params.request(method, requestParams);
500
+ const request = createCodexPluginThreadAppInventoryRequest(params);
463
501
  try {
464
502
  return await appCache.refreshNow({
465
- key: params.appCacheKey,
503
+ key: resolveCodexPluginThreadAppCacheKey(params),
466
504
  request,
467
505
  nowMs: params.nowMs,
468
506
  forceRefetch: options.forceRefetch,
@@ -499,9 +537,9 @@ function normalizeCodexPluginOwnerName(name) {
499
537
  return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "");
500
538
  }
501
539
  async function readCodexThreadAdmissibleAccountApps(params, appCache) {
502
- const request = async (method, requestParams) => await params.request(method, requestParams);
540
+ const request = createCodexPluginThreadAppInventoryRequest(params);
503
541
  const cachedInventory = appCache.read({
504
- key: params.appCacheKey,
542
+ key: resolveCodexPluginThreadAppCacheKey(params),
505
543
  request,
506
544
  nowMs: params.nowMs,
507
545
  suppressRefresh: true
@@ -527,7 +565,8 @@ function toCodexPluginOwnedAccountApp(app) {
527
565
  name: app.name,
528
566
  accessible: app.isAccessible,
529
567
  enabled: app.isEnabled,
530
- needsAuth: !app.isAccessible
568
+ needsAuth: !app.isAccessible,
569
+ ...resolveOwnedAppReadOnlyToolConfigKeys(app)
531
570
  };
532
571
  }
533
572
  function resolveCodexThreadConfigAppsForRecord(params) {
@@ -616,6 +655,11 @@ function buildCodexPluginThreadConfigTimeoutFallback(params) {
616
655
  /** Builds the Codex apps config patch and policy context for a native thread. */
617
656
  async function buildCodexPluginThreadConfig(params) {
618
657
  const appCache = params.appCache ?? defaultCodexAppInventoryCache;
658
+ const threadAppCacheKey = resolveCodexPluginThreadAppCacheKey(params);
659
+ const threadRequest = (method, requestParams) => params.request(method, (method === "app/installed" || method === "app/read") && params.threadId && isJsonObject(requestParams) ? {
660
+ ...requestParams,
661
+ threadId: params.threadId
662
+ } : requestParams);
619
663
  let inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
620
664
  pluginConfig: params.pluginConfig,
621
665
  appCacheKey: params.appCacheKey
@@ -629,9 +673,9 @@ async function buildCodexPluginThreadConfig(params) {
629
673
  let inventory = policy.pluginPolicies.length > 0 ? await readCodexPluginInventory({
630
674
  pluginConfig: params.pluginConfig,
631
675
  policy,
632
- request: params.request,
676
+ request: threadRequest,
633
677
  appCache,
634
- appCacheKey: params.appCacheKey,
678
+ appCacheKey: threadAppCacheKey,
635
679
  configCwd: params.configCwd,
636
680
  metadataCache: params.metadataCache,
637
681
  nowMs: params.nowMs,
@@ -647,9 +691,9 @@ async function buildCodexPluginThreadConfig(params) {
647
691
  inventory = await readCodexPluginInventory({
648
692
  pluginConfig: params.pluginConfig,
649
693
  policy,
650
- request: params.request,
694
+ request: threadRequest,
651
695
  appCache,
652
- appCacheKey: params.appCacheKey,
696
+ appCacheKey: threadAppCacheKey,
653
697
  configCwd: params.configCwd,
654
698
  metadataCache: params.metadataCache,
655
699
  nowMs: params.nowMs
@@ -665,9 +709,9 @@ async function buildCodexPluginThreadConfig(params) {
665
709
  if (!record.activationRequired) continue;
666
710
  const activation = await ensureCodexPluginActivation({
667
711
  identity: record.policy,
668
- request: params.request,
712
+ request: threadRequest,
669
713
  appCache,
670
- appCacheKey: params.appCacheKey,
714
+ appCacheKey: threadAppCacheKey,
671
715
  configCwd: params.configCwd,
672
716
  metadataCache: params.metadataCache,
673
717
  deferAppInventoryRefresh: true,
@@ -691,9 +735,9 @@ async function buildCodexPluginThreadConfig(params) {
691
735
  inventory = await readCodexPluginInventory({
692
736
  pluginConfig: params.pluginConfig,
693
737
  policy,
694
- request: params.request,
738
+ request: threadRequest,
695
739
  appCache,
696
- appCacheKey: params.appCacheKey,
740
+ appCacheKey: threadAppCacheKey,
697
741
  configCwd: params.configCwd,
698
742
  metadataCache: params.metadataCache,
699
743
  nowMs: params.nowMs
@@ -712,9 +756,9 @@ async function buildCodexPluginThreadConfig(params) {
712
756
  inventory = await readCodexPluginInventory({
713
757
  pluginConfig: params.pluginConfig,
714
758
  policy,
715
- request: params.request,
759
+ request: threadRequest,
716
760
  appCache,
717
- appCacheKey: params.appCacheKey,
761
+ appCacheKey: threadAppCacheKey,
718
762
  configCwd: params.configCwd,
719
763
  metadataCache: params.metadataCache,
720
764
  nowMs: params.nowMs
@@ -952,7 +996,7 @@ function readPersistedAppToolApprovalOverrideNames(config, app) {
952
996
  const appConfig = isJsonObject(appsRoot) ? appsRoot[app.id] : void 0;
953
997
  const tools = isJsonObject(appConfig) ? appConfig.tools : void 0;
954
998
  if (!isJsonObject(tools)) return [];
955
- return Object.entries(tools).filter(([, value]) => hasPersistedToolApprovalOverride(value)).map(([toolName]) => toolName).toSorted();
999
+ return Object.entries(tools).filter(([toolName]) => !app.readOnlyToolConfigKeys?.includes(toolName)).filter(([, value]) => hasPersistedToolApprovalOverride(value)).map(([toolName]) => toolName).toSorted();
956
1000
  }
957
1001
  function hasPersistedToolApprovalOverride(value) {
958
1002
  return isJsonObject(value) && value.approval_mode !== void 0;
@@ -1780,33 +1824,6 @@ function applyCodexNativeSkillIsolation(config, isolation) {
1780
1824
  };
1781
1825
  }
1782
1826
  //#endregion
1783
- //#region extensions/codex/src/app-server/thread-lifecycle-errors.ts
1784
- var CodexThreadStartRequestError = class extends Error {
1785
- constructor(cause) {
1786
- super(`thread/start: ${formatErrorMessage(cause)}`, { cause });
1787
- this.name = "CodexThreadStartRequestError";
1788
- }
1789
- };
1790
- var CodexThreadBindingConflictError = class extends Error {
1791
- constructor(threadId, operation) {
1792
- super(`Codex thread binding changed while ${operation}: ${threadId}`);
1793
- this.name = "CodexThreadBindingConflictError";
1794
- }
1795
- };
1796
- var CodexRestrictedToolSurfaceAttestationError = class extends Error {
1797
- constructor(cause) {
1798
- super("Codex restricted-tool-surface MCP attestation failed", { cause });
1799
- this.name = "CodexRestrictedToolSurfaceAttestationError";
1800
- }
1801
- };
1802
- var CodexThreadBindingConflictAfterCleanupError = class extends CodexThreadBindingConflictError {};
1803
- var CodexAdoptedThreadActiveError = class extends Error {
1804
- constructor() {
1805
- super("Codex session became active in another runner; wait for it to finish before continuing");
1806
- this.name = "CodexAdoptedThreadActiveError";
1807
- }
1808
- };
1809
- //#endregion
1810
1827
  //#region extensions/codex/src/app-server/managed-thread-store.ts
1811
1828
  const CODEX_MANAGED_THREAD_NAMESPACE = "app-server-managed-threads";
1812
1829
  const CODEX_MANAGED_THREAD_MAX_ENTRIES = 2e4;
@@ -1981,11 +1998,6 @@ const LEGACY_PRO_REASONING_EFFORTS = [
1981
1998
  ];
1982
1999
  const LEGACY_PRO_MODEL_ID_RE = /^gpt-5\.[45]-pro$/u;
1983
2000
  const MODERN_GPT_5_MODEL_ID_RE = /^gpt-5\.(?:[3-9]|[1-9]\d)(?:$|-)/u;
1984
- function normalizeCodexReasoningEfforts(efforts) {
1985
- if (!efforts) return [];
1986
- const supported = new Set(efforts.map((effort) => effort.trim().toLowerCase()));
1987
- return CODEX_REASONING_EFFORTS.filter((effort) => supported.has(effort));
1988
- }
1989
2001
  /** Read reasoning metadata after the Codex app-server route has been selected. */
1990
2002
  function readCodexSupportedReasoningEfforts(compat) {
1991
2003
  if (!compat || typeof compat !== "object" || Array.isArray(compat)) return;
@@ -1994,7 +2006,8 @@ function readCodexSupportedReasoningEfforts(compat) {
1994
2006
  return efforts.filter((effort) => typeof effort === "string");
1995
2007
  }
1996
2008
  function resolveSupportedReasoningEffort(params) {
1997
- const supported = normalizeCodexReasoningEfforts(params.supportedReasoningEfforts);
2009
+ const declared = new Set(params.supportedReasoningEfforts.map((effort) => effort.trim().toLowerCase()));
2010
+ const supported = CODEX_REASONING_EFFORTS.filter((effort) => declared.has(effort));
1998
2011
  if (supported.includes(params.requested)) return params.requested;
1999
2012
  const fallbackEfforts = params.requested === "ultra" ? supported : supported.filter((effort) => effort !== "ultra");
2000
2013
  const requestedRank = CODEX_REASONING_EFFORTS.indexOf(params.requested);
@@ -2002,7 +2015,8 @@ function resolveSupportedReasoningEffort(params) {
2002
2015
  }
2003
2016
  /** Resolve a turn effort from the selected model's provider-owned metadata. */
2004
2017
  function resolveCodexAppServerReasoningEffort(params) {
2005
- if (params.thinkLevel === "off" || params.thinkLevel === "adaptive") return null;
2018
+ if (params.thinkLevel === "off") return params.supportedReasoningEfforts?.includes("none") ? "none" : null;
2019
+ if (params.thinkLevel === "adaptive") return null;
2006
2020
  if (params.supportedReasoningEfforts) return resolveSupportedReasoningEffort({
2007
2021
  requested: params.thinkLevel,
2008
2022
  supportedReasoningEfforts: params.supportedReasoningEfforts
@@ -2102,6 +2116,7 @@ function buildCodexProjectDocThreadConfig(config) {
2102
2116
  //#region extensions/codex/src/app-server/thread-prompt.ts
2103
2117
  function buildDeveloperInstructions(params, options = {}) {
2104
2118
  const deferredToolNames = /* @__PURE__ */ new Set();
2119
+ let secretsToolName;
2105
2120
  let hasSkillWorkshop = false;
2106
2121
  let hasSessionsSpawn = false;
2107
2122
  let hasSessionsYield = false;
@@ -2115,6 +2130,7 @@ function buildDeveloperInstructions(params, options = {}) {
2115
2130
  for (const tool of spec.type === "namespace" ? spec.tools : [spec]) {
2116
2131
  const name = tool.name.trim();
2117
2132
  if (tool.deferLoading === true && name) deferredToolNames.add(name);
2133
+ if (name === "secrets" && params.disableTools !== true) secretsToolName ??= spec.type === "namespace" ? `${spec.name}.${name}` : name;
2118
2134
  hasSkillWorkshop ||= name === SKILL_WORKSHOP_TOOL_NAME;
2119
2135
  hasSessionsSpawn ||= name === "sessions_spawn";
2120
2136
  hasSessionsYield ||= isDirectNamespace && name === "sessions_yield";
@@ -2154,7 +2170,7 @@ function buildDeveloperInstructions(params, options = {}) {
2154
2170
  sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
2155
2171
  messageToolAvailable
2156
2172
  }),
2157
- TRANSCRIPT_CREDENTIAL_SAFETY_PROMPT,
2173
+ buildCredentialSafetyPrompt(secretsToolName),
2158
2174
  nativeCommandGuidance,
2159
2175
  params.extraSystemPrompt
2160
2176
  ].filter((section) => typeof section === "string" && section.trim()).join("\n\n");
@@ -2261,7 +2277,8 @@ function resolveCodexWebSearchPlan(params) {
2261
2277
  const CODEX_CODE_MODE_THREAD_CONFIG = {
2262
2278
  "features.code_mode": true,
2263
2279
  "features.code_mode_only": false,
2264
- "features.apply_patch_streaming_events": true
2280
+ "features.apply_patch_streaming_events": true,
2281
+ suppress_unstable_features_warning: true
2265
2282
  };
2266
2283
  const CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG = { "features.goals": false };
2267
2284
  const CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG = { "tools.update_plan.enabled": false };
@@ -2451,33 +2468,24 @@ function buildCodexRuntimeThreadConfig(config, options = {}) {
2451
2468
  "features.code_mode_only": options.nativeCodeModeOnlyEnabled === true
2452
2469
  };
2453
2470
  if (options.nativeCodeModeEnabled === false) {
2454
- const disabledConfig = mergeCodexThreadConfigs(configured, CODEX_CODE_MODE_DISABLED_THREAD_CONFIG, CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG, CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG) ?? {
2455
- ...CODEX_CODE_MODE_DISABLED_THREAD_CONFIG,
2456
- ...CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG,
2457
- ...CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG
2458
- };
2471
+ const disabledConfig = expectDefined(mergeCodexThreadConfigs(configured, CODEX_CODE_MODE_DISABLED_THREAD_CONFIG, CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG, CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG), "Codex disabled code mode config");
2459
2472
  delete disabledConfig["features.apply_patch_streaming_events"];
2460
2473
  return disabledConfig;
2461
2474
  }
2462
- if (options.nativeCodeModeOnlyEnabled === true) return ensureDirectOnlyToolNamespaces(mergeCodexThreadConfigs(codeModeConfig, configured, CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG, CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG, { "features.code_mode_only": true }) ?? {
2463
- ...codeModeConfig,
2464
- ...CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG,
2465
- ...CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG,
2466
- "features.code_mode_only": true
2467
- }, options.directOnlyToolNamespaces);
2468
- return ensureDirectOnlyToolNamespaces(mergeCodexThreadConfigs(codeModeConfig, configured, CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG, CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG) ?? {
2469
- ...codeModeConfig,
2470
- ...CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG,
2471
- ...CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG
2472
- }, options.directOnlyToolNamespaces);
2475
+ if (options.nativeCodeModeOnlyEnabled === true) return ensureDirectOnlyToolNamespaces(expectDefined(mergeCodexThreadConfigs(codeModeConfig, configured, CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG, CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG, { "features.code_mode_only": true }), "Codex code mode only config"), options.directOnlyToolNamespaces);
2476
+ return ensureDirectOnlyToolNamespaces(expectDefined(mergeCodexThreadConfigs(codeModeConfig, configured, CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG, CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG), "Codex code mode config"), options.directOnlyToolNamespaces);
2473
2477
  }
2474
2478
  function ensureDirectOnlyToolNamespaces(config, requiredNamespaces) {
2475
2479
  if (!requiredNamespaces?.length) return config;
2476
- const configured = config["code_mode.direct_only_tool_namespaces"];
2477
- const namespaces = Array.isArray(configured) ? configured.filter((entry) => typeof entry === "string" && entry.length > 0) : [];
2480
+ const feature = expectDefined(config["features.code_mode"], "Codex code mode config");
2481
+ const configured = isJsonObject(feature) ? feature : { enabled: feature };
2482
+ const namespaces = Array.isArray(configured.direct_only_tool_namespaces) ? configured.direct_only_tool_namespaces.filter((entry) => typeof entry === "string" && entry.length > 0) : [];
2478
2483
  return {
2479
2484
  ...config,
2480
- "code_mode.direct_only_tool_namespaces": [.../* @__PURE__ */ new Set([...namespaces, ...requiredNamespaces])]
2485
+ "features.code_mode": {
2486
+ ...configured,
2487
+ direct_only_tool_namespaces: [.../* @__PURE__ */ new Set([...namespaces, ...requiredNamespaces])]
2488
+ }
2481
2489
  };
2482
2490
  }
2483
2491
  function resolveDirectOnlyToolNamespaces(dynamicTools) {
@@ -2491,10 +2499,6 @@ function buildCodexRuntimeThreadConfigForRun(params, config, options = {}) {
2491
2499
  const configMcpServers = config?.mcp_servers;
2492
2500
  if (restrictedToolSurface && configMcpServers !== void 0 && !isJsonObject(configMcpServers)) throw new Error("Codex restricted tool surface received invalid thread mcp_servers config");
2493
2501
  const restrictedToolSurfaceMcpServerNames = [...options.restrictedToolSurfaceInheritedMcpServerNames ?? [], ...isJsonObject(configMcpServers) ? Object.keys(configMcpServers) : []];
2494
- const restrictedRunConfig = restrictedToolSurface && isJsonObject(configMcpServers) ? {
2495
- ...config,
2496
- mcp_servers: {}
2497
- } : config;
2498
2502
  const webSearchConfig = resolveCodexWebSearchPlan({
2499
2503
  config: params.config,
2500
2504
  disableTools: params.disableTools,
@@ -2502,7 +2506,7 @@ function buildCodexRuntimeThreadConfigForRun(params, config, options = {}) {
2502
2506
  nativeProviderWebSearchSupport: options.nativeProviderWebSearchSupport,
2503
2507
  webSearchAllowed: options.webSearchAllowed
2504
2508
  }).threadConfig;
2505
- const baseConfig = buildCodexRuntimeThreadConfig(mergeCodexThreadConfigs(restrictedRunConfig, webSearchConfig), options);
2509
+ const baseConfig = buildCodexRuntimeThreadConfig(mergeCodexThreadConfigs(config, webSearchConfig), options);
2506
2510
  return applyCodexManagedShellEnvironment({
2507
2511
  ...mergeCodexThreadConfigs(baseConfig, options.appServer?.networkProxy?.configPatch, params.pluginHarnessToolPolicySafeDeniedTools?.includes("image_generate") ? { "features.image_generation": false } : void 0, shouldDisableCodexToolSearchForModel(params.modelId) ? CODEX_TOOL_SEARCH_UNSUPPORTED_THREAD_CONFIG : void 0, params.delegationCapability === "report_only" ? CODEX_DELEGATION_DISABLED_THREAD_CONFIG : void 0, messageOnlySourceReply || params.pluginHarnessToolPolicyRestricted === true ? buildRestrictedToolConfigPatch(restrictedToolSurfaceMcpServerNames) : buildCodexRingZeroThreadConfigPatch(params, options.hostSystemAgentActive, restrictedToolSurfaceMcpServerNames), restrictedTurnDisablesProjectDocs ? CODEX_NO_PROJECT_DOCS_CONFIG : void 0, params.authoredContextTokenCap === void 0 ? void 0 : { model_context_window: params.authoredContextTokenCap }) ?? baseConfig,
2508
2512
  ...params.bootstrapContextMode === "lightweight" ? CODEX_NO_PROJECT_DOCS_CONFIG : {}
@@ -2613,14 +2617,13 @@ function resolveCodexThreadEnvironmentSelection(options) {
2613
2617
  }
2614
2618
  //#endregion
2615
2619
  //#region extensions/codex/src/app-server/thread-lifecycle-io.ts
2616
- function resolveManagedThreadSourceHomeId(params) {
2617
- const agentId = resolveSessionAgentIds$1({
2620
+ function resolveCodexThreadAgentDir(params) {
2621
+ const agentId = resolveSessionAgentIdsStrict({
2618
2622
  config: params.params.config,
2619
2623
  sessionKey: params.params.sessionKey,
2620
2624
  agentId: params.agentId ?? params.params.agentId
2621
2625
  }).sessionAgentId;
2622
- const agentDir = params.agentDir ?? params.params.agentDir ?? resolveAgentDir$1(params.params.config ?? {}, agentId);
2623
- return codexCatalogHomeId(resolveCodexAppServerLocalHomeDir(params.appServer.start, agentDir));
2626
+ return params.agentDir ?? params.params.agentDir ?? resolveAgentDir$1(params.params.config ?? {}, agentId);
2624
2627
  }
2625
2628
  function resolveCodexThreadRolloutPath(thread) {
2626
2629
  const rolloutPath = thread.path?.trim();
@@ -2630,6 +2633,8 @@ function resolveCodexThreadRolloutPath(thread) {
2630
2633
  async function resumeExistingCodexThread(params, context) {
2631
2634
  const { binding: resumeBinding, bindingIdentity, startModelSelection, startModelProvider, userMcpServersConfigPatch, dynamicToolsFingerprint, dynamicToolsContainDeferred, webSearchThreadConfigFingerprint, nativeSkillIsolationFingerprint, userMcpServersFingerprint, ringZeroConfigFingerprint, ringZeroClientInstanceId, networkProxyConfigFingerprint, contextEngineBinding, environmentSelectionFingerprint, hostSystemAgentActive, ringZeroActive, restrictedToolSurface, restrictedToolSurfaceInheritedMcpServerNames, nativeSkillIsolation, lifecycleTiming, normalizeBindingModelProvider, throwIfAborted, clearCurrentBinding } = context;
2632
2635
  let resumeReservation;
2636
+ let resumeResponseAccepted = false;
2637
+ const abandonClient = params.abandonClient ?? (() => closeCodexStartupClientBestEffort(params.client));
2633
2638
  try {
2634
2639
  const authProfileId = resumeBinding.connectionScope === "supervision" ? void 0 : params.params.authProfileId ?? resumeBinding.authProfileId;
2635
2640
  const finalConfigPatch = context.prebuiltFinalConfigPatch ?? params.buildFinalConfigPatch?.({
@@ -2663,25 +2668,29 @@ async function resumeExistingCodexThread(params, context) {
2663
2668
  }));
2664
2669
  const requestModelProvider = typeof resumeParams.modelProvider === "string" && resumeParams.modelProvider.trim() ? resumeParams.modelProvider : void 0;
2665
2670
  throwIfAborted();
2666
- if (resumeBinding.preserveNativeModel === true) {
2667
- const current = await lifecycleTiming.measure("thread-read-adoption-status", () => params.client.request("thread/read", {
2668
- threadId: resumeBinding.threadId,
2669
- includeTurns: false
2670
- }, { signal: params.signal }));
2671
- throwIfAborted();
2672
- if (current.thread.status?.type === "active") throw new CodexAdoptedThreadActiveError();
2673
- }
2674
2671
  resumeReservation = params.reserveResumeThread?.(resumeBinding.threadId);
2675
2672
  const response = await lifecycleTiming.measure("thread-resume-request", () => resumeCodexAppServerThread({
2676
2673
  client: params.client,
2677
- abandonClient: params.abandonClient ?? (() => closeCodexStartupClientBestEffort(params.client)),
2674
+ abandonClient,
2678
2675
  request: resumeParams,
2679
- signal: params.signal
2676
+ signal: params.signal,
2677
+ assertCurrent: context.assertResumeOwnership,
2678
+ isPrewriteOwnershipError: (error) => error instanceof CodexAdoptedThreadActiveError
2680
2679
  }));
2680
+ resumeResponseAccepted = true;
2681
+ assertCodexThreadAcceptsDirectInput(response.thread);
2682
+ context.assertResumeConfiguration?.();
2683
+ if (resumeBinding.pendingResumeConfiguration) await attestCodexPluginThreadApps({
2684
+ client: params.client,
2685
+ threadId: response.thread.id,
2686
+ appIds: context.prebuiltPluginThreadConfig?.provisionalAppIds ?? [],
2687
+ signal: params.signal
2688
+ });
2681
2689
  if (ringZeroActive || isMessageOnlyCodexSourceReply(params.params) || params.params.pluginHarnessToolPolicyRestricted === true) try {
2682
2690
  await lifecycleTiming.measure("restricted-tool-surface-mcp-attestation", () => attestCodexRestrictedToolSurfaceMcpServersDisabled(params.client, response.thread.id, resumeParams.config, params.signal));
2683
2691
  } catch (error) {
2684
- await (params.abandonClient ?? (() => closeCodexStartupClientBestEffort(params.client)))();
2692
+ context.assertResumeOwnership?.();
2693
+ await abandonClient();
2685
2694
  throw new CodexRestrictedToolSurfaceAttestationError(error);
2686
2695
  }
2687
2696
  throwIfAborted();
@@ -2689,6 +2698,7 @@ async function resumeExistingCodexThread(params, context) {
2689
2698
  const nextMcpServersFingerprint = params.mcpServersFingerprintEvaluated === true ? params.mcpServersFingerprint : resumeBinding.mcpServersFingerprint;
2690
2699
  const resumePatch = {
2691
2700
  clientId: resolveCodexAppServerClientInstanceId(params.client),
2701
+ pendingResumeConfiguration: void 0,
2692
2702
  cwd: params.cwd,
2693
2703
  rolloutPath: resolveCodexThreadRolloutPath(response.thread) ?? resumeBinding.rolloutPath,
2694
2704
  authProfileId: boundAuthProfileId,
@@ -2719,7 +2729,7 @@ async function resumeExistingCodexThread(params, context) {
2719
2729
  kind: "patch",
2720
2730
  threadId: resumeBinding.threadId,
2721
2731
  patch: resumePatch
2722
- }))) throw new CodexThreadBindingConflictError(resumeBinding.threadId, "committing a resumed thread");
2732
+ }, context.assertResumeConfiguration))) throw new CodexThreadBindingConflictError(resumeBinding.threadId, "committing a resumed thread");
2723
2733
  if (contextEngineBinding) embeddedAgentLog.info("codex app-server wrote context-engine thread binding", {
2724
2734
  sessionId: params.params.sessionId,
2725
2735
  sessionKey: params.params.sessionKey,
@@ -2756,19 +2766,26 @@ async function resumeExistingCodexThread(params, context) {
2756
2766
  };
2757
2767
  } catch (error) {
2758
2768
  resumeReservation?.release();
2759
- if (isCodexAppServerStartSelectionChangedError(error)) throw error;
2769
+ if (!resumeResponseAccepted && (!(error instanceof CodexAppServerRpcError) || isCodexAppServerOverloadError(error))) throw error;
2760
2770
  if (error instanceof CodexRestrictedToolSurfaceAttestationError) {
2761
- await clearCurrentBinding("retiring a failed restricted-tool-surface attestation");
2771
+ if (!resumeBinding.pendingResumeConfiguration) await clearCurrentBinding("retiring a failed restricted-tool-surface attestation");
2762
2772
  throw error;
2763
2773
  }
2764
- if (error instanceof CodexAdoptedThreadActiveError) throw error;
2765
- if (isCodexAppServerUnsafeSubscriptionError(error)) throw error;
2766
- const resumeRejected = error instanceof CodexAppServerRpcError;
2767
- if (!await unsubscribeCodexThreadBestEffort(params.client, {
2768
- threadId: resumeBinding.threadId,
2769
- timeoutMs: 5e3
2770
- }) && !resumeRejected && !isCodexAppServerConnectionClosedError(error) && !params.signal?.aborted) throw new CodexAppServerUnsafeSubscriptionError("Codex thread/resume subscription cleanup failed", { cause: error });
2771
- if (isCodexAppServerConnectionClosedError(error) || params.signal?.aborted) throw error;
2774
+ if (resumeResponseAccepted) {
2775
+ if (!await unsubscribeCodexThreadBestEffort(params.client, {
2776
+ threadId: resumeBinding.threadId,
2777
+ timeoutMs: 5e3,
2778
+ assertCurrent: context.assertResumeOwnership
2779
+ }).catch(() => false)) {
2780
+ try {
2781
+ await abandonClient();
2782
+ } catch (abandonError) {
2783
+ throw new CodexAppServerUnsafeSubscriptionError("Codex thread/resume client could not be retired", { cause: abandonError });
2784
+ }
2785
+ throw new CodexAppServerUnsafeSubscriptionError("Codex thread/resume subscription cleanup failed", { cause: error });
2786
+ }
2787
+ }
2788
+ if (resumeBinding.pendingResumeConfiguration || error instanceof CodexThreadDirectInputError || params.signal?.aborted) throw error;
2772
2789
  embeddedAgentLog.warn("codex app-server thread resume failed; starting a new thread", { error });
2773
2790
  await clearCurrentBinding("rotating a stale thread binding");
2774
2791
  }
@@ -2899,7 +2916,7 @@ async function startFreshCodexThread(params, context) {
2899
2916
  throw new CodexAppServerUnsafeSubscriptionError("Codex successor cleanup failed after a binding replacement conflict", cause === void 0 ? void 0 : { cause });
2900
2917
  }
2901
2918
  };
2902
- const managedSourceHomeId = resolveManagedThreadSourceHomeId(params);
2919
+ const managedSourceHomeId = codexCatalogHomeId(resolveCodexAppServerLocalHomeDir(params.appServer.start, resolveCodexThreadAgentDir(params)));
2903
2920
  await lifecycleTiming.measure("thread-start-mark-managed", () => markStartedCodexManagedThread(params.bindingStore.managedThreads, {
2904
2921
  sourceHomeId: managedSourceHomeId,
2905
2922
  threadId: response.thread.id,
@@ -2958,6 +2975,603 @@ async function startFreshCodexThread(params, context) {
2958
2975
  });
2959
2976
  }
2960
2977
  //#endregion
2978
+ //#region extensions/codex/src/app-server/thread-lifecycle-warm.ts
2979
+ /** Preserves the caller's abort reason across thread ownership transitions. */
2980
+ function throwIfCodexThreadLifecycleAborted(signal) {
2981
+ if (!signal?.aborted) return;
2982
+ const reason = signal.reason;
2983
+ if (reason instanceof Error) throw reason;
2984
+ const error = new Error(typeof reason === "string" && reason.length > 0 ? reason : "codex app-server thread lifecycle aborted");
2985
+ error.name = "AbortError";
2986
+ throw error;
2987
+ }
2988
+ /** Releases consumed subscription ownership or retires an unsafe client. */
2989
+ async function releaseCodexConsumedLiveThread(options) {
2990
+ if (await options.lifecycleTiming.measure("retained-thread-unsubscribe", () => unsubscribeCodexThreadBestEffort(options.client, {
2991
+ threadId: options.threadId,
2992
+ timeoutMs: 5e3,
2993
+ assertCurrent: options.assertCurrent
2994
+ }))) return;
2995
+ return await abandonCodexLiveThreadRelease(options, options.cause);
2996
+ }
2997
+ async function abandonCodexLiveThreadRelease(options, cause) {
2998
+ options.assertCurrent?.();
2999
+ await (options.abandonClient ?? (() => closeCodexStartupClientBestEffort(options.client)))();
3000
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex retained thread subscription could not be released: ${options.threadId}`, cause !== void 0 ? { cause } : void 0);
3001
+ }
3002
+ /** Releases through the retained owner, preserving its guarded callback and rollback. */
3003
+ async function releaseCodexRetainedLiveThread(options) {
3004
+ try {
3005
+ return await options.lifecycleTiming.measure("retained-thread-unsubscribe", () => releaseCodexAppServerLiveThread(options.client, options.threadId, options.assertCurrent));
3006
+ } catch (error) {
3007
+ if (isCodexAppServerUnsafeSubscriptionError(error)) throw error;
3008
+ return await abandonCodexLiveThreadRelease(options, error);
3009
+ }
3010
+ }
3011
+ /** Reuses one safely owned, fully matching subscription on its original client. */
3012
+ async function tryReuseCodexLiveThread(options) {
3013
+ const { params, binding, bindingIdentity, clientId, dynamicToolsFingerprint, environmentSelectionFingerprint, hostSystemAgentActive, lifecycleTiming, nativeSkillIsolation, releaseConsumedThread, ringZeroActive, restrictedToolSurfaceInheritedMcpServerNames, startModelProvider, startModelSelection, throwIfAborted, userMcpServersConfigPatch } = options;
3014
+ if (!binding.clientId || binding.clientId !== clientId || binding.preserveNativeModel === true || binding.connectionScope === "supervision" || ringZeroActive) return {};
3015
+ const prebuiltFinalConfigPatch = params.buildFinalConfigPatch?.({
3016
+ action: "resume",
3017
+ binding
3018
+ }) ?? {
3019
+ configPatch: params.finalConfigPatch,
3020
+ nativeHookRelayGeneration: params.nativeHookRelayGeneration
3021
+ };
3022
+ const pluginAppsConfigPatch = params.pluginThreadConfig?.enabled && binding.pluginAppPolicyContext ? buildCodexPluginAppsConfigPatchFromPolicyContext(binding.pluginAppPolicyContext) : void 0;
3023
+ const resumeAuthProfileId = params.params.authProfileId ?? binding.authProfileId;
3024
+ const resumeConfig = mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginAppsConfigPatch, prebuiltFinalConfigPatch.configPatch);
3025
+ const resumeParams = lifecycleTiming.measureSync("warm-thread-resume-params", () => buildThreadResumeParams(params.params, {
3026
+ threadId: binding.threadId,
3027
+ cwd: params.cwd,
3028
+ authProfileId: resumeAuthProfileId,
3029
+ model: startModelSelection.model,
3030
+ modelProvider: startModelProvider,
3031
+ preserveNativeModel: false,
3032
+ appServer: params.appServer,
3033
+ dynamicTools: params.dynamicTools,
3034
+ developerInstructions: params.developerInstructions,
3035
+ config: applyCodexNativeSkillIsolation(resumeConfig, nativeSkillIsolation),
3036
+ nativeCodeModeEnabled: params.nativeCodeModeEnabled,
3037
+ nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
3038
+ nativeCodeModeOnlyEnabled: params.nativeCodeModeOnlyEnabled,
3039
+ webSearchAllowed: params.webSearchAllowed,
3040
+ hostSystemAgentActive,
3041
+ restrictedToolSurfaceInheritedMcpServerNames,
3042
+ shellEnvironment: params.shellEnvironment,
3043
+ disableLoginShell: params.disableLoginShell
3044
+ }));
3045
+ const liveThreadConfigFingerprint = fingerprintCodexThreadConfig({
3046
+ ...resumeParams,
3047
+ model: binding.model ?? resumeParams.model ?? null,
3048
+ requestedModel: resumeParams.model ?? null,
3049
+ modelProvider: binding.modelProvider ?? resumeParams.modelProvider ?? null,
3050
+ requestedModelProvider: resumeParams.modelProvider ?? binding.modelProvider ?? null
3051
+ }, resumeAuthProfileId, dynamicToolsFingerprint);
3052
+ const retainedThread = await consumeCodexAppServerLiveThread(params.client, binding.threadId, liveThreadConfigFingerprint);
3053
+ if (!retainedThread) {
3054
+ const incompatibleOwnership = await consumeCodexAppServerLiveThread(params.client, binding.threadId);
3055
+ if (incompatibleOwnership) await incompatibleOwnership.release(binding.threadId);
3056
+ return { prebuiltFinalConfigPatch };
3057
+ }
3058
+ try {
3059
+ const nativeHookRelayGeneration = prebuiltFinalConfigPatch.nativeHookRelayGeneration ?? binding.nativeHookRelayGeneration;
3060
+ const model = startModelSelection.model;
3061
+ if (!await lifecycleTiming.measure("warm-thread-write-binding", () => params.bindingStore.mutate(bindingIdentity, {
3062
+ kind: "patch",
3063
+ threadId: binding.threadId,
3064
+ patch: {
3065
+ cwd: params.cwd,
3066
+ model,
3067
+ nativeHookRelayGeneration,
3068
+ environmentSelectionFingerprint
3069
+ }
3070
+ }))) throw new CodexThreadBindingConflictError(binding.threadId, "committing a reused thread");
3071
+ throwIfAborted();
3072
+ lifecycleTiming.mark("thread-ready");
3073
+ lifecycleTiming.logSummary({
3074
+ runId: params.params.runId,
3075
+ sessionId: params.params.sessionId,
3076
+ sessionKey: params.params.sessionKey,
3077
+ threadId: binding.threadId,
3078
+ action: "resumed"
3079
+ });
3080
+ return {
3081
+ binding: {
3082
+ ...binding,
3083
+ cwd: params.cwd,
3084
+ model,
3085
+ nativeHookRelayGeneration,
3086
+ environmentSelectionFingerprint,
3087
+ liveThreadConfigFingerprint,
3088
+ liveThreadOwnership: retainedThread,
3089
+ ...retainedThread.serviceTier && resumeParams.serviceTier === void 0 ? { clearInheritedServiceTier: true } : {},
3090
+ lifecycle: { action: "resumed" }
3091
+ },
3092
+ prebuiltFinalConfigPatch
3093
+ };
3094
+ } catch (error) {
3095
+ await releaseConsumedThread(binding.threadId, error);
3096
+ throw error;
3097
+ }
3098
+ }
3099
+ //#endregion
3100
+ //#region extensions/codex/src/app-server/thread-lifecycle-adoption.ts
3101
+ /** Passive refusal must precede releasing or acquiring any native subscription. */
3102
+ async function assertAdoptedCodexThreadResumeAllowed(params, threadId, context) {
3103
+ const { thread } = await context.lifecycleTiming.measure("thread-read-adoption-status", () => params.client.request("thread/read", {
3104
+ threadId,
3105
+ includeTurns: false
3106
+ }, { signal: params.signal }));
3107
+ context.throwIfAborted();
3108
+ assertCodexThreadAcceptsDirectInput(thread);
3109
+ if (thread.status?.type === "active") throw new CodexAdoptedThreadActiveError();
3110
+ }
3111
+ /** Preserve attach's native-queue-before-binding-lease order when consuming pending intent. */
3112
+ async function withCodexThreadLifecycleBinding(params, run) {
3113
+ const identity = sessionBindingIdentity({
3114
+ sessionId: params.params.sessionId,
3115
+ sessionKey: params.params.sessionKey,
3116
+ agentId: params.agentId ?? params.params.agentId,
3117
+ config: params.params.config
3118
+ });
3119
+ const snapshot = await params.bindingStore.read(identity);
3120
+ const pendingThreadId = snapshot?.pendingResumeConfiguration ? snapshot.threadId : void 0;
3121
+ const runWithLease = () => params.bindingStore.withLease(identity, async () => {
3122
+ const binding = await params.bindingStore.read(identity);
3123
+ if (pendingThreadId && (binding?.threadId !== pendingThreadId || !binding.pendingResumeConfiguration)) throw new CodexThreadBindingConflictError(pendingThreadId, "acquiring a pending resume configuration");
3124
+ if (!pendingThreadId && binding?.pendingResumeConfiguration) throw new CodexThreadBindingConflictError(binding.threadId, "acquiring a pending resume configuration");
3125
+ return await run(identity, binding);
3126
+ });
3127
+ return pendingThreadId ? await withExclusiveCodexAppServerThread({
3128
+ bindingStore: params.bindingStore,
3129
+ identity,
3130
+ threadId: pendingThreadId,
3131
+ run: runWithLease
3132
+ }) : await runWithLease();
3133
+ }
3134
+ /** Completes manual attachment only under the native queue and exact binding lease. */
3135
+ async function resumePendingCodexThread(params, context) {
3136
+ const { binding, contextEngineBinding, lifecycleTiming, restrictedToolSurface } = context;
3137
+ if (isIncognitoSessionKey(params.params.sessionKey) || context.transientRestriction || !restrictedToolSurface && binding.nativeToolPolicyRestricted === true || (contextEngineBinding ? !isContextEngineBindingCompatible(binding.contextEngine, contextEngineBinding) : binding.contextEngine !== void 0) || shouldRotateCodexGpt56MultiAgentBinding({
3138
+ bindingModel: binding.model,
3139
+ requestedModel: params.params.modelId
3140
+ })) throw new Error(`Cannot configure resumed Codex thread ${binding.threadId} under a transient or incompatible session policy. The thread is preserved; retry from its normal session or use /new for the current policy.`);
3141
+ const prebuiltPluginThreadConfig = params.pluginThreadConfig?.enabled ? await lifecycleTiming.measure("plugin-config-build", () => params.pluginThreadConfig?.build()) : void 0;
3142
+ const clientId = resolveCodexAppServerClientInstanceId(params.client);
3143
+ const configuration = await preparePendingCodexThreadResume(params, binding, context.dynamicToolsFingerprint, async (assertCurrent) => {
3144
+ const released = await context.releaseRetainedThread(binding.threadId, assertCurrent);
3145
+ assertCurrent();
3146
+ if (!released || binding.clientId && binding.clientId !== clientId) await releaseCodexConsumedLiveThread({
3147
+ client: params.client,
3148
+ abandonClient: params.abandonClient,
3149
+ lifecycleTiming,
3150
+ threadId: binding.threadId,
3151
+ assertCurrent
3152
+ });
3153
+ });
3154
+ try {
3155
+ const resumed = await resumeExistingCodexThread(params, {
3156
+ ...context,
3157
+ prebuiltPluginThreadConfig,
3158
+ assertResumeConfiguration: configuration.assertConfigured,
3159
+ assertResumeOwnership: configuration.assertCurrent
3160
+ });
3161
+ if (!resumed) throw new Error(`Codex did not configure resumed thread ${binding.threadId}.`);
3162
+ return resumed;
3163
+ } finally {
3164
+ configuration.dispose();
3165
+ }
3166
+ }
3167
+ /** Manual attachment is intent, never evidence that loaded native overrides took effect. */
3168
+ async function preparePendingCodexThreadResume(params, binding, dynamicToolsFingerprint, releaseSubscription) {
3169
+ const fail = (reason) => /* @__PURE__ */ new Error(`Cannot configure resumed Codex thread ${binding.threadId}: ${reason}. The thread is preserved; continue it in native Codex or use /new for the current OpenClaw tools.`);
3170
+ const agentDir = resolveCodexThreadAgentDir(params);
3171
+ const localHome = resolveCodexAppServerLocalHomeDir(params.appServer.start, agentDir);
3172
+ if (params.appServer.start.transport !== "stdio" || params.appServer.start.homeScope === "user" || path.resolve(localHome) !== resolveCodexAppServerHomeDir(agentDir) || binding.connectionScope === "supervision" || binding.preserveNativeModel === true) throw fail("configuration adoption requires an OpenClaw-owned local Codex home");
3173
+ if (isCodexAppServerLiveThreadClaimed(params.client, binding.threadId)) throw fail("the thread is claimed by active work; stop that run before resuming");
3174
+ const assertCurrent = captureExclusiveSharedCodexAppServerClient(params.client);
3175
+ const { thread } = await params.client.request("thread/read", {
3176
+ threadId: binding.threadId,
3177
+ includeTurns: false
3178
+ }, { signal: params.signal });
3179
+ assertCurrent();
3180
+ const statusType = thread.status?.type;
3181
+ if (thread.id !== binding.threadId || statusType !== "idle" && statusType !== "notLoaded") throw fail("the native thread is not idle; wait for its current run to finish");
3182
+ assertCodexThreadAcceptsDirectInput(thread);
3183
+ let unloaded = statusType === "notLoaded";
3184
+ const dispose = params.client.addNotificationHandler((notification) => {
3185
+ if (notification.method === "thread/status/changed" && isJsonObject(notification.params) && notification.params.threadId === binding.threadId && isJsonObject(notification.params.status) && notification.params.status.type === "notLoaded") unloaded = true;
3186
+ });
3187
+ try {
3188
+ const rolloutPath = thread.path ?? binding.rolloutPath;
3189
+ const metadata = rolloutPath ? await readCodexSessionMeta(path.join(localHome, "sessions"), rolloutPath, binding.threadId) : void 0;
3190
+ if (!metadata) throw fail("its native tool catalog could not be read from the selected Codex home");
3191
+ const recordedTools = metadata.dynamic_tools ?? [];
3192
+ if (!Array.isArray(recordedTools) || codexDynamicToolsFingerprint(recordedTools) !== dynamicToolsFingerprint) throw fail("its immutable native tool catalog does not match the current OpenClaw tools");
3193
+ assertCurrent();
3194
+ await releaseSubscription(assertCurrent);
3195
+ assertCurrent();
3196
+ return {
3197
+ assertConfigured: () => {
3198
+ assertCurrent();
3199
+ if (!unloaded) throw fail("Codex did not confirm unloading its previous configuration");
3200
+ },
3201
+ assertCurrent,
3202
+ dispose
3203
+ };
3204
+ } catch (error) {
3205
+ dispose();
3206
+ throw error;
3207
+ }
3208
+ }
3209
+ //#endregion
3210
+ //#region extensions/codex/src/app-server/native-hook-relay-state.ts
3211
+ const pending = /* @__PURE__ */ new Set();
3212
+ /** Owns delayed hook-relay cleanup across runtime scheduling and test teardown. */
3213
+ const nativeHookRelayUnregisterQueue = {
3214
+ add(entry) {
3215
+ pending.add(entry);
3216
+ },
3217
+ delete(entry) {
3218
+ return pending.delete(entry);
3219
+ },
3220
+ flush() {
3221
+ while (pending.size > 0) {
3222
+ const entry = pending.values().next().value;
3223
+ if (!entry) return;
3224
+ clearTimeout(entry.timeout);
3225
+ entry.unregister();
3226
+ }
3227
+ },
3228
+ clear() {
3229
+ for (const entry of pending) clearTimeout(entry.timeout);
3230
+ pending.clear();
3231
+ }
3232
+ };
3233
+ //#endregion
3234
+ //#region extensions/codex/src/app-server/native-hook-relay.ts
3235
+ /**
3236
+ * Bridges Codex native hook callbacks into OpenClaw's native hook relay so
3237
+ * app-server tool events can still run OpenClaw policy and diagnostics.
3238
+ */
3239
+ /** Codex hook events that can be registered through OpenClaw's native relay. */
3240
+ const CODEX_NATIVE_HOOK_RELAY_EVENTS = [
3241
+ "pre_tool_use",
3242
+ "post_tool_use",
3243
+ "permission_request",
3244
+ "before_agent_finalize"
3245
+ ];
3246
+ const CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS = CODEX_NATIVE_HOOK_RELAY_EVENTS.filter((event) => event !== "permission_request");
3247
+ const CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS = 30 * 6e4;
3248
+ /** Extra relay lifetime after the expected turn budget, preventing late hook drops. */
3249
+ const CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS = 5 * 6e4;
3250
+ const CODEX_NATIVE_HOOK_RELAY_COMMAND_MIN_PARENT_MARGIN_MS = 250;
3251
+ const CODEX_NATIVE_HOOK_RELAY_COMMAND_MAX_PARENT_MARGIN_MS = 1e3;
3252
+ const CODEX_NATIVE_HOOK_RELAY_DEFAULT_TIMEOUT_SEC = 10;
3253
+ const CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS = 1e4;
3254
+ const CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS = 5e3;
3255
+ const MAX_PENDING_DIRECT_CHILD_ADMISSIONS = 32;
3256
+ const nativeHookPolicyByClient = /* @__PURE__ */ new WeakMap();
3257
+ const CODEX_HOOK_MATCHER_NAMES_BY_TOOL_ID = {
3258
+ exec: [
3259
+ "Bash",
3260
+ "exec",
3261
+ "exec_command"
3262
+ ],
3263
+ apply_patch: [
3264
+ "apply_patch",
3265
+ "Write",
3266
+ "Edit"
3267
+ ],
3268
+ spawn_agent: ["spawn_agent", "Agent"]
3269
+ };
3270
+ /** Enterprise managed-only policy silently drops the session-layer hooks that enforce OpenClaw. */
3271
+ async function assertCodexNativeHookRelayAllowed(client, signal) {
3272
+ let attestation = nativeHookPolicyByClient.get(client);
3273
+ if (!attestation) {
3274
+ attestation = client.request("configRequirements/read", void 0, { signal }).then((response) => {
3275
+ if (!isJsonObject(response) || !Object.hasOwn(response, "requirements")) throw new Error("Codex configRequirements/read returned an invalid hook policy response");
3276
+ const requirements = response.requirements;
3277
+ if (requirements === null) return;
3278
+ if (!isJsonObject(requirements)) throw new Error("Codex configRequirements/read returned invalid hook policy requirements");
3279
+ const managedOnly = requirements.allowManagedHooksOnly;
3280
+ if (managedOnly !== void 0 && managedOnly !== null && typeof managedOnly !== "boolean") throw new Error("Codex configRequirements/read returned invalid managed-only hook policy");
3281
+ if (managedOnly === true) throw new Error("Codex managed-only hooks disable the OpenClaw native hook relay; refusing unenforced execution");
3282
+ });
3283
+ nativeHookPolicyByClient.set(client, attestation);
3284
+ attestation.catch(() => {
3285
+ if (nativeHookPolicyByClient.get(client) === attestation) nativeHookPolicyByClient.delete(client);
3286
+ });
3287
+ }
3288
+ await attestation;
3289
+ }
3290
+ /** Defers relay unregister so late native hook subprocesses can still resolve. */
3291
+ function scheduleCodexNativeHookRelayUnregister(params) {
3292
+ let pending;
3293
+ const unregister = () => {
3294
+ if (!pending) return;
3295
+ const current = pending;
3296
+ pending = void 0;
3297
+ if (!nativeHookRelayUnregisterQueue.delete(current)) return;
3298
+ params.relay.unregister();
3299
+ };
3300
+ const timeout = setTimeout(unregister, resolveCodexNativeHookRelayUnregisterGraceMs(params.hookTimeoutSec));
3301
+ pending = {
3302
+ timeout,
3303
+ unregister
3304
+ };
3305
+ nativeHookRelayUnregisterQueue.add(pending);
3306
+ timeout.unref();
3307
+ }
3308
+ /** Computes the delayed unregister window from Codex's hook timeout. */
3309
+ function resolveCodexNativeHookRelayUnregisterGraceMs(hookTimeoutSec) {
3310
+ const hookTimeoutMs = finiteSecondsToTimerSafeMilliseconds(normalizeHookTimeoutSec(hookTimeoutSec)) ?? 0;
3311
+ return Math.max(CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS, addTimerTimeoutGraceMs(hookTimeoutMs, CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS) ?? 0);
3312
+ }
3313
+ /** Records a native pre-tool failure that Codex does not project as a tool item. */
3314
+ function emitCodexNativePreToolUseFailureDiagnostic(params) {
3315
+ emitTrustedDiagnosticEvent({
3316
+ type: "tool.execution.error",
3317
+ ...params.agentId ? { agentId: params.agentId } : {},
3318
+ sessionId: params.sessionId,
3319
+ ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
3320
+ runId: params.runId,
3321
+ toolName: params.failure.toolName,
3322
+ toolCallId: params.failure.toolCallId,
3323
+ durationMs: params.failure.durationMs,
3324
+ errorCategory: "before_tool_call",
3325
+ terminalReason: params.terminalReason ?? (params.signal?.aborted ? resolveCodexToolAbortTerminalReason(params.signal) : params.failure.disposition),
3326
+ ...params.sourceTimestampMs !== void 0 ? { sourceTimestampMs: params.sourceTimestampMs } : {}
3327
+ });
3328
+ }
3329
+ /** Registers an OpenClaw native hook relay for a Codex app-server turn. */
3330
+ function createCodexNativeHookRelay(params) {
3331
+ if (params.options?.enabled === false) return;
3332
+ const directChildClaims = /* @__PURE__ */ new Map();
3333
+ const pendingDirectChildAdmissions = /* @__PURE__ */ new Map();
3334
+ let foregroundClosed = false;
3335
+ let successfulYieldRetentionAuthorized = false;
3336
+ const assertClaim = (threadId, claim) => () => directChildClaims.get(threadId) === claim;
3337
+ const rejectPendingAdmissions = (reason) => {
3338
+ for (const pending of pendingDirectChildAdmissions.values()) pending.reject(new Error(reason));
3339
+ pendingDirectChildAdmissions.clear();
3340
+ };
3341
+ const relay = registerRetainedNativeHookRelayForBundledRuntime({
3342
+ provider: "codex",
3343
+ relayId: buildCodexNativeHookRelayId({
3344
+ agentId: params.agentId,
3345
+ sessionId: params.sessionId,
3346
+ sessionKey: params.sessionKey
3347
+ }),
3348
+ ...params.generation ? { generation: params.generation } : {},
3349
+ ...params.generationMismatchGraceMs ? { generationMismatchGraceMs: params.generationMismatchGraceMs } : {},
3350
+ ...params.agentId ? { agentId: params.agentId } : {},
3351
+ sessionId: params.sessionId,
3352
+ ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
3353
+ ...params.config ? { config: params.config } : {},
3354
+ runId: params.runId,
3355
+ ...params.channelId ? { channelId: params.channelId } : {},
3356
+ ...params.requester ? { requester: params.requester } : {},
3357
+ ...params.approvalContext ? { approvalContext: params.approvalContext } : {},
3358
+ allowedEvents: params.events,
3359
+ preToolUseLoopDetection: params.loopDetectionPreToolUseRelay,
3360
+ ttlMs: resolveCodexNativeHookRelayTtlMs({
3361
+ explicitTtlMs: params.options?.ttlMs,
3362
+ attemptTimeoutMs: params.attemptTimeoutMs,
3363
+ startupTimeoutMs: params.startupTimeoutMs,
3364
+ turnStartTimeoutMs: params.turnStartTimeoutMs
3365
+ }),
3366
+ signal: params.signal,
3367
+ runBeforeToolCall: params.hostCapabilities.runBeforeToolCall,
3368
+ assertActive: params.hostCapabilities.assertActive,
3369
+ retention: {
3370
+ readClaim: readCodexNativeChildThreadId,
3371
+ shouldRetainAfterForegroundClose: () => successfulYieldRetentionAuthorized && directChildClaims.size > 0,
3372
+ allowPreToolUse: (childThreadId) => directChildClaims.has(childThreadId),
3373
+ awaitForegroundAdmission: (childThreadId) => {
3374
+ if (foregroundClosed) return Promise.reject(/* @__PURE__ */ new Error("native hook relay foreground admission unavailable"));
3375
+ const existingClaim = directChildClaims.get(childThreadId);
3376
+ if (existingClaim) return Promise.resolve(assertClaim(childThreadId, existingClaim));
3377
+ const existingPending = pendingDirectChildAdmissions.get(childThreadId);
3378
+ if (existingPending) return existingPending.promise.then((claim) => assertClaim(childThreadId, claim));
3379
+ if (pendingDirectChildAdmissions.size >= MAX_PENDING_DIRECT_CHILD_ADMISSIONS) return Promise.reject(/* @__PURE__ */ new Error("native hook relay foreground admission capacity reached"));
3380
+ const { promise, resolve, reject } = createDeferred();
3381
+ pendingDirectChildAdmissions.set(childThreadId, {
3382
+ promise,
3383
+ resolve,
3384
+ reject
3385
+ });
3386
+ return promise.then((claim) => assertClaim(childThreadId, claim));
3387
+ },
3388
+ onDispose: () => {
3389
+ foregroundClosed = true;
3390
+ rejectPendingAdmissions("native hook relay registration closed");
3391
+ }
3392
+ },
3393
+ onPreToolUseFailure: params.onPreToolUseFailure,
3394
+ command: {
3395
+ nice: 10,
3396
+ timeoutMs: params.options?.gatewayTimeoutMs
3397
+ }
3398
+ });
3399
+ const unregister = () => {
3400
+ foregroundClosed = true;
3401
+ rejectPendingAdmissions("native hook relay foreground closed");
3402
+ relay.unregister();
3403
+ };
3404
+ return {
3405
+ ...relay,
3406
+ unregister,
3407
+ authorizeRetentionAfterSuccessfulYield: () => {
3408
+ successfulYieldRetentionAuthorized = true;
3409
+ },
3410
+ hasClaimedDirectChild: () => directChildClaims.size > 0,
3411
+ rejectPendingDirectChild: (threadIdInput, reason) => {
3412
+ const threadId = threadIdInput.trim();
3413
+ const pending = threadId ? pendingDirectChildAdmissions.get(threadId) : void 0;
3414
+ if (!pending) return;
3415
+ pendingDirectChildAdmissions.delete(threadId);
3416
+ pending.reject(new Error(reason));
3417
+ },
3418
+ claimDirectChild: (threadIdInput) => {
3419
+ const threadId = threadIdInput.trim();
3420
+ if (!threadId) return () => void 0;
3421
+ if (directChildClaims.get(threadId)) return () => void 0;
3422
+ const claim = Symbol(threadId);
3423
+ directChildClaims.set(threadId, claim);
3424
+ const pending = pendingDirectChildAdmissions.get(threadId);
3425
+ pendingDirectChildAdmissions.delete(threadId);
3426
+ pending?.resolve(claim);
3427
+ let released = false;
3428
+ return () => {
3429
+ if (released) return;
3430
+ released = true;
3431
+ if (directChildClaims.get(threadId) !== claim) return;
3432
+ directChildClaims.delete(threadId);
3433
+ if (foregroundClosed && directChildClaims.size === 0) relay.unregister();
3434
+ };
3435
+ }
3436
+ };
3437
+ }
3438
+ function readCodexNativeChildThreadId(rawPayload) {
3439
+ if (!isJsonObject(rawPayload) || typeof rawPayload.agent_id !== "string") return;
3440
+ return rawPayload.agent_id.trim() || void 0;
3441
+ }
3442
+ /** Selects the native hook events Codex should install for the current approval mode. */
3443
+ function resolveCodexNativeHookRelayEvents(params) {
3444
+ if (params.configuredEvents?.length) return params.configuredEvents;
3445
+ return params.appServer.approvalPolicy === "never" ? CODEX_NATIVE_HOOK_RELAY_EVENTS : CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS;
3446
+ }
3447
+ /** Derives the native hook relay TTL from the turn budget unless explicitly configured. */
3448
+ function resolveCodexNativeHookRelayTtlMs(params) {
3449
+ if (params.explicitTtlMs !== void 0) return params.explicitTtlMs;
3450
+ const relayBudgetMs = params.attemptTimeoutMs + params.startupTimeoutMs + params.turnStartTimeoutMs + CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS;
3451
+ return Math.max(CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS, Math.floor(relayBudgetMs));
3452
+ }
3453
+ /** Builds a stable relay id scoped to the agent and session identity. */
3454
+ function buildCodexNativeHookRelayId(params) {
3455
+ const hash = createHash("sha256");
3456
+ hash.update("openclaw:codex:native-hook-relay:v1");
3457
+ hash.update("\0");
3458
+ hash.update(params.agentId?.trim() || "");
3459
+ hash.update("\0");
3460
+ hash.update(params.sessionKey?.trim() || params.sessionId);
3461
+ return `codex-${hash.digest("hex").slice(0, 40)}`;
3462
+ }
3463
+ const CODEX_HOOK_EVENT_BY_NATIVE_EVENT = {
3464
+ pre_tool_use: "PreToolUse",
3465
+ post_tool_use: "PostToolUse",
3466
+ permission_request: "PermissionRequest",
3467
+ before_agent_finalize: "Stop"
3468
+ };
3469
+ const CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT = {
3470
+ pre_tool_use: "pre_tool_use",
3471
+ post_tool_use: "post_tool_use",
3472
+ permission_request: "permission_request",
3473
+ before_agent_finalize: "stop"
3474
+ };
3475
+ const CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS = ["/<session-flags>/config.toml", "<session-flags>/config.toml"];
3476
+ /** Builds the Codex config overlay that installs trusted command hooks for relay events. */
3477
+ function buildCodexNativeHookRelayConfig(params) {
3478
+ const events = params.events?.length ? params.events : CODEX_NATIVE_HOOK_RELAY_EVENTS;
3479
+ const selectedEvents = new Set(events);
3480
+ const config = { "features.hooks": true };
3481
+ const hookState = {};
3482
+ for (const event of CODEX_NATIVE_HOOK_RELAY_EVENTS) {
3483
+ const codexEvent = CODEX_HOOK_EVENT_BY_NATIVE_EVENT[event];
3484
+ const selected = selectedEvents.has(event);
3485
+ const shouldRelay = params.relay.shouldRelayEvent(event);
3486
+ if (!selected || !shouldRelay) {
3487
+ if (selected || params.clearOmittedEvents) config[`hooks.${codexEvent}`] = [];
3488
+ if (params.clearOmittedEvents) for (const sourcePath of CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS) hookState[`${sourcePath}:${CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[event]}:0:0`] = { enabled: false };
3489
+ continue;
3490
+ }
3491
+ const timeout = normalizeHookTimeoutSec(params.hookTimeoutSec);
3492
+ const command = params.relay.commandForEvent(event, { timeoutMs: resolveCodexNativeHookRelayCommandTimeoutMs(timeout) });
3493
+ const matcher = buildCodexNativeToolMatcher(params.relay.toolMatcherForEvent(event));
3494
+ config[`hooks.${codexEvent}`] = [{
3495
+ ...matcher ? { matcher } : {},
3496
+ hooks: [{
3497
+ type: "command",
3498
+ command,
3499
+ timeout,
3500
+ async: false,
3501
+ statusMessage: "OpenClaw native hook relay"
3502
+ }]
3503
+ }];
3504
+ const state = {
3505
+ enabled: true,
3506
+ trusted_hash: codexCommandHookTrustedHash({
3507
+ event,
3508
+ command,
3509
+ matcher,
3510
+ timeout,
3511
+ statusMessage: "OpenClaw native hook relay"
3512
+ })
3513
+ };
3514
+ for (const sourcePath of CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS) hookState[`${sourcePath}:${CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[event]}:0:0`] = state;
3515
+ }
3516
+ config["hooks.state"] = hookState;
3517
+ return config;
3518
+ }
3519
+ /** Builds a Codex config overlay that disables native hooks and clears hook arrays. */
3520
+ function buildCodexNativeHookRelayDisabledConfig() {
3521
+ return {
3522
+ "features.hooks": false,
3523
+ "hooks.PreToolUse": [],
3524
+ "hooks.PostToolUse": [],
3525
+ "hooks.PermissionRequest": [],
3526
+ "hooks.Stop": []
3527
+ };
3528
+ }
3529
+ function normalizeHookTimeoutSec(value) {
3530
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.ceil(value) : CODEX_NATIVE_HOOK_RELAY_DEFAULT_TIMEOUT_SEC;
3531
+ }
3532
+ function resolveCodexNativeHookRelayCommandTimeoutMs(hookTimeoutSec) {
3533
+ const parentTimeoutMs = finiteSecondsToTimerSafeMilliseconds(normalizeHookTimeoutSec(hookTimeoutSec)) ?? 5e3;
3534
+ const parentMarginMs = Math.min(CODEX_NATIVE_HOOK_RELAY_COMMAND_MAX_PARENT_MARGIN_MS, Math.max(CODEX_NATIVE_HOOK_RELAY_COMMAND_MIN_PARENT_MARGIN_MS, Math.floor(parentTimeoutMs / 5)));
3535
+ return Math.max(1, parentTimeoutMs - parentMarginMs);
3536
+ }
3537
+ function buildCodexNativeToolMatcher(toolNames) {
3538
+ if (toolNames === void 0) return;
3539
+ if (toolNames.length === 0) throw new TypeError("Codex native hook matcher requires at least one tool name");
3540
+ const nativeNames = /* @__PURE__ */ new Set();
3541
+ let hasCustomToolName = false;
3542
+ for (const toolName of toolNames) {
3543
+ const canonicalToolName = toolName.trim();
3544
+ if (!canonicalToolName || canonicalToolName === "*") throw new TypeError("Codex native hook matcher requires canonical OpenClaw tool ids");
3545
+ const nativeAliases = CODEX_HOOK_MATCHER_NAMES_BY_TOOL_ID[canonicalToolName];
3546
+ if (!nativeAliases) hasCustomToolName = true;
3547
+ for (const nativeName of nativeAliases ?? [canonicalToolName]) nativeNames.add(nativeName);
3548
+ }
3549
+ const sortedNames = Array.from(nativeNames).toSorted();
3550
+ if (!hasCustomToolName && sortedNames.every((toolName) => /^[A-Za-z0-9_]+$/.test(toolName))) return sortedNames.join("|");
3551
+ return `(?i)^(?:${sortedNames.map((toolName) => toolName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})$`;
3552
+ }
3553
+ function codexCommandHookTrustedHash(params) {
3554
+ const identity = {
3555
+ event_name: CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[params.event],
3556
+ ...params.matcher ? { matcher: params.matcher } : {},
3557
+ hooks: [{
3558
+ async: false,
3559
+ command: params.command,
3560
+ statusMessage: params.statusMessage,
3561
+ timeout: params.timeout,
3562
+ type: "command"
3563
+ }]
3564
+ };
3565
+ return `sha256:${createHash("sha256").update(JSON.stringify(sortJsonValue(identity))).digest("hex")}`;
3566
+ }
3567
+ function sortJsonValue(value) {
3568
+ if (!value || typeof value !== "object") return value;
3569
+ if (Array.isArray(value)) return value.map(sortJsonValue);
3570
+ const sorted = {};
3571
+ for (const [key, entry] of Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right))) sorted[key] = sortJsonValue(entry);
3572
+ return sorted;
3573
+ }
3574
+ //#endregion
2961
3575
  //#region extensions/codex/src/app-server/profiler-flag.ts
2962
3576
  const PROFILER_FLAGS = ["profiler", "codex.profiler"];
2963
3577
  /** Checks the generic and Codex-specific profiler diagnostic flags. */
@@ -3056,6 +3670,13 @@ function createCodexThreadLifecycleTimingTracker(options = {}) {
3056
3670
  //#endregion
3057
3671
  //#region extensions/codex/src/app-server/thread-lifecycle-preflight.ts
3058
3672
  async function prepareCodexThreadLifecyclePreflight(params) {
3673
+ await assertCodexModelBackedReviewerEffectiveConfig({
3674
+ client: params.client,
3675
+ approvalsReviewer: params.appServer.approvalsReviewer,
3676
+ cwd: params.cwd,
3677
+ signal: params.signal
3678
+ });
3679
+ if (params.nativeHookRelayRequired) await assertCodexNativeHookRelayAllowed(params.client, params.signal);
3059
3680
  const lifecycleTiming = createCodexThreadLifecycleTimingTracker({
3060
3681
  ...params.timing,
3061
3682
  enabled: params.timing?.enabled ?? isCodexAppServerProfilerEnabled(params.params.config)
@@ -3072,11 +3693,12 @@ async function prepareCodexThreadLifecyclePreflight(params) {
3072
3693
  })).threadConfig);
3073
3694
  const networkProxyConfigFingerprint = params.appServer.networkProxy?.configFingerprint;
3074
3695
  const contextEngineBinding = lifecycleTiming.measureSync("context-engine-binding", () => buildContextEngineBinding(params.params, params.contextEngineProjection));
3075
- const userMcpServersConfigPatch = params.userMcpServersEnabled === false ? void 0 : await buildCodexUserMcpServersThreadConfigPatchForRuntime(params.params.config, {
3696
+ const userMcpServersConfigPatch = params.userMcpServersEnabled === false ? void 0 : await buildCodexUserMcpServersThreadConfigPatchForRun({
3697
+ run: params.params,
3698
+ cwd: params.cwd,
3076
3699
  agentId: params.agentId ?? params.params.agentId,
3077
- agentDir: params.params.agentDir,
3078
3700
  allowLiteralOAuthProjection: params.appServer.connectionClass !== "remote",
3079
- toolOverrides: params.params.toolOverrides,
3701
+ warn: (message) => embeddedAgentLog.warn(message),
3080
3702
  onServerUnavailable: (serverName, error) => embeddedAgentLog.warn("skipping unavailable MCP OAuth server", {
3081
3703
  serverName,
3082
3704
  error: formatErrorMessage(error)
@@ -3136,118 +3758,6 @@ async function prepareCodexThreadLifecyclePreflight(params) {
3136
3758
  };
3137
3759
  }
3138
3760
  //#endregion
3139
- //#region extensions/codex/src/app-server/thread-lifecycle-warm.ts
3140
- /** Preserves the caller's abort reason across thread ownership transitions. */
3141
- function throwIfCodexThreadLifecycleAborted(signal) {
3142
- if (!signal?.aborted) return;
3143
- const reason = signal.reason;
3144
- if (reason instanceof Error) throw reason;
3145
- const error = new Error(typeof reason === "string" && reason.length > 0 ? reason : "codex app-server thread lifecycle aborted");
3146
- error.name = "AbortError";
3147
- throw error;
3148
- }
3149
- /** Releases consumed subscription ownership or retires an unsafe client. */
3150
- async function releaseCodexConsumedLiveThread(options) {
3151
- if (await options.lifecycleTiming.measure("retained-thread-unsubscribe", () => unsubscribeCodexThreadBestEffort(options.client, {
3152
- threadId: options.threadId,
3153
- timeoutMs: 5e3
3154
- }))) return;
3155
- await (options.abandonClient ?? (() => closeCodexStartupClientBestEffort(options.client)))();
3156
- throw new CodexAppServerUnsafeSubscriptionError(`Codex retained thread subscription could not be released: ${options.threadId}`, options.cause !== void 0 ? { cause: options.cause } : void 0);
3157
- }
3158
- /** Transfers retained-slot ownership before unconditionally releasing it. */
3159
- async function releaseCodexRetainedLiveThread(options) {
3160
- if (await consumeCodexAppServerLiveThread(options.client, options.threadId)) await releaseCodexConsumedLiveThread(options);
3161
- }
3162
- /** Reuses one safely owned, fully matching subscription on its original client. */
3163
- async function tryReuseCodexLiveThread(options) {
3164
- const { params, binding, bindingIdentity, clientId, dynamicToolsFingerprint, environmentSelectionFingerprint, hostSystemAgentActive, lifecycleTiming, nativeSkillIsolation, releaseConsumedThread, ringZeroActive, restrictedToolSurfaceInheritedMcpServerNames, startModelProvider, startModelSelection, throwIfAborted, userMcpServersConfigPatch } = options;
3165
- if (!binding.clientId || binding.clientId !== clientId || binding.preserveNativeModel === true || binding.connectionScope === "supervision" || ringZeroActive) return {};
3166
- const prebuiltFinalConfigPatch = params.buildFinalConfigPatch?.({
3167
- action: "resume",
3168
- binding
3169
- }) ?? {
3170
- configPatch: params.finalConfigPatch,
3171
- nativeHookRelayGeneration: params.nativeHookRelayGeneration
3172
- };
3173
- const pluginAppsConfigPatch = params.pluginThreadConfig?.enabled && binding.pluginAppPolicyContext ? buildCodexPluginAppsConfigPatchFromPolicyContext(binding.pluginAppPolicyContext) : void 0;
3174
- const resumeAuthProfileId = params.params.authProfileId ?? binding.authProfileId;
3175
- const resumeConfig = mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginAppsConfigPatch, prebuiltFinalConfigPatch.configPatch);
3176
- const resumeParams = lifecycleTiming.measureSync("warm-thread-resume-params", () => buildThreadResumeParams(params.params, {
3177
- threadId: binding.threadId,
3178
- cwd: params.cwd,
3179
- authProfileId: resumeAuthProfileId,
3180
- model: startModelSelection.model,
3181
- modelProvider: startModelProvider,
3182
- preserveNativeModel: false,
3183
- appServer: params.appServer,
3184
- dynamicTools: params.dynamicTools,
3185
- developerInstructions: params.developerInstructions,
3186
- config: applyCodexNativeSkillIsolation(resumeConfig, nativeSkillIsolation),
3187
- nativeCodeModeEnabled: params.nativeCodeModeEnabled,
3188
- nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
3189
- nativeCodeModeOnlyEnabled: params.nativeCodeModeOnlyEnabled,
3190
- webSearchAllowed: params.webSearchAllowed,
3191
- hostSystemAgentActive,
3192
- restrictedToolSurfaceInheritedMcpServerNames,
3193
- shellEnvironment: params.shellEnvironment,
3194
- disableLoginShell: params.disableLoginShell
3195
- }));
3196
- const liveThreadConfigFingerprint = fingerprintCodexThreadConfig({
3197
- ...resumeParams,
3198
- model: binding.model ?? resumeParams.model ?? null,
3199
- requestedModel: resumeParams.model ?? null,
3200
- modelProvider: binding.modelProvider ?? resumeParams.modelProvider ?? null,
3201
- requestedModelProvider: resumeParams.modelProvider ?? binding.modelProvider ?? null
3202
- }, resumeAuthProfileId, dynamicToolsFingerprint);
3203
- const retainedThread = await consumeCodexAppServerLiveThread(params.client, binding.threadId, liveThreadConfigFingerprint);
3204
- if (!retainedThread) {
3205
- const incompatibleOwnership = await consumeCodexAppServerLiveThread(params.client, binding.threadId);
3206
- if (incompatibleOwnership) await incompatibleOwnership.release(binding.threadId);
3207
- return { prebuiltFinalConfigPatch };
3208
- }
3209
- try {
3210
- const nativeHookRelayGeneration = prebuiltFinalConfigPatch.nativeHookRelayGeneration ?? binding.nativeHookRelayGeneration;
3211
- const model = startModelSelection.model;
3212
- if (!await lifecycleTiming.measure("warm-thread-write-binding", () => params.bindingStore.mutate(bindingIdentity, {
3213
- kind: "patch",
3214
- threadId: binding.threadId,
3215
- patch: {
3216
- cwd: params.cwd,
3217
- model,
3218
- nativeHookRelayGeneration,
3219
- environmentSelectionFingerprint
3220
- }
3221
- }))) throw new CodexThreadBindingConflictError(binding.threadId, "committing a reused thread");
3222
- throwIfAborted();
3223
- lifecycleTiming.mark("thread-ready");
3224
- lifecycleTiming.logSummary({
3225
- runId: params.params.runId,
3226
- sessionId: params.params.sessionId,
3227
- sessionKey: params.params.sessionKey,
3228
- threadId: binding.threadId,
3229
- action: "resumed"
3230
- });
3231
- return {
3232
- binding: {
3233
- ...binding,
3234
- cwd: params.cwd,
3235
- model,
3236
- nativeHookRelayGeneration,
3237
- environmentSelectionFingerprint,
3238
- liveThreadConfigFingerprint,
3239
- liveThreadOwnership: retainedThread,
3240
- ...retainedThread.serviceTier && resumeParams.serviceTier === void 0 ? { clearInheritedServiceTier: true } : {},
3241
- lifecycle: { action: "resumed" }
3242
- },
3243
- prebuiltFinalConfigPatch
3244
- };
3245
- } catch (error) {
3246
- await releaseConsumedThread(binding.threadId, error);
3247
- throw error;
3248
- }
3249
- }
3250
- //#endregion
3251
3761
  //#region extensions/codex/src/app-server/thread-supervision.ts
3252
3762
  async function materializePendingSupervisionBranch(params) {
3253
3763
  let pending = params.binding.pendingSupervisionBranch;
@@ -3271,6 +3781,32 @@ async function materializePendingSupervisionBranch(params) {
3271
3781
  });
3272
3782
  let bindingCommitted = false;
3273
3783
  let provisionalCleanupSafe = true;
3784
+ let cleanupExpected = pending;
3785
+ const trackPendingSupervisionArtifacts = async (cleanupThreadIds) => {
3786
+ const expected = pending;
3787
+ pending = withPendingSupervisionCleanup(pending, cleanupThreadIds);
3788
+ let updated;
3789
+ try {
3790
+ updated = await params.bindingStore.mutate(params.bindingIdentity, {
3791
+ kind: "patch-pending-supervision-branch",
3792
+ expected,
3793
+ pending
3794
+ });
3795
+ } catch (error) {
3796
+ try {
3797
+ const current = await params.bindingStore.read(params.bindingIdentity);
3798
+ if (matchesPendingSupervisionState(current, pending)) cleanupExpected = pending;
3799
+ else if (matchesPendingSupervisionState(current, expected)) cleanupExpected = expected;
3800
+ else throw new CodexThreadBindingConflictError(pending.sourceThreadId, "verifying supervised Codex cleanup tracking");
3801
+ } catch (verificationError) {
3802
+ provisionalCleanupSafe = false;
3803
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex supervised branch cleanup tracking could not be verified: ${cleanupThreadIds.join(", ")}`, { cause: new AggregateError([error, verificationError], void 0, { cause: error }) });
3804
+ }
3805
+ throw error;
3806
+ }
3807
+ cleanupExpected = updated ? pending : void 0;
3808
+ if (!updated) throw new CodexThreadBindingConflictError(pending.sourceThreadId, "tracking supervised Codex branch cleanup");
3809
+ };
3274
3810
  try {
3275
3811
  const probeParams = buildPendingSupervisionProbeForkParams(params, pending);
3276
3812
  const rawProbeResponse = await params.lifecycleTiming.measure("supervision-model-probe-fork", async () => {
@@ -3286,10 +3822,17 @@ async function materializePendingSupervisionBranch(params) {
3286
3822
  sourceThreadId: pending.sourceThreadId,
3287
3823
  role: "model probe"
3288
3824
  });
3289
- pending = await trackPendingSupervisionArtifacts(params, pending, [probeThreadId]);
3825
+ let probeResponse;
3826
+ try {
3827
+ params.throwIfAborted();
3828
+ probeResponse = assertCodexThreadForkResponse(rawProbeResponse);
3829
+ if (params.restrictedToolSurface) await params.lifecycleTiming.measure("restricted-tool-surface-mcp-attestation", () => attestCodexRestrictedToolSurfaceMcpServersDisabled(params.client, probeThreadId, probeParams.config ?? void 0, params.signal));
3830
+ } finally {
3831
+ await unsubscribeCodexAppServerLiveThread(params.client, probeThreadId, CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS).catch((cause) => {
3832
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex model probe subscription could not be released: ${probeThreadId}`, { cause });
3833
+ });
3834
+ }
3290
3835
  params.throwIfAborted();
3291
- const probeResponse = assertCodexThreadForkResponse(rawProbeResponse);
3292
- if (params.restrictedToolSurface) await params.lifecycleTiming.measure("restricted-tool-surface-mcp-attestation", () => attestCodexRestrictedToolSurfaceMcpServersDisabled(params.client, probeThreadId, probeParams.config ?? void 0, params.signal));
3293
3836
  const nativeModel = requireNonBlankSupervisionValue(probeResponse.model, "native model");
3294
3837
  const nativeModelProvider = requireNativeSupervisionModelProvider({
3295
3838
  responseModelProvider: probeResponse.modelProvider,
@@ -3335,7 +3878,7 @@ async function materializePendingSupervisionBranch(params) {
3335
3878
  otherThreadId: probeThreadId,
3336
3879
  role: "canonical branch"
3337
3880
  });
3338
- pending = await trackPendingSupervisionArtifacts(params, pending, [probeThreadId, finalThreadId]);
3881
+ await trackPendingSupervisionArtifacts([finalThreadId]);
3339
3882
  params.throwIfAborted();
3340
3883
  assertExactSupervisionModelSelection(assertCodexThreadStartResponse(rawStartResponse), {
3341
3884
  model: nativeModel,
@@ -3355,11 +3898,11 @@ async function materializePendingSupervisionBranch(params) {
3355
3898
  client: params.client,
3356
3899
  threadId: finalThreadId,
3357
3900
  ephemeral: startParams.ephemeral === true
3358
- }) || !await archiveSupervisionArtifact(params.client, probeThreadId)) {
3901
+ })) {
3359
3902
  provisionalCleanupSafe = false;
3360
3903
  throw new CodexAppServerUnsafeSubscriptionError("Codex supervised plugin app attestation cleanup failed", { cause: error });
3361
3904
  }
3362
- pending = await trackPendingSupervisionArtifacts(params, pending, []);
3905
+ await trackPendingSupervisionArtifacts([]);
3363
3906
  throw error;
3364
3907
  }
3365
3908
  if (history.responseItems.length > 0) {
@@ -3369,8 +3912,6 @@ async function materializePendingSupervisionBranch(params) {
3369
3912
  }, { signal: params.signal }));
3370
3913
  params.throwIfAborted();
3371
3914
  }
3372
- if (!await archiveSupervisionArtifact(params.client, probeThreadId)) throw new Error(`Failed to archive temporary Codex model probe: ${probeThreadId}`);
3373
- pending = await trackPendingSupervisionArtifacts(params, pending, [finalThreadId]);
3374
3915
  const historyCoveredThrough = (/* @__PURE__ */ new Date()).toISOString();
3375
3916
  const bindingModelProvider = params.normalizeBindingModelProvider(params.attempt.authProfileId, nativeModelProvider);
3376
3917
  let committed = false;
@@ -3432,31 +3973,28 @@ async function materializePendingSupervisionBranch(params) {
3432
3973
  };
3433
3974
  } catch (error) {
3434
3975
  if (bindingCommitted) throw error;
3435
- if (error instanceof CodexThreadBindingConflictAfterCleanupError) throw error;
3436
3976
  if (!provisionalCleanupSafe) {
3437
3977
  await params.abandonClient();
3438
3978
  throw error;
3439
3979
  }
3440
3980
  const cleanup = await cleanPendingSupervisionArtifacts(params.client, pending);
3981
+ const nextPending = withPendingSupervisionCleanup(pending, cleanup.remaining);
3441
3982
  let cleanupStateError;
3442
- if (cleanup.remaining.length !== (pending.cleanupThreadIds?.length ?? 0)) {
3443
- const nextPending = withPendingSupervisionCleanup(pending, cleanup.remaining);
3444
- try {
3445
- if (await params.bindingStore.mutate(params.bindingIdentity, {
3446
- kind: "patch-pending-supervision-branch",
3447
- expected: pending,
3448
- pending: nextPending
3449
- })) pending = nextPending;
3450
- } catch (stateError) {
3451
- cleanupStateError = stateError;
3452
- }
3983
+ if (cleanupExpected && !isDeepStrictEqual(cleanupExpected, nextPending)) try {
3984
+ await params.bindingStore.mutate(params.bindingIdentity, {
3985
+ kind: "patch-pending-supervision-branch",
3986
+ expected: cleanupExpected,
3987
+ pending: nextPending
3988
+ });
3989
+ } catch (stateError) {
3990
+ cleanupStateError = stateError;
3453
3991
  }
3454
3992
  const unsafeCleanup = cleanup.remaining.length > 0 || isCodexAppServerUnsafeSubscriptionError(error);
3455
3993
  if (unsafeCleanup) await params.abandonClient();
3456
3994
  if (cleanupStateError) {
3457
- const cause = new AggregateError([error, cleanupStateError]);
3995
+ const cause = new AggregateError([error, cleanupStateError], "Codex supervised branch cleanup state could not be recorded", { cause: error });
3458
3996
  if (unsafeCleanup) throw new CodexAppServerUnsafeSubscriptionError("Codex supervised branch cleanup state could not be recorded", { cause });
3459
- throw new AggregateError([error, cleanupStateError], "Codex supervised branch cleanup state could not be recorded", { cause: error });
3997
+ throw cause;
3460
3998
  }
3461
3999
  if (cleanup.remaining.length > 0) throw new CodexAppServerUnsafeSubscriptionError(`Codex supervised branch cleanup remains pending: ${cleanup.remaining.join(", ")}`, { cause: error });
3462
4000
  throw error;
@@ -3484,7 +4022,7 @@ function buildPendingSupervisionProbeForkParams(params, pending) {
3484
4022
  ...params.appServer.serviceTier !== void 0 ? { serviceTier: params.appServer.serviceTier } : {},
3485
4023
  config: runtimeConfig,
3486
4024
  developerInstructions: params.developerInstructions ?? buildDeveloperInstructions(params.attempt, { dynamicTools: params.dynamicTools }),
3487
- ephemeral: isIncognitoSessionKey(params.attempt.sessionKey),
4025
+ ephemeral: true,
3488
4026
  threadSource: "appServer",
3489
4027
  excludeTurns: true
3490
4028
  };
@@ -3526,10 +4064,8 @@ function requireDistinctSupervisionThreadId(params) {
3526
4064
  return threadId;
3527
4065
  }
3528
4066
  function readSupervisionResponseThreadId(value) {
3529
- if (!value || typeof value !== "object" || Array.isArray(value)) return;
3530
- const thread = value.thread;
3531
- if (!thread || typeof thread !== "object" || Array.isArray(thread)) return;
3532
- return thread.id;
4067
+ const thread = isRecord(value) ? value.thread : void 0;
4068
+ return isRecord(thread) ? thread.id : void 0;
3533
4069
  }
3534
4070
  async function recoverPendingSupervisionArtifacts(params, pending) {
3535
4071
  if (!pending.cleanupThreadIds?.length) return pending;
@@ -3552,20 +4088,6 @@ async function recoverPendingSupervisionArtifacts(params, pending) {
3552
4088
  })) throw new CodexThreadBindingConflictError(pending.sourceThreadId, "recovering a supervised Codex branch");
3553
4089
  return next;
3554
4090
  }
3555
- async function trackPendingSupervisionArtifacts(params, pending, cleanupThreadIds) {
3556
- const next = withPendingSupervisionCleanup(pending, cleanupThreadIds);
3557
- if (!await params.bindingStore.mutate(params.bindingIdentity, {
3558
- kind: "patch-pending-supervision-branch",
3559
- expected: pending,
3560
- pending: next
3561
- })) {
3562
- const cleanupFailed = [];
3563
- for (const threadId of cleanupThreadIds) if (!await archiveSupervisionArtifact(params.client, threadId)) cleanupFailed.push(threadId);
3564
- if (cleanupFailed.length > 0) throw new CodexAppServerUnsafeSubscriptionError(`Codex supervised branch CAS cleanup failed: ${cleanupFailed.join(", ")}`);
3565
- throw new CodexThreadBindingConflictAfterCleanupError(pending.sourceThreadId, "tracking supervised Codex branch cleanup");
3566
- }
3567
- return next;
3568
- }
3569
4091
  function withPendingSupervisionCleanup(pending, cleanupThreadIds) {
3570
4092
  return {
3571
4093
  sourceThreadId: pending.sourceThreadId,
@@ -3602,15 +4124,10 @@ async function archiveSupervisionArtifact(client, threadId) {
3602
4124
  async function startOrResumeThread(params) {
3603
4125
  const incognito = isIncognitoSessionKey(params.params.sessionKey);
3604
4126
  const clientId = resolveCodexAppServerClientInstanceId(params.client);
3605
- const bindingIdentity = sessionBindingIdentity({
3606
- sessionId: params.params.sessionId,
3607
- sessionKey: params.params.sessionKey,
3608
- agentId: params.agentId ?? params.params.agentId,
3609
- config: params.params.config
3610
- });
3611
- return await params.bindingStore.withLease(bindingIdentity, async () => {
3612
- const { contextEngineBinding, dynamicToolsContainDeferred, dynamicToolsFingerprint, environmentSelectionFingerprint, hostSystemAgentActive, legacyDynamicToolsFingerprint, legacyUserMcpServersFingerprint, lifecycleTiming, nativeSkillIsolation, nativeSkillIsolationFingerprint, networkProxyConfigFingerprint, ringZeroActive, ringZeroClientInstanceId, ringZeroConfigFingerprint, restrictedToolSurface, restrictedToolSurfaceInheritedMcpServerNames, userMcpServersConfigPatch, userMcpServersFingerprint, webSearchThreadConfigFingerprint } = await prepareCodexThreadLifecyclePreflight(params);
3613
- let binding = await lifecycleTiming.measure("read-binding", () => params.bindingStore.read(bindingIdentity));
4127
+ return await withCodexThreadLifecycleBinding(params, async (bindingIdentity, currentBinding) => {
4128
+ let binding = currentBinding;
4129
+ const preflight = await prepareCodexThreadLifecyclePreflight(params);
4130
+ const { contextEngineBinding, dynamicToolsContainDeferred, dynamicToolsFingerprint, environmentSelectionFingerprint, hostSystemAgentActive, legacyDynamicToolsFingerprint, legacyUserMcpServersFingerprint, lifecycleTiming, nativeSkillIsolation, nativeSkillIsolationFingerprint, networkProxyConfigFingerprint, ringZeroActive, ringZeroClientInstanceId, ringZeroConfigFingerprint, restrictedToolSurface, restrictedToolSurfaceInheritedMcpServerNames, userMcpServersConfigPatch, userMcpServersFingerprint, webSearchThreadConfigFingerprint } = preflight;
3614
4131
  let replacementPredecessor;
3615
4132
  const initialBoundThreadId = binding?.threadId;
3616
4133
  const initialBoundClientId = binding?.clientId;
@@ -3622,26 +4139,33 @@ async function startOrResumeThread(params) {
3622
4139
  config: params.params.config
3623
4140
  });
3624
4141
  const throwIfAborted = () => throwIfCodexThreadLifecycleAborted(params.signal);
3625
- const releaseRetainedThread = async (threadId, ownerClientId = initialBoundClientId) => {
4142
+ const releaseRetainedThread = async (threadId, ownerClientId = initialBoundClientId, assertCurrent) => {
3626
4143
  if (ownerClientId && ownerClientId !== clientId) {
3627
4144
  const previousClient = retainSharedCodexAppServerClientByInstanceId(ownerClientId);
3628
- if (!previousClient) return;
4145
+ if (!previousClient) return false;
3629
4146
  try {
3630
- await releaseCodexRetainedLiveThread({
4147
+ const assertPrevious = assertCurrent ? captureExclusiveSharedCodexAppServerClient(previousClient.client) : void 0;
4148
+ if (isCodexAppServerLiveThreadClaimed(previousClient.client, threadId)) throw new Error(`Codex thread ${threadId} is claimed by active work; stop it first.`);
4149
+ return await releaseCodexRetainedLiveThread({
3631
4150
  client: previousClient.client,
3632
4151
  lifecycleTiming,
3633
- threadId
4152
+ threadId,
4153
+ assertCurrent: assertCurrent ? () => {
4154
+ assertCurrent();
4155
+ assertPrevious?.();
4156
+ } : void 0
3634
4157
  });
3635
4158
  } finally {
3636
4159
  previousClient.release();
3637
4160
  }
3638
- return;
3639
4161
  }
3640
- await releaseCodexRetainedLiveThread({
4162
+ if (isCodexAppServerLiveThreadClaimed(params.client, threadId)) throw new Error(`Codex thread ${threadId} is claimed by active work; stop it first.`);
4163
+ return await releaseCodexRetainedLiveThread({
3641
4164
  client: params.client,
3642
4165
  abandonClient: params.abandonClient,
3643
4166
  lifecycleTiming,
3644
- threadId
4167
+ threadId,
4168
+ assertCurrent
3645
4169
  });
3646
4170
  };
3647
4171
  if (!binding && bindingIdentity.kind === "session" && bindingIdentity.sessionKey) {
@@ -3723,6 +4247,36 @@ async function startOrResumeThread(params) {
3723
4247
  })) throw new CodexThreadBindingConflictError(current.threadId, operation);
3724
4248
  binding = void 0;
3725
4249
  };
4250
+ const resolveRequestContext = () => {
4251
+ const startModelSelection = resolveCodexAppServerThreadModelSelection({
4252
+ provider: params.params.provider,
4253
+ model: params.runtimeModelId ?? params.params.modelId,
4254
+ binding,
4255
+ authProfileId: params.params.authProfileId,
4256
+ authProfileStore: params.params.authProfileStore,
4257
+ agentDir: params.params.agentDir,
4258
+ config: params.params.config
4259
+ });
4260
+ return {
4261
+ ...preflight,
4262
+ bindingIdentity,
4263
+ startModelSelection,
4264
+ startModelProvider: startModelSelection.modelProvider,
4265
+ normalizeBindingModelProvider,
4266
+ throwIfAborted
4267
+ };
4268
+ };
4269
+ const transientDelegationRestriction = params.params.delegationCapability === "report_only";
4270
+ const persistentWebSearchRestriction = params.webSearchAllowed === false && params.persistentWebSearchAllowed === false;
4271
+ const transientNativeToolRestriction = params.nativeCodeModeEnabled === false && !persistentWebSearchRestriction;
4272
+ const transientWebSearchRestriction = isTransientWebSearchRestriction(params);
4273
+ if (binding?.pendingResumeConfiguration) return await resumePendingCodexThread(params, {
4274
+ ...resolveRequestContext(),
4275
+ binding,
4276
+ clearCurrentBinding,
4277
+ releaseRetainedThread: (threadId, assertCurrent) => releaseRetainedThread(threadId, initialBoundClientId, assertCurrent),
4278
+ transientRestriction: transientDelegationRestriction || transientNativeToolRestriction || transientWebSearchRestriction
4279
+ });
3726
4280
  if (binding?.threadId && !restrictedToolSurface && binding.nativeToolPolicyRestricted === true) await clearCurrentBinding("rotating a host-policy-restricted thread binding");
3727
4281
  if (binding?.threadId && binding.nativeSkillIsolationFingerprint !== nativeSkillIsolationFingerprint) {
3728
4282
  embeddedAgentLog.debug("codex app-server native skill isolation changed; starting a new thread", { threadId: binding.threadId });
@@ -3756,24 +4310,12 @@ async function startOrResumeThread(params) {
3756
4310
  await clearCurrentBinding("rotating a GPT-5.6 multi-agent thread binding");
3757
4311
  binding = void 0;
3758
4312
  }
3759
- const startModelSelection = resolveCodexAppServerThreadModelSelection({
3760
- provider: params.params.provider,
3761
- model: params.runtimeModelId ?? params.params.modelId,
3762
- binding,
3763
- authProfileId: params.params.authProfileId,
3764
- authProfileStore: params.params.authProfileStore,
3765
- agentDir: params.params.agentDir,
3766
- config: params.params.config
3767
- });
3768
- const startModelProvider = startModelSelection.modelProvider;
3769
- const transientDelegationRestriction = params.params.delegationCapability === "report_only";
4313
+ const requestContext = resolveRequestContext();
4314
+ const { startModelSelection, startModelProvider } = requestContext;
3770
4315
  let preserveExistingBinding = transientDelegationRestriction || !ringZeroActive && params.nativeProviderWebSearchSupport === "unknown" && !binding?.threadId;
3771
4316
  let rotatedContextEngineBinding = false;
3772
4317
  let prebuiltPluginThreadConfig;
3773
4318
  const webSearchBindingChanged = binding?.threadId && binding.webSearchThreadConfigFingerprint !== webSearchThreadConfigFingerprint;
3774
- const persistentWebSearchRestriction = params.webSearchAllowed === false && params.persistentWebSearchAllowed === false;
3775
- const transientNativeToolRestriction = params.nativeCodeModeEnabled === false && !persistentWebSearchRestriction;
3776
- const transientWebSearchRestriction = isTransientWebSearchRestriction(params);
3777
4319
  const explicitTransientWebSearchRestriction = params.webSearchAllowed === false && params.persistentWebSearchAllowed !== false && transientWebSearchRestriction;
3778
4320
  const unknownProviderWebSearchSupport = params.nativeProviderWebSearchSupport === "unknown";
3779
4321
  if (binding?.threadId && (params.configuredMcpOwnershipVersion === 1 && (binding.configuredMcpOwnershipVersion !== 1 || binding.dynamicToolsFingerprint === void 0 || binding.mcpServersFingerprint !== void 0 || binding.userMcpServersFingerprint !== void 0) || params.configuredMcpOwnershipVersion !== 1 && binding.configuredMcpOwnershipVersion === 1) && binding?.threadId) {
@@ -3944,31 +4486,11 @@ async function startOrResumeThread(params) {
3944
4486
  userMcpServersConfigPatch
3945
4487
  });
3946
4488
  if (warmReuse.binding) return warmReuse.binding;
4489
+ if (binding.preserveNativeModel === true) await assertAdoptedCodexThreadResumeAllowed(params, binding.threadId, requestContext);
3947
4490
  await releaseRetainedThread(binding.threadId);
3948
4491
  const resumed = await resumeExistingCodexThread(params, {
4492
+ ...requestContext,
3949
4493
  binding,
3950
- bindingIdentity,
3951
- startModelSelection,
3952
- startModelProvider,
3953
- userMcpServersConfigPatch,
3954
- dynamicToolsFingerprint,
3955
- dynamicToolsContainDeferred,
3956
- webSearchThreadConfigFingerprint,
3957
- nativeSkillIsolationFingerprint,
3958
- userMcpServersFingerprint,
3959
- ringZeroConfigFingerprint,
3960
- ringZeroClientInstanceId,
3961
- networkProxyConfigFingerprint,
3962
- contextEngineBinding,
3963
- environmentSelectionFingerprint,
3964
- hostSystemAgentActive,
3965
- ringZeroActive,
3966
- restrictedToolSurface,
3967
- restrictedToolSurfaceInheritedMcpServerNames,
3968
- nativeSkillIsolation,
3969
- lifecycleTiming,
3970
- normalizeBindingModelProvider,
3971
- throwIfAborted,
3972
4494
  clearCurrentBinding,
3973
4495
  prebuiltFinalConfigPatch: warmReuse.prebuiltFinalConfigPatch,
3974
4496
  prebuiltPluginThreadConfig
@@ -3977,28 +4499,7 @@ async function startOrResumeThread(params) {
3977
4499
  }
3978
4500
  if (initialBoundThreadId && !preserveExistingBinding && !replacementPredecessor) await releaseRetainedThread(initialBoundThreadId);
3979
4501
  const started = await startFreshCodexThread(params, {
3980
- bindingIdentity,
3981
- startModelSelection,
3982
- startModelProvider,
3983
- userMcpServersConfigPatch,
3984
- dynamicToolsFingerprint,
3985
- dynamicToolsContainDeferred,
3986
- webSearchThreadConfigFingerprint,
3987
- nativeSkillIsolationFingerprint,
3988
- userMcpServersFingerprint,
3989
- ringZeroConfigFingerprint,
3990
- ringZeroClientInstanceId,
3991
- networkProxyConfigFingerprint,
3992
- contextEngineBinding,
3993
- environmentSelectionFingerprint,
3994
- hostSystemAgentActive,
3995
- ringZeroActive,
3996
- restrictedToolSurface,
3997
- restrictedToolSurfaceInheritedMcpServerNames,
3998
- nativeSkillIsolation,
3999
- lifecycleTiming,
4000
- normalizeBindingModelProvider,
4001
- throwIfAborted,
4502
+ ...requestContext,
4002
4503
  prebuiltPluginThreadConfig,
4003
4504
  preserveExistingBinding,
4004
4505
  rotatedContextEngineBinding,
@@ -4105,7 +4606,6 @@ function buildTurnCollaborationMode(params, options = {}) {
4105
4606
  function buildTurnScopedCollaborationInstructions(params, options = {}) {
4106
4607
  const contextInstructions = joinPresentSections(options.turnScopedDeveloperInstructions, options.memoryCollaborationInstructions, options.skillsCollaborationInstructions);
4107
4608
  if (params.trigger === "cron") return joinPresentSections(buildCronCollaborationInstructions(), contextInstructions);
4108
- if (params.trigger === "heartbeat") return joinPresentSections(buildHeartbeatCollaborationInstructions(), contextInstructions);
4109
4609
  if (contextInstructions?.trim()) return joinPresentSections(buildDefaultCollaborationInstructions(), contextInstructions);
4110
4610
  return null;
4111
4611
  }
@@ -4132,15 +4632,8 @@ function buildCronCollaborationInstructions() {
4132
4632
  "Keep output concise and automation-oriented. Prefer the final command result or a short failure summary over status narration."
4133
4633
  ].join("\n\n");
4134
4634
  }
4135
- function buildHeartbeatCollaborationInstructions() {
4136
- return [
4137
- "This is an OpenClaw heartbeat turn. Apply these instructions only to this heartbeat wake; ordinary chat turns should stay in Codex Default mode.",
4138
- "When you are ready to end the heartbeat, prefer the structured `heartbeat_respond` tool so OpenClaw can record the wake outcome and notification decision. If `heartbeat_respond` is not already available and `tool_search` is available, search for `heartbeat_respond`, load it, then call it. Use `notify=false` when nothing should visibly interrupt the user.",
4139
- GPT5_HEARTBEAT_PROMPT_OVERLAY
4140
- ].join("\n\n");
4141
- }
4142
4635
  function joinPresentSections(...sections) {
4143
4636
  return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
4144
4637
  }
4145
4638
  //#endregion
4146
- export { ensureCodexPluginActivation as $, isForcedPrivateQaCodexRuntime as A, neutralizeCodexExplicitMentionSigils as B, CODEX_MANAGED_THREAD_NAMESPACE as C, codexLegacyDynamicToolsFingerprint as D, codexDynamicToolsFingerprint as E, resolveCodexDynamicToolsLoadingForRuntime as F, buildCodexPluginAppsConfigPatchFromPolicyContext as G, resolveCodexContextEngineProjectionMaxChars as H, buildContextEngineBinding as I, buildCodexPluginThreadConfigTimeoutFallback as J, buildCodexPluginThreadConfig as K, isContextEngineBindingCompatible as L, isSystemAgentOnlyCodexDynamicToolAllowlist as M, normalizeCodexDynamicToolName as N, filterCodexDynamicTools as O, resolveCodexDynamicToolsLoading as P, shouldBuildCodexPluginThreadConfig as Q, buildCodexContinuityCalibration as R, CODEX_MANAGED_THREAD_MAX_ENTRIES as S, areCodexDynamicToolFingerprintsCompatible as T, resolveCodexContextEngineProjectionReserveTokens as U, projectContextEngineAssemblyForCodex as V, resolveCodexContinuityProjectionMaxChars as W, buildPluginAppPolicyContext as X, buildDisabledAppsConfigPatch as Y, mergeCodexThreadConfigs as Z, resolveCodexAppServerRequestModelSelection as _, isCodexAppServerProfilerEnabled as a, resolveReasoningEffort as b, buildCodexRingZeroThreadConfigPatch as c, buildCodexNativeWebSearchThreadConfig as d, refreshCodexPluginRuntimeState as et, resolveCodexWebSearchPlan as f, resolveCodexAppServerModelProvider as g, CODEX_NATIVE_PERSONALITY_NONE as h, startOrResumeThread as i, resolveRecoverableCodexPluginConfigKeys as it, isMessageOnlyCodexSourceReply as j, filterCodexDynamicToolsForDisabledNativeSurface as k, buildCodexRuntimeThreadConfig as l, buildCodexProjectDocThreadConfig as m, buildTurnStartParams as n, isOpenAiCuratedMarketplaceName as nt, assertCodexManagedRequirementsDoNotOverrideToolPolicy as o, buildDeveloperInstructions as p, buildCodexPluginThreadConfigInputFingerprint as q, buildCodexUserInput as r, pluginReadParams as rt, attestCodexRestrictedToolSurfaceMcpServersDisabled as s, buildTurnCollaborationMode as t, isOpenAiCuratedMarketplace as tt, readCodexInheritedMcpServerNames as u, resolveCodexAppServerThreadModelSelection as v, createCodexManagedThreadStore as w, readCodexSupportedReasoningEfforts as x, resolveCodexBindingModelProviderFallback as y, fitCodexProjectedContextForTurnStart as z };
4639
+ export { resolveCodexContinuityProjectionMaxChars as $, readCodexSupportedReasoningEfforts as A, isMessageOnlyCodexSourceReply as B, buildCodexProjectDocThreadConfig as C, resolveCodexAppServerThreadModelSelection as D, resolveCodexAppServerRequestModelSelection as E, codexDynamicToolsFingerprint as F, buildContextEngineBinding as G, normalizeCodexDynamicToolName as H, codexLegacyDynamicToolsFingerprint as I, fitCodexProjectedContextForTurnStart as J, isContextEngineBindingCompatible as K, filterCodexDynamicTools as L, CODEX_MANAGED_THREAD_NAMESPACE as M, createCodexManagedThreadStore as N, resolveCodexBindingModelProviderFallback as O, areCodexDynamicToolFingerprintsCompatible as P, resolveCodexContextEngineProjectionReserveTokens as Q, filterCodexDynamicToolsForDisabledNativeSurface as R, buildDeveloperInstructions as S, resolveCodexAppServerModelProvider as T, resolveCodexDynamicToolsLoading as U, isSystemAgentOnlyCodexDynamicToolAllowlist as V, resolveCodexDynamicToolsLoadingForRuntime as W, projectContextEngineAssemblyForCodex as X, neutralizeCodexExplicitMentionSigils as Y, resolveCodexContextEngineProjectionMaxChars as Z, buildCodexRingZeroThreadConfigPatch as _, isCodexAppServerProfilerEnabled as a, buildPluginAppPolicyContext as at, buildCodexNativeWebSearchThreadConfig as b, buildCodexNativeHookRelayConfig as c, ensureCodexPluginActivation as ct, emitCodexNativePreToolUseFailureDiagnostic as d, isOpenAiCuratedMarketplaceName as dt, buildCodexPluginAppsConfigPatchFromPolicyContext as et, resolveCodexNativeHookRelayEvents as f, pluginReadParams as ft, attestCodexRestrictedToolSurfaceMcpServersDisabled as g, assertCodexManagedRequirementsDoNotOverrideToolPolicy as h, startOrResumeThread as i, buildDisabledAppsConfigPatch as it, CODEX_MANAGED_THREAD_MAX_ENTRIES as j, resolveReasoningEffort as k, buildCodexNativeHookRelayDisabledConfig as l, refreshCodexPluginRuntimeState as lt, scheduleCodexNativeHookRelayUnregister as m, buildTurnStartParams as n, buildCodexPluginThreadConfigInputFingerprint as nt, CODEX_NATIVE_HOOK_RELAY_EVENTS as o, mergeCodexThreadConfigs as ot, resolveCodexNativeHookRelayTtlMs as p, resolveRecoverableCodexPluginConfigKeys as pt, buildCodexContinuityCalibration as q, buildCodexUserInput as r, buildCodexPluginThreadConfigTimeoutFallback as rt, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as s, shouldBuildCodexPluginThreadConfig as st, buildTurnCollaborationMode as t, buildCodexPluginThreadConfig as tt, createCodexNativeHookRelay as u, isOpenAiCuratedMarketplace as ut, buildCodexRuntimeThreadConfig as v, CODEX_NATIVE_PERSONALITY_NONE as w, resolveCodexWebSearchPlan as x, readCodexInheritedMcpServerNames as y, isForcedPrivateQaCodexRuntime as z };