@openclaw/codex 2026.9.4 → 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 (160) hide show
  1. package/assets/activity.svg +30 -0
  2. package/assets/icon.png +0 -0
  3. package/dist/.setup/account-usage-runtime-Eem_WGqY.mjs +75 -0
  4. package/dist/{apply-CvT8tW5i.js → .setup/apply-DDOi8uNx.mjs} +24 -30
  5. package/dist/.setup/async-questions-DdhOCwGi.mjs +27 -0
  6. package/dist/{attempt-client-cleanup-DKHzbwt5.js → .setup/attempt-client-cleanup-CEv1cKwF.mjs} +79 -49
  7. package/dist/.setup/attempt-terminal-gZrxQ35N.mjs +5 -0
  8. package/dist/.setup/attempt-workspace-context-DUVEn_CS.mjs +331 -0
  9. package/dist/{auth-binding-CWlKVccJ.js → .setup/auth-binding-DhLWa_7K.mjs} +1 -1
  10. package/dist/{auth-cache-key-7orQae_j.js → .setup/auth-cache-key-B2mpaI9D.mjs} +9 -81
  11. package/dist/{auth-profile-CwzO4_RG.js → .setup/auth-profile-WqZtZfXN.mjs} +1 -1
  12. package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
  13. package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
  14. package/dist/.setup/binding-connection-ThoatDcb.mjs +50 -0
  15. package/dist/.setup/binding-connection.runtime-yoHrABt-.mjs +48 -0
  16. package/dist/{bounded-turn-C_Hneydj.js → .setup/bounded-turn-B2HScEgT.mjs} +143 -32
  17. package/dist/{build-state-BCmg9-5p.js → .setup/build-state-C7EnDVgr.mjs} +1 -1
  18. package/dist/{capabilities-8vx68WLH.js → .setup/capabilities-CDXOOFdZ.mjs} +1 -1
  19. package/dist/{client-B57KWPQx.js → .setup/client-Cs08OXVQ.mjs} +705 -512
  20. package/dist/.setup/client-catalog-response-BMgt_4q4.mjs +285 -0
  21. package/dist/{command-dispatch-BpduNGVf.js → .setup/command-dispatch-B4JuOsOk.mjs} +8 -4
  22. package/dist/{command-formatters-lxlkNZgU.js → .setup/command-formatters-Bmqvr9tO.mjs} +8 -4
  23. package/dist/{command-handlers-tiL9iWj7.js → .setup/command-handlers-DW7Lx9oH.mjs} +137 -186
  24. package/dist/{command-rpc-CR5EOEZX.js → .setup/command-rpc-DixIj3HW.mjs} +47 -23
  25. package/dist/{compact-B_H3AOd7.js → .setup/compact-Du5UvtxA.mjs} +29 -51
  26. package/dist/{config-oIORaQ5T.js → .setup/config-BoTP_mrL.mjs} +5 -4
  27. package/dist/{config-options-CXMq1T-C.js → .setup/config-options-BvaRs51b.mjs} +50 -446
  28. package/dist/{protocol-5bh1G-H7.js → .setup/config-parsing-CcB9iPoq.mjs} +9 -51
  29. package/dist/{config-runtime-D0zGNIHu.js → .setup/config-runtime-C8Rw1m1m.mjs} +2 -2
  30. package/dist/.setup/config-security-BEReZ6go.mjs +380 -0
  31. package/dist/{conversation-binding-DsB4-O7U.js → .setup/conversation-binding-DP-gMrBP.mjs} +29 -38
  32. package/dist/{conversation-binding-data-BiodpIzq.js → .setup/conversation-binding-data-CrcyZk6O.mjs} +1 -1
  33. package/dist/{conversation-control-CtUu1b3m.js → .setup/conversation-control-uK9Jomlc.mjs} +32 -67
  34. package/dist/.setup/cyber-failover-DYwbmf1o.mjs +123 -0
  35. package/dist/.setup/cyber-failover-notice-e9G3J9-e.mjs +17 -0
  36. package/dist/{dynamic-tools-CmN5RAip.js → .setup/dynamic-tools-BDXl-8Cw.mjs} +936 -620
  37. package/dist/{effective-mcp-catalog-Bd73bqA8.js → .setup/effective-mcp-catalog-CvnvnGIe.mjs} +3 -3
  38. package/dist/{ephemeral-turn-D78_VmzO.js → .setup/ephemeral-turn-poidXgek.mjs} +9 -7
  39. package/dist/{event-projector-assistant-message-BmBM4qBV.js → .setup/event-projector-assistant-message-BsruvNrH.mjs} +8 -7
  40. package/dist/{event-projector-items-5VhsECCO.js → .setup/event-projector-items-C6L_5ZiT.mjs} +42 -8
  41. package/dist/{attempt-notifications-C9XufG6l.js → .setup/event-projector-usage-CnBS8Wa3.mjs} +102 -9
  42. package/dist/{harness-C7rRa7bm.js → .setup/harness-a_MsE4-_.mjs} +81 -21
  43. package/dist/{inference-context-Dr_mzvk4.js → .setup/inference-context-D96l9-ew.mjs} +1 -1
  44. package/dist/.setup/inference-proxy-b-aJMSxm.mjs +601 -0
  45. package/dist/{isolated-completion-DWVb5U2J.js → .setup/isolated-completion-BIZFhTNG.mjs} +18 -11
  46. package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
  47. package/dist/{managed-binary-D22rNEcR.js → .setup/managed-binary-BnshlFag.mjs} +14 -3
  48. package/dist/{managed-thread-store-D1t5jh3G.js → .setup/managed-thread-store-BMqgThVL.mjs} +48 -14
  49. package/dist/{model-catalog-Dq2n8f_p.js → .setup/model-catalog-CfXJf9Ay.mjs} +36 -12
  50. package/dist/{models-PCKOim-h.js → .setup/models-KnqBv0hE.mjs} +3 -3
  51. package/dist/.setup/native-auth-rWbGbMn3.mjs +57 -0
  52. package/dist/{native-subagent-history-DjtPloaU.js → .setup/native-subagent-history-0nYYgo0k.mjs} +43 -35
  53. package/dist/.setup/native-subagent-monitor-D3filLY2.mjs +4859 -0
  54. package/dist/{native-subagent-task-ids-BzTdT0Uw.js → .setup/native-subagent-task-ids-wb8CKZGN.mjs} +98 -44
  55. package/dist/{node-cli-sessions-DKaOmVUh.js → .setup/node-cli-sessions-r3avj02l.mjs} +86 -68
  56. package/dist/.setup/node-exec-server.runtime-BDwWXVpK.mjs +247 -0
  57. package/dist/{plan-7uG-Fp36.js → .setup/plan-CN3VwfNU.mjs} +133 -119
  58. package/dist/{plugin-activation-BYQculil.js → .setup/plugin-activation-DT3MNtqj.mjs} +7 -16
  59. package/dist/{plugin-app-cache-key-d0eKxy7b.js → .setup/plugin-app-cache-key-B2CsSdnV.mjs} +32 -44
  60. package/dist/{plugin-approval-roundtrip-Bz3FT8W5.js → .setup/plugin-approval-roundtrip-C0MZzCuP.mjs} +1 -1
  61. package/dist/{plugin-inventory-oL4Na1ZG.js → .setup/plugin-inventory-BoRei8Z4.mjs} +21 -11
  62. package/dist/{plugin-marketplace-discovery-P-Vndfqq.js → .setup/plugin-marketplace-discovery-CDOi8IFs.mjs} +4 -1
  63. package/dist/{plugin-metadata-cache-ClPJpRio.js → .setup/plugin-metadata-cache-Ctmo83k_.mjs} +226 -141
  64. package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
  65. package/dist/{provider-MQ8PVkuE.js → .setup/provider-BOsxQHOM.mjs} +9 -5
  66. package/dist/{provider-capabilities-BvCUL69A.js → .setup/provider-capabilities-BfE88FZ5.mjs} +31 -3
  67. package/dist/{rate-limits-CBMmWBr9.js → .setup/rate-limits-CMU3DUD0.mjs} +174 -151
  68. package/dist/{request-B7hEkBGq.js → .setup/request-D2L0zMrq.mjs} +130 -42
  69. package/dist/{run-attempt-CvsAAGa0.js → .setup/run-attempt-BHu11r7h.mjs} +1628 -966
  70. package/dist/.setup/run-attempt-lifecycle-B7JbY4-F.mjs +71 -0
  71. package/dist/{runtime-artifact-BJ0rXBZ_.js → .setup/runtime-artifact-CLZ8udh-.mjs} +29 -45
  72. package/dist/{sandbox-guard-BxgyoM8M.js → .setup/sandbox-guard-C2sRMOEY.mjs} +3 -3
  73. package/dist/{session-binding-CI8UuilT.js → .setup/session-binding-Cm0apEbd.mjs} +36 -83
  74. package/dist/{session-binding-record-Bcvslnhf.js → .setup/session-binding-record-BGoz8wOK.mjs} +202 -5
  75. package/dist/.setup/session-binding-sidecars-BlB5EvIS.mjs +546 -0
  76. package/dist/.setup/session-catalog-Pno1xGcl.mjs +2764 -0
  77. package/dist/{session-catalog-adoption-tcZi1IfX.js → .setup/session-catalog-adoption-BI6UTDZT.mjs} +58 -26
  78. package/dist/{session-catalog-archive-CwKg8Xz2.js → .setup/session-catalog-archive-lHBqzhaO.mjs} +6 -6
  79. package/dist/.setup/session-catalog-events-Bj6j94E_.mjs +347 -0
  80. package/dist/.setup/session-catalog-index-B9_VQIUz.mjs +1170 -0
  81. package/dist/.setup/session-catalog-index-order-hcdz07yN.mjs +48 -0
  82. package/dist/.setup/session-catalog-index-state-Dgh8ORJm.mjs +183 -0
  83. package/dist/{thread-history-page-D0JIp48V.js → .setup/session-catalog-native-projection-DowriLid.mjs} +223 -95
  84. package/dist/{session-catalog-node-adoption-B1tgDW-m.js → .setup/session-catalog-node-adoption-ITddWx_X.mjs} +25 -13
  85. package/dist/{session-catalog-node-continue-Ci-DXyJP.js → .setup/session-catalog-node-continue-6g6qi4A9.mjs} +24 -15
  86. package/dist/.setup/session-catalog-projection-zK_PUsiE.mjs +422 -0
  87. package/dist/{session-cli-DNN_jhGc.js → .setup/session-cli-irrD-uo7.mjs} +3 -3
  88. package/dist/{session-history-Cz-tOOYj.js → .setup/session-history-BrqhSCf9.mjs} +19 -19
  89. package/dist/{session-history-import-DwyijFI6.js → .setup/session-history-import-D-3wAgOP.mjs} +4 -4
  90. package/dist/{session-history-read-cxPUxyVV.js → .setup/session-history-read-B3ZfSUbF.mjs} +2 -2
  91. package/dist/{session-history.worker-BeK1YOyT.js → .setup/session-history.worker-CaCh0xF_.mjs} +10 -24
  92. package/dist/{session-initialization-Ct0_Hzmg.js → .setup/session-initialization-rcgbZiid.mjs} +2 -2
  93. package/dist/{session-permission-policy-BBmXA8Eg.js → .setup/session-permission-policy-BI1QK_98.mjs} +2 -2
  94. package/dist/{session-retirement-B2YfbAAT.js → .setup/session-retirement-BH-S6qkJ.mjs} +26 -7
  95. package/dist/{settled-turn-context-Du6gdUDd.js → .setup/settled-turn-context-fmwouT5I.mjs} +2 -2
  96. package/dist/{settled-turn-finalizer-Dn91stmc.js → .setup/settled-turn-finalizer-DiAi6Kx6.mjs} +12 -12
  97. package/dist/{shared-client-CscigXXL.js → .setup/shared-client-DA4VR4Eb.mjs} +332 -221
  98. package/dist/{side-question-BGMJQf4U.js → .setup/side-question-BJ1wSDcB.mjs} +183 -230
  99. package/dist/{source-CElXU0Oy.js → .setup/source-CUzJq5WN.mjs} +11 -10
  100. package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
  101. package/dist/{thread-archive-guard-DfpBr-Sz.js → .setup/thread-archive-guard-C9frICzX.mjs} +10 -3
  102. package/dist/.setup/thread-history-page-DoVpnHim.mjs +83 -0
  103. package/dist/{thread-lifecycle-DXl1-I6b.js → .setup/thread-lifecycle-B3mfz1TG.mjs} +347 -2318
  104. package/dist/{thread-ownership-BsDRTsyp.js → .setup/thread-ownership-DcTtAcXj.mjs} +6 -4
  105. package/dist/{thread-policy-BuEQfE0g.js → .setup/thread-policy-DGuQsuFC.mjs} +19 -3
  106. package/dist/.setup/thread-requests-BLvGkP2R.mjs +2205 -0
  107. package/dist/{thread-resume-DsDOZpFg.js → .setup/thread-resume-DIBXwOpE.mjs} +8 -5
  108. package/dist/.setup/timeout-C910MdAB.mjs +80 -0
  109. package/dist/{transcript-history-projection-v17wXgdK.js → .setup/transcript-history-projection-ZZpkFkJ_.mjs} +96 -61
  110. package/dist/{transcript-mirror-C5CKgNy6.js → .setup/transcript-mirror-BtHDBp1G.mjs} +224 -195
  111. package/dist/{transcript-mirror-attestation-DibE0krH.js → .setup/transcript-mirror-attestation-CzM-94NC.mjs} +4 -1
  112. package/dist/{transport-stdio-BGjHoYLr.js → .setup/transport-stdio-h2VHOskC.mjs} +274 -89
  113. package/dist/{upstream-session-fork-BZerMte_.js → .setup/upstream-session-fork-BUr4OUbC.mjs} +51 -42
  114. package/dist/{usage-tCk-mg_x.js → .setup/usage-BML0r-ua.mjs} +5 -4
  115. package/dist/.setup/usage-limit-error-DUMbefVY.mjs +166 -0
  116. package/dist/{web-search-provider.runtime-B7bGbGWq.js → .setup/web-search-provider.runtime-CDKlN-Rv.mjs} +4 -3
  117. package/dist/api.js +23 -12
  118. package/dist/catalog-page-worker-entrypoint.js +12 -0
  119. package/dist/catalog-page.worker.js +9 -0
  120. package/dist/cli-metadata.js +1 -1
  121. package/dist/doctor-contract-api.js +8 -528
  122. package/dist/harness.js +1 -1
  123. package/dist/index.js +306 -215
  124. package/dist/media-understanding-provider.js +3 -3
  125. package/dist/migration-provider-api.js +1 -1
  126. package/dist/native-tool-policy.js +12 -0
  127. package/dist/provider-discovery.js +18 -0
  128. package/dist/session-history-worker-runtime.js +36 -35
  129. package/dist/session-history.worker.js +2 -2
  130. package/dist/web-search-contract-api.js +1 -1
  131. package/openclaw.plugin.json +354 -69
  132. package/package.json +14 -8
  133. package/dist/attempt-context-D44yeDII.js +0 -636
  134. package/dist/binding-connection-D3udKbIE.js +0 -60
  135. package/dist/event-projector-usage-BfXmpOec.js +0 -102
  136. package/dist/inference-proxy-HGXKUIre.js +0 -311
  137. package/dist/launch-args-RXQwn8zV.js +0 -90
  138. package/dist/native-subagent-history-owner-Pcp7JuVF.js +0 -34
  139. package/dist/native-subagent-monitor-fQ7eIXEf.js +0 -2978
  140. package/dist/node-exec-server.runtime-Cl2vapEi.js +0 -226
  141. package/dist/rpc-error-ttN_QjEm.js +0 -30
  142. package/dist/session-catalog-ct-AH01I.js +0 -1477
  143. package/dist/session-catalog-home-id-CwhLdC03.js +0 -18
  144. package/dist/session-catalog-provenance-D-dIfRAH.js +0 -96
  145. package/dist/timeout-BVw8aaM1.js +0 -33
  146. package/dist/version-omm6IPI3.js +0 -12
  147. /package/dist/{auth-profile-selection-DFu9e167.js → .setup/auth-profile-selection-DFu9e167.mjs} +0 -0
  148. /package/dist/{config-utils-DujwEnhg.js → .setup/config-utils-DujwEnhg.mjs} +0 -0
  149. /package/dist/{context-compaction-activity-CMla5FPJ.js → .setup/context-compaction-activity-CMla5FPJ.mjs} +0 -0
  150. /package/dist/{elicitation-input-DPoK8F7w.js → .setup/elicitation-input-DPoK8F7w.mjs} +0 -0
  151. /package/dist/{history-rejection-B4nOXNXF.js → .setup/history-rejection-B4nOXNXF.mjs} +0 -0
  152. /package/dist/{image-payload-sanitizer-tupAr-2o.js → .setup/image-payload-sanitizer-tupAr-2o.mjs} +0 -0
  153. /package/dist/{incognito-session-uhrBF6wJ.js → .setup/incognito-session-uhrBF6wJ.mjs} +0 -0
  154. /package/dist/{local-runtime-attribution-B_2mnqhb.js → .setup/local-runtime-attribution-B_2mnqhb.mjs} +0 -0
  155. /package/dist/{native-execution-policy-umd0tgh4.js → .setup/native-execution-policy-umd0tgh4.mjs} +0 -0
  156. /package/dist/{rolldown-runtime-8H4AJuhK.js → .setup/rolldown-runtime-8H4AJuhK.mjs} +0 -0
  157. /package/dist/{session-binding-meta-B7aEMU7g.js → .setup/session-binding-meta-B7aEMU7g.mjs} +0 -0
  158. /package/dist/{session-upstream-marker-D15C9NHp.js → .setup/session-upstream-marker-D15C9NHp.mjs} +0 -0
  159. /package/dist/{upstream-prompt-provenance-LphB8slG.js → .setup/upstream-prompt-provenance-LphB8slG.mjs} +0 -0
  160. /package/dist/{web-search-provider.shared-BrZmlqyR.js → .setup/web-search-provider.shared-BrZmlqyR.mjs} +0 -0
