@openclaw/codex 2026.9.5 → 2026.9.6

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 (120) hide show
  1. package/dist/.setup/{account-usage-runtime-C2MOIvfq.mjs → account-usage-runtime-Eem_WGqY.mjs} +5 -5
  2. package/dist/.setup/{apply-CJ0ZfmBG.mjs → apply-DDOi8uNx.mjs} +22 -28
  3. package/dist/.setup/{attempt-client-cleanup-BpYKdTA0.mjs → attempt-client-cleanup-CEv1cKwF.mjs} +58 -43
  4. package/dist/.setup/attempt-workspace-context-DUVEn_CS.mjs +331 -0
  5. package/dist/.setup/{auth-cache-key-QirmgiCo.mjs → auth-cache-key-B2mpaI9D.mjs} +9 -81
  6. package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
  7. package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
  8. package/dist/.setup/{binding-connection-Bm38niE8.mjs → binding-connection-ThoatDcb.mjs} +1 -1
  9. package/dist/.setup/{binding-connection.runtime-CnRMC0ta.mjs → binding-connection.runtime-yoHrABt-.mjs} +4 -4
  10. package/dist/.setup/{bounded-turn-BtlZcivC.mjs → bounded-turn-B2HScEgT.mjs} +138 -32
  11. package/dist/.setup/{build-state-Xx9ybZqa.mjs → build-state-C7EnDVgr.mjs} +1 -1
  12. package/dist/.setup/{capabilities-_vXcZGSx.mjs → capabilities-CDXOOFdZ.mjs} +1 -1
  13. package/dist/.setup/{client-vXs2929Q.mjs → client-Cs08OXVQ.mjs} +583 -559
  14. package/dist/.setup/client-catalog-response-BMgt_4q4.mjs +285 -0
  15. package/dist/.setup/{command-dispatch-naHIZwwF.mjs → command-dispatch-B4JuOsOk.mjs} +8 -4
  16. package/dist/.setup/{command-formatters-CGEkdawF.mjs → command-formatters-Bmqvr9tO.mjs} +8 -4
  17. package/dist/.setup/{command-handlers-BtAJEW1X.mjs → command-handlers-DW7Lx9oH.mjs} +106 -172
  18. package/dist/.setup/{command-rpc-DHFpn4le.mjs → command-rpc-DixIj3HW.mjs} +36 -21
  19. package/dist/.setup/{compact-C3i3qlzj.mjs → compact-Du5UvtxA.mjs} +14 -21
  20. package/dist/.setup/{config-CedDWjM-.mjs → config-BoTP_mrL.mjs} +3 -3
  21. package/dist/.setup/{config-options-BsanJ8QG.mjs → config-options-BvaRs51b.mjs} +46 -30
  22. package/dist/.setup/{config-runtime-CeAhl_h4.mjs → config-runtime-C8Rw1m1m.mjs} +1 -1
  23. package/dist/.setup/{config-security-BRQ2mgW9.mjs → config-security-BEReZ6go.mjs} +35 -120
  24. package/dist/.setup/{conversation-binding-DhzrpTM6.mjs → conversation-binding-DP-gMrBP.mjs} +21 -32
  25. package/dist/.setup/{conversation-control-DN53ns41.mjs → conversation-control-uK9Jomlc.mjs} +28 -67
  26. package/dist/.setup/{dynamic-tools-D16lOp67.mjs → dynamic-tools-BDXl-8Cw.mjs} +848 -578
  27. package/dist/.setup/{effective-mcp-catalog-K6kLCN8X.mjs → effective-mcp-catalog-CvnvnGIe.mjs} +3 -3
  28. package/dist/.setup/{ephemeral-turn-R1gA8Sn6.mjs → ephemeral-turn-poidXgek.mjs} +9 -6
  29. package/dist/.setup/{event-projector-assistant-message-DNUR1s0A.mjs → event-projector-assistant-message-BsruvNrH.mjs} +2 -4
  30. package/dist/.setup/{event-projector-items-DyTQ_XqL.mjs → event-projector-items-C6L_5ZiT.mjs} +42 -8
  31. package/dist/.setup/{event-projector-usage-C7Ntzs-f.mjs → event-projector-usage-CnBS8Wa3.mjs} +1 -1
  32. package/dist/.setup/{harness-rxaaoN-o.mjs → harness-a_MsE4-_.mjs} +23 -17
  33. package/dist/.setup/{inference-context-fulhZuz8.mjs → inference-context-D96l9-ew.mjs} +1 -1
  34. package/dist/.setup/inference-proxy-b-aJMSxm.mjs +601 -0
  35. package/dist/.setup/{isolated-completion-B6srt48J.mjs → isolated-completion-BIZFhTNG.mjs} +17 -10
  36. package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
  37. package/dist/.setup/{managed-binary-DP6Rib3P.mjs → managed-binary-BnshlFag.mjs} +13 -2
  38. package/dist/.setup/{model-catalog-DkvUuBey.mjs → model-catalog-CfXJf9Ay.mjs} +9 -10
  39. package/dist/.setup/{models-BDFgm_G-.mjs → models-KnqBv0hE.mjs} +3 -3
  40. package/dist/.setup/{native-auth-BLZGqFjw.mjs → native-auth-rWbGbMn3.mjs} +4 -4
  41. package/dist/.setup/{native-subagent-history-YXaL6dMd.mjs → native-subagent-history-0nYYgo0k.mjs} +26 -13
  42. package/dist/.setup/{native-subagent-monitor-B1hxzIOy.mjs → native-subagent-monitor-D3filLY2.mjs} +145 -317
  43. package/dist/.setup/{native-subagent-task-ids-DsuOonKv.mjs → native-subagent-task-ids-wb8CKZGN.mjs} +69 -39
  44. package/dist/.setup/{node-cli-sessions-Cl8b2ZF3.mjs → node-cli-sessions-r3avj02l.mjs} +86 -68
  45. package/dist/.setup/node-exec-server.runtime-BDwWXVpK.mjs +247 -0
  46. package/dist/.setup/{plan-xD7WKYTM.mjs → plan-CN3VwfNU.mjs} +74 -76
  47. package/dist/.setup/{plugin-activation-r8nq5Jzp.mjs → plugin-activation-DT3MNtqj.mjs} +7 -16
  48. package/dist/.setup/{plugin-app-cache-key-BOxKP7db.mjs → plugin-app-cache-key-B2CsSdnV.mjs} +4 -20
  49. package/dist/.setup/{plugin-approval-roundtrip-CjfzafAZ.mjs → plugin-approval-roundtrip-C0MZzCuP.mjs} +1 -1
  50. package/dist/.setup/{plugin-inventory-DUle8DLz.mjs → plugin-inventory-BoRei8Z4.mjs} +16 -7
  51. package/dist/.setup/{plugin-marketplace-discovery-P-Vndfqq.mjs → plugin-marketplace-discovery-CDOi8IFs.mjs} +4 -1
  52. package/dist/.setup/{plugin-metadata-cache-DsS5buNa.mjs → plugin-metadata-cache-Ctmo83k_.mjs} +224 -154
  53. package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
  54. package/dist/.setup/{provider-fFh_-VR3.mjs → provider-BOsxQHOM.mjs} +9 -5
  55. package/dist/.setup/{provider-capabilities-B8J4Dy-O.mjs → provider-capabilities-BfE88FZ5.mjs} +31 -3
  56. package/dist/.setup/{rate-limits-DOEGYRNs.mjs → rate-limits-CMU3DUD0.mjs} +116 -137
  57. package/dist/.setup/{request-BioXJLYa.mjs → request-D2L0zMrq.mjs} +23 -15
  58. package/dist/.setup/{run-attempt-rlA07pUv.mjs → run-attempt-BHu11r7h.mjs} +1197 -617
  59. package/dist/.setup/{runtime-artifact-Dy38Z5iU.mjs → runtime-artifact-CLZ8udh-.mjs} +29 -45
  60. package/dist/.setup/{sandbox-guard-BBP-RbTf.mjs → sandbox-guard-C2sRMOEY.mjs} +1 -1
  61. package/dist/.setup/{session-binding-_0W_fHRr.mjs → session-binding-Cm0apEbd.mjs} +3 -32
  62. package/dist/.setup/{session-binding-record-TH3xA0zj.mjs → session-binding-record-BGoz8wOK.mjs} +22 -3
  63. package/dist/.setup/{session-binding-sidecars-CKYEcfNn.mjs → session-binding-sidecars-BlB5EvIS.mjs} +48 -45
  64. package/dist/.setup/{session-catalog-fUdWDx-U.mjs → session-catalog-Pno1xGcl.mjs} +482 -182
  65. package/dist/.setup/{session-catalog-adoption-CR_whkEW.mjs → session-catalog-adoption-BI6UTDZT.mjs} +57 -25
  66. package/dist/.setup/{session-catalog-archive-CwZaPacf.mjs → session-catalog-archive-lHBqzhaO.mjs} +6 -6
  67. package/dist/.setup/{session-catalog-events-jMcYfQyd.mjs → session-catalog-events-Bj6j94E_.mjs} +122 -25
  68. package/dist/.setup/{session-catalog-index-B141u15s.mjs → session-catalog-index-B9_VQIUz.mjs} +178 -78
  69. package/dist/.setup/{session-catalog-index-order-Cc5BzlQr.mjs → session-catalog-index-order-hcdz07yN.mjs} +2 -2
  70. package/dist/.setup/{session-catalog-index-state-BAuDztHN.mjs → session-catalog-index-state-Dgh8ORJm.mjs} +5 -2
  71. package/dist/.setup/{session-catalog-native-projection-ChV3cCtm.mjs → session-catalog-native-projection-DowriLid.mjs} +30 -13
  72. package/dist/.setup/{session-catalog-node-adoption-BVRsYOSh.mjs → session-catalog-node-adoption-ITddWx_X.mjs} +24 -12
  73. package/dist/.setup/{session-catalog-node-continue-Dowv8osw.mjs → session-catalog-node-continue-6g6qi4A9.mjs} +22 -13
  74. package/dist/.setup/{session-catalog-projection-C1Bj9Jl-.mjs → session-catalog-projection-zK_PUsiE.mjs} +13 -5
  75. package/dist/.setup/{session-cli-DIj-IE-E.mjs → session-cli-irrD-uo7.mjs} +4 -4
  76. package/dist/.setup/{session-history-C--SrLI8.mjs → session-history-BrqhSCf9.mjs} +17 -22
  77. package/dist/.setup/{session-history-import-JHXT5Xfi.mjs → session-history-import-D-3wAgOP.mjs} +4 -4
  78. package/dist/.setup/{session-history.worker-CpNj7H_P.mjs → session-history.worker-CaCh0xF_.mjs} +5 -18
  79. package/dist/.setup/{session-initialization-DH1z6fXn.mjs → session-initialization-rcgbZiid.mjs} +2 -2
  80. package/dist/.setup/{session-permission-policy-DhurXY0l.mjs → session-permission-policy-BI1QK_98.mjs} +2 -2
  81. package/dist/.setup/{session-retirement-CU87AOg9.mjs → session-retirement-BH-S6qkJ.mjs} +25 -6
  82. package/dist/.setup/{settled-turn-finalizer-CiY2bLFK.mjs → settled-turn-finalizer-DiAi6Kx6.mjs} +8 -8
  83. package/dist/.setup/{shared-client-BpTtuLQ5.mjs → shared-client-DA4VR4Eb.mjs} +59 -89
  84. package/dist/.setup/{side-question-DSCZyoBD.mjs → side-question-BJ1wSDcB.mjs} +147 -211
  85. package/dist/.setup/{source-Bjp4UQij.mjs → source-CUzJq5WN.mjs} +9 -9
  86. package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
  87. package/dist/.setup/{thread-archive-guard-jmecf6OJ.mjs → thread-archive-guard-C9frICzX.mjs} +10 -3
  88. package/dist/.setup/{thread-history-page-BTx-4xsg.mjs → thread-history-page-DoVpnHim.mjs} +1 -1
  89. package/dist/.setup/{thread-lifecycle-Cik28qWn.mjs → thread-lifecycle-B3mfz1TG.mjs} +172 -2271
  90. package/dist/.setup/{thread-ownership-skomxnIt.mjs → thread-ownership-DcTtAcXj.mjs} +4 -2
  91. package/dist/.setup/{thread-policy-Cjs4B8xf.mjs → thread-policy-DGuQsuFC.mjs} +19 -3
  92. package/dist/.setup/thread-requests-BLvGkP2R.mjs +2205 -0
  93. package/dist/.setup/{thread-resume-BkNpj9Pz.mjs → thread-resume-DIBXwOpE.mjs} +6 -6
  94. package/dist/.setup/{timeout-DZF05XrR.mjs → timeout-C910MdAB.mjs} +19 -2
  95. package/dist/.setup/{transcript-history-projection-DHNBDhCU.mjs → transcript-history-projection-ZZpkFkJ_.mjs} +94 -64
  96. package/dist/.setup/{transcript-mirror-D4qp_leP.mjs → transcript-mirror-BtHDBp1G.mjs} +218 -198
  97. package/dist/.setup/{transport-stdio-Cmx94Oiy.mjs → transport-stdio-h2VHOskC.mjs} +135 -55
  98. package/dist/.setup/{upstream-session-fork-D3UKxgVD.mjs → upstream-session-fork-BUr4OUbC.mjs} +44 -36
  99. package/dist/.setup/{usage-BOgBEKso.mjs → usage-BML0r-ua.mjs} +5 -4
  100. package/dist/.setup/{usage-limit-error-C0ow7DOc.mjs → usage-limit-error-DUMbefVY.mjs} +4 -4
  101. package/dist/.setup/{web-search-provider.runtime-CTGuJt6i.mjs → web-search-provider.runtime-CDKlN-Rv.mjs} +4 -3
  102. package/dist/api.js +23 -12
  103. package/dist/catalog-page-worker-entrypoint.js +12 -0
  104. package/dist/catalog-page.worker.js +9 -0
  105. package/dist/cli-metadata.js +1 -1
  106. package/dist/doctor-contract-api.js +2 -2
  107. package/dist/harness.js +1 -1
  108. package/dist/index.js +221 -170
  109. package/dist/media-understanding-provider.js +2 -2
  110. package/dist/migration-provider-api.js +1 -1
  111. package/dist/provider-discovery.js +1 -1
  112. package/dist/session-history-worker-runtime.js +15 -32
  113. package/dist/session-history.worker.js +1 -1
  114. package/package.json +9 -6
  115. package/dist/.setup/attempt-context-VXVwTCfS.mjs +0 -636
  116. package/dist/.setup/inference-proxy-CC15HuSi.mjs +0 -311
  117. package/dist/.setup/launch-args-DnMak49W.mjs +0 -111
  118. package/dist/.setup/node-exec-server.runtime-BaViBKNz.mjs +0 -226
  119. package/dist/.setup/version-CoqzXPgK.mjs +0 -12
  120. package/dist/.setup/{native-execution-policy-YBMHSzC4.mjs → native-execution-policy-umd0tgh4.mjs} +1 -1
@@ -1,620 +1,78 @@
1
- import { a as readCodexPluginInventory, o as resolveOwnedAppApprovalOverrideKeys } from "./plugin-inventory-DUle8DLz.mjs";
2
- import { n as assertCodexBindingMayBeReplaced, p as sessionBindingIdentity } from "./session-binding-record-TH3xA0zj.mjs";
3
- import { g as resolveCodexAppServerLocalHomeDir, h as resolveCodexAppServerHomeDir, m as isJsonObject, p as flattenCodexDynamicToolFunctions } from "./config-security-BRQ2mgW9.mjs";
4
- import { f as resolveCodexPluginsPolicy } from "./config-parsing-CcB9iPoq.mjs";
5
- import { L as resolveCodexToolAbortTerminalReason, _ as assertCodexThreadAcceptsDirectInput, b as assertCodexThreadStartResponse, d as isCodexAppServerRequestTimeoutError, l as isCodexAppServerOverloadError, p as resolveCodexAppServerClientInstanceId, r as getCodexAppServerClientInstanceId, v as assertCodexThreadForkResponse } from "./client-vXs2929Q.mjs";
6
- import { d as readCodexEffectiveConfig, n as codexSandboxPolicyForTurn, s as assertCodexModelBackedReviewerEffectiveConfig, u as CODEX_SESSION_OVERRIDABLE_LAYER_TYPES } from "./config-options-BsanJ8QG.mjs";
7
- import { f as getCurrentSharedClientEntry } from "./auth-cache-key-QirmgiCo.mjs";
1
+ import { m as sessionBindingIdentity, n as assertCodexBindingMayBeReplaced } from "./session-binding-record-BGoz8wOK.mjs";
2
+ import { d as resolveCodexAppServerHomeDir, f as resolveCodexAppServerLocalHomeDir } from "./config-security-BEReZ6go.mjs";
3
+ import { i as isJsonObject, r as flattenCodexDynamicToolFunctions } from "./protocol-CANUwXJ3.mjs";
4
+ import { d as readCodexEffectiveConfig, n as codexSandboxPolicyForTurn, s as assertCodexModelBackedReviewerEffectiveConfig, u as CODEX_SESSION_OVERRIDABLE_LAYER_TYPES } from "./config-options-BvaRs51b.mjs";
8
5
  import { i as markStartedCodexManagedThread } from "./managed-thread-store-BMqgThVL.mjs";
6
+ import { f as getCurrentSharedClientEntry, o as readCodexSessionMeta, s as codexCatalogHomeId } from "./session-catalog-events-Bj6j94E_.mjs";
9
7
  import { n as withCodexAppServerThreadMutation, t as isIncognitoSessionKey } from "./incognito-session-uhrBF6wJ.mjs";
