@openclaw/codex 2026.9.5 → 2026.9.7

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 (174) hide show
  1. package/README.md +2 -0
  2. package/assets/icon.png +0 -0
  3. package/dist/.setup/{account-usage-runtime-C2MOIvfq.mjs → account-usage-runtime-DFhbh1zz.mjs} +6 -6
  4. package/dist/.setup/{apply-CJ0ZfmBG.mjs → apply-D3GcSoSa.mjs} +35 -55
  5. package/dist/.setup/{attempt-client-cleanup-BpYKdTA0.mjs → attempt-client-cleanup-DOP-cW5j.mjs} +179 -73
  6. package/dist/.setup/attempt-workspace-context-C5HigshI.mjs +164 -0
  7. package/dist/.setup/{auth-binding-DhLWa_7K.mjs → auth-binding-BLWz7stm.mjs} +14 -1
  8. package/dist/.setup/{auth-cache-key-QirmgiCo.mjs → auth-cache-key-Dbvq-QgB.mjs} +41 -111
  9. package/dist/.setup/{auth-profile-WqZtZfXN.mjs → auth-profile-B0okYl2D.mjs} +1 -2
  10. package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
  11. package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
  12. package/dist/.setup/auth-start-options-BPIPeEX8.mjs +44 -0
  13. package/dist/.setup/{binding-connection-Bm38niE8.mjs → binding-connection-DTtN1KrX.mjs} +2 -2
  14. package/dist/.setup/{binding-connection.runtime-CnRMC0ta.mjs → binding-connection.runtime-6TpgD1M6.mjs} +5 -5
  15. package/dist/.setup/{bounded-turn-BtlZcivC.mjs → bounded-turn-CbjoN2OW.mjs} +140 -37
  16. package/dist/.setup/bounded-turn-isolation-B8K_ylqk.mjs +14 -0
  17. package/dist/.setup/{build-state-Xx9ybZqa.mjs → build-state-Da1_z0kd.mjs} +1 -1
  18. package/dist/.setup/{capabilities-_vXcZGSx.mjs → capabilities-B3WEZl4e.mjs} +2 -10
  19. package/dist/.setup/{client-vXs2929Q.mjs → client-N0JpgSzF.mjs} +635 -872
  20. package/dist/.setup/client-catalog-response-5HHLdcde.mjs +285 -0
  21. package/dist/.setup/{command-dispatch-naHIZwwF.mjs → command-dispatch-BeAoaovI.mjs} +9 -8
  22. package/dist/.setup/{command-formatters-CGEkdawF.mjs → command-formatters-R3ckE3Co.mjs} +36 -64
  23. package/dist/.setup/{command-handlers-BtAJEW1X.mjs → command-handlers-ylTMS00z.mjs} +301 -488
  24. package/dist/.setup/{command-rpc-DHFpn4le.mjs → command-rpc-CGJGUQ6Y.mjs} +40 -28
  25. package/dist/.setup/compact-C2WamavS.mjs +776 -0
  26. package/dist/.setup/{config-CedDWjM-.mjs → config-DKhXquav.mjs} +26 -28
  27. package/dist/.setup/{config-options-BsanJ8QG.mjs → config-options-CzyWLTJt.mjs} +68 -65
  28. package/dist/.setup/{config-parsing-CcB9iPoq.mjs → config-parsing-b088LyhT.mjs} +57 -60
  29. package/dist/.setup/{config-runtime-CeAhl_h4.mjs → config-runtime-C0NbLms1.mjs} +2 -2
  30. package/dist/.setup/{config-security-BRQ2mgW9.mjs → config-security-CE-FcGw9.mjs} +51 -215
  31. package/dist/.setup/{config-utils-DujwEnhg.mjs → config-utils-D0CXecki.mjs} +3 -13
  32. package/dist/.setup/context-engine-projection-PezSESth.mjs +387 -0
  33. package/dist/.setup/{conversation-binding-DhzrpTM6.mjs → conversation-binding-3Min8qvP.mjs} +71 -105
  34. package/dist/.setup/{conversation-binding-data-CrcyZk6O.mjs → conversation-binding-data-C746z5Pn.mjs} +8 -12
  35. package/dist/.setup/{conversation-control-DN53ns41.mjs → conversation-control-CEP8X5JC.mjs} +30 -69
  36. package/dist/.setup/{cyber-failover-DYwbmf1o.mjs → cyber-failover-XV0nNRZu.mjs} +1 -1
  37. package/dist/.setup/{cyber-failover-notice-e9G3J9-e.mjs → cyber-failover-notice-RNpGpTyP.mjs} +1 -1
  38. package/dist/.setup/{dynamic-tools-D16lOp67.mjs → dynamic-tools-DzlsLUuS.mjs} +3136 -3167
  39. package/dist/.setup/{effective-mcp-catalog-K6kLCN8X.mjs → effective-mcp-catalog-CxUtC-xG.mjs} +8 -17
  40. package/dist/.setup/{ephemeral-turn-R1gA8Sn6.mjs → ephemeral-turn-CDsPJOa2.mjs} +9 -6
  41. package/dist/.setup/event-projector-assistant-message-CigreO4K.mjs +69 -0
  42. package/dist/.setup/{event-projector-usage-C7Ntzs-f.mjs → event-projector-usage-03R0I2dM.mjs} +4 -26
  43. package/dist/.setup/event-projector-values-DJSz8BTk.mjs +106 -0
  44. package/dist/.setup/incognito-session-DWYapfwf.mjs +2 -0
  45. package/dist/.setup/{inference-context-fulhZuz8.mjs → inference-context-D-9gWlTR.mjs} +16 -18
  46. package/dist/.setup/inference-dispatch-CMZtjQyz.mjs +359 -0
  47. package/dist/.setup/inference-metadata-CgIf7sOx.mjs +81 -0
  48. package/dist/.setup/inference-proxy-DhcXOgUE.mjs +561 -0
  49. package/dist/.setup/{isolated-completion-B6srt48J.mjs → isolated-completion-Dm3PzxJk.mjs} +15 -11
  50. package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
  51. package/dist/.setup/{managed-binary-DP6Rib3P.mjs → managed-binary-kiWRhNRE.mjs} +16 -9
  52. package/dist/.setup/{model-catalog-DkvUuBey.mjs → model-catalog-PAuZgJC6.mjs} +14 -14
  53. package/dist/.setup/model-runtime-BdqzOMkU.mjs +11 -0
  54. package/dist/.setup/{models-BDFgm_G-.mjs → models-DHXZtVVk.mjs} +9 -18
  55. package/dist/.setup/{native-auth-BLZGqFjw.mjs → native-auth-CuG53tu4.mjs} +5 -5
  56. package/dist/.setup/{native-execution-policy-YBMHSzC4.mjs → native-execution-policy-BxZJy5mP.mjs} +6 -31
  57. package/dist/.setup/{native-subagent-monitor-B1hxzIOy.mjs → native-subagent-monitor-Dpsmf2wz.mjs} +4422 -3808
  58. package/dist/.setup/native-subagent-pending-assignments-DwkCzLvD.mjs +203 -0
  59. package/dist/.setup/native-task-assignments-DMQ0g3hu.mjs +194 -0
  60. package/dist/.setup/{node-cli-sessions-Cl8b2ZF3.mjs → node-cli-sessions-HC4W6FLI.mjs} +99 -111
  61. package/dist/.setup/node-exec-server.runtime-BgBfWQqo.mjs +244 -0
  62. package/dist/.setup/{plan-xD7WKYTM.mjs → plan-Y-QIvrKB.mjs} +118 -163
  63. package/dist/.setup/{plugin-activation-r8nq5Jzp.mjs → plugin-activation-cNHRfaxU.mjs} +10 -47
  64. package/dist/.setup/{plugin-app-cache-key-BOxKP7db.mjs → plugin-app-cache-key-BL9B5H0L.mjs} +9 -42
  65. package/dist/.setup/{plugin-inventory-DUle8DLz.mjs → plugin-inventory-Cky2XJUw.mjs} +32 -23
  66. package/dist/.setup/{plugin-marketplace-discovery-P-Vndfqq.mjs → plugin-marketplace-discovery-D_dV9FXa.mjs} +22 -25
  67. package/dist/.setup/{plugin-metadata-cache-DsS5buNa.mjs → plugin-metadata-cache-DsjsL1dr.mjs} +328 -318
  68. package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
  69. package/dist/.setup/provider-DH8NSzGt.mjs +51 -0
  70. package/dist/.setup/{provider-capabilities-B8J4Dy-O.mjs → provider-capabilities-CAxoF-X1.mjs} +35 -12
  71. package/dist/.setup/{rate-limits-DOEGYRNs.mjs → rate-limits-B7-X2TgG.mjs} +123 -166
  72. package/dist/.setup/{request-BioXJLYa.mjs → request-BHZ1nz8d.mjs} +25 -16
  73. package/dist/.setup/responses-oauth-twnuTaAa.mjs +93 -0
  74. package/dist/.setup/rpc-error-BlD2vuzn.mjs +31 -0
  75. package/dist/.setup/{run-attempt-rlA07pUv.mjs → run-attempt-D8RZUOzY.mjs} +2046 -1454
  76. package/dist/.setup/{run-attempt-lifecycle-B7JbY4-F.mjs → run-attempt-lifecycle-C-6O3Exn.mjs} +10 -24
  77. package/dist/.setup/{runtime-artifact-Dy38Z5iU.mjs → runtime-artifact-DDQ-HGXf.mjs} +43 -47
  78. package/dist/.setup/runtime-artifact-connection-D68qQn1m.mjs +78 -0
  79. package/dist/.setup/sandbox-guard-DjCz2eOw.mjs +126 -0
  80. package/dist/.setup/scope-DOC1Xjc8.mjs +6 -0
  81. package/dist/.setup/session-binding-DGCYAfvD.mjs +443 -0
  82. package/dist/.setup/{session-binding-record-TH3xA0zj.mjs → session-binding-record-Oe9L-CNY.mjs} +73 -132
  83. package/dist/.setup/{session-binding-sidecars-CKYEcfNn.mjs → session-binding-sidecars-jo6H8dFr.mjs} +242 -60
  84. package/dist/.setup/{session-catalog-fUdWDx-U.mjs → session-catalog-4sCdv5qx.mjs} +598 -452
  85. package/dist/.setup/{session-catalog-adoption-CR_whkEW.mjs → session-catalog-adoption-BU_pHWG7.mjs} +59 -26
  86. package/dist/.setup/{session-catalog-archive-CwZaPacf.mjs → session-catalog-archive-spHfihri.mjs} +7 -7
  87. package/dist/.setup/session-catalog-events-DePDzzjc.mjs +139 -0
  88. package/dist/.setup/session-catalog-home-id-vlih0B_g.mjs +22 -0
  89. package/dist/.setup/{session-catalog-index-B141u15s.mjs → session-catalog-index-CZvDzC6z.mjs} +286 -182
  90. package/dist/.setup/{session-catalog-index-order-Cc5BzlQr.mjs → session-catalog-index-order-BcQpHks3.mjs} +2 -2
  91. package/dist/.setup/{session-catalog-index-state-BAuDztHN.mjs → session-catalog-index-state-TeO7EyO-.mjs} +6 -2
  92. package/dist/.setup/session-catalog-limits-DDxOsQeC.mjs +14 -0
  93. package/dist/.setup/session-catalog-list-request-CvtxrYSe.mjs +170 -0
  94. package/dist/.setup/session-catalog-native-projection-DjhwGL6x.mjs +178 -0
  95. package/dist/.setup/{session-catalog-node-adoption-BVRsYOSh.mjs → session-catalog-node-adoption-DgXvSGu0.mjs} +30 -35
  96. package/dist/.setup/{session-catalog-node-continue-Dowv8osw.mjs → session-catalog-node-continue-DjKXHBbi.mjs} +25 -18
  97. package/dist/.setup/session-catalog-node-lookup-CtAXI5W5.mjs +56 -0
  98. package/dist/.setup/{session-catalog-native-projection-ChV3cCtm.mjs → session-catalog-parsing-CPGaPYr-.mjs} +14 -180
  99. package/dist/.setup/{session-catalog-projection-C1Bj9Jl-.mjs → session-catalog-projection-Cr5qP5Dj.mjs} +15 -5
  100. package/dist/.setup/session-catalog-provenance-DoAvktcj.mjs +95 -0
  101. package/dist/.setup/{session-cli-DIj-IE-E.mjs → session-cli-Cn_nCqfq.mjs} +11 -24
  102. package/dist/.setup/{session-history-C--SrLI8.mjs → session-history-D83lJWHG.mjs} +16 -23
  103. package/dist/.setup/{session-history-import-JHXT5Xfi.mjs → session-history-import-WhX-X33a.mjs} +7 -10
  104. package/dist/.setup/session-history-read-Ov3StuL4.mjs +133 -0
  105. package/dist/.setup/{session-history.worker-CpNj7H_P.mjs → session-history.worker-MnPKncqP.mjs} +14 -23
  106. package/dist/.setup/session-initialization-6aveB9qb.mjs +22 -0
  107. package/dist/.setup/{session-permission-policy-DhurXY0l.mjs → session-permission-policy-Ci_fVX6y.mjs} +4 -8
  108. package/dist/.setup/{session-retirement-CU87AOg9.mjs → session-retirement-qMTxkNx2.mjs} +31 -12
  109. package/dist/.setup/{settled-turn-context-fmwouT5I.mjs → settled-turn-context-D4yj4rxf.mjs} +1 -1
  110. package/dist/.setup/{settled-turn-finalizer-CiY2bLFK.mjs → settled-turn-finalizer-BsvEabkw.mjs} +17 -13
  111. package/dist/.setup/{shared-client-BpTtuLQ5.mjs → shared-client-DqyTMYug.mjs} +826 -485
  112. package/dist/.setup/shared-client-lifecycle-DJIgqgMw.mjs +153 -0
  113. package/dist/.setup/{side-question-DSCZyoBD.mjs → side-question-C4kCmQy1.mjs} +206 -334
  114. package/dist/.setup/{source-Bjp4UQij.mjs → source-CS_7GFJZ.mjs} +82 -139
  115. package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
  116. package/dist/.setup/{thread-archive-guard-jmecf6OJ.mjs → thread-archive-guard-C9frICzX.mjs} +10 -3
  117. package/dist/.setup/thread-lifecycle-DPflntEJ.mjs +2362 -0
  118. package/dist/.setup/{incognito-session-uhrBF6wJ.mjs → thread-ownership-queue-Dp24d7-F.mjs} +1 -2
  119. package/dist/.setup/{thread-ownership-skomxnIt.mjs → thread-ownership-roNP0l1c.mjs} +47 -10
  120. package/dist/.setup/thread-policy-DTd-DtkX.mjs +109 -0
  121. package/dist/.setup/thread-requests-B_bRnMGN.mjs +2102 -0
  122. package/dist/.setup/{thread-resume-BkNpj9Pz.mjs → thread-resume-CdDaoc7T.mjs} +6 -6
  123. package/dist/.setup/timeout-CXOfNoaX.mjs +46 -0
  124. package/dist/.setup/transcript-history-projection-DRSifI-1.mjs +201 -0
  125. package/dist/.setup/{transcript-mirror-attestation-CzM-94NC.mjs → transcript-mirror-attestation-YSegaktH.mjs} +3 -4
  126. package/dist/.setup/{transcript-mirror-D4qp_leP.mjs → transcript-mirror-kxmCYsuF.mjs} +224 -206
  127. package/dist/.setup/{transport-stdio-Cmx94Oiy.mjs → transport-stdio-Bdegpn2V.mjs} +138 -75
  128. package/dist/.setup/transport-websocket-BTBE-LD9.mjs +211 -0
  129. package/dist/.setup/{upstream-prompt-provenance-LphB8slG.mjs → upstream-prompt-provenance-fXkKbPVC.mjs} +3 -9
  130. package/dist/.setup/{upstream-session-fork-D3UKxgVD.mjs → upstream-session-fork-CBeVjBpT.mjs} +48 -40
  131. package/dist/.setup/{usage-BOgBEKso.mjs → usage-BMzNxeR_.mjs} +5 -4
  132. package/dist/.setup/{usage-limit-error-C0ow7DOc.mjs → usage-limit-error-QXerDo3i.mjs} +5 -20
  133. package/dist/.setup/{web-search-provider.runtime-CTGuJt6i.mjs → web-search-provider.runtime-P77OUeoo.mjs} +10 -20
  134. package/dist/api.js +25 -16
  135. package/dist/catalog-page-worker-entrypoint.js +12 -0
  136. package/dist/catalog-page.worker.js +9 -0
  137. package/dist/cli-metadata.js +1 -1
  138. package/dist/doctor-contract-api.js +50 -8
  139. package/dist/harness.js +344 -1
  140. package/dist/index.js +345 -346
  141. package/dist/media-understanding-provider.js +9 -22
  142. package/dist/migration-provider-api.js +1 -1
  143. package/dist/provider-discovery.js +1 -1
  144. package/dist/session-history-worker-runtime.js +16 -33
  145. package/dist/session-history.worker.js +1 -1
  146. package/openclaw.plugin.json +14 -2
  147. package/package.json +11 -7
  148. package/dist/.setup/attempt-context-VXVwTCfS.mjs +0 -636
  149. package/dist/.setup/compact-C3i3qlzj.mjs +0 -687
  150. package/dist/.setup/event-projector-assistant-message-DNUR1s0A.mjs +0 -105
  151. package/dist/.setup/event-projector-items-DyTQ_XqL.mjs +0 -200
  152. package/dist/.setup/harness-rxaaoN-o.mjs +0 -349
  153. package/dist/.setup/history-rejection-B4nOXNXF.mjs +0 -13
  154. package/dist/.setup/image-payload-sanitizer-tupAr-2o.mjs +0 -79
  155. package/dist/.setup/inference-proxy-CC15HuSi.mjs +0 -311
  156. package/dist/.setup/launch-args-DnMak49W.mjs +0 -111
  157. package/dist/.setup/local-runtime-attribution-B_2mnqhb.mjs +0 -19
  158. package/dist/.setup/native-subagent-history-YXaL6dMd.mjs +0 -135
  159. package/dist/.setup/native-subagent-task-ids-DsuOonKv.mjs +0 -411
  160. package/dist/.setup/node-exec-server.runtime-BaViBKNz.mjs +0 -226
  161. package/dist/.setup/plugin-approval-roundtrip-CjfzafAZ.mjs +0 -122
  162. package/dist/.setup/provider-fFh_-VR3.mjs +0 -50
  163. package/dist/.setup/rolldown-runtime-8H4AJuhK.mjs +0 -14
  164. package/dist/.setup/sandbox-guard-BBP-RbTf.mjs +0 -166
  165. package/dist/.setup/session-binding-_0W_fHRr.mjs +0 -721
  166. package/dist/.setup/session-catalog-events-jMcYfQyd.mjs +0 -250
  167. package/dist/.setup/session-history-read-B3ZfSUbF.mjs +0 -50
  168. package/dist/.setup/session-initialization-DH1z6fXn.mjs +0 -75
  169. package/dist/.setup/thread-history-page-BTx-4xsg.mjs +0 -83
  170. package/dist/.setup/thread-lifecycle-Cik28qWn.mjs +0 -4904
  171. package/dist/.setup/thread-policy-Cjs4B8xf.mjs +0 -54
  172. package/dist/.setup/timeout-DZF05XrR.mjs +0 -63
  173. package/dist/.setup/transcript-history-projection-DHNBDhCU.mjs +0 -243
  174. package/dist/.setup/version-CoqzXPgK.mjs +0 -12