@@ -1,619 +1,78 @@
1
- import { a as readCodexPluginInventory, o as resolveOwnedAppApprovalOverrideKeys } from "./plugin-inventory-oL4Na1ZG.js";
2
- import { l as sessionBindingIdentity, n as assertCodexBindingMayBeReplaced } from "./session-binding-record-Bcvslnhf.js";
3
- import { f as assertCodexModelBackedReviewerEffectiveConfig, g as readCodexEffectiveConfig, h as CODEX_SESSION_OVERRIDABLE_LAYER_TYPES, n as codexSandboxPolicyForTurn } from "./config-options-CXMq1T-C.js";
4
- import { S as resolveCodexPluginsPolicy, a as flattenCodexDynamicToolFunctions, c as resolveCodexAppServerLocalHomeDir, o as isJsonObject, s as resolveCodexAppServerHomeDir } from "./protocol-5bh1G-H7.js";
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-B57KWPQx.js";
6
- import { i as markStartedCodexManagedThread } from "./managed-thread-store-D1t5jh3G.js";
7
- import { n as withCodexAppServerThreadMutation, t as isIncognitoSessionKey } from "./incognito-session-uhrBF6wJ.js";
8
- import { n as isCodexThreadReadMissingError, t as CodexAppServerRpcError } from "./rpc-error-ttN_QjEm.js";
9
- import { t as projectBoundedCodexThreadHistory } from "./transcript-history-projection-v17wXgdK.js";
10
- import { c as serializeCodexAppInventoryError, o as CodexAppInventoryCache, s as defaultCodexAppInventoryCache, t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-d0eKxy7b.js";
11
- import { t as withAbortableTimeout } from "./timeout-BVw8aaM1.js";
12
- import { n as codexCatalogHomeId } from "./session-catalog-home-id-CwhLdC03.js";
13
- import { n as readCodexSessionMeta } from "./session-catalog-provenance-D-dIfRAH.js";
14
- import "./config-oIORaQ5T.js";
15
- import { r as sanitizeInlineImageDataUrl, t as invalidInlineImageText } from "./image-payload-sanitizer-tupAr-2o.js";
16
- import { t as assertCodexSessionRuntimeOwnership } from "./binding-connection-D3udKbIE.js";
17
- import { n as normalizeCodexAppServerBindingModelProvider, t as isCodexAppServerNativeAuthProfile } from "./auth-profile-CwzO4_RG.js";
18
- import { C as CodexThreadBindingConflictError, D as bindCodexInferenceThread, E as assertCodexInferenceRouteConfig, H as isCodexAppServerClientRuntimeLive, K as readCodexClientSessionMeta, R as consumeCodexAppServerLiveThread, S as CodexAdoptedThreadActiveError, U as isCodexAppServerLiveThreadClaimed, Y as unsubscribeCodexAppServerLiveThread, _ as retainSharedCodexAppServerClientByInstanceId, k as prepareCodexInferenceThreadConfig, n as captureCodexAppServerClientLifetime, q as releaseCodexAppServerLiveThread, w as CodexThreadStartRequestError } from "./shared-client-CscigXXL.js";
19
- import { a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, l as retireUnsafeCodexTurnClientBestEffort, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError, s as isCodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-DKHzbwt5.js";
20
- import { t as ensureCodexPluginActivation } from "./plugin-activation-BYQculil.js";
21
- import { o as resolveCodexSessionBinding, r as hashCodexAppServerBindingFingerprint } from "./session-binding-CI8UuilT.js";
22
- import { i as refreshCodexThreadPolicy, n as CodexThreadPolicyHandoffError, r as assertCodexSupervisionThreadLineage, t as CodexIncognitoPolicyChangeError } from "./thread-policy-BuEQfE0g.js";
23
- import { t as resumeCodexAppServerThread } from "./thread-resume-DsDOZpFg.js";
24
- import { r as retainCodexAppServerBindingSubscription, s as withExclusiveCodexAppServerThread } from "./thread-ownership-BsDRTsyp.js";
25
- import "./transcript-mirror-C5CKgNy6.js";
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";
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";
7
+ import { n as withCodexAppServerThreadMutation, t as isIncognitoSessionKey } from "./incognito-session-uhrBF6wJ.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";
13
+ import { r as sanitizeInlineImageDataUrl, t as invalidInlineImageText } from "./image-payload-sanitizer-tupAr-2o.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";
26
+ import { isDeepStrictEqual } from "node:util";
29
27
  import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
30
- import { addTimerTimeoutGraceMs, finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
31
28
  import path from "node:path";
32
- import os from "node:os";
33
- import fs from "node:fs/promises";
34
- import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
35
29
  import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
36
- import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
37
30
  import { createStageTimingTracker, formatStageTimings } from "openclaw/plugin-sdk/time-runtime";
38
- import { isPathInside } from "openclaw/plugin-sdk/file-access-runtime";
39
31
  import { resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
40
- import { AgentHarnessPreflightError, SKILL_WORKSHOP_TOOL_NAME, buildCredentialSafetyPrompt, buildDelegationGuidanceSection, buildHarnessVisibleReplyGuidance, buildSkillWorkshopPromptSection, buildTemporalContextText, buildUiPresentationPrompt, embeddedAgentLog, formatErrorMessage, isActiveHarnessContextEngine, isHostScopedAgentToolActive, isOpenClawRuntimeContextCustomMessage, resolveMainSessionDelegationMode } from "openclaw/plugin-sdk/agent-harness-runtime";
41
- import { isDeepStrictEqual } from "node:util";
42
- import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
32
+ import { AgentHarnessPreflightError, buildHarnessVisibleReplyGuidance, buildTemporalContextText, embeddedAgentLog, formatErrorMessage, isActiveHarnessContextEngine, isHostScopedAgentToolActive, isOpenClawRuntimeContextCustomMessage } from "openclaw/plugin-sdk/agent-harness-runtime";
43
33
  import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
44
34
  import { IMAGE_BLOCK_TOKENS } from "openclaw/plugin-sdk/agent-core";
45
- import { resolveRequiredHomeDir, resolveStateDir } from "openclaw/plugin-sdk/state-paths";
46
35
  import { buildCodexUserMcpServersThreadConfigPatchForRun } from "openclaw/plugin-sdk/codex-mcp-projection";
47
- import { registerRetainedNativeHookRelayForBundledRuntime } from "openclaw/plugin-sdk/native-hook-relay-runtime";
48
36
  import { isDiagnosticFlagEnabled } from "openclaw/plugin-sdk/diagnostic-flags";
49
- import { listRegisteredPluginAgentPromptGuidance } from "openclaw/plugin-sdk/plugin-runtime";
50
- import { buildHostnameAllowlistPolicyFromSuffixAllowlist } from "openclaw/plugin-sdk/ssrf-policy";
51
- //#region extensions/codex/src/app-server/plugin-app-approval-overrides.ts
52
- /** Projects ask approvals into the native session layer without changing saved settings. */
53
- function buildCodexAppApprovalOverrides(config, app) {
54
- const appsRoot = config.apps;
55
- const appConfig = isJsonObject(appsRoot) ? appsRoot[app.id] : void 0;
56
- if (!isJsonObject(appConfig)) return {};
57
- const overrides = {};
58
- const keys = app.approvalOverrideToolConfigKeys;
59
- for (const [section, fields] of [["tools", { approval_mode: "auto" }], ["links", {
60
- approvals_reviewer: "user",
61
- default_tools_approval_mode: "auto"
62
- }]]) {
63
- const entries = appConfig[section];
64
- if (!isJsonObject(entries)) continue;
65
- const projected = [];
66
- for (const [name, value] of Object.entries(entries).toSorted(([left], [right]) => left.localeCompare(right))) {
67
- if (!isJsonObject(value) || section === "tools" && keys && !keys.includes(name)) continue;
68
- if (Object.keys(fields).some((field) => value[field] !== void 0 && value[field] !== null)) projected.push([name, fields]);
69
- }
70
- if (projected.length > 0) overrides[section] = Object.fromEntries(projected);
71
- }
72
- return overrides;
73
- }
74
- //#endregion
75
- //#region extensions/codex/src/app-server/plugin-thread-app-admission.ts
76
- function resolveCodexPluginThreadAppCacheKey(params) {
77
- return params.threadId ? `${params.appCacheKey}:thread:${encodeURIComponent(params.threadId)}` : params.appCacheKey;
78
- }
79
- function createCodexPluginThreadAppInventoryRequest(params) {
80
- return async (method, requestParams) => await params.request(method, (method === "app/installed" || method === "app/read") && params.threadId ? {
81
- ...requestParams,
82
- threadId: params.threadId
83
- } : requestParams);
84
- }
85
- async function refreshCodexPluginAppInventory(params, appCache, options = {}) {
86
- if (!params.appCacheKey) return;
87
- const request = createCodexPluginThreadAppInventoryRequest(params);
88
- try {
89
- return await appCache.refreshNow({
90
- key: resolveCodexPluginThreadAppCacheKey(params),
91
- request,
92
- nowMs: params.nowMs,
93
- forceRefetch: options.forceRefetch,
94
- targetAppIds: options.targetAppIds
95
- });
96
- } catch (error) {
97
- embeddedAgentLog.warn("codex plugin thread config app inventory refresh failed", {
98
- reason: options.reason,
99
- forceRefetch: options.forceRefetch === true,
100
- error: serializeCodexAppInventoryError(error)
101
- });
102
- return;
103
- }
104
- }
105
- function collectCodexPluginOwnedAppIds(inventory) {
106
- return Array.from(new Set(inventory.records.flatMap((record) => record.ownedAppIds).filter(Boolean))).toSorted();
107
- }
108
- function collectCodexReservedPluginAppIds(params) {
109
- const reserved = new Set(params.inventory.records.flatMap((record) => record.appOwnership === "proven" ? record.ownedAppIds : []));
110
- const recordsByConfigKey = new Map(params.inventory.records.map((record) => [record.policy.configKey, record]));
111
- const configuredOwnerNames = new Set(params.policy.pluginPolicies.flatMap((policy) => {
112
- const record = recordsByConfigKey.get(policy.configKey);
113
- return [
114
- policy.configKey,
115
- policy.pluginName,
116
- record?.summary.name,
117
- record?.summary.id
118
- ].filter((name) => Boolean(name)).map(normalizeCodexPluginOwnerName);
119
- }));
120
- for (const app of params.accountApps) if (app.pluginDisplayNames.some((name) => configuredOwnerNames.has(normalizeCodexPluginOwnerName(name)))) reserved.add(app.id);
121
- return reserved;
122
- }
123
- function normalizeCodexPluginOwnerName(name) {
124
- return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "");
125
- }
126
- async function readCodexThreadAdmissibleAccountApps(params, appCache) {
127
- const request = createCodexPluginThreadAppInventoryRequest(params);
128
- const cachedInventory = appCache.read({
129
- key: resolveCodexPluginThreadAppCacheKey(params),
130
- request,
131
- nowMs: params.nowMs,
132
- suppressRefresh: true
133
- });
134
- const snapshot = cachedInventory.state === "fresh" && !cachedInventory.snapshot?.targetAppIds?.length ? cachedInventory.snapshot : await refreshCodexPluginAppInventory(params, appCache, {
135
- forceRefetch: false,
136
- reason: "account_apps_all",
137
- targetAppIds: []
138
- });
139
- if (!snapshot) return {
140
- apps: [],
141
- diagnostic: {
142
- code: "account_app_inventory_unavailable",
143
- message: "Codex account app inventory was unavailable; account apps were not exposed."
144
- }
145
- };
146
- const installedAppsById = new Map(snapshot.installedApps.map((app) => [app.id, app]));
147
- return { apps: snapshot.apps.filter((app) => resolveCodexInstalledAppThreadAdmission(toCodexPluginOwnedAccountApp(app), installedAppsById.get(app.id)) !== "blocked").toSorted((left, right) => left.id.localeCompare(right.id)) };
148
- }
149
- function toCodexPluginOwnedAccountApp(app) {
150
- return {
151
- id: app.id,
152
- name: app.name,
153
- accessible: app.isAccessible,
154
- enabled: app.isEnabled,
155
- needsAuth: !app.isAccessible,
156
- ...resolveOwnedAppApprovalOverrideKeys(app)
157
- };
158
- }
159
- function resolveCodexThreadConfigAppsForRecord(params) {
160
- return params.inventory.appInventory?.state === "missing" ? [] : params.record.apps;
161
- }
162
- function resolveCodexPluginAppThreadAdmission(app, inventory) {
163
- const snapshot = inventory.appInventory?.snapshot;
164
- if (!snapshot) return "blocked";
165
- return resolveCodexInstalledAppThreadAdmission(app, snapshot.installedApps.find((candidate) => candidate.id === app.id));
166
- }
167
- function resolveCodexInstalledAppThreadAdmission(app, installed) {
168
- if (!app.accessible || app.needsAuth || !installed) return "blocked";
169
- if (installed.enabled && installed.callable) return "ready";
170
- return !installed.enabled && !installed.callable ? "provisional" : "blocked";
171
- }
172
- async function readCodexConfigForAppAdmission(params) {
173
- try {
174
- const response = await params.request("config/read", {
175
- includeLayers: true,
176
- ...params.configCwd ? { cwd: params.configCwd } : {}
177
- });
178
- if (!isJsonObject(response) || !isJsonObject(response.config) || !Array.isArray(response.layers)) throw new Error("Codex config/read omitted effective config or config layers");
179
- return {
180
- config: response.config,
181
- layers: response.layers.flatMap((layer) => {
182
- if (!isJsonObject(layer)) throw new Error("Codex config/read returned an invalid config layer");
183
- if (layer.disabledReason !== void 0 && layer.disabledReason !== null) {
184
- if (typeof layer.disabledReason !== "string") throw new Error("Codex config/read returned an invalid disabled layer");
185
- return [];
186
- }
187
- if (!isJsonObject(layer.config)) throw new Error("Codex config/read returned an invalid layer config");
188
- if (!isJsonObject(layer.name) || typeof layer.name.type !== "string") throw new Error("Codex config/read returned an invalid config layer source");
189
- 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`);
190
- return [layer.config];
191
- })
192
- };
193
- } catch (error) {
194
- const details = serializeCodexAppInventoryError(error);
195
- embeddedAgentLog.warn("codex plugin app admission config read failed", { error: details });
196
- 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 });
197
- }
198
- }
199
- function resolveCodexExplicitAppEnablement(layersHighestPrecedenceFirst, appId) {
200
- for (const layer of layersHighestPrecedenceFirst) {
201
- const apps = layer.apps;
202
- const app = isJsonObject(apps) ? apps[appId] : void 0;
203
- if (isJsonObject(app) && Object.hasOwn(app, "enabled")) return app.enabled === true;
204
- }
205
- }
206
- function shouldForceRefreshCodexNotReadyPluginApps(params, policy, inventory) {
207
- if (!params.appCacheKey || !policy.pluginPolicies.some((plugin) => plugin.enabled) || inventory.appInventory?.state === "missing") return false;
208
- return inventory.records.some((record) => record.appOwnership === "proven" && record.ownedAppIds.length > 0 && (record.apps.length === 0 || record.apps.some((app) => !app.accessible)));
209
- }
210
- //#endregion
211
- //#region extensions/codex/src/app-server/plugin-thread-config.ts
212
- /**
213
- * Builds Codex thread config patches that expose only policy-approved apps
214
- * for native Codex turns.
215
- */
216
- const CODEX_PLUGIN_THREAD_CONFIG_INPUT_FINGERPRINT_VERSION = 6;
217
- const CODEX_PLUGIN_THREAD_CONFIG_FINGERPRINT_VERSION = 2;
218
- /** Returns true when plugin config exists and thread config may need app patches. */
219
- function shouldBuildCodexPluginThreadConfig(pluginConfig) {
220
- return resolveCodexPluginsPolicy(pluginConfig).configured;
221
- }
222
- /** Fingerprints policy and app-cache identity before runtime inventory is read. */
223
- function buildCodexPluginThreadConfigInputFingerprint(params) {
224
- const policy = resolveCodexPluginsPolicy(params.pluginConfig);
225
- return fingerprintJson({
226
- version: CODEX_PLUGIN_THREAD_CONFIG_INPUT_FINGERPRINT_VERSION,
227
- policy: policyFingerprint(policy),
228
- appCacheKey: params.appCacheKey ?? null
229
- });
230
- }
231
- /** Builds the deny-all app patch used when plugin discovery exceeds its turn budget. */
232
- function buildCodexPluginThreadConfigTimeoutFallback(params) {
233
- return {
234
- ...emptyPluginThreadConfig({
235
- enabled: true,
236
- inputFingerprint: buildCodexPluginThreadConfigInputFingerprint(params),
237
- configPatch: buildDisabledAppsConfigPatch()
238
- }),
239
- diagnostics: [{
240
- code: "plugin_config_timeout",
241
- message: params.message
242
- }]
243
- };
244
- }
245
- /** Builds the Codex apps config patch and policy context for a native thread. */
246
- async function buildCodexPluginThreadConfig(params) {
247
- const appCache = params.appCache ?? defaultCodexAppInventoryCache;
248
- const threadAppCacheKey = resolveCodexPluginThreadAppCacheKey(params);
249
- const threadRequest = (method, requestParams) => params.request(method, (method === "app/installed" || method === "app/read") && params.threadId && isJsonObject(requestParams) ? {
250
- ...requestParams,
251
- threadId: params.threadId
252
- } : requestParams);
253
- let inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
254
- pluginConfig: params.pluginConfig,
255
- appCacheKey: params.appCacheKey
256
- });
257
- const policy = resolveCodexPluginsPolicy(params.pluginConfig);
258
- if (!policy.enabled) return emptyPluginThreadConfig({
259
- enabled: false,
260
- inputFingerprint,
261
- configPatch: buildDisabledAppsConfigPatch()
262
- });
263
- let inventory = policy.pluginPolicies.length > 0 ? await readCodexPluginInventory({
264
- pluginConfig: params.pluginConfig,
265
- policy,
266
- request: threadRequest,
267
- appCache,
268
- appCacheKey: threadAppCacheKey,
269
- configCwd: params.configCwd,
270
- metadataCache: params.metadataCache,
271
- nowMs: params.nowMs,
272
- suppressAppInventoryRefresh: true
273
- }) : emptyCodexPluginInventory(policy);
274
- const appInventoryRefreshDeferredForActivation = inventory.records.some((record) => record.activationRequired) && shouldRefreshMissingAppInventory(params, policy, inventory);
275
- if (shouldWaitForInitialAppInventory(params, policy, inventory)) {
276
- await refreshCodexPluginAppInventory(params, appCache, {
277
- forceRefetch: false,
278
- reason: "initial_missing",
279
- targetAppIds: collectCodexPluginOwnedAppIds(inventory)
280
- });
281
- inventory = await readCodexPluginInventory({
282
- pluginConfig: params.pluginConfig,
283
- policy,
284
- request: threadRequest,
285
- appCache,
286
- appCacheKey: threadAppCacheKey,
287
- configCwd: params.configCwd,
288
- metadataCache: params.metadataCache,
289
- nowMs: params.nowMs
290
- });
291
- inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
292
- pluginConfig: params.pluginConfig,
293
- appCacheKey: params.appCacheKey
294
- });
295
- }
296
- const activationDiagnostics = [];
297
- const activationResults = [];
298
- for (const record of inventory.records) {
299
- if (!record.activationRequired) continue;
300
- const activation = await ensureCodexPluginActivation({
301
- identity: record.policy,
302
- request: threadRequest,
303
- appCache,
304
- appCacheKey: threadAppCacheKey,
305
- configCwd: params.configCwd,
306
- metadataCache: params.metadataCache,
307
- deferAppInventoryRefresh: true,
308
- targetAppIds: record.ownedAppIds
309
- });
310
- activationResults.push(activation);
311
- if (!activation.ok) activationDiagnostics.push({
312
- code: "plugin_activation_failed",
313
- plugin: record.policy,
314
- message: activation.diagnostics.map((item) => item.message).join(" ") || activation.reason
315
- });
316
- }
317
- const postInstallRefreshRequired = activationResults.some((activation) => activation.ok && activation.installAttempted);
318
- const deferredMissingRefreshRequired = appInventoryRefreshDeferredForActivation && !postInstallRefreshRequired && shouldRefreshMissingAppInventory(params, policy, inventory);
319
- if (postInstallRefreshRequired || deferredMissingRefreshRequired) {
320
- await refreshCodexPluginAppInventory(params, appCache, {
321
- forceRefetch: true,
322
- reason: postInstallRefreshRequired ? "post_install" : "deferred_missing",
323
- targetAppIds: collectCodexPluginOwnedAppIds(inventory)
324
- });
325
- inventory = await readCodexPluginInventory({
326
- pluginConfig: params.pluginConfig,
327
- policy,
328
- request: threadRequest,
329
- appCache,
330
- appCacheKey: threadAppCacheKey,
331
- configCwd: params.configCwd,
332
- metadataCache: params.metadataCache,
333
- nowMs: params.nowMs
334
- });
335
- inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
336
- pluginConfig: params.pluginConfig,
337
- appCacheKey: params.appCacheKey
338
- });
339
- }
340
- if (shouldForceRefreshCodexNotReadyPluginApps(params, policy, inventory)) {
341
- await refreshCodexPluginAppInventory(params, appCache, {
342
- forceRefetch: true,
343
- reason: "not_ready_plugin_apps",
344
- targetAppIds: collectCodexPluginOwnedAppIds(inventory)
345
- });
346
- inventory = await readCodexPluginInventory({
347
- pluginConfig: params.pluginConfig,
348
- policy,
349
- request: threadRequest,
350
- appCache,
351
- appCacheKey: threadAppCacheKey,
352
- configCwd: params.configCwd,
353
- metadataCache: params.metadataCache,
354
- nowMs: params.nowMs
355
- });
356
- inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
357
- pluginConfig: params.pluginConfig,
358
- appCacheKey: params.appCacheKey
359
- });
360
- }
361
- const accountAppsResult = policy.allowAllPlugins ? await readCodexThreadAdmissibleAccountApps(params, appCache) : { apps: [] };
362
- let appAdmissionConfig;
363
- const getAdmissionConfig = () => appAdmissionConfig ??= readCodexConfigForAppAdmission(params);
364
- const diagnostics = [
365
- ...inventory.diagnostics,
366
- ...activationDiagnostics,
367
- ...accountAppsResult.diagnostic ? [accountAppsResult.diagnostic] : []
368
- ];
369
- const provisionalAppIds = /* @__PURE__ */ new Set();
370
- const { apps } = buildDisabledAppsConfigPatch();
371
- const policyApps = {};
372
- const pluginAppIds = {};
373
- const pluginOwnedAppIds = collectCodexReservedPluginAppIds({
374
- policy,
375
- inventory,
376
- accountApps: accountAppsResult.apps
377
- });
378
- const unresolvedDisabledPluginOwnership = policy.allowAllPlugins ? policy.pluginPolicies.find((pluginPolicy) => {
379
- const record = inventory.records.find((candidate) => candidate.policy.configKey === pluginPolicy.configKey);
380
- const disabledByMarketplacePolicy = record?.summary.availability === "DISABLED_BY_ADMIN" || record?.summary.installPolicy === "NOT_AVAILABLE";
381
- const unresolvedPluginIdentity = !record && inventory.diagnostics.some((diagnostic) => diagnostic.plugin?.configKey === pluginPolicy.configKey && (diagnostic.code === "plugin_disabled" || diagnostic.code === "plugin_missing" || diagnostic.code === "marketplace_missing"));
382
- return (!pluginPolicy.enabled || disabledByMarketplacePolicy || unresolvedPluginIdentity) && !record?.detail;
383
- }) : void 0;
384
- if (unresolvedDisabledPluginOwnership) diagnostics.push({
385
- code: "account_app_ownership_unavailable",
386
- plugin: unresolvedDisabledPluginOwnership,
387
- message: `Could not verify disabled Codex plugin app ownership for ${unresolvedDisabledPluginOwnership.pluginName}; account apps were not exposed.`
388
- });
389
- for (const record of inventory.records) {
390
- if (!record.policy.enabled) continue;
391
- const activation = activationResults.find((item) => item.identity.configKey === record.policy.configKey);
392
- if (activation?.ok === false || record.activationRequired && !activation?.ok) continue;
393
- if (record.appOwnership !== "proven") continue;
394
- pluginAppIds[record.policy.configKey] = [...record.ownedAppIds].toSorted();
395
- for (const app of resolveCodexThreadConfigAppsForRecord({
396
- record,
397
- inventory
398
- })) {
399
- const admissionConfig = resolveCodexPluginAppThreadAdmission(app, inventory) === "blocked" ? void 0 : await getAdmissionConfig();
400
- if (!admissionConfig || resolveCodexExplicitAppEnablement(admissionConfig.layers, app.id) === false) {
401
- diagnostics.push({
402
- code: "app_not_ready",
403
- plugin: record.policy,
404
- message: `${app.id} is not accessible for ${record.policy.pluginName}.`
405
- });
406
- continue;
407
- }
408
- provisionalAppIds.add(app.id);
409
- apps[app.id] = buildEnabledAppConfig(record.policy, record.policy.destructiveApprovalMode === "ask" ? buildCodexAppApprovalOverrides(admissionConfig.config, app) : void 0);
410
- policyApps[app.id] = {
411
- configKey: record.policy.configKey,
412
- marketplaceName: record.policy.marketplaceName,
413
- pluginName: record.policy.pluginName,
414
- allowDestructiveActions: record.policy.allowDestructiveActions,
415
- allowOpenWorld: true,
416
- destructiveApprovalMode: record.policy.destructiveApprovalMode,
417
- mcpServerNames: [...record.detail?.mcpServers ?? []].toSorted()
418
- };
419
- }
420
- }
421
- for (const app of unresolvedDisabledPluginOwnership ? [] : accountAppsResult.apps) {
422
- if (pluginOwnedAppIds.has(app.id)) continue;
423
- const admissionConfig = await getAdmissionConfig();
424
- if (resolveCodexExplicitAppEnablement(admissionConfig.layers, app.id) === false) continue;
425
- const accountApp = toCodexPluginOwnedAccountApp(app);
426
- provisionalAppIds.add(app.id);
427
- apps[app.id] = buildEnabledAppConfig(policy, policy.destructiveApprovalMode === "ask" ? buildCodexAppApprovalOverrides(admissionConfig.config, accountApp) : void 0);
428
- policyApps[app.id] = {
429
- source: "account",
430
- appName: app.name,
431
- allowDestructiveActions: policy.allowDestructiveActions,
432
- allowOpenWorld: true,
433
- destructiveApprovalMode: policy.destructiveApprovalMode,
434
- mcpServerNames: []
435
- };
436
- }
437
- const configPatch = Object.keys(policyApps).length === 0 ? buildDisabledAppsConfigPatch() : disableUnlistedCodexApps({ apps }, (await getAdmissionConfig()).config);
438
- const policyContext = buildPluginAppPolicyContext(policyApps, pluginAppIds);
439
- return {
440
- enabled: true,
441
- configPatch,
442
- ...provisionalAppIds.size > 0 ? { provisionalAppIds: Array.from(provisionalAppIds).toSorted() } : {},
443
- fingerprint: fingerprintJson({
444
- version: CODEX_PLUGIN_THREAD_CONFIG_FINGERPRINT_VERSION,
445
- inputFingerprint,
446
- configPatch,
447
- policyContext
448
- }),
449
- inputFingerprint,
450
- policyContext,
451
- inventory,
452
- diagnostics
453
- };
454
- }
455
- /** Deep-merges optional Codex thread config patches, returning undefined when empty. */
456
- function mergeCodexThreadConfigs(...configs) {
457
- let merged;
458
- for (const config of configs) {
459
- if (!config) continue;
460
- merged = mergeJsonObjects(merged ?? {}, config);
461
- }
462
- return merged && Object.keys(merged).length > 0 ? merged : void 0;
463
- }
464
- /** Detects when a stored thread binding no longer matches current plugin policy inputs. */
465
- function isCodexPluginThreadBindingStale(params) {
466
- if (!params.codexPluginsEnabled) return Boolean(params.bindingFingerprint || params.bindingInputFingerprint || params.hasBindingPolicyContext);
467
- if (!params.bindingFingerprint || !params.bindingInputFingerprint || !params.hasBindingPolicyContext) return true;
468
- return params.bindingInputFingerprint !== params.currentInputFingerprint;
469
- }
470
- function emptyPluginThreadConfig(params) {
471
- const policyContext = buildPluginAppPolicyContext({}, {});
472
- return {
473
- enabled: params.enabled,
474
- fingerprint: fingerprintJson({
475
- version: CODEX_PLUGIN_THREAD_CONFIG_FINGERPRINT_VERSION,
476
- inputFingerprint: params.inputFingerprint,
477
- configPatch: params.configPatch ?? null,
478
- policyContext
479
- }),
480
- inputFingerprint: params.inputFingerprint,
481
- ...params.configPatch ? { configPatch: params.configPatch } : {},
482
- policyContext,
483
- diagnostics: []
484
- };
485
- }
486
- function buildDisabledAppsConfigPatch() {
487
- return {
488
- "features.apps": false,
489
- apps: { _default: {
490
- enabled: false,
491
- destructive_enabled: false,
492
- open_world_enabled: false
493
- } }
494
- };
495
- }
496
- function disableUnlistedCodexApps(configPatch, nativeConfig) {
497
- const apps = { ...configPatch.apps };
498
- for (const id of Object.keys(isJsonObject(nativeConfig.apps) ? nativeConfig.apps : {})) if (id !== "_default" && !Object.hasOwn(apps, id)) apps[id] = { enabled: false };
499
- return {
500
- ...configPatch,
501
- apps
502
- };
503
- }
504
- function buildEnabledAppConfig(policy, approvalOverrides = {}) {
505
- return {
506
- ...approvalOverrides,
507
- enabled: true,
508
- destructive_enabled: policy.allowDestructiveActions,
509
- open_world_enabled: policy.allowOpenWorld !== false,
510
- default_tools_approval_mode: "auto",
511
- ...policy.destructiveApprovalMode === "ask" ? { approvals_reviewer: "user" } : {}
512
- };
513
- }
514
- /** Rebuilds the safe per-thread apps patch persisted with a Codex thread binding. */
515
- function buildCodexPluginAppsConfigPatchFromPolicyContext(policyContext) {
516
- const disabledConfigPatch = buildDisabledAppsConfigPatch();
517
- const { apps } = disabledConfigPatch;
518
- for (const [appId, policy] of Object.entries(policyContext.apps).toSorted(([left], [right]) => left.localeCompare(right))) apps[appId] = buildEnabledAppConfig(policy);
519
- return Object.keys(policyContext.apps).length > 0 ? { apps } : disabledConfigPatch;
520
- }
521
- /** Projects current ask overrides before a side thread replays its bound app policy. */
522
- async function refreshCodexPluginAppApprovalPolicy(params) {
523
- if (Object.keys(params.policyContext.apps).length === 0) return {
524
- policyContext: params.policyContext,
525
- configPatch: buildDisabledAppsConfigPatch(),
526
- diagnostics: []
527
- };
528
- const targetApps = Object.entries(params.policyContext.apps).filter(([, app]) => app.destructiveApprovalMode === "ask").toSorted(([left], [right]) => left.localeCompare(right));
529
- const targetAppIds = targetApps.map(([id]) => id);
530
- const diagnostics = [];
531
- const readParams = {
532
- ...params,
533
- appCacheKey: "approval-policy-replay"
534
- };
535
- const [inventory, admissionConfig] = await Promise.all([targetAppIds.length > 0 ? refreshCodexPluginAppInventory(readParams, new CodexAppInventoryCache(), { targetAppIds }) : void 0, readCodexConfigForAppAdmission(readParams)]);
536
- const configPatch = disableUnlistedCodexApps(buildCodexPluginAppsConfigPatchFromPolicyContext(params.policyContext), admissionConfig.config);
537
- const currentApps = new Map(inventory?.apps.map((app) => [app.id, toCodexPluginOwnedAccountApp(app)]));
538
- const apps = { ...params.policyContext.apps };
539
- for (const [id, policy] of targetApps) {
540
- const app = currentApps.get(id);
541
- if (!app) diagnostics.push({
542
- code: "app_not_ready",
543
- message: `Could not verify current Codex app approval policy for ${id}; the app was not exposed.`
544
- });
545
- else {
546
- configPatch.apps[id] = buildEnabledAppConfig(policy, buildCodexAppApprovalOverrides(admissionConfig.config, app));
547
- continue;
548
- }
549
- delete apps[id];
550
- configPatch.apps[id] = { enabled: false };
551
- }
552
- return {
553
- policyContext: buildPluginAppPolicyContext(apps, Object.fromEntries(Object.entries(params.policyContext.pluginAppIds).map(([key, ids]) => [key, ids.filter((id) => Object.hasOwn(apps, id))]))),
554
- configPatch,
555
- diagnostics
556
- };
557
- }
558
- function buildPluginAppPolicyContext(apps, pluginAppIds) {
559
- return {
560
- fingerprint: fingerprintJson({
561
- version: 2,
562
- apps,
563
- pluginAppIds
564
- }),
565
- apps,
566
- pluginAppIds
567
- };
568
- }
569
- function shouldWaitForInitialAppInventory(params, policy, inventory) {
570
- if (inventory.records.some((record) => record.activationRequired)) return false;
571
- return shouldRefreshMissingAppInventory(params, policy, inventory);
572
- }
573
- function shouldRefreshMissingAppInventory(params, policy, inventory) {
574
- return Boolean(params.appCacheKey && policy.pluginPolicies.some((plugin) => plugin.enabled) && inventory.appInventory?.state === "missing");
575
- }
576
- function emptyCodexPluginInventory(policy) {
577
- return {
578
- policy,
579
- records: [],
580
- diagnostics: []
581
- };
582
- }
583
- function policyFingerprint(policy) {
584
- return {
585
- enabled: policy.enabled,
586
- allowAllPlugins: policy.allowAllPlugins,
587
- allowDestructiveActions: policy.allowDestructiveActions,
588
- destructiveApprovalMode: policy.destructiveApprovalMode,
589
- plugins: policy.pluginPolicies.map((plugin) => ({
590
- configKey: plugin.configKey,
591
- marketplaceName: plugin.marketplaceName,
592
- pluginName: plugin.pluginName,
593
- enabled: plugin.enabled,
594
- allowDestructiveActions: plugin.allowDestructiveActions,
595
- destructiveApprovalMode: plugin.destructiveApprovalMode
596
- }))
597
- };
598
- }
599
- function mergeJsonObjects(left, right) {
600
- const merged = {
601
- ...left,
602
- ...right
603
- };
604
- for (const [key, value] of Object.entries(right)) {
605
- const existing = left[key];
606
- if (Object.hasOwn(left, key) && isJsonObject(existing) && isJsonObject(value)) merged[key] = mergeJsonObjects(existing, value);
607
- }
608
- 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;
609
56
  }
610
- function fingerprintJson(value) {
611
- 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);
612
63
  }
613
- function stringifyCodexPluginPolicy(value) {
614
- if (Array.isArray(value)) return `[${value.map((item) => stringifyCodexPluginPolicy(item)).join(",")}]`;
615
- if (value && typeof value === "object") return `{${Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stringifyCodexPluginPolicy(item)}`).join(",")}}`;
616
- 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;
617
76
  }
618
77
  //#endregion
619
78
  //#region extensions/codex/src/app-server/context-engine-projection.ts
@@ -638,8 +97,34 @@ const CODEX_TURN_START_TEXT_INPUT_MAX_CHARS = 1 << 20;
638
97
  const DEFAULT_CODEX_PROJECTION_RESERVE_TOKENS = 2e4;
639
98
  const MIN_PROMPT_BUDGET_RATIO = .5;
640
99
  const MIN_PROMPT_BUDGET_TOKENS = 8e3;
100
+ const CODEX_CONTEXT_SENDER_FIELD_MAX_CHARS = 256;
101
+ /**
102
+ * This projection has no access to agent-core's private compaction helper, but
103
+ * must keep the same attribution contract: a stable ID is identity; display
104
+ * labels are optional metadata, never provenance on their own.
105
+ */
106
+ function formatCodexContextSenderSuffix(message) {
107
+ if (message.role !== "user") return "";
108
+ const metadata = Reflect.get(message, "__openclaw");
109
+ if (!metadata || typeof metadata !== "object") return "";
110
+ const normalize = (value) => {
111
+ if (typeof value !== "string") return;
112
+ const normalized = value.replaceAll("\0", "").trim();
113
+ return normalized ? truncateUtf16Safe(normalized, CODEX_CONTEXT_SENDER_FIELD_MAX_CHARS) : void 0;
114
+ };
115
+ const record = metadata;
116
+ const id = normalize(record.senderId);
117
+ if (!id) return "";
118
+ const name = normalize(record.senderName);
119
+ const username = normalize(record.senderUsername);
120
+ return ` sender=${JSON.stringify({
121
+ id,
122
+ ...name ? { name } : {},
123
+ ...username ? { username } : {}
124
+ })}`;
125
+ }
641
126
  function neutralizeCodexExplicitMentionSigils(text) {
642
- return text.replace(/\$(?=[A-Za-z0-9_:-])/gu, "$").replace(/\[@(?=[A-Za-z0-9_:-]+\]\()/gu, "[@");
127
+ return text.replace(/\$(?=[A-Za-z0-9_:-])/gu, "$").replace(/\[@(?=[A-Za-z0-9_:-]+\]\s*\()/gu, "[@");
643
128
  }
644
129
  /** Hidden durable notes are context; transient runtime carriers are current-turn only. */
645
130
  function isCodexDurableCustomMessage(message) {
@@ -675,7 +160,11 @@ async function projectContextEngineAssemblyForCodex(params) {
675
160
  ...promptContextRange ? { promptContextRange } : {},
676
161
  assembledMessages: params.assembledMessages,
677
162
  prePromptMessageCount: params.originalHistoryMessages.length,
678
- ...context.images.length ? { images: context.images } : {}
163
+ ...context.imageGroups.length && promptPrefix ? { imageGroups: context.imageGroups.map((group) => ({
164
+ images: group.images,
165
+ start: group.start + promptPrefix.length,
166
+ end: group.end + promptPrefix.length
167
+ })) } : {}
679
168
  };
680
169
  }
681
170
  /** Resolves rendered context size from a token budget and reserve. */
@@ -719,32 +208,61 @@ function resolveCodexContinuityProjectionMaxChars(params) {
719
208
  }
720
209
  /** Fits projected context prompts under Codex app-server turn/start text limits. */
721
210
  function fitCodexProjectedContextForTurnStart(params) {
211
+ const slice = (start, end, budget = end - start) => {
212
+ const retained = truncateOlderContext(params.promptText.slice(start, end), budget);
213
+ return {
214
+ ...retained,
215
+ sourceStart: start + retained.retainedStart,
216
+ sourceEnd: end
217
+ };
218
+ };
219
+ const finish = (...parts) => {
220
+ const imageGroups = [];
221
+ let offset = 0;
222
+ for (const part of parts) {
223
+ for (const group of params.imageGroups ?? []) if (group.start >= part.sourceStart && group.end <= part.sourceEnd) {
224
+ const shift = offset + part.prefixLength - part.sourceStart;
225
+ imageGroups.push({
226
+ ...group,
227
+ start: group.start + shift,
228
+ end: group.end + shift
229
+ });
230
+ }
231
+ offset += part.text.length;
232
+ }
233
+ return {
234
+ promptText: parts.map((part) => part.text).join(""),
235
+ ...imageGroups.length ? { imageGroups } : {}
236
+ };
237
+ };
722
238
  const maxChars = typeof params.maxChars === "number" && Number.isFinite(params.maxChars) ? Math.max(0, Math.floor(params.maxChars)) : CODEX_TURN_START_TEXT_INPUT_MAX_CHARS;
723
- if (params.promptText.length <= maxChars) return params.promptText;
239
+ if (params.promptText.length <= maxChars) return finish(slice(0, params.promptText.length));
724
240
  const range = normalizeProjectedContextRange(params.contextRange, params.promptText.length);
725
241
  if (!range) {
726
242
  const preservedRange = normalizeProjectedContextRange(params.preservedRange, params.promptText.length);
727
- if (!preservedRange) return params.promptText;
243
+ if (!preservedRange) return finish(slice(0, params.promptText.length));
728
244
  const preservedText = params.promptText.slice(preservedRange.start, preservedRange.end);
729
- if (!preservedText) return truncateOlderContext(params.promptText, maxChars);
730
- if (preservedText.length >= maxChars) return truncateOlderContext(preservedText, maxChars);
731
- return `${truncateOlderContext(params.promptText.slice(0, preservedRange.start), maxChars - preservedText.length)}${preservedText}`;
245
+ if (!preservedText) return finish(slice(0, params.promptText.length, maxChars));
246
+ if (preservedText.length >= maxChars) return finish(slice(preservedRange.start, preservedRange.end, maxChars));
247
+ return finish(slice(0, preservedRange.start, maxChars - preservedText.length), slice(preservedRange.start, preservedRange.end));
732
248
  }
733
249
  const beforeContext = params.promptText.slice(0, range.start);
734
- const context = params.promptText.slice(range.start, range.end);
735
250
  const afterContext = params.promptText.slice(range.end);
736
251
  const requestRange = normalizeProjectedContextRange(params.requestRange, params.promptText.length);
737
252
  if (requestRange && requestRange.start >= range.end && requestRange.end < params.promptText.length) {
738
253
  const request = params.promptText.slice(requestRange.start, requestRange.end);
739
- if (request.length >= maxChars) return truncateOlderContext(request, maxChars);
740
- const fittedAppendedContext = truncateOlderContext(params.promptText.slice(requestRange.end), maxChars - request.length);
741
- const fittedContext = truncateOlderContext(context, maxChars - request.length - fittedAppendedContext.length);
742
- return `${truncateOlderContext(beforeContext, maxChars - fittedContext.length - request.length - fittedAppendedContext.length)}${fittedContext}${request}${fittedAppendedContext}`;
254
+ if (request.length >= maxChars) return finish(slice(requestRange.start, requestRange.end, maxChars));
255
+ const fittedAppendedContext = slice(requestRange.end, params.promptText.length, maxChars - request.length);
256
+ const contextBudget = maxChars - request.length - fittedAppendedContext.text.length;
257
+ const fittedContext = slice(range.start, range.end, contextBudget);
258
+ const beforeContextBudget = maxChars - fittedContext.text.length - request.length - fittedAppendedContext.text.length;
259
+ return finish(slice(0, range.start, beforeContextBudget), fittedContext, slice(requestRange.start, requestRange.end), fittedAppendedContext);
743
260
  }
744
261
  const contextBudget = maxChars - beforeContext.length - afterContext.length;
745
- if (contextBudget > 0) return `${beforeContext}${truncateOlderContext(context, contextBudget)}${afterContext}`;
746
- const afterContextText = truncateOlderContext(afterContext, maxChars);
747
- return `${truncateOlderContext(context, maxChars - afterContextText.length)}${afterContextText}`;
262
+ if (contextBudget > 0) return finish(slice(0, range.start), slice(range.start, range.end, contextBudget), slice(range.end, params.promptText.length));
263
+ const afterContextText = slice(range.end, params.promptText.length, maxChars);
264
+ const contextBudgetAfterRequest = maxChars - afterContextText.text.length;
265
+ return finish(slice(range.start, range.end, contextBudgetAfterRequest), afterContextText);
748
266
  }
749
267
  function normalizeProjectedContextRange(range, textLength) {
750
268
  if (!range) return;
@@ -765,7 +283,6 @@ function resolveProjectionPromptBudgetTokens(params) {
765
283
  }
766
284
  async function renderMessagesForCodexContext(messages, options) {
767
285
  const tail = [];
768
- const images = [];
769
286
  let retainedImageChars = 0;
770
287
  let totalChars = 0;
771
288
  let retainedChars = 0;
@@ -786,29 +303,50 @@ async function renderMessagesForCodexContext(messages, options) {
786
303
  imageChars > 0 && !imagesFit ? "[Attachment images omitted: context budget exceeded]" : void 0
787
304
  ].filter(Boolean).join("\n\n");
788
305
  if (!text && acceptedImageChars === 0) continue;
789
- const chunk = `[${message.role}]\n${text}${totalChars > 0 ? "\n\n" : ""}`;
306
+ const separator = totalChars > 0 ? "\n\n" : "";
307
+ const chunk = `[${message.role}${formatCodexContextSenderSuffix(message)}]\n${text}${separator}`;
790
308
  totalChars += chunk.length;
791
309
  if (remaining > 0) {
792
310
  const retained = neutralizeCodexExplicitMentionSigils(chunk).slice(-(remaining - acceptedImageChars));
793
- tail.push(retained);
311
+ tail.push({
312
+ text: retained,
313
+ separatorLength: separator.length,
314
+ ...imagesFit && files?.images.length && retained.length === chunk.length ? { images: files.images } : {}
315
+ });
794
316
  retainedChars += retained.length + acceptedImageChars;
795
317
  retainedImageChars += acceptedImageChars;
796
- if (imagesFit && files?.images.length) images.unshift(...files.images);
797
318
  }
798
319
  }
320
+ const ordered = tail.toReversed();
321
+ const fitted = truncateOlderContext(ordered.map((entry) => entry.text).join(""), options.maxRenderedContextChars - retainedImageChars, totalChars);
322
+ const imageGroups = [];
323
+ let offset = 0;
324
+ for (const entry of ordered) {
325
+ if (entry.images && offset >= fitted.retainedStart) {
326
+ const start = offset - fitted.retainedStart + fitted.prefixLength;
327
+ imageGroups.push({
328
+ start,
329
+ end: start + entry.text.length - entry.separatorLength,
330
+ images: entry.images
331
+ });
332
+ }
333
+ offset += entry.text.length;
334
+ }
799
335
  return {
800
- text: truncateOlderContext(tail.toReversed().join(""), options.maxRenderedContextChars - retainedImageChars, totalChars),
801
- images
336
+ text: fitted.text,
337
+ imageGroups
802
338
  };
803
339
  }
804
340
  function renderMessageBody(message, options) {
805
341
  if (message.role === "compactionSummary" || message.role === "branchSummary") return truncateText(message.summary.trim(), options.maxTextPartChars);
806
342
  if (!hasMessageContent(message)) return "";
807
- if (typeof message.content === "string") return truncateText(message.content.trim(), options.maxTextPartChars);
808
- if (!Array.isArray(message.content)) return "[non-text content omitted]";
809
- 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;
810
348
  }
811
- function renderMessagePart(part, options) {
349
+ function renderMessagePart(part, options, toolResultBody) {
812
350
  if (!part || typeof part !== "object") return "";
813
351
  const record = part;
814
352
  const type = typeof record.type === "string" ? record.type : void 0;
@@ -821,7 +359,7 @@ function renderMessagePart(part, options) {
821
359
  }
822
360
  if (type === "toolResult" || type === "tool_result") {
823
361
  const label = typeof record.toolUseId === "string" ? `tool result: ${record.toolUseId}` : "tool result";
824
- 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);
825
363
  return `${label} [content omitted]`;
826
364
  }
827
365
  return `[${type ?? "non-text"} content omitted]`;
@@ -873,8 +411,12 @@ function summarizeToolInputShape(value, seen = /* @__PURE__ */ new WeakSet()) {
873
411
  return `[${typeof value}]`;
874
412
  }
875
413
  function redactPreservedToolValue(key, value, seen = /* @__PURE__ */ new WeakSet()) {
876
- if (typeof value === "string") return redactSensitiveFieldValue(key, redactToolPayloadText(value));
877
- if (value === null || value === void 0 || typeof value === "number" || typeof value === "boolean") return value;
414
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
415
+ const text = String(value);
416
+ const redacted = redactSensitiveFieldValue(key, redactToolPayloadText(text));
417
+ return redacted === text ? value : redacted;
418
+ }
419
+ if (value === null || value === void 0) return value;
878
420
  if (Array.isArray(value)) {
879
421
  if (seen.has(value)) return "[Circular]";
880
422
  seen.add(value);
@@ -912,15 +454,32 @@ function truncateText(text, maxChars) {
912
454
  return `${truncated}\n[truncated ${text.length - truncated.length} chars]`;
913
455
  }
914
456
  function truncateOlderContext(text, maxChars, totalChars = text.length) {
915
- if (totalChars <= maxChars) return text;
916
- if (maxChars <= 0) return "";
457
+ if (totalChars <= maxChars) return {
458
+ text,
459
+ retainedStart: 0,
460
+ prefixLength: 0
461
+ };
462
+ if (maxChars <= 0) return {
463
+ text: "",
464
+ retainedStart: text.length,
465
+ prefixLength: 0
466
+ };
917
467
  const buildMarker = (omittedChars) => `[truncated ${omittedChars} chars from older context]\n`;
918
468
  let marker = buildMarker(totalChars - maxChars);
919
469
  let tailChars = Math.max(0, maxChars - marker.length);
920
470
  marker = buildMarker(totalChars - tailChars);
921
- if (marker.length >= maxChars) return marker.slice(0, maxChars);
471
+ if (marker.length >= maxChars) return {
472
+ text: marker.slice(0, maxChars),
473
+ retainedStart: text.length,
474
+ prefixLength: maxChars
475
+ };
922
476
  tailChars = maxChars - marker.length;
923
- return `${marker}${sliceUtf16Safe(text, -tailChars).trimStart()}`;
477
+ const tail = sliceUtf16Safe(text, -tailChars).trimStart();
478
+ return {
479
+ text: `${marker}${tail}`,
480
+ retainedStart: text.length - tail.length,
481
+ prefixLength: marker.length
482
+ };
924
483
  }
925
484
  //#endregion
926
485
  //#region extensions/codex/src/app-server/thread-context-engine.ts
@@ -950,1001 +509,28 @@ function buildContextEngineBinding(params, projection) {
950
509
  function buildContextEngineProjectionBinding(projection) {
951
510
  return {
952
511
  schemaVersion: 1,
953
- mode: "thread_bootstrap",
954
- epoch: projection.epoch,
955
- fingerprint: projection.fingerprint
956
- };
957
- }
958
- function isContextEngineBindingCompatible(previous, next) {
959
- return previous?.schemaVersion === next.schemaVersion && previous.engineId === next.engineId && previous.policyFingerprint === next.policyFingerprint && areContextEngineProjectionBindingsCompatible(previous.projection, next.projection);
960
- }
961
- function areContextEngineProjectionBindingsCompatible(previous, next) {
962
- if (!next) return previous === void 0;
963
- return previous?.schemaVersion === next.schemaVersion && previous.mode === next.mode && previous.epoch === next.epoch && previous.fingerprint === next.fingerprint;
964
- }
965
- function resolveContextEngineCitationsMode(config) {
966
- const rootConfig = isRecord(config) ? config : void 0;
967
- const citations = (isRecord(rootConfig?.memory) ? rootConfig.memory : void 0)?.citations;
968
- return isJsonConfigValue(citations) ? citations : void 0;
969
- }
970
- function isJsonConfigValue(value) {
971
- if (value === null || typeof value === "string" || typeof value === "boolean") return true;
972
- if (typeof value === "number") return Number.isFinite(value);
973
- if (Array.isArray(value)) return value.every(isJsonConfigValue);
974
- return isRecord(value) && Object.values(value).every(isJsonConfigValue);
975
- }
976
- //#endregion
977
- //#region extensions/codex/src/app-server/dynamic-tool-profile.ts
978
- /** Tool names owned by Codex app-server and normally excluded from OpenClaw dynamic tools. */
979
- const CODEX_APP_SERVER_OWNED_DYNAMIC_TOOL_EXCLUDES = [
980
- "read",
981
- "write",
982
- "edit",
983
- "apply_patch",
984
- "exec",
985
- "process",
986
- "update_plan",
987
- "tool_call",
988
- "tool_describe",
989
- "tool_search",
990
- "tool_search_code"
991
- ];
992
- const CODEX_NATIVE_GOAL_TOOL_EXCLUDES = [
993
- "get_goal",
994
- "create_goal",
995
- "update_goal"
996
- ];
997
- const CODEX_APP_SERVER_OWNED_REPLACEABLE_TOOL_EXCLUDES = /* @__PURE__ */ new Set([
998
- "read",
999
- "write",
1000
- "edit",
1001
- "apply_patch",
1002
- ...CODEX_NATIVE_GOAL_TOOL_EXCLUDES
1003
- ]);
1004
- const CODEX_APP_SERVER_OWNED_SHELL_TOOL_EXCLUDES = /* @__PURE__ */ new Set(["exec", "process"]);
1005
- const DYNAMIC_TOOL_NAME_ALIASES = {
1006
- bash: "exec",
1007
- "apply-patch": "apply_patch"
1008
- };
1009
- /** Normalizes OpenClaw/Codex tool names before filtering and allowlist checks. */
1010
- function normalizeCodexDynamicToolName(name) {
1011
- const normalized = name.trim().toLowerCase();
1012
- return DYNAMIC_TOOL_NAME_ALIASES[normalized] ?? normalized;
1013
- }
1014
- /** True only for the host-scoped OpenClaw run's exact tool contract. */
1015
- function isSystemAgentOnlyCodexDynamicToolAllowlist(toolsAllow) {
1016
- return toolsAllow?.length === 1 && normalizeCodexDynamicToolName(toolsAllow[0] ?? "") === "openclaw";
1017
- }
1018
- /** True when a private source reply may use the message delivery tool only. */
1019
- function isMessageOnlyCodexSourceReply(params) {
1020
- return params.sourceReplyDeliveryMode === "message_tool_only" && params.toolsAllow?.length === 1 && normalizeCodexDynamicToolName(params.toolsAllow[0] ?? "") === "message";
1021
- }
1022
- /** Returns true for private QA runs that force the Codex runtime profile. */
1023
- function isForcedPrivateQaCodexRuntime(env = process.env) {
1024
- return env.OPENCLAW_BUILD_PRIVATE_QA === "1" && env.OPENCLAW_QA_FORCE_RUNTIME?.trim().toLowerCase() === "codex";
1025
- }
1026
- /** Resolves whether dynamic tools load directly or through Codex tool search. */
1027
- function resolveCodexDynamicToolsLoading(config, env = process.env) {
1028
- return isForcedPrivateQaCodexRuntime(env) ? "direct" : config.codexDynamicToolsLoading ?? "searchable";
1029
- }
1030
- function normalizeCodexModelId(modelId) {
1031
- const normalized = modelId?.trim().toLowerCase();
1032
- if (!normalized) return "";
1033
- return normalized.includes("/") ? normalized.split("/").at(-1) : normalized;
1034
- }
1035
- /** Returns true when model behavior requires direct dynamic-tool registration. */
1036
- function shouldUseDirectCodexDynamicToolsForModel(modelId) {
1037
- return shouldDisableCodexToolSearchForModel(modelId);
1038
- }
1039
- /** Returns true for models whose tool-search path is unsupported or inefficient. */
1040
- function shouldDisableCodexToolSearchForModel(modelId) {
1041
- return normalizeCodexModelId(modelId) === "gpt-5.4-nano";
1042
- }
1043
- /** Resolves dynamic-tool loading after applying model-specific restrictions. */
1044
- function resolveCodexDynamicToolsLoadingForModel(config, modelId, env = process.env) {
1045
- const loading = resolveCodexDynamicToolsLoading(config, env);
1046
- return loading === "searchable" && shouldUseDirectCodexDynamicToolsForModel(modelId) ? "direct" : loading;
1047
- }
1048
- /** Resolves dynamic-tool loading for the app-server connection that will execute the turn. */
1049
- function resolveCodexDynamicToolsLoadingForRuntime(config, modelId, options = {}, env = process.env) {
1050
- const loading = resolveCodexDynamicToolsLoadingForModel(config, modelId, env);
1051
- return loading === "searchable" && options.connectionClass === "remote" ? "direct" : loading;
1052
- }
1053
- /** Filters OpenClaw tools that Codex owns natively or config explicitly excludes. */
1054
- function filterCodexDynamicTools(tools, config, env = process.env) {
1055
- return filterCodexDynamicToolsWithOptions(tools, config, env, {
1056
- preserveOpenClawReplacements: false,
1057
- preserveOpenClawShell: false
1058
- });
1059
- }
1060
- /** Keeps OpenClaw coding tools that replace a disabled Codex native surface. */
1061
- function filterCodexDynamicToolsForDisabledNativeSurface(tools, config, options, env = process.env) {
1062
- return filterCodexDynamicToolsWithOptions(tools, config, env, {
1063
- preserveOpenClawReplacements: true,
1064
- preserveOpenClawShell: options.preserveShell
1065
- });
1066
- }
1067
- function filterCodexDynamicToolsWithOptions(tools, config, env, options) {
1068
- const excludes = /* @__PURE__ */ new Set();
1069
- if (!options.preserveOpenClawReplacements) for (const name of CODEX_NATIVE_GOAL_TOOL_EXCLUDES) excludes.add(name);
1070
- if (isForcedPrivateQaCodexRuntime(env)) excludes.add("apply_patch");
1071
- else for (const name of CODEX_APP_SERVER_OWNED_DYNAMIC_TOOL_EXCLUDES) {
1072
- if (options.preserveOpenClawReplacements && CODEX_APP_SERVER_OWNED_REPLACEABLE_TOOL_EXCLUDES.has(name)) continue;
1073
- if (options.preserveOpenClawShell && CODEX_APP_SERVER_OWNED_SHELL_TOOL_EXCLUDES.has(name)) continue;
1074
- excludes.add(name);
1075
- }
1076
- for (const name of config.codexDynamicToolsExclude ?? []) {
1077
- const trimmed = normalizeCodexDynamicToolName(name);
1078
- if (trimmed) excludes.add(trimmed);
1079
- }
1080
- return excludes.size === 0 ? tools : tools.filter((tool) => !excludes.has(normalizeCodexDynamicToolName(tool.name)));
1081
- }
1082
- //#endregion
1083
- //#region extensions/codex/src/app-server/thread-binding-policy.ts
1084
- function shouldRotateCodexAppServerBindingForRuntime(params) {
1085
- if (!params.current) return false;
1086
- if (params.binding === params.current) return false;
1087
- return params.connectionClass === "remote" || Boolean(params.binding);
1088
- }
1089
- function resolveCodexGpt56MultiAgentVersion(modelRef) {
1090
- let modelId = modelRef?.trim().toLowerCase();
1091
- if (!modelId) return;
1092
- const slashIndex = modelId.indexOf("/");
1093
- if (slashIndex > 0) {
1094
- const provider = modelId.slice(0, slashIndex);
1095
- if (provider !== "openai" && provider !== "codex") return;
1096
- modelId = modelId.slice(slashIndex + 1);
1097
- }
1098
- if (modelId === "gpt-5.6-sol" || modelId === "gpt-5.6-terra") return "v2";
1099
- return modelId === "gpt-5.6-luna" ? "v1" : void 0;
1100
- }
1101
- function shouldRotateCodexGpt56MultiAgentBinding(params) {
1102
- const bindingVersion = resolveCodexGpt56MultiAgentVersion(params.bindingModel);
1103
- const requestedVersion = resolveCodexGpt56MultiAgentVersion(params.requestedModel);
1104
- return Boolean(bindingVersion && requestedVersion && bindingVersion !== requestedVersion);
1105
- }
1106
- function isTransientWebSearchRestriction(params) {
1107
- if (params.nativeProviderWebSearchSupport === "unknown") return true;
1108
- if (params.params.config?.tools?.web?.search?.enabled === false) return false;
1109
- if (params.params.disableTools === true) return true;
1110
- const persistentWebSearchRestriction = params.webSearchAllowed === false && params.persistentWebSearchAllowed === false;
1111
- if (params.nativeCodeModeEnabled === false && !persistentWebSearchRestriction) return true;
1112
- if (params.webSearchAllowed !== false) return false;
1113
- if (params.persistentWebSearchAllowed !== void 0) return params.persistentWebSearchAllowed;
1114
- if (params.params.toolsAllow === void 0) return false;
1115
- return !params.params.toolsAllow.some((name) => {
1116
- const normalized = normalizeCodexDynamicToolName(name);
1117
- return normalized === "*" || normalized === "web_search";
1118
- });
1119
- }
1120
- function shouldRecheckRecoverablePluginBinding(params) {
1121
- if (!params.pluginThreadConfig?.enabled) return false;
1122
- if (!params.binding.pluginAppsFingerprint || !params.binding.pluginAppsInputFingerprint || params.binding.pluginAppsInputFingerprint !== params.pluginThreadConfig.inputFingerprint) return false;
1123
- const policyContext = params.binding.pluginAppPolicyContext;
1124
- if (!policyContext) return false;
1125
- const enabledPluginConfigKeys = params.pluginThreadConfig.enabledPluginConfigKeys ?? [];
1126
- const recoverablePluginConfigKeys = params.pluginThreadConfig.recoverablePluginConfigKeys ?? enabledPluginConfigKeys;
1127
- const recoverablePluginConfigKeySet = new Set(recoverablePluginConfigKeys);
1128
- 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));
1129
- const accountAppRecoveryEnabled = params.pluginThreadConfig.accountAppRecoveryEnabled ?? enabledPluginConfigKeys.length === 0;
1130
- return bindingContainsSettledPlugin || accountAppRecoveryEnabled && Object.keys(policyContext.apps).length === 0 || recoverablePluginConfigKeys.length > 0;
1131
- }
1132
- //#endregion
1133
- //#region extensions/codex/src/app-server/thread-fingerprints.ts
1134
- function codexDynamicToolsFingerprint(dynamicTools) {
1135
- return hashCodexAppServerBindingFingerprint(legacyFingerprintDynamicTools(dynamicTools));
1136
- }
1137
- function codexLegacyDynamicToolsFingerprint(dynamicTools) {
1138
- return legacyFingerprintDynamicTools(dynamicTools);
1139
- }
1140
- function areCodexDynamicToolFingerprintsCompatible(params) {
1141
- return areDynamicToolFingerprintsCompatible(params.previous, params.next, params.nextLegacy);
1142
- }
1143
- function legacyFingerprintDynamicTools(dynamicTools) {
1144
- return JSON.stringify(dynamicTools.map(stabilizeJsonValue).toSorted(compareJsonFingerprint));
1145
- }
1146
- function legacyFingerprintUserMcpServersConfigPatch(configPatch) {
1147
- return configPatch ? JSON.stringify(stabilizeJsonValue(configPatch)) : void 0;
1148
- }
1149
- function fingerprintUserMcpServersConfigPatch(configPatch) {
1150
- return configPatch ? hashCodexAppServerBindingFingerprint(JSON.stringify(stabilizeJsonValue(redactUserMcpServersFingerprintSecrets(configPatch)))) : void 0;
1151
- }
1152
- function redactUserMcpServersFingerprintSecrets(value) {
1153
- if (Array.isArray(value)) return value.map(redactUserMcpServersFingerprintSecrets);
1154
- if (!value || typeof value !== "object") return value;
1155
- return Object.fromEntries(Object.entries(value).map(([key, entry]) => {
1156
- 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]))];
1157
- return [key, redactUserMcpServersFingerprintSecrets(entry)];
1158
- }));
1159
- }
1160
- function fingerprintUserMcpServersAuthorizationHeader(value) {
1161
- return typeof value === "string" && value.length > 0 ? `<redacted:sha256:${crypto$1.createHash("sha256").update(value).digest("hex")}>` : "<redacted>";
1162
- }
1163
- function fingerprintJsonObject(value) {
1164
- return JSON.stringify(stabilizeJsonValue(value));
1165
- }
1166
- /** Hash thread-creation identity; settings already applied by turn/start must not restart Codex. */
1167
- function fingerprintCodexThreadConfig(request, authProfileId, dynamicToolsFingerprint) {
1168
- return hashCodexAppServerBindingFingerprint(fingerprintJsonObject({
1169
- authProfileId: authProfileId ?? null,
1170
- dynamicToolsFingerprint: dynamicToolsFingerprint ?? null,
1171
- nativeMultiAgentVersion: resolveCodexGpt56MultiAgentVersion(typeof request.requestedModel === "string" ? request.requestedModel : typeof request.model === "string" ? request.model : void 0) ?? null,
1172
- modelProvider: request.modelProvider ?? null,
1173
- requestedModelProvider: request.requestedModelProvider === void 0 ? request.modelProvider ?? null : request.requestedModelProvider,
1174
- permissions: request.permissions ?? null,
1175
- baseInstructions: request.baseInstructions ?? null,
1176
- developerInstructions: request.developerInstructions ?? null,
1177
- config: request.config ?? {}
1178
- }));
1179
- }
1180
- function fingerprintEnvironmentSelection(environments) {
1181
- return environments ? JSON.stringify(environments.map(stabilizeJsonValue)) : void 0;
1182
- }
1183
- function stabilizeJsonValue(value) {
1184
- if (Array.isArray(value)) return value.map(stabilizeJsonValue);
1185
- if (!isJsonObject(value)) return value;
1186
- return Object.fromEntries(Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, child]) => [key, stabilizeJsonValue(child)]));
1187
- }
1188
- function readActiveCodexTurnIds(thread) {
1189
- return (thread.turns ?? []).filter((turn) => turn.status === "inProgress").map((turn) => typeof turn.id === "string" ? turn.id : "").filter((turnId) => turnId.trim().length > 0);
1190
- }
1191
- function readActiveCodexTurnIdsFromResume(response) {
1192
- const pagedTurns = response.initialTurnsPage?.data;
1193
- return readActiveCodexTurnIds(Array.isArray(pagedTurns) ? { turns: pagedTurns } : response.thread);
1194
- }
1195
- const LEGACY_EMPTY_DYNAMIC_TOOLS_FINGERPRINT = legacyFingerprintDynamicTools([]);
1196
- const EMPTY_DYNAMIC_TOOLS_FINGERPRINT = hashCodexAppServerBindingFingerprint(LEGACY_EMPTY_DYNAMIC_TOOLS_FINGERPRINT);
1197
- function areDynamicToolFingerprintsCompatible(previous, next, nextLegacy) {
1198
- return !previous || previous === next || previous === nextLegacy;
1199
- }
1200
- function areUserMcpServersFingerprintsCompatible(params) {
1201
- return params.previous === params.next || params.previous === params.nextLegacy || params.nextLegacy !== void 0 && params.previous === hashCodexAppServerBindingFingerprint(params.nextLegacy);
1202
- }
1203
- function shouldStartTransientNoToolThread(params) {
1204
- return Boolean(params.previous && !isEmptyDynamicToolsFingerprint(params.previous) && !params.nextHasDynamicTools);
1205
- }
1206
- function isEmptyDynamicToolsFingerprint(fingerprint) {
1207
- return fingerprint === EMPTY_DYNAMIC_TOOLS_FINGERPRINT || fingerprint === LEGACY_EMPTY_DYNAMIC_TOOLS_FINGERPRINT;
1208
- }
1209
- function compareJsonFingerprint(left, right) {
1210
- return JSON.stringify(left).localeCompare(JSON.stringify(right));
1211
- }
1212
- //#endregion
1213
- //#region extensions/codex/src/app-server/native-skill-isolation.ts
1214
- const MAX_PERSONAL_SKILL_DIRECTORIES = 2e3;
1215
- const MAX_PERSONAL_SKILL_DEPTH = 6;
1216
- const MAX_PERSONAL_SKILL_ENTRIES = 1e4;
1217
- const nativeSkillIsolationByClient = /* @__PURE__ */ new WeakMap();
1218
- function isMissingPathError(error) {
1219
- return error.code === "ENOENT";
1220
- }
1221
- async function canonicalizeExistingPath(candidate) {
1222
- try {
1223
- return await fs.realpath(candidate);
1224
- } catch {
1225
- return path.resolve(candidate);
1226
- }
1227
- }
1228
- async function usesDefaultStateDir() {
1229
- if (!process.env.OPENCLAW_STATE_DIR?.trim()) return true;
1230
- const home = resolveRequiredHomeDir();
1231
- const [stateDir, defaultStateDir] = await Promise.all([canonicalizeExistingPath(resolveStateDir()), canonicalizeExistingPath(path.join(home, ".openclaw"))]);
1232
- return stateDir === defaultStateDir;
1233
- }
1234
- async function collectPersonalSkillRealPaths(homes, codexHome) {
1235
- const realStateDir = await canonicalizeExistingPath(resolveStateDir());
1236
- const roots = [];
1237
- for (const home of homes) {
1238
- for (const dir of [".agents", ".claude"]) roots.push({
1239
- dir: path.join(home, dir, "skills"),
1240
- onlyEscapedStateTargets: false
1241
- });
1242
- const defaultCodexHome = path.join(home, ".codex");
1243
- const realDefaultCodexHome = await canonicalizeExistingPath(defaultCodexHome);
1244
- roots.push({
1245
- dir: path.join(defaultCodexHome, "skills"),
1246
- onlyEscapedStateTargets: isPathInside(realStateDir, realDefaultCodexHome)
1247
- });
1248
- }
1249
- const configuredCodexHome = codexHome?.trim() || process.env.CODEX_HOME?.trim();
1250
- if (configuredCodexHome) {
1251
- const realCodexHome = await canonicalizeExistingPath(configuredCodexHome);
1252
- const stateOwned = isPathInside(realStateDir, realCodexHome);
1253
- roots.push({
1254
- dir: path.join(configuredCodexHome, "skills"),
1255
- onlyEscapedStateTargets: stateOwned
1256
- });
1257
- }
1258
- const skillPaths = /* @__PURE__ */ new Set();
1259
- let complete = true;
1260
- const seenDirectories = /* @__PURE__ */ new Set();
1261
- const queue = roots.map((root) => ({
1262
- dir: root.dir,
1263
- onlyEscapedStateTargets: root.onlyEscapedStateTargets,
1264
- depth: 0
1265
- }));
1266
- let entryCount = 0;
1267
- const recordSkillFile = async (filePath, onlyEscapedStateTargets) => {
1268
- try {
1269
- const skillRealPath = await fs.realpath(filePath);
1270
- if (!onlyEscapedStateTargets || !isPathInside(realStateDir, skillRealPath)) skillPaths.add(skillRealPath);
1271
- } catch (error) {
1272
- if (!isMissingPathError(error)) complete = false;
1273
- }
1274
- };
1275
- for (const current of queue) {
1276
- let realDir;
1277
- try {
1278
- realDir = await fs.realpath(current.dir);
1279
- } catch (error) {
1280
- if (isMissingPathError(error)) continue;
1281
- complete = false;
1282
- continue;
1283
- }
1284
- if (seenDirectories.has(realDir)) continue;
1285
- seenDirectories.add(realDir);
1286
- if (seenDirectories.size > MAX_PERSONAL_SKILL_DIRECTORIES) {
1287
- complete = false;
1288
- break;
1289
- }
1290
- let directory;
1291
- try {
1292
- directory = await fs.opendir(current.dir);
1293
- } catch (error) {
1294
- if (!isMissingPathError(error)) complete = false;
1295
- continue;
1296
- }
1297
- try {
1298
- for await (const entry of directory) {
1299
- entryCount += 1;
1300
- if (entryCount > MAX_PERSONAL_SKILL_ENTRIES) {
1301
- complete = false;
1302
- queue.length = 0;
1303
- break;
1304
- }
1305
- if (entry.name.startsWith(".")) continue;
1306
- const entryPath = path.join(current.dir, entry.name);
1307
- if (entry.name === "SKILL.md" && entry.isFile()) {
1308
- await recordSkillFile(entryPath, current.onlyEscapedStateTargets);
1309
- continue;
1310
- }
1311
- if (entry.isSymbolicLink()) {
1312
- try {
1313
- const stat = await fs.stat(entryPath);
1314
- if (entry.name === "SKILL.md" && stat.isFile()) await recordSkillFile(entryPath, current.onlyEscapedStateTargets);
1315
- else if (stat.isDirectory()) {
1316
- if (current.depth < MAX_PERSONAL_SKILL_DEPTH) queue.push({
1317
- dir: entryPath,
1318
- depth: current.depth + 1,
1319
- onlyEscapedStateTargets: current.onlyEscapedStateTargets
1320
- });
1321
- else complete = false;
1322
- }
1323
- } catch (error) {
1324
- if (!isMissingPathError(error)) complete = false;
1325
- }
1326
- continue;
1327
- }
1328
- if (current.depth >= MAX_PERSONAL_SKILL_DEPTH) {
1329
- if (entry.isDirectory()) complete = false;
1330
- continue;
1331
- }
1332
- if (entry.isDirectory()) {
1333
- queue.push({
1334
- dir: entryPath,
1335
- depth: current.depth + 1,
1336
- onlyEscapedStateTargets: current.onlyEscapedStateTargets
1337
- });
1338
- continue;
1339
- }
1340
- }
1341
- } catch (error) {
1342
- if (!isMissingPathError(error)) complete = false;
1343
- }
1344
- }
1345
- return {
1346
- complete,
1347
- skillPaths
1348
- };
1349
- }
1350
- /** Resolves the native user-scope skills that an isolated OpenClaw thread must disable. */
1351
- async function resolveCodexNativeSkillIsolation(params) {
1352
- params.signal?.throwIfAborted();
1353
- if (!process.env.OPENCLAW_STATE_DIR?.trim()) return;
1354
- const key = JSON.stringify([
1355
- path.resolve(resolveStateDir()),
1356
- path.resolve(params.cwd),
1357
- params.codexHome?.trim() || process.env.CODEX_HOME?.trim() || "",
1358
- params.home?.trim() || process.env.HOME?.trim() || "",
1359
- params.userProfile?.trim() || process.env.USERPROFILE?.trim() || ""
1360
- ]);
1361
- const cached = nativeSkillIsolationByClient.get(params.client);
1362
- if (cached?.key === key && (cached.settled || cached.signal === params.signal)) {
1363
- const isolation = await cached.result;
1364
- params.signal?.throwIfAborted();
1365
- return isolation;
1366
- }
1367
- const result = resolveUncachedCodexNativeSkillIsolation(params);
1368
- const entry = {
1369
- key,
1370
- result,
1371
- settled: false,
1372
- signal: params.signal
1373
- };
1374
- nativeSkillIsolationByClient.set(params.client, entry);
1375
- try {
1376
- const isolation = await result;
1377
- entry.settled = true;
1378
- params.signal?.throwIfAborted();
1379
- return isolation;
1380
- } catch (error) {
1381
- if (nativeSkillIsolationByClient.get(params.client)?.result === result) nativeSkillIsolationByClient.delete(params.client);
1382
- throw error;
1383
- }
1384
- }
1385
- async function resolveUncachedCodexNativeSkillIsolation(params) {
1386
- if (await usesDefaultStateDir()) return;
1387
- const response = await params.client.request("skills/list", {
1388
- cwds: [params.cwd],
1389
- forceReload: true
1390
- }, { signal: params.signal });
1391
- const homes = [params.home?.trim() || process.env.HOME?.trim() || process.env.USERPROFILE?.trim() || os.homedir()];
1392
- if (process.platform === "win32") homes.push(params.userProfile?.trim() || os.homedir());
1393
- const personalSkills = await collectPersonalSkillRealPaths([...new Set(homes.map((home) => path.resolve(home)))], params.codexHome);
1394
- 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)) };
1395
- }
1396
- /** Applies path-exact session rules after caller config so isolated user skills stay disabled. */
1397
- function applyCodexNativeSkillIsolation(config, isolation) {
1398
- if (!isolation) return config;
1399
- const existingRules = config?.["skills.config"];
1400
- if (existingRules !== void 0 && !Array.isArray(existingRules)) throw new Error("Codex thread skills.config must be an array");
1401
- const disabledRules = isolation.disabledUserSkillPaths.map((skillPath) => ({
1402
- path: skillPath,
1403
- enabled: false
1404
- }));
1405
- return {
1406
- ...config,
1407
- "skills.include_instructions": false,
1408
- "skills.config": [...existingRules ?? [], ...disabledRules]
1409
- };
1410
- }
1411
- //#endregion
1412
- //#region extensions/codex/src/app-server/native-tool-catalog.ts
1413
- function hasCodexNativeToolCatalog(binding) {
1414
- return binding?.connectionScope === "supervision" && !binding.pendingSupervisionBranch;
1415
- }
1416
- /** Pinned serde omits empty catalogs and false deferLoading; declarations remain native-owned. */
1417
- function parseCodexNativeToolCatalog(metadata, threadId, fingerprint) {
1418
- 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.");
1419
- if (!isJsonObject(metadata) || metadata.id !== threadId) throw fail();
1420
- const catalog = metadata.dynamic_tools ?? [];
1421
- if (!Array.isArray(catalog) || Buffer.byteLength(JSON.stringify(catalog)) > 1048576) throw fail();
1422
- const names = /* @__PURE__ */ new Set();
1423
- const namespaces = /* @__PURE__ */ new Set();
1424
- const validName = (name) => typeof name === "string" && /^[a-zA-Z0-9_-]{1,128}$/u.test(name);
1425
- const readFunction = (value) => {
1426
- 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) => ![
1427
- "type",
1428
- "name",
1429
- "description",
1430
- "inputSchema",
1431
- "deferLoading"
1432
- ].includes(key)) || names.has(value.name) || names.size >= 2e3) throw fail();
1433
- names.add(value.name);
1434
- return {
1435
- type: "function",
1436
- name: value.name,
1437
- description: value.description,
1438
- inputSchema: structuredClone(value.inputSchema),
1439
- ...value.deferLoading === true ? { deferLoading: true } : {}
1440
- };
1441
- };
1442
- const tools = catalog.map((value) => {
1443
- if (!isJsonObject(value) || value.type !== "namespace") return readFunction(value);
1444
- if (!validName(value.name) || namespaces.has(value.name) || typeof value.description !== "string" || !Array.isArray(value.tools) || !value.tools.length || Object.keys(value).some((key) => ![
1445
- "type",
1446
- "name",
1447
- "description",
1448
- "tools"
1449
- ].includes(key))) throw fail();
1450
- namespaces.add(value.name);
1451
- return {
1452
- type: "namespace",
1453
- name: value.name,
1454
- description: value.description,
1455
- tools: value.tools.map(readFunction)
1456
- };
1457
- });
1458
- if (fingerprint !== void 0 && codexDynamicToolsFingerprint(tools) !== fingerprint) throw fail();
1459
- return tools;
1460
- }
1461
- /** Existing supervised bindings identify data, never authorize an executor or a new adoption. */
1462
- async function loadCodexNativeToolCatalog(params) {
1463
- const { binding, client, appServer, agentDir, assertCurrent } = params;
1464
- assertCurrent();
1465
- const home = resolveCodexAppServerLocalHomeDir(appServer.start, agentDir);
1466
- const actualHome = client.getRuntimeIdentity()?.codexHome;
1467
- 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.");
1468
- const metadata = await readCodexClientSessionMeta(client, path.join(home, "sessions"), binding.rolloutPath, binding.threadId);
1469
- assertCurrent();
1470
- return parseCodexNativeToolCatalog(metadata, binding.threadId, binding.dynamicToolsFingerprint);
1471
- }
1472
- //#endregion
1473
- //#region extensions/codex/src/app-server/thread-mcp-attestation.ts
1474
- async function attestCodexRestrictedToolSurfaceMcpServersDisabled(client, threadId, threadConfig, signal, expectedActiveServerNames = []) {
1475
- const configuredServers = threadConfig?.mcp_servers;
1476
- if (configuredServers !== void 0 && !isJsonObject(configuredServers)) throw new Error("Codex restricted-tool-surface thread config has invalid mcp_servers");
1477
- const expectedServers = /* @__PURE__ */ new Map();
1478
- for (const [name, serverConfig] of Object.entries(configuredServers ?? {})) {
1479
- if (!isJsonObject(serverConfig) || serverConfig.enabled !== false) throw new Error(`Codex restricted-tool-surface MCP server ${name} is not disabled`);
1480
- expectedServers.set(name, "disabled");
1481
- }
1482
- for (const name of expectedActiveServerNames) {
1483
- if (expectedServers.get(name) === "disabled") throw new Error(`Codex restricted-tool-surface MCP server ${name} has conflicting policy`);
1484
- expectedServers.set(name, "active");
1485
- }
1486
- const response = await client.request("mcpServerStatus/list", {
1487
- threadId,
1488
- detail: "toolsAndAuthOnly"
1489
- }, { signal });
1490
- if (!isJsonObject(response) || !Array.isArray(response.data)) throw new Error("Codex mcpServerStatus/list returned an invalid restricted-tool-surface attestation");
1491
- const observedServerNames = /* @__PURE__ */ new Set();
1492
- for (const status of response.data) {
1493
- if (!isJsonObject(status) || typeof status.name !== "string" || !isJsonObject(status.tools)) throw new Error("Codex mcpServerStatus/list returned an invalid restricted-tool-surface server");
1494
- if (!expectedServers.has(status.name)) throw new Error(`Codex restricted-tool-surface MCP attestation found unexpected server ${status.name}`);
1495
- if (observedServerNames.has(status.name)) throw new Error(`Codex restricted-tool-surface MCP attestation returned duplicate server ${status.name}`);
1496
- observedServerNames.add(status.name);
1497
- if (!Object.hasOwn(status, "serverInfo")) throw new Error(`Codex restricted-tool-surface MCP attestation returned malformed server ${status.name}`);
1498
- if (expectedServers.get(status.name) === "active") {
1499
- 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}`);
1500
- continue;
1501
- }
1502
- if (status.serverInfo !== null) throw new Error(`Codex restricted-tool-surface MCP attestation found active server ${status.name}`);
1503
- if (Object.keys(status.tools).length > 0) throw new Error(`Codex restricted-tool-surface MCP attestation found tools for server ${status.name}`);
1504
- }
1505
- 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}`);
1506
- if (response.nextCursor !== void 0 && response.nextCursor !== null) throw new Error("Codex mcpServerStatus/list returned an invalid empty-page cursor");
1507
- }
1508
- //#endregion
1509
- //#region extensions/codex/src/app-server/plugin-thread-attestation.ts
1510
- /**
1511
- * Checks app availability and enforces restricted MCP surfaces before a turn.
1512
- */
1513
- /** Every admission path checks the same surface; its lifecycle owner keeps the claim fenced. */
1514
- async function attestCodexThreadToolSurface(params) {
1515
- params.assertCurrent();
1516
- if (params.appIds.length > 0) {
1517
- await params.lifecycleTiming.measure("plugin-app-attestation", () => checkCodexThreadAppAvailability(params));
1518
- params.assertCurrent();
1519
- }
1520
- if (params.restrictedToolSurface) {
1521
- await params.lifecycleTiming.measure("restricted-tool-surface-mcp-attestation", () => attestCodexRestrictedToolSurfaceMcpServersDisabled(params.client, params.threadId, params.threadConfig, params.signal, params.appIds.length > 0 ? ["codex_apps"] : []));
1522
- params.assertCurrent();
1523
- }
1524
- }
1525
- var CodexPluginThreadAppAttestationError = class extends Error {
1526
- constructor(message, options) {
1527
- super(message, options);
1528
- this.name = "CodexPluginThreadAppAttestationError";
1529
- }
1530
- };
1531
- /** Reads the existing runtime snapshot with the started thread's effective app policy. */
1532
- async function checkCodexThreadAppAvailability(params) {
1533
- const appIds = Array.from(new Set(params.appIds.filter(Boolean))).toSorted();
1534
- if (appIds.length === 0) return;
1535
- let response;
1536
- try {
1537
- response = await params.client.request("app/installed", {
1538
- threadId: params.threadId,
1539
- forceRefresh: false
1540
- }, { signal: params.signal });
1541
- } catch (error) {
1542
- params.signal?.throwIfAborted();
1543
- throw new CodexPluginThreadAppAttestationError(`Codex could not confirm admitted apps for thread ${params.threadId}`, { cause: error });
1544
- }
1545
- params.signal?.throwIfAborted();
1546
- const installedById = new Map(response.apps.map((app) => [app.id, app]));
1547
- const failures = appIds.flatMap((appId) => {
1548
- const app = installedById.get(appId);
1549
- if (!app) return [`${appId}:missing`];
1550
- if (!app.enabled) return [`${appId}:disabled`];
1551
- return app.callable ? [] : [`${appId}:not-callable`];
1552
- });
1553
- if (failures.length > 0) embeddedAgentLog.warn("codex apps unavailable; continuing with remaining tools", {
1554
- threadId: params.threadId,
1555
- failures
1556
- });
1557
- }
1558
- /** Deletes a persistent pre-turn thread; ephemeral threads can only be unsubscribed. */
1559
- async function discardUnattestedCodexPluginThread(params) {
1560
- if (params.ephemeral) return await unsubscribeCodexThreadBestEffort(params.client, {
1561
- threadId: params.threadId,
1562
- timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
1563
- });
1564
- try {
1565
- await params.client.request("thread/delete", { threadId: params.threadId }, { timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS });
1566
- return true;
1567
- } catch (error) {
1568
- embeddedAgentLog.debug("codex plugin app attestation thread deletion failed", {
1569
- threadId: params.threadId,
1570
- error
1571
- });
1572
- await unsubscribeCodexThreadBestEffort(params.client, {
1573
- threadId: params.threadId,
1574
- timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
1575
- });
1576
- return false;
1577
- }
1578
- }
1579
- //#endregion
1580
- //#region extensions/codex/src/app-server/native-hook-relay-state.ts
1581
- const pending = /* @__PURE__ */ new Set();
1582
- /** Owns delayed hook-relay cleanup across runtime scheduling and test teardown. */
1583
- const nativeHookRelayUnregisterQueue = {
1584
- add(entry) {
1585
- pending.add(entry);
1586
- },
1587
- delete(entry) {
1588
- return pending.delete(entry);
1589
- },
1590
- flush() {
1591
- while (pending.size > 0) {
1592
- const entry = pending.values().next().value;
1593
- if (!entry) return;
1594
- clearTimeout(entry.timeout);
1595
- entry.unregister();
1596
- }
1597
- },
1598
- clear() {
1599
- for (const entry of pending) clearTimeout(entry.timeout);
1600
- pending.clear();
1601
- }
1602
- };
1603
- //#endregion
1604
- //#region extensions/codex/src/app-server/native-hook-relay.ts
1605
- /**
1606
- * Bridges Codex native hook callbacks into OpenClaw's native hook relay so
1607
- * app-server tool events can still run OpenClaw policy and diagnostics.
1608
- */
1609
- /** Codex hook events that can be registered through OpenClaw's native relay. */
1610
- const CODEX_NATIVE_HOOK_RELAY_EVENTS = [
1611
- "pre_tool_use",
1612
- "post_tool_use",
1613
- "permission_request",
1614
- "before_agent_finalize"
1615
- ];
1616
- const CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS = CODEX_NATIVE_HOOK_RELAY_EVENTS.filter((event) => event !== "permission_request");
1617
- const CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS = 18e5;
1618
- /** Extra relay lifetime after the expected turn budget, preventing late hook drops. */
1619
- const CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS = 3e5;
1620
- const CODEX_NATIVE_HOOK_RELAY_COMMAND_MIN_PARENT_MARGIN_MS = 250;
1621
- const CODEX_NATIVE_HOOK_RELAY_COMMAND_MAX_PARENT_MARGIN_MS = 1e3;
1622
- const CODEX_NATIVE_HOOK_RELAY_DEFAULT_TIMEOUT_SEC = 10;
1623
- const CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS = 1e4;
1624
- const CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS = 5e3;
1625
- const MAX_PENDING_DIRECT_CHILD_ADMISSIONS = 32;
1626
- const nativeHookPolicyByClient = /* @__PURE__ */ new WeakMap();
1627
- const CODEX_HOOK_MATCHER_NAMES_BY_TOOL_ID = {
1628
- exec: [
1629
- "Bash",
1630
- "exec",
1631
- "exec_command"
1632
- ],
1633
- apply_patch: [
1634
- "apply_patch",
1635
- "Write",
1636
- "Edit"
1637
- ],
1638
- spawn_agent: ["spawn_agent", "Agent"]
1639
- };
1640
- /** Enterprise managed-only policy silently drops the session-layer hooks that enforce OpenClaw. */
1641
- async function assertCodexNativeHookRelayAllowed(client, signal) {
1642
- let attestation = nativeHookPolicyByClient.get(client);
1643
- if (!attestation) {
1644
- attestation = client.request("configRequirements/read", void 0, { signal }).then((response) => {
1645
- if (!isJsonObject(response) || !Object.hasOwn(response, "requirements")) throw new Error("Codex configRequirements/read returned an invalid hook policy response");
1646
- const requirements = response.requirements;
1647
- if (requirements === null) return;
1648
- if (!isJsonObject(requirements)) throw new Error("Codex configRequirements/read returned invalid hook policy requirements");
1649
- const managedOnly = requirements.allowManagedHooksOnly;
1650
- if (managedOnly !== void 0 && managedOnly !== null && typeof managedOnly !== "boolean") throw new Error("Codex configRequirements/read returned invalid managed-only hook policy");
1651
- if (managedOnly === true) throw new Error("Codex managed-only hooks disable the OpenClaw native hook relay; refusing unenforced execution");
1652
- });
1653
- nativeHookPolicyByClient.set(client, attestation);
1654
- attestation.catch(() => {
1655
- if (nativeHookPolicyByClient.get(client) === attestation) nativeHookPolicyByClient.delete(client);
1656
- });
1657
- }
1658
- await attestation;
1659
- }
1660
- /** Defers relay unregister so late native hook subprocesses can still resolve. */
1661
- function scheduleCodexNativeHookRelayUnregister(params) {
1662
- let pending;
1663
- const unregister = () => {
1664
- if (!pending) return;
1665
- const current = pending;
1666
- pending = void 0;
1667
- if (!nativeHookRelayUnregisterQueue.delete(current)) return;
1668
- params.relay.unregister();
1669
- };
1670
- const timeout = setTimeout(unregister, resolveCodexNativeHookRelayUnregisterGraceMs(params.hookTimeoutSec));
1671
- pending = {
1672
- timeout,
1673
- unregister
1674
- };
1675
- nativeHookRelayUnregisterQueue.add(pending);
1676
- timeout.unref();
1677
- }
1678
- /** Computes the delayed unregister window from Codex's hook timeout. */
1679
- function resolveCodexNativeHookRelayUnregisterGraceMs(hookTimeoutSec) {
1680
- const hookTimeoutMs = finiteSecondsToTimerSafeMilliseconds(normalizeHookTimeoutSec(hookTimeoutSec)) ?? 0;
1681
- return Math.max(CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS, addTimerTimeoutGraceMs(hookTimeoutMs, CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS) ?? 0);
1682
- }
1683
- /** Records a native pre-tool failure that Codex does not project as a tool item. */
1684
- function emitCodexNativePreToolUseFailureDiagnostic(params) {
1685
- emitTrustedDiagnosticEvent({
1686
- type: "tool.execution.error",
1687
- ...params.agentId ? { agentId: params.agentId } : {},
1688
- sessionId: params.sessionId,
1689
- ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
1690
- runId: params.runId,
1691
- toolName: params.failure.toolName,
1692
- toolCallId: params.failure.toolCallId,
1693
- durationMs: params.failure.durationMs,
1694
- errorCategory: "before_tool_call",
1695
- terminalReason: params.terminalReason ?? (params.signal?.aborted ? resolveCodexToolAbortTerminalReason(params.signal) : params.failure.disposition),
1696
- ...params.sourceTimestampMs !== void 0 ? { sourceTimestampMs: params.sourceTimestampMs } : {}
1697
- });
1698
- }
1699
- /** Registers an OpenClaw native hook relay for a Codex app-server turn. */
1700
- function createCodexNativeHookRelay(params) {
1701
- if (params.options?.enabled === false) return;
1702
- const directChildClaims = /* @__PURE__ */ new Map();
1703
- const pendingDirectChildAdmissions = /* @__PURE__ */ new Map();
1704
- let foregroundClosed = false;
1705
- let successfulYieldRetentionAuthorized = false;
1706
- const assertClaim = (threadId, claim) => () => directChildClaims.get(threadId) === claim;
1707
- const rejectPendingAdmissions = (reason) => {
1708
- for (const pending of pendingDirectChildAdmissions.values()) pending.reject(new Error(reason));
1709
- pendingDirectChildAdmissions.clear();
1710
- };
1711
- const relay = registerRetainedNativeHookRelayForBundledRuntime({
1712
- provider: "codex",
1713
- relayId: buildCodexNativeHookRelayId({
1714
- agentId: params.agentId,
1715
- sessionId: params.sessionId,
1716
- sessionKey: params.sessionKey
1717
- }),
1718
- ...params.generation ? { generation: params.generation } : {},
1719
- ...params.generationMismatchGraceMs ? { generationMismatchGraceMs: params.generationMismatchGraceMs } : {},
1720
- ...params.agentId ? { agentId: params.agentId } : {},
1721
- sessionId: params.sessionId,
1722
- ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
1723
- ...params.config ? { config: params.config } : {},
1724
- autoApproveMcpTools: params.autoApproveMcpTools,
1725
- projectedMcpServers: params.projectedMcpServers,
1726
- runId: params.runId,
1727
- ...params.channelId ? { channelId: params.channelId } : {},
1728
- ...params.requester ? { requester: params.requester } : {},
1729
- ...params.approvalContext ? { approvalContext: params.approvalContext } : {},
1730
- allowedEvents: params.events,
1731
- preToolUseLoopDetection: params.loopDetectionPreToolUseRelay,
1732
- ttlMs: resolveCodexNativeHookRelayTtlMs({
1733
- explicitTtlMs: params.options?.ttlMs,
1734
- attemptTimeoutMs: params.attemptTimeoutMs,
1735
- startupTimeoutMs: params.startupTimeoutMs,
1736
- turnStartTimeoutMs: params.turnStartTimeoutMs
1737
- }),
1738
- signal: params.signal,
1739
- runBeforeToolCall: params.hostCapabilities.runBeforeToolCall,
1740
- assertActive: () => {
1741
- params.hostCapabilities.assertActive();
1742
- params.assertCurrent?.();
1743
- },
1744
- retention: {
1745
- readClaim: readCodexNativeChildThreadId,
1746
- shouldRetainAfterForegroundClose: () => successfulYieldRetentionAuthorized && directChildClaims.size > 0,
1747
- allowPreToolUse: (childThreadId) => directChildClaims.has(childThreadId),
1748
- awaitForegroundAdmission: (childThreadId) => {
1749
- if (foregroundClosed) return Promise.reject(/* @__PURE__ */ new Error("native hook relay foreground admission unavailable"));
1750
- const existingClaim = directChildClaims.get(childThreadId);
1751
- if (existingClaim) return Promise.resolve(assertClaim(childThreadId, existingClaim));
1752
- const existingPending = pendingDirectChildAdmissions.get(childThreadId);
1753
- if (existingPending) return existingPending.promise.then((claim) => assertClaim(childThreadId, claim));
1754
- if (pendingDirectChildAdmissions.size >= MAX_PENDING_DIRECT_CHILD_ADMISSIONS) return Promise.reject(/* @__PURE__ */ new Error("native hook relay foreground admission capacity reached"));
1755
- const { promise, resolve, reject } = createDeferred();
1756
- pendingDirectChildAdmissions.set(childThreadId, {
1757
- promise,
1758
- resolve,
1759
- reject
1760
- });
1761
- return promise.then((claim) => assertClaim(childThreadId, claim));
1762
- },
1763
- onDispose: () => {
1764
- foregroundClosed = true;
1765
- rejectPendingAdmissions("native hook relay registration closed");
1766
- }
1767
- },
1768
- onPreToolUseFailure: params.onPreToolUseFailure,
1769
- command: {
1770
- nice: 10,
1771
- timeoutMs: params.options?.gatewayTimeoutMs
1772
- }
1773
- });
1774
- const unregister = () => {
1775
- foregroundClosed = true;
1776
- rejectPendingAdmissions("native hook relay foreground closed");
1777
- relay.unregister();
1778
- };
1779
- return {
1780
- ...relay,
1781
- unregister,
1782
- authorizeRetentionAfterSuccessfulYield: () => {
1783
- successfulYieldRetentionAuthorized = true;
1784
- },
1785
- hasClaimedDirectChild: () => directChildClaims.size > 0,
1786
- rejectPendingDirectChild: (threadIdInput, reason) => {
1787
- const threadId = threadIdInput.trim();
1788
- const pending = threadId ? pendingDirectChildAdmissions.get(threadId) : void 0;
1789
- if (!pending) return;
1790
- pendingDirectChildAdmissions.delete(threadId);
1791
- pending.reject(new Error(reason));
1792
- },
1793
- claimDirectChild: (threadIdInput) => {
1794
- const threadId = threadIdInput.trim();
1795
- if (!threadId) return () => void 0;
1796
- if (directChildClaims.get(threadId)) return () => void 0;
1797
- const claim = Symbol(threadId);
1798
- directChildClaims.set(threadId, claim);
1799
- const pending = pendingDirectChildAdmissions.get(threadId);
1800
- pendingDirectChildAdmissions.delete(threadId);
1801
- pending?.resolve(claim);
1802
- let released = false;
1803
- return () => {
1804
- if (released) return;
1805
- released = true;
1806
- if (directChildClaims.get(threadId) !== claim) return;
1807
- directChildClaims.delete(threadId);
1808
- if (foregroundClosed && directChildClaims.size === 0) relay.unregister();
1809
- };
1810
- }
1811
- };
1812
- }
1813
- function readCodexNativeChildThreadId(rawPayload) {
1814
- if (!isJsonObject(rawPayload) || typeof rawPayload.agent_id !== "string") return;
1815
- return rawPayload.agent_id.trim() || void 0;
1816
- }
1817
- /** Selects the native hook events Codex should install for the current approval mode. */
1818
- function resolveCodexNativeHookRelayEvents(params) {
1819
- if (params.configuredEvents?.length) return params.configuredEvents;
1820
- return params.appServer.approvalPolicy === "never" ? CODEX_NATIVE_HOOK_RELAY_EVENTS : CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS;
1821
- }
1822
- /** Derives the native hook relay TTL from the turn budget unless explicitly configured. */
1823
- function resolveCodexNativeHookRelayTtlMs(params) {
1824
- if (params.explicitTtlMs !== void 0) return params.explicitTtlMs;
1825
- const relayBudgetMs = params.attemptTimeoutMs + params.startupTimeoutMs + params.turnStartTimeoutMs + CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS;
1826
- return Math.max(CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS, Math.floor(relayBudgetMs));
1827
- }
1828
- /** Builds a stable relay id scoped to the agent and session identity. */
1829
- function buildCodexNativeHookRelayId(params) {
1830
- const hash = createHash("sha256");
1831
- hash.update("openclaw:codex:native-hook-relay:v1");
1832
- hash.update("\0");
1833
- hash.update(params.agentId?.trim() || "");
1834
- hash.update("\0");
1835
- hash.update(params.sessionKey?.trim() || params.sessionId);
1836
- return `codex-${hash.digest("hex").slice(0, 40)}`;
1837
- }
1838
- const CODEX_HOOK_EVENT_BY_NATIVE_EVENT = {
1839
- pre_tool_use: "PreToolUse",
1840
- post_tool_use: "PostToolUse",
1841
- permission_request: "PermissionRequest",
1842
- before_agent_finalize: "Stop"
1843
- };
1844
- const CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT = {
1845
- pre_tool_use: "pre_tool_use",
1846
- post_tool_use: "post_tool_use",
1847
- permission_request: "permission_request",
1848
- before_agent_finalize: "stop"
1849
- };
1850
- const CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS = ["/<session-flags>/config.toml", "<session-flags>/config.toml"];
1851
- /** Builds the Codex config overlay that installs trusted command hooks for relay events. */
1852
- function buildCodexNativeHookRelayConfig(params) {
1853
- const events = params.events?.length ? params.events : CODEX_NATIVE_HOOK_RELAY_EVENTS;
1854
- const selectedEvents = new Set(events);
1855
- const config = { "features.hooks": true };
1856
- const hookState = {};
1857
- for (const event of CODEX_NATIVE_HOOK_RELAY_EVENTS) {
1858
- const codexEvent = CODEX_HOOK_EVENT_BY_NATIVE_EVENT[event];
1859
- const selected = selectedEvents.has(event);
1860
- const shouldRelay = params.relay.shouldRelayEvent(event);
1861
- if (!selected || !shouldRelay) {
1862
- if (selected || params.clearOmittedEvents) config[`hooks.${codexEvent}`] = [];
1863
- 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 };
1864
- continue;
1865
- }
1866
- const timeout = normalizeHookTimeoutSec(params.hookTimeoutSec);
1867
- const command = params.relay.commandForEvent(event, { timeoutMs: resolveCodexNativeHookRelayCommandTimeoutMs(timeout) });
1868
- const matcher = buildCodexNativeToolMatcher(params.relay.toolMatcherForEvent(event));
1869
- config[`hooks.${codexEvent}`] = [{
1870
- ...matcher ? { matcher } : {},
1871
- hooks: [{
1872
- type: "command",
1873
- command,
1874
- timeout,
1875
- async: false,
1876
- statusMessage: "OpenClaw native hook relay"
1877
- }]
1878
- }];
1879
- const state = {
1880
- enabled: true,
1881
- trusted_hash: codexCommandHookTrustedHash({
1882
- event,
1883
- command,
1884
- matcher,
1885
- timeout,
1886
- statusMessage: "OpenClaw native hook relay"
1887
- })
1888
- };
1889
- for (const sourcePath of CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS) hookState[`${sourcePath}:${CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[event]}:0:0`] = state;
1890
- }
1891
- config["hooks.state"] = hookState;
1892
- return config;
1893
- }
1894
- /** Builds a Codex config overlay that disables native hooks and clears hook arrays. */
1895
- function buildCodexNativeHookRelayDisabledConfig() {
1896
- return {
1897
- "features.hooks": false,
1898
- "hooks.PreToolUse": [],
1899
- "hooks.PostToolUse": [],
1900
- "hooks.PermissionRequest": [],
1901
- "hooks.Stop": []
512
+ mode: "thread_bootstrap",
513
+ epoch: projection.epoch,
514
+ fingerprint: projection.fingerprint
1902
515
  };
1903
516
  }