10
- import { a as isCodexThreadReadMissingError, i as CodexAppServerRpcError, t as withAbortableTimeout } from "./timeout-DZF05XrR.mjs";
11
- import { t as projectBoundedCodexThreadHistory } from "./transcript-history-projection-DHNBDhCU.mjs";
12
- import { a as defaultCodexAppInventoryCache, i as CodexAppInventoryCache, o as serializeCodexAppInventoryError, s as codexAppIdentityKey, t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-BOxKP7db.mjs";
13
- import { a as codexCatalogHomeId, c as readCodexSessionMeta } from "./session-catalog-events-jMcYfQyd.mjs";
14
- import { t as assertCodexSessionRuntimeOwnership } from "./binding-connection-Bm38niE8.mjs";
15
- import "./config-CedDWjM-.mjs";
8
+ import { o as CodexAppServerRpcError, r as withAbortableTimeout, s as isCodexThreadReadMissingError } from "./timeout-C910MdAB.mjs";
9
+ import { t as projectBoundedCodexThreadHistory } from "./transcript-history-projection-ZZpkFkJ_.mjs";
10
+ import { t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-B2CsSdnV.mjs";
11
+ import { t as assertCodexSessionRuntimeOwnership } from "./binding-connection-ThoatDcb.mjs";
12
+ import "./config-BoTP_mrL.mjs";
16
13
  import { r as sanitizeInlineImageDataUrl, t as invalidInlineImageText } from "./image-payload-sanitizer-tupAr-2o.mjs";
17
- import { n as normalizeCodexAppServerBindingModelProvider, t as isCodexAppServerNativeAuthProfile } from "./auth-profile-WqZtZfXN.mjs";
18
- import { C as CodexThreadBindingConflictError, E as nativeHookRelayUnregisterQueue, G as unsubscribeCodexAppServerLiveThread, H as readCodexClientSessionMeta, L as hasCodexAppServerSiblingThreadWork, N as consumeCodexAppServerLiveThread, O as assertCodexInferenceRouteConfig, R as isCodexAppServerClientRuntimeLive, S as CodexAdoptedThreadActiveError, T as CodexThreadStartRequestError, U as releaseCodexAppServerLiveThread, _ as retainSharedCodexAppServerClientByInstanceId, j as prepareCodexInferenceThreadConfig, k as bindCodexInferenceThread, n as captureCodexAppServerClientLifetime, w as CodexThreadClientReplacementError, z as isCodexAppServerLiveThreadClaimed } from "./shared-client-BpTtuLQ5.mjs";
19
- import { a as closeCodexStartupClientBestEffort, f as unsubscribeCodexThreadBestEffort, h as hasCodexAppServerSiblingRouteWork, l as retireUnsafeCodexTurnClientBestEffort, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError, s as isCodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-BpYKdTA0.mjs";
20
- import { t as ensureCodexPluginActivation } from "./plugin-activation-r8nq5Jzp.mjs";
21
- import { o as resolveCodexSessionBinding, r as hashCodexAppServerBindingFingerprint } from "./session-binding-_0W_fHRr.mjs";
22
- import { i as refreshCodexThreadPolicy, n as CodexThreadPolicyHandoffError, r as assertCodexSupervisionThreadLineage, t as CodexIncognitoPolicyChangeError } from "./thread-policy-Cjs4B8xf.mjs";
23
- import { t as resumeCodexAppServerThread } from "./thread-resume-BkNpj9Pz.mjs";
24
- import { r as retainCodexAppServerBindingSubscription, s as withExclusiveCodexAppServerThread } from "./thread-ownership-skomxnIt.mjs";
25
- import "./transcript-mirror-D4qp_leP.mjs";
14
+ import { n as normalizeCodexAppServerBindingModelProvider } from "./auth-profile-WqZtZfXN.mjs";
15
+ import { C as CodexThreadBindingConflictError, G as unsubscribeCodexAppServerLiveThread, L as hasCodexAppServerSiblingThreadWork, N as consumeCodexAppServerLiveThread, O as assertCodexInferenceRouteConfig, R as isCodexAppServerClientRuntimeLive, S as CodexAdoptedThreadActiveError, T as CodexThreadStartRequestError, U as releaseCodexAppServerLiveThread, _ as retainSharedCodexAppServerClientByInstanceId, j as prepareCodexInferenceThreadConfig, k as bindCodexInferenceThread, n as captureCodexAppServerClientLifetime, w as CodexThreadClientReplacementError, z as isCodexAppServerLiveThreadClaimed } from "./shared-client-DA4VR4Eb.mjs";
16
+ import { d as isCodexAppServerRequestTimeoutError, l as isCodexAppServerOverloadError, p as resolveCodexAppServerClientInstanceId, r as getCodexAppServerClientInstanceId, v as assertCodexThreadAcceptsDirectInput, x as assertCodexThreadStartResponse, y as assertCodexThreadForkResponse } from "./client-Cs08OXVQ.mjs";
17
+ import { c as isCodexAppServerUnsafeSubscriptionError, g as hasCodexAppServerSiblingRouteWork, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, o as closeCodexStartupClientBestEffort, p as unsubscribeCodexThreadBestEffort, r as CodexAppServerUnsafeSubscriptionError, u as retireUnsafeCodexTurnClientBestEffort } from "./attempt-client-cleanup-CEv1cKwF.mjs";
18
+ import { $ as readActiveCodexTurnIdsFromResume, F as checkCodexThreadAppAvailability, G as areUserMcpServersFingerprintsCompatible, H as resolveCodexNativeSkillIsolation, I as discardUnattestedCodexPluginThread, J as fingerprintCodexThreadConfig, K as codexDynamicToolsFingerprint, L as attestCodexRestrictedToolSurfaceMcpServersDisabled, P as attestCodexThreadToolSurface, Q as legacyFingerprintUserMcpServersConfigPatch, R as hasCodexNativeToolCatalog, T as assertCodexNativeHookRelayAllowed, Tt as buildCodexAppApprovalOverrides, V as applyCodexNativeSkillIsolation, W as areDynamicToolFingerprintsCompatible, X as fingerprintJsonObject, Y as fingerprintEnvironmentSelection, Z as fingerprintUserMcpServersConfigPatch, _ as resolveCodexAppServerRequestModelSelection, bt as isCodexPluginThreadBindingStale, c as codexThreadSandboxOrPermissions, ct as isMessageOnlyCodexSourceReply, d as resolveCodexThreadApprovalsReviewer, et as shouldStartTransientNoToolThread, g as resolveCodexAppServerModelProvider, h as CODEX_NATIVE_PERSONALITY_NONE, i as buildCodexRuntimeThreadConfigForRun, it as shouldRotateCodexGpt56MultiAgentBinding, l as readCodexInheritedMcpServerNames, lt as isSystemAgentOnlyCodexDynamicToolAllowlist, m as buildDeveloperInstructions, n as buildCodexRingZeroThreadConfigPatch, nt as shouldRecheckRecoverablePluginBinding, o as buildThreadResumeParams, p as resolveCodexWebSearchPlan, pt as buildCodexPluginAppsConfigPatchFromPolicyContext, q as codexLegacyDynamicToolsFingerprint, rt as shouldRotateCodexAppServerBindingForRuntime, s as buildThreadStartParams, t as assertCodexManagedRequirementsDoNotOverrideToolPolicy, tt as isTransientWebSearchRestriction, u as readCodexManagedRequirementsFingerprint, v as resolveCodexAppServerThreadModelSelection, vt as buildPluginAppPolicyContext, wt as stringifyCodexPluginPolicy, x as mergeCodexNativeProjectDocThreadConfig, xt as mergeCodexThreadConfigs, yt as disableUnlistedCodexApps, z as loadCodexNativeToolCatalog } from "./thread-requests-BLvGkP2R.mjs";
19
+ import { o as resolveCodexSessionBinding, r as hashCodexAppServerBindingFingerprint } from "./session-binding-Cm0apEbd.mjs";
20
+ import { a as refreshCodexThreadPolicy, i as assertCodexSupervisionThreadLineage, n as CodexThreadPolicyHandoffError, r as assertAdoptedCodexThreadResumeAllowed, t as CodexIncognitoPolicyChangeError } from "./thread-policy-DGuQsuFC.mjs";
21
+ import { t as resumeCodexAppServerThread } from "./thread-resume-DIBXwOpE.mjs";
22
+ import { r as retainCodexAppServerBindingSubscription, s as withExclusiveCodexAppServerThread, t as isSameCodexAppServerThreadOwner } from "./thread-ownership-DcTtAcXj.mjs";
23
+ import "./transcript-mirror-BtHDBp1G.mjs";
26
24
  import { asOptionalRecord, isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
27
- import * as crypto$1 from "node:crypto";
28
- import crypto, { createHash } from "node:crypto";
25
+ import crypto from "node:crypto";
29
26
  import { isDeepStrictEqual } from "node:util";
30
27
  import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
31
- import { addTimerTimeoutGraceMs, finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
32
28
  import path from "node:path";
33
- import os from "node:os";
34
- import fs from "node:fs/promises";
35
- import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
36
- import { toErrorObject } from "openclaw/plugin-sdk/error-runtime";
37
29
  import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
38
- import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
39
- import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
40
30
  import { createStageTimingTracker, formatStageTimings } from "openclaw/plugin-sdk/time-runtime";
41
- import { isPathInside } from "openclaw/plugin-sdk/file-access-runtime";
42
31
  import { resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
43
- import { AgentHarnessPreflightError, SKILL_WORKSHOP_TOOL_NAME, buildCredentialSafetyPrompt, buildDelegationGuidanceSection, buildHarnessVisibleReplyGuidance, buildSkillWorkshopPromptSection, buildTemporalContextText, buildUiPresentationPrompt, embeddedAgentLog, formatErrorMessage as formatErrorMessage$1, isActiveHarnessContextEngine, isHostScopedAgentToolActive, isOpenClawRuntimeContextCustomMessage, resolveMainSessionDelegationMode } from "openclaw/plugin-sdk/agent-harness-runtime";
32
+ import { AgentHarnessPreflightError, buildHarnessVisibleReplyGuidance, buildTemporalContextText, embeddedAgentLog, formatErrorMessage, isActiveHarnessContextEngine, isHostScopedAgentToolActive, isOpenClawRuntimeContextCustomMessage } from "openclaw/plugin-sdk/agent-harness-runtime";
44
33
  import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
45
34
  import { IMAGE_BLOCK_TOKENS } from "openclaw/plugin-sdk/agent-core";
46
- import { resolveRequiredHomeDir, resolveStateDir } from "openclaw/plugin-sdk/state-paths";
47
35
  import { buildCodexUserMcpServersThreadConfigPatchForRun } from "openclaw/plugin-sdk/codex-mcp-projection";
48
- import { registerNativeHookRelayForBundledRuntime } from "openclaw/plugin-sdk/native-hook-relay-runtime";
49
36
  import { isDiagnosticFlagEnabled } from "openclaw/plugin-sdk/diagnostic-flags";
50
- import { listRegisteredPluginAgentPromptGuidance } from "openclaw/plugin-sdk/plugin-runtime";
51
- import { buildHostnameAllowlistPolicyFromSuffixAllowlist } from "openclaw/plugin-sdk/ssrf-policy";
52
- //#region extensions/codex/src/app-server/plugin-app-approval-overrides.ts
53
- /** Projects ask approvals into the native session layer without changing saved settings. */
54
- function buildCodexAppApprovalOverrides(config, app) {
55
- const appsRoot = config.apps;
56
- const appConfig = isJsonObject(appsRoot) ? appsRoot[app.id] : void 0;
57
- if (!isJsonObject(appConfig)) return {};
58
- const overrides = {};
59
- const keys = app.approvalOverrideToolConfigKeys;
60
- for (const [section, fields] of [["tools", { approval_mode: "auto" }], ["links", {
61
- approvals_reviewer: "user",
62
- default_tools_approval_mode: "auto"
63
- }]]) {
64
- const entries = appConfig[section];
65
- if (!isJsonObject(entries)) continue;
66
- const projected = [];
67
- for (const [name, value] of Object.entries(entries).toSorted(([left], [right]) => left.localeCompare(right))) {
68
- if (!isJsonObject(value) || section === "tools" && keys && !keys.includes(name)) continue;
69
- if (Object.keys(fields).some((field) => value[field] !== void 0 && value[field] !== null)) projected.push([name, fields]);
70
- }
71
- if (projected.length > 0) overrides[section] = Object.fromEntries(projected);
72
- }
73
- return overrides;
74
- }
75
- //#endregion
76
- //#region extensions/codex/src/app-server/plugin-thread-app-admission.ts
77
- function resolveCodexPluginThreadAppCacheKey(params) {
78
- return params.threadId ? `${params.appCacheKey}:thread:${encodeURIComponent(params.threadId)}` : params.appCacheKey;
79
- }
80
- function createCodexPluginThreadAppInventoryRequest(params) {
81
- return async (method, requestParams) => await params.request(method, (method === "app/installed" || method === "app/read") && params.threadId ? {
82
- ...requestParams,
83
- threadId: params.threadId
84
- } : requestParams);
85
- }
86
- async function refreshCodexPluginAppInventory(params, appCache, options = {}) {
87
- if (!params.appCacheKey) return;
88
- const request = createCodexPluginThreadAppInventoryRequest(params);
89
- try {
90
- return await appCache.refreshNow({
91
- key: resolveCodexPluginThreadAppCacheKey(params),
92
- request,
93
- nowMs: params.nowMs,
94
- forceRefetch: options.forceRefetch,
95
- targetAppIds: options.targetAppIds
96
- });
97
- } catch (error) {
98
- embeddedAgentLog.warn("codex plugin thread config app inventory refresh failed", {
99
- reason: options.reason,
100
- forceRefetch: options.forceRefetch === true,
101
- error: serializeCodexAppInventoryError(error)
102
- });
103
- return;
104
- }
105
- }
106
- function collectCodexPluginOwnedAppIds(inventory) {
107
- return Array.from(new Set(inventory.records.flatMap((record) => record.ownedAppIds).filter(Boolean))).toSorted();
108
- }
109
- function collectCodexReservedPluginAppIds(params) {
110
- const reserved = new Set(params.inventory.records.flatMap((record) => record.appOwnership === "proven" ? record.ownedAppIds : []).map(codexAppIdentityKey));
111
- const recordsByConfigKey = new Map(params.inventory.records.map((record) => [record.policy.configKey, record]));
112
- const configuredOwnerNames = new Set(params.policy.pluginPolicies.flatMap((policy) => {
113
- const record = recordsByConfigKey.get(policy.configKey);
114
- return [
115
- policy.configKey,
116
- policy.pluginName,
117
- record?.summary.name,
118
- record?.summary.id
119
- ].filter((name) => Boolean(name)).map(normalizeCodexPluginOwnerName);
120
- }));
121
- for (const app of params.accountApps) if (app.pluginDisplayNames.some((name) => configuredOwnerNames.has(normalizeCodexPluginOwnerName(name)))) reserved.add(codexAppIdentityKey(app.id));
122
- return reserved;
123
- }
124
- function normalizeCodexPluginOwnerName(name) {
125
- return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "");
126
- }
127
- async function readCodexThreadAdmissibleAccountApps(params, appCache) {
128
- const request = createCodexPluginThreadAppInventoryRequest(params);
129
- const cachedInventory = appCache.read({
130
- key: resolveCodexPluginThreadAppCacheKey(params),
131
- request,
132
- nowMs: params.nowMs,
133
- suppressRefresh: true
134
- });
135
- const snapshot = cachedInventory.state === "fresh" && !cachedInventory.snapshot?.targetAppIds?.length ? cachedInventory.snapshot : await refreshCodexPluginAppInventory(params, appCache, {
136
- forceRefetch: false,
137
- reason: "account_apps_all",
138
- targetAppIds: []
139
- });
140
- if (!snapshot) return {
141
- apps: [],
142
- diagnostic: {
143
- code: "account_app_inventory_unavailable",
144
- message: "Codex account app inventory was unavailable; account apps were not exposed."
145
- }
146
- };
147
- const installedAppsById = new Map(snapshot.installedApps.map((app) => [app.id, app]));
148
- return { apps: snapshot.apps.filter((app) => resolveCodexInstalledAppThreadAdmission(toCodexPluginOwnedAccountApp(app), installedAppsById.get(app.id)) !== "blocked").toSorted((left, right) => left.id.localeCompare(right.id)) };
149
- }
150
- function toCodexPluginOwnedAccountApp(app) {
151
- return {
152
- id: app.id,
153
- name: app.name,
154
- accessible: app.isAccessible,
155
- enabled: app.isEnabled,
156
- needsAuth: !app.isAccessible,
157
- ...resolveOwnedAppApprovalOverrideKeys(app)
158
- };
159
- }
160
- function resolveCodexThreadConfigAppsForRecord(params) {
161
- return params.inventory.appInventory?.state === "missing" ? [] : params.record.apps;
162
- }
163
- function resolveCodexPluginAppThreadAdmission(app, inventory) {
164
- const snapshot = inventory.appInventory?.snapshot;
165
- if (!snapshot) return "blocked";
166
- return resolveCodexInstalledAppThreadAdmission(app, snapshot.installedApps.find((candidate) => candidate.id === app.id));
167
- }
168
- function resolveCodexInstalledAppThreadAdmission(app, installed) {
169
- if (!app.accessible || app.needsAuth || !installed) return "blocked";
170
- if (installed.enabled && installed.callable) return "ready";
171
- return !installed.enabled && !installed.callable ? "provisional" : "blocked";
172
- }
173
- async function readCodexConfigForAppAdmission(params) {
174
- try {
175
- const response = await params.request("config/read", {
176
- includeLayers: true,
177
- ...params.configCwd ? { cwd: params.configCwd } : {}
178
- });
179
- if (!isJsonObject(response) || !isJsonObject(response.config) || !Array.isArray(response.layers)) throw new Error("Codex config/read omitted effective config or config layers");
180
- return {
181
- config: response.config,
182
- layers: response.layers.flatMap((layer) => {
183
- if (!isJsonObject(layer)) throw new Error("Codex config/read returned an invalid config layer");
184
- if (layer.disabledReason !== void 0 && layer.disabledReason !== null) {
185
- if (typeof layer.disabledReason !== "string") throw new Error("Codex config/read returned an invalid disabled layer");
186
- return [];
187
- }
188
- if (!isJsonObject(layer.config)) throw new Error("Codex config/read returned an invalid layer config");
189
- if (!isJsonObject(layer.name) || typeof layer.name.type !== "string") throw new Error("Codex config/read returned an invalid config layer source");
190
- if (layer.config.apps !== void 0 && !CODEX_SESSION_OVERRIDABLE_LAYER_TYPES.has(layer.name.type)) throw new Error(`Codex app policy cannot override ${layer.name.type}; move app settings to a supported user or project config layer before exposing native apps`);
191
- return [layer.config];
192
- })
193
- };
194
- } catch (error) {
195
- const details = serializeCodexAppInventoryError(error);
196
- embeddedAgentLog.warn("codex plugin app admission config read failed", { error: details });
197
- throw new Error(`Could not verify the Codex app allowlist: ${String(details.message)}. No native thread was started; resolve the native configuration error and retry.`, { cause: error });
198
- }
199
- }
200
- function resolveCodexExplicitAppEnablement(layersHighestPrecedenceFirst, appId) {
201
- for (const layer of layersHighestPrecedenceFirst) {
202
- const apps = layer.apps;
203
- const values = isJsonObject(apps) ? Object.entries(apps).filter(([id, app]) => codexAppIdentityKey(id) === codexAppIdentityKey(appId) && isJsonObject(app) && Object.hasOwn(app, "enabled")).map(([, app]) => isJsonObject(app) && app.enabled === true) : [];
204
- if (values.length > 0) return values.every(Boolean);
205
- }
206
- }
207
- function shouldForceRefreshCodexNotReadyPluginApps(params, policy, inventory) {
208
- if (!params.appCacheKey || !policy.pluginPolicies.some((plugin) => plugin.enabled) || inventory.appInventory?.state === "missing") return false;
209
- return inventory.records.some((record) => record.appOwnership === "proven" && record.ownedAppIds.length > 0 && (record.apps.length === 0 || record.apps.some((app) => !app.accessible)));
210
- }
211
- //#endregion
212
- //#region extensions/codex/src/app-server/plugin-thread-config.ts
213
- /**
214
- * Builds Codex thread config patches that expose only policy-approved apps
215
- * for native Codex turns.
216
- */
217
- const CODEX_PLUGIN_THREAD_CONFIG_INPUT_FINGERPRINT_VERSION = 7;
218
- const CODEX_PLUGIN_THREAD_CONFIG_FINGERPRINT_VERSION = 2;
219
- /** Returns true when plugin config exists and thread config may need app patches. */
220
- function shouldBuildCodexPluginThreadConfig(pluginConfig) {
221
- return resolveCodexPluginsPolicy(pluginConfig).configured;
222
- }
223
- /** Fingerprints policy and app-cache identity before runtime inventory is read. */
224
- function buildCodexPluginThreadConfigInputFingerprint(params) {
225
- const policy = resolveCodexPluginsPolicy(params.pluginConfig);
226
- return fingerprintJson({
227
- version: CODEX_PLUGIN_THREAD_CONFIG_INPUT_FINGERPRINT_VERSION,
228
- policy: policyFingerprint(policy),
229
- appCacheKey: params.appCacheKey ?? null
230
- });
231
- }
232
- /** Builds the deny-all app patch used when plugin discovery exceeds its turn budget. */
233
- function buildCodexPluginThreadConfigTimeoutFallback(params) {
234
- return {
235
- ...emptyPluginThreadConfig({
236
- enabled: true,
237
- inputFingerprint: buildCodexPluginThreadConfigInputFingerprint(params),
238
- configPatch: buildDisabledAppsConfigPatch()
239
- }),
240
- diagnostics: [{
241
- code: "plugin_config_timeout",
242
- message: params.message
243
- }]
244
- };
245
- }
246
- /** Builds the Codex apps config patch and policy context for a native thread. */
247
- async function buildCodexPluginThreadConfig(params) {
248
- const appCache = params.appCache ?? defaultCodexAppInventoryCache;
249
- const threadAppCacheKey = resolveCodexPluginThreadAppCacheKey(params);
250
- const threadRequest = (method, requestParams) => params.request(method, (method === "app/installed" || method === "app/read") && params.threadId && isJsonObject(requestParams) ? {
251
- ...requestParams,
252
- threadId: params.threadId
253
- } : requestParams);
254
- let inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
255
- pluginConfig: params.pluginConfig,
256
- appCacheKey: params.appCacheKey
257
- });
258
- const policy = resolveCodexPluginsPolicy(params.pluginConfig);
259
- if (!policy.enabled) return emptyPluginThreadConfig({
260
- enabled: false,
261
- inputFingerprint,
262
- configPatch: buildDisabledAppsConfigPatch()
263
- });
264
- let inventory = policy.pluginPolicies.length > 0 ? await readCodexPluginInventory({
265
- pluginConfig: params.pluginConfig,
266
- policy,
267
- request: threadRequest,
268
- appCache,
269
- appCacheKey: threadAppCacheKey,
270
- configCwd: params.configCwd,
271
- metadataCache: params.metadataCache,
272
- nowMs: params.nowMs,
273
- suppressAppInventoryRefresh: true
274
- }) : emptyCodexPluginInventory(policy);
275
- const appInventoryRefreshDeferredForActivation = inventory.records.some((record) => record.activationRequired) && shouldRefreshMissingAppInventory(params, policy, inventory);
276
- if (shouldWaitForInitialAppInventory(params, policy, inventory)) {
277
- await refreshCodexPluginAppInventory(params, appCache, {
278
- forceRefetch: false,
279
- reason: "initial_missing",
280
- targetAppIds: collectCodexPluginOwnedAppIds(inventory)
281
- });
282
- inventory = await readCodexPluginInventory({
283
- pluginConfig: params.pluginConfig,
284
- policy,
285
- request: threadRequest,
286
- appCache,
287
- appCacheKey: threadAppCacheKey,
288
- configCwd: params.configCwd,
289
- metadataCache: params.metadataCache,
290
- nowMs: params.nowMs
291
- });
292
- inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
293
- pluginConfig: params.pluginConfig,
294
- appCacheKey: params.appCacheKey
295
- });
296
- }
297
- const activationDiagnostics = [];
298
- const activationResults = [];
299
- for (const record of inventory.records) {
300
- if (!record.activationRequired) continue;
301
- const activation = await ensureCodexPluginActivation({
302
- identity: record.policy,
303
- request: threadRequest,
304
- appCache,
305
- appCacheKey: threadAppCacheKey,
306
- configCwd: params.configCwd,
307
- metadataCache: params.metadataCache,
308
- deferAppInventoryRefresh: true,
309
- targetAppIds: record.ownedAppIds
310
- });
311
- activationResults.push(activation);
312
- if (!activation.ok) activationDiagnostics.push({
313
- code: "plugin_activation_failed",
314
- plugin: record.policy,
315
- message: activation.diagnostics.map((item) => item.message).join(" ") || activation.reason
316
- });
317
- }
318
- const postInstallRefreshRequired = activationResults.some((activation) => activation.ok && activation.installAttempted);
319
- const deferredMissingRefreshRequired = appInventoryRefreshDeferredForActivation && !postInstallRefreshRequired && shouldRefreshMissingAppInventory(params, policy, inventory);
320
- if (postInstallRefreshRequired || deferredMissingRefreshRequired) {
321
- await refreshCodexPluginAppInventory(params, appCache, {
322
- forceRefetch: true,
323
- reason: postInstallRefreshRequired ? "post_install" : "deferred_missing",
324
- targetAppIds: collectCodexPluginOwnedAppIds(inventory)
325
- });
326
- inventory = await readCodexPluginInventory({
327
- pluginConfig: params.pluginConfig,
328
- policy,
329
- request: threadRequest,
330
- appCache,
331
- appCacheKey: threadAppCacheKey,
332
- configCwd: params.configCwd,
333
- metadataCache: params.metadataCache,
334
- nowMs: params.nowMs
335
- });
336
- inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
337
- pluginConfig: params.pluginConfig,
338
- appCacheKey: params.appCacheKey
339
- });
340
- }
341
- if (shouldForceRefreshCodexNotReadyPluginApps(params, policy, inventory)) {
342
- await refreshCodexPluginAppInventory(params, appCache, {
343
- forceRefetch: true,
344
- reason: "not_ready_plugin_apps",
345
- targetAppIds: collectCodexPluginOwnedAppIds(inventory)
346
- });
347
- inventory = await readCodexPluginInventory({
348
- pluginConfig: params.pluginConfig,
349
- policy,
350
- request: threadRequest,
351
- appCache,
352
- appCacheKey: threadAppCacheKey,
353
- configCwd: params.configCwd,
354
- metadataCache: params.metadataCache,
355
- nowMs: params.nowMs
356
- });
357
- inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
358
- pluginConfig: params.pluginConfig,
359
- appCacheKey: params.appCacheKey
360
- });
361
- }
362
- const accountAppsResult = policy.allowAllPlugins ? await readCodexThreadAdmissibleAccountApps(params, appCache) : { apps: [] };
363
- let appAdmissionConfig;
364
- const getAdmissionConfig = () => appAdmissionConfig ??= readCodexConfigForAppAdmission(params);
365
- const diagnostics = [
366
- ...inventory.diagnostics,
367
- ...activationDiagnostics,
368
- ...accountAppsResult.diagnostic ? [accountAppsResult.diagnostic] : []
369
- ];
370
- const provisionalAppIds = /* @__PURE__ */ new Set();
371
- const { apps } = buildDisabledAppsConfigPatch();
372
- const policyApps = {};
373
- const pluginAppIds = {};
374
- const pluginOwnedAppIds = collectCodexReservedPluginAppIds({
375
- policy,
376
- inventory,
377
- accountApps: accountAppsResult.apps
378
- });
379
- const unresolvedDisabledPluginOwnership = policy.allowAllPlugins ? policy.pluginPolicies.find((pluginPolicy) => {
380
- const record = inventory.records.find((candidate) => candidate.policy.configKey === pluginPolicy.configKey);
381
- const disabledByMarketplacePolicy = record?.summary.availability === "DISABLED_BY_ADMIN" || record?.summary.installPolicy === "NOT_AVAILABLE";
382
- const unresolvedPluginIdentity = !record && inventory.diagnostics.some((diagnostic) => diagnostic.plugin?.configKey === pluginPolicy.configKey && (diagnostic.code === "plugin_disabled" || diagnostic.code === "plugin_missing" || diagnostic.code === "marketplace_missing"));
383
- return (!pluginPolicy.enabled || disabledByMarketplacePolicy || unresolvedPluginIdentity) && !record?.detail;
384
- }) : void 0;
385
- if (unresolvedDisabledPluginOwnership) diagnostics.push({
386
- code: "account_app_ownership_unavailable",
387
- plugin: unresolvedDisabledPluginOwnership,
388
- message: `Could not verify disabled Codex plugin app ownership for ${unresolvedDisabledPluginOwnership.pluginName}; account apps were not exposed.`
389
- });
390
- for (const record of inventory.records) {
391
- if (!record.policy.enabled) continue;
392
- const activation = activationResults.find((item) => item.identity.configKey === record.policy.configKey);
393
- if (activation?.ok === false || record.activationRequired && !activation?.ok) continue;
394
- if (record.appOwnership !== "proven") continue;
395
- pluginAppIds[record.policy.configKey] = [...record.ownedAppIds].toSorted();
396
- for (const app of resolveCodexThreadConfigAppsForRecord({
397
- record,
398
- inventory
399
- })) {
400
- const admissionConfig = resolveCodexPluginAppThreadAdmission(app, inventory) === "blocked" ? void 0 : await getAdmissionConfig();
401
- if (!admissionConfig || resolveCodexExplicitAppEnablement(admissionConfig.layers, app.id) === false) {
402
- diagnostics.push({
403
- code: "app_not_ready",
404
- plugin: record.policy,
405
- message: `${app.id} is not accessible for ${record.policy.pluginName}.`
406
- });
407
- continue;
408
- }
409
- provisionalAppIds.add(app.id);
410
- apps[app.id] = buildEnabledAppConfig(record.policy, record.policy.destructiveApprovalMode === "ask" ? buildCodexAppApprovalOverrides(admissionConfig.config, app) : void 0);
411
- policyApps[app.id] = {
412
- configKey: record.policy.configKey,
413
- marketplaceName: record.policy.marketplaceName,
414
- pluginName: record.policy.pluginName,
415
- allowDestructiveActions: record.policy.allowDestructiveActions,
416
- allowOpenWorld: true,
417
- destructiveApprovalMode: record.policy.destructiveApprovalMode,
418
- mcpServerNames: [...record.detail?.mcpServers ?? []].toSorted()
419
- };
420
- }
421
- }
422
- for (const app of unresolvedDisabledPluginOwnership ? [] : accountAppsResult.apps) {
423
- if (pluginOwnedAppIds.has(codexAppIdentityKey(app.id))) continue;
424
- const admissionConfig = await getAdmissionConfig();
425
- if (resolveCodexExplicitAppEnablement(admissionConfig.layers, app.id) === false) continue;
426
- const accountApp = toCodexPluginOwnedAccountApp(app);
427
- provisionalAppIds.add(app.id);
428
- apps[app.id] = buildEnabledAppConfig(policy, policy.destructiveApprovalMode === "ask" ? buildCodexAppApprovalOverrides(admissionConfig.config, accountApp) : void 0);
429
- policyApps[app.id] = {
430
- source: "account",
431
- appName: app.name,
432
- allowDestructiveActions: policy.allowDestructiveActions,
433
- allowOpenWorld: true,
434
- destructiveApprovalMode: policy.destructiveApprovalMode,
435
- mcpServerNames: []
436
- };
437
- }
438
- const configPatch = Object.keys(policyApps).length === 0 ? buildDisabledAppsConfigPatch() : disableUnlistedCodexApps({ apps }, (await getAdmissionConfig()).config);
439
- const policyContext = buildPluginAppPolicyContext(policyApps, pluginAppIds);
440
- return {
441
- enabled: true,
442
- configPatch,
443
- ...provisionalAppIds.size > 0 ? { provisionalAppIds: Array.from(provisionalAppIds).toSorted() } : {},
444
- fingerprint: fingerprintJson({
445
- version: CODEX_PLUGIN_THREAD_CONFIG_FINGERPRINT_VERSION,
446
- inputFingerprint,
447
- configPatch,
448
- policyContext
449
- }),
450
- inputFingerprint,
451
- policyContext,
452
- inventory,
453
- diagnostics
454
- };
455
- }
456
- /** Deep-merges optional Codex thread config patches, returning undefined when empty. */
457
- function mergeCodexThreadConfigs(...configs) {
458
- let merged;
459
- for (const config of configs) {
460
- if (!config) continue;
461
- merged = mergeJsonObjects(merged ?? {}, config);
462
- }
463
- return merged && Object.keys(merged).length > 0 ? merged : void 0;
464
- }
465
- /** Detects when a stored thread binding no longer matches current plugin policy inputs. */
466
- function isCodexPluginThreadBindingStale(params) {
467
- if (!params.codexPluginsEnabled) return Boolean(params.bindingFingerprint || params.bindingInputFingerprint || params.hasBindingPolicyContext);
468
- if (!params.bindingFingerprint || !params.bindingInputFingerprint || !params.hasBindingPolicyContext) return true;
469
- return params.bindingInputFingerprint !== params.currentInputFingerprint;
470
- }
471
- function emptyPluginThreadConfig(params) {
472
- const policyContext = buildPluginAppPolicyContext({}, {});
473
- return {
474
- enabled: params.enabled,
475
- fingerprint: fingerprintJson({
476
- version: CODEX_PLUGIN_THREAD_CONFIG_FINGERPRINT_VERSION,
477
- inputFingerprint: params.inputFingerprint,
478
- configPatch: params.configPatch ?? null,
479
- policyContext
480
- }),
481
- inputFingerprint: params.inputFingerprint,
482
- ...params.configPatch ? { configPatch: params.configPatch } : {},
483
- policyContext,
484
- diagnostics: []
485
- };
486
- }
487
- function buildDisabledAppsConfigPatch() {
488
- return {
489
- "features.apps": false,
490
- apps: { _default: {
491
- enabled: false,
492
- destructive_enabled: false,
493
- open_world_enabled: false
494
- } }
495
- };
496
- }
497
- function disableUnlistedCodexApps(configPatch, nativeConfig) {
498
- const apps = { ...configPatch.apps };
499
- for (const id of Object.keys(isJsonObject(nativeConfig.apps) ? nativeConfig.apps : {})) if (id !== "_default" && !Object.hasOwn(apps, id)) apps[id] = { enabled: false };
500
- return {
501
- ...configPatch,
502
- apps
503
- };
504
- }
505
- function buildEnabledAppConfig(policy, approvalOverrides = {}) {
506
- return {
507
- ...approvalOverrides,
508
- enabled: true,
509
- destructive_enabled: policy.allowDestructiveActions,
510
- open_world_enabled: policy.allowOpenWorld !== false,
511
- default_tools_approval_mode: "auto",
512
- ...policy.destructiveApprovalMode === "ask" ? { approvals_reviewer: "user" } : {}
513
- };
514
- }
515
- /** Rebuilds the safe per-thread apps patch persisted with a Codex thread binding. */
516
- function buildCodexPluginAppsConfigPatchFromPolicyContext(policyContext) {
517
- const disabledConfigPatch = buildDisabledAppsConfigPatch();
518
- const { apps } = disabledConfigPatch;
519
- for (const [appId, policy] of Object.entries(policyContext.apps).toSorted(([left], [right]) => left.localeCompare(right))) apps[appId] = buildEnabledAppConfig(policy);
520
- return Object.keys(policyContext.apps).length > 0 ? { apps } : disabledConfigPatch;
521
- }
522
- /** Projects current ask overrides before a side thread replays its bound app policy. */
523
- async function refreshCodexPluginAppApprovalPolicy(params) {
524
- if (Object.keys(params.policyContext.apps).length === 0) return {
525
- policyContext: params.policyContext,
526
- configPatch: buildDisabledAppsConfigPatch(),
527
- diagnostics: []
528
- };
529
- const targetApps = Object.entries(params.policyContext.apps).filter(([, app]) => app.destructiveApprovalMode === "ask").toSorted(([left], [right]) => left.localeCompare(right));
530
- const targetAppIds = targetApps.map(([id]) => id);
531
- const diagnostics = [];
532
- const readParams = {
533
- ...params,
534
- appCacheKey: "approval-policy-replay"
535
- };
536
- const [inventory, admissionConfig] = await Promise.all([targetAppIds.length > 0 ? refreshCodexPluginAppInventory(readParams, new CodexAppInventoryCache(), { targetAppIds }) : void 0, readCodexConfigForAppAdmission(readParams)]);
537
- const configPatch = disableUnlistedCodexApps(buildCodexPluginAppsConfigPatchFromPolicyContext(params.policyContext), admissionConfig.config);
538
- const currentApps = new Map(inventory?.apps.map((app) => [app.id, toCodexPluginOwnedAccountApp(app)]));
539
- const apps = { ...params.policyContext.apps };
540
- for (const [id, policy] of targetApps) {
541
- const app = currentApps.get(id);
542
- if (!app) diagnostics.push({
543
- code: "app_not_ready",
544
- message: `Could not verify current Codex app approval policy for ${id}; the app was not exposed.`
545
- });
546
- else {
547
- configPatch.apps[id] = buildEnabledAppConfig(policy, buildCodexAppApprovalOverrides(admissionConfig.config, app));
548
- continue;
549
- }
550
- delete apps[id];
551
- configPatch.apps[id] = { enabled: false };
552
- }
553
- return {
554
- policyContext: buildPluginAppPolicyContext(apps, Object.fromEntries(Object.entries(params.policyContext.pluginAppIds).map(([key, ids]) => [key, ids.filter((id) => Object.hasOwn(apps, id))]))),
555
- configPatch,
556
- diagnostics
557
- };
558
- }
559
- function buildPluginAppPolicyContext(apps, pluginAppIds) {
560
- return {
561
- fingerprint: fingerprintJson({
562
- version: 2,
563
- apps,
564
- pluginAppIds
565
- }),
566
- apps,
567
- pluginAppIds
568
- };
569
- }
570
- function shouldWaitForInitialAppInventory(params, policy, inventory) {
571
- if (inventory.records.some((record) => record.activationRequired)) return false;
572
- return shouldRefreshMissingAppInventory(params, policy, inventory);
573
- }
574
- function shouldRefreshMissingAppInventory(params, policy, inventory) {
575
- return Boolean(params.appCacheKey && policy.pluginPolicies.some((plugin) => plugin.enabled) && inventory.appInventory?.state === "missing");
576
- }
577
- function emptyCodexPluginInventory(policy) {
578
- return {
579
- policy,
580
- records: [],
581
- diagnostics: []
582
- };
583
- }
584
- function policyFingerprint(policy) {
585
- return {
586
- enabled: policy.enabled,
587
- allowAllPlugins: policy.allowAllPlugins,
588
- allowDestructiveActions: policy.allowDestructiveActions,
589
- destructiveApprovalMode: policy.destructiveApprovalMode,
590
- plugins: policy.pluginPolicies.map((plugin) => ({
591
- configKey: plugin.configKey,
592
- marketplaceName: plugin.marketplaceName,
593
- pluginName: plugin.pluginName,
594
- enabled: plugin.enabled,
595
- allowDestructiveActions: plugin.allowDestructiveActions,
596
- destructiveApprovalMode: plugin.destructiveApprovalMode
597
- }))
598
- };
599
- }
600
- function mergeJsonObjects(left, right) {
601
- const merged = {
602
- ...left,
603
- ...right
604
- };
605
- for (const [key, value] of Object.entries(right)) {
606
- const existing = left[key];
607
- if (Object.hasOwn(left, key) && isJsonObject(existing) && isJsonObject(value)) merged[key] = mergeJsonObjects(existing, value);
608
- }
609
- return merged;
37
+ //#region extensions/codex/src/app-server/reasoning-effort.ts
38
+ const CODEX_REASONING_EFFORTS = [
39
+ "minimal",
40
+ "low",
41
+ "medium",
42
+ "high",
43
+ "xhigh",
44
+ "max"
45
+ ];
46
+ const LEGACY_PRO_REASONING_EFFORTS = [
47
+ "medium",
48
+ "high",
49
+ "xhigh"
50
+ ];
51
+ const LEGACY_PRO_MODEL_ID_RE = /^gpt-5\.[45]-pro$/u;
52
+ const MODERN_GPT_5_MODEL_ID_RE = /^gpt-5\.(?:[3-9]|[1-9]\d)(?:$|-)/u;
53
+ /** Read reasoning metadata after the Codex app-server route has been selected. */
54
+ function readCodexSupportedReasoningEfforts(compat) {
55
+ return compat && "supportedReasoningEfforts" in compat ? compat.supportedReasoningEfforts : void 0;
610
56
  }
611
- function fingerprintJson(value) {
612
- return crypto.createHash("sha256").update(stringifyCodexPluginPolicy(value)).digest("hex");
57
+ function resolveSupportedReasoningEffort(params) {
58
+ const declared = new Set(params.supportedReasoningEfforts.map((effort) => effort.trim().toLowerCase()));
59
+ const supported = CODEX_REASONING_EFFORTS.filter((effort) => declared.has(effort));
60
+ if (supported.includes(params.requested)) return params.requested;
61
+ const requestedRank = CODEX_REASONING_EFFORTS.indexOf(params.requested);
62
+ return supported.find((effort) => CODEX_REASONING_EFFORTS.indexOf(effort) >= requestedRank) ?? supported.at(-1);
613
63
  }
614
- function stringifyCodexPluginPolicy(value) {
615
- if (Array.isArray(value)) return `[${value.map((item) => stringifyCodexPluginPolicy(item)).join(",")}]`;
616
- if (value && typeof value === "object") return `{${Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stringifyCodexPluginPolicy(item)}`).join(",")}}`;
617
- return JSON.stringify(value);
64
+ function resolveCodexAppServerReasoningEffort(params) {
65
+ if (params.thinkLevel === "ultra") return "ultra";
66
+ if (params.thinkLevel === "off") return params.supportedReasoningEfforts?.includes("none") ? "none" : null;
67
+ if (params.thinkLevel === "adaptive") return null;
68
+ const modelId = params.modelId.trim().toLowerCase();
69
+ const supportedReasoningEfforts = params.supportedReasoningEfforts ?? (LEGACY_PRO_MODEL_ID_RE.test(modelId) ? LEGACY_PRO_REASONING_EFFORTS : void 0);
70
+ if (supportedReasoningEfforts) return resolveSupportedReasoningEffort({
71
+ requested: params.thinkLevel,
72
+ supportedReasoningEfforts
73
+ }) ?? null;
74
+ if (params.thinkLevel === "minimal" && MODERN_GPT_5_MODEL_ID_RE.test(modelId)) return "low";
75
+ return params.thinkLevel === "max" ? null : params.thinkLevel;
618
76
  }
619
77
  //#endregion
620
78
  //#region extensions/codex/src/app-server/context-engine-projection.ts
@@ -882,11 +340,13 @@ async function renderMessagesForCodexContext(messages, options) {
882
340
  function renderMessageBody(message, options) {
883
341
  if (message.role === "compactionSummary" || message.role === "branchSummary") return truncateText(message.summary.trim(), options.maxTextPartChars);
884
342
  if (!hasMessageContent(message)) return "";
885
- if (typeof message.content === "string") return truncateText(message.content.trim(), options.maxTextPartChars);
886
- if (!Array.isArray(message.content)) return "[non-text content omitted]";
887
- return message.content.map((part) => renderMessagePart(part, options)).filter((value) => value.length > 0).join("\n").trim();
343
+ const toolResult = message.role === "toolResult";
344
+ const toolResultLabel = toolResult && message.toolCallId ? `tool result: ${message.toolCallId}` : "tool result";
345
+ if (toolResult && options.toolPayloadMode === "elide") return `${toolResultLabel} [content omitted]`;
346
+ const body = typeof message.content === "string" ? truncateText(message.content.trim(), options.maxTextPartChars) : Array.isArray(message.content) ? message.content.map((part) => renderMessagePart(part, options, toolResult)).filter((value) => value.length > 0).join("\n").trim() : "[non-text content omitted]";
347
+ return toolResult ? redactToolPayloadText(`${toolResultLabel}${message.toolName ? ` (${message.toolName})` : ""}\n${body}`) : body;
888
348
  }
889
- function renderMessagePart(part, options) {
349
+ function renderMessagePart(part, options, toolResultBody) {
890
350
  if (!part || typeof part !== "object") return "";
891
351
  const record = part;
892
352
  const type = typeof record.type === "string" ? record.type : void 0;
@@ -899,7 +359,7 @@ function renderMessagePart(part, options) {
899
359
  }
900
360
  if (type === "toolResult" || type === "tool_result") {
901
361
  const label = typeof record.toolUseId === "string" ? `tool result: ${record.toolUseId}` : "tool result";
902
- if (options.toolPayloadMode === "preserve") return truncateText(`${label}\n${stableJson(renderToolResultPayload(record))}`, options.maxTextPartChars);
362
+ if (options.toolPayloadMode === "preserve") return truncateText(`${toolResultBody ? "" : `${label}\n`}${stableJson(renderToolResultPayload(record))}`, options.maxTextPartChars);
903
363
  return `${label} [content omitted]`;
904
364
  }
905
365
  return `[${type ?? "non-text"} content omitted]`;
@@ -1040,1003 +500,37 @@ function buildContextEngineBinding(params, projection) {
1040
500
  contextTokenBudget: params.contextTokenBudget,
1041
501
  projectionMaxChars: resolveCodexContextEngineProjectionMaxChars({
1042
502
  contextTokenBudget: params.contextTokenBudget,
1043
- reserveTokens: resolveCodexContextEngineProjectionReserveTokens()
1044
- })
1045
- }),
1046
- projection: projection ? buildContextEngineProjectionBinding(projection) : void 0
1047
- };
1048
- }
1049
- function buildContextEngineProjectionBinding(projection) {
1050
- return {
1051
- schemaVersion: 1,
1052
- mode: "thread_bootstrap",
1053
- epoch: projection.epoch,
1054
- fingerprint: projection.fingerprint
1055
- };
1056
- }
1057
- function isContextEngineBindingCompatible(previous, next) {
1058
- return previous?.schemaVersion === next.schemaVersion && previous.engineId === next.engineId && previous.policyFingerprint === next.policyFingerprint && areContextEngineProjectionBindingsCompatible(previous.projection, next.projection);
1059
- }
1060
- function areContextEngineProjectionBindingsCompatible(previous, next) {
1061
- if (!next) return previous === void 0;
1062
- return previous?.schemaVersion === next.schemaVersion && previous.mode === next.mode && previous.epoch === next.epoch && previous.fingerprint === next.fingerprint;
1063
- }
1064
- function resolveContextEngineCitationsMode(config) {
1065
- const rootConfig = isRecord(config) ? config : void 0;
1066
- const citations = (isRecord(rootConfig?.memory) ? rootConfig.memory : void 0)?.citations;
1067
- return isJsonConfigValue(citations) ? citations : void 0;
1068
- }
1069
- function isJsonConfigValue(value) {
1070
- if (value === null || typeof value === "string" || typeof value === "boolean") return true;
1071
- if (typeof value === "number") return Number.isFinite(value);
1072
- if (Array.isArray(value)) return value.every(isJsonConfigValue);
1073
- return isRecord(value) && Object.values(value).every(isJsonConfigValue);
1074
- }
1075
- //#endregion
1076
- //#region extensions/codex/src/app-server/dynamic-tool-profile.ts
1077
- /** Tool names owned by Codex app-server and normally excluded from OpenClaw dynamic tools. */
1078
- const CODEX_APP_SERVER_OWNED_DYNAMIC_TOOL_EXCLUDES = [
1079
- "read",
1080
- "write",
1081
- "edit",
1082
- "apply_patch",
1083
- "exec",
1084
- "process",
1085
- "update_plan",
1086
- "tool_call",
1087
- "tool_describe",
1088
- "tool_search",
1089
- "tool_search_code"
1090
- ];
1091
- const CODEX_NATIVE_GOAL_TOOL_EXCLUDES = [
1092
- "get_goal",
1093
- "create_goal",
1094
- "update_goal"
1095
- ];
1096
- const CODEX_APP_SERVER_OWNED_REPLACEABLE_TOOL_EXCLUDES = /* @__PURE__ */ new Set([
1097
- "read",
1098
- "write",
1099
- "edit",
1100
- "apply_patch",
1101
- ...CODEX_NATIVE_GOAL_TOOL_EXCLUDES
1102
- ]);
1103
- const CODEX_APP_SERVER_OWNED_SHELL_TOOL_EXCLUDES = /* @__PURE__ */ new Set(["exec", "process"]);
1104
- const DYNAMIC_TOOL_NAME_ALIASES = {
1105
- bash: "exec",
1106
- "apply-patch": "apply_patch"
1107
- };
1108
- /** Normalizes OpenClaw/Codex tool names before filtering and allowlist checks. */
1109
- function normalizeCodexDynamicToolName(name) {
1110
- const normalized = name.trim().toLowerCase();
1111
- return DYNAMIC_TOOL_NAME_ALIASES[normalized] ?? normalized;
1112
- }
1113
- /** True only for the host-scoped OpenClaw run's exact tool contract. */
1114
- function isSystemAgentOnlyCodexDynamicToolAllowlist(toolsAllow) {
1115
- return toolsAllow?.length === 1 && normalizeCodexDynamicToolName(toolsAllow[0] ?? "") === "openclaw";
1116
- }
1117
- /** True when a private source reply may use the message delivery tool only. */
1118
- function isMessageOnlyCodexSourceReply(params) {
1119
- return params.sourceReplyDeliveryMode === "message_tool_only" && params.toolsAllow?.length === 1 && normalizeCodexDynamicToolName(params.toolsAllow[0] ?? "") === "message";
1120
- }
1121
- /** Returns true for private QA runs that force the Codex runtime profile. */
1122
- function isForcedPrivateQaCodexRuntime(env = process.env) {
1123
- return env.OPENCLAW_BUILD_PRIVATE_QA === "1" && env.OPENCLAW_QA_FORCE_RUNTIME?.trim().toLowerCase() === "codex";
1124
- }
1125
- /** Resolves whether dynamic tools load directly or through Codex tool search. */
1126
- function resolveCodexDynamicToolsLoading(config, env = process.env) {
1127
- return isForcedPrivateQaCodexRuntime(env) ? "direct" : config.codexDynamicToolsLoading ?? "searchable";
1128
- }
1129
- function normalizeCodexModelId(modelId) {
1130
- const normalized = modelId?.trim().toLowerCase();
1131
- if (!normalized) return "";
1132
- return normalized.includes("/") ? normalized.split("/").at(-1) : normalized;
1133
- }
1134
- /** Returns true when model behavior requires direct dynamic-tool registration. */
1135
- function shouldUseDirectCodexDynamicToolsForModel(modelId) {
1136
- return shouldDisableCodexToolSearchForModel(modelId);
1137
- }
1138
- /** Returns true for models whose tool-search path is unsupported or inefficient. */
1139
- function shouldDisableCodexToolSearchForModel(modelId) {
1140
- return normalizeCodexModelId(modelId) === "gpt-5.4-nano";
1141
- }
1142
- /** Resolves dynamic-tool loading after applying model-specific restrictions. */
1143
- function resolveCodexDynamicToolsLoadingForModel(config, modelId, env = process.env) {
1144
- const loading = resolveCodexDynamicToolsLoading(config, env);
1145
- return loading === "searchable" && shouldUseDirectCodexDynamicToolsForModel(modelId) ? "direct" : loading;
1146
- }
1147
- /** Resolves dynamic-tool loading for the app-server connection that will execute the turn. */
1148
- function resolveCodexDynamicToolsLoadingForRuntime(config, modelId, options = {}, env = process.env) {
1149
- const loading = resolveCodexDynamicToolsLoadingForModel(config, modelId, env);
1150
- return loading === "searchable" && options.connectionClass === "remote" ? "direct" : loading;
1151
- }
1152
- /** Filters OpenClaw tools that Codex owns natively or config explicitly excludes. */
1153
- function filterCodexDynamicTools(tools, config, env = process.env) {
1154
- return filterCodexDynamicToolsWithOptions(tools, config, env, {
1155
- preserveOpenClawReplacements: false,
1156
- preserveOpenClawShell: false
1157
- });
1158
- }
1159
- /** Keeps OpenClaw coding tools that replace a disabled Codex native surface. */
1160
- function filterCodexDynamicToolsForDisabledNativeSurface(tools, config, options, env = process.env) {
1161
- return filterCodexDynamicToolsWithOptions(tools, config, env, {
1162
- preserveOpenClawReplacements: true,
1163
- preserveOpenClawShell: options.preserveShell
1164
- });
1165
- }
1166
- function filterCodexDynamicToolsWithOptions(tools, config, env, options) {
1167
- const excludes = /* @__PURE__ */ new Set();
1168
- if (!options.preserveOpenClawReplacements) for (const name of CODEX_NATIVE_GOAL_TOOL_EXCLUDES) excludes.add(name);
1169
- if (isForcedPrivateQaCodexRuntime(env)) excludes.add("apply_patch");
1170
- else for (const name of CODEX_APP_SERVER_OWNED_DYNAMIC_TOOL_EXCLUDES) {
1171
- if (options.preserveOpenClawReplacements && CODEX_APP_SERVER_OWNED_REPLACEABLE_TOOL_EXCLUDES.has(name)) continue;
1172
- if (options.preserveOpenClawShell && CODEX_APP_SERVER_OWNED_SHELL_TOOL_EXCLUDES.has(name)) continue;
1173
- excludes.add(name);
1174
- }
1175
- for (const name of config.codexDynamicToolsExclude ?? []) {
1176
- const trimmed = normalizeCodexDynamicToolName(name);
1177
- if (trimmed) excludes.add(trimmed);
1178
- }
1179
- return excludes.size === 0 ? tools : tools.filter((tool) => !excludes.has(normalizeCodexDynamicToolName(tool.name)));
1180
- }
1181
- //#endregion
1182
- //#region extensions/codex/src/app-server/thread-binding-policy.ts
1183
- function shouldRotateCodexAppServerBindingForRuntime(params) {
1184
- if (!params.current) return false;
1185
- if (params.binding === params.current) return false;
1186
- return params.connectionClass === "remote" || Boolean(params.binding);
1187
- }
1188
- function resolveCodexGpt56MultiAgentVersion(modelRef) {
1189
- let modelId = modelRef?.trim().toLowerCase();
1190
- if (!modelId) return;
1191
- const slashIndex = modelId.indexOf("/");
1192
- if (slashIndex > 0) {
1193
- const provider = modelId.slice(0, slashIndex);
1194
- if (provider !== "openai" && provider !== "codex") return;
1195
- modelId = modelId.slice(slashIndex + 1);
1196
- }
1197
- if (modelId === "gpt-5.6-sol" || modelId === "gpt-5.6-terra") return "v2";
1198
- return modelId === "gpt-5.6-luna" ? "v1" : void 0;
1199
- }
1200
- function shouldRotateCodexGpt56MultiAgentBinding(params) {
1201
- const bindingVersion = resolveCodexGpt56MultiAgentVersion(params.bindingModel);
1202
- const requestedVersion = resolveCodexGpt56MultiAgentVersion(params.requestedModel);
1203
- return Boolean(bindingVersion && requestedVersion && bindingVersion !== requestedVersion);
1204
- }
1205
- function isTransientWebSearchRestriction(params) {
1206
- if (params.nativeProviderWebSearchSupport === "unknown") return true;
1207
- if (params.params.config?.tools?.web?.search?.enabled === false) return false;
1208
- if (params.params.disableTools === true) return true;
1209
- const persistentWebSearchRestriction = params.webSearchAllowed === false && params.persistentWebSearchAllowed === false;
1210
- if (params.nativeCodeModeEnabled === false && !persistentWebSearchRestriction) return true;
1211
- if (params.webSearchAllowed !== false) return false;
1212
- if (params.persistentWebSearchAllowed !== void 0) return params.persistentWebSearchAllowed;
1213
- if (params.params.toolsAllow === void 0) return false;
1214
- return !params.params.toolsAllow.some((name) => {
1215
- const normalized = normalizeCodexDynamicToolName(name);
1216
- return normalized === "*" || normalized === "web_search";
1217
- });
1218
- }
1219
- function shouldRecheckRecoverablePluginBinding(params) {
1220
- if (!params.pluginThreadConfig?.enabled) return false;
1221
- if (!params.binding.pluginAppsFingerprint || !params.binding.pluginAppsInputFingerprint || params.binding.pluginAppsInputFingerprint !== params.pluginThreadConfig.inputFingerprint) return false;
1222
- const policyContext = params.binding.pluginAppPolicyContext;
1223
- if (!policyContext) return false;
1224
- const enabledPluginConfigKeys = params.pluginThreadConfig.enabledPluginConfigKeys ?? [];
1225
- const recoverablePluginConfigKeys = params.pluginThreadConfig.recoverablePluginConfigKeys ?? enabledPluginConfigKeys;
1226
- const recoverablePluginConfigKeySet = new Set(recoverablePluginConfigKeys);
1227
- const bindingContainsSettledPlugin = enabledPluginConfigKeys.filter((configKey) => !recoverablePluginConfigKeySet.has(configKey)).some((configKey) => (policyContext.pluginAppIds[configKey]?.length ?? 0) > 0 || Object.values(policyContext.apps).some((app) => app.source !== "account" && app.configKey === configKey));
1228
- const accountAppRecoveryEnabled = params.pluginThreadConfig.accountAppRecoveryEnabled ?? enabledPluginConfigKeys.length === 0;
1229
- return bindingContainsSettledPlugin || accountAppRecoveryEnabled && Object.keys(policyContext.apps).length === 0 || recoverablePluginConfigKeys.length > 0;
1230
- }
1231
- //#endregion
1232
- //#region extensions/codex/src/app-server/thread-fingerprints.ts
1233
- function codexDynamicToolsFingerprint(dynamicTools) {
1234
- return hashCodexAppServerBindingFingerprint(legacyFingerprintDynamicTools(dynamicTools));
1235
- }
1236
- function codexLegacyDynamicToolsFingerprint(dynamicTools) {
1237
- return legacyFingerprintDynamicTools(dynamicTools);
1238
- }
1239
- function areCodexDynamicToolFingerprintsCompatible(params) {
1240
- return areDynamicToolFingerprintsCompatible(params.previous, params.next, params.nextLegacy);
1241
- }
1242
- function legacyFingerprintDynamicTools(dynamicTools) {
1243
- return JSON.stringify(dynamicTools.map(stabilizeJsonValue).toSorted(compareJsonFingerprint));
1244
- }
1245
- function legacyFingerprintUserMcpServersConfigPatch(configPatch) {
1246
- return configPatch ? JSON.stringify(stabilizeJsonValue(configPatch)) : void 0;
1247
- }
1248
- function fingerprintUserMcpServersConfigPatch(configPatch) {
1249
- return configPatch ? hashCodexAppServerBindingFingerprint(JSON.stringify(stabilizeJsonValue(redactUserMcpServersFingerprintSecrets(configPatch)))) : void 0;
1250
- }
1251
- function redactUserMcpServersFingerprintSecrets(value) {
1252
- if (Array.isArray(value)) return value.map(redactUserMcpServersFingerprintSecrets);
1253
- if (!value || typeof value !== "object") return value;
1254
- return Object.fromEntries(Object.entries(value).map(([key, entry]) => {
1255
- if (key === "http_headers" && entry && typeof entry === "object" && !Array.isArray(entry)) return [key, Object.fromEntries(Object.entries(entry).map(([header, headerValue]) => [header, header.toLowerCase() === "authorization" ? fingerprintUserMcpServersAuthorizationHeader(headerValue) : headerValue]))];
1256
- return [key, redactUserMcpServersFingerprintSecrets(entry)];
1257
- }));
1258
- }
1259
- function fingerprintUserMcpServersAuthorizationHeader(value) {
1260
- return typeof value === "string" && value.length > 0 ? `<redacted:sha256:${crypto$1.createHash("sha256").update(value).digest("hex")}>` : "<redacted>";
1261
- }
1262
- function fingerprintJsonObject(value) {
1263
- return JSON.stringify(stabilizeJsonValue(value));
1264
- }
1265
- /** Hash thread-creation identity; settings already applied by turn/start must not restart Codex. */
1266
- function fingerprintCodexThreadConfig(request, authProfileId, dynamicToolsFingerprint) {
1267
- return hashCodexAppServerBindingFingerprint(fingerprintJsonObject({
1268
- authProfileId: authProfileId ?? null,
1269
- dynamicToolsFingerprint: dynamicToolsFingerprint ?? null,
1270
- nativeMultiAgentVersion: resolveCodexGpt56MultiAgentVersion(typeof request.requestedModel === "string" ? request.requestedModel : typeof request.model === "string" ? request.model : void 0) ?? null,
1271
- modelProvider: request.modelProvider ?? null,
1272
- requestedModelProvider: request.requestedModelProvider === void 0 ? request.modelProvider ?? null : request.requestedModelProvider,
1273
- permissions: request.permissions ?? null,
1274
- baseInstructions: request.baseInstructions ?? null,
1275
- developerInstructions: request.developerInstructions ?? null,
1276
- config: request.config ?? {}
1277
- }));
1278
- }
1279
- function fingerprintEnvironmentSelection(environments) {
1280
- return environments ? JSON.stringify(environments.map(stabilizeJsonValue)) : void 0;
1281
- }
1282
- function stabilizeJsonValue(value) {
1283
- if (Array.isArray(value)) return value.map(stabilizeJsonValue);
1284
- if (!isJsonObject(value)) return value;
1285
- return Object.fromEntries(Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, child]) => [key, stabilizeJsonValue(child)]));
1286
- }
1287
- function readActiveCodexTurnIds(thread) {
1288
- return (thread.turns ?? []).filter((turn) => turn.status === "inProgress").map((turn) => typeof turn.id === "string" ? turn.id : "").filter((turnId) => turnId.trim().length > 0);
1289
- }
1290
- function readActiveCodexTurnIdsFromResume(response) {
1291
- const pagedTurns = response.initialTurnsPage?.data;
1292
- return readActiveCodexTurnIds(Array.isArray(pagedTurns) ? { turns: pagedTurns } : response.thread);
1293
- }
1294
- const LEGACY_EMPTY_DYNAMIC_TOOLS_FINGERPRINT = legacyFingerprintDynamicTools([]);
1295
- const EMPTY_DYNAMIC_TOOLS_FINGERPRINT = hashCodexAppServerBindingFingerprint(LEGACY_EMPTY_DYNAMIC_TOOLS_FINGERPRINT);
1296
- function areDynamicToolFingerprintsCompatible(previous, next, nextLegacy) {
1297
- return !previous || previous === next || previous === nextLegacy;
1298
- }
1299
- function areUserMcpServersFingerprintsCompatible(params) {
1300
- return params.previous === params.next || params.previous === params.nextLegacy || params.nextLegacy !== void 0 && params.previous === hashCodexAppServerBindingFingerprint(params.nextLegacy);
1301
- }
1302
- function shouldStartTransientNoToolThread(params) {
1303
- return Boolean(params.previous && !isEmptyDynamicToolsFingerprint(params.previous) && !params.nextHasDynamicTools);
1304
- }
1305
- function isEmptyDynamicToolsFingerprint(fingerprint) {
1306
- return fingerprint === EMPTY_DYNAMIC_TOOLS_FINGERPRINT || fingerprint === LEGACY_EMPTY_DYNAMIC_TOOLS_FINGERPRINT;
1307
- }
1308
- function compareJsonFingerprint(left, right) {
1309
- return JSON.stringify(left).localeCompare(JSON.stringify(right));
1310
- }
1311
- //#endregion
1312
- //#region extensions/codex/src/app-server/native-skill-isolation.ts
1313
- const MAX_PERSONAL_SKILL_DIRECTORIES = 2e3;
1314
- const MAX_PERSONAL_SKILL_DEPTH = 6;
1315
- const MAX_PERSONAL_SKILL_ENTRIES = 1e4;
1316
- const nativeSkillIsolationByClient = /* @__PURE__ */ new WeakMap();
1317
- function isMissingPathError(error) {
1318
- return error.code === "ENOENT";
1319
- }
1320
- async function canonicalizeExistingPath(candidate) {
1321
- try {
1322
- return await fs.realpath(candidate);
1323
- } catch {
1324
- return path.resolve(candidate);
1325
- }
1326
- }
1327
- async function usesDefaultStateDir() {
1328
- if (!process.env.OPENCLAW_STATE_DIR?.trim()) return true;
1329
- const home = resolveRequiredHomeDir();
1330
- const [stateDir, defaultStateDir] = await Promise.all([canonicalizeExistingPath(resolveStateDir()), canonicalizeExistingPath(path.join(home, ".openclaw"))]);
1331
- return stateDir === defaultStateDir;
1332
- }
1333
- async function collectPersonalSkillRealPaths(homes, codexHome) {
1334
- const realStateDir = await canonicalizeExistingPath(resolveStateDir());
1335
- const roots = [];
1336
- for (const home of homes) {
1337
- for (const dir of [".agents", ".claude"]) roots.push({
1338
- dir: path.join(home, dir, "skills"),
1339
- onlyEscapedStateTargets: false
1340
- });
1341
- const defaultCodexHome = path.join(home, ".codex");
1342
- const realDefaultCodexHome = await canonicalizeExistingPath(defaultCodexHome);
1343
- roots.push({
1344
- dir: path.join(defaultCodexHome, "skills"),
1345
- onlyEscapedStateTargets: isPathInside(realStateDir, realDefaultCodexHome)
1346
- });
1347
- }
1348
- const configuredCodexHome = codexHome?.trim() || process.env.CODEX_HOME?.trim();
1349
- if (configuredCodexHome) {
1350
- const realCodexHome = await canonicalizeExistingPath(configuredCodexHome);
1351
- const stateOwned = isPathInside(realStateDir, realCodexHome);
1352
- roots.push({
1353
- dir: path.join(configuredCodexHome, "skills"),
1354
- onlyEscapedStateTargets: stateOwned
1355
- });
1356
- }
1357
- const skillPaths = /* @__PURE__ */ new Set();
1358
- let complete = true;
1359
- const seenDirectories = /* @__PURE__ */ new Set();
1360
- const queue = roots.map((root) => ({
1361
- dir: root.dir,
1362
- onlyEscapedStateTargets: root.onlyEscapedStateTargets,
1363
- depth: 0
1364
- }));
1365
- let entryCount = 0;
1366
- const recordSkillFile = async (filePath, onlyEscapedStateTargets) => {
1367
- try {
1368
- const skillRealPath = await fs.realpath(filePath);
1369
- if (!onlyEscapedStateTargets || !isPathInside(realStateDir, skillRealPath)) skillPaths.add(skillRealPath);
1370
- } catch (error) {
1371
- if (!isMissingPathError(error)) complete = false;
1372
- }
1373
- };
1374
- for (const current of queue) {
1375
- let realDir;
1376
- try {
1377
- realDir = await fs.realpath(current.dir);
1378
- } catch (error) {
1379
- if (isMissingPathError(error)) continue;
1380
- complete = false;
1381
- continue;
1382
- }
1383
- if (seenDirectories.has(realDir)) continue;
1384
- seenDirectories.add(realDir);
1385
- if (seenDirectories.size > MAX_PERSONAL_SKILL_DIRECTORIES) {
1386
- complete = false;
1387
- break;
1388
- }
1389
- let directory;
1390
- try {
1391
- directory = await fs.opendir(current.dir);
1392
- } catch (error) {
1393
- if (!isMissingPathError(error)) complete = false;
1394
- continue;
1395
- }
1396
- try {
1397
- for await (const entry of directory) {
1398
- entryCount += 1;
1399
- if (entryCount > MAX_PERSONAL_SKILL_ENTRIES) {
1400
- complete = false;
1401
- queue.length = 0;
1402
- break;
1403
- }
1404
- if (entry.name.startsWith(".")) continue;
1405
- const entryPath = path.join(current.dir, entry.name);
1406
- if (entry.name === "SKILL.md" && entry.isFile()) {
1407
- await recordSkillFile(entryPath, current.onlyEscapedStateTargets);
1408
- continue;
1409
- }
1410
- if (entry.isSymbolicLink()) {
1411
- try {
1412
- const stat = await fs.stat(entryPath);
1413
- if (entry.name === "SKILL.md" && stat.isFile()) await recordSkillFile(entryPath, current.onlyEscapedStateTargets);
1414
- else if (stat.isDirectory()) {
1415
- if (current.depth < MAX_PERSONAL_SKILL_DEPTH) queue.push({
1416
- dir: entryPath,
1417
- depth: current.depth + 1,
1418
- onlyEscapedStateTargets: current.onlyEscapedStateTargets
1419
- });
1420
- else complete = false;
1421
- }
1422
- } catch (error) {
1423
- if (!isMissingPathError(error)) complete = false;
1424
- }
1425
- continue;
1426
- }
1427
- if (current.depth >= MAX_PERSONAL_SKILL_DEPTH) {
1428
- if (entry.isDirectory()) complete = false;
1429
- continue;
1430
- }
1431
- if (entry.isDirectory()) {
1432
- queue.push({
1433
- dir: entryPath,
1434
- depth: current.depth + 1,
1435
- onlyEscapedStateTargets: current.onlyEscapedStateTargets
1436
- });
1437
- continue;
1438
- }
1439
- }
1440
- } catch (error) {
1441
- if (!isMissingPathError(error)) complete = false;
1442
- }
1443
- }
1444
- return {
1445
- complete,
1446
- skillPaths
1447
- };
1448
- }
1449
- /** Resolves the native user-scope skills that an isolated OpenClaw thread must disable. */
1450
- async function resolveCodexNativeSkillIsolation(params) {
1451
- params.signal?.throwIfAborted();
1452
- if (!process.env.OPENCLAW_STATE_DIR?.trim()) return;
1453
- const key = JSON.stringify([
1454
- path.resolve(resolveStateDir()),
1455
- path.resolve(params.cwd),
1456
- params.codexHome?.trim() || process.env.CODEX_HOME?.trim() || "",
1457
- params.home?.trim() || process.env.HOME?.trim() || "",
1458
- params.userProfile?.trim() || process.env.USERPROFILE?.trim() || ""
1459
- ]);
1460
- const cached = nativeSkillIsolationByClient.get(params.client);
1461
- if (cached?.key === key && (cached.settled || cached.signal === params.signal)) {
1462
- const isolation = await cached.result;
1463
- params.signal?.throwIfAborted();
1464
- return isolation;
1465
- }
1466
- const result = resolveUncachedCodexNativeSkillIsolation(params);
1467
- const entry = {
1468
- key,
1469
- result,
1470
- settled: false,
1471
- signal: params.signal
1472
- };
1473
- nativeSkillIsolationByClient.set(params.client, entry);
1474
- try {
1475
- const isolation = await result;
1476
- entry.settled = true;
1477
- params.signal?.throwIfAborted();
1478
- return isolation;
1479
- } catch (error) {
1480
- if (nativeSkillIsolationByClient.get(params.client)?.result === result) nativeSkillIsolationByClient.delete(params.client);
1481
- throw error;
1482
- }
1483
- }
1484
- async function resolveUncachedCodexNativeSkillIsolation(params) {
1485
- if (await usesDefaultStateDir()) return;
1486
- const response = await params.client.request("skills/list", {
1487
- cwds: [params.cwd],
1488
- forceReload: true
1489
- }, { signal: params.signal });
1490
- const homes = [params.home?.trim() || process.env.HOME?.trim() || process.env.USERPROFILE?.trim() || os.homedir()];
1491
- if (process.platform === "win32") homes.push(params.userProfile?.trim() || os.homedir());
1492
- const personalSkills = await collectPersonalSkillRealPaths([...new Set(homes.map((home) => path.resolve(home)))], params.codexHome);
1493
- return { disabledUserSkillPaths: [...personalSkills.complete ? personalSkills.skillPaths : /* @__PURE__ */ new Set([...personalSkills.skillPaths, ...response.data.flatMap((entry) => entry.skills.filter((skill) => skill.scope === "user").map((skill) => skill.path))])].toSorted((left, right) => left.localeCompare(right)) };
1494
- }
1495
- /** Applies path-exact session rules after caller config so isolated user skills stay disabled. */
1496
- function applyCodexNativeSkillIsolation(config, isolation) {
1497
- if (!isolation) return config;
1498
- const existingRules = config?.["skills.config"];
1499
- if (existingRules !== void 0 && !Array.isArray(existingRules)) throw new Error("Codex thread skills.config must be an array");
1500
- const disabledRules = isolation.disabledUserSkillPaths.map((skillPath) => ({
1501
- path: skillPath,
1502
- enabled: false
1503
- }));
1504
- return {
1505
- ...config,
1506
- "skills.include_instructions": false,
1507
- "skills.config": [...existingRules ?? [], ...disabledRules]
1508
- };
1509
- }
1510
- //#endregion
1511
- //#region extensions/codex/src/app-server/native-tool-catalog.ts
1512
- function hasCodexNativeToolCatalog(binding) {
1513
- return binding?.connectionScope === "supervision" && !binding.pendingSupervisionBranch;
1514
- }
1515
- /** Pinned serde omits empty catalogs and false deferLoading; declarations remain native-owned. */
1516
- function parseCodexNativeToolCatalog(metadata, threadId, fingerprint) {
1517
- const fail = () => /* @__PURE__ */ new Error("The canonical Codex native tool catalog is missing, corrupt, or changed; the thread is preserved. Reconnect and inspect its native metadata before retrying.");
1518
- if (!isJsonObject(metadata) || metadata.id !== threadId) throw fail();
1519
- const catalog = metadata.dynamic_tools ?? [];
1520
- if (!Array.isArray(catalog) || Buffer.byteLength(JSON.stringify(catalog)) > 1048576) throw fail();
1521
- const names = /* @__PURE__ */ new Set();
1522
- const namespaces = /* @__PURE__ */ new Set();
1523
- const validName = (name) => typeof name === "string" && /^[a-zA-Z0-9_-]{1,128}$/u.test(name);
1524
- const readFunction = (value) => {
1525
- if (!isJsonObject(value) || value.type !== "function" || !validName(value.name) || typeof value.description !== "string" || !isJsonObject(value.inputSchema) || value.deferLoading !== void 0 && typeof value.deferLoading !== "boolean" || Object.keys(value).some((key) => ![
1526
- "type",
1527
- "name",
1528
- "description",
1529
- "inputSchema",
1530
- "deferLoading"
1531
- ].includes(key)) || names.has(value.name) || names.size >= 2e3) throw fail();
1532
- names.add(value.name);
1533
- return {
1534
- type: "function",
1535
- name: value.name,
1536
- description: value.description,
1537
- inputSchema: structuredClone(value.inputSchema),
1538
- ...value.deferLoading === true ? { deferLoading: true } : {}
1539
- };
1540
- };
1541
- const tools = catalog.map((value) => {
1542
- if (!isJsonObject(value) || value.type !== "namespace") return readFunction(value);
1543
- if (!validName(value.name) || namespaces.has(value.name) || typeof value.description !== "string" || !Array.isArray(value.tools) || !value.tools.length || Object.keys(value).some((key) => ![
1544
- "type",
1545
- "name",
1546
- "description",
1547
- "tools"
1548
- ].includes(key))) throw fail();
1549
- namespaces.add(value.name);
1550
- return {
1551
- type: "namespace",
1552
- name: value.name,
1553
- description: value.description,
1554
- tools: value.tools.map(readFunction)
1555
- };
1556
- });
1557
- if (fingerprint !== void 0 && codexDynamicToolsFingerprint(tools) !== fingerprint) throw fail();
1558
- return tools;
1559
- }
1560
- /** Existing supervised bindings identify data, never authorize an executor or a new adoption. */
1561
- async function loadCodexNativeToolCatalog(params) {
1562
- const { binding, client, appServer, agentDir, assertCurrent } = params;
1563
- assertCurrent();
1564
- const home = resolveCodexAppServerLocalHomeDir(appServer.start, agentDir);
1565
- const actualHome = client.getRuntimeIdentity()?.codexHome;
1566
- if (!hasCodexNativeToolCatalog(binding) || !binding.dynamicToolsFingerprint || appServer.start.transport !== "stdio" || appServer.remoteWorkspaceRoot || !actualHome || path.resolve(actualHome) !== path.resolve(home) || binding.appServerRuntimeFingerprint !== buildCodexAppServerConnectionFingerprint(appServer, agentDir)) throw new Error("Canonical Codex declarations require the original verified local binding and selected native connection; the thread is preserved.");
1567
- const metadata = await readCodexClientSessionMeta(client, path.join(home, "sessions"), binding.rolloutPath, binding.threadId);
1568
- assertCurrent();
1569
- return parseCodexNativeToolCatalog(metadata, binding.threadId, binding.dynamicToolsFingerprint);
1570
- }
1571
- //#endregion
1572
- //#region extensions/codex/src/app-server/thread-mcp-attestation.ts
1573
- async function attestCodexRestrictedToolSurfaceMcpServersDisabled(client, threadId, threadConfig, signal, expectedActiveServerNames = []) {
1574
- const configuredServers = threadConfig?.mcp_servers;
1575
- if (configuredServers !== void 0 && !isJsonObject(configuredServers)) throw new Error("Codex restricted-tool-surface thread config has invalid mcp_servers");
1576
- const expectedServers = /* @__PURE__ */ new Map();
1577
- for (const [name, serverConfig] of Object.entries(configuredServers ?? {})) {
1578
- if (!isJsonObject(serverConfig) || serverConfig.enabled !== false) throw new Error(`Codex restricted-tool-surface MCP server ${name} is not disabled`);
1579
- expectedServers.set(name, "disabled");
1580
- }
1581
- for (const name of expectedActiveServerNames) {
1582
- if (expectedServers.get(name) === "disabled") throw new Error(`Codex restricted-tool-surface MCP server ${name} has conflicting policy`);
1583
- expectedServers.set(name, "active");
1584
- }
1585
- const response = await client.request("mcpServerStatus/list", {
1586
- threadId,
1587
- detail: "toolsAndAuthOnly"
1588
- }, { signal });
1589
- if (!isJsonObject(response) || !Array.isArray(response.data)) throw new Error("Codex mcpServerStatus/list returned an invalid restricted-tool-surface attestation");
1590
- const observedServerNames = /* @__PURE__ */ new Set();
1591
- for (const status of response.data) {
1592
- if (!isJsonObject(status) || typeof status.name !== "string" || !isJsonObject(status.tools)) throw new Error("Codex mcpServerStatus/list returned an invalid restricted-tool-surface server");
1593
- if (!expectedServers.has(status.name)) throw new Error(`Codex restricted-tool-surface MCP attestation found unexpected server ${status.name}`);
1594
- if (observedServerNames.has(status.name)) throw new Error(`Codex restricted-tool-surface MCP attestation returned duplicate server ${status.name}`);
1595
- observedServerNames.add(status.name);
1596
- if (!Object.hasOwn(status, "serverInfo")) throw new Error(`Codex restricted-tool-surface MCP attestation returned malformed server ${status.name}`);
1597
- if (expectedServers.get(status.name) === "active") {
1598
- if (status.serverInfo === null || Object.keys(status.tools).length === 0) throw new Error(`Codex restricted-tool-surface MCP attestation found inactive admitted server ${status.name}`);
1599
- continue;
1600
- }
1601
- if (status.serverInfo !== null) throw new Error(`Codex restricted-tool-surface MCP attestation found active server ${status.name}`);
1602
- if (Object.keys(status.tools).length > 0) throw new Error(`Codex restricted-tool-surface MCP attestation found tools for server ${status.name}`);
1603
- }
1604
- for (const [expectedName, state] of expectedServers) if (!observedServerNames.has(expectedName)) throw new Error(`Codex restricted-tool-surface MCP attestation is missing ${state === "active" ? "admitted " : ""}server ${expectedName}`);
1605
- if (response.nextCursor !== void 0 && response.nextCursor !== null) throw new Error("Codex mcpServerStatus/list returned an invalid empty-page cursor");
1606
- }
1607
- //#endregion
1608
- //#region extensions/codex/src/app-server/plugin-thread-attestation.ts
1609
- /**
1610
- * Checks app availability and enforces restricted MCP surfaces before a turn.
1611
- */
1612
- /** Every admission path checks the same surface; its lifecycle owner keeps the claim fenced. */
1613
- async function attestCodexThreadToolSurface(params) {
1614
- params.assertCurrent();
1615
- if (params.appIds.length > 0) {
1616
- await params.lifecycleTiming.measure("plugin-app-attestation", () => checkCodexThreadAppAvailability(params));
1617
- params.assertCurrent();
1618
- }
1619
- if (params.restrictedToolSurface) {
1620
- await params.lifecycleTiming.measure("restricted-tool-surface-mcp-attestation", () => attestCodexRestrictedToolSurfaceMcpServersDisabled(params.client, params.threadId, params.threadConfig, params.signal, params.appIds.length > 0 ? ["codex_apps"] : []));
1621
- params.assertCurrent();
1622
- }
1623
- }
1624
- var CodexPluginThreadAppAttestationError = class extends Error {
1625
- constructor(message, options) {
1626
- super(message, options);
1627
- this.name = "CodexPluginThreadAppAttestationError";
1628
- }
1629
- };
1630
- /** Reads the existing runtime snapshot with the started thread's effective app policy. */
1631
- async function checkCodexThreadAppAvailability(params) {
1632
- const appIds = Array.from(new Set(params.appIds.filter(Boolean))).toSorted();
1633
- if (appIds.length === 0) return;
1634
- let response;
1635
- try {
1636
- response = await params.client.request("app/installed", {
1637
- threadId: params.threadId,
1638
- forceRefresh: false
1639
- }, { signal: params.signal });
1640
- } catch (error) {
1641
- params.signal?.throwIfAborted();
1642
- throw new CodexPluginThreadAppAttestationError(`Codex could not confirm admitted apps for thread ${params.threadId}`, { cause: error });
1643
- }
1644
- params.signal?.throwIfAborted();
1645
- const installedById = new Map(response.apps.map((app) => [app.id, app]));
1646
- const failures = appIds.flatMap((appId) => {
1647
- const app = installedById.get(appId);
1648
- if (!app) return [`${appId}:missing`];
1649
- if (!app.enabled) return [`${appId}:disabled`];
1650
- return app.callable ? [] : [`${appId}:not-callable`];
1651
- });
1652
- if (failures.length > 0) embeddedAgentLog.warn("codex apps unavailable; continuing with remaining tools", {
1653
- threadId: params.threadId,
1654
- failures
1655
- });
1656
- }
1657
- /** Deletes a persistent pre-turn thread; ephemeral threads can only be unsubscribed. */
1658
- async function discardUnattestedCodexPluginThread(params) {
1659
- if (params.ephemeral) return await unsubscribeCodexThreadBestEffort(params.client, {
1660
- threadId: params.threadId,
1661
- timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
1662
- });
1663
- try {
1664
- await params.client.request("thread/delete", { threadId: params.threadId }, { timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS });
1665
- return true;
1666
- } catch (error) {
1667
- embeddedAgentLog.debug("codex plugin app attestation thread deletion failed", {
1668
- threadId: params.threadId,
1669
- error
1670
- });
1671
- await unsubscribeCodexThreadBestEffort(params.client, {
1672
- threadId: params.threadId,
1673
- timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
1674
- });
1675
- return false;
1676
- }
1677
- }
1678
- //#endregion
1679
- //#region extensions/codex/src/app-server/native-hook-relay.ts
1680
- /**
1681
- * Bridges Codex native hook callbacks into OpenClaw's native hook relay so
1682
- * app-server tool events can still run OpenClaw policy and diagnostics.
1683
- */
1684
- /** Codex hook events that can be registered through OpenClaw's native relay. */
1685
- const CODEX_NATIVE_HOOK_RELAY_EVENTS = [
1686
- "pre_tool_use",
1687
- "post_tool_use",
1688
- "permission_request",
1689
- "before_agent_finalize"
1690
- ];
1691
- const CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS = CODEX_NATIVE_HOOK_RELAY_EVENTS.filter((event) => event !== "permission_request");
1692
- const CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS = 18e5;
1693
- /** Extra relay lifetime after the expected turn budget, preventing late hook drops. */
1694
- const CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS = 3e5;
1695
- const CODEX_NATIVE_HOOK_RELAY_COMMAND_MIN_PARENT_MARGIN_MS = 250;
1696
- const CODEX_NATIVE_HOOK_RELAY_COMMAND_MAX_PARENT_MARGIN_MS = 1e3;
1697
- const CODEX_NATIVE_HOOK_RELAY_DEFAULT_TIMEOUT_SEC = 10;
1698
- const CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS = 1e4;
1699
- const CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS = 5e3;
1700
- const MAX_PENDING_DIRECT_CHILD_ADMISSIONS = 32;
1701
- const nativeHookPolicyByClient = /* @__PURE__ */ new WeakMap();
1702
- const CODEX_HOOK_MATCHER_NAMES_BY_TOOL_ID = {
1703
- exec: [
1704
- "Bash",
1705
- "exec",
1706
- "exec_command"
1707
- ],
1708
- apply_patch: [
1709
- "apply_patch",
1710
- "Write",
1711
- "Edit"
1712
- ],
1713
- spawn_agent: ["spawn_agent", "Agent"]
1714
- };
1715
- /** Enterprise managed-only policy silently drops the session-layer hooks that enforce OpenClaw. */
1716
- async function assertCodexNativeHookRelayAllowed(client, signal) {
1717
- let attestation = nativeHookPolicyByClient.get(client);
1718
- if (!attestation) {
1719
- attestation = client.request("configRequirements/read", void 0, { signal }).then((response) => {
1720
- if (!isJsonObject(response) || !Object.hasOwn(response, "requirements")) throw new Error("Codex configRequirements/read returned an invalid hook policy response");
1721
- const requirements = response.requirements;
1722
- if (requirements === null) return;
1723
- if (!isJsonObject(requirements)) throw new Error("Codex configRequirements/read returned invalid hook policy requirements");
1724
- const managedOnly = requirements.allowManagedHooksOnly;
1725
- if (managedOnly !== void 0 && managedOnly !== null && typeof managedOnly !== "boolean") throw new Error("Codex configRequirements/read returned invalid managed-only hook policy");
1726
- if (managedOnly === true) throw new Error("Codex managed-only hooks disable the OpenClaw native hook relay; refusing unenforced execution");
1727
- });
1728
- nativeHookPolicyByClient.set(client, attestation);
1729
- attestation.catch(() => {
1730
- if (nativeHookPolicyByClient.get(client) === attestation) nativeHookPolicyByClient.delete(client);
1731
- });
1732
- }
1733
- await attestation;
1734
- }
1735
- /** Defers relay unregister so late native hook subprocesses can still resolve. */
1736
- function scheduleCodexNativeHookRelayUnregister(params) {
1737
- let pending;
1738
- const unregister = () => {
1739
- if (!pending) return;
1740
- const current = pending;
1741
- pending = void 0;
1742
- if (!nativeHookRelayUnregisterQueue.delete(current)) return;
1743
- params.relay.unregister();
1744
- nativeHookRelayUnregisterQueue.track(params.relay.drain());
1745
- };
1746
- const timeout = setTimeout(unregister, resolveCodexNativeHookRelayUnregisterGraceMs(params.hookTimeoutSec));
1747
- pending = {
1748
- timeout,
1749
- unregister
1750
- };
1751
- nativeHookRelayUnregisterQueue.add(pending);
1752
- timeout.unref();
1753
- }
1754
- /** Computes the delayed unregister window from Codex's hook timeout. */
1755
- function resolveCodexNativeHookRelayUnregisterGraceMs(hookTimeoutSec) {
1756
- const hookTimeoutMs = finiteSecondsToTimerSafeMilliseconds(normalizeHookTimeoutSec(hookTimeoutSec)) ?? 0;
1757
- return Math.max(CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS, addTimerTimeoutGraceMs(hookTimeoutMs, CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS) ?? 0);
1758
- }
1759
- /** Records a native pre-tool failure that Codex does not project as a tool item. */
1760
- function emitCodexNativePreToolUseFailureDiagnostic(params) {
1761
- emitTrustedDiagnosticEvent({
1762
- type: "tool.execution.error",
1763
- ...params.agentId ? { agentId: params.agentId } : {},
1764
- sessionId: params.sessionId,
1765
- ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
1766
- runId: params.runId,
1767
- toolName: params.failure.toolName,
1768
- toolCallId: params.failure.toolCallId,
1769
- durationMs: params.failure.durationMs,
1770
- errorCategory: "before_tool_call",
1771
- terminalReason: params.terminalReason ?? (params.signal?.aborted ? resolveCodexToolAbortTerminalReason(params.signal) : params.failure.disposition),
1772
- ...params.sourceTimestampMs !== void 0 ? { sourceTimestampMs: params.sourceTimestampMs } : {}
1773
- });
1774
- }
1775
- /** Registers an OpenClaw native hook relay for a Codex app-server turn. */
1776
- function createCodexNativeHookRelay(params) {
1777
- if (params.options?.enabled === false) return;
1778
- const directChildClaims = /* @__PURE__ */ new Map();
1779
- const pendingDirectChildAdmissions = /* @__PURE__ */ new Map();
1780
- let foregroundClosed = false;
1781
- let successfulYieldRetentionAuthorized = false;
1782
- const assertClaim = (threadId, claim) => () => directChildClaims.get(threadId) === claim;
1783
- const rejectPendingAdmissions = (reason) => {
1784
- for (const pending of pendingDirectChildAdmissions.values()) pending.reject(new Error(reason));
1785
- pendingDirectChildAdmissions.clear();
1786
- };
1787
- const relay = registerNativeHookRelayForBundledRuntime({
1788
- provider: "codex",
1789
- relayId: buildCodexNativeHookRelayId({
1790
- agentId: params.agentId,
1791
- sessionId: params.sessionId,
1792
- sessionKey: params.sessionKey
1793
- }),
1794
- ...params.generation ? { generation: params.generation } : {},
1795
- ...params.generationMismatchGraceMs ? { generationMismatchGraceMs: params.generationMismatchGraceMs } : {},
1796
- ...params.agentId ? { agentId: params.agentId } : {},
1797
- sessionId: params.sessionId,
1798
- ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
1799
- ...params.config ? { config: params.config } : {},
1800
- autoApproveMcpTools: params.autoApproveMcpTools,
1801
- projectedMcpServers: params.projectedMcpServers,
1802
- runId: params.runId,
1803
- ...params.channelId ? { channelId: params.channelId } : {},
1804
- ...params.requester ? { requester: params.requester } : {},
1805
- ...params.approvalContext ? { approvalContext: params.approvalContext } : {},
1806
- allowedEvents: params.events,
1807
- preToolUseLoopDetection: params.loopDetectionPreToolUseRelay,
1808
- ttlMs: resolveCodexNativeHookRelayTtlMs({
1809
- explicitTtlMs: params.options?.ttlMs,
1810
- attemptTimeoutMs: params.attemptTimeoutMs,
1811
- startupTimeoutMs: params.startupTimeoutMs,
1812
- turnStartTimeoutMs: params.turnStartTimeoutMs
1813
- }),
1814
- signal: params.signal,
1815
- runBeforeToolCall: params.hostCapabilities.runBeforeToolCall,
1816
- approvalHost: params.hostCapabilities,
1817
- assertActive: () => {
1818
- params.hostCapabilities.assertActive();
1819
- params.assertCurrent?.();
1820
- },
1821
- retention: {
1822
- readClaim: readCodexNativeChildThreadId,
1823
- shouldRetainAfterForegroundClose: () => successfulYieldRetentionAuthorized && directChildClaims.size > 0,
1824
- allowPreToolUse: (childThreadId) => directChildClaims.has(childThreadId),
1825
- awaitForegroundAdmission: (childThreadId, signal) => {
1826
- if (foregroundClosed) return Promise.reject(/* @__PURE__ */ new Error("native hook relay foreground admission unavailable"));
1827
- const existingClaim = directChildClaims.get(childThreadId);
1828
- if (existingClaim) return Promise.resolve(assertClaim(childThreadId, existingClaim));
1829
- let pending = pendingDirectChildAdmissions.get(childThreadId);
1830
- if (!pending) {
1831
- if (pendingDirectChildAdmissions.size >= MAX_PENDING_DIRECT_CHILD_ADMISSIONS) return Promise.reject(/* @__PURE__ */ new Error("native hook relay foreground admission capacity reached"));
1832
- pending = {
1833
- ...createDeferred(),
1834
- waiters: 0
1835
- };
1836
- pendingDirectChildAdmissions.set(childThreadId, pending);
1837
- }
1838
- const admission = pending;
1839
- admission.waiters++;
1840
- let onAbort;
1841
- return new Promise((resolve, reject) => {
1842
- admission.promise.then(resolve, reject);
1843
- onAbort = () => reject(toErrorObject(signal?.reason, "native hook relay admission aborted"));
1844
- signal?.addEventListener("abort", onAbort, { once: true });
1845
- if (signal?.aborted) onAbort();
1846
- }).then((claim) => assertClaim(childThreadId, claim)).finally(() => {
1847
- if (onAbort) signal?.removeEventListener("abort", onAbort);
1848
- admission.waiters--;
1849
- if (admission.waiters === 0 && pendingDirectChildAdmissions.get(childThreadId) === admission) pendingDirectChildAdmissions.delete(childThreadId);
1850
- });
1851
- },
1852
- onDispose: () => {
1853
- foregroundClosed = true;
1854
- rejectPendingAdmissions("native hook relay registration closed");
1855
- }
1856
- },
1857
- onPreToolUseFailure: params.onPreToolUseFailure,
1858
- command: {
1859
- nice: 10,
1860
- timeoutMs: params.options?.gatewayTimeoutMs
1861
- }
1862
- });
1863
- const unregister = () => {
1864
- foregroundClosed = true;
1865
- rejectPendingAdmissions("native hook relay foreground closed");
1866
- relay.unregister();
1867
- };
1868
- return {
1869
- ...relay,
1870
- unregister,
1871
- authorizeRetentionAfterSuccessfulYield: () => {
1872
- successfulYieldRetentionAuthorized = true;
1873
- },
1874
- hasClaimedDirectChild: () => directChildClaims.size > 0,
1875
- rejectPendingDirectChild: (threadIdInput, reason) => {
1876
- const threadId = threadIdInput.trim();
1877
- const pending = threadId ? pendingDirectChildAdmissions.get(threadId) : void 0;
1878
- if (!pending) return;
1879
- pendingDirectChildAdmissions.delete(threadId);
1880
- pending.reject(new Error(reason));
1881
- },
1882
- claimDirectChild: (threadIdInput) => {
1883
- const threadId = threadIdInput.trim();
1884
- if (!threadId) return () => void 0;
1885
- if (directChildClaims.get(threadId)) return () => void 0;
1886
- const claim = Symbol(threadId);
1887
- directChildClaims.set(threadId, claim);
1888
- const pending = pendingDirectChildAdmissions.get(threadId);
1889
- pendingDirectChildAdmissions.delete(threadId);
1890
- pending?.resolve(claim);
1891
- let released = false;
1892
- return () => {
1893
- if (released) return;
1894
- released = true;
1895
- if (directChildClaims.get(threadId) !== claim) return;
1896
- directChildClaims.delete(threadId);
1897
- if (foregroundClosed && directChildClaims.size === 0) {
1898
- relay.unregister();
1899
- nativeHookRelayUnregisterQueue.track(relay.drain());
1900
- }
1901
- };
1902
- }
1903
- };
1904
- }
1905
- function readCodexNativeChildThreadId(rawPayload) {
1906
- if (!isJsonObject(rawPayload) || typeof rawPayload.agent_id !== "string") return;
1907
- return rawPayload.agent_id.trim() || void 0;
1908
- }
1909
- /** Selects the native hook events Codex should install for the current approval mode. */
1910
- function resolveCodexNativeHookRelayEvents(params) {
1911
- if (params.configuredEvents?.length) return params.configuredEvents;
1912
- return params.appServer.approvalPolicy === "never" ? CODEX_NATIVE_HOOK_RELAY_EVENTS : CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS;
1913
- }
1914
- /** Derives the native hook relay TTL from the turn budget unless explicitly configured. */
1915
- function resolveCodexNativeHookRelayTtlMs(params) {
1916
- if (params.explicitTtlMs !== void 0) return params.explicitTtlMs;
1917
- const relayBudgetMs = params.attemptTimeoutMs + params.startupTimeoutMs + params.turnStartTimeoutMs + CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS;
1918
- return Math.max(CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS, Math.floor(relayBudgetMs));
1919
- }
1920
- /** Builds a stable relay id scoped to the agent and session identity. */
1921
- function buildCodexNativeHookRelayId(params) {
1922
- const hash = createHash("sha256");
1923
- hash.update("openclaw:codex:native-hook-relay:v1");
1924
- hash.update("\0");
1925
- hash.update(params.agentId?.trim() || "");
1926
- hash.update("\0");
1927
- hash.update(params.sessionKey?.trim() || params.sessionId);
1928
- return `codex-${hash.digest("hex").slice(0, 40)}`;
1929
- }
1930
- const CODEX_HOOK_EVENT_BY_NATIVE_EVENT = {
1931
- pre_tool_use: "PreToolUse",
1932
- post_tool_use: "PostToolUse",
1933
- permission_request: "PermissionRequest",
1934
- before_agent_finalize: "Stop"
1935
- };
1936
- const CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT = {
1937
- pre_tool_use: "pre_tool_use",
1938
- post_tool_use: "post_tool_use",
1939
- permission_request: "permission_request",
1940
- before_agent_finalize: "stop"
1941
- };
1942
- const CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS = ["/<session-flags>/config.toml", "<session-flags>/config.toml"];
1943
- /** Builds the Codex config overlay that installs trusted command hooks for relay events. */
1944
- function buildCodexNativeHookRelayConfig(params) {
1945
- const events = params.events?.length ? params.events : CODEX_NATIVE_HOOK_RELAY_EVENTS;
1946
- const selectedEvents = new Set(events);
1947
- const config = { "features.hooks": true };
1948
- const hookState = {};
1949
- for (const event of CODEX_NATIVE_HOOK_RELAY_EVENTS) {
1950
- const codexEvent = CODEX_HOOK_EVENT_BY_NATIVE_EVENT[event];
1951
- const selected = selectedEvents.has(event);
1952
- const shouldRelay = params.relay.shouldRelayEvent(event);
1953
- if (!selected || !shouldRelay) {
1954
- if (selected || params.clearOmittedEvents) config[`hooks.${codexEvent}`] = [];
1955
- 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 };
1956
- continue;
1957
- }
1958
- const timeout = normalizeHookTimeoutSec(params.hookTimeoutSec);
1959
- const command = params.relay.commandForEvent(event, { timeoutMs: resolveCodexNativeHookRelayCommandTimeoutMs(timeout) });
1960
- const matcher = buildCodexNativeToolMatcher(params.relay.toolMatcherForEvent(event));
1961
- config[`hooks.${codexEvent}`] = [{
1962
- ...matcher ? { matcher } : {},
1963
- hooks: [{
1964
- type: "command",
1965
- command,
1966
- timeout,
1967
- async: false,
1968
- statusMessage: "OpenClaw native hook relay"
1969
- }]
1970
- }];
1971
- const state = {
1972
- enabled: true,
1973
- trusted_hash: codexCommandHookTrustedHash({
1974
- event,
1975
- command,
1976
- matcher,
1977
- timeout,
1978
- statusMessage: "OpenClaw native hook relay"
503
+ reserveTokens: resolveCodexContextEngineProjectionReserveTokens()
1979
504
  })
1980
- };
1981
- for (const sourcePath of CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS) hookState[`${sourcePath}:${CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[event]}:0:0`] = state;
1982
- }
1983
- config["hooks.state"] = hookState;
1984
- return config;
505
+ }),
506
+ projection: projection ? buildContextEngineProjectionBinding(projection) : void 0
507
+ };
1985
508
  }
1986
- /** Builds a Codex config overlay that disables native hooks and clears hook arrays. */
1987
- function buildCodexNativeHookRelayDisabledConfig() {
509
+ function buildContextEngineProjectionBinding(projection) {
1988
510
  return {
1989
- "features.hooks": false,
1990
- "hooks.PreToolUse": [],
1991
- "hooks.PostToolUse": [],
1992
- "hooks.PermissionRequest": [],
1993
- "hooks.Stop": []
511
+ schemaVersion: 1,
512
+ mode: "thread_bootstrap",
513
+ epoch: projection.epoch,
514
+ fingerprint: projection.fingerprint
1994
515
  };
1995
516
  }
1996
- function normalizeHookTimeoutSec(value) {
1997
- return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.ceil(value) : CODEX_NATIVE_HOOK_RELAY_DEFAULT_TIMEOUT_SEC;
1998
- }
1999
- function resolveCodexNativeHookRelayCommandTimeoutMs(hookTimeoutSec) {
2000
- const parentTimeoutMs = finiteSecondsToTimerSafeMilliseconds(normalizeHookTimeoutSec(hookTimeoutSec)) ?? 5e3;
2001
- 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)));
2002
- return Math.max(1, parentTimeoutMs - parentMarginMs);
517
+ function isContextEngineBindingCompatible(previous, next) {
518
+ return previous?.schemaVersion === next.schemaVersion && previous.engineId === next.engineId && previous.policyFingerprint === next.policyFingerprint && areContextEngineProjectionBindingsCompatible(previous.projection, next.projection);
2003
519
  }
2004
- function buildCodexNativeToolMatcher(toolNames) {
2005
- if (toolNames === void 0) return;
2006
- if (toolNames.length === 0) throw new TypeError("Codex native hook matcher requires at least one tool name");
2007
- const nativeNames = /* @__PURE__ */ new Set();
2008
- let hasCustomToolName = false;
2009
- for (const toolName of toolNames) {
2010
- const canonicalToolName = toolName.trim();
2011
- if (!canonicalToolName || canonicalToolName === "*") throw new TypeError("Codex native hook matcher requires canonical OpenClaw tool ids");
2012
- const nativeAliases = CODEX_HOOK_MATCHER_NAMES_BY_TOOL_ID[canonicalToolName];
2013
- if (!nativeAliases) hasCustomToolName = true;
2014
- for (const nativeName of nativeAliases ?? [canonicalToolName]) nativeNames.add(nativeName);
2015
- }
2016
- const sortedNames = Array.from(nativeNames).toSorted();
2017
- if (!hasCustomToolName && sortedNames.every((toolName) => /^[A-Za-z0-9_]+$/.test(toolName))) return sortedNames.join("|");
2018
- return `(?i)^(?:${sortedNames.map((toolName) => toolName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})$`;
520
+ function areContextEngineProjectionBindingsCompatible(previous, next) {
521
+ if (!next) return previous === void 0;
522
+ return previous?.schemaVersion === next.schemaVersion && previous.mode === next.mode && previous.epoch === next.epoch && previous.fingerprint === next.fingerprint;
2019
523
  }
2020
- function codexCommandHookTrustedHash(params) {
2021
- const identity = {
2022
- event_name: CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[params.event],
2023
- ...params.matcher ? { matcher: params.matcher } : {},
2024
- hooks: [{
2025
- async: false,
2026
- command: params.command,
2027
- statusMessage: params.statusMessage,
2028
- timeout: params.timeout,
2029
- type: "command"
2030
- }]
2031
- };
2032
- return `sha256:${createHash("sha256").update(JSON.stringify(sortJsonValue(identity))).digest("hex")}`;
524
+ function resolveContextEngineCitationsMode(config) {
525
+ const rootConfig = isRecord(config) ? config : void 0;
526
+ const citations = (isRecord(rootConfig?.memory) ? rootConfig.memory : void 0)?.citations;
527
+ return isJsonConfigValue(citations) ? citations : void 0;
2033
528
  }
2034
- function sortJsonValue(value) {
2035
- if (!value || typeof value !== "object") return value;
2036
- if (Array.isArray(value)) return value.map(sortJsonValue);
2037
- const sorted = {};
2038
- for (const [key, entry] of Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right))) sorted[key] = sortJsonValue(entry);
2039
- return sorted;
529
+ function isJsonConfigValue(value) {
530
+ if (value === null || typeof value === "string" || typeof value === "boolean") return true;
531
+ if (typeof value === "number") return Number.isFinite(value);
532
+ if (Array.isArray(value)) return value.every(isJsonConfigValue);
533
+ return isRecord(value) && Object.values(value).every(isJsonConfigValue);
2040
534
  }
2041
535
  //#endregion
2042
536
  //#region extensions/codex/src/app-server/profiler-flag.ts
@@ -2046,23 +540,6 @@ function isCodexAppServerProfilerEnabled(config, env = process.env) {
2046
540
  return PROFILER_FLAGS.some((flag) => isDiagnosticFlagEnabled(flag, config, env));
2047
541
  }
2048
542
  //#endregion
2049
- //#region extensions/codex/src/app-server/project-doc-thread-config.ts
2050
- const CODEX_NATIVE_PROJECT_DOC_MAX_BYTES = 131072;
2051
- function buildCodexProjectDocThreadConfig(config, effectiveNativeConfig) {
2052
- const defaults = { project_doc_max_bytes: resolveCodexNativeProjectDocMaxBytes(effectiveNativeConfig) ?? CODEX_NATIVE_PROJECT_DOC_MAX_BYTES };
2053
- return mergeCodexThreadConfigs(defaults, config) ?? defaults;
2054
- }
2055
- function resolveCodexNativeProjectDocMaxBytes(effectiveNativeConfig) {
2056
- if (effectiveNativeConfig?.origins?.project_doc_max_bytes === void 0) return;
2057
- const authoredMaxBytes = effectiveNativeConfig.config.project_doc_max_bytes;
2058
- if (typeof authoredMaxBytes !== "number" || !Number.isSafeInteger(authoredMaxBytes) || authoredMaxBytes < 0) throw new Error("Codex config/read returned an invalid project_doc_max_bytes value");
2059
- return authoredMaxBytes;
2060
- }
2061
- function mergeCodexNativeProjectDocThreadConfig(config, effectiveNativeConfig) {
2062
- const authoredMaxBytes = resolveCodexNativeProjectDocMaxBytes(effectiveNativeConfig);
2063
- return authoredMaxBytes === void 0 ? config : mergeCodexThreadConfigs({ project_doc_max_bytes: authoredMaxBytes }, config);
2064
- }
2065
- //#endregion
2066
543
  //#region extensions/codex/src/app-server/mcp-tool-metadata.ts
2067
544
  /** Hosted app ownership is authoritative only on metadata supplied by Codex. */
2068
545
  function readCodexMcpToolConnectorId(tool) {
@@ -2077,571 +554,44 @@ function readCodexMcpToolUiVisibility(tool) {
2077
554
  return [...new Set(visibility.filter((value) => value === "app" || value === "model"))].toSorted();
2078
555
  }
2079
556
  //#endregion
2080
- //#region extensions/codex/src/app-server/thread-model-selection.ts
2081
- const CODEX_NATIVE_PERSONALITY_NONE = "none";
2082
- function resolveCodexBindingModelProviderFallback(params) {
2083
- const provider = params.provider?.trim().toLowerCase();
2084
- if (provider && provider !== "codex") return;
2085
- const currentModel = params.currentModel?.trim();
2086
- const bindingModel = params.bindingModel?.trim();
2087
- if (currentModel && bindingModel && currentModel === bindingModel && params.bindingModelProvider) return params.bindingModelProvider;
2088
- return hasProviderQualifiedModelRef(currentModel) ? void 0 : params.bindingModelProvider;
2089
- }
2090
- function resolveCodexAppServerThreadModelSelection(params) {
2091
- const authProfileId = params.authProfileId ?? params.binding?.authProfileId;
2092
- const explicitModelProvider = resolveCodexAppServerModelProvider({
2093
- provider: params.provider,
2094
- authProfileId,
2095
- authProfileStore: params.authProfileStore,
2096
- agentDir: params.agentDir,
2097
- config: params.config
2098
- });
2099
- const bindingModelProvider = params.binding?.threadId ? resolveCodexBindingModelProviderFallback({
2100
- provider: params.provider,
2101
- currentModel: params.model,
2102
- bindingModel: params.binding.model,
2103
- bindingModelProvider: params.binding.modelProvider
2104
- }) : void 0;
2105
- return resolveCodexAppServerRequestModelSelection({
2106
- model: params.model,
2107
- modelProvider: explicitModelProvider ?? bindingModelProvider,
2108
- authProfileId,
2109
- authProfileStore: params.authProfileStore,
2110
- agentDir: params.agentDir,
2111
- config: params.config
2112
- });
2113
- }
2114
- function resolveCodexAppServerRequestModelSelection(params) {
2115
- const model = params.model.trim();
2116
- const modelProvider = params.modelProvider?.trim();
2117
- if (modelProvider) return {
2118
- model,
2119
- modelProvider
2120
- };
2121
- const slashIndex = model.indexOf("/");
2122
- if (slashIndex <= 0 || slashIndex >= model.length - 1) return { model };
2123
- const inferredModelProvider = resolveCodexAppServerModelProvider({
2124
- provider: model.slice(0, slashIndex),
2125
- authProfileId: params.authProfileId,
2126
- authProfileStore: params.authProfileStore,
2127
- agentDir: params.agentDir,
2128
- config: params.config
2129
- });
2130
- return {
2131
- model: model.slice(slashIndex + 1).trim(),
2132
- ...inferredModelProvider ? { modelProvider: inferredModelProvider } : {}
2133
- };
2134
- }
2135
- function hasProviderQualifiedModelRef(model) {
2136
- const trimmed = model?.trim();
2137
- const slashIndex = trimmed?.indexOf("/") ?? -1;
2138
- return slashIndex > 0 && slashIndex < (trimmed?.length ?? 0) - 1;
2139
- }
2140
- function resolveCodexAppServerModelProvider(params) {
2141
- const normalized = params.provider.trim();
2142
- const normalizedLower = normalized.toLowerCase();
2143
- if (!normalized || normalizedLower === "codex") return;
2144
- if (isCodexAppServerNativeAuthProfile(params) && normalizedLower === "openai") return;
2145
- return normalizedLower === "openai" ? "openai" : normalized;
2146
- }
2147
- //#endregion
2148
- //#region extensions/codex/src/app-server/thread-prompt.ts
2149
- function buildDeveloperInstructions(params, options = {}) {
2150
- const deferredToolNames = /* @__PURE__ */ new Set();
2151
- let screenToolName;
2152
- let showWidgetToolName;
2153
- let dashboardToolName;
2154
- let portalToolName;
2155
- let messageTool;
2156
- let hasSkillWorkshop = false;
2157
- let hasSessionsSpawn = false;
2158
- let hasSessionsYield = false;
2159
- let hasSubagentsList = false;
2160
- let hasSessionsSend = false;
2161
- let hasControlTools = false;
2162
- let hasSeenDirectNamespace = false;
2163
- for (const spec of options.dynamicTools ?? []) {
2164
- const isDirectNamespace = spec.type === "namespace" && !hasSeenDirectNamespace && spec.name.trim() === "openclaw_direct";
2165
- if (isDirectNamespace) hasSeenDirectNamespace = true;
2166
- for (const tool of spec.type === "namespace" ? spec.tools : [spec]) {
2167
- const name = tool.name.trim();
2168
- const qualifiedName = spec.type === "namespace" ? `${spec.name}.${name}` : name;
2169
- if (tool.deferLoading === true && name) deferredToolNames.add(name);
2170
- if (name === "screen") screenToolName ??= qualifiedName;
2171
- if (name === "show_widget") showWidgetToolName ??= qualifiedName;
2172
- if (name === "dashboard") dashboardToolName ??= qualifiedName;
2173
- if (name === "portal") portalToolName ??= qualifiedName;
2174
- if (name === "message") messageTool ??= {
2175
- name: qualifiedName,
2176
- parameters: tool.inputSchema
2177
- };
2178
- hasSkillWorkshop ||= name === SKILL_WORKSHOP_TOOL_NAME;
2179
- hasSessionsSpawn ||= name === "sessions_spawn";
2180
- hasSessionsYield ||= isDirectNamespace && name === "sessions_yield";
2181
- hasSubagentsList ||= name === "subagents";
2182
- hasSessionsSend ||= name === "sessions_send";
2183
- hasControlTools ||= name === "openclaw" || name === "gateway";
2184
- }
2185
- }
2186
- const nativeCommandGuidance = listRegisteredPluginAgentPromptGuidance({
2187
- surface: "codex_app_server",
2188
- includeLegacyGlobalGuidance: false
2189
- }).join("\n");
2190
- const delegationGuidanceAvailable = params.disableTools !== true && params.delegationCapability !== "report_only" && !isMessageOnlyCodexSourceReply(params);
2191
- const nativeDelegationAvailable = delegationGuidanceAvailable && !isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow) && !shouldDisableCodexToolSearchForModel(params.modelId);
2192
- const deferredToolDiscoveryGuidance = deferredToolNames.size > 0 || nativeDelegationAvailable ? "Deferred tools may be absent from the direct tool list. Use `tool_search` when directly callable. On code-mode-only models, use `exec` instead: filter `ALL_TOOLS` by name and description, then call the matching entry through `tools`." : void 0;
2193
- return [
2194
- "You are a personal agent running inside OpenClaw. OpenClaw has dynamic tools for OpenClaw-owned messaging, cron, sessions, media, gateway, and nodes.",
2195
- deferredToolNames.size > 0 ? `Deferred searchable OpenClaw dynamic tools available: ${[...deferredToolNames].toSorted((left, right) => left.localeCompare(right)).join(", ")}.` : void 0,
2196
- deferredToolDiscoveryGuidance,
2197
- hasSkillWorkshop ? buildSkillWorkshopPromptSection().join("\n") : void 0,
2198
- nativeDelegationAvailable ? `Use Codex native \`spawn_agent\` for Codex subagents. \`spawn_agent\` and the other native collaboration tools may be deferred.${hasSessionsSpawn ? " Use OpenClaw `sessions_spawn` only for OpenClaw or ACP delegation, never as a substitute for `spawn_agent` on internal legwork." : ""}` : void 0,
2199
- hasSessionsYield && nativeDelegationAvailable ? "When a native child's result belongs in a later turn, end the current turn with `openclaw_direct.sessions_yield`; the completion arrives as the next model-visible input. Use native `wait_agent` only for an intentional same-turn wait when the immediate next step is blocked on the child. Never loop-poll for native child completion." : void 0,
2200
- delegationGuidanceAvailable ? buildDelegationGuidanceSection({
2201
- mode: resolveMainSessionDelegationMode({
2202
- config: params.config,
2203
- agentId: params.agentId,
2204
- sessionKey: params.sessionKey
2205
- }),
2206
- isMinimal: params.promptMode === "minimal" || params.promptMode === "none",
2207
- hiddenDelegationTool: nativeDelegationAvailable ? "native `spawn_agent`" : hasSessionsSpawn ? "`sessions_spawn`" : "",
2208
- hasVisibleSessionSpawn: hasSessionsSpawn,
2209
- hasSessionsYield,
2210
- hasSubagentsList,
2211
- hasSessionsSend
2212
- }).join("\n") : void 0,
2213
- params.disableTools !== true && params.promptMode !== "minimal" && params.promptMode !== "none" ? buildUiPresentationPrompt({
2214
- screenToolName,
2215
- showWidgetToolName,
2216
- dashboardToolName,
2217
- portalToolName,
2218
- messageTool
2219
- }) : void 0,
2220
- buildCredentialSafetyPrompt({ controlToolsAvailable: params.disableTools !== true && hasControlTools }),
2221
- nativeCommandGuidance,
2222
- params.gitCoauthorPrompt,
2223
- params.extraSystemPrompt
2224
- ].filter((section) => typeof section === "string" && section.trim()).join("\n\n");
557
+ //#region extensions/codex/src/app-server/scheduled-app-tool-policy.ts
558
+ function normalizeAppToolApprovalMode(value) {
559
+ return value === "auto" || value === "prompt" || value === "writes" || value === "approve" ? value : void 0;
2225
560
  }