@@ -0,0 +1,2362 @@
1
+ import { i as isJsonObject, r as flattenCodexDynamicToolFunctions } from "./protocol-CANUwXJ3.mjs";
2
+ import { a as matchesPendingSupervisionBranch, n as assertCodexBindingMayBeReplaced, v as sessionBindingIdentity } from "./session-binding-record-Oe9L-CNY.mjs";
3
+ import { u as stringifyCodexPolicy } from "./config-security-CE-FcGw9.mjs";
4
+ import { n as resolveCodexAppServerLocalHomeDir, t as resolveCodexAppServerHomeDir } from "./auth-start-options-BPIPeEX8.mjs";
5
+ import { d as readCodexEffectiveConfig, n as codexSandboxPolicyForTurn, s as assertCodexModelBackedReviewerEffectiveConfig, u as CODEX_SESSION_OVERRIDABLE_LAYER_TYPES } from "./config-options-CzyWLTJt.mjs";
6
+ import { i as markStartedCodexManagedThread } from "./managed-thread-store-BMqgThVL.mjs";
7
+ import { l as retainSharedCodexAppServerClientByInstanceId, n as getCurrentSharedClientEntry } from "./shared-client-lifecycle-DJIgqgMw.mjs";
8
+ import { t as withCodexAppServerThreadMutation } from "./thread-ownership-queue-Dp24d7-F.mjs";
9
+ import { t as isIncognitoSessionKey } from "./incognito-session-DWYapfwf.mjs";
10
+ import { n as CodexAppServerRpcError, r as isCodexThreadReadMissingError } from "./rpc-error-BlD2vuzn.mjs";
11
+ import { t as codexCatalogHomeId } from "./session-catalog-home-id-vlih0B_g.mjs";
12
+ import { r as withAbortableTimeout } from "./timeout-CXOfNoaX.mjs";
13
+ import { t as projectBoundedCodexThreadHistory } from "./transcript-history-projection-DRSifI-1.mjs";
14
+ import { t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-BL9B5H0L.mjs";
15
+ import { n as readCodexSessionMeta } from "./session-catalog-provenance-DoAvktcj.mjs";
16
+ import { t as assertCodexSessionRuntimeOwnership } from "./binding-connection-DTtN1KrX.mjs";
17
+ import "./config-DKhXquav.mjs";
18
+ import { i as sanitizeInlineImageDataUrl, r as invalidInlineImageText } from "./session-history-read-Ov3StuL4.mjs";
19
+ import { c as resolveCodexContextEngineProjectionMaxChars, o as neutralizeCodexExplicitMentionSigils } from "./context-engine-projection-PezSESth.mjs";
20
+ import { n as normalizeCodexAppServerBindingModelProvider } from "./auth-profile-B0okYl2D.mjs";
21
+ import { A as bindCodexInferenceThread, B as isCodexAppServerClientRuntimeLive, C as CodexThreadBindingConflictError, F as consumeCodexAppServerLiveThread, G as releaseCodexAppServerLiveThread, J as unsubscribeCodexAppServerLiveThread, M as getCodexInferenceThreadQualification, N as prepareCodexInferenceThreadConfig, Q as createCodexEphemeralThreadPolicy, S as CodexAdoptedThreadActiveError, T as CodexThreadStartRequestError, V as isCodexAppServerLiveThreadClaimed, j as getCodexInferenceThread, k as assertCodexInferenceRouteConfig, n as captureCodexAppServerClientLifetime, w as CodexThreadClientReplacementError, z as hasCodexAppServerSiblingThreadWork } from "./shared-client-DqyTMYug.mjs";
22
+ import { C as assertExactSupervisionModelSelection, D as readSupervisionResponseThreadId, O as resolveCodexThreadRolloutPath, d as isCodexAppServerRequestTimeoutError, l as isCodexAppServerOverloadError, p as resolveCodexAppServerClientInstanceId, r as getCodexAppServerClientInstanceId, v as assertCodexThreadAcceptsDirectInput, x as assertCodexThreadStartResponse, y as assertCodexThreadForkResponse } from "./client-N0JpgSzF.mjs";
23
+ 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-DOP-cW5j.mjs";
24
+ import { $ as readActiveCodexTurnIdsFromResume, B as loadCodexNativeToolCatalog, C as mergeCodexNativeProjectDocThreadConfig, E as assertCodexNativeHookRelayAllowed, F as attestCodexThreadToolSurface, G as areUserMcpServersFingerprintsCompatible, H as applyCodexNativeSkillIsolation, I as checkCodexThreadAppAvailability, J as fingerprintCodexThreadConfig, K as codexDynamicToolsFingerprint, L as discardUnattestedCodexPluginThread, Q as legacyFingerprintUserMcpServersConfigPatch, R as attestCodexRestrictedToolSurfaceMcpServersDisabled, St as mergeCodexThreadConfigs, T as CodexManagedHooksOnlyError, Tt as buildCodexAppApprovalOverrides, U as resolveCodexNativeSkillIsolation, W as areCodexDynamicToolFingerprintsCompatible, X as fingerprintJsonObject, Y as fingerprintEnvironmentSelection, Z as fingerprintUserMcpServersConfigPatch, _ as resolveCodexAppServerModelProvider, at as shouldRotateCodexGpt56MultiAgentBinding, bt as disableUnlistedCodexApps, c as codexThreadSandboxOrPermissions, d as resolveCodexThreadApprovalsReviewer, et as shouldStartTransientNoToolThread, g as CODEX_NATIVE_PERSONALITY_NONE, h as buildDeveloperInstructions, i as buildCodexRuntimeThreadConfigForRun, it as shouldRotateCodexAppServerBindingForRuntime, l as readCodexInheritedMcpServerNames, lt as isMessageOnlyCodexSourceReply, m as mergeCodexNativeShellEnvironment, mt as buildCodexPluginAppsConfigPatchFromPolicyContext, n as buildCodexRingZeroThreadConfigPatch, nt as isTransientWebSearchRestriction, o as buildThreadResumeParams, p as resolveCodexWebSearchPlan, q as codexLegacyDynamicToolsFingerprint, rt as shouldRecheckRecoverablePluginBinding, s as buildThreadStartParams, t as assertCodexManagedRequirementsDoNotOverrideToolPolicy, u as readCodexManagedRequirementsFingerprint, ut as isSystemAgentOnlyCodexDynamicToolAllowlist, v as resolveCodexAppServerRequestModelSelection, x as joinPresentSections, xt as isCodexPluginThreadBindingStale, y as resolveCodexAppServerThreadModelSelection, yt as buildPluginAppPolicyContext, z as hasCodexNativeToolCatalog } from "./thread-requests-B_bRnMGN.mjs";
25
+ import { o as resolveCodexSessionBinding, r as hashCodexAppServerBindingFingerprint } from "./session-binding-DGCYAfvD.mjs";
26
+ import { a as refreshCodexThreadPolicy, i as assertCodexSupervisionThreadLineage, n as CodexThreadPolicyHandoffError, o as refreshCodexThreadSkillsCatalog, r as assertAdoptedCodexThreadResumeAllowed, t as CodexIncognitoPolicyChangeError } from "./thread-policy-DTd-DtkX.mjs";
27
+ import { t as resumeCodexAppServerThread } from "./thread-resume-CdDaoc7T.mjs";
28
+ import { c as withExclusiveCodexAppServerThread, r as retainCodexAppServerBindingSubscription, t as isSameCodexAppServerThreadOwner } from "./thread-ownership-roNP0l1c.mjs";
29
+ import "./transcript-mirror-kxmCYsuF.mjs";
30
+ import { asOptionalRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
31
+ import crypto from "node:crypto";
32
+ import { isDeepStrictEqual } from "node:util";
33
+ import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
34
+ import path from "node:path";
35
+ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
36
+ import { createStageTimingTracker, formatStageTimings } from "openclaw/plugin-sdk/time-runtime";
37
+ import { resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
38
+ import { AgentHarnessPreflightError, buildHarnessVisibleReplyGuidance, buildTemporalContextText, embeddedAgentLog, formatErrorMessage, isActiveHarnessContextEngine, isHostScopedAgentToolActive } from "openclaw/plugin-sdk/agent-harness-runtime";
39
+ import { selectSupportedReasoningEffort } from "openclaw/plugin-sdk/agent-harness-attempt-runtime";
40
+ import { buildCodexUserMcpServersThreadConfigPatchForRun } from "openclaw/plugin-sdk/codex-mcp-projection";
41
+ import { isDiagnosticFlagEnabled } from "openclaw/plugin-sdk/diagnostic-flags";
42
+ //#region extensions/codex/src/app-server/reasoning-effort.ts
43
+ const CODEX_REASONING_EFFORTS = [
44
+ "minimal",
45
+ "low",
46
+ "medium",
47
+ "high",
48
+ "xhigh",
49
+ "max"
50
+ ];
51
+ const LEGACY_PRO_REASONING_EFFORTS = [
52
+ "medium",
53
+ "high",
54
+ "xhigh"
55
+ ];
56
+ const LEGACY_PRO_MODEL_ID_RE = /^gpt-5\.[45]-pro$/u;
57
+ const MODERN_GPT_5_MODEL_ID_RE = /^gpt-5\.(?:[3-9]|[1-9]\d)(?:$|-)/u;
58
+ /** Read reasoning metadata after the Codex app-server route has been selected. */
59
+ function readCodexSupportedReasoningEfforts(compat) {
60
+ return compat && "supportedReasoningEfforts" in compat ? compat.supportedReasoningEfforts : void 0;
61
+ }
62
+ function resolveCodexAppServerReasoningEffort(params) {
63
+ if (params.thinkLevel === "ultra") return "ultra";
64
+ if (params.thinkLevel === "off") return params.supportedReasoningEfforts?.includes("none") ? "none" : null;
65
+ if (params.thinkLevel === "adaptive") return null;
66
+ const modelId = params.modelId.trim().toLowerCase();
67
+ const supportedReasoningEfforts = params.supportedReasoningEfforts ?? (LEGACY_PRO_MODEL_ID_RE.test(modelId) ? LEGACY_PRO_REASONING_EFFORTS : void 0);
68
+ if (supportedReasoningEfforts) return selectSupportedReasoningEffort({
69
+ requested: params.thinkLevel,
70
+ supportedEfforts: supportedReasoningEfforts.map((effort) => effort.trim().toLowerCase()),
71
+ effortOrder: CODEX_REASONING_EFFORTS
72
+ }) ?? null;
73
+ if (params.thinkLevel === "minimal" && MODERN_GPT_5_MODEL_ID_RE.test(modelId)) return "low";
74
+ return params.thinkLevel === "max" ? null : params.thinkLevel;
75
+ }
76
+ //#endregion
77
+ //#region extensions/codex/src/app-server/thread-context-engine.ts
78
+ function buildContextEngineBinding(params, projection) {
79
+ const contextEngine = isActiveHarnessContextEngine(params.contextEngine) ? params.contextEngine : void 0;
80
+ const engineId = contextEngine?.info?.id?.trim();
81
+ if (!contextEngine || !engineId) return;
82
+ return {
83
+ schemaVersion: 1,
84
+ engineId,
85
+ policyFingerprint: JSON.stringify({
86
+ schemaVersion: 1,
87
+ engineId,
88
+ engineVersion: contextEngine.info.version,
89
+ ownsCompaction: contextEngine.info.ownsCompaction === true,
90
+ turnMaintenanceMode: contextEngine.info.turnMaintenanceMode,
91
+ citationsMode: params.config?.memory?.citations,
92
+ contextTokenBudget: params.contextTokenBudget,
93
+ projectionMaxChars: resolveCodexContextEngineProjectionMaxChars({ contextTokenBudget: params.contextTokenBudget })
94
+ }),
95
+ projection: projection ? {
96
+ schemaVersion: 1,
97
+ mode: "thread_bootstrap",
98
+ epoch: projection.epoch,
99
+ fingerprint: projection.fingerprint
100
+ } : void 0
101
+ };
102
+ }
103
+ function isContextEngineBindingCompatible(previous, next) {
104
+ return previous?.schemaVersion === next.schemaVersion && previous.engineId === next.engineId && previous.policyFingerprint === next.policyFingerprint && areContextEngineProjectionBindingsCompatible(previous.projection, next.projection);
105
+ }
106
+ function areContextEngineProjectionBindingsCompatible(previous, next) {
107
+ if (!next) return previous === void 0;
108
+ return previous?.schemaVersion === next.schemaVersion && previous.mode === next.mode && previous.epoch === next.epoch && previous.fingerprint === next.fingerprint;
109
+ }
110
+ //#endregion
111
+ //#region extensions/codex/src/app-server/native-model-input-tools.ts
112
+ /** Stock native hooks flatten the configured V2 namespace without a delimiter. */
113
+ function resolveCodexNativeModelInputTools(config) {
114
+ const features = isJsonObject(config.features) ? config.features : void 0;
115
+ const multiAgent = isJsonObject(features?.multi_agent_v2) ? features.multi_agent_v2 : void 0;
116
+ const namespace = typeof multiAgent?.tool_namespace === "string" ? multiAgent.tool_namespace.trim() : "collaboration";
117
+ return [
118
+ "multi_agent_v1send_input",
119
+ "send_message",
120
+ "followup_task",
121
+ ...namespace ? [`${namespace}send_message`, `${namespace}followup_task`] : []
122
+ ];
123
+ }
124
+ //#endregion
125
+ //#region extensions/codex/src/app-server/profiler-flag.ts
126
+ const PROFILER_FLAGS = ["profiler", "codex.profiler"];
127
+ function isCodexAppServerProfilerEnabled(config, env = process.env) {
128
+ return PROFILER_FLAGS.some((flag) => isDiagnosticFlagEnabled(flag, config, env));
129
+ }
130
+ //#endregion
131
+ //#region extensions/codex/src/app-server/mcp-tool-metadata.ts
132
+ /** Hosted app ownership is authoritative only on metadata supplied by Codex. */
133
+ function readCodexMcpToolConnectorId(tool) {
134
+ const metadata = asOptionalRecord(asOptionalRecord(tool)?.["_meta"]);
135
+ return normalizeOptionalString(metadata?.connector_id) ?? normalizeOptionalString(metadata?.connectorId);
136
+ }
137
+ /** Preserve MCP App visibility so model-only tools cannot become widget authority. */
138
+ function readCodexMcpToolUiVisibility(tool) {
139
+ const metadata = asOptionalRecord(asOptionalRecord(tool)?.["_meta"]);
140
+ const visibility = asOptionalRecord(metadata?.ui)?.visibility;
141
+ if (!Array.isArray(visibility)) return;
142
+ return [...new Set(visibility.filter((value) => value === "app" || value === "model"))].toSorted();
143
+ }
144
+ //#endregion
145
+ //#region extensions/codex/src/app-server/scheduled-app-tool-policy.ts
146
+ function normalizeAppToolApprovalMode(value) {
147
+ return value === "auto" || value === "prompt" || value === "writes" || value === "approve" ? value : void 0;
148
+ }
149
+ function readCurrentToolPolicy(config, appId, toolName, metadata, fallbackApprovalMode = "auto") {
150
+ const apps = asOptionalRecord(config.apps);
151
+ const app = asOptionalRecord(apps?.[appId]);
152
+ const defaults = asOptionalRecord(apps?.["_default"]);
153
+ const tools = asOptionalRecord(app?.tools);
154
+ const tool = asOptionalRecord(tools?.[toolName] ?? (metadata?.title !== void 0 ? tools?.[metadata.title] : void 0));
155
+ const toolApprovalMode = normalizeAppToolApprovalMode(tool?.approval_mode);
156
+ let approvalMode = toolApprovalMode ?? normalizeAppToolApprovalMode(app?.default_tools_approval_mode) ?? normalizeAppToolApprovalMode(defaults?.default_tools_approval_mode) ?? fallbackApprovalMode;
157
+ if (!toolApprovalMode) {
158
+ const links = asOptionalRecord(app?.links);
159
+ if (metadata?.requiresExplicitLinkId) for (const link of Object.values(links ?? {})) {
160
+ const linkMode = normalizeAppToolApprovalMode(asOptionalRecord(link)?.default_tools_approval_mode);
161
+ if (linkMode) approvalMode = intersectToolApprovalMode(approvalMode, linkMode);
162
+ }
163
+ else if (metadata?.linkId) approvalMode = normalizeAppToolApprovalMode(asOptionalRecord(links?.[metadata.linkId])?.default_tools_approval_mode) ?? approvalMode;
164
+ }
165
+ const defaultToolsEnabled = app?.default_tools_enabled;
166
+ return {
167
+ enabled: (app ? app.enabled !== false : defaults?.enabled !== false) && (typeof tool?.enabled === "boolean" ? tool.enabled : typeof defaultToolsEnabled === "boolean" ? defaultToolsEnabled : appToolHintsAllowed(metadata, {
168
+ allowDestructiveActions: (app?.destructive_enabled ?? defaults?.destructive_enabled) !== false,
169
+ allowOpenWorld: (app?.open_world_enabled ?? defaults?.open_world_enabled) !== false
170
+ })),
171
+ approvalMode
172
+ };
173
+ }
174
+ function appToolHintsAllowed(tool, policy) {
175
+ return (policy.allowDestructiveActions || tool?.destructiveHint === false) && (policy.allowOpenWorld !== false || tool?.openWorldHint === false);
176
+ }
177
+ function intersectToolApprovalMode(captured, current) {
178
+ if (captured === current) return captured;
179
+ if (captured === "prompt" || current === "prompt") return "prompt";
180
+ if (captured === "approve") return current;
181
+ if (current === "approve") return captured;
182
+ return "prompt";
183
+ }
184
+ //#endregion
185
+ //#region extensions/codex/src/app-server/scheduled-app-authority.ts
186
+ const CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE = "codex.apps";
187
+ const CODEX_APPS_MCP_SERVER = "codex_apps";
188
+ const MCP_STATUS_PAGE_SIZE = 100;
189
+ const MCP_STATUS_MAX_PAGES = 100;
190
+ const CODEX_APP_AUTHORITY_CAPTURE_TIMEOUT_MS = 6e4;
191
+ const CODEX_APP_AUTHORITY_CAPTURE_MIN_TIMEOUT_MS = 100;
192
+ /** Hashes stable configured endpoint identity without retaining credentials or endpoint details. */
193
+ function buildScheduledCodexAppServerConnectionIdentity(appServer) {
194
+ const start = appServer.start;
195
+ return crypto.createHash("sha256").update("openclaw:codex:scheduled-app-server:v1\0").update(JSON.stringify({
196
+ transport: start.transport,
197
+ command: start.command,
198
+ commandSource: start.commandSource ?? null,
199
+ args: start.args,
200
+ cwd: start.cwd ?? null,
201
+ url: start.url ?? null,
202
+ homeScope: start.homeScope ?? null,
203
+ connectionClass: appServer.connectionClass,
204
+ remoteWorkspaceRoot: appServer.remoteWorkspaceRoot ?? null
205
+ })).digest("hex");
206
+ }
207
+ function resolveScheduledCodexAppCreatorCaptureDecision(params) {
208
+ if (!params.appsMayBeVisible) return {
209
+ required: false,
210
+ supported: false
211
+ };
212
+ const unavailableReason = params.authenticatedScheduledMode ? "A scheduled Codex continuation cannot create new app-authorized automations. Recreate it from a fresh authenticated owner turn; no automation changes were saved." : params.usesSupervisionConnection ? "Codex apps are visible through a supervised connection that cannot capture creator authority. Use an isolated prepared-profile Codex creator turn; no automation changes were saved." : params.homeScope === "user" ? "Codex apps are visible through a user-home runtime that cannot capture isolated creator authority. Use an agent-scoped prepared-profile Codex creator turn; no automation changes were saved." : !params.hasPreparedAccountIdentity && !params.hasConfiguredAppServerIdentity ? "Codex app authority requires either a prepared ChatGPT profile or an isolated configured app-server identity. Reauthenticate the selected Codex profile or configured app-server, then retry; no automation changes were saved." : void 0;
213
+ return {
214
+ required: true,
215
+ supported: !unavailableReason,
216
+ ...unavailableReason ? { unavailableReason } : {}
217
+ };
218
+ }
219
+ function normalizeApprovalMode(value) {
220
+ return value === "allow" || value === "deny" || value === "auto" || value === "ask" ? value : void 0;
221
+ }
222
+ function defaultApprovalMode(entry) {
223
+ return entry.destructiveApprovalMode ?? (entry.allowDestructiveActions ? "allow" : "deny");
224
+ }
225
+ function parseScheduledCodexAppAuthority(authority) {
226
+ if (!authority || authority.runtimeId !== "codex") return;
227
+ if (authority.version !== 1) throw new Error("Unsupported Codex scheduled authority version; reauthorize this automation.");
228
+ if (authority.namespace !== CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE) throw new Error(`Unsupported Codex scheduled authority namespace ${authority.namespace}; reauthorize this automation.`);
229
+ const payload = asOptionalRecord(authority.payload);
230
+ const auth = asOptionalRecord(payload?.auth);
231
+ const profileId = normalizeOptionalString(auth?.profileId);
232
+ const connectionFingerprint = normalizeOptionalString(auth?.connectionFingerprint);
233
+ const managedRequirementsFingerprint = normalizeOptionalString(auth?.managedRequirementsFingerprint);
234
+ const accountId = normalizeOptionalString(auth?.accountId);
235
+ const parsedAuth = auth?.kind === "configured-app-server" && connectionFingerprint && managedRequirementsFingerprint ? {
236
+ kind: "configured-app-server",
237
+ connectionFingerprint,
238
+ managedRequirementsFingerprint
239
+ } : auth?.kind === void 0 && profileId && accountId ? {
240
+ profileId,
241
+ accountId
242
+ } : void 0;
243
+ if (payload?.version !== 1 || !parsedAuth || !Array.isArray(payload.apps)) throw new Error("Stored Codex app authority is invalid; reauthorize this automation.");
244
+ const seen = /* @__PURE__ */ new Set();
245
+ return {
246
+ version: 1,
247
+ auth: parsedAuth,
248
+ apps: payload.apps.map((raw) => {
249
+ const app = asOptionalRecord(raw);
250
+ const id = normalizeOptionalString(app?.id);
251
+ const destructiveApprovalMode = normalizeApprovalMode(app?.destructiveApprovalMode);
252
+ const rawTools = asOptionalRecord(app?.tools);
253
+ if (!id || seen.has(id) || typeof app?.allowDestructiveActions !== "boolean" || typeof app.allowOpenWorld !== "boolean" || !destructiveApprovalMode || !rawTools) throw new Error("Stored Codex app authority is invalid; reauthorize this automation.");
254
+ seen.add(id);
255
+ const tools = {};
256
+ for (const [name, rawMode] of Object.entries(rawTools)) {
257
+ const toolName = normalizeOptionalString(name);
258
+ const mode = normalizeAppToolApprovalMode(rawMode);
259
+ if (!toolName || !mode) throw new Error("Stored Codex app authority is invalid; reauthorize this automation.");
260
+ tools[toolName] = mode;
261
+ }
262
+ return {
263
+ id,
264
+ allowDestructiveActions: app.allowDestructiveActions,
265
+ allowOpenWorld: app.allowOpenWorld,
266
+ destructiveApprovalMode,
267
+ tools
268
+ };
269
+ })
270
+ };
271
+ }
272
+ async function readCodexScheduledAppToolsByApp(params) {
273
+ const toolsByApp = /* @__PURE__ */ new Map();
274
+ const seenCursors = /* @__PURE__ */ new Set();
275
+ let cursor;
276
+ for (let page = 0; page < MCP_STATUS_MAX_PAGES; page += 1) {
277
+ const response = await params.request("mcpServerStatus/list", {
278
+ ...params.threadId ? { threadId: params.threadId } : {},
279
+ detail: "toolsAndAuthOnly",
280
+ limit: MCP_STATUS_PAGE_SIZE,
281
+ ...cursor ? { cursor } : {}
282
+ });
283
+ if (!isJsonObject(response) || !Array.isArray(response.data)) throw new Error("Codex mcpServerStatus/list returned invalid scheduled app inventory");
284
+ for (const status of response.data) {
285
+ if (!isJsonObject(status) || !isJsonObject(status.tools)) throw new Error("Codex scheduled app inventory contained an invalid server status");
286
+ if (status.name !== CODEX_APPS_MCP_SERVER) continue;
287
+ for (const [toolName, tool] of Object.entries(status.tools)) {
288
+ const connectorId = readCodexMcpToolConnectorId(tool);
289
+ if (connectorId) {
290
+ const tools = toolsByApp.get(connectorId) ?? /* @__PURE__ */ new Map();
291
+ const metadata = asOptionalRecord(tool);
292
+ const appMetadata = asOptionalRecord(metadata?._meta);
293
+ const annotations = asOptionalRecord(metadata?.annotations);
294
+ tools.set(toolName, {
295
+ title: typeof metadata?.title === "string" ? metadata.title : void 0,
296
+ linkId: typeof appMetadata?.link_id === "string" && appMetadata.link_id.trim() ? appMetadata.link_id : void 0,
297
+ requiresExplicitLinkId: asOptionalRecord(appMetadata?.["_codex_apps"])?.requires_explicit_link_id === true,
298
+ destructiveHint: annotations?.destructiveHint === false ? false : void 0,
299
+ openWorldHint: annotations?.openWorldHint === false ? false : void 0
300
+ });
301
+ toolsByApp.set(connectorId, tools);
302
+ }
303
+ }
304
+ }
305
+ if (response.nextCursor !== void 0 && response.nextCursor !== null && typeof response.nextCursor !== "string") throw new Error("Codex scheduled app inventory returned an invalid pagination cursor");
306
+ cursor = response.nextCursor;
307
+ if (!cursor) return toolsByApp;
308
+ if (seenCursors.has(cursor)) throw new Error("Codex app connector inventory repeated its pagination cursor");
309
+ seenCursors.add(cursor);
310
+ }
311
+ throw new Error("Codex app connector inventory exceeded its bounded page limit");
312
+ }
313
+ /** Reads current account policy and connector-backed tool metadata under one caller deadline. */
314
+ async function readCurrentCodexScheduledAppPolicy(params) {
315
+ const [configResponse, toolsByApp] = await Promise.all([params.request("config/read", {
316
+ includeLayers: false,
317
+ ...params.configCwd ? { cwd: params.configCwd } : {}
318
+ }), readCodexScheduledAppToolsByApp(params)]);
319
+ if (!isJsonObject(configResponse)) throw new Error("Codex config/read returned an invalid scheduled app policy response");
320
+ return {
321
+ config: isJsonObject(configResponse.config) ? configResponse.config : {},
322
+ toolsByApp
323
+ };
324
+ }
325
+ /** Captures only apps callable on the exact active Codex client/thread. */
326
+ async function captureScheduledCodexAppAuthority(params) {
327
+ const requestedTimeoutMs = params.timeoutMs ?? CODEX_APP_AUTHORITY_CAPTURE_TIMEOUT_MS;
328
+ const timeoutMs = Math.min(CODEX_APP_AUTHORITY_CAPTURE_TIMEOUT_MS, Math.max(CODEX_APP_AUTHORITY_CAPTURE_MIN_TIMEOUT_MS, Number.isFinite(requestedTimeoutMs) ? Math.floor(requestedTimeoutMs) : CODEX_APP_AUTHORITY_CAPTURE_TIMEOUT_MS));
329
+ const deadlineMs = Date.now() + timeoutMs;
330
+ const boundedClient = { request: ((method, requestParams) => {
331
+ const remainingTimeoutMs = deadlineMs - Date.now();
332
+ if (remainingTimeoutMs <= 0) throw new CodexScheduledAppAuthorityCaptureTimeoutError();
333
+ return params.client.request(method, requestParams, {
334
+ timeoutMs: remainingTimeoutMs,
335
+ signal: params.signal
336
+ });
337
+ }) };
338
+ let installed;
339
+ let currentPolicy;
340
+ let auth;
341
+ const creatorAuth = params.auth;
342
+ try {
343
+ [installed, currentPolicy, auth] = await withAbortableTimeout({
344
+ promise: Promise.all([
345
+ boundedClient.request("app/installed", {
346
+ threadId: params.threadId,
347
+ forceRefresh: false
348
+ }),
349
+ readCurrentCodexScheduledAppPolicy({
350
+ request: (method, requestParams) => boundedClient.request(method, requestParams),
351
+ threadId: params.threadId,
352
+ configCwd: params.configCwd
353
+ }),
354
+ creatorAuth.kind === "prepared-profile" ? Promise.resolve({
355
+ profileId: creatorAuth.profileId,
356
+ accountId: creatorAuth.accountId
357
+ }) : readCodexManagedRequirementsFingerprint(boundedClient, params.signal).then((managedRequirementsFingerprint) => ({
358
+ kind: creatorAuth.kind,
359
+ connectionFingerprint: creatorAuth.connectionFingerprint,
360
+ managedRequirementsFingerprint
361
+ }))
362
+ ]),
363
+ timeoutMs,
364
+ signal: params.signal,
365
+ timeoutMessage: "Codex scheduled app authority capture deadline elapsed",
366
+ createTimeoutError: () => new CodexScheduledAppAuthorityCaptureTimeoutError()
367
+ });
368
+ } catch (error) {
369
+ if (params.signal?.aborted || !(error instanceof CodexScheduledAppAuthorityCaptureTimeoutError) && !isCodexAppServerRequestTimeoutError(error)) throw error;
370
+ throw new Error(`Codex app authority capture exceeded its ${timeoutMs} ms total budget. No automation changes were saved; retry after Codex app inventory is responsive.`, { cause: error });
371
+ }
372
+ const callableIds = new Set(installed.apps.filter((app) => app.enabled && app.callable).map((app) => app.id));
373
+ const apps = Object.entries(params.policyContext.apps).filter(([id]) => callableIds.has(id) && currentPolicy.toolsByApp.has(id)).map(([id, policy]) => ({
374
+ id,
375
+ allowDestructiveActions: policy.allowDestructiveActions,
376
+ allowOpenWorld: policy.allowOpenWorld !== false,
377
+ destructiveApprovalMode: defaultApprovalMode(policy),
378
+ tools: Object.fromEntries([...currentPolicy.toolsByApp.get(id)?.keys() ?? []].toSorted().map((toolName) => [toolName, readCurrentToolPolicy(currentPolicy.config, id, toolName, currentPolicy.toolsByApp.get(id)?.get(toolName), appApprovalCeiling(defaultApprovalMode(policy))).approvalMode]))
379
+ })).toSorted((left, right) => left.id.localeCompare(right.id));
380
+ if (apps.length === 0) return;
381
+ return {
382
+ version: 1,
383
+ runtimeId: "codex",
384
+ namespace: CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE,
385
+ payload: {
386
+ version: 1,
387
+ auth,
388
+ apps
389
+ }
390
+ };
391
+ }
392
+ var CodexScheduledAppAuthorityCaptureTimeoutError = class extends Error {
393
+ constructor() {
394
+ super("Codex scheduled app authority capture deadline elapsed");
395
+ this.name = "CodexScheduledAppAuthorityCaptureTimeoutError";
396
+ }
397
+ };
398
+ const APPROVAL_RANK = {
399
+ deny: 0,
400
+ ask: 1,
401
+ auto: 2,
402
+ allow: 3
403
+ };
404
+ function stricterApprovalMode(left, right) {
405
+ return APPROVAL_RANK[left] <= APPROVAL_RANK[right] ? left : right;
406
+ }
407
+ function appApprovalCeiling(mode) {
408
+ if (mode === "allow") return "approve";
409
+ return mode === "ask" ? "prompt" : "auto";
410
+ }
411
+ /** Intersects a stored app-ID cap with current policy without admitting new apps. */
412
+ function intersectCodexPluginThreadConfigWithScheduledAuthority(config, authority, currentPolicy = {
413
+ config: {},
414
+ toolsByApp: /* @__PURE__ */ new Map()
415
+ }) {
416
+ const scheduled = parseScheduledCodexAppAuthority(authority);
417
+ if (!scheduled) return config;
418
+ const omittedAppIds = scheduled.apps.map((app) => app.id).filter((id) => {
419
+ const currentTools = currentPolicy.toolsByApp.get(id);
420
+ return !Object.hasOwn(config.policyContext.apps, id) || !currentTools || currentTools.size === 0;
421
+ }).toSorted();
422
+ if (omittedAppIds.length > 0) {
423
+ const visibleIds = omittedAppIds.slice(0, 10).join(", ");
424
+ const remaining = omittedAppIds.length - Math.min(omittedAppIds.length, 10);
425
+ throw new AgentHarnessPreflightError(`Scheduled Codex apps are unavailable under the current policy or account: ${visibleIds}${remaining > 0 ? ` (and ${remaining} more)` : ""}. Restore access or reauthorize the automation from a fresh authenticated Codex owner turn.`);
426
+ }
427
+ const capturedById = new Map(scheduled.apps.map((app) => [app.id, app]));
428
+ const apps = {};
429
+ for (const [id, current] of Object.entries(config.policyContext.apps)) {
430
+ const captured = capturedById.get(id);
431
+ if (!captured) continue;
432
+ apps[id] = {
433
+ ...current,
434
+ allowDestructiveActions: current.allowDestructiveActions && captured.allowDestructiveActions,
435
+ allowOpenWorld: current.allowOpenWorld !== false && captured.allowOpenWorld,
436
+ destructiveApprovalMode: stricterApprovalMode(defaultApprovalMode(current), captured.destructiveApprovalMode)
437
+ };
438
+ }
439
+ 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));
440
+ const policyContext = buildPluginAppPolicyContext(apps, pluginAppIds);
441
+ const configPatch = disableUnlistedCodexApps(buildCodexPluginAppsConfigPatchFromPolicyContext(policyContext), currentPolicy.config);
442
+ const appsPatch = asOptionalRecord(configPatch.apps);
443
+ for (const [appId, captured] of capturedById) {
444
+ const appPatch = asOptionalRecord(appsPatch?.[appId]);
445
+ if (!appPatch || !Object.hasOwn(apps, appId)) continue;
446
+ const currentApp = apps[appId];
447
+ if (!currentApp) continue;
448
+ if (currentApp.destructiveApprovalMode === "ask") Object.assign(appPatch, buildCodexAppApprovalOverrides(currentPolicy.config, {
449
+ id: appId,
450
+ approvalOverrideToolConfigKeys: []
451
+ }));
452
+ const storedAppCeiling = appApprovalCeiling(captured.destructiveApprovalMode);
453
+ const currentAppCeiling = appApprovalCeiling(defaultApprovalMode(currentApp));
454
+ const tools = currentPolicy.toolsByApp.get(appId) ?? /* @__PURE__ */ new Map();
455
+ appPatch.tools = Object.fromEntries([...tools.keys()].toSorted().map((toolName) => {
456
+ const capturedMode = captured.tools[toolName] ?? storedAppCeiling;
457
+ const currentToolPolicy = readCurrentToolPolicy(currentPolicy.config, appId, toolName, tools.get(toolName), currentAppCeiling);
458
+ return [toolName, {
459
+ enabled: currentToolPolicy.enabled && appToolHintsAllowed(tools.get(toolName), currentApp),
460
+ approval_mode: intersectToolApprovalMode(intersectToolApprovalMode(capturedMode, storedAppCeiling), intersectToolApprovalMode(currentToolPolicy.approvalMode, currentAppCeiling))
461
+ }];
462
+ }));
463
+ }
464
+ const fingerprint = crypto.createHash("sha256").update(stringifyCodexPolicy({
465
+ version: 1,
466
+ namespace: CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE,
467
+ authority: scheduled,
468
+ inputFingerprint: config.inputFingerprint,
469
+ policyContext,
470
+ configPatch
471
+ })).digest("hex");
472
+ return {
473
+ ...config,
474
+ fingerprint,
475
+ configPatch,
476
+ provisionalAppIds: Object.keys(apps).toSorted(),
477
+ policyContext
478
+ };
479
+ }
480
+ /** Returns the managed-requirements identity captured for a configured app-server job. */
481
+ function readScheduledCodexAppManagedRequirementsFingerprint(authority) {
482
+ const auth = parseScheduledCodexAppAuthority(authority)?.auth;
483
+ return auth?.kind === "configured-app-server" ? auth.managedRequirementsFingerprint : void 0;
484
+ }
485
+ function assertScheduledCodexAppAuthorityRuntime(connection, params) {
486
+ const scheduledAuth = parseScheduledCodexAppAuthority(params.scheduledRuntimeAuthority)?.auth;
487
+ if (!scheduledAuth) return;
488
+ if (params.trigger !== "cron" || connection.usesSupervisionConnection || connection.appServer.start.homeScope === "user") throw new AgentHarnessPreflightError("This automation's Codex app authority requires an isolated scheduled runtime. Reauthorize it from a supported Codex creator turn.");
489
+ if (scheduledAuth.kind === "configured-app-server") {
490
+ if (buildScheduledCodexAppServerConnectionIdentity(connection.appServer) !== scheduledAuth.connectionFingerprint) throw new AgentHarnessPreflightError("This automation was authorized for a different configured Codex app-server. Restore that connection or reauthorize the automation from a fresh owner turn.");
491
+ return;
492
+ }
493
+ const prepared = connection.startupPreparedAuth;
494
+ if (prepared?.kind !== "profile" || prepared.profileId !== scheduledAuth.profileId || prepared.snapshot?.loginParams.type !== "chatgptAuthTokens" || prepared.snapshot.chatgptAccountId !== scheduledAuth.accountId) throw new AgentHarnessPreflightError(`This automation was authorized for Codex profile ${scheduledAuth.profileId}, but that exact prepared account is not active. Restore the profile or reauthorize the automation from a fresh owner turn.`);
495
+ }
496
+ function buildLegacyScheduledCodexAppRecoveryPrompt(params) {
497
+ if (params.trigger !== "cron" || !params.scheduledRuntimeAuthorityRecoveryRequired || params.scheduledRuntimeAuthority) return;
498
+ return "Scheduled Codex app access is unavailable because this automation predates runtime-specific app authority capture. Tell the operator to recreate or reauthorize it from a fresh authenticated Codex owner turn; do not claim an app action succeeded.";
499
+ }
500
+ /** Makes stored-cap identity part of thread reuse admission, including cap removal. */
501
+ function buildScheduledCodexAppAuthorityInputFingerprint(baseFingerprint, authority) {
502
+ const scheduled = parseScheduledCodexAppAuthority(authority);
503
+ if (!scheduled) return baseFingerprint;
504
+ return crypto.createHash("sha256").update(stringifyCodexPolicy({
505
+ version: 1,
506
+ namespace: CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE,
507
+ baseFingerprint,
508
+ authority: scheduled
509
+ })).digest("hex");
510
+ }
511
+ //#endregion
512
+ //#region extensions/codex/src/app-server/thread-lifecycle-timing.ts
513
+ const CODEX_THREAD_LIFECYCLE_TIMING_WARN_TOTAL_MS = 1e3;
514
+ const CODEX_THREAD_LIFECYCLE_TIMING_WARN_STAGE_MS = 500;
515
+ function createCodexThreadLifecycleTimingTracker(options = {}) {
516
+ const log = options.log ?? embeddedAgentLog;
517
+ const timing = createStageTimingTracker(options.now ?? Date.now);
518
+ let didLog = false;
519
+ return {
520
+ measure: timing.measure,
521
+ measureSync: timing.measureSync,
522
+ mark(name) {
523
+ timing.measureSync(name, () => void 0);
524
+ },
525
+ logSummary(params) {
526
+ if (didLog) return;
527
+ const { totalMs, stages: spans } = timing.snapshot();
528
+ const detailed = options.enabled || log.isEnabled?.("trace");
529
+ const totalThresholdMs = options.totalThresholdMs ?? (detailed ? CODEX_THREAD_LIFECYCLE_TIMING_WARN_TOTAL_MS : 1e4);
530
+ const stageThresholdMs = options.stageThresholdMs ?? (detailed ? CODEX_THREAD_LIFECYCLE_TIMING_WARN_STAGE_MS : 5e3);
531
+ const shouldWarn = totalMs >= totalThresholdMs || spans.some((span) => span.durationMs >= stageThresholdMs);
532
+ if (!shouldWarn && !log.isEnabled?.("trace")) return;
533
+ didLog = true;
534
+ const message = `[trace:codex-app-server] thread lifecycle: runId=${params.runId} sessionId=${params.sessionId} sessionKey=${params.sessionKey ?? "unknown"} action=${params.action} totalMs=${totalMs} stages=${formatStageTimings(spans)}`;
535
+ const meta = {
536
+ runId: params.runId,
537
+ sessionId: params.sessionId,
538
+ sessionKey: params.sessionKey,
539
+ action: params.action,
540
+ threadId: params.threadId,
541
+ totalMs,
542
+ spans
543
+ };
544
+ if (shouldWarn) log.warn(message, meta);
545
+ else log.trace(message, meta);
546
+ }
547
+ };
548
+ }
549
+ //#endregion
550
+ //#region extensions/codex/src/app-server/thread-lifecycle-preflight.ts
551
+ function assertCodexThreadInferenceAuthority(params, modelPolicyEnforced) {
552
+ if (params.inferenceRoute && modelPolicyEnforced) return;
553
+ const host = params.params.hostCapabilities;
554
+ const unavailable = () => new AgentHarnessPreflightError("This Codex connection cannot enforce your operator role's model policy. Use an OpenClaw-managed connection with an owned inference route; no turn was sent.");
555
+ if (!host.retainSourceAuthority) throw unavailable();
556
+ const source = host.retainSourceAuthority();
557
+ if (source === void 0) return;
558
+ try {
559
+ source.assertCurrent();
560
+ if (source.modelPolicyRequired !== false) throw unavailable();
561
+ } finally {
562
+ source.release();
563
+ }
564
+ }
565
+ /** Preserve the selected provider when only its physical thread must be replaced. */
566
+ async function prepareCodexThreadRequestContext(params, options) {
567
+ const startModelSelection = resolveCodexAppServerThreadModelSelection({
568
+ homeScope: params.appServer.start.homeScope,
569
+ provider: params.params.provider,
570
+ model: params.runtimeModelId ?? params.params.modelId,
571
+ binding: options.selectionBinding,
572
+ authProfileId: params.params.authProfileId,
573
+ authProfileStore: params.params.authProfileStore,
574
+ agentDir: params.params.agentDir,
575
+ config: params.params.config
576
+ });
577
+ const source = params.params.hostCapabilities.retainSourceAuthority?.();
578
+ const modelPolicyEnforced = params.nativeModelAdmission === void 0 || options.preflight.nativeModelInputTools !== void 0;
579
+ let inference;
580
+ try {
581
+ source?.assertCurrent();
582
+ inference = await prepareCodexInferenceThreadConfig({
583
+ ...params,
584
+ config: options.config,
585
+ binding: options.binding,
586
+ clientId: options.clientId,
587
+ operatorBacked: source !== void 0,
588
+ modelPolicyEnforced,
589
+ modelProvider: options.binding?.preserveNativeModel || options.binding?.connectionScope === "supervision" ? options.binding.modelProvider : startModelSelection.modelProvider,
590
+ effectiveConfig: options.preflight.effectiveConfig,
591
+ assertCurrent: () => {
592
+ options.assertCurrent();
593
+ source?.assertCurrent();
594
+ }
595
+ });
596
+ } finally {
597
+ source?.release();
598
+ }
599
+ params.config = inference?.config ?? options.config;
600
+ params.inferenceRoute = inference?.route;
601
+ params.inferenceProviderRoutes = inference?.providers;
602
+ params.assertCurrent = () => {
603
+ options.throwIfAborted();
604
+ options.assertCurrent();
605
+ assertCodexThreadInferenceAuthority(params, modelPolicyEnforced);
606
+ };
607
+ params.assertCurrent();
608
+ return {
609
+ ...options.preflight,
610
+ bindingIdentity: options.bindingIdentity,
611
+ startModelSelection,
612
+ startModelProvider: startModelSelection.modelProvider,
613
+ normalizeBindingModelProvider: (authProfileId, modelProvider) => normalizeCodexAppServerBindingModelProvider({
614
+ authProfileId,
615
+ modelProvider,
616
+ authProfileStore: params.params.authProfileStore,
617
+ agentDir: params.params.agentDir,
618
+ config: params.params.config
619
+ }),
620
+ throwIfAborted: options.throwIfAborted
621
+ };
622
+ }
623
+ function publishCodexThreadInferenceBinding(params, binding, reusedConfiguration = false) {
624
+ params.assertCurrent?.();
625
+ params.signal?.throwIfAborted();
626
+ assertCodexInferenceRouteConfig(params.client, params.inferenceRoute, params.config, binding.modelProvider, params.inferenceProviderRoutes);
627
+ if (reusedConfiguration) {
628
+ if (getCodexInferenceThread(params.client, binding.threadId) !== params.inferenceRoute) throw new Error("Codex inference thread configuration changed before reuse");
629
+ } else bindCodexInferenceThread(params.client, binding.threadId, params.inferenceRoute, params.inferenceProviderRoutes);
630
+ return binding;
631
+ }
632
+ function resolveCodexThreadAgentDir(params) {
633
+ const agentId = resolveSessionAgentIdsStrict({
634
+ config: params.params.config,
635
+ sessionKey: params.params.sessionKey,
636
+ agentId: params.agentId ?? params.params.agentId
637
+ }).sessionAgentId;
638
+ return params.agentDir ?? params.params.agentDir ?? resolveAgentDir$1(params.params.config ?? {}, agentId);
639
+ }
640
+ function buildCodexThreadBindingPolicy(params, preflight) {
641
+ return {
642
+ dynamicToolsFingerprint: preflight.dynamicToolsFingerprint,
643
+ dynamicToolsContainDeferred: preflight.dynamicToolsContainDeferred,
644
+ nativeSkillIsolationFingerprint: preflight.nativeSkillIsolationFingerprint,
645
+ userMcpServersFingerprint: preflight.userMcpServersFingerprint,
646
+ configuredMcpOwnershipVersion: params.configuredMcpOwnershipVersion,
647
+ networkProxyProfileName: params.appServer.networkProxy?.profileName,
648
+ networkProxyConfigFingerprint: preflight.networkProxyConfigFingerprint,
649
+ contextEngine: preflight.contextEngineBinding,
650
+ environmentSelectionFingerprint: preflight.environmentSelectionFingerprint
651
+ };
652
+ }
653
+ async function prepareCodexThreadFinalConfigPatch(params, nativeModelInputTools, binding) {
654
+ return await params.buildFinalConfigPatch?.({
655
+ ...binding ? {
656
+ action: "resume",
657
+ binding
658
+ } : { action: "start" },
659
+ ...nativeModelInputTools ? { nativeModelInputTools } : {}
660
+ }) ?? {
661
+ configPatch: params.finalConfigPatch,
662
+ nativeHookRelayGeneration: params.nativeHookRelayGeneration
663
+ };
664
+ }
665
+ async function prepareCodexThreadLifecyclePreflight(params) {
666
+ let effectiveConfig = await assertCodexModelBackedReviewerEffectiveConfig({
667
+ client: params.client,
668
+ approvalsReviewer: params.appServer.approvalsReviewer,
669
+ cwd: params.cwd,
670
+ signal: params.signal
671
+ });
672
+ const nativeHooksRequired = params.nativeHookRelayRequired || params.nativeModelAdmission === "required";
673
+ let modelAdmissionAvailable = params.nativeModelAdmission !== void 0 && (params.nativeModelAdmission !== "disabled" || nativeHooksRequired);
674
+ if (nativeHooksRequired || modelAdmissionAvailable) try {
675
+ await assertCodexNativeHookRelayAllowed(params.client, params.signal);
676
+ } catch (error) {
677
+ if (nativeHooksRequired || !(error instanceof CodexManagedHooksOnlyError)) throw error;
678
+ modelAdmissionAvailable = false;
679
+ }
680
+ const lifecycleTiming = createCodexThreadLifecycleTimingTracker({
681
+ ...params.timing,
682
+ enabled: params.timing?.enabled ?? isCodexAppServerProfilerEnabled(params.params.config)
683
+ });
684
+ const legacyDynamicToolsFingerprint = lifecycleTiming.measureSync("legacy-dynamic-tools-fingerprint", () => codexLegacyDynamicToolsFingerprint(params.dynamicTools));
685
+ const dynamicToolsFingerprint = lifecycleTiming.measureSync("dynamic-tools-fingerprint", () => hashCodexAppServerBindingFingerprint(legacyDynamicToolsFingerprint));
686
+ const dynamicToolsContainDeferred = flattenCodexDynamicToolFunctions(params.dynamicTools).some((tool) => tool.deferLoading === true);
687
+ const webSearchPlan = lifecycleTiming.measureSync("web-search-plan", () => resolveCodexWebSearchPlan({
688
+ config: params.params.config,
689
+ disableTools: params.params.disableTools,
690
+ nativeToolSurfaceEnabled: params.nativeCodeModeEnabled,
691
+ nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
692
+ webSearchAllowed: params.webSearchAllowed
693
+ }));
694
+ const webSearchThreadConfigFingerprint = fingerprintJsonObject(webSearchPlan.threadConfig);
695
+ const networkProxyConfigFingerprint = params.appServer.networkProxy?.configFingerprint;
696
+ const contextEngineBinding = lifecycleTiming.measureSync("context-engine-binding", () => buildContextEngineBinding(params.params, params.contextEngineProjection));
697
+ const userMcpServersConfigPatch = params.userMcpServersEnabled === false ? void 0 : await buildCodexUserMcpServersThreadConfigPatchForRun({
698
+ run: params.params,
699
+ cwd: params.cwd,
700
+ agentId: params.agentId ?? params.params.agentId,
701
+ allowLiteralOAuthProjection: params.appServer.connectionClass !== "remote",
702
+ warn: (message) => embeddedAgentLog.warn(message),
703
+ onServerUnavailable: (serverName, error) => embeddedAgentLog.warn("skipping unavailable MCP OAuth server", {
704
+ serverName,
705
+ error: formatErrorMessage(error)
706
+ })
707
+ });
708
+ const nativeSkillIsolation = await lifecycleTiming.measure("native-skill-isolation", () => resolveCodexNativeSkillIsolation({
709
+ client: params.client,
710
+ codexHome: params.appServer.start.codexHome ?? params.appServer.start.env?.CODEX_HOME,
711
+ cwd: params.cwd,
712
+ home: params.appServer.start.env?.HOME,
713
+ signal: params.signal,
714
+ userProfile: params.appServer.start.env?.USERPROFILE
715
+ }));
716
+ const nativeSkillIsolationFingerprint = nativeSkillIsolation ? fingerprintJsonObject({
717
+ version: 1,
718
+ disabledUserSkillPaths: nativeSkillIsolation.disabledUserSkillPaths
719
+ }) : void 0;
720
+ const legacyUserMcpServersFingerprint = legacyFingerprintUserMcpServersConfigPatch(userMcpServersConfigPatch);
721
+ const userMcpServersFingerprint = fingerprintUserMcpServersConfigPatch(userMcpServersConfigPatch);
722
+ const environmentSelectionFingerprint = fingerprintEnvironmentSelection(params.environmentSelection);
723
+ const hostSystemAgentActive = params.hostSystemAgentActive ?? isHostScopedAgentToolActive("openclaw");
724
+ const ringZeroActive = hostSystemAgentActive && isSystemAgentOnlyCodexDynamicToolAllowlist(params.params.toolsAllow);
725
+ const messageOnlySourceReply = isMessageOnlyCodexSourceReply(params.params);
726
+ const restrictedToolSurface = ringZeroActive || messageOnlySourceReply || params.params.pluginHarnessToolPolicyRestricted === true;
727
+ const allowConfiguredManagedHooks = params.params.pluginHarnessToolPolicyRestricted === true && !ringZeroActive && !messageOnlySourceReply && params.params.scheduledRuntimeAuthority === void 0;
728
+ const imageGenerationDenied = params.params.pluginHarnessToolPolicySafeDeniedTools?.includes("image_generate") === true;
729
+ if (restrictedToolSurface && params.nativeCodeModeEnabled !== false) throw new Error("Codex restricted tool surfaces require native code mode to be disabled");
730
+ if (!effectiveConfig) effectiveConfig = await lifecycleTiming.measure("effective-config-read", () => readCodexEffectiveConfig(params.client, params.cwd, { signal: params.signal }));
731
+ params.config = mergeCodexNativeProjectDocThreadConfig(params.config, effectiveConfig);
732
+ if (params.shellEnvironment) params.config = mergeCodexNativeShellEnvironment(params.config, effectiveConfig.config.shell_environment_policy);
733
+ const restrictedToolSurfaceInheritedMcpServerNames = restrictedToolSurface ? await lifecycleTiming.measure("restricted-tool-surface-mcp-policy", () => readCodexInheritedMcpServerNames(params.client, params.cwd, params.signal, effectiveConfig)) : [];
734
+ if (restrictedToolSurface || imageGenerationDenied || params.nativeCodeModeEnabled !== false) await lifecycleTiming.measure("tool-policy-config-requirements-read", () => assertCodexManagedRequirementsDoNotOverrideToolPolicy(params.client, {
735
+ restrictedToolSurface,
736
+ requiredNativeShell: params.nativeCodeModeEnabled !== false,
737
+ additionalDeniedFeatures: imageGenerationDenied ? ["image_generation"] : void 0,
738
+ allowedManagedRequirementsFingerprint: readScheduledCodexAppManagedRequirementsFingerprint(params.params.scheduledRuntimeAuthority),
739
+ allowConfiguredManagedHooks
740
+ }, params.signal));
741
+ const features = effectiveConfig?.config.features;
742
+ if (params.nativeCodeModeEnabled !== false && isJsonObject(features) && features.shell_tool === false && !CODEX_SESSION_OVERRIDABLE_LAYER_TYPES.has(effectiveConfig?.origins?.["features.shell_tool"]?.name.type ?? "")) throw new Error("Codex native code mode requires shell_tool, but the effective shell setting cannot be overridden. Ask your administrator to allow the shell, or select a tool policy that disables native code mode; no automation authority was captured.");
743
+ const ringZeroConfigFingerprint = ringZeroActive ? fingerprintJsonObject({
744
+ version: 1,
745
+ baseInstructions: "",
746
+ config: buildCodexRingZeroThreadConfigPatch(params.params, true, restrictedToolSurfaceInheritedMcpServerNames)
747
+ }) : void 0;
748
+ const ringZeroClientInstanceId = ringZeroActive ? getCodexAppServerClientInstanceId(params.client) : void 0;
749
+ return {
750
+ nativeModelInputTools: nativeHooksRequired || modelAdmissionAvailable ? resolveCodexNativeModelInputTools(effectiveConfig.config) : void 0,
751
+ effectiveConfig,
752
+ contextEngineBinding,
753
+ dynamicToolsContainDeferred,
754
+ dynamicToolsFingerprint,
755
+ environmentSelectionFingerprint,
756
+ hostSystemAgentActive,
757
+ legacyDynamicToolsFingerprint,
758
+ legacyUserMcpServersFingerprint,
759
+ lifecycleTiming,
760
+ nativeSkillIsolation,
761
+ nativeSkillIsolationFingerprint,
762
+ networkProxyConfigFingerprint,
763
+ ringZeroActive,
764
+ ringZeroClientInstanceId,
765
+ ringZeroConfigFingerprint,
766
+ restrictedToolSurface,
767
+ restrictedToolSurfaceInheritedMcpServerNames,
768
+ userMcpServersConfigPatch,
769
+ userMcpServersFingerprint,
770
+ webSearchThreadConfigFingerprint
771
+ };
772
+ }
773
+ //#endregion
774
+ //#region extensions/codex/src/app-server/thread-lifecycle-io.ts
775
+ async function resumeExistingCodexThread(params, context) {
776
+ const { binding: resumeBinding, bindingIdentity, startModelSelection, startModelProvider, userMcpServersConfigPatch, dynamicToolsFingerprint, webSearchThreadConfigFingerprint, ringZeroConfigFingerprint, ringZeroClientInstanceId, contextEngineBinding, hostSystemAgentActive, restrictedToolSurface, restrictedToolSurfaceInheritedMcpServerNames, nativeSkillIsolation, lifecycleTiming, normalizeBindingModelProvider, throwIfAborted, clearCurrentBinding } = context;
777
+ let acceptedConfiguration;
778
+ let disposeConfiguration;
779
+ let resumeReservation;
780
+ let ordinaryAppConfigChanged = false;
781
+ let policyOutcome = "not-written";
782
+ const abandonClient = params.abandonClient ?? (() => closeCodexStartupClientBestEffort(params.client));
783
+ try {
784
+ const configuration = await context.prepareResume();
785
+ const assertHandoffCurrent = configuration.assertConfigured;
786
+ disposeConfiguration = configuration.dispose;
787
+ await context.releaseRetainedThread(configuration.assertCurrent);
788
+ configuration.assertCurrent();
789
+ const clientBoundThread = ringZeroClientInstanceId !== void 0 || resumeBinding.ringZeroClientInstanceId !== void 0 || resumeBinding.ringZeroConfigFingerprint !== void 0 || context.ringZeroActive;
790
+ const sharedEntry = getCurrentSharedClientEntry(params.client);
791
+ if (configuration.settledSystemError && !clientBoundThread && resumeBinding.connectionScope !== "supervision" && (!sharedEntry || sharedEntry.activeLeases <= 1 && sharedEntry.pendingAcquires === 0) && !hasCodexAppServerSiblingThreadWork(params.client, resumeBinding.threadId) && !hasCodexAppServerSiblingRouteWork(params.client, resumeBinding.threadId)) {
792
+ await abandonClient();
793
+ throw new CodexThreadClientReplacementError();
794
+ }
795
+ const authProfileId = resumeBinding.connectionScope === "supervision" ? void 0 : params.params.authProfileId ?? resumeBinding.authProfileId;
796
+ const finalConfigPatch = context.prebuiltFinalConfigPatch ?? await prepareCodexThreadFinalConfigPatch(params, context.nativeModelInputTools, resumeBinding);
797
+ const pluginThreadConfig = context.prebuiltPluginThreadConfig ?? (params.pluginThreadConfig?.enabled ? await lifecycleTiming.measure("plugin-config-build", () => params.pluginThreadConfig?.build()) : void 0);
798
+ const resumeConfig = applyCodexNativeSkillIsolation(mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginThreadConfig?.configPatch, finalConfigPatch.configPatch), nativeSkillIsolation);
799
+ const resumeParams = lifecycleTiming.measureSync("thread-resume-params", () => buildThreadResumeParams(params.params, {
800
+ ...params,
801
+ threadId: resumeBinding.threadId,
802
+ authProfileId,
803
+ model: startModelSelection.model,
804
+ modelProvider: startModelProvider,
805
+ preserveNativeModel: resumeBinding.preserveNativeModel === true,
806
+ config: resumeConfig,
807
+ hostSystemAgentActive,
808
+ restrictedToolSurfaceInheritedMcpServerNames
809
+ }));
810
+ const requestModelProvider = typeof resumeParams.modelProvider === "string" && resumeParams.modelProvider.trim() ? resumeParams.modelProvider : void 0;
811
+ throwIfAborted();
812
+ resumeReservation = params.reserveResumeThread?.(resumeBinding.threadId);
813
+ const response = await lifecycleTiming.measure("thread-resume-request", () => resumeCodexAppServerThread({
814
+ client: params.client,
815
+ abandonClient,
816
+ request: resumeParams,
817
+ signal: params.signal,
818
+ assertCurrent: () => {
819
+ configuration.assertCurrent();
820
+ assertCodexInferenceRouteConfig(params.client, params.inferenceRoute, resumeParams.config, requestModelProvider ?? (resumeBinding.preserveNativeModel ? configuration.modelProvider ?? void 0 : void 0), params.inferenceProviderRoutes);
821
+ }
822
+ }));
823
+ acceptedConfiguration = configuration;
824
+ assertCodexThreadAcceptsDirectInput(response.thread);
825
+ configuration.assertConfigured();
826
+ if (requestModelProvider && response.modelProvider !== requestModelProvider) throw new Error("Codex resumed a different model provider than the one selected for this turn");
827
+ const loadedPluginThreadConfig = await context.buildLoadedPluginThreadConfig?.(resumeBinding);
828
+ if (loadedPluginThreadConfig && loadedPluginThreadConfig.fingerprint !== (pluginThreadConfig?.fingerprint ?? resumeBinding.pluginAppsFingerprint)) {
829
+ ordinaryAppConfigChanged = resumeBinding.connectionScope !== "supervision" && !resumeBinding.pendingResumeConfiguration;
830
+ throw new Error("Codex thread app policy changed; a fresh thread configuration is required");
831
+ }
832
+ const provisionalAppIds = loadedPluginThreadConfig?.provisionalAppIds ?? pluginThreadConfig?.provisionalAppIds ?? [];
833
+ await attestCodexThreadToolSurface({
834
+ client: params.client,
835
+ threadId: response.thread.id,
836
+ appIds: provisionalAppIds,
837
+ signal: params.signal,
838
+ threadConfig: resumeParams.config,
839
+ restrictedToolSurface,
840
+ lifecycleTiming,
841
+ assertCurrent: assertHandoffCurrent
842
+ });
843
+ throwIfAborted();
844
+ await refreshCodexThreadPolicy({
845
+ client: params.client,
846
+ threadId: resumeBinding.threadId,
847
+ developerInstructions: resumeParams.developerInstructions,
848
+ timeoutMs: params.appServer.requestTimeoutMs,
849
+ signal: params.signal,
850
+ assertCurrent: assertHandoffCurrent
851
+ });
852
+ policyOutcome = "acknowledged";
853
+ assertHandoffCurrent();
854
+ const resumePatch = {
855
+ clientId: resolveCodexAppServerClientInstanceId(params.client),
856
+ pendingResumeConfiguration: void 0,
857
+ ...resumeBinding.agentWorkspaceDeveloperInstructions === void 0 && params.agentWorkspaceDeveloperInstructions !== void 0 ? { agentWorkspaceDeveloperInstructions: params.agentWorkspaceDeveloperInstructions } : {},
858
+ cwd: params.cwd,
859
+ rolloutPath: resolveCodexThreadRolloutPath(response.thread) ?? resumeBinding.rolloutPath,
860
+ authProfileId,
861
+ model: resumeParams.model ?? response.model ?? params.params.modelId,
862
+ preserveNativeModel: resumeBinding.preserveNativeModel === true ? true : void 0,
863
+ modelProvider: normalizeBindingModelProvider(authProfileId, response.modelProvider ?? requestModelProvider ?? startModelProvider),
864
+ ...buildCodexThreadBindingPolicy(params, context),
865
+ webSearchThreadConfigFingerprint,
866
+ mcpServersFingerprint: params.mcpServersFingerprintEvaluated === true ? params.mcpServersFingerprint : resumeBinding.mcpServersFingerprint,
867
+ ringZeroConfigFingerprint,
868
+ ringZeroClientInstanceId,
869
+ nativeToolPolicyRestricted: restrictedToolSurface ? true : void 0,
870
+ nativeHookRelayGeneration: finalConfigPatch.nativeHookRelayGeneration ?? resumeBinding.nativeHookRelayGeneration,
871
+ appServerRuntimeFingerprint: resumeBinding.connectionScope === "supervision" ? buildCodexAppServerConnectionFingerprint(params.appServer, params.params.agentDir) : params.appServerRuntimeFingerprint,
872
+ pluginAppsFingerprint: pluginThreadConfig?.fingerprint ?? resumeBinding.pluginAppsFingerprint,
873
+ pluginAppsInputFingerprint: pluginThreadConfig?.inputFingerprint ?? resumeBinding.pluginAppsInputFingerprint,
874
+ pluginAppPolicyContext: pluginThreadConfig?.policyContext ?? resumeBinding.pluginAppPolicyContext
875
+ };
876
+ if (!await lifecycleTiming.measure("thread-resume-write-binding", () => params.bindingStore.mutate(bindingIdentity, {
877
+ kind: "patch",
878
+ threadId: resumeBinding.threadId,
879
+ patch: resumePatch
880
+ }, assertHandoffCurrent))) throw new CodexThreadBindingConflictError(resumeBinding.threadId, "committing a resumed thread");
881
+ assertHandoffCurrent();
882
+ if (contextEngineBinding) embeddedAgentLog.info("codex app-server wrote context-engine thread binding", {
883
+ sessionId: params.params.sessionId,
884
+ sessionKey: params.params.sessionKey,
885
+ threadId: response.thread.id,
886
+ engineId: contextEngineBinding.engineId,
887
+ epoch: contextEngineBinding.projection?.epoch,
888
+ fingerprint: contextEngineBinding.projection?.fingerprint,
889
+ action: "resumed"
890
+ });
891
+ lifecycleTiming.mark("thread-ready");
892
+ lifecycleTiming.logSummary({
893
+ runId: params.params.runId,
894
+ sessionId: params.params.sessionId,
895
+ sessionKey: params.params.sessionKey,
896
+ threadId: response.thread.id,
897
+ action: "resumed"
898
+ });
899
+ const activeTurnIds = readActiveCodexTurnIdsFromResume(response);
900
+ return {
901
+ ...resumeBinding,
902
+ threadId: response.thread.id,
903
+ ...resumePatch,
904
+ liveThreadConfigFingerprint: fingerprintCodexThreadConfig({
905
+ ...resumeParams,
906
+ model: resumeBinding.preserveNativeModel === true ? null : response.model ?? resumeParams.model ?? null,
907
+ requestedModel: resumeBinding.preserveNativeModel === true ? null : resumeParams.model ?? null,
908
+ modelProvider: resumeBinding.preserveNativeModel === true ? null : resumePatch.modelProvider ?? null,
909
+ requestedModelProvider: resumeBinding.preserveNativeModel === true ? null : resumeParams.modelProvider ?? resumePatch.modelProvider ?? null
910
+ }, authProfileId, dynamicToolsFingerprint),
911
+ lifecycle: {
912
+ action: "resumed",
913
+ ...activeTurnIds.length ? { activeTurnIds } : {}
914
+ }
915
+ };
916
+ } catch (error) {
917
+ resumeReservation?.release();
918
+ if (!acceptedConfiguration && (!(error instanceof CodexAppServerRpcError) || error.method === "thread/read" && !isCodexThreadReadMissingError(error, resumeBinding.threadId) || isCodexAppServerOverloadError(error))) throw error;
919
+ if (acceptedConfiguration) {
920
+ const handoffError = error instanceof CodexThreadPolicyHandoffError || error instanceof CodexAppServerUnsafeSubscriptionError ? error : new CodexThreadPolicyHandoffError(policyOutcome, error);
921
+ const subscriptionReleased = await unsubscribeCodexThreadBestEffort(params.client, {
922
+ threadId: resumeBinding.threadId,
923
+ timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS,
924
+ assertCurrent: acceptedConfiguration.assertCurrent
925
+ }).catch(() => false);
926
+ if (!subscriptionReleased || handoffError instanceof CodexThreadPolicyHandoffError && handoffError.outcome === "unknown") {
927
+ if (resumeBinding.connectionScope === "supervision") await retireUnsafeCodexTurnClientBestEffort(params.client, "session policy handoff");
928
+ else try {
929
+ await abandonClient();
930
+ } catch (cause) {
931
+ throw new CodexThreadPolicyHandoffError(handoffError instanceof CodexThreadPolicyHandoffError ? handoffError.outcome : policyOutcome, new AggregateError([handoffError, cause], "Codex thread/resume client could not be retired"));
932
+ }
933
+ }
934
+ if (!ordinaryAppConfigChanged || !subscriptionReleased) throw handoffError;
935
+ acceptedConfiguration.assertConfigured();
936
+ }
937
+ if (resumeBinding.pendingResumeConfiguration || resumeBinding.preserveNativeModel || resumeBinding.connectionScope === "supervision" || params.signal?.aborted) throw error;
938
+ embeddedAgentLog.warn("codex app-server thread resume failed; starting a new thread", { error });
939
+ await clearCurrentBinding("rotating a stale thread binding");
940
+ } finally {
941
+ disposeConfiguration?.();
942
+ }
943
+ }
944
+ async function startFreshCodexThread(params, context) {
945
+ const clientId = resolveCodexAppServerClientInstanceId(params.client);
946
+ const { bindingIdentity, startModelSelection, startModelProvider, userMcpServersConfigPatch, dynamicToolsFingerprint, webSearchThreadConfigFingerprint, ringZeroConfigFingerprint, ringZeroClientInstanceId, contextEngineBinding, hostSystemAgentActive, restrictedToolSurface, restrictedToolSurfaceInheritedMcpServerNames, nativeSkillIsolation, lifecycleTiming, normalizeBindingModelProvider, throwIfAborted, prebuiltPluginThreadConfig, preserveExistingBinding, rotatedContextEngineBinding, replacementPredecessor } = context;
947
+ const pluginThreadConfig = params.pluginThreadConfig?.enabled ? prebuiltPluginThreadConfig ?? await lifecycleTiming.measure("plugin-config-build", () => params.pluginThreadConfig?.build()) : void 0;
948
+ const finalConfigPatch = await prepareCodexThreadFinalConfigPatch(params, context.nativeModelInputTools);
949
+ const config = lifecycleTiming.measureSync("merge-thread-config", () => applyCodexNativeSkillIsolation(mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginThreadConfig?.configPatch, finalConfigPatch.configPatch), nativeSkillIsolation));
950
+ const startParams = lifecycleTiming.measureSync("thread-start-params", () => buildThreadStartParams(params.params, {
951
+ ...params,
952
+ config,
953
+ model: startModelSelection.model,
954
+ modelProvider: startModelProvider,
955
+ hostSystemAgentActive,
956
+ restrictedToolSurfaceInheritedMcpServerNames
957
+ }));
958
+ const requestModelProvider = typeof startParams.modelProvider === "string" && startParams.modelProvider.trim() ? startParams.modelProvider : void 0;
959
+ const assertCurrent = () => {
960
+ throwIfAborted();
961
+ params.params.hostCapabilities.assertActive();
962
+ params.assertCurrent?.();
963
+ };
964
+ const assertInferenceCurrent = () => {
965
+ assertCurrent();
966
+ assertCodexInferenceRouteConfig(params.client, params.inferenceRoute, startParams.config, requestModelProvider, params.inferenceProviderRoutes);
967
+ };
968
+ const threadStartResponse = await lifecycleTiming.measure("thread-start-request", async () => {
969
+ try {
970
+ assertCurrent();
971
+ return await params.client.request("thread/start", startParams, {
972
+ signal: params.signal,
973
+ assertCurrent: assertInferenceCurrent
974
+ });
975
+ } catch (error) {
976
+ if (error instanceof CodexAppServerRpcError) throw new CodexThreadStartRequestError(error);
977
+ throw error;
978
+ }
979
+ });
980
+ const response = assertCodexThreadStartResponse(threadStartResponse);
981
+ const provisionalAppIds = pluginThreadConfig?.provisionalAppIds;
982
+ const rejectUncommittedThread = async (cause) => {
983
+ if (!await discardUnattestedCodexPluginThread({
984
+ client: params.client,
985
+ threadId: response.thread.id,
986
+ ephemeral: startParams.ephemeral === true
987
+ })) {
988
+ await (params.abandonClient ?? (() => closeCodexStartupClientBestEffort(params.client)))();
989
+ throw new CodexAppServerUnsafeSubscriptionError("Codex uncommitted thread cleanup failed", { cause });
990
+ }
991
+ throw cause;
992
+ };
993
+ try {
994
+ await attestCodexThreadToolSurface({
995
+ client: params.client,
996
+ threadId: response.thread.id,
997
+ appIds: provisionalAppIds ?? [],
998
+ signal: params.signal,
999
+ threadConfig: startParams.config,
1000
+ restrictedToolSurface,
1001
+ lifecycleTiming,
1002
+ assertCurrent
1003
+ });
1004
+ assertCurrent();
1005
+ } catch (error) {
1006
+ return await rejectUncommittedThread(error);
1007
+ }
1008
+ const rolloutPath = resolveCodexThreadRolloutPath(response.thread);
1009
+ const modelProvider = resolveCodexAppServerModelProvider({
1010
+ homeScope: params.appServer.start.homeScope,
1011
+ provider: params.params.provider,
1012
+ authProfileId: params.params.authProfileId,
1013
+ authProfileStore: params.params.authProfileStore,
1014
+ agentDir: params.params.agentDir,
1015
+ config: params.params.config
1016
+ });
1017
+ const bindingModelProvider = normalizeBindingModelProvider(params.params.authProfileId, response.modelProvider ?? requestModelProvider ?? startModelProvider ?? modelProvider);
1018
+ const nextMcpServersFingerprint = params.mcpServersFingerprintEvaluated === true ? params.mcpServersFingerprint : void 0;
1019
+ const startedBinding = {
1020
+ threadId: response.thread.id,
1021
+ ...clientId ? { clientId } : {},
1022
+ cwd: params.cwd,
1023
+ ...rolloutPath ? { rolloutPath } : {},
1024
+ authProfileId: params.params.authProfileId,
1025
+ agentWorkspaceDeveloperInstructions: params.agentWorkspaceDeveloperInstructions,
1026
+ model: response.model ?? startParams.model ?? params.params.modelId,
1027
+ modelProvider: bindingModelProvider,
1028
+ ...buildCodexThreadBindingPolicy(params, context),
1029
+ mcpServersFingerprint: nextMcpServersFingerprint,
1030
+ ringZeroConfigFingerprint,
1031
+ ringZeroClientInstanceId,
1032
+ nativeHookRelayGeneration: finalConfigPatch.nativeHookRelayGeneration,
1033
+ appServerRuntimeFingerprint: params.appServerRuntimeFingerprint,
1034
+ pluginAppsFingerprint: pluginThreadConfig?.fingerprint,
1035
+ pluginAppsInputFingerprint: pluginThreadConfig?.inputFingerprint,
1036
+ pluginAppPolicyContext: pluginThreadConfig?.policyContext
1037
+ };
1038
+ if (!preserveExistingBinding) {
1039
+ const nextBinding = {
1040
+ ...startedBinding,
1041
+ webSearchThreadConfigFingerprint,
1042
+ nativeToolPolicyRestricted: restrictedToolSurface ? true : void 0
1043
+ };
1044
+ const managedSourceHomeId = codexCatalogHomeId(resolveCodexAppServerLocalHomeDir(params.appServer.start, resolveCodexThreadAgentDir(params)));
1045
+ let committed;
1046
+ try {
1047
+ await lifecycleTiming.measure("thread-start-mark-managed", () => markStartedCodexManagedThread(params.bindingStore.managedThreads, {
1048
+ sourceHomeId: managedSourceHomeId,
1049
+ threadId: response.thread.id,
1050
+ ...rolloutPath ? { rolloutPath } : {}
1051
+ }));
1052
+ committed = await lifecycleTiming.measure("thread-start-write-binding", () => params.bindingStore.mutate(bindingIdentity, replacementPredecessor ? {
1053
+ kind: "replace-thread",
1054
+ expectedThreadId: replacementPredecessor.threadId,
1055
+ binding: nextBinding
1056
+ } : {
1057
+ kind: "set",
1058
+ if: { kind: "absent" },
1059
+ binding: nextBinding
1060
+ }, assertCurrent));
1061
+ } catch (error) {
1062
+ return await rejectUncommittedThread(error);
1063
+ }
1064
+ if (!committed) return await rejectUncommittedThread(new CodexThreadBindingConflictError(replacementPredecessor?.threadId ?? response.thread.id, "committing a fresh thread"));
1065
+ if (contextEngineBinding) embeddedAgentLog.info("codex app-server wrote context-engine thread binding", {
1066
+ sessionId: params.params.sessionId,
1067
+ sessionKey: params.params.sessionKey,
1068
+ threadId: response.thread.id,
1069
+ engineId: contextEngineBinding.engineId,
1070
+ epoch: contextEngineBinding.projection?.epoch,
1071
+ fingerprint: contextEngineBinding.projection?.fingerprint,
1072
+ action: rotatedContextEngineBinding ? "rotated" : "started"
1073
+ });
1074
+ }
1075
+ lifecycleTiming.mark("thread-ready");
1076
+ lifecycleTiming.logSummary({
1077
+ runId: params.params.runId,
1078
+ sessionId: params.params.sessionId,
1079
+ sessionKey: params.params.sessionKey,
1080
+ threadId: response.thread.id,
1081
+ action: rotatedContextEngineBinding ? "rotated" : "started"
1082
+ });
1083
+ return {
1084
+ ...startedBinding,
1085
+ modelProvider: response.modelProvider ?? requestModelProvider ?? startModelProvider ?? modelProvider,
1086
+ liveThreadEphemeralPolicy: startParams.ephemeral ? createCodexEphemeralThreadPolicy(params) : void 0,
1087
+ ...!preserveExistingBinding ? { liveThreadConfigFingerprint: fingerprintCodexThreadConfig({
1088
+ ...startParams,
1089
+ model: response.model ?? startParams.model ?? null,
1090
+ requestedModel: startParams.model ?? null,
1091
+ modelProvider: bindingModelProvider ?? null,
1092
+ requestedModelProvider: startParams.modelProvider ?? bindingModelProvider ?? null
1093
+ }, params.params.authProfileId, dynamicToolsFingerprint) } : {},
1094
+ lifecycle: {
1095
+ action: "started",
1096
+ ...preserveExistingBinding ? { preserveExistingBinding: true } : {},
1097
+ ...rotatedContextEngineBinding ? { rotatedContextEngineBinding: true } : {}
1098
+ }
1099
+ };
1100
+ }
1101
+ //#endregion
1102
+ //#region extensions/codex/src/app-server/thread-lifecycle-warm.ts
1103
+ /** Preserves the caller's abort reason across thread ownership transitions. */
1104
+ function throwIfCodexThreadLifecycleAborted(signal) {
1105
+ if (!signal?.aborted) return;
1106
+ const reason = signal.reason;
1107
+ if (reason instanceof Error) throw reason;
1108
+ const error = new Error(typeof reason === "string" && reason.length > 0 ? reason : "codex app-server thread lifecycle aborted");
1109
+ error.name = "AbortError";
1110
+ throw error;
1111
+ }
1112
+ /** Releases consumed subscription ownership or retires an unsafe client. */
1113
+ async function releaseCodexConsumedLiveThread(options) {
1114
+ if (await options.lifecycleTiming.measure("retained-thread-unsubscribe", () => unsubscribeCodexThreadBestEffort(options.client, {
1115
+ threadId: options.threadId,
1116
+ timeoutMs: 5e3,
1117
+ assertCurrent: options.assertCurrent
1118
+ }))) return;
1119
+ return await abandonCodexLiveThreadRelease(options, options.cause);
1120
+ }
1121
+ async function abandonCodexLiveThreadRelease(options, cause) {
1122
+ options.assertCurrent?.();
1123
+ await (options.abandonClient ?? (() => closeCodexStartupClientBestEffort(options.client)))();
1124
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex retained thread subscription could not be released: ${options.threadId}`, cause !== void 0 ? { cause } : void 0);
1125
+ }
1126
+ /** Releases through the retained owner, preserving its guarded callback and rollback. */
1127
+ async function releaseCodexRetainedLiveThread(options) {
1128
+ try {
1129
+ return await options.lifecycleTiming.measure("retained-thread-unsubscribe", () => releaseCodexAppServerLiveThread(options.client, options.threadId, options.assertCurrent));
1130
+ } catch (error) {
1131
+ if (isCodexAppServerUnsafeSubscriptionError(error)) throw error;
1132
+ return await abandonCodexLiveThreadRelease(options, error);
1133
+ }
1134
+ }
1135
+ /** Release follows the physical owner across connection rotation, never a copied thread id. */
1136
+ async function releaseCodexBoundLiveThread(options) {
1137
+ const changedClient = options.ownerClientId && options.ownerClientId !== options.clientId;
1138
+ const previous = changedClient ? await retainSharedCodexAppServerClientByInstanceId(options.ownerClientId) : void 0;
1139
+ if (changedClient && !previous) return false;
1140
+ const client = previous?.client ?? options.client;
1141
+ try {
1142
+ if (isCodexAppServerLiveThreadClaimed(client, options.threadId)) throw new Error(`Codex thread ${options.threadId} is claimed by active work; stop it first.`);
1143
+ return await releaseCodexRetainedLiveThread({
1144
+ ...options,
1145
+ client,
1146
+ abandonClient: previous ? void 0 : options.abandonClient,
1147
+ assertCurrent: options.assertCurrent ? () => {
1148
+ options.assertCurrent?.();
1149
+ const closed = previous?.client.getCloseError();
1150
+ if (closed) throw closed;
1151
+ } : void 0
1152
+ });
1153
+ } finally {
1154
+ await previous?.release(!isCodexAppServerLiveThreadClaimed(client, options.threadId));
1155
+ }
1156
+ }
1157
+ /** Reuses one safely owned, fully matching subscription on its original client. */
1158
+ async function tryReuseCodexLiveThread(options) {
1159
+ const { params, binding, bindingIdentity, clientId, dynamicToolsFingerprint, environmentSelectionFingerprint, hostSystemAgentActive, lifecycleTiming, nativeSkillIsolation, ringZeroActive, restrictedToolSurface, restrictedToolSurfaceInheritedMcpServerNames, startModelProvider, startModelSelection, throwIfAborted, userMcpServersConfigPatch } = options;
1160
+ const incognito = isIncognitoSessionKey(params.params.sessionKey);
1161
+ if (incognito && (binding.preserveNativeModel || binding.connectionScope === "supervision")) {
1162
+ if (binding.clientId === clientId && binding.clientId && ((await options.buildLoadedPluginThreadConfig(binding))?.fingerprint ?? binding.pluginAppsFingerprint) === binding.pluginAppsFingerprint) {
1163
+ await params.buildFinalConfigPatch?.({
1164
+ action: "resume",
1165
+ binding,
1166
+ ...options.nativeModelInputTools ? { nativeModelInputTools: options.nativeModelInputTools } : {}
1167
+ });
1168
+ throwIfAborted();
1169
+ params.assertCurrent?.();
1170
+ return {
1171
+ kind: "ready",
1172
+ binding: {
1173
+ ...binding,
1174
+ lifecycle: { action: "resumed" }
1175
+ }
1176
+ };
1177
+ }
1178
+ return { kind: "rotate" };
1179
+ }
1180
+ if (!binding.clientId || binding.clientId !== clientId || ringZeroActive && !incognito) return { kind: "resume" };
1181
+ const retainedThread = await consumeCodexAppServerLiveThread(params.client, binding.threadId);
1182
+ if (!retainedThread) return { kind: "resume" };
1183
+ const assertWarmOwner = () => {
1184
+ throwIfAborted();
1185
+ if (!isCodexAppServerClientRuntimeLive(params.client)) throw params.client.getCloseError() ?? /* @__PURE__ */ new Error("codex app-server client is closed");
1186
+ try {
1187
+ retainedThread.assertCurrent();
1188
+ params.params.hostCapabilities.assertActive();
1189
+ params.assertCurrent?.();
1190
+ } catch (cause) {
1191
+ throw new AgentHarnessPreflightError("Codex warm thread ownership changed before this turn could run. No turn was sent; reconnect before continuing, or start a new conversation if the original thread was closed.", { cause });
1192
+ }
1193
+ };
1194
+ let ownershipTransferred = false;
1195
+ let preserveSubscription = false;
1196
+ let nativeThread;
1197
+ try {
1198
+ assertWarmOwner();
1199
+ if (binding.preserveNativeModel || binding.connectionScope === "supervision") {
1200
+ try {
1201
+ nativeThread = await assertAdoptedCodexThreadResumeAllowed(params, binding.threadId, options, assertWarmOwner);
1202
+ } catch (error) {
1203
+ assertWarmOwner();
1204
+ preserveSubscription = isSameCodexAppServerThreadOwner(params.bindingStore.read(bindingIdentity), binding);
1205
+ throw error;
1206
+ }
1207
+ assertWarmOwner();
1208
+ if (nativeThread.status?.type === "notLoaded") {
1209
+ preserveSubscription = true;
1210
+ return { kind: "resume" };
1211
+ }
1212
+ }
1213
+ const pluginThreadConfig = await options.buildLoadedPluginThreadConfig(binding);
1214
+ assertWarmOwner();
1215
+ if (pluginThreadConfig && pluginThreadConfig.fingerprint !== binding.pluginAppsFingerprint) return { kind: "rotate" };
1216
+ const prebuiltFinalConfigPatch = await prepareCodexThreadFinalConfigPatch(params, options.nativeModelInputTools, binding);
1217
+ const pluginAppsConfigPatch = pluginThreadConfig?.configPatch ?? (params.pluginThreadConfig?.enabled && binding.pluginAppPolicyContext ? buildCodexPluginAppsConfigPatchFromPolicyContext(binding.pluginAppPolicyContext) : void 0);
1218
+ const resumeAuthProfileId = binding.connectionScope === "supervision" ? void 0 : params.params.authProfileId ?? binding.authProfileId;
1219
+ const resumeConfig = mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginAppsConfigPatch, prebuiltFinalConfigPatch.configPatch);
1220
+ const resumeParams = lifecycleTiming.measureSync("warm-thread-resume-params", () => buildThreadResumeParams(params.params, {
1221
+ ...params,
1222
+ threadId: binding.threadId,
1223
+ authProfileId: resumeAuthProfileId,
1224
+ model: startModelSelection.model,
1225
+ modelProvider: startModelProvider,
1226
+ preserveNativeModel: binding.preserveNativeModel === true,
1227
+ config: applyCodexNativeSkillIsolation(resumeConfig, nativeSkillIsolation),
1228
+ hostSystemAgentActive,
1229
+ restrictedToolSurfaceInheritedMcpServerNames
1230
+ }));
1231
+ assertCodexInferenceRouteConfig(params.client, params.inferenceRoute, resumeParams.config, resumeParams.modelProvider ?? (binding.preserveNativeModel ? nativeThread?.modelProvider?.trim() || binding.modelProvider : void 0), params.inferenceProviderRoutes);
1232
+ const liveThreadConfigFingerprint = incognito ? retainedThread.configFingerprint : fingerprintCodexThreadConfig({
1233
+ ...resumeParams,
1234
+ model: binding.preserveNativeModel ? null : binding.model ?? resumeParams.model ?? null,
1235
+ requestedModel: binding.preserveNativeModel ? null : resumeParams.model ?? null,
1236
+ modelProvider: binding.preserveNativeModel ? null : binding.modelProvider ?? resumeParams.modelProvider ?? null,
1237
+ requestedModelProvider: binding.preserveNativeModel ? null : resumeParams.modelProvider ?? binding.modelProvider ?? null
1238
+ }, resumeAuthProfileId, dynamicToolsFingerprint);
1239
+ const ephemeralPolicy = retainedThread.ephemeralPolicy;
1240
+ if (incognito && (!ephemeralPolicy || ephemeralPolicy.developerInstructions !== params.developerInstructions || getCodexInferenceThread(params.client, binding.threadId) !== params.inferenceRoute || [...params.inferenceProviderRoutes?.keys() ?? []].some((provider) => !getCodexInferenceThreadQualification(params.client, binding.threadId)?.hasProvider(provider)))) {
1241
+ preserveSubscription = true;
1242
+ throw new CodexIncognitoPolicyChangeError();
1243
+ }
1244
+ if (!incognito && retainedThread.configFingerprint !== liveThreadConfigFingerprint) {
1245
+ preserveSubscription = true;
1246
+ return {
1247
+ kind: "resume",
1248
+ prebuiltFinalConfigPatch
1249
+ };
1250
+ }
1251
+ await attestCodexThreadToolSurface({
1252
+ client: params.client,
1253
+ threadId: binding.threadId,
1254
+ appIds: pluginThreadConfig?.provisionalAppIds ?? [],
1255
+ signal: params.signal,
1256
+ threadConfig: resumeParams.config,
1257
+ restrictedToolSurface,
1258
+ lifecycleTiming,
1259
+ assertCurrent: assertWarmOwner
1260
+ });
1261
+ assertWarmOwner();
1262
+ if (ephemeralPolicy && ephemeralPolicy.skillsInstructions !== params.skillsInstructions) try {
1263
+ await refreshCodexThreadSkillsCatalog({
1264
+ client: params.client,
1265
+ threadId: binding.threadId,
1266
+ skillsInstructions: params.skillsInstructions,
1267
+ timeoutMs: params.appServer.requestTimeoutMs,
1268
+ signal: params.signal,
1269
+ assertCurrent: assertWarmOwner
1270
+ });
1271
+ } catch (error) {
1272
+ preserveSubscription = true;
1273
+ throw error;
1274
+ }
1275
+ const nativeHookRelayGeneration = prebuiltFinalConfigPatch.nativeHookRelayGeneration ?? binding.nativeHookRelayGeneration;
1276
+ const model = binding.preserveNativeModel ? nativeThread?.model?.trim() || binding.model : startModelSelection.model;
1277
+ const modelProvider = binding.preserveNativeModel ? nativeThread?.modelProvider?.trim() || binding.modelProvider : binding.modelProvider;
1278
+ if (!(incognito || await lifecycleTiming.measure("warm-thread-write-binding", () => params.bindingStore.mutate(bindingIdentity, {
1279
+ kind: "patch",
1280
+ threadId: binding.threadId,
1281
+ patch: {
1282
+ cwd: params.cwd,
1283
+ model,
1284
+ modelProvider,
1285
+ nativeHookRelayGeneration,
1286
+ environmentSelectionFingerprint
1287
+ }
1288
+ }, assertWarmOwner)))) throw new CodexThreadBindingConflictError(binding.threadId, "committing a reused thread");
1289
+ assertWarmOwner();
1290
+ lifecycleTiming.mark("thread-ready");
1291
+ lifecycleTiming.logSummary({
1292
+ runId: params.params.runId,
1293
+ sessionId: params.params.sessionId,
1294
+ sessionKey: params.params.sessionKey,
1295
+ threadId: binding.threadId,
1296
+ action: "resumed"
1297
+ });
1298
+ ownershipTransferred = true;
1299
+ return {
1300
+ kind: "ready",
1301
+ binding: {
1302
+ ...binding,
1303
+ ...!incognito ? {
1304
+ cwd: params.cwd,
1305
+ model,
1306
+ modelProvider,
1307
+ nativeHookRelayGeneration,
1308
+ environmentSelectionFingerprint
1309
+ } : {},
1310
+ liveThreadConfigFingerprint,
1311
+ liveThreadEphemeralPolicy: ephemeralPolicy && {
1312
+ ...ephemeralPolicy,
1313
+ skillsInstructions: params.skillsInstructions
1314
+ },
1315
+ liveThreadOwnership: retainedThread,
1316
+ ...!incognito && retainedThread.serviceTier && resumeParams.serviceTier === void 0 ? { clearInheritedServiceTier: true } : {},
1317
+ lifecycle: { action: "resumed" }
1318
+ }
1319
+ };
1320
+ } finally {
1321
+ if (!ownershipTransferred) {
1322
+ let failure;
1323
+ try {
1324
+ if (preserveSubscription) try {
1325
+ assertWarmOwner();
1326
+ preserveSubscription = isSameCodexAppServerThreadOwner(params.bindingStore.read(bindingIdentity), binding);
1327
+ } catch {
1328
+ preserveSubscription = false;
1329
+ }
1330
+ if (preserveSubscription) {
1331
+ if (!await retainCodexAppServerBindingSubscription(params.client, binding.threadId, retainedThread)) failure = { cause: /* @__PURE__ */ new Error("Codex live thread ownership could not be returned to its session") };
1332
+ } else await retainedThread.release(binding.threadId);
1333
+ } catch (cause) {
1334
+ failure = { cause };
1335
+ }
1336
+ if (failure) await abandonCodexLiveThreadRelease({
1337
+ client: params.client,
1338
+ abandonClient: params.abandonClient,
1339
+ lifecycleTiming,
1340
+ threadId: binding.threadId
1341
+ }, failure.cause);
1342
+ }
1343
+ }
1344
+ }
1345
+ //#endregion
1346
+ //#region extensions/codex/src/app-server/thread-lifecycle-adoption.ts
1347
+ /** All bound preparation follows attach's native-queue-before-binding-lease order. */
1348
+ async function withCodexThreadLifecycleBinding(params, run) {
1349
+ const identity = sessionBindingIdentity({
1350
+ sessionId: params.params.sessionId,
1351
+ sessionKey: params.params.sessionKey,
1352
+ agentId: params.agentId ?? params.params.agentId,
1353
+ config: params.params.config
1354
+ });
1355
+ const { binding: snapshot, assertCurrent } = await resolveCodexSessionBinding({
1356
+ reclaimStale: true,
1357
+ bindingStore: params.bindingStore,
1358
+ identity,
1359
+ config: params.params.config,
1360
+ storePath: params.params.sessionTarget?.storePath,
1361
+ assertCurrent: () => {
1362
+ params.params.hostCapabilities.assertActive();
1363
+ params.assertCurrent?.();
1364
+ },
1365
+ signal: params.signal,
1366
+ assertBinding: params.params.expectedSessionRuntimeOwnership ? (binding) => assertCodexSessionRuntimeOwnership(binding, params.params.expectedSessionRuntimeOwnership) : void 0
1367
+ });
1368
+ const runWithLease = () => params.bindingStore.withLease(identity, async () => {
1369
+ const binding = params.bindingStore.read(identity);
1370
+ assertCodexSessionRuntimeOwnership(binding, params.params.expectedSessionRuntimeOwnership);
1371
+ if (binding?.threadId !== snapshot?.threadId || binding?.clientId !== snapshot?.clientId) throw new CodexThreadBindingConflictError(binding?.threadId ?? snapshot?.threadId ?? params.params.sessionId, "acquiring thread lifecycle ownership");
1372
+ assertCurrent();
1373
+ return await run(identity, binding, assertCurrent);
1374
+ });
1375
+ return snapshot?.pendingResumeConfiguration ? await withExclusiveCodexAppServerThread({
1376
+ bindingStore: params.bindingStore,
1377
+ identity,
1378
+ threadId: snapshot.threadId,
1379
+ run: runWithLease
1380
+ }) : snapshot ? await withCodexAppServerThreadMutation(snapshot.threadId, runWithLease) : await runWithLease();
1381
+ }
1382
+ /** Completes manual attachment only under the native queue and exact binding lease. */
1383
+ async function resumePendingCodexThread(params, context) {
1384
+ const { binding, contextEngineBinding, lifecycleTiming, restrictedToolSurface } = context;
1385
+ if (isIncognitoSessionKey(params.params.sessionKey) || context.transientRestriction || !restrictedToolSurface && binding.nativeToolPolicyRestricted === true || (contextEngineBinding ? !isContextEngineBindingCompatible(binding.contextEngine, contextEngineBinding) : binding.contextEngine !== void 0) || shouldRotateCodexGpt56MultiAgentBinding({
1386
+ bindingModel: binding.model,
1387
+ requestedModel: params.params.modelId
1388
+ })) throw new Error(`Cannot configure resumed Codex thread ${binding.threadId} under a transient or incompatible session policy. The thread is preserved; retry from its normal session or use /new for the current policy.`);
1389
+ const prebuiltPluginThreadConfig = params.pluginThreadConfig?.enabled ? await lifecycleTiming.measure("plugin-config-build", () => params.pluginThreadConfig?.build()) : void 0;
1390
+ const clientId = resolveCodexAppServerClientInstanceId(params.client);
1391
+ const resumed = await resumeExistingCodexThread(params, {
1392
+ ...context,
1393
+ prebuiltPluginThreadConfig,
1394
+ prepareResume: () => preparePendingCodexThreadResume(params, binding, context.dynamicToolsFingerprint),
1395
+ releaseRetainedThread: async (assertCurrent) => {
1396
+ const released = await context.releaseRetainedThread(binding.threadId, assertCurrent);
1397
+ assertCurrent();
1398
+ if (!released || binding.clientId && binding.clientId !== clientId) await releaseCodexConsumedLiveThread({
1399
+ client: params.client,
1400
+ abandonClient: params.abandonClient,
1401
+ lifecycleTiming,
1402
+ threadId: binding.threadId,
1403
+ assertCurrent
1404
+ });
1405
+ }
1406
+ });
1407
+ if (!resumed) throw new Error(`Codex did not configure resumed thread ${binding.threadId}.`);
1408
+ return resumed;
1409
+ }
1410
+ /** Manual attachment is intent, never evidence that loaded native overrides took effect. */
1411
+ async function preparePendingCodexThreadResume(params, binding, dynamicToolsFingerprint) {
1412
+ const fail = (reason) => /* @__PURE__ */ new Error(`Cannot configure resumed Codex thread ${binding.threadId}: ${reason}. The thread is preserved; continue it in native Codex or use /new for the current OpenClaw tools.`);
1413
+ const agentDir = resolveCodexThreadAgentDir(params);
1414
+ const localHome = resolveCodexAppServerLocalHomeDir(params.appServer.start, agentDir);
1415
+ if (params.appServer.start.transport !== "stdio" || params.appServer.start.homeScope === "user" || path.resolve(localHome) !== resolveCodexAppServerHomeDir(agentDir) || binding.connectionScope === "supervision" || binding.preserveNativeModel === true) throw fail("configuration adoption requires an OpenClaw-owned local Codex home");
1416
+ if (isCodexAppServerLiveThreadClaimed(params.client, binding.threadId)) throw fail("the thread is claimed by active work; stop that run before resuming");
1417
+ const assertClient = captureCodexAppServerClientLifetime(params.client, "native-process");
1418
+ const assertCurrent = () => {
1419
+ params.params.hostCapabilities.assertActive();
1420
+ params.assertCurrent?.();
1421
+ params.signal?.throwIfAborted();
1422
+ assertClient();
1423
+ if (isCodexAppServerLiveThreadClaimed(params.client, binding.threadId)) throw new CodexAdoptedThreadActiveError();
1424
+ };
1425
+ assertCurrent();
1426
+ const { thread } = await params.client.request("thread/read", {
1427
+ threadId: binding.threadId,
1428
+ includeTurns: false
1429
+ }, {
1430
+ signal: params.signal,
1431
+ assertCurrent
1432
+ });
1433
+ assertCurrent();
1434
+ if (thread.id !== binding.threadId || !isCodexThreadNonRunning(thread.status)) throw fail("the native thread is not idle; wait for its current run to finish");
1435
+ assertCodexThreadAcceptsDirectInput(thread);
1436
+ const observation = observeCodexThreadConfiguration(params, thread, assertCurrent);
1437
+ const dispose = observation.dispose;
1438
+ try {
1439
+ const rolloutPath = thread.path ?? binding.rolloutPath;
1440
+ const metadata = rolloutPath ? await readCodexSessionMeta(path.join(localHome, "sessions"), rolloutPath, binding.threadId) : void 0;
1441
+ if (!metadata) throw fail("its native tool catalog could not be read from the selected Codex home");
1442
+ const recordedTools = metadata.dynamic_tools ?? [];
1443
+ if (!Array.isArray(recordedTools) || codexDynamicToolsFingerprint(recordedTools) !== dynamicToolsFingerprint) throw fail("its immutable native tool catalog does not match the current OpenClaw tools");
1444
+ assertCurrent();
1445
+ return {
1446
+ ...observation,
1447
+ assertCurrent
1448
+ };
1449
+ } catch (error) {
1450
+ dispose();
1451
+ throw error;
1452
+ }
1453
+ }
1454
+ /** Observe teardown before release; a successful resume alone can acknowledge ignored overrides. */
1455
+ async function prepareCodexThreadResume(params, binding, context) {
1456
+ const assertClient = captureCodexAppServerClientLifetime(params.client, binding.connectionScope === "supervision" ? "connection" : "thread-configuration");
1457
+ const assertCurrent = () => {
1458
+ params.params.hostCapabilities.assertActive();
1459
+ params.assertCurrent?.();
1460
+ params.signal?.throwIfAborted();
1461
+ assertClient();
1462
+ if (isCodexAppServerLiveThreadClaimed(params.client, binding.threadId)) throw new CodexAdoptedThreadActiveError();
1463
+ };
1464
+ assertCurrent();
1465
+ let thread;
1466
+ try {
1467
+ thread = await assertAdoptedCodexThreadResumeAllowed(params, binding.threadId, context, assertCurrent);
1468
+ } finally {
1469
+ assertCurrent();
1470
+ }
1471
+ assertCodexSupervisionThreadLineage(binding, thread);
1472
+ return {
1473
+ ...observeCodexThreadConfiguration(params, thread, assertCurrent),
1474
+ assertCurrent
1475
+ };
1476
+ }
1477
+ function isCodexThreadNonRunning(status) {
1478
+ return status?.type === "idle" || status?.type === "notLoaded" || status?.type === "systemError";
1479
+ }
1480
+ function observeCodexThreadConfiguration(params, thread, assertCurrent) {
1481
+ if (!isCodexThreadNonRunning(thread.status)) throw new CodexAdoptedThreadActiveError();
1482
+ const settledSystemError = thread.status.type === "systemError";
1483
+ let unloaded = thread.status.type === "notLoaded";
1484
+ const dispose = params.client.addNotificationHandler((notification) => {
1485
+ 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;
1486
+ });
1487
+ return {
1488
+ modelProvider: thread.modelProvider,
1489
+ dispose,
1490
+ settledSystemError,
1491
+ assertConfigured: () => {
1492
+ assertCurrent();
1493
+ 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.");
1494
+ }
1495
+ };
1496
+ }
1497
+ //#endregion
1498
+ //#region extensions/codex/src/app-server/thread-supervision.ts
1499
+ async function materializePendingSupervisionBranch(params) {
1500
+ let pending = params.binding.pendingSupervisionBranch;
1501
+ const requestOptions = {
1502
+ signal: params.signal,
1503
+ assertCurrent: params.throwIfAborted
1504
+ };
1505
+ const connectionFingerprint = buildCodexAppServerConnectionFingerprint(params.appServer, params.attempt.agentDir);
1506
+ if (!pending.connectionFingerprint || pending.connectionFingerprint !== connectionFingerprint) throw new Error("Codex supervision source connection changed before branch materialization");
1507
+ pending = await recoverPendingSupervisionArtifacts(params, pending);
1508
+ params.throwIfAborted();
1509
+ const sourceResponse = await params.lifecycleTiming.measure("supervision-source-read", () => params.client.request("thread/read", {
1510
+ threadId: pending.sourceThreadId,
1511
+ includeTurns: true
1512
+ }, requestOptions));
1513
+ params.throwIfAborted();
1514
+ const sourceThread = sourceResponse.thread;
1515
+ if (sourceThread.id !== pending.sourceThreadId) throw new Error(`Codex supervision source read returned ${sourceThread.id} for ${pending.sourceThreadId}`);
1516
+ assertPendingSupervisionSnapshotUnchanged(sourceThread, pending);
1517
+ const history = projectBoundedCodexThreadHistory({
1518
+ thread: sourceThread,
1519
+ throughTurnId: pending.lastTurnId ?? null,
1520
+ importedAt: Date.now(),
1521
+ modelProvider: sourceThread.modelProvider
1522
+ });
1523
+ let bindingCommitted = false;
1524
+ let provisionalCleanupSafe = true;
1525
+ let cleanupExpected = pending;
1526
+ const trackPendingSupervisionArtifacts = async (cleanupThreadIds) => {
1527
+ const expected = pending;
1528
+ pending = withPendingSupervisionCleanup(pending, cleanupThreadIds);
1529
+ let updated;
1530
+ try {
1531
+ updated = await params.bindingStore.mutate(params.bindingIdentity, {
1532
+ kind: "patch-pending-supervision-branch",
1533
+ expected,
1534
+ pending
1535
+ });
1536
+ } catch (error) {
1537
+ try {
1538
+ const current = params.bindingStore.read(params.bindingIdentity);
1539
+ if (matchesPendingSupervisionState(current, pending)) cleanupExpected = pending;
1540
+ else if (matchesPendingSupervisionState(current, expected)) cleanupExpected = expected;
1541
+ else throw new CodexThreadBindingConflictError(pending.sourceThreadId, "verifying supervised Codex cleanup tracking");
1542
+ } catch (verificationError) {
1543
+ provisionalCleanupSafe = false;
1544
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex supervised branch cleanup tracking could not be verified: ${cleanupThreadIds.join(", ")}`, { cause: new AggregateError([error, verificationError], void 0, { cause: error }) });
1545
+ }
1546
+ throw error;
1547
+ }
1548
+ cleanupExpected = updated ? pending : void 0;
1549
+ if (!updated) throw new CodexThreadBindingConflictError(pending.sourceThreadId, "tracking supervised Codex branch cleanup");
1550
+ };
1551
+ try {
1552
+ const probeParams = buildPendingSupervisionProbeForkParams(params, pending);
1553
+ const rawProbeResponse = await params.lifecycleTiming.measure("supervision-model-probe-fork", async () => {
1554
+ try {
1555
+ return await params.client.request("thread/fork", probeParams, requestOptions);
1556
+ } catch (error) {
1557
+ if (!(error instanceof CodexAppServerRpcError)) throw new CodexAppServerUnsafeSubscriptionError("Codex model probe fork may have materialized without a response", { cause: error });
1558
+ throw error;
1559
+ }
1560
+ });
1561
+ const probeThreadId = requireDistinctSupervisionThreadId({
1562
+ threadId: readSupervisionResponseThreadId(rawProbeResponse),
1563
+ sourceThreadId: pending.sourceThreadId,
1564
+ role: "model probe"
1565
+ });
1566
+ let probeResponse;
1567
+ try {
1568
+ params.throwIfAborted();
1569
+ probeResponse = assertCodexThreadForkResponse(rawProbeResponse);
1570
+ if (params.restrictedToolSurface) await params.lifecycleTiming.measure("restricted-tool-surface-mcp-attestation", () => attestCodexRestrictedToolSurfaceMcpServersDisabled(params.client, probeThreadId, probeParams.config ?? void 0, params.signal));
1571
+ } finally {
1572
+ await unsubscribeCodexAppServerLiveThread(params.client, probeThreadId, CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS).catch((cause) => {
1573
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex model probe subscription could not be released: ${probeThreadId}`, { cause });
1574
+ });
1575
+ }
1576
+ params.throwIfAborted();
1577
+ const nativeModel = requireNonBlankSupervisionValue(probeResponse.model, "native model");
1578
+ const nativeModelProvider = requireNativeSupervisionModelProvider({
1579
+ responseModelProvider: probeResponse.modelProvider,
1580
+ responseThreadModelProvider: probeResponse.thread.modelProvider
1581
+ });
1582
+ const nativeAttempt = {
1583
+ ...params.attempt,
1584
+ modelId: nativeModel
1585
+ };
1586
+ const startParams = buildThreadStartParams(nativeAttempt, {
1587
+ ...params,
1588
+ model: nativeModel,
1589
+ modelProvider: nativeModelProvider
1590
+ });
1591
+ assertExactSupervisionModelSelection(startParams, {
1592
+ model: nativeModel,
1593
+ modelProvider: nativeModelProvider,
1594
+ operation: "thread/start request"
1595
+ });
1596
+ const rawStartResponse = await params.lifecycleTiming.measure("supervision-thread-start", async () => {
1597
+ try {
1598
+ return await params.client.request("thread/start", startParams, requestOptions);
1599
+ } catch (error) {
1600
+ if (error instanceof CodexAppServerRpcError) throw new CodexThreadStartRequestError(error);
1601
+ throw new CodexAppServerUnsafeSubscriptionError("Canonical Codex branch may have started without a response", { cause: error });
1602
+ }
1603
+ });
1604
+ const finalThreadId = requireDistinctSupervisionThreadId({
1605
+ threadId: readSupervisionResponseThreadId(rawStartResponse),
1606
+ sourceThreadId: pending.sourceThreadId,
1607
+ otherThreadId: probeThreadId,
1608
+ role: "canonical branch"
1609
+ });
1610
+ await trackPendingSupervisionArtifacts([finalThreadId]);
1611
+ params.throwIfAborted();
1612
+ const startResponse = assertCodexThreadStartResponse(rawStartResponse);
1613
+ assertExactSupervisionModelSelection(startResponse, {
1614
+ model: nativeModel,
1615
+ modelProvider: nativeModelProvider,
1616
+ operation: "thread/start response"
1617
+ });
1618
+ if (params.restrictedToolSurface) await params.lifecycleTiming.measure("restricted-tool-surface-mcp-attestation", () => attestCodexRestrictedToolSurfaceMcpServersDisabled(params.client, finalThreadId, startParams.config, params.signal));
1619
+ if (params.provisionalAppIds?.length) try {
1620
+ await params.lifecycleTiming.measure("plugin-app-attestation", () => checkCodexThreadAppAvailability({
1621
+ client: params.client,
1622
+ threadId: finalThreadId,
1623
+ appIds: params.provisionalAppIds ?? [],
1624
+ signal: params.signal
1625
+ }));
1626
+ } catch (error) {
1627
+ if (!await discardUnattestedCodexPluginThread({
1628
+ client: params.client,
1629
+ threadId: finalThreadId,
1630
+ ephemeral: startParams.ephemeral === true
1631
+ })) {
1632
+ provisionalCleanupSafe = false;
1633
+ throw new CodexAppServerUnsafeSubscriptionError("Codex supervised plugin app attestation cleanup failed", { cause: error });
1634
+ }
1635
+ await trackPendingSupervisionArtifacts([]);
1636
+ throw error;
1637
+ }
1638
+ if (history.responseItems.length > 0) {
1639
+ await params.lifecycleTiming.measure("supervision-history-inject", () => params.client.request("thread/inject_items", {
1640
+ threadId: finalThreadId,
1641
+ items: history.responseItems
1642
+ }, requestOptions));
1643
+ params.throwIfAborted();
1644
+ }
1645
+ const historyCoveredThrough = (/* @__PURE__ */ new Date()).toISOString();
1646
+ const bindingModelProvider = params.normalizeBindingModelProvider(params.attempt.authProfileId, nativeModelProvider);
1647
+ let committed = false;
1648
+ try {
1649
+ committed = await params.bindingStore.mutate(params.bindingIdentity, {
1650
+ kind: "commit-pending-supervision-branch",
1651
+ expected: pending,
1652
+ threadId: finalThreadId,
1653
+ patch: {
1654
+ ...params.bindingPatch,
1655
+ model: nativeModel,
1656
+ modelProvider: bindingModelProvider,
1657
+ historyCoveredThrough
1658
+ }
1659
+ }, params.throwIfAborted);
1660
+ } catch (error) {
1661
+ let current;
1662
+ try {
1663
+ current = params.bindingStore.read(params.bindingIdentity);
1664
+ } catch (readError) {
1665
+ provisionalCleanupSafe = false;
1666
+ throw new CodexAppServerUnsafeSubscriptionError(`Canonical Codex branch binding could not be verified: ${finalThreadId}`, { cause: new AggregateError([error, readError]) });
1667
+ }
1668
+ if (matchesMaterializedSupervisionBranch(current, {
1669
+ sourceThreadId: pending.sourceThreadId,
1670
+ connectionFingerprint,
1671
+ threadId: finalThreadId,
1672
+ model: nativeModel,
1673
+ modelProvider: bindingModelProvider,
1674
+ historyCoveredThrough
1675
+ })) committed = true;
1676
+ else {
1677
+ if (!matchesPendingSupervisionState(current, pending)) {
1678
+ provisionalCleanupSafe = false;
1679
+ throw new CodexAppServerUnsafeSubscriptionError(`Canonical Codex branch binding changed while commit was uncertain: ${finalThreadId}`, { cause: error });
1680
+ }
1681
+ throw error;
1682
+ }
1683
+ }
1684
+ if (!committed) throw new CodexThreadBindingConflictError(pending.sourceThreadId, "committing a supervised Codex branch");
1685
+ bindingCommitted = true;
1686
+ params.lifecycleTiming.mark("thread-ready");
1687
+ params.lifecycleTiming.logSummary({
1688
+ runId: params.attempt.runId,
1689
+ sessionId: params.attempt.sessionId,
1690
+ sessionKey: params.attempt.sessionKey,
1691
+ threadId: finalThreadId,
1692
+ action: "forked"
1693
+ });
1694
+ return {
1695
+ ...params.binding,
1696
+ ...params.bindingPatch,
1697
+ threadId: finalThreadId,
1698
+ pendingSupervisionBranch: void 0,
1699
+ model: nativeModel,
1700
+ modelProvider: bindingModelProvider,
1701
+ historyCoveredThrough,
1702
+ lifecycle: { action: "forked" }
1703
+ };
1704
+ } catch (error) {
1705
+ if (bindingCommitted) throw error;
1706
+ if (!provisionalCleanupSafe) {
1707
+ await params.abandonClient();
1708
+ throw error;
1709
+ }
1710
+ const cleanup = await cleanPendingSupervisionArtifacts(params.client, pending);
1711
+ const nextPending = withPendingSupervisionCleanup(pending, cleanup.remaining);
1712
+ let cleanupStateError;
1713
+ if (cleanupExpected && !isDeepStrictEqual(cleanupExpected, nextPending)) try {
1714
+ await params.bindingStore.mutate(params.bindingIdentity, {
1715
+ kind: "patch-pending-supervision-branch",
1716
+ expected: cleanupExpected,
1717
+ pending: nextPending
1718
+ });
1719
+ } catch (stateError) {
1720
+ cleanupStateError = stateError;
1721
+ }
1722
+ const unsafeCleanup = cleanup.remaining.length > 0 || isCodexAppServerUnsafeSubscriptionError(error);
1723
+ if (unsafeCleanup) await params.abandonClient();
1724
+ if (cleanupStateError) {
1725
+ const cause = new AggregateError([error, cleanupStateError], "Codex supervised branch cleanup state could not be recorded", { cause: error });
1726
+ if (unsafeCleanup) throw new CodexAppServerUnsafeSubscriptionError("Codex supervised branch cleanup state could not be recorded", { cause });
1727
+ throw cause;
1728
+ }
1729
+ if (cleanup.remaining.length > 0) throw new CodexAppServerUnsafeSubscriptionError(`Codex supervised branch cleanup remains pending: ${cleanup.remaining.join(", ")}`, { cause: error });
1730
+ throw error;
1731
+ }
1732
+ }
1733
+ function buildPendingSupervisionProbeForkParams(params, pending) {
1734
+ const runtimeConfig = buildCodexRuntimeThreadConfigForRun(params.attempt, params.config, params);
1735
+ return {
1736
+ threadId: pending.sourceThreadId,
1737
+ ...pending.lastTurnId ? { lastTurnId: pending.lastTurnId } : {},
1738
+ cwd: params.cwd,
1739
+ approvalPolicy: params.appServer.approvalPolicy,
1740
+ approvalsReviewer: resolveCodexThreadApprovalsReviewer(params.appServer, runtimeConfig),
1741
+ ...codexThreadSandboxOrPermissions(params.appServer),
1742
+ ...params.appServer.serviceTier !== void 0 ? { serviceTier: params.appServer.serviceTier } : {},
1743
+ config: runtimeConfig,
1744
+ developerInstructions: params.developerInstructions ?? buildDeveloperInstructions(params.attempt, { dynamicTools: params.dynamicTools }),
1745
+ ephemeral: true,
1746
+ threadSource: "appServer",
1747
+ excludeTurns: true
1748
+ };
1749
+ }
1750
+ function assertPendingSupervisionSnapshotUnchanged(thread, pending) {
1751
+ if (pending.lastTurnId) return;
1752
+ if (thread.status?.type === "active" || (thread.turns?.length ?? 0) > 0) throw new Error("Codex source changed after Continue; reopen the source session before sending a message");
1753
+ }
1754
+ function requireNonBlankSupervisionValue(value, label) {
1755
+ if (typeof value !== "string" || !value.trim()) throw new Error(`Codex supervision ${label} is missing`);
1756
+ return value.trim();
1757
+ }
1758
+ function requireNativeSupervisionModelProvider(params) {
1759
+ const responseProvider = requireNonBlankSupervisionValue(params.responseModelProvider, "native model provider");
1760
+ const threadProvider = params.responseThreadModelProvider?.trim();
1761
+ if (threadProvider && threadProvider !== responseProvider) throw new Error(`Codex supervision model provider mismatch: ${responseProvider} != ${threadProvider}`);
1762
+ return responseProvider;
1763
+ }
1764
+ function matchesPendingSupervisionState(binding, expected) {
1765
+ return binding?.connectionScope === "supervision" && binding.supervisionSourceThreadId === expected.sourceThreadId && matchesPendingSupervisionBranch(binding, expected);
1766
+ }
1767
+ function matchesMaterializedSupervisionBranch(binding, expected) {
1768
+ return binding?.threadId === expected.threadId && binding.connectionScope === "supervision" && binding.supervisionSourceThreadId === expected.sourceThreadId && binding.appServerRuntimeFingerprint === expected.connectionFingerprint && binding.pendingSupervisionBranch === void 0 && binding.model === expected.model && binding.modelProvider === expected.modelProvider && binding.historyCoveredThrough === expected.historyCoveredThrough;
1769
+ }
1770
+ function requireDistinctSupervisionThreadId(params) {
1771
+ let threadId;
1772
+ try {
1773
+ threadId = requireNonBlankSupervisionValue(params.threadId, `${params.role} thread id`);
1774
+ } catch (error) {
1775
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex supervision ${params.role} may have materialized without a safe thread id`, { cause: error });
1776
+ }
1777
+ if (threadId === params.sourceThreadId || threadId === params.otherThreadId) throw new CodexAppServerUnsafeSubscriptionError(`Codex supervision ${params.role} reused an existing thread: ${threadId}`);
1778
+ return threadId;
1779
+ }
1780
+ async function recoverPendingSupervisionArtifacts(params, pending) {
1781
+ if (!pending.cleanupThreadIds?.length) return pending;
1782
+ const cleanup = await cleanPendingSupervisionArtifacts(params.client, pending);
1783
+ const next = withPendingSupervisionCleanup(pending, cleanup.remaining);
1784
+ if (cleanup.remaining.length > 0) {
1785
+ if (cleanup.remaining.length !== pending.cleanupThreadIds.length) {
1786
+ if (!await params.bindingStore.mutate(params.bindingIdentity, {
1787
+ kind: "patch-pending-supervision-branch",
1788
+ expected: pending,
1789
+ pending: next
1790
+ })) throw new CodexThreadBindingConflictError(pending.sourceThreadId, "recording supervised Codex cleanup recovery");
1791
+ }
1792
+ throw new Error(`Codex supervised branch cleanup must finish before retry: ${cleanup.remaining.join(", ")}`);
1793
+ }
1794
+ if (!await params.bindingStore.mutate(params.bindingIdentity, {
1795
+ kind: "patch-pending-supervision-branch",
1796
+ expected: pending,
1797
+ pending: next
1798
+ })) throw new CodexThreadBindingConflictError(pending.sourceThreadId, "recovering a supervised Codex branch");
1799
+ return next;
1800
+ }
1801
+ function withPendingSupervisionCleanup(pending, cleanupThreadIds) {
1802
+ return {
1803
+ sourceThreadId: pending.sourceThreadId,
1804
+ ...pending.connectionFingerprint ? { connectionFingerprint: pending.connectionFingerprint } : {},
1805
+ ...pending.lastTurnId ? { lastTurnId: pending.lastTurnId } : {},
1806
+ ...cleanupThreadIds.length > 0 ? { cleanupThreadIds } : {}
1807
+ };
1808
+ }
1809
+ async function cleanPendingSupervisionArtifacts(client, pending) {
1810
+ const remaining = [];
1811
+ for (const threadId of pending.cleanupThreadIds ?? []) if (!await archiveSupervisionArtifact(client, threadId)) remaining.push(threadId);
1812
+ return { remaining };
1813
+ }
1814
+ async function archiveSupervisionArtifact(client, threadId) {
1815
+ try {
1816
+ await client.request("thread/archive", { threadId }, { timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS });
1817
+ return true;
1818
+ } catch (error) {
1819
+ const message = formatErrorMessage(error).toLowerCase();
1820
+ if (message.includes("no rollout found for thread id") || message.includes("thread not found") || message.includes("already archived")) return true;
1821
+ await unsubscribeCodexThreadBestEffort(client, {
1822
+ threadId,
1823
+ timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
1824
+ });
1825
+ embeddedAgentLog.warn("failed to archive temporary Codex supervision thread", {
1826
+ threadId,
1827
+ error
1828
+ });
1829
+ return false;
1830
+ }
1831
+ }
1832
+ //#endregion
1833
+ //#region extensions/codex/src/app-server/thread-lifecycle-run.ts
1834
+ async function startOrResumeThread(input) {
1835
+ const incognito = isIncognitoSessionKey(input.params.sessionKey);
1836
+ const clientId = resolveCodexAppServerClientInstanceId(input.client);
1837
+ return await withCodexThreadLifecycleBinding(input, async (bindingIdentity, saved, assert) => {
1838
+ const params = {
1839
+ ...input,
1840
+ assertCurrent: assert
1841
+ };
1842
+ const expectedOwnership = params.params.expectedSessionRuntimeOwnership;
1843
+ let binding = saved;
1844
+ let selectionBinding = binding;
1845
+ if (hasCodexNativeToolCatalog(binding)) {
1846
+ const nativeCatalog = await loadCodexNativeToolCatalog({
1847
+ client: params.client,
1848
+ binding,
1849
+ appServer: params.appServer,
1850
+ agentDir: resolveCodexThreadAgentDir(params),
1851
+ assertCurrent: () => {
1852
+ params.signal?.throwIfAborted();
1853
+ assert();
1854
+ }
1855
+ });
1856
+ if (!isDeepStrictEqual(params.dynamicTools, nativeCatalog)) throw new Error("Canonical Codex declarations changed after tool preparation; retry the turn on its preserved native thread.");
1857
+ }
1858
+ const preflight = await prepareCodexThreadLifecyclePreflight(params);
1859
+ const callerConfig = params.config;
1860
+ const { contextEngineBinding, dynamicToolsContainDeferred, dynamicToolsFingerprint, hostSystemAgentActive, legacyDynamicToolsFingerprint, legacyUserMcpServersFingerprint, lifecycleTiming, nativeSkillIsolation, nativeSkillIsolationFingerprint, networkProxyConfigFingerprint, ringZeroActive, ringZeroClientInstanceId, ringZeroConfigFingerprint, restrictedToolSurface, restrictedToolSurfaceInheritedMcpServerNames, userMcpServersConfigPatch, userMcpServersFingerprint, webSearchThreadConfigFingerprint } = preflight;
1861
+ let replacementPredecessor;
1862
+ const initialBoundThreadId = binding?.threadId;
1863
+ const initialBoundClientId = binding?.clientId;
1864
+ const throwIfAborted = () => throwIfCodexThreadLifecycleAborted(params.signal);
1865
+ const prepareRequestContext = async () => {
1866
+ const context = await prepareCodexThreadRequestContext(params, {
1867
+ binding,
1868
+ selectionBinding,
1869
+ bindingIdentity,
1870
+ clientId,
1871
+ config: callerConfig,
1872
+ preflight,
1873
+ assertCurrent: assert,
1874
+ throwIfAborted
1875
+ });
1876
+ params.skillsInstructions = params.inferenceRoute ? void 0 : input.skillsInstructions;
1877
+ return context;
1878
+ };
1879
+ const releaseRetainedThread = (threadId, ownerClientId = initialBoundClientId, assertCurrent) => releaseCodexBoundLiveThread({
1880
+ client: params.client,
1881
+ clientId,
1882
+ ownerClientId,
1883
+ abandonClient: params.abandonClient,
1884
+ lifecycleTiming,
1885
+ threadId,
1886
+ assertCurrent
1887
+ });
1888
+ if (binding?.pendingSupervisionBranch) {
1889
+ const requestContext = await prepareRequestContext();
1890
+ await releaseRetainedThread(binding.threadId);
1891
+ const pendingBinding = binding;
1892
+ const pluginThreadConfig = params.pluginThreadConfig?.enabled ? await lifecycleTiming.measure("plugin-config-build", () => params.pluginThreadConfig?.build()) : void 0;
1893
+ const finalConfigPatch = await prepareCodexThreadFinalConfigPatch(params, requestContext.nativeModelInputTools);
1894
+ const config = lifecycleTiming.measureSync("merge-thread-config", () => applyCodexNativeSkillIsolation(mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginThreadConfig?.configPatch, finalConfigPatch.configPatch), nativeSkillIsolation));
1895
+ return publishCodexThreadInferenceBinding(params, await materializePendingSupervisionBranch({
1896
+ client: params.client,
1897
+ abandonClient: params.abandonClient ?? (() => closeCodexStartupClientBestEffort(params.client)),
1898
+ bindingStore: params.bindingStore,
1899
+ bindingIdentity,
1900
+ binding: pendingBinding,
1901
+ attempt: params.params,
1902
+ cwd: params.cwd,
1903
+ dynamicTools: params.dynamicTools,
1904
+ appServer: params.appServer,
1905
+ developerInstructions: params.developerInstructions,
1906
+ skillsInstructions: params.skillsInstructions,
1907
+ config,
1908
+ nativeCodeModeEnabled: params.nativeCodeModeEnabled,
1909
+ nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
1910
+ nativeCodeModeOnlyEnabled: params.nativeCodeModeOnlyEnabled,
1911
+ webSearchAllowed: params.webSearchAllowed,
1912
+ hostSystemAgentActive,
1913
+ restrictedToolSurface,
1914
+ restrictedToolSurfaceInheritedMcpServerNames,
1915
+ shellEnvironment: params.shellEnvironment,
1916
+ shellPathPrepend: params.shellPathPrepend,
1917
+ disableLoginShell: params.disableLoginShell,
1918
+ environmentSelection: params.environmentSelection,
1919
+ provisionalAppIds: pluginThreadConfig?.provisionalAppIds,
1920
+ signal: params.signal,
1921
+ throwIfAborted: () => {
1922
+ params.assertCurrent?.();
1923
+ assertCodexInferenceRouteConfig(params.client, params.inferenceRoute, config, void 0, params.inferenceProviderRoutes);
1924
+ },
1925
+ lifecycleTiming,
1926
+ normalizeBindingModelProvider: requestContext.normalizeBindingModelProvider,
1927
+ bindingPatch: {
1928
+ cwd: params.cwd,
1929
+ ...clientId ? { clientId } : {},
1930
+ authProfileId: void 0,
1931
+ agentWorkspaceDeveloperInstructions: params.agentWorkspaceDeveloperInstructions,
1932
+ preserveNativeModel: true,
1933
+ ...buildCodexThreadBindingPolicy(params, preflight),
1934
+ webSearchThreadConfigFingerprint,
1935
+ mcpServersFingerprint: params.mcpServersFingerprintEvaluated === true ? params.mcpServersFingerprint : pendingBinding.mcpServersFingerprint,
1936
+ nativeHookRelayGeneration: finalConfigPatch.nativeHookRelayGeneration,
1937
+ appServerRuntimeFingerprint: buildCodexAppServerConnectionFingerprint(params.appServer, params.params.agentDir),
1938
+ pluginAppsFingerprint: pluginThreadConfig?.fingerprint,
1939
+ pluginAppsInputFingerprint: pluginThreadConfig?.inputFingerprint,
1940
+ pluginAppPolicyContext: pluginThreadConfig?.policyContext,
1941
+ conversationSourceTransferComplete: true
1942
+ }
1943
+ }));
1944
+ }
1945
+ const clearCurrentBinding = async (operation) => {
1946
+ const current = binding;
1947
+ if (!current?.threadId) return;
1948
+ assertCodexBindingMayBeReplaced(current, operation, expectedOwnership);
1949
+ if (!await params.bindingStore.mutate(bindingIdentity, {
1950
+ kind: "clear",
1951
+ threadId: current.threadId
1952
+ }, assert)) throw new CodexThreadBindingConflictError(current.threadId, operation);
1953
+ binding = void 0;
1954
+ };
1955
+ const transientDelegationRestriction = params.params.delegationCapability === "report_only";
1956
+ const persistentWebSearchRestriction = params.webSearchAllowed === false && params.persistentWebSearchAllowed === false;
1957
+ const transientNativeToolRestriction = params.nativeCodeModeEnabled === false && !persistentWebSearchRestriction;
1958
+ const transientWebSearchRestriction = isTransientWebSearchRestriction(params);
1959
+ if (binding?.pendingResumeConfiguration) return publishCodexThreadInferenceBinding(params, await resumePendingCodexThread(params, {
1960
+ ...await prepareRequestContext(),
1961
+ binding,
1962
+ clearCurrentBinding,
1963
+ releaseRetainedThread: (threadId, assertCurrent) => releaseRetainedThread(threadId, initialBoundClientId, assertCurrent),
1964
+ transientRestriction: transientDelegationRestriction || transientNativeToolRestriction || transientWebSearchRestriction
1965
+ }));
1966
+ if (binding?.threadId && !restrictedToolSurface && binding.nativeToolPolicyRestricted === true) await clearCurrentBinding("rotating a host-policy-restricted thread binding");
1967
+ if (binding?.threadId && binding.nativeSkillIsolationFingerprint !== nativeSkillIsolationFingerprint) {
1968
+ embeddedAgentLog.debug("codex app-server native skill isolation changed; starting a new thread", { threadId: binding.threadId });
1969
+ await clearCurrentBinding("rotating stale native skill isolation");
1970
+ }
1971
+ if (binding?.threadId && (binding.ringZeroConfigFingerprint !== ringZeroConfigFingerprint || binding.ringZeroClientInstanceId !== ringZeroClientInstanceId) && (ringZeroActive || binding.ringZeroConfigFingerprint !== void 0)) {
1972
+ embeddedAgentLog.debug("codex app-server ring-zero restriction changed; rotating thread", { threadId: binding.threadId });
1973
+ await clearCurrentBinding("rotating a ring-zero thread binding");
1974
+ }
1975
+ if (binding?.threadId && shouldRotateCodexAppServerBindingForRuntime({
1976
+ connectionClass: params.appServer.connectionClass,
1977
+ current: binding.connectionScope === "supervision" ? buildCodexAppServerConnectionFingerprint(params.appServer, params.params.agentDir) : params.appServerRuntimeFingerprint,
1978
+ binding: binding.appServerRuntimeFingerprint
1979
+ })) {
1980
+ embeddedAgentLog.debug("codex app-server runtime identity changed; starting a new thread", {
1981
+ threadId: binding.threadId,
1982
+ connectionClass: params.appServer.connectionClass
1983
+ });
1984
+ await clearCurrentBinding("rotating a stale thread binding");
1985
+ }
1986
+ if (binding?.threadId && shouldRotateCodexGpt56MultiAgentBinding({
1987
+ bindingModel: binding.model,
1988
+ requestedModel: params.params.modelId
1989
+ })) {
1990
+ embeddedAgentLog.debug("codex app-server GPT-5.6 multi-agent version changed; starting a new thread", {
1991
+ threadId: binding.threadId,
1992
+ bindingModel: binding.model,
1993
+ requestedModel: params.params.modelId
1994
+ });
1995
+ await clearCurrentBinding("rotating a GPT-5.6 multi-agent thread binding");
1996
+ }
1997
+ selectionBinding = binding;
1998
+ let preserveExistingBinding = transientDelegationRestriction || !ringZeroActive && params.nativeProviderWebSearchSupport === "unknown" && !binding?.threadId;
1999
+ let rotatedContextEngineBinding = false;
2000
+ let prebuiltPluginThreadConfig;
2001
+ const buildLoadedPluginThreadConfig = async (current) => {
2002
+ if (!params.pluginThreadConfig?.requiresCurrentPolicyCheck && !shouldRecheckRecoverablePluginBinding({
2003
+ binding: current,
2004
+ pluginThreadConfig: params.pluginThreadConfig
2005
+ })) return;
2006
+ try {
2007
+ prebuiltPluginThreadConfig = await lifecycleTiming.measure("plugin-config-recovery", () => params.pluginThreadConfig?.build({ threadId: current.threadId }));
2008
+ } catch (error) {
2009
+ throwIfAborted();
2010
+ if (params.pluginThreadConfig?.requiresCurrentPolicyCheck) throw error;
2011
+ embeddedAgentLog.warn("codex app-server plugin app config recovery check failed", {
2012
+ error,
2013
+ threadId: current.threadId
2014
+ });
2015
+ return;
2016
+ }
2017
+ throwIfAborted();
2018
+ return prebuiltPluginThreadConfig;
2019
+ };
2020
+ const webSearchBindingChanged = binding?.threadId && binding.webSearchThreadConfigFingerprint !== webSearchThreadConfigFingerprint;
2021
+ const explicitTransientWebSearchRestriction = params.webSearchAllowed === false && params.persistentWebSearchAllowed !== false && transientWebSearchRestriction;
2022
+ const unknownProviderWebSearchSupport = params.nativeProviderWebSearchSupport === "unknown";
2023
+ if (binding?.threadId && (params.configuredMcpOwnershipVersion === 1 && (binding.configuredMcpOwnershipVersion !== 1 || binding.dynamicToolsFingerprint === void 0 || binding.mcpServersFingerprint !== void 0 || binding.userMcpServersFingerprint !== void 0) || params.configuredMcpOwnershipVersion !== 1 && binding.configuredMcpOwnershipVersion === 1) && binding?.threadId) {
2024
+ const predecessorBinding = binding;
2025
+ assertCodexBindingMayBeReplaced(predecessorBinding, "changing configured MCP ownership", expectedOwnership);
2026
+ embeddedAgentLog.debug("codex app-server configured MCP ownership changed; starting a new thread", { threadId: predecessorBinding.threadId });
2027
+ replacementPredecessor = predecessorBinding;
2028
+ binding = void 0;
2029
+ preserveExistingBinding = false;
2030
+ }
2031
+ if (binding?.threadId && params.mcpServersFingerprintEvaluated === true && binding.mcpServersFingerprint !== params.mcpServersFingerprint) {
2032
+ assertCodexBindingMayBeReplaced(binding, "changing MCP configuration", expectedOwnership);
2033
+ if (!ringZeroActive && (transientNativeToolRestriction || webSearchBindingChanged && (explicitTransientWebSearchRestriction || unknownProviderWebSearchSupport))) {
2034
+ embeddedAgentLog.debug("codex app-server MCP config changed during transient restricted turn; starting transient thread", { threadId: binding.threadId });
2035
+ preserveExistingBinding = true;
2036
+ } else {
2037
+ embeddedAgentLog.debug("codex app-server MCP config changed; starting a new thread", { threadId: binding.threadId });
2038
+ await clearCurrentBinding("rotating a stale thread binding");
2039
+ }
2040
+ binding = void 0;
2041
+ }
2042
+ const deferLegacyWebSearchRotationToTransientNativeSurface = params.nativeCodeModeEnabled === false && binding?.webSearchThreadConfigFingerprint === void 0 && !persistentWebSearchRestriction;
2043
+ if (binding?.threadId && webSearchBindingChanged && !deferLegacyWebSearchRotationToTransientNativeSurface) {
2044
+ assertCodexBindingMayBeReplaced(binding, "changing web-search configuration", expectedOwnership);
2045
+ if (!ringZeroActive && transientWebSearchRestriction) {
2046
+ embeddedAgentLog.debug("codex app-server tool surface restricted for turn; starting transient thread", { threadId: binding.threadId });
2047
+ preserveExistingBinding = true;
2048
+ } else {
2049
+ embeddedAgentLog.debug("codex app-server web search config changed; starting a new thread", { threadId: binding.threadId });
2050
+ await clearCurrentBinding("rotating a stale thread binding");
2051
+ }
2052
+ binding = void 0;
2053
+ }
2054
+ if (binding?.threadId && transientNativeToolRestriction && !ringZeroActive) {
2055
+ assertCodexBindingMayBeReplaced(binding, "starting a native-tool-restricted turn", expectedOwnership);
2056
+ embeddedAgentLog.debug("codex app-server native tool surface disabled for turn; starting transient thread", { threadId: binding.threadId });
2057
+ preserveExistingBinding = true;
2058
+ binding = void 0;
2059
+ }
2060
+ if (binding?.threadId && transientDelegationRestriction) {
2061
+ assertCodexBindingMayBeReplaced(binding, "starting a delegation-restricted turn", expectedOwnership);
2062
+ embeddedAgentLog.debug("codex app-server delegation restricted for turn; starting transient thread", { threadId: binding.threadId });
2063
+ binding = void 0;
2064
+ }
2065
+ if (binding?.threadId && (binding.contextEngine || contextEngineBinding)) {
2066
+ if (!contextEngineBinding || !isContextEngineBindingCompatible(binding.contextEngine, contextEngineBinding)) {
2067
+ embeddedAgentLog.debug("codex app-server context-engine binding changed; starting a new thread", {
2068
+ threadId: binding.threadId,
2069
+ engineId: contextEngineBinding?.engineId,
2070
+ previousEngineId: binding.contextEngine?.engineId,
2071
+ epoch: contextEngineBinding?.projection?.epoch,
2072
+ previousEpoch: binding.contextEngine?.projection?.epoch,
2073
+ fingerprint: contextEngineBinding?.projection?.fingerprint,
2074
+ previousFingerprint: binding.contextEngine?.projection?.fingerprint,
2075
+ policyFingerprint: contextEngineBinding?.policyFingerprint,
2076
+ previousPolicyFingerprint: binding.contextEngine?.policyFingerprint
2077
+ });
2078
+ await clearCurrentBinding("rotating a stale thread binding");
2079
+ rotatedContextEngineBinding = true;
2080
+ }
2081
+ }
2082
+ if (binding?.threadId && !areUserMcpServersFingerprintsCompatible({
2083
+ previous: binding.userMcpServersFingerprint,
2084
+ next: userMcpServersFingerprint,
2085
+ nextLegacy: legacyUserMcpServersFingerprint
2086
+ })) {
2087
+ embeddedAgentLog.debug("codex app-server user MCP config changed; starting a new thread", { threadId: binding.threadId });
2088
+ await clearCurrentBinding("rotating a stale thread binding");
2089
+ }
2090
+ if (binding?.threadId && (binding.networkProxyConfigFingerprint !== networkProxyConfigFingerprint || binding.networkProxyProfileName !== params.appServer.networkProxy?.profileName)) {
2091
+ embeddedAgentLog.debug("codex app-server network proxy config changed; starting a new thread", { threadId: binding.threadId });
2092
+ await clearCurrentBinding("rotating a stale thread binding");
2093
+ }
2094
+ if (binding?.threadId) {
2095
+ if (isCodexPluginThreadBindingStale({
2096
+ codexPluginsEnabled: params.pluginThreadConfig?.enabled ?? false,
2097
+ bindingFingerprint: binding.pluginAppsFingerprint,
2098
+ bindingInputFingerprint: binding.pluginAppsInputFingerprint,
2099
+ currentInputFingerprint: params.pluginThreadConfig?.inputFingerprint,
2100
+ hasBindingPolicyContext: Boolean(binding.pluginAppPolicyContext)
2101
+ })) {
2102
+ embeddedAgentLog.debug("codex app-server plugin app config changed; starting a new thread", { threadId: binding.threadId });
2103
+ await clearCurrentBinding("rotating a stale thread binding");
2104
+ }
2105
+ }
2106
+ if (binding?.threadId) {
2107
+ if (binding.dynamicToolsFingerprint && params.dynamicTools.length > 0 && binding.dynamicToolsContainDeferred !== dynamicToolsContainDeferred && (binding.dynamicToolsContainDeferred !== void 0 || !dynamicToolsContainDeferred)) {
2108
+ embeddedAgentLog.debug("codex app-server dynamic tool loading changed; starting a new thread", { threadId: binding.threadId });
2109
+ await clearCurrentBinding("rotating a stale thread binding");
2110
+ }
2111
+ }
2112
+ if (binding?.threadId) {
2113
+ if (binding.dynamicToolsFingerprint && !areCodexDynamicToolFingerprintsCompatible({
2114
+ previous: binding.dynamicToolsFingerprint,
2115
+ next: dynamicToolsFingerprint,
2116
+ nextLegacy: legacyDynamicToolsFingerprint
2117
+ })) {
2118
+ assertCodexBindingMayBeReplaced(binding, "changing the dynamic tool catalog", expectedOwnership);
2119
+ preserveExistingBinding = shouldStartTransientNoToolThread({
2120
+ previous: binding.dynamicToolsFingerprint,
2121
+ nextHasDynamicTools: params.dynamicTools.length > 0
2122
+ });
2123
+ if (preserveExistingBinding) embeddedAgentLog.debug("codex app-server dynamic tools unavailable for turn; starting transient thread", { threadId: binding.threadId });
2124
+ else {
2125
+ embeddedAgentLog.debug("codex app-server dynamic tool catalog changed; starting a new thread", { threadId: binding.threadId });
2126
+ await clearCurrentBinding("rotating a stale thread binding");
2127
+ }
2128
+ } else {
2129
+ const requestContext = await prepareRequestContext();
2130
+ const warmReuse = await tryReuseCodexLiveThread({
2131
+ ...requestContext,
2132
+ params,
2133
+ binding,
2134
+ clientId,
2135
+ buildLoadedPluginThreadConfig
2136
+ });
2137
+ if (warmReuse.kind === "ready") return publishCodexThreadInferenceBinding(params, warmReuse.binding, true);
2138
+ if (incognito || warmReuse.kind === "rotate") {
2139
+ throwIfAborted();
2140
+ await clearCurrentBinding(incognito ? "rotating an unavailable ephemeral thread binding" : "rotating a stale plugin app binding");
2141
+ } else {
2142
+ const resumeBinding = binding;
2143
+ const resumed = await resumeExistingCodexThread(params, {
2144
+ ...requestContext,
2145
+ binding: resumeBinding,
2146
+ clearCurrentBinding,
2147
+ prebuiltFinalConfigPatch: warmReuse.prebuiltFinalConfigPatch,
2148
+ prebuiltPluginThreadConfig,
2149
+ buildLoadedPluginThreadConfig,
2150
+ prepareResume: () => prepareCodexThreadResume(params, resumeBinding, requestContext),
2151
+ releaseRetainedThread: async (assertCurrent) => {
2152
+ await releaseRetainedThread(resumeBinding.threadId, resumeBinding.clientId, assertCurrent);
2153
+ }
2154
+ });
2155
+ if (resumed) return publishCodexThreadInferenceBinding(params, resumed);
2156
+ }
2157
+ }
2158
+ }
2159
+ assertCodexBindingMayBeReplaced(binding, "starting a fresh native thread", expectedOwnership);
2160
+ const requestContext = await prepareRequestContext();
2161
+ if (initialBoundThreadId && !preserveExistingBinding && !replacementPredecessor) await releaseRetainedThread(initialBoundThreadId);
2162
+ const started = await startFreshCodexThread(params, {
2163
+ ...requestContext,
2164
+ prebuiltPluginThreadConfig,
2165
+ preserveExistingBinding,
2166
+ rotatedContextEngineBinding,
2167
+ replacementPredecessor
2168
+ });
2169
+ if (replacementPredecessor) await releaseRetainedThread(replacementPredecessor.threadId, replacementPredecessor.clientId);
2170
+ return publishCodexThreadInferenceBinding(params, started);
2171
+ });
2172
+ }
2173
+ //#endregion
2174
+ //#region extensions/codex/src/app-server/user-input.ts
2175
+ function prependHistoryProvenance(input, historyProvenancePrefix) {
2176
+ if (!historyProvenancePrefix) return input;
2177
+ const firstTextIndex = input.findIndex((item) => item.type === "text");
2178
+ if (firstTextIndex === -1) return [{
2179
+ type: "text",
2180
+ text: historyProvenancePrefix,
2181
+ text_elements: []
2182
+ }, ...input];
2183
+ return input.map((item, index) => index === firstTextIndex && item.type === "text" ? {
2184
+ ...item,
2185
+ text: `${historyProvenancePrefix}${item.text}`
2186
+ } : item);
2187
+ }
2188
+ /** Builds ordered Codex user input for both new turns and same-turn steering. */
2189
+ function buildCodexUserInput(text, images, contextImageGroups, historyProvenancePrefix) {
2190
+ if (text !== void 0 && contextImageGroups?.length) {
2191
+ let offset = 0;
2192
+ return prependHistoryProvenance([...contextImageGroups.flatMap((group) => {
2193
+ const parts = buildCodexUserInput(text.slice(offset, group.end), group.images);
2194
+ offset = group.end;
2195
+ return parts;
2196
+ }), ...buildCodexUserInput(text.slice(offset), images)], historyProvenancePrefix);
2197
+ }
2198
+ const imageInputs = (images ?? []).map((image) => {
2199
+ const imageUrl = sanitizeInlineImageDataUrl(`data:${image.mimeType};base64,${image.data}`);
2200
+ return imageUrl ? {
2201
+ type: "image",
2202
+ url: imageUrl
2203
+ } : {
2204
+ type: "text",
2205
+ text: invalidInlineImageText("codex user input"),
2206
+ text_elements: []
2207
+ };
2208
+ });
2209
+ return prependHistoryProvenance([...text === void 0 ? [] : [{
2210
+ type: "text",
2211
+ text,
2212
+ text_elements: []
2213
+ }], ...imageInputs], historyProvenancePrefix);
2214
+ }
2215
+ //#endregion
2216
+ //#region extensions/codex/src/app-server/turn-params.ts
2217
+ const CODEX_CURRENT_SENDER_FIELD_MAX_CHARS = 256;
2218
+ function readCodexCurrentSender(params) {
2219
+ const metadata = asOptionalRecord(asOptionalRecord(params.userTurnTranscriptRecorder?.message)?.["__openclaw"]);
2220
+ const recorded = [
2221
+ normalizeOptionalString(metadata?.["senderId"]),
2222
+ normalizeOptionalString(metadata?.["senderName"]),
2223
+ normalizeOptionalString(metadata?.["senderUsername"])
2224
+ ];
2225
+ const [id, name, username] = recorded.some(Boolean) ? recorded : [
2226
+ normalizeOptionalString(params.senderId),
2227
+ normalizeOptionalString(params.senderName),
2228
+ normalizeOptionalString(params.senderUsername)
2229
+ ];
2230
+ if (!id && !name && !username) return;
2231
+ const bound = (value) => truncateUtf16Safe(value, CODEX_CURRENT_SENDER_FIELD_MAX_CHARS);
2232
+ return {
2233
+ ...id ? { id: bound(id) } : {},
2234
+ ...name ? { name: bound(name) } : {},
2235
+ ...username ? { username: bound(username) } : {}
2236
+ };
2237
+ }
2238
+ function buildCodexHistoryProvenancePrefix(params) {
2239
+ const sender = readCodexCurrentSender(params);
2240
+ return sender?.id ? neutralizeCodexExplicitMentionSigils(`[OpenClaw conversation info: sender=${JSON.stringify(sender)}]\n`) : void 0;
2241
+ }
2242
+ function buildTurnStartParams(params, options) {
2243
+ const modelSelection = options.preserveNativeTurnSettings ? void 0 : resolveCodexAppServerRequestModelSelection({
2244
+ homeScope: options.appServer.start.homeScope,
2245
+ model: options.model ?? params.modelId,
2246
+ modelProvider: options.modelProvider,
2247
+ authProfileId: params.authProfileId,
2248
+ authProfileStore: params.authProfileStore,
2249
+ agentDir: params.agentDir,
2250
+ config: params.config
2251
+ });
2252
+ const collaborationMode = modelSelection ? buildTurnCollaborationMode(params, {
2253
+ model: modelSelection.model,
2254
+ turnScopedDeveloperInstructions: options.turnScopedDeveloperInstructions,
2255
+ memoryCollaborationInstructions: options.memoryCollaborationInstructions
2256
+ }) : void 0;
2257
+ if (collaborationMode && options.parentLocalEgress) collaborationMode.settings.developer_instructions = null;
2258
+ const useThreadPermissionProfile = options.appServer.networkProxy && !options.sandboxPolicy;
2259
+ const currentSender = params.trigger === "user" ? readCodexCurrentSender(params) : void 0;
2260
+ const additionalContext = {
2261
+ ...buildCodexTemporalAdditionalContext(params, { sessionStatusAvailable: options.sessionStatusAvailable === true }),
2262
+ openclaw_active_computer: {
2263
+ kind: "application",
2264
+ value: params.hostCapabilities.activeComputerContext?.() ?? "Current active computer: active_node=unknown (host presence unavailable)"
2265
+ },
2266
+ openclaw_source_delivery: {
2267
+ kind: "application",
2268
+ value: ["Current source-delivery policy for this turn (replaces earlier source-delivery guidance):", buildHarnessVisibleReplyGuidance({
2269
+ sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
2270
+ messageToolAvailable: options.messageToolAvailable === true,
2271
+ requireExplicitMessageTarget: options.requireExplicitMessageTarget
2272
+ })].join("\n")
2273
+ }
2274
+ };
2275
+ if (currentSender) additionalContext.openclaw_current_sender = {
2276
+ kind: "untrusted",
2277
+ value: JSON.stringify({ sender: currentSender })
2278
+ };
2279
+ if (params.permissionChange?.notice) additionalContext.openclaw_permission_change = {
2280
+ kind: "application",
2281
+ value: params.permissionChange.notice
2282
+ };
2283
+ return {
2284
+ threadId: options.threadId,
2285
+ ...params.trigger ? { turnTrigger: params.trigger } : {},
2286
+ input: [...buildCodexUserInput(options.promptText ?? params.prompt, params.images, options.contextImageGroups, options.historyProvenancePrefix ?? (params.trigger === "user" ? buildCodexHistoryProvenancePrefix(params) : void 0)), ...options.explicitSkillInputs ?? []],
2287
+ additionalContext,
2288
+ cwd: options.cwd,
2289
+ ...options.appServer.sessionRoot ? { runtimeWorkspaceRoots: [options.appServer.sessionRoot] } : {},
2290
+ approvalPolicy: options.appServer.approvalPolicy,
2291
+ approvalsReviewer: options.appServer.approvalsReviewer,
2292
+ ...useThreadPermissionProfile ? {} : { sandboxPolicy: options.sandboxPolicy ?? codexSandboxPolicyForTurn(options.appServer.sandbox, options.appServer.sessionRoot ?? options.cwd, options.appServer.start?.args) },
2293
+ ...modelSelection ? {
2294
+ model: modelSelection.model,
2295
+ personality: CODEX_NATIVE_PERSONALITY_NONE
2296
+ } : {},
2297
+ ...options.appServer.serviceTier !== void 0 ? { serviceTier: options.appServer.serviceTier } : options.clearInheritedServiceTier ? { serviceTier: null } : {},
2298
+ ...collaborationMode ? {
2299
+ effort: collaborationMode.settings.reasoning_effort,
2300
+ collaborationMode
2301
+ } : {},
2302
+ ...options.environmentSelection ? { environments: options.environmentSelection } : {}
2303
+ };
2304
+ }
2305
+ function buildCodexTemporalAdditionalContext(params, options) {
2306
+ return { openclaw_temporal_context: {
2307
+ kind: "application",
2308
+ value: buildTemporalContextText({
2309
+ configuredTimezone: params.config?.agents?.defaults?.userTimezone,
2310
+ sessionStatusAvailable: options.sessionStatusAvailable
2311
+ })
2312
+ } };
2313
+ }
2314
+ function buildTurnCollaborationMode(params, options = {}) {
2315
+ const model = options.model ?? params.modelId;
2316
+ return {
2317
+ mode: "default",
2318
+ settings: {
2319
+ model,
2320
+ reasoning_effort: resolveCodexAppServerReasoningEffort({
2321
+ thinkLevel: params.thinkLevel,
2322
+ modelId: model,
2323
+ supportedReasoningEfforts: readCodexSupportedReasoningEfforts(params.model?.compat)
2324
+ }),
2325
+ developer_instructions: buildTurnScopedCollaborationInstructions(params, options)
2326
+ }
2327
+ };
2328
+ }
2329
+ function buildCodexParentLocalInstructions(params, options = {}) {
2330
+ const contextInstructions = joinPresentSections(options.turnScopedDeveloperInstructions, options.skillsInstructions, options.memoryCollaborationInstructions);
2331
+ if (params.trigger === "cron") return joinPresentSections(buildCronCollaborationInstructions(), contextInstructions);
2332
+ return contextInstructions || null;
2333
+ }
2334
+ function buildTurnScopedCollaborationInstructions(params, options) {
2335
+ const instructions = buildCodexParentLocalInstructions(params, options);
2336
+ return instructions && params.trigger !== "cron" ? joinPresentSections(buildDefaultCollaborationInstructions(), instructions) : instructions;
2337
+ }
2338
+ function buildDefaultCollaborationInstructions() {
2339
+ return [
2340
+ "# Collaboration Mode: Default",
2341
+ "",
2342
+ "You are now in Default mode. Any previous instructions for other modes (e.g. Plan mode) are no longer active.",
2343
+ "",
2344
+ "Your active mode changes only when new developer instructions with a different `<collaboration_mode>...</collaboration_mode>` change it; user requests or tool descriptions do not change mode by themselves. Known mode names are Default and Plan.",
2345
+ "",
2346
+ "## request_user_input availability",
2347
+ "",
2348
+ "Use the `request_user_input` tool only when it is listed in the available tools for this turn.",
2349
+ "",
2350
+ "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."
2351
+ ].join("\n");
2352
+ }
2353
+ function buildCronCollaborationInstructions() {
2354
+ return [
2355
+ "This is an OpenClaw cron automation turn. Apply these instructions only to this scheduled job; ordinary chat turns should stay in Codex Default mode.",
2356
+ "Execute the cron payload directly. If it asks you to run an exact command, run that command before doing any investigation, planning, memory review, or workspace bootstrap.",
2357
+ "Use context already provided by the runtime, but do not spend time loading or re-reading workspace bootstrap, memory, or project-doc files before executing the cron payload. Inspect those files only if the payload asks for them or the command fails and they are needed to diagnose it.",
2358
+ "Keep output concise and automation-oriented. Prefer the final command result or a short failure summary over status narration."
2359
+ ].join("\n\n");
2360
+ }
2361
+ //#endregion
2362
+ export { resolveCodexAppServerReasoningEffort as S, 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, 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, readCodexSupportedReasoningEfforts as x, buildContextEngineBinding as y };