1904
- function normalizeHookTimeoutSec(value) {
1905
- return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.ceil(value) : CODEX_NATIVE_HOOK_RELAY_DEFAULT_TIMEOUT_SEC;
1906
- }
1907
- function resolveCodexNativeHookRelayCommandTimeoutMs(hookTimeoutSec) {
1908
- const parentTimeoutMs = finiteSecondsToTimerSafeMilliseconds(normalizeHookTimeoutSec(hookTimeoutSec)) ?? 5e3;
1909
- 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)));
1910
- 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);
1911
519
  }
1912
- function buildCodexNativeToolMatcher(toolNames) {
1913
- if (toolNames === void 0) return;
1914
- if (toolNames.length === 0) throw new TypeError("Codex native hook matcher requires at least one tool name");
1915
- const nativeNames = /* @__PURE__ */ new Set();
1916
- let hasCustomToolName = false;
1917
- for (const toolName of toolNames) {
1918
- const canonicalToolName = toolName.trim();
1919
- if (!canonicalToolName || canonicalToolName === "*") throw new TypeError("Codex native hook matcher requires canonical OpenClaw tool ids");
1920
- const nativeAliases = CODEX_HOOK_MATCHER_NAMES_BY_TOOL_ID[canonicalToolName];
1921
- if (!nativeAliases) hasCustomToolName = true;
1922
- for (const nativeName of nativeAliases ?? [canonicalToolName]) nativeNames.add(nativeName);
1923
- }
1924
- const sortedNames = Array.from(nativeNames).toSorted();
1925
- if (!hasCustomToolName && sortedNames.every((toolName) => /^[A-Za-z0-9_]+$/.test(toolName))) return sortedNames.join("|");
1926
- 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;
1927
523
  }