2226
- //#endregion
2227
- //#region extensions/codex/src/app-server/thread-shell-environment.ts
2228
- /** Applies host-selected values and any required login-shell restriction last. */
2229
- function applyCodexManagedShellEnvironment(config, environment, disableLoginShell = false) {
2230
- if (!environment || Object.keys(environment).length === 0) return disableLoginShell ? {
2231
- ...config,
2232
- allow_login_shell: false
2233
- } : config;
2234
- const current = isJsonObject(config.shell_environment_policy) ? config.shell_environment_policy : {};
2235
- const currentSet = isJsonObject(current.set) ? current.set : {};
2236
- const names = Object.keys(environment).toSorted();
2237
- const includeOnly = Array.isArray(current.include_only) ? current.include_only.filter((entry) => typeof entry === "string") : [];
2238
- const filters = isJsonObject(current.filters) ? current.filters : void 0;
2239
- const hasIncludeFilter = filters && Object.values(filters).includes("include");
2240
- const managedConfig = {
2241
- ...config,
2242
- shell_environment_policy: {
2243
- ...current,
2244
- experimental_use_profile: false,
2245
- set: {
2246
- ...currentSet,
2247
- ...environment
2248
- },
2249
- ...filters ? hasIncludeFilter ? { filters: {
2250
- ...filters,
2251
- ...Object.fromEntries(names.map((name) => [name, "include"]))
2252
- } } : {} : includeOnly.length > 0 ? { include_only: [.../* @__PURE__ */ new Set([...includeOnly, ...names])] } : {}
561
+ function readCurrentToolPolicy(config, appId, toolName, metadata, fallbackApprovalMode = "auto") {
562
+ const apps = asOptionalRecord(config.apps);
563
+ const app = asOptionalRecord(apps?.[appId]);
564
+ const defaults = asOptionalRecord(apps?.["_default"]);
565
+ const tools = asOptionalRecord(app?.tools);
566
+ const tool = asOptionalRecord(tools?.[toolName] ?? (metadata?.title !== void 0 ? tools?.[metadata.title] : void 0));
567
+ const toolApprovalMode = normalizeAppToolApprovalMode(tool?.approval_mode);
568
+ let approvalMode = toolApprovalMode ?? normalizeAppToolApprovalMode(app?.default_tools_approval_mode) ?? normalizeAppToolApprovalMode(defaults?.default_tools_approval_mode) ?? fallbackApprovalMode;
569
+ if (!toolApprovalMode) {
570
+ const links = asOptionalRecord(app?.links);
571
+ if (metadata?.requiresExplicitLinkId) for (const link of Object.values(links ?? {})) {
572
+ const linkMode = normalizeAppToolApprovalMode(asOptionalRecord(link)?.default_tools_approval_mode);
573
+ if (linkMode) approvalMode = intersectToolApprovalMode(approvalMode, linkMode);
2253
574
  }
2254
- };
2255
- return disableLoginShell ? {
2256
- ...managedConfig,
2257
- allow_login_shell: false
2258
- } : managedConfig;
2259
- }
2260
- //#endregion
2261
- //#region extensions/codex/src/app-server/web-search.ts
2262
- const CODEX_NATIVE_WEB_SEARCH_DISABLED_CONFIG = {
2263
- "features.standalone_web_search": false,
2264
- web_search: "disabled"
2265
- };
2266
- function normalizeUniqueStrings(value) {
2267
- if (!Array.isArray(value)) return;
2268
- const normalized = [...new Set(value.map(normalizeOptionalString).filter((entry) => Boolean(entry)))];
2269
- return normalized.length > 0 ? normalized : void 0;
2270
- }
2271
- function hasManagedSearchProvider(config) {
2272
- return normalizeOptionalString(config?.tools?.web?.search?.provider) !== void 0;
2273
- }
2274
- function hasNativeDomainRestrictions(config) {
2275
- return normalizeUniqueStrings(config?.tools?.web?.search?.openaiCodex?.allowedDomains) !== void 0;
2276
- }
2277
- function buildCodexNativeWebSearchThreadConfig(config) {
2278
- const nativeConfig = config?.tools?.web?.search?.openaiCodex;
2279
- const threadConfig = {
2280
- "features.standalone_web_search": false,
2281
- web_search: nativeConfig?.mode === "live" ? "live" : "cached"
2282
- };
2283
- const allowedDomains = normalizeUniqueStrings(nativeConfig?.allowedDomains);
2284
- if (allowedDomains) threadConfig["tools.web_search.allowed_domains"] = allowedDomains;
2285
- if (nativeConfig?.contextSize) threadConfig["tools.web_search.context_size"] = nativeConfig.contextSize;
2286
- const location = nativeConfig?.userLocation;
2287
- const country = normalizeOptionalString(location?.country);
2288
- const region = normalizeOptionalString(location?.region);
2289
- const city = normalizeOptionalString(location?.city);
2290
- const timezone = normalizeOptionalString(location?.timezone);
2291
- if (country) threadConfig["tools.web_search.location.country"] = country;
2292
- if (region) threadConfig["tools.web_search.location.region"] = region;
2293
- if (city) threadConfig["tools.web_search.location.city"] = city;
2294
- if (timezone) threadConfig["tools.web_search.location.timezone"] = timezone;
2295
- return threadConfig;
2296
- }
2297
- function resolveCodexWebSearchPlan(params) {
2298
- if (params.disableTools === true || params.webSearchAllowed === false || params.config?.tools?.web?.search?.enabled === false) return {
2299
- kind: "disabled",
2300
- suppressManagedWebSearch: true,
2301
- threadConfig: CODEX_NATIVE_WEB_SEARCH_DISABLED_CONFIG
2302
- };
2303
- const nativeConfig = params.config?.tools?.web?.search?.openaiCodex;
2304
- const managedSearchExplicit = hasManagedSearchProvider(params.config) || nativeConfig?.enabled === false;
2305
- const nativeProviderSupportsSearch = params.nativeProviderWebSearchSupport === void 0 || params.nativeProviderWebSearchSupport === "supported";
2306
- if (!(params.nativeToolSurfaceEnabled !== false && nativeProviderSupportsSearch && nativeConfig?.enabled !== false && !hasManagedSearchProvider(params.config))) {
2307
- if (!managedSearchExplicit && hasNativeDomainRestrictions(params.config)) return {
2308
- kind: "disabled",
2309
- suppressManagedWebSearch: true,
2310
- threadConfig: CODEX_NATIVE_WEB_SEARCH_DISABLED_CONFIG
2311
- };
2312
- return {
2313
- kind: "managed",
2314
- suppressManagedWebSearch: false,
2315
- threadConfig: CODEX_NATIVE_WEB_SEARCH_DISABLED_CONFIG
2316
- };
2317
- }
2318
- return {
2319
- kind: "native-hosted",
2320
- suppressManagedWebSearch: true,
2321
- threadConfig: buildCodexNativeWebSearchThreadConfig(params.config),
2322
- webFetchHostnameAllowlist: buildHostnameAllowlistPolicyFromSuffixAllowlist(nativeConfig?.allowedDomains)?.hostnameAllowlist
2323
- };
2324
- }
2325
- const CODEX_CODE_MODE_THREAD_CONFIG = {
2326
- "features.code_mode": true,
2327
- "features.code_mode_only": false,
2328
- "features.shell_tool": true,
2329
- "features.apply_patch_streaming_events": true,
2330
- suppress_unstable_features_warning: true
2331
- };
2332
- const CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG = { "features.goals": false };
2333
- const CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG = { "tools.update_plan.enabled": false };
2334
- const CODEX_CODE_MODE_DISABLED_THREAD_CONFIG = {
2335
- "features.code_mode": false,
2336
- "features.code_mode_only": false
2337
- };
2338
- const CODEX_NO_PROJECT_DOCS_CONFIG = { project_doc_max_bytes: 0 };
2339
- const CODEX_TOOL_SEARCH_UNSUPPORTED_THREAD_CONFIG = { "features.multi_agent": false };
2340
- const CODEX_DELEGATION_DISABLED_THREAD_CONFIG = {
2341
- "agents.enabled": false,
2342
- "features.multi_agent": false,
2343
- "features.multi_agent_v2": false
2344
- };
2345
- const CODEX_RING_ZERO_RESTRICTED_FEATURES = /* @__PURE__ */ new Set([
2346
- "apps",
2347
- "artifact",
2348
- "browser_use",
2349
- "browser_use_external",
2350
- "browser_use_full_cdp_access",
2351
- "chronicle",
2352
- "code_mode",
2353
- "code_mode_only",
2354
- "computer_use",
2355
- "context_management",
2356
- "current_time_reminder",
2357
- "default_mode_request_user_input",
2358
- "deferred_executor",
2359
- "goals",
2360
- "hooks",
2361
- "image_generation",
2362
- "memories",
2363
- "multi_agent",
2364
- "multi_agent_v2",
2365
- "plugins",
2366
- "request_permissions_tool",
2367
- "skill_search",
2368
- "shell_tool",
2369
- "standalone_web_search",
2370
- "token_budget",
2371
- "unified_exec",
2372
- "view_image",
2373
- "web_search_cached",
2374
- "web_search_request",
2375
- "workspace_dependencies"
2376
- ]);
2377
- const CODEX_RING_ZERO_THREAD_CONFIG = {
2378
- ...CODEX_DELEGATION_DISABLED_THREAD_CONFIG,
2379
- ...Object.fromEntries([...CODEX_RING_ZERO_RESTRICTED_FEATURES].map((feature) => [`features.${feature}`, false])),
2380
- "orchestrator.mcp.enabled": false,
2381
- "orchestrator.skills.enabled": false,
2382
- "skills.bundled.enabled": false,
2383
- "skills.include_instructions": false,
2384
- "tools.experimental_request_user_input.enabled": false,
2385
- hooks: {
2386
- PreToolUse: [],
2387
- PermissionRequest: [],
2388
- PostToolUse: [],
2389
- PreCompact: [],
2390
- PostCompact: [],
2391
- SessionStart: [],
2392
- UserPromptSubmit: [],
2393
- SubagentStart: [],
2394
- SubagentStop: [],
2395
- Stop: []
2396
- },
2397
- notify: [],
2398
- web_search: "disabled"
2399
- };
2400
- const CODEX_RING_ZERO_RESTRICTED_FEATURE_ALIASES = /* @__PURE__ */ new Map([
2401
- ["connectors", "apps"],
2402
- ["imagegenext", "image_generation"],
2403
- ["collab", "multi_agent"],
2404
- ["memory_tool", "memories"],
2405
- ["telepathy", "chronicle"],
2406
- ["codex_hooks", "hooks"]
2407
- ]);
2408
- /** Common deterministic start/resume/fork fields; no run resources or unsupported setters. */
2409
- function buildCodexThreadConfiguration(params, options) {
2410
- return {
2411
- ...options.cwd !== void 0 ? { cwd: options.cwd } : {},
2412
- ...options.appServer.sessionRoot ? { runtimeWorkspaceRoots: [options.appServer.sessionRoot] } : {},
2413
- approvalPolicy: options.appServer.approvalPolicy,
2414
- approvalsReviewer: resolveCodexThreadApprovalsReviewer(options.appServer, options.config),
2415
- ...codexThreadSandboxOrPermissions(options.appServer),
2416
- ...options.appServer.serviceTier !== void 0 ? { serviceTier: options.appServer.serviceTier } : {},
2417
- config: buildCodexRuntimeThreadConfigForRun(params, options.config, {
2418
- nativeCodeModeEnabled: options.nativeCodeModeEnabled,
2419
- nativeProviderWebSearchSupport: options.nativeProviderWebSearchSupport,
2420
- nativeCodeModeOnlyEnabled: options.nativeCodeModeOnlyEnabled,
2421
- directOnlyToolNamespaces: resolveDirectOnlyToolNamespaces(options.dynamicTools),
2422
- webSearchAllowed: options.webSearchAllowed,
2423
- appServer: options.appServer,
2424
- hostSystemAgentActive: options.hostSystemAgentActive,
2425
- restrictedToolSurfaceInheritedMcpServerNames: options.restrictedToolSurfaceInheritedMcpServerNames,
2426
- shellEnvironment: options.shellEnvironment,
2427
- disableLoginShell: options.disableLoginShell
2428
- }),
2429
- developerInstructions: options.developerInstructions ?? buildDeveloperInstructions(params, { dynamicTools: options.dynamicTools })
2430
- };
2431
- }
2432
- function buildThreadStartParams(params, options) {
2433
- const resolvedModelProvider = resolveCodexAppServerModelProvider({
2434
- provider: params.provider,
2435
- authProfileId: params.authProfileId,
2436
- authProfileStore: params.authProfileStore,
2437
- agentDir: params.agentDir,
2438
- config: params.config
2439
- });
2440
- const modelSelection = resolveCodexAppServerRequestModelSelection({
2441
- model: options.model ?? params.modelId,
2442
- modelProvider: options.modelProvider ?? resolvedModelProvider,
2443
- authProfileId: params.authProfileId,
2444
- authProfileStore: params.authProfileStore,
2445
- agentDir: params.agentDir,
2446
- config: params.config
2447
- });
2448
- return {
2449
- model: modelSelection.model,
2450
- ...modelSelection.modelProvider ? { modelProvider: modelSelection.modelProvider } : {},
2451
- ...buildCodexThreadConfiguration(params, options),
2452
- ...(options.hostSystemAgentActive ?? isHostScopedAgentToolActive("openclaw")) && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow) ? { baseInstructions: "" } : {},
2453
- personality: CODEX_NATIVE_PERSONALITY_NONE,
2454
- serviceName: "OpenClaw",
2455
- threadSource: "openclaw",
2456
- ...resolveCodexThreadEnvironmentSelection(options),
2457
- dynamicTools: [...options.dynamicTools],
2458
- experimentalRawEvents: true,
2459
- ...isIncognitoSessionKey(params.sessionKey) ? { ephemeral: true } : {}
2460
- };
2461
- }
2462
- function buildThreadResumeParams(params, options) {
2463
- const modelSelection = options.preserveNativeModel ? void 0 : resolveCodexAppServerRequestModelSelection({
2464
- model: options.model ?? params.modelId,
2465
- modelProvider: options.modelProvider ?? resolveCodexAppServerModelProvider({
2466
- provider: params.provider,
2467
- authProfileId: options.authProfileId ?? params.authProfileId,
2468
- authProfileStore: params.authProfileStore,
2469
- agentDir: params.agentDir,
2470
- config: params.config
2471
- }),
2472
- authProfileId: options.authProfileId ?? params.authProfileId,
2473
- authProfileStore: params.authProfileStore,
2474
- agentDir: params.agentDir,
2475
- config: params.config
2476
- });
2477
- return {
2478
- threadId: options.threadId,
2479
- excludeTurns: true,
2480
- initialTurnsPage: {
2481
- limit: 1,
2482
- sortDirection: "desc",
2483
- itemsView: "notLoaded"
2484
- },
2485
- ...modelSelection ? {
2486
- model: modelSelection.model,
2487
- ...modelSelection.modelProvider ? { modelProvider: modelSelection.modelProvider } : {}
2488
- } : {},
2489
- ...buildCodexThreadConfiguration(params, options),
2490
- personality: CODEX_NATIVE_PERSONALITY_NONE
2491
- };
2492
- }
2493
- function buildCodexRuntimeThreadConfig(config, options = {}) {
2494
- const configured = buildCodexProjectDocThreadConfig(config);
2495
- const codeModeConfig = {
2496
- ...CODEX_CODE_MODE_THREAD_CONFIG,
2497
- "features.code_mode_only": options.nativeCodeModeOnlyEnabled === true
2498
- };
2499
- if (options.nativeCodeModeEnabled === false) {
2500
- 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");
2501
- delete disabledConfig["features.apply_patch_streaming_events"];
2502
- return disabledConfig;
575
+ else if (metadata?.linkId) approvalMode = normalizeAppToolApprovalMode(asOptionalRecord(links?.[metadata.linkId])?.default_tools_approval_mode) ?? approvalMode;
2503
576
  }
2504
- 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);
2505
- 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);
2506
- }
2507
- function ensureDirectOnlyToolNamespaces(config, requiredNamespaces) {
2508
- if (!requiredNamespaces?.length) return config;
2509
- const feature = expectDefined(config["features.code_mode"], "Codex code mode config");
2510
- const configured = isJsonObject(feature) ? feature : { enabled: feature };
2511
- const namespaces = Array.isArray(configured.direct_only_tool_namespaces) ? configured.direct_only_tool_namespaces.filter((entry) => typeof entry === "string" && entry.length > 0) : [];
2512
- return {
2513
- ...config,
2514
- "features.code_mode": {
2515
- ...configured,
2516
- direct_only_tool_namespaces: [.../* @__PURE__ */ new Set([...namespaces, ...requiredNamespaces])]
2517
- }
2518
- };
2519
- }
2520
- function resolveDirectOnlyToolNamespaces(dynamicTools) {
2521
- return (dynamicTools ?? []).filter((tool) => tool.type === "namespace" && tool.name === "openclaw_direct").map((tool) => tool.name);
2522
- }
2523
- function buildCodexRuntimeThreadConfigForRun(params, config, options = {}) {
2524
- const ringZeroActive = (options.hostSystemAgentActive ?? isHostScopedAgentToolActive("openclaw")) && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow);
2525
- const messageOnlySourceReply = isMessageOnlyCodexSourceReply(params);
2526
- const restrictedToolSurface = ringZeroActive || messageOnlySourceReply || params.pluginHarnessToolPolicyRestricted === true;
2527
- const restrictedTurnDisablesProjectDocs = ringZeroActive || messageOnlySourceReply || params.pluginHarnessToolPolicyRestricted && params.disableTools;
2528
- const configMcpServers = config?.mcp_servers;
2529
- if (restrictedToolSurface && configMcpServers !== void 0 && !isJsonObject(configMcpServers)) throw new Error("Codex restricted tool surface received invalid thread mcp_servers config");
2530
- const restrictedToolSurfaceMcpServerNames = [...options.restrictedToolSurfaceInheritedMcpServerNames ?? [], ...isJsonObject(configMcpServers) ? Object.keys(configMcpServers) : []];
2531
- const webSearchConfig = resolveCodexWebSearchPlan({
2532
- config: params.config,
2533
- disableTools: params.disableTools,
2534
- nativeToolSurfaceEnabled: options.nativeCodeModeEnabled,
2535
- nativeProviderWebSearchSupport: options.nativeProviderWebSearchSupport,
2536
- webSearchAllowed: options.webSearchAllowed
2537
- }).threadConfig;
2538
- const baseConfig = buildCodexRuntimeThreadConfig(mergeCodexThreadConfigs(config, webSearchConfig), options);
2539
- return applyCodexManagedShellEnvironment({
2540
- ...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, Boolean(params.scheduledRuntimeAuthority)) : 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,
2541
- ...params.bootstrapContextMode === "lightweight" ? CODEX_NO_PROJECT_DOCS_CONFIG : {}
2542
- }, options.shellEnvironment, options.disableLoginShell);
2543
- }
2544
- function buildCodexRingZeroThreadConfigPatch(params, hostSystemAgentActive = isHostScopedAgentToolActive("openclaw"), inheritedMcpServerNames = []) {
2545
- if (!hostSystemAgentActive || !isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow)) return;
2546
- return {
2547
- ...buildRestrictedToolConfigPatch(inheritedMcpServerNames),
2548
- ...CODEX_NO_PROJECT_DOCS_CONFIG
2549
- };
2550
- }
2551
- function buildRestrictedToolConfigPatch(inheritedMcpServerNames, scheduledAppAuthorityActive = false) {
2552
- const mcpServers = Object.fromEntries([...new Set(inheritedMcpServerNames)].toSorted().map((name) => [name, { enabled: false }]));
577
+ const defaultToolsEnabled = app?.default_tools_enabled;
2553
578
  return {
2554
- ...CODEX_RING_ZERO_THREAD_CONFIG,
2555
- ...scheduledAppAuthorityActive ? {
2556
- "features.apps": true,
2557
- "orchestrator.mcp.enabled": true
2558
- } : {},
2559
- ...Object.keys(mcpServers).length > 0 ? { mcp_servers: mcpServers } : {}
579
+ enabled: (app ? app.enabled !== false : defaults?.enabled !== false) && (typeof tool?.enabled === "boolean" ? tool.enabled : typeof defaultToolsEnabled === "boolean" ? defaultToolsEnabled : appToolHintsAllowed(metadata, {
580
+ allowDestructiveActions: (app?.destructive_enabled ?? defaults?.destructive_enabled) !== false,
581
+ allowOpenWorld: (app?.open_world_enabled ?? defaults?.open_world_enabled) !== false
582
+ })),
583
+ approvalMode
2560
584
  };
2561
585
  }