1928
- function codexCommandHookTrustedHash(params) {
1929
- const identity = {
1930
- event_name: CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[params.event],
1931
- ...params.matcher ? { matcher: params.matcher } : {},
1932
- hooks: [{
1933
- async: false,
1934
- command: params.command,
1935
- statusMessage: params.statusMessage,
1936
- timeout: params.timeout,
1937
- type: "command"
1938
- }]
1939
- };
1940
- 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;
1941
528
  }
1942
- function sortJsonValue(value) {
1943
- if (!value || typeof value !== "object") return value;
1944
- if (Array.isArray(value)) return value.map(sortJsonValue);
1945
- const sorted = {};
1946
- for (const [key, entry] of Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right))) sorted[key] = sortJsonValue(entry);
1947
- 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);
1948
534
  }
1949
535
  //#endregion
1950
536
  //#region extensions/codex/src/app-server/profiler-flag.ts
@@ -1954,23 +540,6 @@ function isCodexAppServerProfilerEnabled(config, env = process.env) {
1954
540
  return PROFILER_FLAGS.some((flag) => isDiagnosticFlagEnabled(flag, config, env));
1955
541
  }
1956
542
  //#endregion
1957
- //#region extensions/codex/src/app-server/project-doc-thread-config.ts
1958
- const CODEX_NATIVE_PROJECT_DOC_MAX_BYTES = 131072;
1959
- function buildCodexProjectDocThreadConfig(config, effectiveNativeConfig) {
1960
- const defaults = { project_doc_max_bytes: resolveCodexNativeProjectDocMaxBytes(effectiveNativeConfig) ?? CODEX_NATIVE_PROJECT_DOC_MAX_BYTES };
1961
- return mergeCodexThreadConfigs(defaults, config) ?? defaults;
1962
- }
1963
- function resolveCodexNativeProjectDocMaxBytes(effectiveNativeConfig) {
1964
- if (effectiveNativeConfig?.origins?.project_doc_max_bytes === void 0) return;
1965
- const authoredMaxBytes = effectiveNativeConfig.config.project_doc_max_bytes;
1966
- if (typeof authoredMaxBytes !== "number" || !Number.isSafeInteger(authoredMaxBytes) || authoredMaxBytes < 0) throw new Error("Codex config/read returned an invalid project_doc_max_bytes value");
1967
- return authoredMaxBytes;
1968
- }
1969
- function mergeCodexNativeProjectDocThreadConfig(config, effectiveNativeConfig) {
1970
- const authoredMaxBytes = resolveCodexNativeProjectDocMaxBytes(effectiveNativeConfig);
1971
- return authoredMaxBytes === void 0 ? config : mergeCodexThreadConfigs({ project_doc_max_bytes: authoredMaxBytes }, config);
1972
- }
1973
- //#endregion
1974
543
  //#region extensions/codex/src/app-server/mcp-tool-metadata.ts
1975
544
  /** Hosted app ownership is authoritative only on metadata supplied by Codex. */
1976
545
  function readCodexMcpToolConnectorId(tool) {
@@ -1985,567 +554,44 @@ function readCodexMcpToolUiVisibility(tool) {
1985
554
  return [...new Set(visibility.filter((value) => value === "app" || value === "model"))].toSorted();
1986
555
  }
1987
556
  //#endregion
1988
- //#region extensions/codex/src/app-server/thread-model-selection.ts
1989
- const CODEX_NATIVE_PERSONALITY_NONE = "none";
1990
- function resolveCodexBindingModelProviderFallback(params) {
1991
- const provider = params.provider?.trim().toLowerCase();
1992
- if (provider && provider !== "codex") return;
1993
- const currentModel = params.currentModel?.trim();
1994
- const bindingModel = params.bindingModel?.trim();
1995
- if (currentModel && bindingModel && currentModel === bindingModel && params.bindingModelProvider) return params.bindingModelProvider;
1996
- return hasProviderQualifiedModelRef(currentModel) ? void 0 : params.bindingModelProvider;
1997
- }
1998
- function resolveCodexAppServerThreadModelSelection(params) {
1999
- const authProfileId = params.authProfileId ?? params.binding?.authProfileId;
2000
- const explicitModelProvider = resolveCodexAppServerModelProvider({
2001
- provider: params.provider,
2002
- authProfileId,
2003
- authProfileStore: params.authProfileStore,
2004
- agentDir: params.agentDir,
2005
- config: params.config
2006
- });
2007
- const bindingModelProvider = params.binding?.threadId ? resolveCodexBindingModelProviderFallback({
2008
- provider: params.provider,
2009
- currentModel: params.model,
2010
- bindingModel: params.binding.model,
2011
- bindingModelProvider: params.binding.modelProvider
2012
- }) : void 0;
2013
- return resolveCodexAppServerRequestModelSelection({
2014
- model: params.model,
2015
- modelProvider: explicitModelProvider ?? bindingModelProvider,
2016
- authProfileId,
2017
- authProfileStore: params.authProfileStore,
2018
- agentDir: params.agentDir,
2019
- config: params.config
2020
- });
2021
- }
2022
- function resolveCodexAppServerRequestModelSelection(params) {
2023
- const model = params.model.trim();
2024
- const modelProvider = params.modelProvider?.trim();
2025
- if (modelProvider) return {
2026
- model,
2027
- modelProvider
2028
- };
2029
- const slashIndex = model.indexOf("/");
2030
- if (slashIndex <= 0 || slashIndex >= model.length - 1) return { model };
2031
- const inferredModelProvider = resolveCodexAppServerModelProvider({
2032
- provider: model.slice(0, slashIndex),
2033
- authProfileId: params.authProfileId,
2034
- authProfileStore: params.authProfileStore,
2035
- agentDir: params.agentDir,
2036
- config: params.config
2037
- });
2038
- return {
2039
- model: model.slice(slashIndex + 1).trim(),
2040
- ...inferredModelProvider ? { modelProvider: inferredModelProvider } : {}
2041
- };
2042
- }
2043
- function hasProviderQualifiedModelRef(model) {
2044
- const trimmed = model?.trim();
2045
- const slashIndex = trimmed?.indexOf("/") ?? -1;
2046
- return slashIndex > 0 && slashIndex < (trimmed?.length ?? 0) - 1;
2047
- }
2048
- function resolveCodexAppServerModelProvider(params) {
2049
- const normalized = params.provider.trim();
2050
- const normalizedLower = normalized.toLowerCase();
2051
- if (!normalized || normalizedLower === "codex") return;
2052
- if (isCodexAppServerNativeAuthProfile(params) && normalizedLower === "openai") return;
2053
- return normalizedLower === "openai" ? "openai" : normalized;
2054
- }
2055
- //#endregion
2056
- //#region extensions/codex/src/app-server/thread-prompt.ts
2057
- function buildDeveloperInstructions(params, options = {}) {
2058
- const deferredToolNames = /* @__PURE__ */ new Set();
2059
- let showWidgetToolName;
2060
- let dashboardToolName;
2061
- let portalToolName;
2062
- let messageTool;
2063
- let hasSkillWorkshop = false;
2064
- let hasSessionsSpawn = false;
2065
- let hasSessionsYield = false;
2066
- let hasSubagentsList = false;
2067
- let hasSessionsSend = false;
2068
- let hasControlTools = false;
2069
- let hasSeenDirectNamespace = false;
2070
- for (const spec of options.dynamicTools ?? []) {
2071
- const isDirectNamespace = spec.type === "namespace" && !hasSeenDirectNamespace && spec.name.trim() === "openclaw_direct";
2072
- if (isDirectNamespace) hasSeenDirectNamespace = true;
2073
- for (const tool of spec.type === "namespace" ? spec.tools : [spec]) {
2074
- const name = tool.name.trim();
2075
- const qualifiedName = spec.type === "namespace" ? `${spec.name}.${name}` : name;
2076
- if (tool.deferLoading === true && name) deferredToolNames.add(name);
2077
- if (name === "show_widget") showWidgetToolName ??= qualifiedName;
2078
- if (name === "dashboard") dashboardToolName ??= qualifiedName;
2079
- if (name === "portal") portalToolName ??= qualifiedName;
2080
- if (name === "message") messageTool ??= {
2081
- name: qualifiedName,
2082
- parameters: tool.inputSchema
2083
- };
2084
- hasSkillWorkshop ||= name === SKILL_WORKSHOP_TOOL_NAME;
2085
- hasSessionsSpawn ||= name === "sessions_spawn";
2086
- hasSessionsYield ||= isDirectNamespace && name === "sessions_yield";
2087
- hasSubagentsList ||= name === "subagents";
2088
- hasSessionsSend ||= name === "sessions_send";
2089
- hasControlTools ||= name === "openclaw" || name === "gateway";
2090
- }
2091
- }
2092
- const nativeCommandGuidance = listRegisteredPluginAgentPromptGuidance({
2093
- surface: "codex_app_server",
2094
- includeLegacyGlobalGuidance: false
2095
- }).join("\n");
2096
- const delegationGuidanceAvailable = params.disableTools !== true && params.delegationCapability !== "report_only" && !isMessageOnlyCodexSourceReply(params);
2097
- const nativeDelegationAvailable = delegationGuidanceAvailable && !isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow) && !shouldDisableCodexToolSearchForModel(params.modelId);
2098
- 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;
2099
- return [
2100
- "You are a personal agent running inside OpenClaw. OpenClaw has dynamic tools for OpenClaw-owned messaging, cron, sessions, media, gateway, and nodes.",
2101
- deferredToolNames.size > 0 ? `Deferred searchable OpenClaw dynamic tools available: ${[...deferredToolNames].toSorted((left, right) => left.localeCompare(right)).join(", ")}.` : void 0,
2102
- deferredToolDiscoveryGuidance,
2103
- hasSkillWorkshop ? buildSkillWorkshopPromptSection().join("\n") : void 0,
2104
- 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,
2105
- 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,
2106
- delegationGuidanceAvailable ? buildDelegationGuidanceSection({
2107
- mode: resolveMainSessionDelegationMode({
2108
- config: params.config,
2109
- agentId: params.agentId,
2110
- sessionKey: params.sessionKey
2111
- }),
2112
- isMinimal: params.promptMode === "minimal" || params.promptMode === "none",
2113
- hiddenDelegationTool: nativeDelegationAvailable ? "native `spawn_agent`" : hasSessionsSpawn ? "`sessions_spawn`" : "",
2114
- hasVisibleSessionSpawn: hasSessionsSpawn,
2115
- hasSessionsYield,
2116
- hasSubagentsList,
2117
- hasSessionsSend
2118
- }).join("\n") : void 0,
2119
- params.disableTools !== true && params.promptMode !== "minimal" && params.promptMode !== "none" ? buildUiPresentationPrompt({
2120
- showWidgetToolName,
2121
- dashboardToolName,
2122
- portalToolName,
2123
- messageTool
2124
- }) : void 0,
2125
- buildCredentialSafetyPrompt({ controlToolsAvailable: params.disableTools !== true && hasControlTools }),
2126
- nativeCommandGuidance,
2127
- params.gitCoauthorPrompt,
2128
- params.extraSystemPrompt
2129
- ].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;
2130
560
  }