2562
- async function readCodexInheritedMcpServerNames(client, cwd, signal, effectiveConfig) {
2563
- const response = effectiveConfig ?? await readCodexEffectiveConfig(client, cwd, { signal });
2564
- if (!Array.isArray(response.layers)) throw new Error("Codex config/read omitted effective config layers");
2565
- for (const layer of response.layers) {
2566
- if (!isJsonObject(layer) || !isJsonObject(layer.name) || typeof layer.name.type !== "string") throw new Error("Codex config/read returned invalid effective config layers");
2567
- if (layer.name.type === "legacyManagedConfigTomlFromFile" || layer.name.type === "legacyManagedConfigTomlFromMdm") {
2568
- const migrationGuidance = layer.name.type === "legacyManagedConfigTomlFromFile" ? "migrate /etc/codex/managed_config.toml to /etc/codex/requirements.toml before running restricted or isolated turns. For ChatGPT-only authentication, use allowed_login_methods = [\"chatgpt\"] in /etc/codex/requirements.toml" : "replace the legacy MDM payload with base64-encoded TOML requirements in the com.openai.codex managed preference requirements_toml_base64 before running restricted or isolated turns. For ChatGPT-only authentication, include allowed_login_methods = [\"chatgpt\"] in that TOML payload";
2569
- throw new Error(`Codex restricted tool surface cannot override config layer ${layer.name.type}; ${migrationGuidance}.`);
2570
- }
2571
- if (!CODEX_SESSION_OVERRIDABLE_LAYER_TYPES.has(layer.name.type)) throw new Error(`Codex restricted tool surface does not recognize config layer ${layer.name.type}`);
2572
- }
2573
- const configuredServers = response.config.mcp_servers;
2574
- if (configuredServers === void 0) return [];
2575
- if (!isJsonObject(configuredServers)) throw new Error("Codex config/read returned invalid mcp_servers");
2576
- return Object.keys(configuredServers).toSorted();
2577
- }
2578
- async function assertCodexManagedRequirementsDoNotOverrideToolPolicy(client, options, signal) {
2579
- const requirements = await readCodexManagedRequirements(client, signal);
2580
- const managedRequirementsFingerprint = buildCodexManagedRequirementsFingerprint(requirements);
2581
- const managedRequirementsMatch = options.allowedManagedRequirementsFingerprint !== void 0 && managedRequirementsFingerprint === options.allowedManagedRequirementsFingerprint;
2582
- const managedHooksAllowed = managedRequirementsMatch || options.allowConfiguredManagedHooks === true;
2583
- if (options.allowedManagedRequirementsFingerprint !== void 0 && !managedRequirementsMatch) throw new Error("Codex managed requirements changed since this automation was authorized; reauthorize the automation from a fresh owner turn");
2584
- if (requirements === null) return;
2585
- if (options.restrictedToolSurface) for (const key of [
2586
- "hooks",
2587
- "managedHooks",
2588
- "managed_hooks"
2589
- ]) {
2590
- const hooks = requirements[key];
2591
- if (hooks === void 0 || hooks === null) continue;
2592
- if (!isJsonObject(hooks)) throw new Error("Codex configRequirements/read returned invalid managed hooks");
2593
- if (hasNonEmptyJsonValue(hooks) && !managedHooksAllowed) throw new Error("Codex restricted tool surface cannot override managed hooks");
2594
- }
2595
- const additionalDeniedFeatures = new Set(options.additionalDeniedFeatures);
2596
- for (const key of ["featureRequirements", "feature_requirements"]) {
2597
- const featureRequirements = requirements[key];
2598
- if (featureRequirements === void 0 || featureRequirements === null) continue;
2599
- if (!isJsonObject(featureRequirements)) throw new Error("Codex configRequirements/read returned invalid feature requirements");
2600
- for (const [feature, enabled] of Object.entries(featureRequirements)) {
2601
- if (typeof enabled !== "boolean") throw new Error("Codex configRequirements/read returned invalid feature requirements");
2602
- const canonicalFeature = CODEX_RING_ZERO_RESTRICTED_FEATURE_ALIASES.get(feature) ?? feature;
2603
- if (options.requiredNativeShell && canonicalFeature === "shell_tool" && !enabled) throw new Error("Codex native code mode requires shell_tool, but managed requirements disable it. Ask your administrator to allow the shell, or select a tool policy that disables native code mode; no automation authority was captured.");
2604
- const deniedByToolPolicy = options.restrictedToolSurface && CODEX_RING_ZERO_RESTRICTED_FEATURES.has(canonicalFeature) || additionalDeniedFeatures.has(canonicalFeature);
2605
- if (canonicalFeature === "hooks" && managedHooksAllowed) continue;
2606
- if (enabled && deniedByToolPolicy) throw new Error(`Codex tool policy cannot override required feature ${feature}`);
2607
- }
2608
- }
2609
- }
2610
- /** Hashes the exact managed requirements without retaining their hook commands or policy details. */
2611
- function buildCodexManagedRequirementsFingerprint(requirements) {
2612
- const fingerprint = fingerprintJsonObject({
2613
- version: 1,
2614
- requirements
2615
- });
2616
- return crypto.createHash("sha256").update(fingerprint).digest("hex");
2617
- }
2618
- /** Reads and fingerprints the exact managed requirements active on this app-server. */
2619
- async function readCodexManagedRequirementsFingerprint(client, signal) {
2620
- return buildCodexManagedRequirementsFingerprint(await readCodexManagedRequirements(client, signal));
2621
- }
2622
- async function readCodexManagedRequirements(client, signal) {
2623
- const response = await client.request("configRequirements/read", void 0, { signal });
2624
- if (!isJsonObject(response) || !Object.hasOwn(response, "requirements")) throw new Error("Codex configRequirements/read returned an invalid response");
2625
- if (response.requirements !== null && !isJsonObject(response.requirements)) throw new Error("Codex configRequirements/read returned invalid requirements");
2626
- return response.requirements;
2627
- }
2628
- function hasNonEmptyJsonValue(value) {
2629
- if (value === null || value === false || value === "") return false;
2630
- if (Array.isArray(value)) return value.length > 0;
2631
- if (typeof value === "object") return Object.values(value).some(hasNonEmptyJsonValue);
2632
- return true;
2633
- }
2634
- function resolveCodexThreadApprovalsReviewer(appServer, config) {
2635
- return config?.approvals_reviewer === "user" ? "user" : appServer.approvalsReviewer;
2636
- }
2637
- function codexThreadSandboxOrPermissions(appServer) {
2638
- if (appServer.networkProxy) return {};
2639
- return { sandbox: appServer.sandbox };
586
+ function appToolHintsAllowed(tool, policy) {
587
+ return (policy.allowDestructiveActions || tool?.destructiveHint === false) && (policy.allowOpenWorld !== false || tool?.openWorldHint === false);
2640
588
  }
2641
- function resolveCodexThreadEnvironmentSelection(options) {
2642
- if (options.nativeCodeModeEnabled === false) return { environments: [] };
2643
- if (options.environmentSelection) return { environments: options.environmentSelection };
2644
- return {};
589
+ function intersectToolApprovalMode(captured, current) {
590
+ if (captured === current) return captured;
591
+ if (captured === "prompt" || current === "prompt") return "prompt";
592
+ if (captured === "approve") return current;
593
+ if (current === "approve") return captured;
594
+ return "prompt";
2645
595
  }
2646
596
  //#endregion
2647
597
  //#region extensions/codex/src/app-server/scheduled-app-authority.ts
@@ -2681,9 +631,6 @@ function resolveScheduledCodexAppCreatorCaptureDecision(params) {
2681
631
  function normalizeApprovalMode(value) {
2682
632
  return value === "allow" || value === "deny" || value === "auto" || value === "ask" ? value : void 0;
2683
633
  }
2684
- function normalizeAppToolApprovalMode(value) {
2685
- return value === "auto" || value === "prompt" || value === "writes" || value === "approve" ? value : void 0;
2686
- }
2687
634
  function defaultApprovalMode(entry) {
2688
635
  return entry.destructiveApprovalMode ?? (entry.allowDestructiveActions ? "allow" : "deny");
2689
636
  }
@@ -2754,9 +701,12 @@ async function readCodexScheduledAppToolsByApp(params) {
2754
701
  if (connectorId) {
2755
702
  const tools = toolsByApp.get(connectorId) ?? /* @__PURE__ */ new Map();
2756
703
  const metadata = asOptionalRecord(tool);
704
+ const appMetadata = asOptionalRecord(metadata?._meta);
2757
705
  const annotations = asOptionalRecord(metadata?.annotations);
2758
706
  tools.set(toolName, {
2759
707
  title: typeof metadata?.title === "string" ? metadata.title : void 0,
708
+ linkId: typeof appMetadata?.link_id === "string" && appMetadata.link_id.trim() ? appMetadata.link_id : void 0,
709
+ requiresExplicitLinkId: asOptionalRecord(appMetadata?.["_codex_apps"])?.requires_explicit_link_id === true,
2760
710
  destructiveHint: annotations?.destructiveHint === false ? false : void 0,
2761
711
  openWorldHint: annotations?.openWorldHint === false ? false : void 0
2762
712
  });
@@ -2784,24 +734,6 @@ async function readCurrentCodexScheduledAppPolicy(params) {
2784
734
  toolsByApp
2785
735
  };
2786
736
  }
2787
- function readCurrentToolPolicy(config, appId, toolName, metadata, fallbackApprovalMode = "auto") {
2788
- const apps = asOptionalRecord(config.apps);
2789
- const app = asOptionalRecord(apps?.[appId]);
2790
- const defaults = asOptionalRecord(apps?.["_default"]);
2791
- const tools = asOptionalRecord(app?.tools);
2792
- const tool = asOptionalRecord(tools?.[toolName] ?? (metadata?.title !== void 0 ? tools?.[metadata.title] : void 0));
2793
- const defaultToolsEnabled = app?.default_tools_enabled;
2794
- return {
2795
- enabled: (app ? app.enabled !== false : defaults?.enabled !== false) && (typeof tool?.enabled === "boolean" ? tool.enabled : typeof defaultToolsEnabled === "boolean" ? defaultToolsEnabled : appToolHintsAllowed(metadata, {
2796
- allowDestructiveActions: (app?.destructive_enabled ?? defaults?.destructive_enabled) !== false,
2797
- allowOpenWorld: (app?.open_world_enabled ?? defaults?.open_world_enabled) !== false
2798
- })),
2799
- approvalMode: normalizeAppToolApprovalMode(tool?.approval_mode) ?? normalizeAppToolApprovalMode(app?.default_tools_approval_mode) ?? normalizeAppToolApprovalMode(defaults?.default_tools_approval_mode) ?? fallbackApprovalMode
2800
- };
2801
- }
2802
- function appToolHintsAllowed(tool, policy) {
2803
- return (policy.allowDestructiveActions || tool?.destructiveHint === false) && (policy.allowOpenWorld !== false || tool?.openWorldHint === false);
2804
- }
2805
737
  /** Captures only apps callable on the exact active Codex client/thread. */
2806
738
  async function captureScheduledCodexAppAuthority(params) {
2807
739
  const requestedTimeoutMs = params.timeoutMs ?? CODEX_APP_AUTHORITY_CAPTURE_TIMEOUT_MS;
@@ -2884,13 +816,6 @@ const APPROVAL_RANK = {
2884
816
  function stricterApprovalMode(left, right) {
2885
817
  return APPROVAL_RANK[left] <= APPROVAL_RANK[right] ? left : right;
2886
818
  }
2887
- function intersectToolApprovalMode(captured, current) {
2888
- if (captured === current) return captured;
2889
- if (captured === "prompt" || current === "prompt") return "prompt";
2890
- if (captured === "approve") return current;
2891
- if (current === "approve") return captured;
2892
- return "prompt";
2893
- }
2894
819
  function appApprovalCeiling(mode) {
2895
820
  if (mode === "allow") return "approve";
2896
821
  return mode === "ask" ? "prompt" : "auto";
@@ -2923,7 +848,8 @@ function intersectCodexPluginThreadConfigWithScheduledAuthority(config, authorit
2923
848
  destructiveApprovalMode: stricterApprovalMode(defaultApprovalMode(current), captured.destructiveApprovalMode)
2924
849
  };
2925
850
  }
2926
- const policyContext = buildPluginAppPolicyContext(apps, Object.fromEntries(Object.entries(config.policyContext.pluginAppIds).map(([key, ids]) => [key, ids.filter((id) => Object.hasOwn(apps, id))]).filter(([, ids]) => ids.length > 0)));
851
+ const pluginAppIds = Object.fromEntries(Object.entries(config.policyContext.pluginAppIds).map(([key, ids]) => [key, ids.filter((id) => Object.hasOwn(apps, id))]).filter(([, ids]) => ids.length > 0));
852
+ const policyContext = buildPluginAppPolicyContext(apps, pluginAppIds);
2927
853
  const configPatch = disableUnlistedCodexApps(buildCodexPluginAppsConfigPatchFromPolicyContext(policyContext), currentPolicy.config);
2928
854
  const appsPatch = asOptionalRecord(configPatch.apps);
2929
855
  for (const [appId, captured] of capturedById) {
@@ -3077,13 +1003,14 @@ async function prepareCodexThreadLifecyclePreflight(params) {
3077
1003
  const legacyDynamicToolsFingerprint = lifecycleTiming.measureSync("legacy-dynamic-tools-fingerprint", () => codexLegacyDynamicToolsFingerprint(params.dynamicTools));
3078
1004
  const dynamicToolsFingerprint = lifecycleTiming.measureSync("dynamic-tools-fingerprint", () => hashCodexAppServerBindingFingerprint(legacyDynamicToolsFingerprint));
3079
1005
  const dynamicToolsContainDeferred = flattenCodexDynamicToolFunctions(params.dynamicTools).some((tool) => tool.deferLoading === true);
3080
- const webSearchThreadConfigFingerprint = fingerprintJsonObject(lifecycleTiming.measureSync("web-search-plan", () => resolveCodexWebSearchPlan({
1006
+ const webSearchPlan = lifecycleTiming.measureSync("web-search-plan", () => resolveCodexWebSearchPlan({
3081
1007
  config: params.params.config,
3082
1008
  disableTools: params.params.disableTools,
3083
1009
  nativeToolSurfaceEnabled: params.nativeCodeModeEnabled,
3084
1010
  nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
3085
1011
  webSearchAllowed: params.webSearchAllowed
3086
- })).threadConfig);
1012
+ }));
1013
+ const webSearchThreadConfigFingerprint = fingerprintJsonObject(webSearchPlan.threadConfig);
3087
1014
  const networkProxyConfigFingerprint = params.appServer.networkProxy?.configFingerprint;
3088
1015
  const contextEngineBinding = lifecycleTiming.measureSync("context-engine-binding", () => buildContextEngineBinding(params.params, params.contextEngineProjection));
3089
1016
  const userMcpServersConfigPatch = params.userMcpServersEnabled === false ? void 0 : await buildCodexUserMcpServersThreadConfigPatchForRun({
@@ -3094,12 +1021,12 @@ async function prepareCodexThreadLifecyclePreflight(params) {
3094
1021
  warn: (message) => embeddedAgentLog.warn(message),
3095
1022
  onServerUnavailable: (serverName, error) => embeddedAgentLog.warn("skipping unavailable MCP OAuth server", {
3096
1023
  serverName,
3097
- error: formatErrorMessage$1(error)
1024
+ error: formatErrorMessage(error)
3098
1025
  })
3099
1026
  });
3100
1027
  const nativeSkillIsolation = await lifecycleTiming.measure("native-skill-isolation", () => resolveCodexNativeSkillIsolation({
3101
1028
  client: params.client,
3102
- codexHome: params.appServer.start.env?.CODEX_HOME,
1029
+ codexHome: params.appServer.start.codexHome ?? params.appServer.start.env?.CODEX_HOME,
3103
1030
  cwd: params.cwd,
3104
1031
  home: params.appServer.start.env?.HOME,
3105
1032
  signal: params.signal,
@@ -3265,6 +1192,7 @@ async function resumeExistingCodexThread(params, context) {
3265
1192
  const resumePatch = {
3266
1193
  clientId: resolveCodexAppServerClientInstanceId(params.client),
3267
1194
  pendingResumeConfiguration: void 0,
1195
+ ...resumeBinding.agentWorkspaceDeveloperInstructions === void 0 && params.agentWorkspaceDeveloperInstructions !== void 0 ? { agentWorkspaceDeveloperInstructions: params.agentWorkspaceDeveloperInstructions } : {},
3268
1196
  cwd: params.cwd,
3269
1197
  rolloutPath: resolveCodexThreadRolloutPath(response.thread) ?? resumeBinding.rolloutPath,
3270
1198
  authProfileId,
@@ -3613,7 +1541,7 @@ async function tryReuseCodexLiveThread(options) {
3613
1541
  }
3614
1542
  return { kind: "rotate" };
3615
1543
  }
3616
- if (!binding.clientId || binding.clientId !== clientId || binding.preserveNativeModel === true || binding.connectionScope === "supervision" || ringZeroActive && !incognito) return { kind: "resume" };
1544
+ if (!binding.clientId || binding.clientId !== clientId || ringZeroActive && !incognito) return { kind: "resume" };
3617
1545
  const retainedThread = await consumeCodexAppServerLiveThread(params.client, binding.threadId);
3618
1546
  if (!retainedThread) return { kind: "resume" };
3619
1547
  const assertWarmOwner = () => {
@@ -3629,8 +1557,23 @@ async function tryReuseCodexLiveThread(options) {
3629
1557
  };
3630
1558
  let ownershipTransferred = false;
3631
1559
  let preserveSubscription = false;
1560
+ let nativeThread;
3632
1561
  try {
3633
1562
  assertWarmOwner();
1563
+ if (binding.preserveNativeModel || binding.connectionScope === "supervision") {
1564
+ try {
1565
+ nativeThread = await assertAdoptedCodexThreadResumeAllowed(params, binding.threadId, options, assertWarmOwner);
1566
+ } catch (error) {
1567
+ assertWarmOwner();
1568
+ preserveSubscription = isSameCodexAppServerThreadOwner(params.bindingStore.read(bindingIdentity), binding);
1569
+ throw error;
1570
+ }
1571
+ assertWarmOwner();
1572
+ if (nativeThread.status?.type === "notLoaded") {
1573
+ preserveSubscription = true;
1574
+ return { kind: "resume" };
1575
+ }
1576
+ }
3634
1577
  const pluginThreadConfig = await options.buildLoadedPluginThreadConfig(binding);
3635
1578
  assertWarmOwner();
3636
1579
  if (pluginThreadConfig && pluginThreadConfig.fingerprint !== binding.pluginAppsFingerprint) return { kind: "rotate" };
@@ -3642,7 +1585,7 @@ async function tryReuseCodexLiveThread(options) {
3642
1585
  nativeHookRelayGeneration: params.nativeHookRelayGeneration
3643
1586
  };
3644
1587
  const pluginAppsConfigPatch = pluginThreadConfig?.configPatch ?? (params.pluginThreadConfig?.enabled && binding.pluginAppPolicyContext ? buildCodexPluginAppsConfigPatchFromPolicyContext(binding.pluginAppPolicyContext) : void 0);
3645
- const resumeAuthProfileId = params.params.authProfileId ?? binding.authProfileId;
1588
+ const resumeAuthProfileId = binding.connectionScope === "supervision" ? void 0 : params.params.authProfileId ?? binding.authProfileId;
3646
1589
  const resumeConfig = mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginAppsConfigPatch, prebuiltFinalConfigPatch.configPatch);
3647
1590
  const resumeParams = lifecycleTiming.measureSync("warm-thread-resume-params", () => buildThreadResumeParams(params.params, {
3648
1591
  threadId: binding.threadId,
@@ -3650,7 +1593,7 @@ async function tryReuseCodexLiveThread(options) {
3650
1593
  authProfileId: resumeAuthProfileId,
3651
1594
  model: startModelSelection.model,
3652
1595
  modelProvider: startModelProvider,
3653
- preserveNativeModel: false,
1596
+ preserveNativeModel: binding.preserveNativeModel === true,
3654
1597
  appServer: params.appServer,
3655
1598
  dynamicTools: params.dynamicTools,
3656
1599
  developerInstructions: params.developerInstructions,
@@ -3666,10 +1609,10 @@ async function tryReuseCodexLiveThread(options) {
3666
1609
  }));
3667
1610
  const liveThreadConfigFingerprint = incognito ? retainedThread.configFingerprint : fingerprintCodexThreadConfig({
3668
1611
  ...resumeParams,
3669
- model: binding.model ?? resumeParams.model ?? null,
3670
- requestedModel: resumeParams.model ?? null,
3671
- modelProvider: binding.modelProvider ?? resumeParams.modelProvider ?? null,
3672
- requestedModelProvider: resumeParams.modelProvider ?? binding.modelProvider ?? null
1612
+ model: binding.preserveNativeModel ? null : binding.model ?? resumeParams.model ?? null,
1613
+ requestedModel: binding.preserveNativeModel ? null : resumeParams.model ?? null,
1614
+ modelProvider: binding.preserveNativeModel ? null : binding.modelProvider ?? resumeParams.modelProvider ?? null,
1615
+ requestedModelProvider: binding.preserveNativeModel ? null : resumeParams.modelProvider ?? binding.modelProvider ?? null
3673
1616
  }, resumeAuthProfileId, dynamicToolsFingerprint);
3674
1617
  if (incognito && retainedThread.ephemeralPolicy !== resumeParams.developerInstructions) {
3675
1618
  preserveSubscription = true;
@@ -3694,13 +1637,15 @@ async function tryReuseCodexLiveThread(options) {
3694
1637
  });
3695
1638
  assertWarmOwner();
3696
1639
  const nativeHookRelayGeneration = prebuiltFinalConfigPatch.nativeHookRelayGeneration ?? binding.nativeHookRelayGeneration;
3697
- const model = startModelSelection.model;
1640
+ const model = binding.preserveNativeModel ? nativeThread?.model?.trim() || binding.model : startModelSelection.model;
1641
+ const modelProvider = binding.preserveNativeModel ? nativeThread?.modelProvider?.trim() || binding.modelProvider : binding.modelProvider;
3698
1642
  if (!(incognito || await lifecycleTiming.measure("warm-thread-write-binding", () => params.bindingStore.mutate(bindingIdentity, {
3699
1643
  kind: "patch",
3700
1644
  threadId: binding.threadId,
3701
1645
  patch: {
3702
1646
  cwd: params.cwd,
3703
1647
  model,
1648
+ modelProvider,
3704
1649
  nativeHookRelayGeneration,
3705
1650
  environmentSelectionFingerprint
3706
1651
  }
@@ -3722,6 +1667,7 @@ async function tryReuseCodexLiveThread(options) {
3722
1667
  ...!incognito ? {
3723
1668
  cwd: params.cwd,
3724
1669
  model,
1670
+ modelProvider,
3725
1671
  nativeHookRelayGeneration,
3726
1672
  environmentSelectionFingerprint
3727
1673
  } : {},
@@ -3736,6 +1682,12 @@ async function tryReuseCodexLiveThread(options) {
3736
1682
  if (!ownershipTransferred) {
3737
1683
  let failure;
3738
1684
  try {
1685
+ if (preserveSubscription) try {
1686
+ assertWarmOwner();
1687
+ preserveSubscription = isSameCodexAppServerThreadOwner(params.bindingStore.read(bindingIdentity), binding);
1688
+ } catch {
1689
+ preserveSubscription = false;
1690
+ }
3739
1691
  if (preserveSubscription) {
3740
1692
  if (!await retainCodexAppServerBindingSubscription(params.client, binding.threadId, retainedThread)) failure = { cause: /* @__PURE__ */ new Error("Codex live thread ownership could not be returned to its session") };
3741
1693
  } else await retainedThread.release(binding.threadId);
@@ -3753,21 +1705,6 @@ async function tryReuseCodexLiveThread(options) {
3753
1705
  }
3754
1706
  //#endregion
3755
1707
  //#region extensions/codex/src/app-server/thread-lifecycle-adoption.ts
3756
- /** Passive refusal must precede releasing or acquiring any native subscription. */
3757
- async function assertAdoptedCodexThreadResumeAllowed(params, threadId, context, assertCurrent) {
3758
- const { thread } = await context.lifecycleTiming.measure("thread-read-adoption-status", () => params.client.request("thread/read", {
3759
- threadId,
3760
- includeTurns: false
3761
- }, {
3762
- signal: params.signal,
3763
- assertCurrent
3764
- }));
3765
- context.throwIfAborted();
3766
- assertCodexThreadAcceptsDirectInput(thread);
3767
- if (thread.status?.type === "active") throw new CodexAdoptedThreadActiveError();
3768
- if (thread.id !== threadId) throw new Error("Codex returned another thread during adoption status read");
3769
- return thread;
3770
- }
3771
1708
  /** All bound preparation follows attach's native-queue-before-binding-lease order. */
3772
1709
  async function withCodexThreadLifecycleBinding(params, run) {
3773
1710
  const identity = sessionBindingIdentity({
@@ -4003,10 +1940,11 @@ async function materializePendingSupervisionBranch(params) {
4003
1940
  responseModelProvider: probeResponse.modelProvider,
4004
1941
  responseThreadModelProvider: probeResponse.thread.modelProvider
4005
1942
  });
4006
- const startParams = buildThreadStartParams({
1943
+ const nativeAttempt = {
4007
1944
  ...params.attempt,
4008
1945
  modelId: nativeModel
4009
- }, {
1946
+ };
1947
+ const startParams = buildThreadStartParams(nativeAttempt, {
4010
1948
  cwd: params.cwd,
4011
1949
  dynamicTools: params.dynamicTools,
4012
1950
  appServer: params.appServer,
@@ -4271,7 +2209,7 @@ async function archiveSupervisionArtifact(client, threadId) {
4271
2209
  await client.request("thread/archive", { threadId }, { timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS });
4272
2210
  return true;
4273
2211
  } catch (error) {
4274
- const message = formatErrorMessage$1(error).toLowerCase();
2212
+ const message = formatErrorMessage(error).toLowerCase();
4275
2213
  if (message.includes("no rollout found for thread id") || message.includes("thread not found") || message.includes("already archived")) return true;
4276
2214
  await unsubscribeCodexThreadBestEffort(client, {
4277
2215
  threadId,
@@ -4662,47 +2600,6 @@ async function startOrResumeThread(input) {
4662
2600
  });
4663
2601
  }
4664
2602
  //#endregion
4665
- //#region extensions/codex/src/app-server/reasoning-effort.ts
4666
- const CODEX_REASONING_EFFORTS = [
4667
- "minimal",
4668
- "low",
4669
- "medium",
4670
- "high",
4671
- "xhigh",
4672
- "max"
4673
- ];
4674
- const LEGACY_PRO_REASONING_EFFORTS = [
4675
- "medium",
4676
- "high",
4677
- "xhigh"
4678
- ];
4679
- const LEGACY_PRO_MODEL_ID_RE = /^gpt-5\.[45]-pro$/u;
4680
- const MODERN_GPT_5_MODEL_ID_RE = /^gpt-5\.(?:[3-9]|[1-9]\d)(?:$|-)/u;
4681
- /** Read reasoning metadata after the Codex app-server route has been selected. */
4682
- function readCodexSupportedReasoningEfforts(compat) {
4683
- return compat && "supportedReasoningEfforts" in compat ? compat.supportedReasoningEfforts : void 0;
4684
- }
4685
- function resolveSupportedReasoningEffort(params) {
4686
- const declared = new Set(params.supportedReasoningEfforts.map((effort) => effort.trim().toLowerCase()));
4687
- const supported = CODEX_REASONING_EFFORTS.filter((effort) => declared.has(effort));
4688
- if (supported.includes(params.requested)) return params.requested;
4689
- const requestedRank = CODEX_REASONING_EFFORTS.indexOf(params.requested);
4690
- return supported.find((effort) => CODEX_REASONING_EFFORTS.indexOf(effort) >= requestedRank) ?? supported.at(-1);
4691
- }
4692
- function resolveCodexAppServerReasoningEffort(params) {
4693
- if (params.thinkLevel === "ultra") return "ultra";
4694
- if (params.thinkLevel === "off") return params.supportedReasoningEfforts?.includes("none") ? "none" : null;
4695
- if (params.thinkLevel === "adaptive") return null;
4696
- const modelId = params.modelId.trim().toLowerCase();
4697
- const supportedReasoningEfforts = params.supportedReasoningEfforts ?? (LEGACY_PRO_MODEL_ID_RE.test(modelId) ? LEGACY_PRO_REASONING_EFFORTS : void 0);
4698
- if (supportedReasoningEfforts) return resolveSupportedReasoningEffort({
4699
- requested: params.thinkLevel,
4700
- supportedReasoningEfforts
4701
- }) ?? null;
4702
- if (params.thinkLevel === "minimal" && MODERN_GPT_5_MODEL_ID_RE.test(modelId)) return "low";
4703
- return params.thinkLevel === "max" ? null : params.thinkLevel;
4704
- }
4705
- //#endregion
4706
2603
  //#region extensions/codex/src/app-server/user-input.ts
4707
2604
  function prependHistoryProvenance(input, historyProvenancePrefix) {
4708
2605
  if (!historyProvenancePrefix) return input;
@@ -4796,6 +2693,10 @@ function buildTurnStartParams(params, options) {
4796
2693
  let additionalContext = buildCodexTemporalAdditionalContext(params, { sessionStatusAvailable: options.sessionStatusAvailable === true });
4797
2694
  additionalContext = {
4798
2695
  ...additionalContext,
2696
+ openclaw_active_computer: {
2697
+ kind: "application",
2698
+ value: params.hostCapabilities.activeComputerContext?.() ?? "Current active computer: active_node=unknown (host presence unavailable)"
2699
+ },
4799
2700
  openclaw_source_delivery: {
4800
2701
  kind: "application",
4801
2702
  value: ["Current source-delivery policy for this turn (replaces earlier source-delivery guidance):", buildHarnessVisibleReplyGuidance({
@@ -4901,4 +2802,4 @@ function joinPresentSections(...sections) {
4901
2802
  return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
4902
2803
  }
4903
2804
  //#endregion
4904
- export { areCodexDynamicToolFingerprintsCompatible as $, resolveCodexBindingModelProviderFallback as A, shouldBuildCodexPluginThreadConfig as At, buildCodexNativeHookRelayId as B, buildCodexNativeWebSearchThreadConfig as C, resolveCodexContinuityProjectionMaxChars as Ct, resolveCodexAppServerModelProvider as D, buildDisabledAppsConfigPatch as Dt, CODEX_NATIVE_PERSONALITY_NONE as E, buildCodexPluginThreadConfigTimeoutFallback as Et, CODEX_NATIVE_HOOK_RELAY_EVENTS as F, scheduleCodexNativeHookRelayUnregister as G, emitCodexNativePreToolUseFailureDiagnostic as H, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as I, hasCodexNativeToolCatalog as J, checkCodexThreadAppAvailability as K, assertCodexNativeHookRelayAllowed as L, readCodexMcpToolUiVisibility as M, buildCodexProjectDocThreadConfig as N, resolveCodexAppServerRequestModelSelection as O, mergeCodexThreadConfigs as Ot, isCodexAppServerProfilerEnabled as P, resolveCodexNativeSkillIsolation as Q, buildCodexNativeHookRelayConfig as R, readCodexInheritedMcpServerNames as S, resolveCodexContextEngineProjectionReserveTokens as St, buildDeveloperInstructions as T, buildCodexPluginThreadConfigInputFingerprint as Tt, resolveCodexNativeHookRelayEvents as U, createCodexNativeHookRelay as V, resolveCodexNativeHookRelayTtlMs as W, parseCodexNativeToolCatalog as X, loadCodexNativeToolCatalog as Y, applyCodexNativeSkillIsolation as Z, resolveScheduledCodexAppCreatorCaptureDecision as _, fitCodexProjectedContextForTurnStart as _t, buildTurnStartParams as a, filterCodexDynamicToolsForDisabledNativeSurface as at, buildCodexRuntimeThreadConfig as b, projectContextEngineAssemblyForCodex as bt, resolveCodexAppServerReasoningEffort as c, isSystemAgentOnlyCodexDynamicToolAllowlist as ct, buildLegacyScheduledCodexAppRecoveryPrompt as d, resolveCodexDynamicToolsLoadingForRuntime as dt, codexDynamicToolsFingerprint as et, buildScheduledCodexAppAuthorityInputFingerprint as f, buildContextEngineBinding as ft, readCurrentCodexScheduledAppPolicy as g, buildCodexContinuityCalibration as gt, intersectCodexPluginThreadConfigWithScheduledAuthority as h, CodexContextAttachmentError as ht, buildTurnCollaborationMode as i, filterCodexDynamicTools as it, readCodexMcpToolConnectorId as j, resolveCodexAppServerThreadModelSelection as k, refreshCodexPluginAppApprovalPolicy as kt, startOrResumeThread as l, normalizeCodexDynamicToolName as lt, captureScheduledCodexAppAuthority as m, CODEX_TURN_START_TEXT_INPUT_MAX_CHARS as mt, buildCodexParentLocalInstructions as n, fingerprintJsonObject as nt, buildCodexUserInput as o, isForcedPrivateQaCodexRuntime as ot, buildScheduledCodexAppServerConnectionIdentity as p, isContextEngineBindingCompatible as pt, attestCodexRestrictedToolSurfaceMcpServersDisabled as q, buildCodexTemporalAdditionalContext as r, fingerprintUserMcpServersConfigPatch as rt, readCodexSupportedReasoningEfforts as s, isMessageOnlyCodexSourceReply as st, buildCodexHistoryProvenancePrefix as t, codexLegacyDynamicToolsFingerprint as tt, assertScheduledCodexAppAuthorityRuntime as u, resolveCodexDynamicToolsLoading as ut, assertCodexManagedRequirementsDoNotOverrideToolPolicy as v, isCodexDurableCustomMessage as vt, resolveCodexWebSearchPlan as w, buildCodexPluginThreadConfig as wt, buildCodexThreadConfiguration as x, resolveCodexContextEngineProjectionMaxChars as xt, buildCodexRingZeroThreadConfigPatch as y, neutralizeCodexExplicitMentionSigils as yt, buildCodexNativeHookRelayDisabledConfig as z };
2805
+ export { resolveCodexContinuityProjectionMaxChars as A, buildCodexContinuityCalibration as C, projectContextEngineAssemblyForCodex as D, neutralizeCodexExplicitMentionSigils as E, resolveCodexAppServerReasoningEffort as M, resolveCodexContextEngineProjectionMaxChars as O, CodexContextAttachmentError as S, isCodexDurableCustomMessage as T, readCodexMcpToolUiVisibility as _, buildTurnStartParams as a, isContextEngineBindingCompatible as b, assertScheduledCodexAppAuthorityRuntime as c, buildScheduledCodexAppServerConnectionIdentity as d, captureScheduledCodexAppAuthority as f, readCodexMcpToolConnectorId as g, resolveScheduledCodexAppCreatorCaptureDecision as h, buildTurnCollaborationMode as i, readCodexSupportedReasoningEfforts as j, resolveCodexContextEngineProjectionReserveTokens as k, buildLegacyScheduledCodexAppRecoveryPrompt as l, readCurrentCodexScheduledAppPolicy as m, buildCodexParentLocalInstructions as n, buildCodexUserInput as o, intersectCodexPluginThreadConfigWithScheduledAuthority as p, buildCodexTemporalAdditionalContext as r, startOrResumeThread as s, buildCodexHistoryProvenancePrefix as t, buildScheduledCodexAppAuthorityInputFingerprint as u, isCodexAppServerProfilerEnabled as v, fitCodexProjectedContextForTurnStart as w, CODEX_TURN_START_TEXT_INPUT_MAX_CHARS as x, buildContextEngineBinding as y };