2131
- //#endregion
2132
- //#region extensions/codex/src/app-server/thread-shell-environment.ts
2133
- /** Applies host-selected values and any required login-shell restriction last. */
2134
- function applyCodexManagedShellEnvironment(config, environment, disableLoginShell = false) {
2135
- if (!environment || Object.keys(environment).length === 0) return disableLoginShell ? {
2136
- ...config,
2137
- allow_login_shell: false
2138
- } : config;
2139
- const current = isJsonObject(config.shell_environment_policy) ? config.shell_environment_policy : {};
2140
- const currentSet = isJsonObject(current.set) ? current.set : {};
2141
- const names = Object.keys(environment).toSorted();
2142
- const includeOnly = Array.isArray(current.include_only) ? current.include_only.filter((entry) => typeof entry === "string") : [];
2143
- const filters = isJsonObject(current.filters) ? current.filters : void 0;
2144
- const hasIncludeFilter = filters && Object.values(filters).includes("include");
2145
- const managedConfig = {
2146
- ...config,
2147
- shell_environment_policy: {
2148
- ...current,
2149
- experimental_use_profile: false,
2150
- set: {
2151
- ...currentSet,
2152
- ...environment
2153
- },
2154
- ...filters ? hasIncludeFilter ? { filters: {
2155
- ...filters,
2156
- ...Object.fromEntries(names.map((name) => [name, "include"]))
2157
- } } : {} : 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);
2158
574
  }
2159
- };
2160
- return disableLoginShell ? {
2161
- ...managedConfig,
2162
- allow_login_shell: false
2163
- } : managedConfig;
2164
- }
2165
- //#endregion
2166
- //#region extensions/codex/src/app-server/web-search.ts
2167
- const CODEX_NATIVE_WEB_SEARCH_DISABLED_CONFIG = {
2168
- "features.standalone_web_search": false,
2169
- web_search: "disabled"
2170
- };
2171
- function normalizeUniqueStrings(value) {
2172
- if (!Array.isArray(value)) return;
2173
- const normalized = [...new Set(value.map(normalizeOptionalString).filter((entry) => Boolean(entry)))];
2174
- return normalized.length > 0 ? normalized : void 0;
2175
- }
2176
- function hasManagedSearchProvider(config) {
2177
- return normalizeOptionalString(config?.tools?.web?.search?.provider) !== void 0;
2178
- }
2179
- function hasNativeDomainRestrictions(config) {
2180
- return normalizeUniqueStrings(config?.tools?.web?.search?.openaiCodex?.allowedDomains) !== void 0;
2181
- }
2182
- function buildCodexNativeWebSearchThreadConfig(config) {
2183
- const nativeConfig = config?.tools?.web?.search?.openaiCodex;
2184
- const threadConfig = {
2185
- "features.standalone_web_search": false,
2186
- web_search: nativeConfig?.mode === "live" ? "live" : "cached"
2187
- };
2188
- const allowedDomains = normalizeUniqueStrings(nativeConfig?.allowedDomains);
2189
- if (allowedDomains) threadConfig["tools.web_search.allowed_domains"] = allowedDomains;
2190
- if (nativeConfig?.contextSize) threadConfig["tools.web_search.context_size"] = nativeConfig.contextSize;
2191
- const location = nativeConfig?.userLocation;
2192
- const country = normalizeOptionalString(location?.country);
2193
- const region = normalizeOptionalString(location?.region);
2194
- const city = normalizeOptionalString(location?.city);
2195
- const timezone = normalizeOptionalString(location?.timezone);
2196
- if (country) threadConfig["tools.web_search.location.country"] = country;
2197
- if (region) threadConfig["tools.web_search.location.region"] = region;
2198
- if (city) threadConfig["tools.web_search.location.city"] = city;
2199
- if (timezone) threadConfig["tools.web_search.location.timezone"] = timezone;
2200
- return threadConfig;
2201
- }
2202
- function resolveCodexWebSearchPlan(params) {
2203
- if (params.disableTools === true || params.webSearchAllowed === false || params.config?.tools?.web?.search?.enabled === false) return {
2204
- kind: "disabled",
2205
- suppressManagedWebSearch: true,
2206
- threadConfig: CODEX_NATIVE_WEB_SEARCH_DISABLED_CONFIG
2207
- };
2208
- const nativeConfig = params.config?.tools?.web?.search?.openaiCodex;
2209
- const managedSearchExplicit = hasManagedSearchProvider(params.config) || nativeConfig?.enabled === false;
2210
- const nativeProviderSupportsSearch = params.nativeProviderWebSearchSupport === void 0 || params.nativeProviderWebSearchSupport === "supported";
2211
- if (!(params.nativeToolSurfaceEnabled !== false && nativeProviderSupportsSearch && nativeConfig?.enabled !== false && !hasManagedSearchProvider(params.config))) {
2212
- if (!managedSearchExplicit && hasNativeDomainRestrictions(params.config)) return {
2213
- kind: "disabled",
2214
- suppressManagedWebSearch: true,
2215
- threadConfig: CODEX_NATIVE_WEB_SEARCH_DISABLED_CONFIG
2216
- };
2217
- return {
2218
- kind: "managed",
2219
- suppressManagedWebSearch: false,
2220
- threadConfig: CODEX_NATIVE_WEB_SEARCH_DISABLED_CONFIG
2221
- };
2222
- }
2223
- return {
2224
- kind: "native-hosted",
2225
- suppressManagedWebSearch: true,
2226
- threadConfig: buildCodexNativeWebSearchThreadConfig(params.config),
2227
- webFetchHostnameAllowlist: buildHostnameAllowlistPolicyFromSuffixAllowlist(nativeConfig?.allowedDomains)?.hostnameAllowlist
2228
- };
2229
- }
2230
- const CODEX_CODE_MODE_THREAD_CONFIG = {
2231
- "features.code_mode": true,
2232
- "features.code_mode_only": false,
2233
- "features.shell_tool": true,
2234
- "features.apply_patch_streaming_events": true,
2235
- suppress_unstable_features_warning: true
2236
- };
2237
- const CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG = { "features.goals": false };
2238
- const CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG = { "tools.update_plan.enabled": false };
2239
- const CODEX_CODE_MODE_DISABLED_THREAD_CONFIG = {
2240
- "features.code_mode": false,
2241
- "features.code_mode_only": false
2242
- };
2243
- const CODEX_NO_PROJECT_DOCS_CONFIG = { project_doc_max_bytes: 0 };
2244
- const CODEX_TOOL_SEARCH_UNSUPPORTED_THREAD_CONFIG = { "features.multi_agent": false };
2245
- const CODEX_DELEGATION_DISABLED_THREAD_CONFIG = {
2246
- "agents.enabled": false,
2247
- "features.multi_agent": false,
2248
- "features.multi_agent_v2": false
2249
- };
2250
- const CODEX_RING_ZERO_RESTRICTED_FEATURES = /* @__PURE__ */ new Set([
2251
- "apps",
2252
- "artifact",
2253
- "browser_use",
2254
- "browser_use_external",
2255
- "browser_use_full_cdp_access",
2256
- "chronicle",
2257
- "code_mode",
2258
- "code_mode_only",
2259
- "computer_use",
2260
- "context_management",
2261
- "current_time_reminder",
2262
- "default_mode_request_user_input",
2263
- "deferred_executor",
2264
- "goals",
2265
- "hooks",
2266
- "image_generation",
2267
- "memories",
2268
- "multi_agent",
2269
- "multi_agent_v2",
2270
- "plugins",
2271
- "request_permissions_tool",
2272
- "skill_search",
2273
- "shell_tool",
2274
- "standalone_web_search",
2275
- "token_budget",
2276
- "unified_exec",
2277
- "view_image",
2278
- "web_search_cached",
2279
- "web_search_request",
2280
- "workspace_dependencies"
2281
- ]);
2282
- const CODEX_RING_ZERO_THREAD_CONFIG = {
2283
- ...CODEX_DELEGATION_DISABLED_THREAD_CONFIG,
2284
- ...Object.fromEntries([...CODEX_RING_ZERO_RESTRICTED_FEATURES].map((feature) => [`features.${feature}`, false])),
2285
- "orchestrator.mcp.enabled": false,
2286
- "orchestrator.skills.enabled": false,
2287
- "skills.bundled.enabled": false,
2288
- "skills.include_instructions": false,
2289
- "tools.experimental_request_user_input.enabled": false,
2290
- hooks: {
2291
- PreToolUse: [],
2292
- PermissionRequest: [],
2293
- PostToolUse: [],
2294
- PreCompact: [],
2295
- PostCompact: [],
2296
- SessionStart: [],
2297
- UserPromptSubmit: [],
2298
- SubagentStart: [],
2299
- SubagentStop: [],
2300
- Stop: []
2301
- },
2302
- notify: [],
2303
- web_search: "disabled"
2304
- };
2305
- const CODEX_RING_ZERO_RESTRICTED_FEATURE_ALIASES = /* @__PURE__ */ new Map([
2306
- ["connectors", "apps"],
2307
- ["imagegenext", "image_generation"],
2308
- ["collab", "multi_agent"],
2309
- ["memory_tool", "memories"],
2310
- ["telepathy", "chronicle"],
2311
- ["codex_hooks", "hooks"]
2312
- ]);
2313
- /** Common deterministic start/resume/fork fields; no run resources or unsupported setters. */
2314
- function buildCodexThreadConfiguration(params, options) {
2315
- return {
2316
- ...options.cwd !== void 0 ? { cwd: options.cwd } : {},
2317
- ...options.appServer.sessionRoot ? { runtimeWorkspaceRoots: [options.appServer.sessionRoot] } : {},
2318
- approvalPolicy: options.appServer.approvalPolicy,
2319
- approvalsReviewer: resolveCodexThreadApprovalsReviewer(options.appServer, options.config),
2320
- ...codexThreadSandboxOrPermissions(options.appServer),
2321
- ...options.appServer.serviceTier !== void 0 ? { serviceTier: options.appServer.serviceTier } : {},
2322
- config: buildCodexRuntimeThreadConfigForRun(params, options.config, {
2323
- nativeCodeModeEnabled: options.nativeCodeModeEnabled,
2324
- nativeProviderWebSearchSupport: options.nativeProviderWebSearchSupport,
2325
- nativeCodeModeOnlyEnabled: options.nativeCodeModeOnlyEnabled,
2326
- directOnlyToolNamespaces: resolveDirectOnlyToolNamespaces(options.dynamicTools),
2327
- webSearchAllowed: options.webSearchAllowed,
2328
- appServer: options.appServer,
2329
- hostSystemAgentActive: options.hostSystemAgentActive,
2330
- restrictedToolSurfaceInheritedMcpServerNames: options.restrictedToolSurfaceInheritedMcpServerNames,
2331
- shellEnvironment: options.shellEnvironment,
2332
- disableLoginShell: options.disableLoginShell
2333
- }),
2334
- developerInstructions: options.developerInstructions ?? buildDeveloperInstructions(params, { dynamicTools: options.dynamicTools })
2335
- };
2336
- }
2337
- function buildThreadStartParams(params, options) {
2338
- const resolvedModelProvider = resolveCodexAppServerModelProvider({
2339
- provider: params.provider,
2340
- authProfileId: params.authProfileId,
2341
- authProfileStore: params.authProfileStore,
2342
- agentDir: params.agentDir,
2343
- config: params.config
2344
- });
2345
- const modelSelection = resolveCodexAppServerRequestModelSelection({
2346
- model: options.model ?? params.modelId,
2347
- modelProvider: options.modelProvider ?? resolvedModelProvider,
2348
- authProfileId: params.authProfileId,
2349
- authProfileStore: params.authProfileStore,
2350
- agentDir: params.agentDir,
2351
- config: params.config
2352
- });
2353
- return {
2354
- model: modelSelection.model,
2355
- ...modelSelection.modelProvider ? { modelProvider: modelSelection.modelProvider } : {},
2356
- ...buildCodexThreadConfiguration(params, options),
2357
- ...(options.hostSystemAgentActive ?? isHostScopedAgentToolActive("openclaw")) && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow) ? { baseInstructions: "" } : {},
2358
- personality: CODEX_NATIVE_PERSONALITY_NONE,
2359
- serviceName: "OpenClaw",
2360
- ...resolveCodexThreadEnvironmentSelection(options),
2361
- dynamicTools: [...options.dynamicTools],
2362
- experimentalRawEvents: true,
2363
- ...isIncognitoSessionKey(params.sessionKey) ? { ephemeral: true } : {}
2364
- };
2365
- }
2366
- function buildThreadResumeParams(params, options) {
2367
- const modelSelection = options.preserveNativeModel ? void 0 : resolveCodexAppServerRequestModelSelection({
2368
- model: options.model ?? params.modelId,
2369
- modelProvider: options.modelProvider ?? resolveCodexAppServerModelProvider({
2370
- provider: params.provider,
2371
- authProfileId: options.authProfileId ?? params.authProfileId,
2372
- authProfileStore: params.authProfileStore,
2373
- agentDir: params.agentDir,
2374
- config: params.config
2375
- }),
2376
- authProfileId: options.authProfileId ?? params.authProfileId,
2377
- authProfileStore: params.authProfileStore,
2378
- agentDir: params.agentDir,
2379
- config: params.config
2380
- });
2381
- return {
2382
- threadId: options.threadId,
2383
- excludeTurns: true,
2384
- initialTurnsPage: {
2385
- limit: 1,
2386
- sortDirection: "desc",
2387
- itemsView: "notLoaded"
2388
- },
2389
- ...modelSelection ? {
2390
- model: modelSelection.model,
2391
- ...modelSelection.modelProvider ? { modelProvider: modelSelection.modelProvider } : {}
2392
- } : {},
2393
- ...buildCodexThreadConfiguration(params, options),
2394
- personality: CODEX_NATIVE_PERSONALITY_NONE
2395
- };
2396
- }
2397
- function buildCodexRuntimeThreadConfig(config, options = {}) {
2398
- const configured = buildCodexProjectDocThreadConfig(config);
2399
- const codeModeConfig = {
2400
- ...CODEX_CODE_MODE_THREAD_CONFIG,
2401
- "features.code_mode_only": options.nativeCodeModeOnlyEnabled === true
2402
- };
2403
- if (options.nativeCodeModeEnabled === false) {
2404
- 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");
2405
- delete disabledConfig["features.apply_patch_streaming_events"];
2406
- return disabledConfig;
575
+ else if (metadata?.linkId) approvalMode = normalizeAppToolApprovalMode(asOptionalRecord(links?.[metadata.linkId])?.default_tools_approval_mode) ?? approvalMode;
2407
576
  }
2408
- 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);
2409
- 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);
2410
- }
2411
- function ensureDirectOnlyToolNamespaces(config, requiredNamespaces) {
2412
- if (!requiredNamespaces?.length) return config;
2413
- const feature = expectDefined(config["features.code_mode"], "Codex code mode config");
2414
- const configured = isJsonObject(feature) ? feature : { enabled: feature };
2415
- const namespaces = Array.isArray(configured.direct_only_tool_namespaces) ? configured.direct_only_tool_namespaces.filter((entry) => typeof entry === "string" && entry.length > 0) : [];
2416
- return {
2417
- ...config,
2418
- "features.code_mode": {
2419
- ...configured,
2420
- direct_only_tool_namespaces: [.../* @__PURE__ */ new Set([...namespaces, ...requiredNamespaces])]
2421
- }
2422
- };
2423
- }
2424
- function resolveDirectOnlyToolNamespaces(dynamicTools) {
2425
- return (dynamicTools ?? []).filter((tool) => tool.type === "namespace" && tool.name === "openclaw_direct").map((tool) => tool.name);
2426
- }
2427
- function buildCodexRuntimeThreadConfigForRun(params, config, options = {}) {
2428
- const ringZeroActive = (options.hostSystemAgentActive ?? isHostScopedAgentToolActive("openclaw")) && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow);
2429
- const messageOnlySourceReply = isMessageOnlyCodexSourceReply(params);
2430
- const restrictedToolSurface = ringZeroActive || messageOnlySourceReply || params.pluginHarnessToolPolicyRestricted === true;
2431
- const restrictedTurnDisablesProjectDocs = ringZeroActive || messageOnlySourceReply || params.pluginHarnessToolPolicyRestricted && params.disableTools;
2432
- const configMcpServers = config?.mcp_servers;
2433
- if (restrictedToolSurface && configMcpServers !== void 0 && !isJsonObject(configMcpServers)) throw new Error("Codex restricted tool surface received invalid thread mcp_servers config");
2434
- const restrictedToolSurfaceMcpServerNames = [...options.restrictedToolSurfaceInheritedMcpServerNames ?? [], ...isJsonObject(configMcpServers) ? Object.keys(configMcpServers) : []];
2435
- const webSearchConfig = resolveCodexWebSearchPlan({
2436
- config: params.config,
2437
- disableTools: params.disableTools,
2438
- nativeToolSurfaceEnabled: options.nativeCodeModeEnabled,
2439
- nativeProviderWebSearchSupport: options.nativeProviderWebSearchSupport,
2440
- webSearchAllowed: options.webSearchAllowed
2441
- }).threadConfig;
2442
- const baseConfig = buildCodexRuntimeThreadConfig(mergeCodexThreadConfigs(config, webSearchConfig), options);
2443
- return applyCodexManagedShellEnvironment({
2444
- ...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,
2445
- ...params.bootstrapContextMode === "lightweight" ? CODEX_NO_PROJECT_DOCS_CONFIG : {}
2446
- }, options.shellEnvironment, options.disableLoginShell);
2447
- }
2448
- function buildCodexRingZeroThreadConfigPatch(params, hostSystemAgentActive = isHostScopedAgentToolActive("openclaw"), inheritedMcpServerNames = []) {
2449
- if (!hostSystemAgentActive || !isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow)) return;
2450
- return {
2451
- ...buildRestrictedToolConfigPatch(inheritedMcpServerNames),
2452
- ...CODEX_NO_PROJECT_DOCS_CONFIG
2453
- };
2454
- }
2455
- function buildRestrictedToolConfigPatch(inheritedMcpServerNames, scheduledAppAuthorityActive = false) {
2456
- const mcpServers = Object.fromEntries([...new Set(inheritedMcpServerNames)].toSorted().map((name) => [name, { enabled: false }]));
577
+ const defaultToolsEnabled = app?.default_tools_enabled;
2457
578
  return {
2458
- ...CODEX_RING_ZERO_THREAD_CONFIG,
2459
- ...scheduledAppAuthorityActive ? {
2460
- "features.apps": true,
2461
- "orchestrator.mcp.enabled": true
2462
- } : {},
2463
- ...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
2464
584
  };
2465
585
  }
2466
- async function readCodexInheritedMcpServerNames(client, cwd, signal, effectiveConfig) {
2467
- const response = effectiveConfig ?? await readCodexEffectiveConfig(client, cwd, { signal });
2468
- if (!Array.isArray(response.layers)) throw new Error("Codex config/read omitted effective config layers");
2469
- for (const layer of response.layers) {
2470
- if (!isJsonObject(layer) || !isJsonObject(layer.name) || typeof layer.name.type !== "string") throw new Error("Codex config/read returned invalid effective config layers");
2471
- if (layer.name.type === "legacyManagedConfigTomlFromFile" || layer.name.type === "legacyManagedConfigTomlFromMdm") {
2472
- 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";
2473
- throw new Error(`Codex restricted tool surface cannot override config layer ${layer.name.type}; ${migrationGuidance}.`);
2474
- }
2475
- 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}`);
2476
- }
2477
- const configuredServers = response.config.mcp_servers;
2478
- if (configuredServers === void 0) return [];
2479
- if (!isJsonObject(configuredServers)) throw new Error("Codex config/read returned invalid mcp_servers");
2480
- return Object.keys(configuredServers).toSorted();
2481
- }
2482
- async function assertCodexManagedRequirementsDoNotOverrideToolPolicy(client, options, signal) {
2483
- const requirements = await readCodexManagedRequirements(client, signal);
2484
- const managedRequirementsFingerprint = buildCodexManagedRequirementsFingerprint(requirements);
2485
- const managedRequirementsMatch = options.allowedManagedRequirementsFingerprint !== void 0 && managedRequirementsFingerprint === options.allowedManagedRequirementsFingerprint;
2486
- const managedHooksAllowed = managedRequirementsMatch || options.allowConfiguredManagedHooks === true;
2487
- 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");
2488
- if (requirements === null) return;
2489
- if (options.restrictedToolSurface) for (const key of [
2490
- "hooks",
2491
- "managedHooks",
2492
- "managed_hooks"
2493
- ]) {
2494
- const hooks = requirements[key];
2495
- if (hooks === void 0 || hooks === null) continue;
2496
- if (!isJsonObject(hooks)) throw new Error("Codex configRequirements/read returned invalid managed hooks");
2497
- if (hasNonEmptyJsonValue(hooks) && !managedHooksAllowed) throw new Error("Codex restricted tool surface cannot override managed hooks");
2498
- }
2499
- const additionalDeniedFeatures = new Set(options.additionalDeniedFeatures);
2500
- for (const key of ["featureRequirements", "feature_requirements"]) {
2501
- const featureRequirements = requirements[key];
2502
- if (featureRequirements === void 0 || featureRequirements === null) continue;
2503
- if (!isJsonObject(featureRequirements)) throw new Error("Codex configRequirements/read returned invalid feature requirements");
2504
- for (const [feature, enabled] of Object.entries(featureRequirements)) {
2505
- if (typeof enabled !== "boolean") throw new Error("Codex configRequirements/read returned invalid feature requirements");
2506
- const canonicalFeature = CODEX_RING_ZERO_RESTRICTED_FEATURE_ALIASES.get(feature) ?? feature;
2507
- 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.");
2508
- const deniedByToolPolicy = options.restrictedToolSurface && CODEX_RING_ZERO_RESTRICTED_FEATURES.has(canonicalFeature) || additionalDeniedFeatures.has(canonicalFeature);
2509
- if (canonicalFeature === "hooks" && managedHooksAllowed) continue;
2510
- if (enabled && deniedByToolPolicy) throw new Error(`Codex tool policy cannot override required feature ${feature}`);
2511
- }
2512
- }
2513
- }
2514
- /** Hashes the exact managed requirements without retaining their hook commands or policy details. */
2515
- function buildCodexManagedRequirementsFingerprint(requirements) {
2516
- const fingerprint = fingerprintJsonObject({
2517
- version: 1,
2518
- requirements
2519
- });
2520
- return crypto.createHash("sha256").update(fingerprint).digest("hex");
2521
- }
2522
- /** Reads and fingerprints the exact managed requirements active on this app-server. */
2523
- async function readCodexManagedRequirementsFingerprint(client, signal) {
2524
- return buildCodexManagedRequirementsFingerprint(await readCodexManagedRequirements(client, signal));
2525
- }
2526
- async function readCodexManagedRequirements(client, signal) {
2527
- const response = await client.request("configRequirements/read", void 0, { signal });
2528
- if (!isJsonObject(response) || !Object.hasOwn(response, "requirements")) throw new Error("Codex configRequirements/read returned an invalid response");
2529
- if (response.requirements !== null && !isJsonObject(response.requirements)) throw new Error("Codex configRequirements/read returned invalid requirements");
2530
- return response.requirements;
2531
- }
2532
- function hasNonEmptyJsonValue(value) {
2533
- if (value === null || value === false || value === "") return false;
2534
- if (Array.isArray(value)) return value.length > 0;
2535
- if (typeof value === "object") return Object.values(value).some(hasNonEmptyJsonValue);
2536
- return true;
2537
- }
2538
- function resolveCodexThreadApprovalsReviewer(appServer, config) {
2539
- return config?.approvals_reviewer === "user" ? "user" : appServer.approvalsReviewer;
2540
- }
2541
- function codexThreadSandboxOrPermissions(appServer) {
2542
- if (appServer.networkProxy) return {};
2543
- return { sandbox: appServer.sandbox };
586
+ function appToolHintsAllowed(tool, policy) {
587
+ return (policy.allowDestructiveActions || tool?.destructiveHint === false) && (policy.allowOpenWorld !== false || tool?.openWorldHint === false);
2544
588
  }
2545
- function resolveCodexThreadEnvironmentSelection(options) {
2546
- if (options.nativeCodeModeEnabled === false) return { environments: [] };
2547
- if (options.environmentSelection) return { environments: options.environmentSelection };
2548
- 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";
2549
595
  }
2550
596
  //#endregion
2551
597
  //#region extensions/codex/src/app-server/scheduled-app-authority.ts
@@ -2585,9 +631,6 @@ function resolveScheduledCodexAppCreatorCaptureDecision(params) {
2585
631
  function normalizeApprovalMode(value) {
2586
632
  return value === "allow" || value === "deny" || value === "auto" || value === "ask" ? value : void 0;
2587
633
  }
2588
- function normalizeAppToolApprovalMode(value) {
2589
- return value === "auto" || value === "prompt" || value === "writes" || value === "approve" ? value : void 0;
2590
- }
2591
634
  function defaultApprovalMode(entry) {
2592
635
  return entry.destructiveApprovalMode ?? (entry.allowDestructiveActions ? "allow" : "deny");
2593
636
  }
@@ -2658,9 +701,12 @@ async function readCodexScheduledAppToolsByApp(params) {
2658
701
  if (connectorId) {
2659
702
  const tools = toolsByApp.get(connectorId) ?? /* @__PURE__ */ new Map();
2660
703
  const metadata = asOptionalRecord(tool);
704
+ const appMetadata = asOptionalRecord(metadata?._meta);
2661
705
  const annotations = asOptionalRecord(metadata?.annotations);
2662
706
  tools.set(toolName, {
2663
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,
2664
710
  destructiveHint: annotations?.destructiveHint === false ? false : void 0,
2665
711
  openWorldHint: annotations?.openWorldHint === false ? false : void 0
2666
712
  });
@@ -2688,24 +734,6 @@ async function readCurrentCodexScheduledAppPolicy(params) {
2688
734
  toolsByApp
2689
735
  };
2690
736
  }
2691
- function readCurrentToolPolicy(config, appId, toolName, metadata, fallbackApprovalMode = "auto") {
2692
- const apps = asOptionalRecord(config.apps);
2693
- const app = asOptionalRecord(apps?.[appId]);
2694
- const defaults = asOptionalRecord(apps?.["_default"]);
2695
- const tools = asOptionalRecord(app?.tools);
2696
- const tool = asOptionalRecord(tools?.[toolName] ?? (metadata?.title !== void 0 ? tools?.[metadata.title] : void 0));
2697
- const defaultToolsEnabled = app?.default_tools_enabled;
2698
- return {
2699
- enabled: (app ? app.enabled !== false : defaults?.enabled !== false) && (typeof tool?.enabled === "boolean" ? tool.enabled : typeof defaultToolsEnabled === "boolean" ? defaultToolsEnabled : appToolHintsAllowed(metadata, {
2700
- allowDestructiveActions: (app?.destructive_enabled ?? defaults?.destructive_enabled) !== false,
2701
- allowOpenWorld: (app?.open_world_enabled ?? defaults?.open_world_enabled) !== false
2702
- })),
2703
- approvalMode: normalizeAppToolApprovalMode(tool?.approval_mode) ?? normalizeAppToolApprovalMode(app?.default_tools_approval_mode) ?? normalizeAppToolApprovalMode(defaults?.default_tools_approval_mode) ?? fallbackApprovalMode
2704
- };
2705
- }
2706
- function appToolHintsAllowed(tool, policy) {
2707
- return (policy.allowDestructiveActions || tool?.destructiveHint === false) && (policy.allowOpenWorld !== false || tool?.openWorldHint === false);
2708
- }
2709
737
  /** Captures only apps callable on the exact active Codex client/thread. */
2710
738
  async function captureScheduledCodexAppAuthority(params) {
2711
739
  const requestedTimeoutMs = params.timeoutMs ?? CODEX_APP_AUTHORITY_CAPTURE_TIMEOUT_MS;
@@ -2788,13 +816,6 @@ const APPROVAL_RANK = {
2788
816
  function stricterApprovalMode(left, right) {
2789
817
  return APPROVAL_RANK[left] <= APPROVAL_RANK[right] ? left : right;
2790
818
  }
2791
- function intersectToolApprovalMode(captured, current) {
2792
- if (captured === current) return captured;
2793
- if (captured === "prompt" || current === "prompt") return "prompt";
2794
- if (captured === "approve") return current;
2795
- if (current === "approve") return captured;
2796
- return "prompt";
2797
- }
2798
819
  function appApprovalCeiling(mode) {
2799
820
  if (mode === "allow") return "approve";
2800
821
  return mode === "ask" ? "prompt" : "auto";
@@ -2827,7 +848,8 @@ function intersectCodexPluginThreadConfigWithScheduledAuthority(config, authorit
2827
848
  destructiveApprovalMode: stricterApprovalMode(defaultApprovalMode(current), captured.destructiveApprovalMode)
2828
849
  };
2829
850
  }
2830
- 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);
2831
853
  const configPatch = disableUnlistedCodexApps(buildCodexPluginAppsConfigPatchFromPolicyContext(policyContext), currentPolicy.config);
2832
854
  const appsPatch = asOptionalRecord(configPatch.apps);
2833
855
  for (const [appId, captured] of capturedById) {
@@ -2981,13 +1003,14 @@ async function prepareCodexThreadLifecyclePreflight(params) {
2981
1003
  const legacyDynamicToolsFingerprint = lifecycleTiming.measureSync("legacy-dynamic-tools-fingerprint", () => codexLegacyDynamicToolsFingerprint(params.dynamicTools));
2982
1004
  const dynamicToolsFingerprint = lifecycleTiming.measureSync("dynamic-tools-fingerprint", () => hashCodexAppServerBindingFingerprint(legacyDynamicToolsFingerprint));
2983
1005
  const dynamicToolsContainDeferred = flattenCodexDynamicToolFunctions(params.dynamicTools).some((tool) => tool.deferLoading === true);
2984
- const webSearchThreadConfigFingerprint = fingerprintJsonObject(lifecycleTiming.measureSync("web-search-plan", () => resolveCodexWebSearchPlan({
1006
+ const webSearchPlan = lifecycleTiming.measureSync("web-search-plan", () => resolveCodexWebSearchPlan({
2985
1007
  config: params.params.config,
2986
1008
  disableTools: params.params.disableTools,
2987
1009
  nativeToolSurfaceEnabled: params.nativeCodeModeEnabled,
2988
1010
  nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
2989
1011
  webSearchAllowed: params.webSearchAllowed
2990
- })).threadConfig);
1012
+ }));
1013
+ const webSearchThreadConfigFingerprint = fingerprintJsonObject(webSearchPlan.threadConfig);
2991
1014
  const networkProxyConfigFingerprint = params.appServer.networkProxy?.configFingerprint;
2992
1015
  const contextEngineBinding = lifecycleTiming.measureSync("context-engine-binding", () => buildContextEngineBinding(params.params, params.contextEngineProjection));
2993
1016
  const userMcpServersConfigPatch = params.userMcpServersEnabled === false ? void 0 : await buildCodexUserMcpServersThreadConfigPatchForRun({
@@ -3003,7 +1026,7 @@ async function prepareCodexThreadLifecyclePreflight(params) {
3003
1026
  });
3004
1027
  const nativeSkillIsolation = await lifecycleTiming.measure("native-skill-isolation", () => resolveCodexNativeSkillIsolation({
3005
1028
  client: params.client,
3006
- codexHome: params.appServer.start.env?.CODEX_HOME,
1029
+ codexHome: params.appServer.start.codexHome ?? params.appServer.start.env?.CODEX_HOME,
3007
1030
  cwd: params.cwd,
3008
1031
  home: params.appServer.start.env?.HOME,
3009
1032
  signal: params.signal,
@@ -3085,8 +1108,14 @@ async function resumeExistingCodexThread(params, context) {
3085
1108
  disposeConfiguration = configuration.dispose;
3086
1109
  await context.releaseRetainedThread(configuration.assertCurrent);
3087
1110
  configuration.assertCurrent();
1111
+ const clientBoundThread = ringZeroClientInstanceId !== void 0 || resumeBinding.ringZeroClientInstanceId !== void 0 || resumeBinding.ringZeroConfigFingerprint !== void 0 || context.ringZeroActive;
1112
+ const sharedEntry = getCurrentSharedClientEntry(params.client);
1113
+ if (configuration.settledSystemError && !clientBoundThread && resumeBinding.connectionScope !== "supervision" && (!sharedEntry || sharedEntry.activeLeases <= 1 && sharedEntry.pendingAcquires === 0) && !hasCodexAppServerSiblingThreadWork(params.client, resumeBinding.threadId) && !hasCodexAppServerSiblingRouteWork(params.client, resumeBinding.threadId)) {
1114
+ await abandonClient();
1115
+ throw new CodexThreadClientReplacementError();
1116
+ }
3088
1117
  const authProfileId = resumeBinding.connectionScope === "supervision" ? void 0 : params.params.authProfileId ?? resumeBinding.authProfileId;
3089
- const finalConfigPatch = context.prebuiltFinalConfigPatch ?? params.buildFinalConfigPatch?.({
1118
+ const finalConfigPatch = context.prebuiltFinalConfigPatch ?? await params.buildFinalConfigPatch?.({
3090
1119
  action: "resume",
3091
1120
  binding: resumeBinding
3092
1121
  }) ?? {
@@ -3163,6 +1192,7 @@ async function resumeExistingCodexThread(params, context) {
3163
1192
  const resumePatch = {
3164
1193
  clientId: resolveCodexAppServerClientInstanceId(params.client),
3165
1194
  pendingResumeConfiguration: void 0,
1195
+ ...resumeBinding.agentWorkspaceDeveloperInstructions === void 0 && params.agentWorkspaceDeveloperInstructions !== void 0 ? { agentWorkspaceDeveloperInstructions: params.agentWorkspaceDeveloperInstructions } : {},
3166
1196
  cwd: params.cwd,
3167
1197
  rolloutPath: resolveCodexThreadRolloutPath(response.thread) ?? resumeBinding.rolloutPath,
3168
1198
  authProfileId,
@@ -3261,7 +1291,7 @@ async function startFreshCodexThread(params, context) {
3261
1291
  const clientId = resolveCodexAppServerClientInstanceId(params.client);
3262
1292
  const { bindingIdentity, startModelSelection, startModelProvider, userMcpServersConfigPatch, dynamicToolsFingerprint, dynamicToolsContainDeferred, webSearchThreadConfigFingerprint, nativeSkillIsolationFingerprint, userMcpServersFingerprint, ringZeroConfigFingerprint, ringZeroClientInstanceId, networkProxyConfigFingerprint, contextEngineBinding, environmentSelectionFingerprint, hostSystemAgentActive, restrictedToolSurface, restrictedToolSurfaceInheritedMcpServerNames, nativeSkillIsolation, lifecycleTiming, normalizeBindingModelProvider, throwIfAborted, prebuiltPluginThreadConfig, preserveExistingBinding, rotatedContextEngineBinding, replacementPredecessor } = context;
3263
1293
  const pluginThreadConfig = params.pluginThreadConfig?.enabled ? prebuiltPluginThreadConfig ?? await lifecycleTiming.measure("plugin-config-build", () => params.pluginThreadConfig?.build()) : void 0;
3264
- const finalConfigPatch = params.buildFinalConfigPatch?.({ action: "start" }) ?? {
1294
+ const finalConfigPatch = await params.buildFinalConfigPatch?.({ action: "start" }) ?? {
3265
1295
  configPatch: params.finalConfigPatch,
3266
1296
  nativeHookRelayGeneration: params.nativeHookRelayGeneration
3267
1297
  };
@@ -3496,7 +1526,7 @@ async function tryReuseCodexLiveThread(options) {
3496
1526
  const incognito = isIncognitoSessionKey(params.params.sessionKey);
3497
1527
  if (incognito && (binding.preserveNativeModel || binding.connectionScope === "supervision")) {
3498
1528
  if (binding.clientId === clientId && binding.clientId && ((await options.buildLoadedPluginThreadConfig(binding))?.fingerprint ?? binding.pluginAppsFingerprint) === binding.pluginAppsFingerprint) {
3499
- params.buildFinalConfigPatch?.({
1529
+ await params.buildFinalConfigPatch?.({
3500
1530
  action: "resume",
3501
1531
  binding
3502
1532
  });
@@ -3511,7 +1541,7 @@ async function tryReuseCodexLiveThread(options) {
3511
1541
  }
3512
1542
  return { kind: "rotate" };
3513
1543
  }
3514
- 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" };
3515
1545
  const retainedThread = await consumeCodexAppServerLiveThread(params.client, binding.threadId);
3516
1546
  if (!retainedThread) return { kind: "resume" };
3517
1547
  const assertWarmOwner = () => {
@@ -3527,12 +1557,27 @@ async function tryReuseCodexLiveThread(options) {
3527
1557
  };
3528
1558
  let ownershipTransferred = false;
3529
1559
  let preserveSubscription = false;
1560
+ let nativeThread;
3530
1561
  try {
3531
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
+ }
3532
1577
  const pluginThreadConfig = await options.buildLoadedPluginThreadConfig(binding);
3533
1578
  assertWarmOwner();
3534
1579
  if (pluginThreadConfig && pluginThreadConfig.fingerprint !== binding.pluginAppsFingerprint) return { kind: "rotate" };
3535
- const prebuiltFinalConfigPatch = params.buildFinalConfigPatch?.({
1580
+ const prebuiltFinalConfigPatch = await params.buildFinalConfigPatch?.({
3536
1581
  action: "resume",
3537
1582
  binding
3538
1583
  }) ?? {
@@ -3540,7 +1585,7 @@ async function tryReuseCodexLiveThread(options) {
3540
1585
  nativeHookRelayGeneration: params.nativeHookRelayGeneration
3541
1586
  };
3542
1587
  const pluginAppsConfigPatch = pluginThreadConfig?.configPatch ?? (params.pluginThreadConfig?.enabled && binding.pluginAppPolicyContext ? buildCodexPluginAppsConfigPatchFromPolicyContext(binding.pluginAppPolicyContext) : void 0);
3543
- const resumeAuthProfileId = params.params.authProfileId ?? binding.authProfileId;
1588
+ const resumeAuthProfileId = binding.connectionScope === "supervision" ? void 0 : params.params.authProfileId ?? binding.authProfileId;
3544
1589
  const resumeConfig = mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginAppsConfigPatch, prebuiltFinalConfigPatch.configPatch);
3545
1590
  const resumeParams = lifecycleTiming.measureSync("warm-thread-resume-params", () => buildThreadResumeParams(params.params, {
3546
1591
  threadId: binding.threadId,
@@ -3548,7 +1593,7 @@ async function tryReuseCodexLiveThread(options) {
3548
1593
  authProfileId: resumeAuthProfileId,
3549
1594
  model: startModelSelection.model,
3550
1595
  modelProvider: startModelProvider,
3551
- preserveNativeModel: false,
1596
+ preserveNativeModel: binding.preserveNativeModel === true,
3552
1597
  appServer: params.appServer,
3553
1598
  dynamicTools: params.dynamicTools,
3554
1599
  developerInstructions: params.developerInstructions,
@@ -3564,10 +1609,10 @@ async function tryReuseCodexLiveThread(options) {
3564
1609
  }));
3565
1610
  const liveThreadConfigFingerprint = incognito ? retainedThread.configFingerprint : fingerprintCodexThreadConfig({
3566
1611
  ...resumeParams,
3567
- model: binding.model ?? resumeParams.model ?? null,
3568
- requestedModel: resumeParams.model ?? null,
3569
- modelProvider: binding.modelProvider ?? resumeParams.modelProvider ?? null,
3570
- 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
3571
1616
  }, resumeAuthProfileId, dynamicToolsFingerprint);
3572
1617
  if (incognito && retainedThread.ephemeralPolicy !== resumeParams.developerInstructions) {
3573
1618
  preserveSubscription = true;
@@ -3592,13 +1637,15 @@ async function tryReuseCodexLiveThread(options) {
3592
1637
  });
3593
1638
  assertWarmOwner();
3594
1639
  const nativeHookRelayGeneration = prebuiltFinalConfigPatch.nativeHookRelayGeneration ?? binding.nativeHookRelayGeneration;
3595
- 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;
3596
1642
  if (!(incognito || await lifecycleTiming.measure("warm-thread-write-binding", () => params.bindingStore.mutate(bindingIdentity, {
3597
1643
  kind: "patch",
3598
1644
  threadId: binding.threadId,
3599
1645
  patch: {
3600
1646
  cwd: params.cwd,
3601
1647
  model,
1648
+ modelProvider,
3602
1649
  nativeHookRelayGeneration,
3603
1650
  environmentSelectionFingerprint
3604
1651
  }
@@ -3620,6 +1667,7 @@ async function tryReuseCodexLiveThread(options) {
3620
1667
  ...!incognito ? {
3621
1668
  cwd: params.cwd,
3622
1669
  model,
1670
+ modelProvider,
3623
1671
  nativeHookRelayGeneration,
3624
1672
  environmentSelectionFingerprint
3625
1673
  } : {},
@@ -3634,6 +1682,12 @@ async function tryReuseCodexLiveThread(options) {
3634
1682
  if (!ownershipTransferred) {
3635
1683
  let failure;
3636
1684
  try {
1685
+ if (preserveSubscription) try {
1686
+ assertWarmOwner();
1687
+ preserveSubscription = isSameCodexAppServerThreadOwner(params.bindingStore.read(bindingIdentity), binding);
1688
+ } catch {
1689
+ preserveSubscription = false;
1690
+ }
3637
1691
  if (preserveSubscription) {
3638
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") };
3639
1693
  } else await retainedThread.release(binding.threadId);
@@ -3651,21 +1705,6 @@ async function tryReuseCodexLiveThread(options) {
3651
1705
  }
3652
1706
  //#endregion
3653
1707
  //#region extensions/codex/src/app-server/thread-lifecycle-adoption.ts
3654
- /** Passive refusal must precede releasing or acquiring any native subscription. */
3655
- async function assertAdoptedCodexThreadResumeAllowed(params, threadId, context, assertCurrent) {
3656
- const { thread } = await context.lifecycleTiming.measure("thread-read-adoption-status", () => params.client.request("thread/read", {
3657
- threadId,
3658
- includeTurns: false
3659
- }, {
3660
- signal: params.signal,
3661
- assertCurrent
3662
- }));
3663
- context.throwIfAborted();
3664
- assertCodexThreadAcceptsDirectInput(thread);
3665
- if (thread.status?.type === "active") throw new CodexAdoptedThreadActiveError();
3666
- if (thread.id !== threadId) throw new Error("Codex returned another thread during adoption status read");
3667
- return thread;
3668
- }
3669
1708
  /** All bound preparation follows attach's native-queue-before-binding-lease order. */
3670
1709
  async function withCodexThreadLifecycleBinding(params, run) {
3671
1710
  const identity = sessionBindingIdentity({
@@ -3767,7 +1806,8 @@ async function preparePendingCodexThreadResume(params, binding, dynamicToolsFing
3767
1806
  return {
3768
1807
  assertConfigured: observation.assertConfigured,
3769
1808
  assertCurrent,
3770
- dispose
1809
+ dispose,
1810
+ settledSystemError: observation.settledSystemError
3771
1811
  };
3772
1812
  } catch (error) {
3773
1813
  dispose();
@@ -3776,7 +1816,7 @@ async function preparePendingCodexThreadResume(params, binding, dynamicToolsFing
3776
1816
  }
3777
1817
  /** Observe teardown before release; a successful resume alone can acknowledge ignored overrides. */
3778
1818
  async function prepareCodexThreadResume(params, binding, context) {
3779
- const assertClient = captureCodexAppServerClientLifetime(params.client, binding.connectionScope === "supervision" ? "connection" : "native-process");
1819
+ const assertClient = captureCodexAppServerClientLifetime(params.client, binding.connectionScope === "supervision" ? "connection" : "thread-configuration");
3780
1820
  const assertCurrent = () => {
3781
1821
  params.params.hostCapabilities.assertActive();
3782
1822
  params.assertCurrent?.();
@@ -3802,11 +1842,13 @@ function isCodexThreadNonRunning(status) {
3802
1842
  }
3803
1843
  function observeCodexThreadConfiguration(params, thread, assertCurrent) {
3804
1844
  if (!isCodexThreadNonRunning(thread.status)) throw new CodexAdoptedThreadActiveError();
1845
+ const settledSystemError = thread.status.type === "systemError";
3805
1846
  let unloaded = thread.status.type === "notLoaded";
3806
1847
  return {
3807
1848
  dispose: params.client.addNotificationHandler((notification) => {
3808
1849
  if (notification.method === "thread/status/changed" && isJsonObject(notification.params) && notification.params.threadId === thread.id && isJsonObject(notification.params.status) && notification.params.status.type === "notLoaded") unloaded = true;
3809
1850
  }),
1851
+ settledSystemError,
3810
1852
  assertConfigured: () => {
3811
1853
  assertCurrent();
3812
1854
  if (!unloaded) throw new Error("Codex did not confirm unloading its previous configuration. The thread is preserved; stop competing native work and reconnect before retrying.");
@@ -3898,10 +1940,11 @@ async function materializePendingSupervisionBranch(params) {
3898
1940
  responseModelProvider: probeResponse.modelProvider,
3899
1941
  responseThreadModelProvider: probeResponse.thread.modelProvider
3900
1942
  });
3901
- const startParams = buildThreadStartParams({
1943
+ const nativeAttempt = {
3902
1944
  ...params.attempt,
3903
1945
  modelId: nativeModel
3904
- }, {
1946
+ };
1947
+ const startParams = buildThreadStartParams(nativeAttempt, {
3905
1948
  cwd: params.cwd,
3906
1949
  dynamicTools: params.dynamicTools,
3907
1950
  appServer: params.appServer,
@@ -4247,7 +2290,7 @@ async function startOrResumeThread(input) {
4247
2290
  await releaseRetainedThread(binding.threadId);
4248
2291
  const pendingBinding = binding;
4249
2292
  const pluginThreadConfig = params.pluginThreadConfig?.enabled ? await lifecycleTiming.measure("plugin-config-build", () => params.pluginThreadConfig?.build()) : void 0;
4250
- const finalConfigPatch = params.buildFinalConfigPatch?.({ action: "start" }) ?? {
2293
+ const finalConfigPatch = await params.buildFinalConfigPatch?.({ action: "start" }) ?? {
4251
2294
  configPatch: params.finalConfigPatch,
4252
2295
  nativeHookRelayGeneration: params.nativeHookRelayGeneration
4253
2296
  };
@@ -4557,57 +2600,30 @@ async function startOrResumeThread(input) {
4557
2600
  });
4558
2601
  }
4559
2602
  //#endregion
4560
- //#region extensions/codex/src/app-server/reasoning-effort.ts
4561
- const CODEX_REASONING_EFFORTS = [
4562
- "minimal",
4563
- "low",
4564
- "medium",
4565
- "high",
4566
- "xhigh",
4567
- "max"
4568
- ];
4569
- const LEGACY_PRO_REASONING_EFFORTS = [
4570
- "medium",
4571
- "high",
4572
- "xhigh"
4573
- ];
4574
- const LEGACY_PRO_MODEL_ID_RE = /^gpt-5\.[45]-pro$/u;
4575
- const MODERN_GPT_5_MODEL_ID_RE = /^gpt-5\.(?:[3-9]|[1-9]\d)(?:$|-)/u;
4576
- /** Read reasoning metadata after the Codex app-server route has been selected. */
4577
- function readCodexSupportedReasoningEfforts(compat) {
4578
- if (!compat || typeof compat !== "object" || Array.isArray(compat)) return;
4579
- const efforts = compat.supportedReasoningEfforts;
4580
- if (!Array.isArray(efforts)) return;
4581
- return efforts.filter((effort) => typeof effort === "string");
4582
- }
4583
- function resolveSupportedReasoningEffort(params) {
4584
- const declared = new Set(params.supportedReasoningEfforts.map((effort) => effort.trim().toLowerCase()));
4585
- const supported = CODEX_REASONING_EFFORTS.filter((effort) => declared.has(effort));
4586
- if (supported.includes(params.requested)) return params.requested;
4587
- const requestedRank = CODEX_REASONING_EFFORTS.indexOf(params.requested);
4588
- return supported.find((effort) => CODEX_REASONING_EFFORTS.indexOf(effort) >= requestedRank) ?? supported.at(-1);
4589
- }
4590
- function resolveCodexAppServerReasoningEffort(params) {
4591
- if (params.thinkLevel === "ultra") return "ultra";
4592
- if (params.thinkLevel === "off") return params.supportedReasoningEfforts?.includes("none") ? "none" : null;
4593
- if (params.thinkLevel === "adaptive") return null;
4594
- if (params.supportedReasoningEfforts) return resolveSupportedReasoningEffort({
4595
- requested: params.thinkLevel,
4596
- supportedReasoningEfforts: params.supportedReasoningEfforts
4597
- }) ?? null;
4598
- const modelId = params.modelId.trim().toLowerCase();
4599
- if (LEGACY_PRO_MODEL_ID_RE.test(modelId)) return resolveSupportedReasoningEffort({
4600
- requested: params.thinkLevel,
4601
- supportedReasoningEfforts: LEGACY_PRO_REASONING_EFFORTS
4602
- }) ?? null;
4603
- if (params.thinkLevel === "minimal" && MODERN_GPT_5_MODEL_ID_RE.test(modelId)) return "low";
4604
- if (params.thinkLevel === "minimal" || params.thinkLevel === "low" || params.thinkLevel === "medium" || params.thinkLevel === "high" || params.thinkLevel === "xhigh") return params.thinkLevel;
4605
- return null;
4606
- }
4607
- //#endregion
4608
2603
  //#region extensions/codex/src/app-server/user-input.ts
2604
+ function prependHistoryProvenance(input, historyProvenancePrefix) {
2605
+ if (!historyProvenancePrefix) return input;
2606
+ const firstTextIndex = input.findIndex((item) => item.type === "text");
2607
+ if (firstTextIndex === -1) return [{
2608
+ type: "text",
2609
+ text: historyProvenancePrefix,
2610
+ text_elements: []
2611
+ }, ...input];
2612
+ return input.map((item, index) => index === firstTextIndex && item.type === "text" ? {
2613
+ ...item,
2614
+ text: `${historyProvenancePrefix}${item.text}`
2615
+ } : item);
2616
+ }
4609
2617
  /** Builds ordered Codex user input for both new turns and same-turn steering. */
4610
- function buildCodexUserInput(text, images) {
2618
+ function buildCodexUserInput(text, images, contextImageGroups, historyProvenancePrefix) {
2619
+ if (text !== void 0 && contextImageGroups?.length) {
2620
+ let offset = 0;
2621
+ return prependHistoryProvenance([...contextImageGroups.flatMap((group) => {
2622
+ const parts = buildCodexUserInput(text.slice(offset, group.end), group.images);
2623
+ offset = group.end;
2624
+ return parts;
2625
+ }), ...buildCodexUserInput(text.slice(offset), images)], historyProvenancePrefix);
2626
+ }
4611
2627
  const imageInputs = (images ?? []).map((image) => {
4612
2628
  const imageUrl = sanitizeInlineImageDataUrl(`data:${image.mimeType};base64,${image.data}`);
4613
2629
  return imageUrl ? {
@@ -4619,16 +2635,16 @@ function buildCodexUserInput(text, images) {
4619
2635
  text_elements: []
4620
2636
  };
4621
2637
  });
4622
- return [...text === void 0 ? [] : [{
2638
+ return prependHistoryProvenance([...text === void 0 ? [] : [{
4623
2639
  type: "text",
4624
2640
  text,
4625
2641
  text_elements: []
4626
- }], ...imageInputs];
2642
+ }], ...imageInputs], historyProvenancePrefix);
4627
2643
  }
4628
2644
  //#endregion
4629
2645
  //#region extensions/codex/src/app-server/turn-params.ts
4630
2646
  const CODEX_CURRENT_SENDER_FIELD_MAX_CHARS = 256;
4631
- function buildCodexCurrentSenderContextValue(params) {
2647
+ function readCodexCurrentSender(params) {
4632
2648
  const metadata = asOptionalRecord(asOptionalRecord(params.userTurnTranscriptRecorder?.message)?.["__openclaw"]);
4633
2649
  const recorded = [
4634
2650
  normalizeOptionalString(metadata?.["senderId"]),
@@ -4642,11 +2658,19 @@ function buildCodexCurrentSenderContextValue(params) {
4642
2658
  ];
4643
2659
  if (!id && !name && !username) return;
4644
2660
  const bound = (value) => truncateUtf16Safe(value, CODEX_CURRENT_SENDER_FIELD_MAX_CHARS);
4645
- return JSON.stringify({ sender: {
2661
+ return {
4646
2662
  ...id ? { id: bound(id) } : {},
4647
2663
  ...name ? { name: bound(name) } : {},
4648
2664
  ...username ? { username: bound(username) } : {}
4649
- } });
2665
+ };
2666
+ }
2667
+ function buildCodexCurrentSenderContextValue(params) {
2668
+ const sender = readCodexCurrentSender(params);
2669
+ return sender ? JSON.stringify({ sender }) : void 0;
2670
+ }
2671
+ function buildCodexHistoryProvenancePrefix(params) {
2672
+ const sender = readCodexCurrentSender(params);
2673
+ return sender?.id ? neutralizeCodexExplicitMentionSigils(`[OpenClaw conversation info: sender=${JSON.stringify(sender)}]\n`) : void 0;
4650
2674
  }
4651
2675
  function buildTurnStartParams(params, options) {
4652
2676
  const modelSelection = options.preserveNativeTurnSettings ? void 0 : resolveCodexAppServerRequestModelSelection({
@@ -4669,6 +2693,10 @@ function buildTurnStartParams(params, options) {
4669
2693
  let additionalContext = buildCodexTemporalAdditionalContext(params, { sessionStatusAvailable: options.sessionStatusAvailable === true });
4670
2694
  additionalContext = {
4671
2695
  ...additionalContext,
2696
+ openclaw_active_computer: {
2697
+ kind: "application",
2698
+ value: params.hostCapabilities.activeComputerContext?.() ?? "Current active computer: active_node=unknown (host presence unavailable)"
2699
+ },
4672
2700
  openclaw_source_delivery: {
4673
2701
  kind: "application",
4674
2702
  value: ["Current source-delivery policy for this turn (replaces earlier source-delivery guidance):", buildHarnessVisibleReplyGuidance({
@@ -4694,7 +2722,8 @@ function buildTurnStartParams(params, options) {
4694
2722
  };
4695
2723
  return {
4696
2724
  threadId: options.threadId,
4697
- input: [...buildCodexUserInput(options.promptText ?? params.prompt, params.images), ...options.explicitSkillInputs ?? []],
2725
+ ...params.trigger ? { turnTrigger: params.trigger } : {},
2726
+ input: [...buildCodexUserInput(options.promptText ?? params.prompt, params.images, options.contextImageGroups, options.historyProvenancePrefix ?? (params.trigger === "user" ? buildCodexHistoryProvenancePrefix(params) : void 0)), ...options.explicitSkillInputs ?? []],
4698
2727
  ...additionalContext ? { additionalContext } : {},
4699
2728
  cwd: options.cwd,
4700
2729
  ...options.appServer.sessionRoot ? { runtimeWorkspaceRoots: [options.appServer.sessionRoot] } : {},
@@ -4758,7 +2787,7 @@ function buildDefaultCollaborationInstructions() {
4758
2787
  "",
4759
2788
  "Use the `request_user_input` tool only when it is listed in the available tools for this turn.",
4760
2789
  "",
4761
- "In Default mode, strongly prefer making reasonable assumptions and executing the user's request rather than stopping to ask questions. If you absolutely must ask a question because the answer cannot be discovered from local context and a reasonable assumption would be risky, ask the user directly with a concise plain-text question. Never write a multiple choice question as a textual assistant message."
2790
+ "In Default mode, strongly prefer making reasonable assumptions and executing the user's request rather than stopping to ask questions. When a missing preference, constraint, or clarification warrants a question, use `request_user_input_async` if it is available and continue independent work. Answers arrive as ordinary user messages. A suggested or preselected answer is not consent; wait for explicit approval before dependent actions that require it. If neither question tool is available, ask a concise plain-text question. Never write a multiple choice question as a textual assistant message."
4762
2791
  ].join("\n");
4763
2792
  }
4764
2793
  function buildCronCollaborationInstructions() {
@@ -4773,4 +2802,4 @@ function joinPresentSections(...sections) {
4773
2802
  return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
4774
2803
  }
4775
2804
  //#endregion
4776
- export { codexDynamicToolsFingerprint as $, readCodexMcpToolConnectorId as A, createCodexNativeHookRelay as B, resolveCodexWebSearchPlan as C, buildCodexPluginThreadConfigInputFingerprint as Ct, resolveCodexAppServerRequestModelSelection as D, refreshCodexPluginAppApprovalPolicy as Dt, resolveCodexAppServerModelProvider as E, mergeCodexThreadConfigs as Et, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as F, checkCodexThreadAppAvailability as G, resolveCodexNativeHookRelayEvents as H, assertCodexNativeHookRelayAllowed as I, loadCodexNativeToolCatalog as J, attestCodexRestrictedToolSurfaceMcpServersDisabled as K, buildCodexNativeHookRelayConfig as L, buildCodexProjectDocThreadConfig as M, isCodexAppServerProfilerEnabled as N, resolveCodexAppServerThreadModelSelection as O, shouldBuildCodexPluginThreadConfig as Ot, CODEX_NATIVE_HOOK_RELAY_EVENTS as P, areCodexDynamicToolFingerprintsCompatible as Q, buildCodexNativeHookRelayDisabledConfig as R, buildCodexNativeWebSearchThreadConfig as S, buildCodexPluginThreadConfig as St, CODEX_NATIVE_PERSONALITY_NONE as T, buildDisabledAppsConfigPatch as Tt, resolveCodexNativeHookRelayTtlMs as U, emitCodexNativePreToolUseFailureDiagnostic as V, scheduleCodexNativeHookRelayUnregister as W, applyCodexNativeSkillIsolation as X, parseCodexNativeToolCatalog as Y, resolveCodexNativeSkillIsolation as Z, assertCodexManagedRequirementsDoNotOverrideToolPolicy as _, neutralizeCodexExplicitMentionSigils as _t, buildCodexUserInput as a, isForcedPrivateQaCodexRuntime as at, buildCodexThreadConfiguration as b, resolveCodexContextEngineProjectionReserveTokens as bt, startOrResumeThread as c, normalizeCodexDynamicToolName as ct, buildScheduledCodexAppAuthorityInputFingerprint as d, buildContextEngineBinding as dt, codexLegacyDynamicToolsFingerprint as et, buildScheduledCodexAppServerConnectionIdentity as f, isContextEngineBindingCompatible as ft, resolveScheduledCodexAppCreatorCaptureDecision as g, isCodexDurableCustomMessage as gt, readCurrentCodexScheduledAppPolicy as h, fitCodexProjectedContextForTurnStart as ht, buildTurnStartParams as i, filterCodexDynamicToolsForDisabledNativeSurface as it, readCodexMcpToolUiVisibility as j, resolveCodexBindingModelProviderFallback as k, assertScheduledCodexAppAuthorityRuntime as l, resolveCodexDynamicToolsLoading as lt, intersectCodexPluginThreadConfigWithScheduledAuthority as m, buildCodexContinuityCalibration as mt, buildCodexTemporalAdditionalContext as n, fingerprintUserMcpServersConfigPatch as nt, readCodexSupportedReasoningEfforts as o, isMessageOnlyCodexSourceReply as ot, captureScheduledCodexAppAuthority as p, CodexContextAttachmentError as pt, hasCodexNativeToolCatalog as q, buildTurnCollaborationMode as r, filterCodexDynamicTools as rt, resolveCodexAppServerReasoningEffort as s, isSystemAgentOnlyCodexDynamicToolAllowlist as st, buildCodexParentLocalInstructions as t, fingerprintJsonObject as tt, buildLegacyScheduledCodexAppRecoveryPrompt as u, resolveCodexDynamicToolsLoadingForRuntime as ut, buildCodexRingZeroThreadConfigPatch as v, projectContextEngineAssemblyForCodex as vt, buildDeveloperInstructions as w, buildCodexPluginThreadConfigTimeoutFallback as wt, readCodexInheritedMcpServerNames as x, resolveCodexContinuityProjectionMaxChars as xt, buildCodexRuntimeThreadConfig as y, resolveCodexContextEngineProjectionMaxChars as yt, buildCodexNativeHookRelayId 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 };