@openclaw/codex 2026.9.5 → 2026.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/dist/.setup/{account-usage-runtime-C2MOIvfq.mjs → account-usage-runtime-Eem_WGqY.mjs} +5 -5
  2. package/dist/.setup/{apply-CJ0ZfmBG.mjs → apply-DDOi8uNx.mjs} +22 -28
  3. package/dist/.setup/{attempt-client-cleanup-BpYKdTA0.mjs → attempt-client-cleanup-CEv1cKwF.mjs} +58 -43
  4. package/dist/.setup/attempt-workspace-context-DUVEn_CS.mjs +331 -0
  5. package/dist/.setup/{auth-cache-key-QirmgiCo.mjs → auth-cache-key-B2mpaI9D.mjs} +9 -81
  6. package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
  7. package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
  8. package/dist/.setup/{binding-connection-Bm38niE8.mjs → binding-connection-ThoatDcb.mjs} +1 -1
  9. package/dist/.setup/{binding-connection.runtime-CnRMC0ta.mjs → binding-connection.runtime-yoHrABt-.mjs} +4 -4
  10. package/dist/.setup/{bounded-turn-BtlZcivC.mjs → bounded-turn-B2HScEgT.mjs} +138 -32
  11. package/dist/.setup/{build-state-Xx9ybZqa.mjs → build-state-C7EnDVgr.mjs} +1 -1
  12. package/dist/.setup/{capabilities-_vXcZGSx.mjs → capabilities-CDXOOFdZ.mjs} +1 -1
  13. package/dist/.setup/{client-vXs2929Q.mjs → client-Cs08OXVQ.mjs} +583 -559
  14. package/dist/.setup/client-catalog-response-BMgt_4q4.mjs +285 -0
  15. package/dist/.setup/{command-dispatch-naHIZwwF.mjs → command-dispatch-B4JuOsOk.mjs} +8 -4
  16. package/dist/.setup/{command-formatters-CGEkdawF.mjs → command-formatters-Bmqvr9tO.mjs} +8 -4
  17. package/dist/.setup/{command-handlers-BtAJEW1X.mjs → command-handlers-DW7Lx9oH.mjs} +106 -172
  18. package/dist/.setup/{command-rpc-DHFpn4le.mjs → command-rpc-DixIj3HW.mjs} +36 -21
  19. package/dist/.setup/{compact-C3i3qlzj.mjs → compact-Du5UvtxA.mjs} +14 -21
  20. package/dist/.setup/{config-CedDWjM-.mjs → config-BoTP_mrL.mjs} +3 -3
  21. package/dist/.setup/{config-options-BsanJ8QG.mjs → config-options-BvaRs51b.mjs} +46 -30
  22. package/dist/.setup/{config-runtime-CeAhl_h4.mjs → config-runtime-C8Rw1m1m.mjs} +1 -1
  23. package/dist/.setup/{config-security-BRQ2mgW9.mjs → config-security-BEReZ6go.mjs} +35 -120
  24. package/dist/.setup/{conversation-binding-DhzrpTM6.mjs → conversation-binding-DP-gMrBP.mjs} +21 -32
  25. package/dist/.setup/{conversation-control-DN53ns41.mjs → conversation-control-uK9Jomlc.mjs} +28 -67
  26. package/dist/.setup/{dynamic-tools-D16lOp67.mjs → dynamic-tools-BDXl-8Cw.mjs} +848 -578
  27. package/dist/.setup/{effective-mcp-catalog-K6kLCN8X.mjs → effective-mcp-catalog-CvnvnGIe.mjs} +3 -3
  28. package/dist/.setup/{ephemeral-turn-R1gA8Sn6.mjs → ephemeral-turn-poidXgek.mjs} +9 -6
  29. package/dist/.setup/{event-projector-assistant-message-DNUR1s0A.mjs → event-projector-assistant-message-BsruvNrH.mjs} +2 -4
  30. package/dist/.setup/{event-projector-items-DyTQ_XqL.mjs → event-projector-items-C6L_5ZiT.mjs} +42 -8
  31. package/dist/.setup/{event-projector-usage-C7Ntzs-f.mjs → event-projector-usage-CnBS8Wa3.mjs} +1 -1
  32. package/dist/.setup/{harness-rxaaoN-o.mjs → harness-a_MsE4-_.mjs} +23 -17
  33. package/dist/.setup/{inference-context-fulhZuz8.mjs → inference-context-D96l9-ew.mjs} +1 -1
  34. package/dist/.setup/inference-proxy-b-aJMSxm.mjs +601 -0
  35. package/dist/.setup/{isolated-completion-B6srt48J.mjs → isolated-completion-BIZFhTNG.mjs} +17 -10
  36. package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
  37. package/dist/.setup/{managed-binary-DP6Rib3P.mjs → managed-binary-BnshlFag.mjs} +13 -2
  38. package/dist/.setup/{model-catalog-DkvUuBey.mjs → model-catalog-CfXJf9Ay.mjs} +9 -10
  39. package/dist/.setup/{models-BDFgm_G-.mjs → models-KnqBv0hE.mjs} +3 -3
  40. package/dist/.setup/{native-auth-BLZGqFjw.mjs → native-auth-rWbGbMn3.mjs} +4 -4
  41. package/dist/.setup/{native-subagent-history-YXaL6dMd.mjs → native-subagent-history-0nYYgo0k.mjs} +26 -13
  42. package/dist/.setup/{native-subagent-monitor-B1hxzIOy.mjs → native-subagent-monitor-D3filLY2.mjs} +145 -317
  43. package/dist/.setup/{native-subagent-task-ids-DsuOonKv.mjs → native-subagent-task-ids-wb8CKZGN.mjs} +69 -39
  44. package/dist/.setup/{node-cli-sessions-Cl8b2ZF3.mjs → node-cli-sessions-r3avj02l.mjs} +86 -68
  45. package/dist/.setup/node-exec-server.runtime-BDwWXVpK.mjs +247 -0
  46. package/dist/.setup/{plan-xD7WKYTM.mjs → plan-CN3VwfNU.mjs} +74 -76
  47. package/dist/.setup/{plugin-activation-r8nq5Jzp.mjs → plugin-activation-DT3MNtqj.mjs} +7 -16
  48. package/dist/.setup/{plugin-app-cache-key-BOxKP7db.mjs → plugin-app-cache-key-B2CsSdnV.mjs} +4 -20
  49. package/dist/.setup/{plugin-approval-roundtrip-CjfzafAZ.mjs → plugin-approval-roundtrip-C0MZzCuP.mjs} +1 -1
  50. package/dist/.setup/{plugin-inventory-DUle8DLz.mjs → plugin-inventory-BoRei8Z4.mjs} +16 -7
  51. package/dist/.setup/{plugin-marketplace-discovery-P-Vndfqq.mjs → plugin-marketplace-discovery-CDOi8IFs.mjs} +4 -1
  52. package/dist/.setup/{plugin-metadata-cache-DsS5buNa.mjs → plugin-metadata-cache-Ctmo83k_.mjs} +224 -154
  53. package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
  54. package/dist/.setup/{provider-fFh_-VR3.mjs → provider-BOsxQHOM.mjs} +9 -5
  55. package/dist/.setup/{provider-capabilities-B8J4Dy-O.mjs → provider-capabilities-BfE88FZ5.mjs} +31 -3
  56. package/dist/.setup/{rate-limits-DOEGYRNs.mjs → rate-limits-CMU3DUD0.mjs} +116 -137
  57. package/dist/.setup/{request-BioXJLYa.mjs → request-D2L0zMrq.mjs} +23 -15
  58. package/dist/.setup/{run-attempt-rlA07pUv.mjs → run-attempt-BHu11r7h.mjs} +1197 -617
  59. package/dist/.setup/{runtime-artifact-Dy38Z5iU.mjs → runtime-artifact-CLZ8udh-.mjs} +29 -45
  60. package/dist/.setup/{sandbox-guard-BBP-RbTf.mjs → sandbox-guard-C2sRMOEY.mjs} +1 -1
  61. package/dist/.setup/{session-binding-_0W_fHRr.mjs → session-binding-Cm0apEbd.mjs} +3 -32
  62. package/dist/.setup/{session-binding-record-TH3xA0zj.mjs → session-binding-record-BGoz8wOK.mjs} +22 -3
  63. package/dist/.setup/{session-binding-sidecars-CKYEcfNn.mjs → session-binding-sidecars-BlB5EvIS.mjs} +48 -45
  64. package/dist/.setup/{session-catalog-fUdWDx-U.mjs → session-catalog-Pno1xGcl.mjs} +482 -182
  65. package/dist/.setup/{session-catalog-adoption-CR_whkEW.mjs → session-catalog-adoption-BI6UTDZT.mjs} +57 -25
  66. package/dist/.setup/{session-catalog-archive-CwZaPacf.mjs → session-catalog-archive-lHBqzhaO.mjs} +6 -6
  67. package/dist/.setup/{session-catalog-events-jMcYfQyd.mjs → session-catalog-events-Bj6j94E_.mjs} +122 -25
  68. package/dist/.setup/{session-catalog-index-B141u15s.mjs → session-catalog-index-B9_VQIUz.mjs} +178 -78
  69. package/dist/.setup/{session-catalog-index-order-Cc5BzlQr.mjs → session-catalog-index-order-hcdz07yN.mjs} +2 -2
  70. package/dist/.setup/{session-catalog-index-state-BAuDztHN.mjs → session-catalog-index-state-Dgh8ORJm.mjs} +5 -2
  71. package/dist/.setup/{session-catalog-native-projection-ChV3cCtm.mjs → session-catalog-native-projection-DowriLid.mjs} +30 -13
  72. package/dist/.setup/{session-catalog-node-adoption-BVRsYOSh.mjs → session-catalog-node-adoption-ITddWx_X.mjs} +24 -12
  73. package/dist/.setup/{session-catalog-node-continue-Dowv8osw.mjs → session-catalog-node-continue-6g6qi4A9.mjs} +22 -13
  74. package/dist/.setup/{session-catalog-projection-C1Bj9Jl-.mjs → session-catalog-projection-zK_PUsiE.mjs} +13 -5
  75. package/dist/.setup/{session-cli-DIj-IE-E.mjs → session-cli-irrD-uo7.mjs} +4 -4
  76. package/dist/.setup/{session-history-C--SrLI8.mjs → session-history-BrqhSCf9.mjs} +17 -22
  77. package/dist/.setup/{session-history-import-JHXT5Xfi.mjs → session-history-import-D-3wAgOP.mjs} +4 -4
  78. package/dist/.setup/{session-history.worker-CpNj7H_P.mjs → session-history.worker-CaCh0xF_.mjs} +5 -18
  79. package/dist/.setup/{session-initialization-DH1z6fXn.mjs → session-initialization-rcgbZiid.mjs} +2 -2
  80. package/dist/.setup/{session-permission-policy-DhurXY0l.mjs → session-permission-policy-BI1QK_98.mjs} +2 -2
  81. package/dist/.setup/{session-retirement-CU87AOg9.mjs → session-retirement-BH-S6qkJ.mjs} +25 -6
  82. package/dist/.setup/{settled-turn-finalizer-CiY2bLFK.mjs → settled-turn-finalizer-DiAi6Kx6.mjs} +8 -8
  83. package/dist/.setup/{shared-client-BpTtuLQ5.mjs → shared-client-DA4VR4Eb.mjs} +59 -89
  84. package/dist/.setup/{side-question-DSCZyoBD.mjs → side-question-BJ1wSDcB.mjs} +147 -211
  85. package/dist/.setup/{source-Bjp4UQij.mjs → source-CUzJq5WN.mjs} +9 -9
  86. package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
  87. package/dist/.setup/{thread-archive-guard-jmecf6OJ.mjs → thread-archive-guard-C9frICzX.mjs} +10 -3
  88. package/dist/.setup/{thread-history-page-BTx-4xsg.mjs → thread-history-page-DoVpnHim.mjs} +1 -1
  89. package/dist/.setup/{thread-lifecycle-Cik28qWn.mjs → thread-lifecycle-B3mfz1TG.mjs} +172 -2271
  90. package/dist/.setup/{thread-ownership-skomxnIt.mjs → thread-ownership-DcTtAcXj.mjs} +4 -2
  91. package/dist/.setup/{thread-policy-Cjs4B8xf.mjs → thread-policy-DGuQsuFC.mjs} +19 -3
  92. package/dist/.setup/thread-requests-BLvGkP2R.mjs +2205 -0
  93. package/dist/.setup/{thread-resume-BkNpj9Pz.mjs → thread-resume-DIBXwOpE.mjs} +6 -6
  94. package/dist/.setup/{timeout-DZF05XrR.mjs → timeout-C910MdAB.mjs} +19 -2
  95. package/dist/.setup/{transcript-history-projection-DHNBDhCU.mjs → transcript-history-projection-ZZpkFkJ_.mjs} +94 -64
  96. package/dist/.setup/{transcript-mirror-D4qp_leP.mjs → transcript-mirror-BtHDBp1G.mjs} +218 -198
  97. package/dist/.setup/{transport-stdio-Cmx94Oiy.mjs → transport-stdio-h2VHOskC.mjs} +135 -55
  98. package/dist/.setup/{upstream-session-fork-D3UKxgVD.mjs → upstream-session-fork-BUr4OUbC.mjs} +44 -36
  99. package/dist/.setup/{usage-BOgBEKso.mjs → usage-BML0r-ua.mjs} +5 -4
  100. package/dist/.setup/{usage-limit-error-C0ow7DOc.mjs → usage-limit-error-DUMbefVY.mjs} +4 -4
  101. package/dist/.setup/{web-search-provider.runtime-CTGuJt6i.mjs → web-search-provider.runtime-CDKlN-Rv.mjs} +4 -3
  102. package/dist/api.js +23 -12
  103. package/dist/catalog-page-worker-entrypoint.js +12 -0
  104. package/dist/catalog-page.worker.js +9 -0
  105. package/dist/cli-metadata.js +1 -1
  106. package/dist/doctor-contract-api.js +2 -2
  107. package/dist/harness.js +1 -1
  108. package/dist/index.js +221 -170
  109. package/dist/media-understanding-provider.js +2 -2
  110. package/dist/migration-provider-api.js +1 -1
  111. package/dist/provider-discovery.js +1 -1
  112. package/dist/session-history-worker-runtime.js +15 -32
  113. package/dist/session-history.worker.js +1 -1
  114. package/package.json +9 -6
  115. package/dist/.setup/attempt-context-VXVwTCfS.mjs +0 -636
  116. package/dist/.setup/inference-proxy-CC15HuSi.mjs +0 -311
  117. package/dist/.setup/launch-args-DnMak49W.mjs +0 -111
  118. package/dist/.setup/node-exec-server.runtime-BaViBKNz.mjs +0 -226
  119. package/dist/.setup/version-CoqzXPgK.mjs +0 -12
  120. package/dist/.setup/{native-execution-policy-YBMHSzC4.mjs → native-execution-policy-umd0tgh4.mjs} +1 -1
@@ -1,72 +1,78 @@
1
- import { s as resolveRecoverableCodexPluginConfigKeys } from "./plugin-inventory-DUle8DLz.mjs";
2
- import { b as createCodexNativeSubagentHistoryOwner, i as matchesCodexNativeSubagentSubmissionBinding, n as assertCodexBindingMayBeReplaced, p as sessionBindingIdentity } from "./session-binding-record-TH3xA0zj.mjs";
3
- import { n as defineCodexBuildState } from "./build-state-Xx9ybZqa.mjs";
4
- import { E as readCodexRequirementsToml, h as resolveCodexAppServerHomeDir, l as shouldAutoApproveCodexAppServerApprovals, m as isJsonObject, n as hasCodexMcpToolApprovalOverrides, p as flattenCodexDynamicToolFunctions, u as withMcpElicitationsApprovalPolicy } from "./config-security-BRQ2mgW9.mjs";
1
+ import { s as resolveRecoverableCodexPluginConfigKeys } from "./plugin-inventory-BoRei8Z4.mjs";
2
+ import { i as matchesCodexNativeSubagentSubmissionBinding, m as sessionBindingIdentity, n as assertCodexBindingMayBeReplaced, x as createCodexNativeSubagentHistoryOwner } from "./session-binding-record-BGoz8wOK.mjs";
3
+ import { n as defineCodexBuildState } from "./build-state-C7EnDVgr.mjs";
4
+ import { d as resolveCodexAppServerHomeDir, l as shouldAutoApproveCodexAppServerApprovals, n as hasCodexMcpToolApprovalOverrides, u as withMcpElicitationsApprovalPolicy, y as readCodexRequirementsToml } from "./config-security-BEReZ6go.mjs";
5
5
  import { c as isCodexPairedNodeRemoteExecPlacementSandbox, d as readCodexPluginConfig, f as resolveCodexPluginsPolicy, l as isCodexRemoteExecPlacementSandbox, u as isCodexSandboxExecServerEnabled } from "./config-parsing-CcB9iPoq.mjs";
6
- import { A as isMatchingDynamicToolTerminalDiagnostic, D as handleDynamicToolCallWithTimeout, E as createCodexElicitationResponse, F as toCodexDynamicToolProgressResponse, I as toCodexDynamicToolProtocolResponse, L as resolveCodexToolAbortTerminalReason, M as resolveTerminalDynamicToolBatchAction, N as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult, O as hasPendingDynamicToolTerminalDiagnostic, P as shouldReleaseTurnAfterTerminalDynamicTool, S as readCodexDynamicToolCallParams, T as readCodexTurnCompletedNotification, c as isCodexAppServerIndeterminateTransportError, i as isCodexAppServerApprovalRequest, j as resolveDynamicToolCallTimeoutMs, k as isDynamicToolTerminalDiagnosticEvent, o as isCodexAppServerConnectionClosedError, p as resolveCodexAppServerClientInstanceId, r as getCodexAppServerClientInstanceId, s as isCodexAppServerIndeterminateRequestCancellationError, w as readCodexTurn, x as assertCodexTurnStartResponse } from "./client-vXs2929Q.mjs";
7
- import { i as resolveCodexAppServerHomeScope, l as resolveCodexModelBackedReviewerPolicyContext, o as resolveCodexComputerUseConfig } from "./config-options-BsanJ8QG.mjs";
8
- import { c as resolveCodexAppServerPreparedApiKeyCacheKey, m as retireSharedCodexAppServerClientIfCurrent, s as resolveCodexAppServerFallbackApiKeyCacheKey } from "./auth-cache-key-QirmgiCo.mjs";
6
+ import { i as isJsonObject, r as flattenCodexDynamicToolFunctions } from "./protocol-CANUwXJ3.mjs";
7
+ import { i as resolveCodexAppServerHomeScope, l as resolveCodexModelBackedReviewerPolicyContext, o as resolveCodexComputerUseConfig } from "./config-options-BvaRs51b.mjs";
8
+ import { c as resolveCodexAppServerPreparedApiKeyCacheKey, s as resolveCodexAppServerFallbackApiKeyCacheKey } from "./auth-cache-key-B2mpaI9D.mjs";
9
+ import { h as retireSharedCodexAppServerClientIfCurrent } from "./session-catalog-events-Bj6j94E_.mjs";
9
10
  import { t as isIncognitoSessionKey } from "./incognito-session-uhrBF6wJ.mjs";
10
- import { o as formatCodexDisplayText } from "./command-formatters-CGEkdawF.mjs";
11
- import { i as CodexAppServerRpcError, t as withAbortableTimeout } from "./timeout-DZF05XrR.mjs";
11
+ import { o as formatCodexDisplayText } from "./command-formatters-Bmqvr9tO.mjs";
12
+ import { n as waitForPromiseOrAbort, o as CodexAppServerRpcError, r as withAbortableTimeout } from "./timeout-C910MdAB.mjs";
12
13
  import { t as readCodexAsyncQuestions } from "./async-questions-DdhOCwGi.mjs";
13
- import { D as splitPlanText, E as readNullableString, S as readItemString, T as readNonNegativeInteger, d as matchesCodexSnapshotTurn, f as shouldClearTerminalPresentationForNativeItem, g as extractRawAssistantText, v as readCodexErrorNotificationMessage, x as readItem, y as readCodexProviderRefusal } from "./event-projector-items-DyTQ_XqL.mjs";
14
+ import { C as readItemString, D as readNullableString, E as readNonNegativeInteger, O as splitPlanText, S as readItem, _ as extractRawAssistantText, b as readCodexProviderRefusal, d as matchesCodexSnapshotTurn, f as shouldClearTerminalPresentationForNativeItem, y as readCodexErrorNotificationMessage } from "./event-projector-items-C6L_5ZiT.mjs";
14
15
  import { r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-LphB8slG.mjs";
15
- import { a as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-BOxKP7db.mjs";
16
- import { i as resolveCodexBindingAppServerConnection, t as assertCodexSessionRuntimeOwnership } from "./binding-connection-Bm38niE8.mjs";
17
- import { n as resolveOpenClawExecPolicyForCodexAppServer, t as canUseCodexModelBackedApprovalsReviewerForModel } from "./config-CedDWjM-.mjs";
16
+ import { a as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-B2CsSdnV.mjs";
17
+ import { i as resolveCodexBindingAppServerConnection, t as assertCodexSessionRuntimeOwnership } from "./binding-connection-ThoatDcb.mjs";
18
+ import { n as resolveOpenClawExecPolicyForCodexAppServer, t as canUseCodexModelBackedApprovalsReviewerForModel } from "./config-BoTP_mrL.mjs";
18
19
  import { o as hasCodexMirrorOrigin, t as applyCodexTranscriptTaint } from "./transcript-mirror-attestation-CzM-94NC.mjs";
20
+ import { t as readCodexMirroredSessionHistoryMessages } from "./session-history-BrqhSCf9.mjs";
19
21
  import { i as resolveCodexAppServerAuthProfileIdForAgent, r as resolveCodexAppServerAuthProfileId } from "./auth-profile-WqZtZfXN.mjs";
22
+ import { A as getCodexInferenceThread, B as prepareCodexWorkspaceReferences, K as readCodexRateLimitsRevision, P as ensureCodexAppServerClientRuntime, V as protectCodexAppServerLiveThread, X as resolveCodexAppServerAuthAccountCacheKey, Z as resolveCodexAppServerPreparedAuthHandoff, a as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, at as resolveCodexStartupTimeoutMs, c as getLeasedSharedCodexAppServerClient, et as CodexAppServerStartupError, f as readCodexAppServerClientDesktopGenerationFingerprint, h as releaseLeasedSharedCodexAppServerClient, i as clearSharedCodexAppServerClientIfCurrent, l as getSharedCodexAppServerClient, nt as TURN_TERMINAL_SETTLEMENT_TIMEOUT_MS, ot as withCodexStartupTimeout, q as readRecentCodexRateLimits, s as createIsolatedCodexAppServerClient, tt as TURN_FINALIZE_DRAIN_ABORT_GRACE_MS, u as isCodexAppServerStartSelectionChangedError, v as retainSharedCodexAppServerClientIfCurrent, w as CodexThreadClientReplacementError } from "./shared-client-DA4VR4Eb.mjs";
23
+ import { A as isMatchingDynamicToolTerminalDiagnostic, B as CODEX_APP_SERVER_OPT_OUT_NOTIFICATION_METHODS, C as readCodexDynamicToolCallParams, D as handleDynamicToolCallWithTimeout, E as createCodexElicitationResponse, F as toCodexDynamicToolProgressResponse, I as toCodexDynamicToolProtocolResponse, L as resolveCodexToolAbortTerminalReason, M as resolveTerminalDynamicToolBatchAction, N as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult, O as hasPendingDynamicToolTerminalDiagnostic, P as shouldReleaseTurnAfterTerminalDynamicTool, S as assertCodexTurnStartResponse, T as readCodexTurnCompletedNotification, c as isCodexAppServerIndeterminateTransportError, i as isCodexAppServerApprovalRequest, j as resolveDynamicToolCallTimeoutMs, k as isDynamicToolTerminalDiagnosticEvent, m as CodexServerRequestResolvedError, o as isCodexAppServerConnectionClosedError, p as resolveCodexAppServerClientInstanceId, r as getCodexAppServerClientInstanceId, s as isCodexAppServerIndeterminateRequestCancellationError } from "./client-Cs08OXVQ.mjs";
24
+ import { _ as CodexProjectionDiagnostics, d as shouldRetireCodexStartupClient, f as terminateCodexBackgroundTerminals, h as getCodexAppServerTurnRouter, m as CODEX_APP_SERVER_NATIVE_TURN_WAIT_TIMEOUT_MS, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, o as closeCodexStartupClientBestEffort, p as unsubscribeCodexThreadBestEffort, r as CodexAppServerUnsafeSubscriptionError, s as interruptCodexTurnAndWaitBestEffort, u as retireUnsafeCodexTurnClientBestEffort, v as isCodexNotificationForTurn, y as readCodexNotificationThreadId } from "./attempt-client-cleanup-CEv1cKwF.mjs";
20
25
  import { r as prepareCodexAppServerAuthBinding } from "./auth-binding-DhLWa_7K.mjs";
21
- import { A as getCodexInferenceThread, B as prepareCodexWorkspaceReferences, K as readCodexRateLimitsRevision, P as ensureCodexAppServerClientRuntime, V as protectCodexAppServerLiveThread, X as resolveCodexAppServerAuthAccountCacheKey, Z as resolveCodexAppServerPreparedAuthHandoff, a as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, at as resolveCodexStartupTimeoutMs, c as getLeasedSharedCodexAppServerClient, et as CodexAppServerStartupError, f as readCodexAppServerClientDesktopGenerationFingerprint, h as releaseLeasedSharedCodexAppServerClient, i as clearSharedCodexAppServerClientIfCurrent, l as getSharedCodexAppServerClient, nt as TURN_TERMINAL_SETTLEMENT_TIMEOUT_MS, ot as withCodexStartupTimeout, q as readRecentCodexRateLimits, s as createIsolatedCodexAppServerClient, tt as TURN_FINALIZE_DRAIN_ABORT_GRACE_MS, u as isCodexAppServerStartSelectionChangedError, v as retainSharedCodexAppServerClientIfCurrent, w as CodexThreadClientReplacementError } from "./shared-client-BpTtuLQ5.mjs";
22
- import { _ as CodexProjectionDiagnostics, a as closeCodexStartupClientBestEffort, d as terminateCodexBackgroundTerminals, f as unsubscribeCodexThreadBestEffort, g as waitForPromiseOrAbort, l as retireUnsafeCodexTurnClientBestEffort, m as getCodexAppServerTurnRouter, o as interruptCodexTurnAndWaitBestEffort, p as CODEX_APP_SERVER_NATIVE_TURN_WAIT_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError, u as shouldRetireCodexStartupClient, v as isCodexNotificationForTurn, y as readCodexNotificationThreadId } from "./attempt-client-cleanup-BpYKdTA0.mjs";
23
- import { a as isPendingOpenClawDynamicToolCompletionNotification, c as readCodexNotificationItem, d as updateActiveTurnItemIds, i as isCodexTurnAbortMarkerNotification, l as readNotificationItemId, o as isRawFunctionToolOutputCompletionNotification, r as codexExecutionToolName, s as isTerminalTurnStatus, t as CodexUsageProjection, u as readRawResponseToolCallId } from "./event-projector-usage-C7Ntzs-f.mjs";
24
- import { At as shouldBuildCodexPluginThreadConfig, Ct as resolveCodexContinuityProjectionMaxChars, Et as buildCodexPluginThreadConfigTimeoutFallback, G as scheduleCodexNativeHookRelayUnregister, H as emitCodexNativePreToolUseFailureDiagnostic, I as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, J as hasCodexNativeToolCatalog, M as readCodexMcpToolUiVisibility, Ot as mergeCodexThreadConfigs, P as isCodexAppServerProfilerEnabled, R as buildCodexNativeHookRelayConfig, St as resolveCodexContextEngineProjectionReserveTokens, T as buildDeveloperInstructions, Tt as buildCodexPluginThreadConfigInputFingerprint, U as resolveCodexNativeHookRelayEvents, V as createCodexNativeHookRelay, W as resolveCodexNativeHookRelayTtlMs, Y as loadCodexNativeToolCatalog, _ as resolveScheduledCodexAppCreatorCaptureDecision, _t as fitCodexProjectedContextForTurnStart, a as buildTurnStartParams, bt as projectContextEngineAssemblyForCodex, ct as isSystemAgentOnlyCodexDynamicToolAllowlist, d as buildLegacyScheduledCodexAppRecoveryPrompt, dt as resolveCodexDynamicToolsLoadingForRuntime, et as codexDynamicToolsFingerprint, f as buildScheduledCodexAppAuthorityInputFingerprint, ft as buildContextEngineBinding, g as readCurrentCodexScheduledAppPolicy$1, gt as buildCodexContinuityCalibration, h as intersectCodexPluginThreadConfigWithScheduledAuthority, ht as CodexContextAttachmentError, i as buildTurnCollaborationMode, it as filterCodexDynamicTools, j as readCodexMcpToolConnectorId, k as resolveCodexAppServerThreadModelSelection, l as startOrResumeThread, m as captureScheduledCodexAppAuthority, mt as CODEX_TURN_START_TEXT_INPUT_MAX_CHARS, n as buildCodexParentLocalInstructions, o as buildCodexUserInput, p as buildScheduledCodexAppServerConnectionIdentity, t as buildCodexHistoryProvenancePrefix, tt as codexLegacyDynamicToolsFingerprint, u as assertScheduledCodexAppAuthorityRuntime, vt as isCodexDurableCustomMessage, w as resolveCodexWebSearchPlan, wt as buildCodexPluginThreadConfig, xt as resolveCodexContextEngineProjectionMaxChars, yt as neutralizeCodexExplicitMentionSigils, z as buildCodexNativeHookRelayDisabledConfig } from "./thread-lifecycle-Cik28qWn.mjs";
25
- import { a as resolveCodexRunSessionBindingAuthority, n as createCodexSessionGenerationSupersededError, o as resolveCodexSessionBinding, s as scopeCodexRunBindingStore } from "./session-binding-_0W_fHRr.mjs";
26
- import { n as CodexThreadPolicyHandoffError } from "./thread-policy-Cjs4B8xf.mjs";
27
- import { r as retainCodexAppServerBindingSubscription, s as withExclusiveCodexAppServerThread, t as isSameCodexAppServerThreadOwner } from "./thread-ownership-skomxnIt.mjs";
28
- import { c as promptSnapshot, i as mirrorPromptAtTurnStartBestEffort, n as createCodexAppServerUserMessagePersistenceNotifier, o as buildCodexUserPromptMessage, s as buildResolvedCodexUserPromptMessage, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-D4qp_leP.mjs";
29
- import { a as resolveCodexPromptError, i as refreshCodexUsageLimitPromptError, n as formatCodexTurnStartUsageLimitError, r as markCodexAuthProfileBlockedFromRateLimits, t as CodexUsageLimitPromptError } from "./usage-limit-error-C0ow7DOc.mjs";
26
+ import { a as isPendingOpenClawDynamicToolCompletionNotification, c as readCodexNotificationItem, d as updateActiveTurnItemIds, i as isCodexTurnAbortMarkerNotification, l as readNotificationItemId, o as isRawFunctionToolOutputCompletionNotification, r as codexExecutionToolName, s as isTerminalTurnStatus, t as CodexUsageProjection, u as readRawResponseToolCallId } from "./event-projector-usage-CnBS8Wa3.mjs";
27
+ import { A as emitCodexNativePreToolUseFailureDiagnostic, C as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, Ct as shouldBuildCodexPluginThreadConfig, D as buildCodexNativeHookRelayDisabledConfig, E as buildCodexNativeHookRelayConfig, K as codexDynamicToolsFingerprint, M as resolveCodexNativeHookRelayTtlMs, N as scheduleCodexNativeHookRelayUnregister, R as hasCodexNativeToolCatalog, T as assertCodexNativeHookRelayAllowed, U as areCodexDynamicToolFingerprintsCompatible, X as fingerprintJsonObject, at as filterCodexDynamicTools, ft as resolveCodexDynamicToolsLoadingForRuntime, gt as buildCodexPluginThreadConfigTimeoutFallback, ht as buildCodexPluginThreadConfigInputFingerprint, j as resolveCodexNativeHookRelayEvents, k as createCodexNativeHookRelay, lt as isSystemAgentOnlyCodexDynamicToolAllowlist, m as buildDeveloperInstructions, mt as buildCodexPluginThreadConfig, p as resolveCodexWebSearchPlan, q as codexLegacyDynamicToolsFingerprint, v as resolveCodexAppServerThreadModelSelection, w as CodexManagedHooksOnlyError, xt as mergeCodexThreadConfigs, z as loadCodexNativeToolCatalog } from "./thread-requests-BLvGkP2R.mjs";
28
+ import { A as resolveCodexContinuityProjectionMaxChars, C as buildCodexContinuityCalibration, D as projectContextEngineAssemblyForCodex, E as neutralizeCodexExplicitMentionSigils, O as resolveCodexContextEngineProjectionMaxChars, S as CodexContextAttachmentError, T as isCodexDurableCustomMessage, _ as readCodexMcpToolUiVisibility, a as buildTurnStartParams, b as isContextEngineBindingCompatible, c as assertScheduledCodexAppAuthorityRuntime, d as buildScheduledCodexAppServerConnectionIdentity, f as captureScheduledCodexAppAuthority, g as readCodexMcpToolConnectorId, h as resolveScheduledCodexAppCreatorCaptureDecision, i as buildTurnCollaborationMode, k as resolveCodexContextEngineProjectionReserveTokens, l as buildLegacyScheduledCodexAppRecoveryPrompt, m as readCurrentCodexScheduledAppPolicy$1, n as buildCodexParentLocalInstructions, o as buildCodexUserInput, p as intersectCodexPluginThreadConfigWithScheduledAuthority, s as startOrResumeThread, t as buildCodexHistoryProvenancePrefix, u as buildScheduledCodexAppAuthorityInputFingerprint, v as isCodexAppServerProfilerEnabled, w as fitCodexProjectedContextForTurnStart, x as CODEX_TURN_START_TEXT_INPUT_MAX_CHARS, y as buildContextEngineBinding } from "./thread-lifecycle-B3mfz1TG.mjs";
29
+ import { a as resolveCodexRunSessionBindingAuthority, n as createCodexSessionGenerationSupersededError, o as resolveCodexSessionBinding } from "./session-binding-Cm0apEbd.mjs";
30
+ import { n as CodexThreadPolicyHandoffError } from "./thread-policy-DGuQsuFC.mjs";
31
+ import { r as retainCodexAppServerBindingSubscription, s as withExclusiveCodexAppServerThread, t as isSameCodexAppServerThreadOwner } from "./thread-ownership-DcTtAcXj.mjs";
32
+ import { c as promptSnapshot, i as mirrorPromptAtTurnStartBestEffort, n as createCodexAppServerUserMessagePersistenceNotifier, o as buildCodexUserPromptMessage, s as buildResolvedCodexUserPromptMessage, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-BtHDBp1G.mjs";
33
+ import { a as resolveCodexPromptError, i as refreshCodexUsageLimitPromptError, n as formatCodexTurnStartUsageLimitError, r as markCodexAuthProfileBlockedFromRateLimits, t as CodexUsageLimitPromptError } from "./usage-limit-error-DUMbefVY.mjs";
30
34
  import { t as persistCodexContextCompactionActivity } from "./context-compaction-activity-CMla5FPJ.mjs";
31
35
  import { t as attemptTerminal } from "./attempt-terminal-gZrxQ35N.mjs";
32
36
  import { a as shouldKeepCodexSharedAbortOpen, i as runCodexAgentEndHook, n as ensureCodexWorkspaceDirOnce, o as withCodexAppServerFastModeServiceTier, r as estimateCodexAppServerProjectedTurnTokens, t as emitCodexAppServerEvent } from "./run-attempt-lifecycle-B7JbY4-F.mjs";
33
- import { t as CODEX_INFERENCE_GENERATION_KEY } from "./inference-context-fulhZuz8.mjs";
34
- import { i as createAssistantReasoningMessage, n as createAssistantCommentaryMessage, r as createAssistantMessage, t as createAssistantAsyncMessage } from "./event-projector-assistant-message-DNUR1s0A.mjs";
35
- import { _ as inferCodexDynamicToolMeta, b as sanitizeCodexToolArguments, v as isCodexCommandBearingToolCall, x as sanitizeCodexToolResponse, y as resolveCodexToolProgressDetailMode } from "./native-subagent-task-ids-DsuOonKv.mjs";
36
- import { C as shouldRequireCodexSandboxExecServerEnvironment, S as shouldEnableCodexAppServerNativeToolSurface, _ as resolveCodexAppServerHookChannelId, a as emitDynamicToolStartedDiagnostic, c as ensureCodexSandboxExecServerEnvironment, d as CodexNativeToolLifecycleProjector, f as buildDynamicTools, g as resolveCodexAppServerExecutionCwd, h as formatCodexDynamicToolBuildStageSummary, i as emitDynamicToolErrorDiagnostic, l as releaseCodexSandboxExecServerEnvironment, m as disableCodexPluginThreadConfig, n as projectCodexExecutableDynamicTools, o as emitDynamicToolTerminalDiagnostic, p as createCodexDynamicToolBuildStageTracker, r as routeCodexAppServerElicitationRequest, s as handleCodexAppServerApprovalRequest, t as createCodexDynamicToolBridge, u as readBoundedCodexRemoteWorkspaceFile, v as resolveCodexExternalSandboxPolicyForOpenClawSandbox, w as shouldWarnCodexDynamicToolBuildStageSummary, x as resolveCodexSandboxEnvironmentSelection, y as resolveCodexMessageToolProvider } from "./dynamic-tools-D16lOp67.mjs";
37
- import { t as resolveCodexProviderWebSearchSupport } from "./provider-capabilities-B8J4Dy-O.mjs";
38
- import { a as requestPluginApprovalOutcome } from "./plugin-approval-roundtrip-CjfzafAZ.mjs";
39
- import { a as CodexToolProgressProjection, i as CodexToolTranscriptProjection, n as CodexEventProjection, o as shouldEmitTranscriptToolProgress, r as emitCodexAgentEvent, t as codexNativeSubagentMonitorRuntime } from "./native-subagent-monitor-B1hxzIOy.mjs";
40
- import { a as resolveCodexAppServerForModelProvider, i as resolveCodexSessionPermissionCwd, n as applyCodexSessionPermissionPolicy, r as resolveCodexEffectiveSessionPermissionPolicy } from "./session-permission-policy-DhurXY0l.mjs";
41
- import { a as getCodexWorkspaceMemoryToolNames, c as readContextEngineThreadBootstrapProjection, d as resolveCodexDeliveryHintPreservedInputRange, f as resolveContextEngineBootstrapProjectionDecision, i as buildCodexWorkspaceBootstrapContext, l as readMirroredSessionHistoryMessages, n as buildCodexSystemPromptReport, r as buildCodexWatchedSessionsContext, s as prependCodexOpenClawPromptContext, t as buildCodexOpenClawPromptContext, u as renderCodexSkillsCollaborationInstructions } from "./attempt-context-VXVwTCfS.mjs";
37
+ import { t as CODEX_INFERENCE_GENERATION_KEY } from "./inference-context-D96l9-ew.mjs";
38
+ import { i as createAssistantReasoningMessage, n as createAssistantCommentaryMessage, r as createAssistantMessage, t as createAssistantAsyncMessage } from "./event-projector-assistant-message-BsruvNrH.mjs";
39
+ import { C as sanitizeCodexToolArguments, S as resolveCodexToolProgressDetailMode, b as inferCodexDynamicToolMeta, w as sanitizeCodexToolResponse, x as isCodexCommandBearingToolCall } from "./native-subagent-task-ids-wb8CKZGN.mjs";
40
+ import { C as shouldEnableCodexAppServerNativeToolSurface, E as mapCodexAppServerRemoteWorkspacePath, S as resolveCodexSandboxEnvironmentSelection, T as shouldWarnCodexDynamicToolBuildStageSummary, _ as formatCodexDynamicToolBuildStageSummary, a as emitDynamicToolStartedDiagnostic, b as resolveCodexExternalSandboxPolicyForOpenClawSandbox, c as ensureCodexSandboxExecServerEnvironment, d as hasCodexNativeBackgroundProcesses, f as readBoundedCodexRemoteWorkspaceFile, g as disableCodexPluginThreadConfig, h as createCodexDynamicToolBuildStageTracker, i as emitDynamicToolErrorDiagnostic, l as releaseCodexSandboxExecServerEnvironment, m as buildDynamicTools, n as projectCodexExecutableDynamicTools, o as emitDynamicToolTerminalDiagnostic, p as CodexNativeToolLifecycleProjector, r as routeCodexAppServerElicitationRequest, s as handleCodexAppServerApprovalRequest, t as createCodexDynamicToolBridge, u as CodexNativeProcessAuthority, v as resolveCodexAppServerExecutionCwd, w as shouldRequireCodexSandboxExecServerEnvironment, x as resolveCodexMessageToolProvider, y as resolveCodexAppServerHookChannelId } from "./dynamic-tools-BDXl-8Cw.mjs";
41
+ import { t as resolveCodexProviderWebSearchSupport } from "./provider-capabilities-BfE88FZ5.mjs";
42
+ import { a as requestPluginApprovalOutcome } from "./plugin-approval-roundtrip-C0MZzCuP.mjs";
43
+ import { a as CodexToolProgressProjection, i as CodexToolTranscriptProjection, n as CodexEventProjection, o as shouldEmitTranscriptToolProgress, r as emitCodexAgentEvent, t as codexNativeSubagentMonitorRuntime } from "./native-subagent-monitor-D3filLY2.mjs";
44
+ import { a as resolveCodexAppServerForModelProvider, i as resolveCodexSessionPermissionCwd, n as applyCodexSessionPermissionPolicy, r as resolveCodexEffectiveSessionPermissionPolicy } from "./session-permission-policy-BI1QK_98.mjs";
45
+ import { a as getCodexContextFileDisplayBasename, c as normalizeCodexContextFilePath, d as shouldInjectCodexOpenClawPromptContext, i as getCodexContextFileBasename, l as normalizeCodexDynamicToolName, n as CODEX_NATIVE_PROJECT_DOC_BASENAMES, o as getCodexWorkspaceMemoryToolNames, r as buildCodexWorkspaceBootstrapContext, s as isNonEmptyString$1 } from "./attempt-workspace-context-DUVEn_CS.mjs";
42
46
  import { n as captureCodexSettledTurnFinalizationContext } from "./settled-turn-context-fmwouT5I.mjs";
43
- import { a as runCodexComputerUseLiveTest, n as ensureCodexComputerUse, t as defaultCodexPluginMetadataCache } from "./plugin-metadata-cache-DsS5buNa.mjs";
44
- import { asOptionalRecord, normalizeOptionalString, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
47
+ import { a as runCodexComputerUseLiveTest, n as ensureCodexComputerUse, t as defaultCodexPluginMetadataCache } from "./plugin-metadata-cache-Ctmo83k_.mjs";
48
+ import { asOptionalRecord, normalizeOptionalString, readNonBlankString, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
45
49
  import { createHash } from "node:crypto";
46
50
  import { isDeepStrictEqual } from "node:util";
47
51
  import { resolveAgentConfig, resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
48
52
  import { MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
49
53
  import path from "node:path";
50
54
  import fs from "node:fs/promises";
55
+ import { isPathStrictlyInside, readFileWindowFully, root } from "openclaw/plugin-sdk/file-access-runtime";
51
56
  import { addAbortListener } from "node:events";
52
57
  import { truncateUtf16Safe, truncateUtf8Prefix } from "openclaw/plugin-sdk/text-utility-runtime";
53
58
  import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
54
59
  import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
55
60
  import { Buffer as Buffer$1 } from "node:buffer";
56
- import { isPathStrictlyInside, root } from "openclaw/plugin-sdk/file-access-runtime";
57
61
  import { resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
58
- import { AgentHarnessPreflightError, CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, agentHarnessStructuredInput, assembleHarnessContextEngine, assertContextEngineHostSupport, bootstrapHarnessContextEngine, buildAgentHookContextChannelFields, buildEmbeddedForegroundPromptContext, buildHarnessContextEngineRuntimeContext, cancelPendingAgentQuestionForSession, claimPendingAgentQuestionAnswer, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, detectAndLoadAgentHarnessPromptImages, embeddedAgentLog, emptyAgentHarnessUserInputAnswers, formatErrorMessage, formatFastModeAutoProgressText, getAgentHarnessHookRunner, hasBeforeToolCallPolicy, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, prepareHarnessNativeMcpAppPreview, projectAgentHarnessTranscriptMessageForDisplay, projectProgressCardChannelUpdate, resolveAgentDir as resolveAgentDir$2, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveAttemptFsWorkspaceOnly, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveUserPath, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
62
+ import { AgentHarnessPreflightError, CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, agentHarnessStructuredInput, assembleHarnessContextEngine, assertContextEngineHostSupport, bootstrapHarnessContextEngine, buildAgentHookContextChannelFields, buildEmbeddedForegroundPromptContext, buildHarnessContextEngineRuntimeContext, buildWatchedSessionsHarnessContext, cancelPendingAgentQuestionForSession, claimPendingAgentQuestionAnswer, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, detectAndLoadAgentHarnessPromptImages, embeddedAgentLog, emptyAgentHarnessUserInputAnswers, formatErrorMessage, formatFastModeAutoProgressText, getAgentHarnessHookRunner, hasBeforeToolCallPolicy, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, prepareHarnessNativeMcpAppPreview, projectAgentHarnessTranscriptMessageForDisplay, projectAgentToolActivity, projectProgressCardChannelUpdate, resolveAgentDir as resolveAgentDir$2, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveAttemptFsWorkspaceOnly, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveUserPath, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
59
63
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
60
- import { getSessionEntry, parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
64
+ import { getSessionEntry } from "openclaw/plugin-sdk/session-store-runtime";
61
65
  import { acknowledgeInternalToolResult } from "openclaw/plugin-sdk/agent-harness-tool-runtime";
62
66
  import { captureFinalCodexCronCreatorToolAllowlist, formatMcpCodexApprovalRemedy, materializeStaticMcpToolsForHarnessRun, resolveCodexMcpToolOverridesForAgent, resolveCodexTtsProvenanceTransfer } from "openclaw/plugin-sdk/codex-mcp-projection";
63
67
  import { appendSessionYieldContext, hasPromptImageInput } from "openclaw/plugin-sdk/session-transcript-runtime";
68
+ import { prepareAgentWorkspaceAttachments } from "openclaw/plugin-sdk/agent-workspace-runtime";
64
69
  import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-local-roots";
65
70
  import { isSilentReplyPayloadText } from "openclaw/plugin-sdk/reply-chunking";
66
71
  import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
67
72
  import { resolveGeneratedMediaMaxBytes } from "openclaw/plugin-sdk/media-generation-runtime";
68
- import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
73
+ import { normalizeMediaReferenceForComparison, saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
69
74
  import { stripInvisibleUnicode } from "openclaw/plugin-sdk/web-content-extractor";
75
+ import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
70
76
  import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
71
77
  //#region extensions/codex/src/app-server/attempt-preparation-timing.ts
72
78
  /** Records startup before the native turn owns inference and tool execution. */
@@ -216,7 +222,10 @@ function createCodexSteeringQueue(params) {
216
222
  for (const item of pendingItems) {
217
223
  if (!isCurrent(item)) continue;
218
224
  try {
219
- prepared.push(Object.assign(item, { prepared: await params.prepareMessage(item.text, item) }));
225
+ prepared.push(Object.assign(item, { prepared: await params.prepareMessage(item.text, item, () => {
226
+ assertActive();
227
+ item.assertCurrent();
228
+ }) }));
220
229
  } catch (error) {
221
230
  if (isCurrent(item)) throw error;
222
231
  }
@@ -447,7 +456,7 @@ var CodexAssistantProjection = class {
447
456
  if (item?.type === "agentMessage" && typeof item.text === "string") {
448
457
  this.rememberAssistantItem(item.id);
449
458
  this.assistantTextByItem.set(item.id, item.text);
450
- if (item.text && this.isCommentaryAssistantItem(item.id)) {
459
+ if (this.isCommentaryAssistantItem(item.id)) {
451
460
  this.emitCommentaryProgress({
452
461
  itemId: item.id,
453
462
  text: item.text,
@@ -481,15 +490,11 @@ var CodexAssistantProjection = class {
481
490
  this.pendingRawCommentaryEchoes -= 1;
482
491
  return;
483
492
  }
484
- const text = extractRawAssistantText(item);
485
493
  if (isPendingTerminalAssistantEcho) {
486
- const typedItemId = pendingTerminalAssistantEchoItemId;
487
494
  this.pendingRawTerminalAssistantEchoItemId = void 0;
488
- if (this.assistantTextByItem.get(typedItemId)?.trim() || !text) return;
489
- this.rememberAssistantItem(typedItemId);
490
- this.assistantTextByItem.set(typedItemId, text);
491
495
  return;
492
496
  }
497
+ const text = extractRawAssistantText(item);
493
498
  if (text === void 0 || !text && (phase === "commentary" || activeItemIds.size > 0 || readStringField(item, "type") !== "message")) return;
494
499
  const itemId = rawItemId ?? `raw-assistant-${this.assistantItemOrder.length + 1}`;
495
500
  const isIdlessTerminalAssistantAfterCompletedWork = candidateWasSupersededBeforeRaw && rawItemId === void 0 && pendingTerminalAssistantEchoItemId === void 0 && activeItemIds.size === 0;
@@ -816,7 +821,7 @@ var CodexGeneratedMediaProjection = class {
816
821
  this.config = config;
817
822
  this.remote = remote;
818
823
  this.itemIds = /* @__PURE__ */ new Set();
819
- this.urlsByItemId = /* @__PURE__ */ new Map();
824
+ this.mediaByItemId = /* @__PURE__ */ new Map();
820
825
  this.gatewayMaterializedItemIds = /* @__PURE__ */ new Set();
821
826
  this.pendingMaterializationsByItemId = /* @__PURE__ */ new Map();
822
827
  }
@@ -826,6 +831,11 @@ var CodexGeneratedMediaProjection = class {
826
831
  async recordNative(item) {
827
832
  if (item?.type !== "imageGeneration") return;
828
833
  this.itemIds.add(item.id);
834
+ const savedPath = readItemString(item, "savedPath")?.trim();
835
+ if (savedPath) this.mediaByItemId.set(item.id, {
836
+ ...this.mediaByItemId.get(item.id),
837
+ savedPath
838
+ });
829
839
  const result = readItemString(item, "result");
830
840
  if (result) {
831
841
  await this.recordImage({
@@ -836,7 +846,6 @@ var CodexGeneratedMediaProjection = class {
836
846
  });
837
847
  return;
838
848
  }
839
- const savedPath = readItemString(item, "savedPath")?.trim();
840
849
  if (savedPath) {
841
850
  if (this.remote?.remoteWorkspaceRoot) {
842
851
  if (!this.remote.readFile) {
@@ -937,22 +946,53 @@ var CodexGeneratedMediaProjection = class {
937
946
  });
938
947
  }
939
948
  }
940
- buildToolMediaUrls(params) {
949
+ projectDelivery(params) {
950
+ const generatedUrls = /* @__PURE__ */ new Set();
951
+ const generatedUrlBySource = /* @__PURE__ */ new Map();
952
+ for (const { mediaUrl, savedPath } of this.mediaByItemId.values()) {
953
+ if (!mediaUrl) continue;
954
+ generatedUrls.add(mediaUrl);
955
+ generatedUrlBySource.set(normalizeMediaReferenceForComparison(mediaUrl), mediaUrl);
956
+ if (savedPath) generatedUrlBySource.set(normalizeMediaReferenceForComparison(savedPath), mediaUrl);
957
+ }
958
+ const sentMediaUrls = new Set(params.messagingToolSentMediaUrls);
959
+ const generatedUrlsByTarget = /* @__PURE__ */ new Map();
960
+ for (const delivery of params.confirmedMediaDeliveries ?? []) for (const sourceUrl of delivery.sourceUrls) {
961
+ const generatedUrl = generatedUrlBySource.get(normalizeMediaReferenceForComparison(sourceUrl));
962
+ if (!generatedUrl) continue;
963
+ if (delivery.kind === "sourceReply") generatedUrls.delete(generatedUrl);
964
+ else {
965
+ const targetUrls = generatedUrlsByTarget.get(delivery.target) ?? /* @__PURE__ */ new Set();
966
+ targetUrls.add(generatedUrl);
967
+ generatedUrlsByTarget.set(delivery.target, targetUrls);
968
+ sentMediaUrls.add(generatedUrl);
969
+ }
970
+ }
941
971
  const mediaUrls = new Set(params.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []);
942
- if ((params.messagingToolSentMediaUrls?.length ?? 0) === 0) for (const mediaUrl of this.urlsByItemId.values()) mediaUrls.add(mediaUrl);
943
- return mediaUrls.size > 0 ? [...mediaUrls] : params.toolMediaUrls;
944
- }
945
- buildHostOwnedMediaUrls(params) {
946
- if ((params.messagingToolSentMediaUrls?.length ?? 0) > 0) return;
947
- const mediaUrls = [...this.urlsByItemId.values()];
948
- return mediaUrls.length > 0 ? mediaUrls : void 0;
972
+ for (const mediaUrl of generatedUrls) mediaUrls.add(mediaUrl);
973
+ return {
974
+ toolMediaUrls: mediaUrls.size > 0 ? [...mediaUrls] : params.toolMediaUrls,
975
+ hostOwnedToolMediaUrls: generatedUrls.size > 0 ? [...generatedUrls] : void 0,
976
+ messagingToolSentMediaUrls: [...sentMediaUrls],
977
+ messagingToolSentTargets: params.messagingToolSentTargets.map((target) => {
978
+ const aliases = generatedUrlsByTarget.get(target);
979
+ return aliases ? {
980
+ ...target,
981
+ mediaUrls: [.../* @__PURE__ */ new Set([...target.mediaUrls ?? [], ...aliases])]
982
+ } : target;
983
+ })
984
+ };
949
985
  }
950
986
  recordUrl(params) {
951
- if (this.urlsByItemId.has(params.itemId) && params.replaceExisting !== true) {
987
+ const existing = this.mediaByItemId.get(params.itemId);
988
+ if (existing?.mediaUrl && params.replaceExisting !== true) {
952
989
  this.itemIds.add(params.itemId);
953
990
  return;
954
991
  }
955
- this.urlsByItemId.set(params.itemId, params.mediaUrl);
992
+ this.mediaByItemId.set(params.itemId, {
993
+ ...existing,
994
+ mediaUrl: params.mediaUrl
995
+ });
956
996
  this.itemIds.add(params.itemId);
957
997
  }
958
998
  };
@@ -1220,7 +1260,8 @@ var CodexTerminalFailureProjection = class {
1220
1260
  this.promptErrorSource = null;
1221
1261
  }
1222
1262
  record(params) {
1223
- this.providerRefusal ??= readCodexProviderRefusal(params.message, params.codexErrorInfo);
1263
+ const refusal = readCodexProviderRefusal(params.message, params.codexErrorInfo, params);
1264
+ if (!this.providerRefusal || refusal?.category === "misalignment" && this.providerRefusal.category === "misalignment" && params.misalignment != null) this.providerRefusal = refusal;
1224
1265
  if (this.providerRefusal) return;
1225
1266
  this.promptError = resolveCodexPromptError({
1226
1267
  message: params.message,
@@ -1422,7 +1463,8 @@ var CodexTurnProjection = class {
1422
1463
  });
1423
1464
  const toolMetas = this.toolProgressProjection.toolMetas;
1424
1465
  const hadPotentialSideEffects = toolTelemetry.didSendViaMessagingTool || Boolean(toolTelemetry.successfulCronAdds || toolTelemetry.acceptedSessionSpawns?.length) || this.generatedMediaProjection.hasGeneratedMedia() || this.toolProgressProjection.hasPotentialSideEffects;
1425
- const sentMediaUrls = new Set(toolTelemetry.messagingToolSentMediaUrls.map((url) => url.trim()));
1466
+ const mediaDelivery = this.generatedMediaProjection.projectDelivery(toolTelemetry);
1467
+ const sentMediaUrls = new Set(mediaDelivery.messagingToolSentMediaUrls.map((url) => url.trim()));
1426
1468
  const toolAutoDeliveryMediaUrls = toolTelemetry.toolAutoDeliveryMediaUrls?.filter((url) => !sentMediaUrls.has(url.trim()));
1427
1469
  const result = {
1428
1470
  terminal: attemptTerminal.normalize({
@@ -1446,12 +1488,9 @@ var CodexTurnProjection = class {
1446
1488
  didDeliverSourceReplyViaMessageTool: toolTelemetry.didDeliverSourceReplyViaMessageTool === true,
1447
1489
  sourceReplyDelivered: toolTelemetry.sourceReplyDelivered,
1448
1490
  messagingToolSentTexts: toolTelemetry.messagingToolSentTexts,
1449
- messagingToolSentMediaUrls: toolTelemetry.messagingToolSentMediaUrls,
1450
- messagingToolSentTargets: toolTelemetry.messagingToolSentTargets,
1491
+ ...mediaDelivery,
1451
1492
  messagingToolSourceReplyPayloads: toolTelemetry.messagingToolSourceReplyPayloads ?? [],
1452
1493
  heartbeatToolResponse: toolTelemetry.heartbeatToolResponse,
1453
- toolMediaUrls: this.generatedMediaProjection.buildToolMediaUrls(toolTelemetry),
1454
- hostOwnedToolMediaUrls: this.generatedMediaProjection.buildHostOwnedMediaUrls(toolTelemetry),
1455
1494
  toolAudioAsVoice: toolTelemetry.toolAudioAsVoice,
1456
1495
  successfulCronAdds: toolTelemetry.successfulCronAdds,
1457
1496
  acceptedSessionSpawns: toolTelemetry.acceptedSessionSpawns,
@@ -1482,6 +1521,7 @@ var CodexTurnProjection = class {
1482
1521
  };
1483
1522
  //#endregion
1484
1523
  //#region extensions/codex/src/app-server/event-projector.ts
1524
+ const optedOutNotificationMethods = new Set(CODEX_APP_SERVER_OPT_OUT_NOTIFICATION_METHODS);
1485
1525
  var CodexAppServerEventProjector = class extends CodexTurnProjection {
1486
1526
  getCompletedTurnStatus() {
1487
1527
  return this.completedTurn?.status;
@@ -1634,23 +1674,23 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
1634
1674
  this.terminalFailure.record({
1635
1675
  message: readCodexErrorNotificationMessage(params),
1636
1676
  codexErrorInfo,
1677
+ misalignment: isJsonObject(params.error) ? params.error.misalignment : void 0,
1678
+ nativeThreadId: this.threadId,
1679
+ nativeTurnId: this.turnId,
1637
1680
  rateLimits: this.options.readRecentRateLimits?.(),
1638
1681
  fallbackMessage: "codex app-server error",
1639
1682
  promptErrorSource: compactionFailure ? "compaction" : "prompt"
1640
1683
  });
1641
1684
  break;
1642
1685
  }
1643
- case "thread/compacted":
1644
1686
  case "turn/started":
1645
- case "turn/diff/updated":
1646
1687
  case "item/reasoning/summaryPartAdded":
1647
1688
  case "item/commandExecution/terminalInteraction":
1648
- case "item/fileChange/outputDelta":
1649
1689
  case "item/fileChange/patchUpdated":
1650
1690
  case "item/mcpToolCall/progress":
1651
1691
  case "model/verification":
1652
1692
  case "turn/moderationMetadata": break;
1653
- default: this.diagnostics.warnUnknownEvent(notification, params);
1693
+ default: if (!optedOutNotificationMethods.has(notification.method)) this.diagnostics.warnUnknownEvent(notification, params);
1654
1694
  }
1655
1695
  if (!this.projectionClosed && [
1656
1696
  "item/started",
@@ -1834,7 +1874,7 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
1834
1874
  });
1835
1875
  }
1836
1876
  async handleTurnCompleted(params) {
1837
- const turn = readCodexTurn(params.turn);
1877
+ const turn = readCodexTurnCompletedNotification(params)?.turn;
1838
1878
  if (!turn || turn.id !== this.turnId) return;
1839
1879
  this.completedTurn = turn;
1840
1880
  this.eventProjection.endSafetyBuffering();
@@ -1847,6 +1887,9 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
1847
1887
  this.terminalFailure.record({
1848
1888
  message: turn.error?.message,
1849
1889
  codexErrorInfo,
1890
+ misalignment: turn.error?.misalignment,
1891
+ nativeThreadId: this.threadId,
1892
+ nativeTurnId: this.turnId,
1850
1893
  rateLimits: this.options.readRecentRateLimits?.(),
1851
1894
  fallbackMessage: "codex app-server turn failed",
1852
1895
  promptErrorSource: compactionFailure ? "compaction" : "prompt"
@@ -1860,7 +1903,7 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
1860
1903
  this.eventProjection.emitCompactionEnd(itemId, false);
1861
1904
  }
1862
1905
  }
1863
- const turnItems = turn.items ?? [];
1906
+ const turnItems = turn.items;
1864
1907
  const unsettledAsyncDeliveries = this.asyncDeliveryProjection.pending();
1865
1908
  const lastToolItem = turnItems.findLast((item) => matchesCodexSnapshotTurn(item, this.turnId) && (item.type === "dynamicToolCall" || shouldClearTerminalPresentationForNativeItem(item)));
1866
1909
  if (lastToolItem?.type !== "dynamicToolCall") this.nativeToolLifecycleProjector.clearTerminalPresentationForNativeItem(lastToolItem);
@@ -2175,52 +2218,31 @@ const MAX_USER_INPUT_HEADER = 64;
2175
2218
  const MAX_USER_INPUT_TEXT = 4096;
2176
2219
  /** Creates the single per-turn owner for Codex operator input. */
2177
2220
  function createCodexUserInputBridge(params) {
2178
- const jobs = [];
2179
- let activeCompletion;
2221
+ const cleanup = new AbortController();
2222
+ const bridgeSignal = params.signal ? AbortSignal.any([params.signal, cleanup.signal]) : cleanup.signal;
2223
+ let completion = Promise.resolve();
2180
2224
  const inputSessionKey = params.paramsForRun.sessionKey ?? params.paramsForRun.sessionId;
2181
- const pump = () => {
2182
- const job = jobs[0];
2183
- if (activeCompletion || !job) return;
2184
- activeCompletion = job.run(job.abort.signal).catch((error) => {
2185
- embeddedAgentLog.warn("failed to bridge codex operator input", { error });
2186
- return job.abort.signal.aborted ? job.cancelValue : job.failureValue;
2187
- }).then((value) => {
2188
- const response = job.abort.signal.aborted ? job.cancelValue : value ?? job.failureValue;
2189
- job.onResponse?.(response);
2190
- job.resolve(response);
2191
- }).finally(() => {
2192
- if (jobs[0] === job) jobs.shift();
2193
- activeCompletion = void 0;
2194
- pump();
2195
- });
2196
- };
2197
- const enqueue = (definition) => {
2198
- if (params.signal?.aborted) return Promise.resolve(definition.cancelValue);
2199
- return new Promise((resolve) => {
2200
- jobs.push({
2201
- ...definition,
2202
- resolve
2203
- });
2204
- pump();
2225
+ const enqueue = (job, requestSignal) => {
2226
+ const signal = requestSignal ? AbortSignal.any([bridgeSignal, requestSignal]) : bridgeSignal;
2227
+ if (signal.aborted) return Promise.resolve(job.cancelValue);
2228
+ return new Promise((resolve, reject) => {
2229
+ const onAbort = () => resolve(job.cancelValue);
2230
+ signal.addEventListener("abort", onAbort, { once: true });
2231
+ completion = completion.then(async () => {
2232
+ signal.removeEventListener("abort", onAbort);
2233
+ if (signal.aborted) return;
2234
+ let value;
2235
+ try {
2236
+ value = await job.run(signal);
2237
+ } catch (error) {
2238
+ if (!signal.aborted) embeddedAgentLog.warn("failed to bridge codex operator input", { error });
2239
+ }
2240
+ const response = signal.aborted ? job.cancelValue : value ?? job.failureValue;
2241
+ if (!(signal.reason instanceof CodexServerRequestResolvedError)) job.onResponse?.(response);
2242
+ resolve(response);
2243
+ }).catch(reject);
2205
2244
  });
2206
2245
  };
2207
- const cancelJob = (job) => {
2208
- const index = jobs.indexOf(job);
2209
- if (index < 0) return;
2210
- if (index === 0) {
2211
- job.abort.abort(/* @__PURE__ */ new Error("Codex operator input request cancelled"));
2212
- return;
2213
- }
2214
- jobs.splice(index, 1);
2215
- job.resolve(job.cancelValue);
2216
- };
2217
- const cancelPending = async () => {
2218
- const pendingCompletion = activeCompletion;
2219
- const queuedJobs = jobs.splice(1);
2220
- for (const job of queuedJobs) job.resolve(job.cancelValue);
2221
- jobs[0]?.abort.abort(/* @__PURE__ */ new Error("Codex operator input request cancelled"));
2222
- await pendingCompletion;
2223
- };
2224
2246
  const execute = (input, timeoutMs, signal) => agentHarnessStructuredInput.run({
2225
2247
  input,
2226
2248
  sessionKey: inputSessionKey,
@@ -2236,9 +2258,8 @@ function createCodexUserInputBridge(params) {
2236
2258
  urlIntro: "Codex needs confirmation:"
2237
2259
  }
2238
2260
  });
2239
- params.signal?.addEventListener("abort", () => void cancelPending(), { once: true });
2240
2261
  return {
2241
- async handleRequest(request) {
2262
+ async handleRequest(request, requestSignal) {
2242
2263
  const requestParams = readUserInputParams(request.params);
2243
2264
  if (!requestParams || requestParams.threadId !== params.threadId || requestParams.turnId !== params.turnId) return;
2244
2265
  if (requestParams.questions.length === 0) return emptyUserInputResponse();
@@ -2246,8 +2267,6 @@ function createCodexUserInputBridge(params) {
2246
2267
  const input = compileUserInputQuestions(requestParams.questions);
2247
2268
  const cancelValue = emptyUserInputResponse();
2248
2269
  return await enqueue({
2249
- requestId: request.id,
2250
- abort: new AbortController(),
2251
2270
  cancelValue,
2252
2271
  failureValue: cancelValue,
2253
2272
  onResponse: requestParams.questions.some((question) => question.isSecret) ? void 0 : (response) => params.onOrdinaryResponse?.({
@@ -2259,39 +2278,27 @@ function createCodexUserInputBridge(params) {
2259
2278
  const result = await execute(input, timeoutMs, signal);
2260
2279
  return result.status === "answered" ? gatewayAnswersToCodexResponse(result.answers) : cancelValue;
2261
2280
  }
2262
- });
2281
+ }, requestSignal);
2263
2282
  },
2264
- async handleElicitationRequest(request) {
2283
+ async handleElicitationRequest(request, requestSignal) {
2265
2284
  if (readOwnDataString(request.params, "threadId") !== params.threadId) return;
2266
2285
  const requestSnapshot = agentHarnessStructuredInput.snapshot(request.params);
2267
- if (!agentHarnessStructuredInput.isRecord(requestSnapshot)) {
2268
- const cancelValue = createCodexElicitationResponse("cancel");
2269
- return await enqueue({
2270
- requestId: request.id,
2271
- abort: new AbortController(),
2272
- cancelValue,
2273
- failureValue: declineElicitation("OpenClaw could not handle this elicitation."),
2274
- run: async (signal) => {
2275
- const result = await execute({
2276
- kind: "unsupported",
2277
- message: "OpenClaw declined a malformed or over-limit MCP elicitation request."
2278
- }, params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS, signal);
2279
- return result.status === "unsupported" ? declineElicitation(result.message) : cancelValue;
2280
- }
2281
- });
2282
- }
2283
- if (readOwnDataString(requestSnapshot, "threadId") !== params.threadId) return;
2286
+ if (agentHarnessStructuredInput.isRecord(requestSnapshot) && readOwnDataString(requestSnapshot, "threadId") !== params.threadId) return;
2284
2287
  const { compileCodexOrdinaryElicitation } = await import("./elicitation-input-DPoK8F7w.mjs");
2285
- const compiled = compileCodexOrdinaryElicitation({
2288
+ const compiled = agentHarnessStructuredInput.isRecord(requestSnapshot) ? compileCodexOrdinaryElicitation({
2286
2289
  snapshot: requestSnapshot,
2287
2290
  turnId: params.turnId
2288
- });
2291
+ }) : {
2292
+ kind: "compiled",
2293
+ input: {
2294
+ kind: "unsupported",
2295
+ message: "OpenClaw declined a malformed or over-limit MCP elicitation request."
2296
+ }
2297
+ };
2289
2298
  if (compiled.kind === "ignored") return;
2290
2299
  const cancelValue = createCodexElicitationResponse("cancel");
2291
2300
  const timeoutMs = params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS;
2292
2301
  return await enqueue({
2293
- requestId: request.id,
2294
- abort: new AbortController(),
2295
2302
  cancelValue,
2296
2303
  failureValue: declineElicitation("OpenClaw could not handle this elicitation."),
2297
2304
  run: async (signal) => {
@@ -2300,20 +2307,15 @@ function createCodexUserInputBridge(params) {
2300
2307
  const content = compiled.input.kind === "ready" && compiled.input.plan.kind === "url" ? null : result.content;
2301
2308
  return createCodexElicitationResponse("accept", content);
2302
2309
  }
2303
- if (result.status === "declined") return declineElicitation(result.message);
2304
- if (result.status === "unsupported") return declineElicitation(result.message);
2310
+ if (result.status === "declined" || result.status === "unsupported") return declineElicitation(result.message);
2305
2311
  return cancelValue;
2306
2312
  }
2307
- });
2308
- },
2309
- handleNotification(notification) {
2310
- if (notification.method !== "serverRequest/resolved" || !isJsonObject(notification.params)) return;
2311
- const requestId = readRequestId(notification.params);
2312
- if (requestId === void 0 || readOwnDataString(notification.params, "threadId") !== params.threadId) return;
2313
- const job = jobs.find((candidate) => typeof candidate.requestId === typeof requestId && candidate.requestId === requestId);
2314
- if (job) cancelJob(job);
2313
+ }, requestSignal);
2315
2314
  },
2316
- cancelPending
2315
+ async cancelPending() {
2316
+ cleanup.abort(/* @__PURE__ */ new Error("Codex operator input request cancelled"));
2317
+ await completion;
2318
+ }
2317
2319
  };
2318
2320
  }
2319
2321
  function compileUserInputQuestions(questions) {
@@ -2394,11 +2396,6 @@ function readOwnDataString(value, key) {
2394
2396
  const descriptor = Object.getOwnPropertyDescriptor(value, key);
2395
2397
  return descriptor && "value" in descriptor && typeof descriptor.value === "string" ? descriptor.value : void 0;
2396
2398
  }
2397
- function readRequestId(record) {
2398
- const descriptor = Object.getOwnPropertyDescriptor(record, "requestId");
2399
- const value = descriptor && "value" in descriptor ? descriptor.value : void 0;
2400
- return typeof value === "string" || typeof value === "number" ? value : void 0;
2401
- }
2402
2399
  function gatewayAnswersToCodexResponse(answers) {
2403
2400
  return { answers: Object.fromEntries(Object.entries(answers).map(([questionId, values]) => [questionId, { answers: values }])) };
2404
2401
  }
@@ -2410,7 +2407,7 @@ function declineElicitation(message) {
2410
2407
  }
2411
2408
  //#endregion
2412
2409
  //#region extensions/codex/src/app-server/run-attempt-active-turn.ts
2413
- function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, turn) {
2410
+ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, { turn, upstreamUserText }) {
2414
2411
  const { prompt, state: resourceState, projectorRef, trajectoryRecorder, pendingNativePreToolUseFailures } = resources;
2415
2412
  const { context, turnState } = prompt;
2416
2413
  const { runtime, attemptTools, hookContext } = context;
@@ -2437,6 +2434,31 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
2437
2434
  provider: runtimeModelSelection.provider
2438
2435
  }
2439
2436
  } : dynamicToolParams;
2437
+ const hostPrepareReplyMedia = params.hostCapabilities.prepareReplyMedia;
2438
+ const remoteWorkspaceRoot = connection.appServer.remoteWorkspaceRoot;
2439
+ const replyMediaClient = resourceState.client;
2440
+ const prepareReplyMedia = hostPrepareReplyMedia && remoteWorkspaceRoot ? async (content, transferSignal) => hostPrepareReplyMedia({
2441
+ ...content,
2442
+ workspaceRoot: remoteWorkspaceRoot,
2443
+ signal: runAbortController.signal,
2444
+ readWorkspaceFile: async (relativePath, { maxBytes, signal }) => {
2445
+ connection.assertCurrent();
2446
+ const file = await readBoundedCodexRemoteWorkspaceFile({
2447
+ client: replyMediaClient,
2448
+ path: mapCodexAppServerRemoteWorkspacePath({
2449
+ value: path.resolve(params.workspaceDir, relativePath),
2450
+ localWorkspaceRoot: params.workspaceDir,
2451
+ remoteWorkspaceRoot
2452
+ }),
2453
+ workspaceRoot: remoteWorkspaceRoot,
2454
+ maxBytes,
2455
+ signal: transferSignal ? AbortSignal.any([signal, transferSignal]) : signal,
2456
+ timeoutMs: connection.appServer.requestTimeoutMs
2457
+ });
2458
+ connection.assertCurrent();
2459
+ return Buffer.from(file.dataBase64, "base64");
2460
+ }
2461
+ }) : void 0;
2440
2462
  const progressCardTool = toolBridge.availableTools.find((tool) => tool.name === "progress_card");
2441
2463
  let nativePlanUpdateOrdinal = 0;
2442
2464
  const prepareNativeMcpAppResultDetails = createCodexNativeMcpAppResultDetailsPreparer({
@@ -2448,20 +2470,6 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
2448
2470
  eventEmitted: false,
2449
2471
  needsTerminalSnapshot: false
2450
2472
  };
2451
- emitExecutionPhaseOnce("turn_accepted", { phase: "turn_accepted" });
2452
- userInputBridgeRef.current = createCodexUserInputBridge({
2453
- paramsForRun: params,
2454
- onOrdinaryResponse: (response) => projectorRef.current?.recordUserInputResponse(response),
2455
- threadId: resourceState.thread.threadId,
2456
- turnId: activeTurnId,
2457
- signal: runAbortController.signal
2458
- });
2459
- trajectoryRecorder?.recordEvent("prompt.submitted", {
2460
- threadId: resourceState.thread.threadId,
2461
- turnId: activeTurnId,
2462
- prompt: turnState.codexTurnPromptText,
2463
- imagesCount: params.images?.length ?? 0
2464
- });
2465
2473
  projectorRef.current = new CodexAppServerEventProjector({
2466
2474
  ...projectionParams,
2467
2475
  onAgentEvent: (event) => {
@@ -2478,7 +2486,17 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
2478
2486
  asyncUserMessageAllowed: params.disableTools !== true && (params.toolsAllow === void 0 || toolBridge.availableTools.some((tool) => tool.name === "message")),
2479
2487
  onAsyncDelivery: async (delivery) => {
2480
2488
  return await codexTranscriptMirrorRuntime.deliverAsyncMessageBestEffort({
2481
- params: projectionParams,
2489
+ params: prepareReplyMedia && projectionParams.onBlockReply ? {
2490
+ ...projectionParams,
2491
+ onBlockReply: async (payload, options) => {
2492
+ const prepared = await prepareReplyMedia({
2493
+ kind: "payload",
2494
+ payload
2495
+ });
2496
+ if (prepared.kind !== "payload") throw new Error("Reply media preparation returned the wrong result kind");
2497
+ await projectionParams.onBlockReply?.(prepared.payload, options);
2498
+ }
2499
+ } : projectionParams,
2482
2500
  cwd: effectiveCwd,
2483
2501
  threadId: resourceState.thread.threadId,
2484
2502
  turnId: activeTurnId,
@@ -2489,9 +2507,9 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
2489
2507
  runAbortSignal: runAbortController.signal,
2490
2508
  remoteWorkspaceRoot: connection.appServer.remoteWorkspaceRoot,
2491
2509
  remoteWorkspaceRequestTimeoutMs: connection.appServer.requestTimeoutMs,
2492
- readRemoteWorkspaceFile: ({ path, maxBytes, signal, timeoutMs }) => readBoundedCodexRemoteWorkspaceFile({
2510
+ readRemoteWorkspaceFile: ({ path: remotePath, maxBytes, signal, timeoutMs }) => readBoundedCodexRemoteWorkspaceFile({
2493
2511
  client: resourceState.client,
2494
- path,
2512
+ path: remotePath,
2495
2513
  maxBytes,
2496
2514
  signal,
2497
2515
  timeoutMs
@@ -2513,7 +2531,7 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
2513
2531
  }
2514
2532
  } } : {},
2515
2533
  ...prepareNativeMcpAppResultDetails ? { prepareNativeMcpAppResultDetails } : {},
2516
- upstreamUserText: turnState.codexTurnPromptText,
2534
+ upstreamUserText,
2517
2535
  onContextCompacted: async () => {
2518
2536
  computerContextEpoch.value += 1;
2519
2537
  delete computerContextEpoch.frameToolCallId;
@@ -2534,22 +2552,14 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
2534
2552
  }
2535
2553
  }
2536
2554
  });
2537
- if (isTerminalTurnStatus(turn.turn.status)) {
2538
- projectorRef.current.settlement.terminalReceipt = turn.turn;
2539
- state.terminalTurnNotificationQueued = true;
2540
- deadlines.beginSettlement(Date.now());
2541
- }
2542
- emitLifecycleStart({
2543
- provider: projectionParams.provider,
2544
- model: projectionParams.modelId
2545
- });
2546
2555
  const activeProjector = projectorRef.current;
2547
- noteProgress("turn:start");
2556
+ let activationFailed = false;
2548
2557
  const abortListener = () => {
2549
2558
  state.abortCleanup = interruptTurn(activeTurnId).then(async (confirmed) => {
2550
- if (!terminalState.explicitCancellationObserved && !state.permissionChangeRestart && !state.timeout) return;
2559
+ if (!activationFailed && !terminalState.explicitCancellationObserved && !state.permissionChangeRestart && !state.timeout) return;
2551
2560
  if (!confirmed) throw new Error(state.permissionChangeRestart ? "Permission change could not confirm the previous Codex turn stopped." : "Codex cancellation could not confirm the turn stopped; background terminals may still be running.");
2552
- await terminateCodexBackgroundTerminals(resourceState.client, resourceState.thread.threadId);
2561
+ if (resources.nativeProcessAuthority) await resources.nativeProcessAuthority.cancelTurn(resourceState.client, resourceState.thread.threadId, activeTurnId);
2562
+ else await terminateCodexBackgroundTerminals(resourceState.client, resourceState.thread.threadId);
2553
2563
  if (state.permissionChangeRestart) state.permissionChangeRestart = "confirmed";
2554
2564
  });
2555
2565
  state.abortCleanup.then(completeTurn, (error) => {
@@ -2557,32 +2567,18 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
2557
2567
  completeTurn();
2558
2568
  });
2559
2569
  };
2560
- runAbortController.signal.addEventListener("abort", abortListener, { once: true });
2561
- if (runAbortController.signal.aborted) abortListener();
2562
- for (const failure of pendingNativePreToolUseFailures.splice(0)) activeProjector.recordNativeToolPreToolUseFailure(failure);
2563
2570
  const notifyUserMessagePersisted = createCodexAppServerUserMessagePersistenceNotifier(params);
2564
- const promptMirrorPromise = mirrorPromptAtTurnStartBestEffort({
2565
- params,
2566
- agentId: sessionAgentId,
2567
- notifyUserMessagePersisted,
2568
- sessionKey: contextSessionKey,
2569
- cwd: effectiveCwd,
2570
- threadId: resourceState.thread.threadId,
2571
- turnId: activeTurnId,
2572
- upstreamUserText: turnState.codexTurnPromptText
2573
- });
2574
- const bindProjection = async () => {
2571
+ const bindProjection = async (promptMirrorPromise) => {
2575
2572
  state.activeLocalProjections += 1;
2576
2573
  try {
2577
- await Promise.race([promptMirrorPromise, completion]);
2578
- if (state.completed) return;
2579
2574
  if (resourceState.turnRoute) try {
2580
- await Promise.race([resourceState.turnRoute.bindTurn(activeTurnId), completion]);
2575
+ await Promise.race([resourceState.turnRoute.bindTurn(activeTurnId, { beforeNotifications: promptMirrorPromise }), completion]);
2581
2576
  } catch (error) {
2582
2577
  if (!state.terminalTurnNotificationQueued && !runAbortController.signal.aborted) throw error;
2583
2578
  await Promise.race([resourceState.turnRoute.drain(), completion]);
2584
2579
  if (!state.completed) throw error;
2585
2580
  }
2581
+ else await Promise.race([promptMirrorPromise, completion]);
2586
2582
  if (!state.completed && isTerminalTurnStatus(turn.turn.status)) {
2587
2583
  if (!isJsonObject(turn.turn)) throw new Error("Codex turn completion payload is not a JSON object");
2588
2584
  await enqueueNotification({
@@ -2612,6 +2608,7 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
2612
2608
  });
2613
2609
  const imageContext = {
2614
2610
  workspaceDir: connection.effectiveWorkspace,
2611
+ agentWorkspaceDir: params.workspaceDir,
2615
2612
  model: params.model,
2616
2613
  config: params.config,
2617
2614
  workspaceOnly,
@@ -2628,7 +2625,18 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
2628
2625
  requestTimeoutMs: connection.appServer.requestTimeoutMs,
2629
2626
  signal: runAbortController.signal,
2630
2627
  assertActive: assertSteeringActive,
2631
- prepareMessage: async (text, options) => {
2628
+ prepareMessage: async (text, options, assertMessageCurrent) => {
2629
+ const attachmentNote = await prepareAgentWorkspaceAttachments({
2630
+ workspaceDir: params.workspaceDir,
2631
+ turn: {
2632
+ config: params.config,
2633
+ media: options.media,
2634
+ timeoutMs: params.timeoutMs,
2635
+ abortSignal: runAbortController.signal,
2636
+ userTurnTranscriptRecorder: options.userTurnTranscriptRecorder
2637
+ },
2638
+ assertCurrent: assertMessageCurrent
2639
+ });
2632
2640
  const result = await detectAndLoadAgentHarnessPromptImages({
2633
2641
  ...imageContext,
2634
2642
  prompt: text,
@@ -2645,7 +2653,7 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
2645
2653
  userTurnTranscriptRecorder: options.userTurnTranscriptRecorder
2646
2654
  });
2647
2655
  return {
2648
- input: buildCodexUserInput(text, result.images),
2656
+ input: buildCodexUserInput(attachmentNote ? `${text}\n\n${attachmentNote}` : text, result.images),
2649
2657
  message: {
2650
2658
  ...source,
2651
2659
  role: "user",
@@ -2788,27 +2796,72 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
2788
2796
  cancel: () => abortExplicitly("cancelled"),
2789
2797
  abort: () => abortExplicitly("aborted")
2790
2798
  };
2791
- if (thread.preserveNativeModel !== true && thread.connectionScope !== "supervision" && !params.expectedSessionRuntimeOwnership) {
2792
- const route = resourceState.turnRoute;
2793
- params.registerPluginRuntimeRefreshConsumer?.(() => resourceState.turnRoute === route && route?.signal.aborted === false && turnRuntime.turnIdRef.current === activeTurnId && !state.completed && !state.terminalTurnNotificationQueued && !runAbortController.signal.aborted);
2794
- }
2795
- const projectionReady = bindProjection();
2796
- params.replyOperation?.attachBackend(handle);
2797
- setActiveEmbeddedRun(params.sessionId, handle, params.sessionKey, params.sessionFile, sessionAgentId);
2798
2799
  const freezeRunTerminalOutcome = () => {
2799
2800
  if (terminalState.terminalOutcomeFrozen) return;
2800
2801
  terminalState.terminalOutcomeFrozen = true;
2801
2802
  params.abortSignal?.removeEventListener("abort", abortFromUpstream);
2802
2803
  };
2803
- if (!runAbortController.signal.aborted && params.permissionChange && !params.permissionChange.applied()) {
2804
- state.permissionChangeRestart = "requested";
2805
- runAbortController.abort("permission-change");
2806
- }
2804
+ const projectionReady = Promise.resolve().then(async () => {
2805
+ runAbortController.signal.addEventListener("abort", abortListener, { once: true });
2806
+ if (runAbortController.signal.aborted) abortListener();
2807
+ try {
2808
+ emitExecutionPhaseOnce("turn_accepted", { phase: "turn_accepted" });
2809
+ userInputBridgeRef.current = createCodexUserInputBridge({
2810
+ paramsForRun: params,
2811
+ onOrdinaryResponse: (response) => activeProjector.recordUserInputResponse(response),
2812
+ threadId: resourceState.thread.threadId,
2813
+ turnId: activeTurnId,
2814
+ signal: runAbortController.signal
2815
+ });
2816
+ trajectoryRecorder?.recordEvent("prompt.submitted", {
2817
+ threadId: resourceState.thread.threadId,
2818
+ turnId: activeTurnId,
2819
+ prompt: turnState.codexTurnPromptText,
2820
+ imagesCount: params.images?.length ?? 0
2821
+ });
2822
+ if (isTerminalTurnStatus(turn.turn.status)) {
2823
+ activeProjector.settlement.terminalReceipt = turn.turn;
2824
+ state.terminalTurnNotificationQueued = true;
2825
+ deadlines.beginSettlement(Date.now());
2826
+ }
2827
+ emitLifecycleStart({
2828
+ provider: projectionParams.provider,
2829
+ model: projectionParams.modelId
2830
+ });
2831
+ noteProgress("turn:start");
2832
+ for (const failure of pendingNativePreToolUseFailures.splice(0)) activeProjector.recordNativeToolPreToolUseFailure(failure);
2833
+ if (thread.preserveNativeModel !== true && thread.connectionScope !== "supervision" && !params.expectedSessionRuntimeOwnership) {
2834
+ const route = resourceState.turnRoute;
2835
+ params.registerPluginRuntimeRefreshConsumer?.(() => resourceState.turnRoute === route && route?.signal.aborted === false && turnRuntime.turnIdRef.current === activeTurnId && !state.completed && !state.terminalTurnNotificationQueued && !runAbortController.signal.aborted);
2836
+ }
2837
+ params.replyOperation?.attachBackend(handle);
2838
+ setActiveEmbeddedRun(params.sessionId, handle, params.sessionKey, params.sessionFile, sessionAgentId);
2839
+ if (!runAbortController.signal.aborted && params.permissionChange && !params.permissionChange.applied()) {
2840
+ state.permissionChangeRestart = "requested";
2841
+ runAbortController.abort("permission-change");
2842
+ }
2843
+ await bindProjection(mirrorPromptAtTurnStartBestEffort({
2844
+ params,
2845
+ agentId: sessionAgentId,
2846
+ notifyUserMessagePersisted,
2847
+ sessionKey: contextSessionKey,
2848
+ cwd: effectiveCwd,
2849
+ threadId: resourceState.thread.threadId,
2850
+ turnId: activeTurnId,
2851
+ upstreamUserText
2852
+ }));
2853
+ } catch (error) {
2854
+ activationFailed = true;
2855
+ runAbortController.abort(error);
2856
+ throw error;
2857
+ }
2858
+ });
2807
2859
  return {
2808
2860
  activeTurnId,
2809
2861
  activeProjector,
2810
2862
  runtimeModelSelection,
2811
2863
  streamState,
2864
+ prepareReplyMedia,
2812
2865
  handle,
2813
2866
  freezeRunTerminalOutcome,
2814
2867
  notifyUserMessagePersisted,
@@ -2819,7 +2872,7 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
2819
2872
  //#endregion
2820
2873
  //#region extensions/codex/src/app-server/run-attempt-cleanup.ts
2821
2874
  async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRuntime, activeTurn) {
2822
- const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, releaseSharedClientLeaseAndRetireOneShotClient, releaseSandboxExecEnvironment, runCleanupStep } = resources;
2875
+ const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, releaseSharedClientLeaseAndRetireOneShotClient, releaseSandboxExecEnvironment, releaseNativeProcessAuthority, retainThreadSubscription, releaseThreadSubscription, runCleanupStep } = resources;
2823
2876
  const { connection } = prompt.context.runtime;
2824
2877
  const { params, options, runAbortController, terminalState, bindingStore, bindingIdentity } = connection;
2825
2878
  const { state, steeringQueueRef, userInputBridgeRef, deadlines } = turnRuntime;
@@ -2859,29 +2912,14 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
2859
2912
  await runCleanupStep("codex-trajectory-flush", () => trajectoryRecorder?.flush());
2860
2913
  const pluginRuntimeRefreshing = state.pluginRuntimeRefreshStop !== void 0 && !runAbortController.signal.aborted && terminalState.settledTurnStatus === "completed";
2861
2914
  const retainLiveIncognitoThread = !pluginRuntimeRefreshing && (terminalState.settledTurnStatus === "completed" || state.permissionChangeRestart === "confirmed" && !params.abortSignal?.aborted) && isIncognitoSessionKey(params.sessionKey);
2862
- const retainLiveThread = (!pluginRuntimeRefreshing && (retainLiveIncognitoThread && resourceState.thread.liveThreadEphemeralPolicy !== void 0 || terminalState.settledTurnStatus !== void 0 && !isIncognitoSessionKey(params.sessionKey) && params.cleanupBundleMcpOnRunEnd !== true && resourceState.thread.liveThreadConfigFingerprint !== void 0 && resourceState.thread.preserveNativeModel !== true && resourceState.thread.connectionScope !== "supervision" && !resourceState.thread.ringZeroConfigFingerprint) && resourceState.thread.clientId === resolveCodexAppServerClientInstanceId(resourceState.client) ? bindingStore.read(bindingIdentity)?.threadId === resourceState.thread.threadId && await bindingStore.withLease(bindingIdentity, async () => {
2863
- if (bindingStore.read(bindingIdentity)?.threadId !== resourceState.thread.threadId) return false;
2864
- return await retainCodexAppServerBindingSubscription(resourceState.client, resourceState.thread.threadId, {
2865
- release: resourceState.thread.liveThreadOwnership?.release,
2866
- configFingerprint: resourceState.thread.liveThreadConfigFingerprint,
2867
- serviceTier: connection.mutable.pluginAppServer.serviceTier,
2868
- ephemeralPolicy: resourceState.thread.liveThreadEphemeralPolicy
2869
- });
2870
- }) : false) || retainLiveIncognitoThread && resourceState.thread.liveThreadEphemeralPolicy === void 0;
2915
+ const retainLiveThread = !pluginRuntimeRefreshing && (retainLiveIncognitoThread && resourceState.thread.liveThreadEphemeralPolicy !== void 0 || terminalState.settledTurnStatus !== void 0 && !isIncognitoSessionKey(params.sessionKey) && params.cleanupBundleMcpOnRunEnd !== true && resourceState.thread.liveThreadConfigFingerprint !== void 0 && !resourceState.thread.ringZeroConfigFingerprint) && await retainThreadSubscription() || retainLiveIncognitoThread && resourceState.thread.liveThreadEphemeralPolicy === void 0;
2871
2916
  if (pluginRuntimeRefreshing) await withExclusiveCodexAppServerThread({
2872
2917
  bindingStore,
2873
2918
  identity: bindingIdentity,
2874
2919
  threadId: resourceState.thread.threadId,
2875
2920
  run: () => bindingStore.withLease(bindingIdentity, async () => {
2876
2921
  if (!isSameCodexAppServerThreadOwner(bindingStore.read(bindingIdentity), resourceState.thread)) throw new Error("Codex plugin refresh lost its managed thread binding.");
2877
- if (!await unsubscribeCodexThreadBestEffort(resourceState.client, {
2878
- threadId: resourceState.thread.threadId,
2879
- timeoutMs: 5e3,
2880
- assertCurrent: connection.assertCurrent
2881
- })) {
2882
- await closeCodexStartupClientBestEffort(resourceState.client);
2883
- throw new Error("Plugin reload could not release the previous Codex thread.");
2884
- }
2922
+ if (!await releaseThreadSubscription(connection.assertCurrent)) throw new Error("Plugin reload could not release the previous Codex thread.");
2885
2923
  if (!await bindingStore.mutate(bindingIdentity, {
2886
2924
  kind: "clear",
2887
2925
  threadId: resourceState.thread.threadId
@@ -2895,11 +2933,7 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
2895
2933
  }) : true;
2896
2934
  if (!retainLiveThread) {
2897
2935
  if (bindingReleased) {
2898
- if (!await unsubscribeCodexThreadBestEffort(resourceState.client, {
2899
- threadId: resourceState.thread.threadId,
2900
- timeoutMs: 5e3
2901
- })) {
2902
- await closeCodexStartupClientBestEffort(resourceState.client);
2936
+ if (!await releaseThreadSubscription()) {
2903
2937
  if (params.oneShotCliRun) await runCleanupStep("codex-one-shot-unsubscribe", async () => {
2904
2938
  throw new Error("Codex one-shot thread unsubscribe was not confirmed");
2905
2939
  });
@@ -2908,14 +2942,12 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
2908
2942
  }
2909
2943
  }
2910
2944
  } finally {
2945
+ if (resourceState.thread.liveThreadOwnership) await runCleanupStep("codex-unsettled-subscription", async () => {
2946
+ await releaseThreadSubscription();
2947
+ });
2911
2948
  await runCleanupStep("codex-user-input-cancel", () => userInputBridgeRef.current?.cancelPending());
2912
2949
  await runCleanupStep("codex-turn-deadline-clear", () => deadlines.dispose());
2913
- await runCleanupStep("codex-dynamic-tool-cleanup", async () => {
2914
- const cleanupReason = terminalState.settledTurnStatus === "completed" ? "completion" : state.timeout ? "timeout" : runAbortController.signal.aborted ? "cancel" : "error";
2915
- const cleanups = prompt.context.attemptTools.runCleanups.splice(0);
2916
- const errors = (await Promise.allSettled(cleanups.map(async (cleanup) => await cleanup(cleanupReason)))).filter((result) => result.status === "rejected");
2917
- if (params.oneShotCliRun && errors.length) throw new AggregateError(errors.map((result) => result.reason), "Codex tool cleanup failed");
2918
- });
2950
+ await prompt.context.attemptTools.disposeTools(terminalState.settledTurnStatus === "completed" ? "completion" : state.timeout ? "timeout" : runAbortController.signal.aborted ? "cancel" : "error");
2919
2951
  await runCleanupStep("codex-route-release", releaseCurrentRoute);
2920
2952
  await checkpointCleanup;
2921
2953
  await runCleanupStep("codex-shared-client-release", releaseSharedClientLeaseAndRetireOneShotClient);
@@ -2931,6 +2963,7 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
2931
2963
  await nativeHookRelay.drain();
2932
2964
  });
2933
2965
  await runCleanupStep("codex-sandbox-release", releaseSandboxExecEnvironment);
2966
+ await runCleanupStep("codex-native-process-source-release", releaseNativeProcessAuthority);
2934
2967
  await runCleanupStep("codex-abort-listener-remove", () => {
2935
2968
  runAbortController.signal.removeEventListener("abort", abortListener);
2936
2969
  });
@@ -2943,6 +2976,39 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
2943
2976
  await state.abortCleanup;
2944
2977
  }
2945
2978
  //#endregion
2979
+ //#region extensions/codex/src/app-server/session-binding-scope.ts
2980
+ /** Carries one prepared run identity through callers that rederive it from public params. */
2981
+ function scopeCodexRunBindingStore(params) {
2982
+ const mapSessionIdentity = (identity) => identity.agentId === params.logicalIdentity.agentId && identity.sessionId === params.logicalIdentity.sessionId && identity.sessionKey?.trim() === params.logicalIdentity.sessionKey?.trim() ? params.physicalIdentity : identity;
2983
+ const mapIdentity = (identity) => identity.kind === "session" ? mapSessionIdentity(identity) : identity;
2984
+ const mapHistoryOwner = (identity, owner) => {
2985
+ const mapped = mapIdentity(identity);
2986
+ return identity.kind === "session" && mapped.kind === "session" && owner.sessionId === identity.sessionId ? {
2987
+ ...owner,
2988
+ sessionId: mapped.sessionId
2989
+ } : owner;
2990
+ };
2991
+ const readMany = params.bindingStore.readMany?.bind(params.bindingStore);
2992
+ return {
2993
+ ...params.bindingStore,
2994
+ read: (identity) => params.bindingStore.read(mapIdentity(identity)),
2995
+ ...readMany ? { readMany: (identities) => readMany(identities.map(mapIdentity)) } : {},
2996
+ readNativeSubagentSubmissions: (identity, owner) => params.bindingStore.readNativeSubagentSubmissions(mapIdentity(identity), mapHistoryOwner(identity, owner)),
2997
+ hasOtherThreadOwner: (threadId, identity) => params.bindingStore.hasOtherThreadOwner(threadId, identity ? mapIdentity(identity) : void 0),
2998
+ mutate: (identity, mutation, assertCurrent) => params.bindingStore.mutate(mapIdentity(identity), mutation.kind === "record-native-subagent-submission" || mutation.kind === "consume-native-subagent-submission" ? {
2999
+ ...mutation,
3000
+ owner: mapHistoryOwner(identity, mutation.owner)
3001
+ } : mutation, assertCurrent),
3002
+ prepareSessionGenerationReclaim: (identity) => params.bindingStore.prepareSessionGenerationReclaim(mapSessionIdentity(identity)),
3003
+ adoptSessionGeneration: (identity, expectedPreviousSessionId, assertCurrent) => params.bindingStore.adoptSessionGeneration(mapSessionIdentity(identity), expectedPreviousSessionId, assertCurrent),
3004
+ resetSessionGeneration: (identity) => params.bindingStore.resetSessionGeneration(mapSessionIdentity(identity)),
3005
+ retireSessionGeneration: (identity) => params.bindingStore.retireSessionGeneration(mapSessionIdentity(identity)),
3006
+ withSessionDeletion: (identity, assertCurrent, run) => params.bindingStore.withSessionDeletion(mapSessionIdentity(identity), assertCurrent, run),
3007
+ withThreadArchiveFence: (run) => params.bindingStore.withThreadArchiveFence(run),
3008
+ withLease: (identity, run) => params.bindingStore.withLease(mapIdentity(identity), run)
3009
+ };
3010
+ }
3011
+ //#endregion
2946
3012
  //#region extensions/codex/src/app-server/startup-binding.ts
2947
3013
  const CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS = 3e5;
2948
3014
  const CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS = 2e4;
@@ -2964,7 +3030,6 @@ const CODEX_APP_SERVER_BYTE_UNITS = {
2964
3030
  tb: 1099511627776,
2965
3031
  tib: 1099511627776
2966
3032
  };
2967
- const codexSessionRecordCache = /* @__PURE__ */ new Map();
2968
3033
  function parseCodexAppServerByteLimit(value) {
2969
3034
  if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.floor(value);
2970
3035
  if (typeof value !== "string") return;
@@ -3032,51 +3097,6 @@ async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codex
3032
3097
  }
3033
3098
  return files;
3034
3099
  }
3035
- async function readCodexSessionRecordForSessionFile(sessionFile) {
3036
- if (isSqliteSessionFileMarker(sessionFile)) return;
3037
- const sessionsFile = path.join(path.dirname(sessionFile), "sessions.json");
3038
- const resolvedSessionFile = path.resolve(sessionFile);
3039
- let stat;
3040
- try {
3041
- stat = await fs.stat(sessionsFile);
3042
- } catch {
3043
- codexSessionRecordCache.delete(resolvedSessionFile);
3044
- return;
3045
- }
3046
- const cached = codexSessionRecordCache.get(resolvedSessionFile);
3047
- if (cached?.sessionsFile === sessionsFile && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) return cached.record;
3048
- let store;
3049
- try {
3050
- store = JSON.parse(await fs.readFile(sessionsFile, "utf8"));
3051
- } catch {
3052
- codexSessionRecordCache.delete(resolvedSessionFile);
3053
- return;
3054
- }
3055
- if (!isJsonObject(store)) {
3056
- codexSessionRecordCache.delete(resolvedSessionFile);
3057
- return;
3058
- }
3059
- let found;
3060
- for (const [sessionKey, record] of Object.entries(store)) {
3061
- if (!isJsonObject(record) || typeof record.sessionFile !== "string") continue;
3062
- if (path.resolve(record.sessionFile) !== resolvedSessionFile) continue;
3063
- found = {
3064
- sessionKey,
3065
- ...record
3066
- };
3067
- break;
3068
- }
3069
- codexSessionRecordCache.set(resolvedSessionFile, {
3070
- sessionsFile,
3071
- mtimeMs: stat.mtimeMs,
3072
- size: stat.size,
3073
- record: found
3074
- });
3075
- return found;
3076
- }
3077
- function isSqliteSessionFileMarker(sessionFile) {
3078
- return parseSqliteSessionFileMarker(sessionFile) !== void 0;
3079
- }
3080
3100
  async function readCodexAppServerRolloutTokenSnapshot(file, openedHandle) {
3081
3101
  let handle = openedHandle;
3082
3102
  if (!handle) try {
@@ -3100,12 +3120,8 @@ async function readCodexAppServerRolloutTokenSnapshot(file, openedHandle) {
3100
3120
  const bytesToRead = Math.min(position, CODEX_APP_SERVER_ROLLOUT_TAIL_READ_BYTES);
3101
3121
  const nextPosition = position - bytesToRead;
3102
3122
  const chunk = Buffer.allocUnsafe(bytesToRead);
3103
- let bytesRead = 0;
3104
- while (bytesRead < bytesToRead) {
3105
- const result = await handle.read(chunk, bytesRead, bytesToRead - bytesRead, nextPosition + bytesRead);
3106
- if (result.bytesRead === 0) return snapshot;
3107
- bytesRead += result.bytesRead;
3108
- }
3123
+ const bytesRead = await readFileWindowFully(handle, chunk, nextPosition);
3124
+ if (bytesRead < bytesToRead) return snapshot;
3109
3125
  let lineEnd = bytesRead;
3110
3126
  while (lineEnd > 0) {
3111
3127
  const index = chunk.lastIndexOf(10, lineEnd - 1);
@@ -3148,9 +3164,6 @@ function readCodexAppServerRolloutTokenSnapshotLine(line) {
3148
3164
  function readCompactionConfig(config) {
3149
3165
  return isJsonObject(config?.agents?.defaults?.compaction) ? config.agents.defaults.compaction : void 0;
3150
3166
  }
3151
- function resolveCodexAppServerNativeThreadReserveTokens(_config) {
3152
- return CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS;
3153
- }
3154
3167
  function resolveCodexAppServerNativeThreadTokenFuse(params) {
3155
3168
  const projectedTurnTokens = typeof params.projectedTurnTokens === "number" && Number.isFinite(params.projectedTurnTokens) && params.projectedTurnTokens > 0 ? Math.floor(params.projectedTurnTokens) : 0;
3156
3169
  const contextWindow = params.modelContextWindow ?? CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS;
@@ -3163,11 +3176,6 @@ function maxFiniteNumber(values) {
3163
3176
  if (nums.length === 0) return;
3164
3177
  return Math.max(...nums);
3165
3178
  }
3166
- function minFiniteNumber(values) {
3167
- const nums = values.filter((value) => typeof value === "number" && Number.isFinite(value));
3168
- if (nums.length === 0) return;
3169
- return Math.min(...nums);
3170
- }
3171
3179
  function hasContextEngineThreadBootstrapProjection(binding) {
3172
3180
  return binding.contextEngine?.projection?.mode === "thread_bootstrap";
3173
3181
  }
@@ -3176,7 +3184,6 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
3176
3184
  const binding = params.binding;
3177
3185
  if (!binding?.threadId) return { binding };
3178
3186
  if (binding.connectionScope === "supervision") return { binding };
3179
- const sessionRecord = await readCodexSessionRecordForSessionFile(params.sessionFile);
3180
3187
  const rolloutFiles = await listCodexAppServerRolloutFilesForThread(params.agentDir, binding.threadId, params.codexHome, binding.rolloutPath);
3181
3188
  const maxBytes = parseCodexAppServerByteLimit(readCompactionConfig(params.config)?.maxActiveTranscriptBytes);
3182
3189
  if (maxBytes !== void 0 && params.contextEngineActive === true && hasContextEngineThreadBootstrapProjection(binding)) embeddedAgentLog.debug("codex app-server deferring native transcript byte guard for context-engine thread bootstrap", {
@@ -3210,25 +3217,19 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
3210
3217
  const nativeTokenSnapshots = await Promise.all(rolloutFiles.map(async (file) => readCodexAppServerRolloutTokenSnapshot(file.path, file.handle)));
3211
3218
  const nativeTokens = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.totalTokens));
3212
3219
  const nativeModelContextWindow = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.modelContextWindow));
3213
- const sessionModelContextWindow = typeof sessionRecord?.contextTokens === "number" && Number.isFinite(sessionRecord.contextTokens) && sessionRecord.contextTokens > 0 ? Math.floor(sessionRecord.contextTokens) : void 0;
3214
- const reserveTokens = resolveCodexAppServerNativeThreadReserveTokens(params.config);
3220
+ const reserveTokens = CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS;
3215
3221
  const maxTokens = resolveCodexAppServerNativeThreadTokenFuse({
3216
- modelContextWindow: minFiniteNumber([nativeModelContextWindow, sessionModelContextWindow]),
3222
+ modelContextWindow: nativeModelContextWindow,
3217
3223
  reserveTokens,
3218
3224
  projectedTurnTokens: params.projectedTurnTokens
3219
3225
  });
3220
- const sessionTokens = sessionRecord?.totalTokensFresh === true && sessionRecord.totalTokensVersion === 1 && typeof sessionRecord?.totalTokens === "number" && Number.isFinite(sessionRecord.totalTokens) ? sessionRecord.totalTokens : void 0;
3221
- const tokenCount = maxFiniteNumber([sessionTokens, nativeTokens]);
3222
- if (tokenCount !== void 0 && tokenCount >= maxTokens) {
3226
+ if (nativeTokens !== void 0 && nativeTokens >= maxTokens) {
3223
3227
  assertCodexBindingMayBeReplaced(binding, "rotating a full native context", params.expectedSessionRuntimeOwnership);
3224
3228
  embeddedAgentLog.warn("codex app-server native transcript exceeded active token limit; starting a fresh thread", {
3225
3229
  threadId: binding.threadId,
3226
3230
  maxTokens,
3227
- sessionKey: sessionRecord?.sessionKey,
3228
- sessionTokens,
3229
3231
  nativeTokens,
3230
3232
  nativeModelContextWindow,
3231
- sessionModelContextWindow,
3232
3233
  reserveTokens,
3233
3234
  projectedTurnTokens: params.projectedTurnTokens
3234
3235
  });
@@ -3238,10 +3239,9 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
3238
3239
  }, params.assertCurrent);
3239
3240
  return { binding: void 0 };
3240
3241
  }
3241
- const startupContextTokens = nativeModelContextWindow ?? sessionModelContextWindow;
3242
3242
  return {
3243
3243
  binding,
3244
- ...startupContextTokens ? { startupContextTokens } : {}
3244
+ ...nativeModelContextWindow ? { startupContextTokens: nativeModelContextWindow } : {}
3245
3245
  };
3246
3246
  }
3247
3247
  //#endregion
@@ -3517,9 +3517,8 @@ async function prepareCodexAttemptConnection({ params, options }) {
3517
3517
  binding: startupBinding,
3518
3518
  bindingStore,
3519
3519
  identity: bindingIdentity,
3520
- sessionFile: params.sessionFile,
3521
3520
  agentDir,
3522
- codexHome: appServer.start.env?.CODEX_HOME,
3521
+ codexHome: appServer.start.codexHome ?? appServer.start.env?.CODEX_HOME,
3523
3522
  config: params.config,
3524
3523
  contextEngineActive: Boolean(activeContextEngine),
3525
3524
  expectedSessionRuntimeOwnership: params.expectedSessionRuntimeOwnership
@@ -3614,6 +3613,314 @@ async function prepareCodexAttemptConnection({ params, options }) {
3614
3613
  }
3615
3614
  }
3616
3615
  //#endregion
3616
+ //#region extensions/codex/src/app-server/attempt-context.ts
3617
+ /**
3618
+ * Builds Codex app-server prompt context,
3619
+ * system-prompt reports, and context-engine projection decisions.
3620
+ */
3621
+ /** Reads mirrored Codex session history for harness hooks. */
3622
+ async function readMirroredSessionHistoryMessages(params) {
3623
+ const { admission, signal, contextTokenBudget, ...target } = params;
3624
+ const messages = await readCodexMirroredSessionHistoryMessages(target, admission, signal, contextTokenBudget);
3625
+ if (!messages) embeddedAgentLog.warn("failed to read mirrored session history for codex harness hooks", { sessionFile: params.sessionFile });
3626
+ return messages;
3627
+ }
3628
+ /** Reads a valid thread-bootstrap projection request from context-engine output. */
3629
+ function readContextEngineThreadBootstrapProjection(projection) {
3630
+ if (projection?.mode !== "thread_bootstrap") return;
3631
+ const epoch = projection.epoch?.trim();
3632
+ if (!epoch) {
3633
+ embeddedAgentLog.warn("context engine requested Codex thread-bootstrap projection without an epoch; using per-turn projection");
3634
+ return;
3635
+ }
3636
+ const fingerprint = projection.fingerprint?.trim();
3637
+ return {
3638
+ mode: "thread_bootstrap",
3639
+ epoch,
3640
+ ...fingerprint ? { fingerprint } : {}
3641
+ };
3642
+ }
3643
+ /**
3644
+ * Decides whether an existing Codex thread can reuse its context-engine
3645
+ * bootstrap projection or must be reprojected.
3646
+ */
3647
+ function resolveContextEngineBootstrapProjectionDecision(params) {
3648
+ const bindingProjection = params.startupBinding?.contextEngine?.projection;
3649
+ if (!params.startupBinding?.threadId || !bindingProjection) return {
3650
+ project: true,
3651
+ reason: !params.startupBinding?.threadId ? "missing-thread-binding" : "missing-projection-binding"
3652
+ };
3653
+ if (!params.expectedBinding || !isContextEngineBindingCompatible(params.startupBinding.contextEngine, params.expectedBinding)) return {
3654
+ project: true,
3655
+ reason: "context-engine-binding-mismatch"
3656
+ };
3657
+ if (!areCodexDynamicToolFingerprintsCompatible({
3658
+ previous: params.startupBinding.dynamicToolsFingerprint,
3659
+ next: params.dynamicToolsFingerprint,
3660
+ nextLegacy: params.legacyDynamicToolsFingerprint
3661
+ })) return {
3662
+ project: true,
3663
+ reason: "dynamic-tools-mismatch"
3664
+ };
3665
+ return bindingProjection.mode !== "thread_bootstrap" || bindingProjection.epoch !== params.projection.epoch || bindingProjection.fingerprint !== params.projection.fingerprint ? {
3666
+ project: true,
3667
+ reason: "projection-mismatch"
3668
+ } : {
3669
+ project: false,
3670
+ reason: "matching-thread-bootstrap-binding"
3671
+ };
3672
+ }
3673
+ /**
3674
+ * Builds the prompt-size, bootstrap-file, skill, and tool-schema accounting
3675
+ * report for a Codex run.
3676
+ */
3677
+ function buildCodexSystemPromptReport(params) {
3678
+ const toolEntries = flattenCodexDynamicToolFunctions(params.tools).map(buildCodexToolReportEntry);
3679
+ const schemaChars = toolEntries.reduce((sum, tool) => sum + tool.schemaChars, 0);
3680
+ const skillsPrompt = params.skillsPrompt.trim();
3681
+ const bootstrapMaxChars = readPositiveNumber(params.attempt.config?.agents?.defaults?.bootstrapMaxChars);
3682
+ const bootstrapTotalMaxChars = readPositiveNumber(params.attempt.config?.agents?.defaults?.bootstrapTotalMaxChars);
3683
+ return {
3684
+ source: "run",
3685
+ generatedAt: Date.now(),
3686
+ sessionId: params.attempt.sessionId,
3687
+ sessionKey: params.sessionKey,
3688
+ provider: params.attempt.provider,
3689
+ model: params.attempt.modelId,
3690
+ workspaceDir: params.workspaceDir,
3691
+ ...bootstrapMaxChars ? { bootstrapMaxChars } : {},
3692
+ ...bootstrapTotalMaxChars ? { bootstrapTotalMaxChars } : {},
3693
+ systemPrompt: {
3694
+ chars: params.developerInstructions.length,
3695
+ projectContextChars: 0,
3696
+ nonProjectContextChars: params.developerInstructions.length,
3697
+ hash: sha256Text(params.developerInstructions)
3698
+ },
3699
+ injectedWorkspaceFiles: buildCodexBootstrapInjectionStats({
3700
+ bootstrapFiles: params.workspaceBootstrapContext.bootstrapFiles,
3701
+ injectedFiles: params.workspaceBootstrapContext.promptContextFiles ?? [],
3702
+ omitReferenceFiles: params.omitWorkspaceReferences,
3703
+ developerInstructionFiles: [...params.workspaceBootstrapContext.threadDeveloperInstructionFiles ?? [], ...params.workspaceBootstrapContext.turnScopedDeveloperInstructionFiles ?? []],
3704
+ memoryToolRoutedBootstrapFiles: params.workspaceBootstrapContext.memoryToolRoutedBootstrapFiles ?? [],
3705
+ memoryToolRouted: params.workspaceBootstrapContext.memoryToolRouted === true
3706
+ }),
3707
+ skills: {
3708
+ promptChars: skillsPrompt.length,
3709
+ hash: sha256Text(skillsPrompt),
3710
+ entries: buildCodexSkillReportEntries(skillsPrompt)
3711
+ },
3712
+ tools: {
3713
+ listChars: 0,
3714
+ schemaChars,
3715
+ entries: toolEntries
3716
+ }
3717
+ };
3718
+ }
3719
+ function buildCodexSkillReportEntries(skillsPrompt) {
3720
+ if (!skillsPrompt) return [];
3721
+ return Array.from(skillsPrompt.matchAll(/<skill>[\s\S]*?<\/skill>/gi)).map((match) => match[0] ?? "").map((block) => ({
3722
+ name: block.match(/<name>\s*([^<]+?)\s*<\/name>/i)?.[1]?.trim() || "(unknown)",
3723
+ blockChars: block.length
3724
+ })).filter((entry) => entry.blockChars > 0);
3725
+ }
3726
+ function buildCodexToolReportEntry(tool) {
3727
+ const summary = tool.description.trim();
3728
+ if (tool.deferLoading === true) return {
3729
+ name: tool.name,
3730
+ summaryChars: summary.length,
3731
+ summaryHash: sha256Text(summary),
3732
+ schemaChars: 0,
3733
+ schemaHash: stableJsonHash(null),
3734
+ propertiesCount: null
3735
+ };
3736
+ return {
3737
+ name: tool.name,
3738
+ summaryChars: summary.length,
3739
+ summaryHash: sha256Text(summary),
3740
+ ...buildCodexToolSchemaStats(tool.inputSchema)
3741
+ };
3742
+ }
3743
+ function buildCodexToolSchemaStats(schema) {
3744
+ const schemaChars = (() => {
3745
+ try {
3746
+ return JSON.stringify(schema).length;
3747
+ } catch {
3748
+ return 0;
3749
+ }
3750
+ })();
3751
+ const properties = isJsonObject(schema) && isJsonObject(schema.properties) ? schema.properties : null;
3752
+ return {
3753
+ schemaChars,
3754
+ schemaHash: stableJsonHash(schema),
3755
+ propertiesCount: properties ? Object.keys(properties).length : null
3756
+ };
3757
+ }
3758
+ function sha256Text(value) {
3759
+ return createHash("sha256").update(value).digest("hex");
3760
+ }
3761
+ function normalizeForStableHash(value) {
3762
+ if (Array.isArray(value)) return value.map((entry) => normalizeForStableHash(entry));
3763
+ if (value && typeof value === "object") {
3764
+ const record = value;
3765
+ return Object.fromEntries(Object.keys(record).toSorted((left, right) => left.localeCompare(right)).map((key) => [key, normalizeForStableHash(record[key])]));
3766
+ }
3767
+ return value;
3768
+ }
3769
+ function stableJsonHash(value) {
3770
+ return sha256Text(JSON.stringify(normalizeForStableHash(value)) ?? "null");
3771
+ }
3772
+ function buildCodexBootstrapInjectionStats(params) {
3773
+ const injectedIndex = indexCodexContextFileContent(params.injectedFiles);
3774
+ const developerInstructionIndex = indexCodexContextFileContent(params.developerInstructionFiles ?? []);
3775
+ const memoryToolRoutedPaths = new Set((params.memoryToolRoutedBootstrapFiles ?? []).map((file) => readNonBlankString(file.path)).filter(isNonEmptyString$1).map(normalizeCodexContextFilePath));
3776
+ return params.bootstrapFiles.map((file) => {
3777
+ const fileName = readNonBlankString(file.name);
3778
+ const pathValue = readNonBlankString(file.path) ?? fileName ?? "";
3779
+ const displayName = (fileName ?? getCodexContextFileDisplayBasename(pathValue)) || pathValue;
3780
+ const baseName = getCodexContextFileBasename(pathValue || fileName || "");
3781
+ const rawChars = file.missing ? 0 : (file.content ?? "").trimEnd().length;
3782
+ const memoryToolRoutedFile = baseName === "memory.md" && params.memoryToolRouted === true && memoryToolRoutedPaths.has(normalizeCodexContextFilePath(pathValue));
3783
+ const injected = memoryToolRoutedFile ? void 0 : readCodexIndexedContextFileContent(injectedIndex, pathValue, fileName) ?? readCodexIndexedContextFileContent(developerInstructionIndex, pathValue, fileName);
3784
+ if (!file.missing && injected === void 0 && CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName)) return {
3785
+ name: displayName,
3786
+ path: pathValue,
3787
+ missing: false,
3788
+ rawChars,
3789
+ injectionStatus: "native_unverified",
3790
+ injectedChars: null,
3791
+ truncated: null
3792
+ };
3793
+ const omitted = memoryToolRoutedFile || params.omitReferenceFiles && readCodexIndexedContextFileContent(injectedIndex, pathValue, fileName) !== void 0;
3794
+ const injectedChars = omitted ? 0 : injected?.length ?? 0;
3795
+ const truncated = omitted ? false : !file.missing && injectedChars < rawChars;
3796
+ return {
3797
+ name: displayName,
3798
+ path: pathValue,
3799
+ missing: file.missing,
3800
+ rawChars,
3801
+ injectedChars,
3802
+ truncated
3803
+ };
3804
+ });
3805
+ }
3806
+ function indexCodexContextFileContent(files) {
3807
+ const byPath = /* @__PURE__ */ new Map();
3808
+ const byBaseName = /* @__PURE__ */ new Map();
3809
+ for (const file of files) {
3810
+ const pathValue = readNonBlankString(file.path);
3811
+ if (!pathValue) continue;
3812
+ if (!byPath.has(pathValue)) byPath.set(pathValue, file.content);
3813
+ const baseName = getCodexContextFileBasename(pathValue);
3814
+ if (baseName && !byBaseName.has(baseName)) byBaseName.set(baseName, file.content);
3815
+ }
3816
+ return {
3817
+ byPath,
3818
+ byBaseName
3819
+ };
3820
+ }
3821
+ function readCodexIndexedContextFileContent(index, pathValue, fileName) {
3822
+ const pathContent = index.byPath.get(pathValue);
3823
+ if (pathContent !== void 0) return pathContent;
3824
+ if (fileName) {
3825
+ const nameContent = index.byPath.get(fileName);
3826
+ if (nameContent !== void 0) return nameContent;
3827
+ }
3828
+ const baseName = getCodexContextFileBasename(fileName ?? pathValue);
3829
+ return baseName ? index.byBaseName.get(baseName) : void 0;
3830
+ }
3831
+ function readPositiveNumber(value) {
3832
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : void 0;
3833
+ }
3834
+ /**
3835
+ * Builds OpenClaw-provided workspace prompt context for the current Codex turn.
3836
+ */
3837
+ function buildCodexOpenClawPromptContext(params) {
3838
+ if (!shouldInjectCodexOpenClawPromptContext(params.params)) return;
3839
+ const sections = [params.workspacePromptContext?.trim() ? [
3840
+ "## OpenClaw Workspace Context",
3841
+ "",
3842
+ params.workspacePromptContext.trim()
3843
+ ].join("\n") : void 0, params.watchedSessionsContext?.trim() || void 0].filter(isNonEmptyString$1);
3844
+ if (sections.length === 0) return;
3845
+ return [
3846
+ "OpenClaw runtime context for this turn:",
3847
+ "Treat this OpenClaw-provided context as supporting project/user reference for the current request.",
3848
+ "",
3849
+ ...sections
3850
+ ].join("\n");
3851
+ }
3852
+ /**
3853
+ * Renders the watched-sessions block for the Codex per-turn runtime context.
3854
+ * Codex builds its own instruction layers, so the embedded prompt's Watched
3855
+ * Sessions section must be re-surfaced here or Codex-backed main sessions
3856
+ * keep refusing cross-session questions (openclaw#114797).
3857
+ */
3858
+ function buildCodexWatchedSessionsContext(params) {
3859
+ if (!shouldInjectCodexOpenClawPromptContext(params.attempt)) return;
3860
+ return buildWatchedSessionsHarnessContext({
3861
+ config: params.attempt.config,
3862
+ sessionKey: params.sessionKey,
3863
+ sandboxed: params.sandboxed,
3864
+ toolNames: flattenCodexDynamicToolFunctions(params.dynamicTools).map((tool) => normalizeCodexDynamicToolName(tool.name))
3865
+ });
3866
+ }
3867
+ /** Renders loaded OpenClaw skill prompts as Codex collaboration instructions. */
3868
+ function renderCodexSkillsCollaborationInstructions(params) {
3869
+ if (!shouldInjectCodexOpenClawPromptContext(params.attempt)) return;
3870
+ return params.skillsPrompt?.trim() ? [
3871
+ "## OpenClaw Skills",
3872
+ "",
3873
+ params.skillsPrompt.trim()
3874
+ ].join("\n") : void 0;
3875
+ }
3876
+ /**
3877
+ * Prepends OpenClaw context while preserving leading delivery metadata as
3878
+ * routing guidance instead of user request text.
3879
+ */
3880
+ function prependCodexOpenClawPromptContext(prompt, context, options = {}) {
3881
+ const { deliveryHint, prompt: promptWithoutDeliveryHint } = splitLeadingCodexDeliveryHint(prompt);
3882
+ if (!context?.trim() && (!deliveryHint || options.preservePromptWithoutContext)) return prompt;
3883
+ const promptSection = promptWithoutDeliveryHint.startsWith("OpenClaw assembled context for this turn:") ? promptWithoutDeliveryHint : ["Current user request:", promptWithoutDeliveryHint].join("\n");
3884
+ const deliverySection = deliveryHint ? [
3885
+ "OpenClaw delivery metadata:",
3886
+ "This delivery metadata is runtime routing guidance, not the user's request.",
3887
+ deliveryHint
3888
+ ].join("\n") : void 0;
3889
+ return [
3890
+ context?.trim(),
3891
+ deliverySection,
3892
+ promptSection
3893
+ ].filter(Boolean).join("\n\n");
3894
+ }
3895
+ /**
3896
+ * Maps the surviving user-request portion of an input range after delivery
3897
+ * metadata has been relocated before the request.
3898
+ */
3899
+ function resolveCodexDeliveryHintPreservedInputRange(params) {
3900
+ const { prompt, promptInputRange, decoratedPrompt } = params;
3901
+ const { deliveryHint, prompt: promptWithoutDeliveryHint } = splitLeadingCodexDeliveryHint(prompt);
3902
+ if (!deliveryHint || !promptInputRange || promptInputRange.start < 0 || promptInputRange.end < promptInputRange.start || promptInputRange.end > prompt.length || !decoratedPrompt.endsWith(promptWithoutDeliveryHint)) return;
3903
+ const promptWithoutDeliveryHintStart = prompt.length - promptWithoutDeliveryHint.length;
3904
+ const inputStart = Math.max(promptInputRange.start, promptWithoutDeliveryHintStart);
3905
+ const inputEnd = Math.max(inputStart, Math.min(promptInputRange.end, promptWithoutDeliveryHint.length + promptWithoutDeliveryHintStart));
3906
+ const decoratedPromptSuffixStart = decoratedPrompt.length - promptWithoutDeliveryHint.length;
3907
+ const requestHeader = "Current user request:\n";
3908
+ const requestHeaderStart = decoratedPromptSuffixStart - 22;
3909
+ return {
3910
+ start: inputStart === promptWithoutDeliveryHintStart && decoratedPrompt.slice(requestHeaderStart, decoratedPromptSuffixStart) === requestHeader ? requestHeaderStart : decoratedPromptSuffixStart + inputStart - promptWithoutDeliveryHintStart,
3911
+ end: decoratedPromptSuffixStart + inputEnd - promptWithoutDeliveryHintStart
3912
+ };
3913
+ }
3914
+ function splitLeadingCodexDeliveryHint(prompt) {
3915
+ const trimmedStart = prompt.trimStart();
3916
+ const matchedHint = MESSAGE_TOOL_DELIVERY_HINTS.find((hint) => trimmedStart.startsWith(hint));
3917
+ if (!matchedHint) return { prompt };
3918
+ return {
3919
+ deliveryHint: matchedHint,
3920
+ prompt: trimmedStart.slice(matchedHint.length).replace(/^\s*\n/, "").trimStart()
3921
+ };
3922
+ }
3923
+ //#endregion
3617
3924
  //#region extensions/codex/src/app-server/run-attempt-state.ts
3618
3925
  async function clearCodexBindingAfterInvalidImagePayload(bindingStore, identity, fields, expected) {
3619
3926
  const currentBinding = bindingStore.read(identity);
@@ -3749,6 +4056,7 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
3749
4056
  const memoryToolNames = getCodexWorkspaceMemoryToolNames(toolBridge.availableSpecs);
3750
4057
  const workspaceBootstrapContext = await buildCodexWorkspaceBootstrapContext({
3751
4058
  params: runtimeParams,
4059
+ agentWorkspaceDeveloperInstructions: connection.mutable.startupBinding?.agentWorkspaceDeveloperInstructions,
3752
4060
  resolvedWorkspace: runtimeParams.bootstrapWorkspaceDir ?? resolvedWorkspace,
3753
4061
  executionWorkspace: resolvedWorkspace,
3754
4062
  effectiveWorkspace,
@@ -3758,7 +4066,7 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
3758
4066
  ringZeroActive: isHostScopedAgentToolActive("openclaw") && isSystemAgentOnlyCodexDynamicToolAllowlist(runtimeParams.toolsAllow),
3759
4067
  sandboxed: sandbox?.enabled === true
3760
4068
  });
3761
- const agentWorkspaceDeveloperInstructions = workspaceBootstrapContext.threadDeveloperInstructions ? connection.mutable.startupBinding?.agentWorkspaceDeveloperInstructions ?? workspaceBootstrapContext.threadDeveloperInstructions : void 0;
4069
+ const agentWorkspaceDeveloperInstructions = workspaceBootstrapContext.threadDeveloperInstructions;
3762
4070
  const baseDeveloperInstructions = joinPresentSections(buildDeveloperInstructions(runtimeParams, { dynamicTools: toolBridge.availableSpecs }), agentWorkspaceDeveloperInstructions);
3763
4071
  const watchedSessionsContext = buildCodexWatchedSessionsContext({
3764
4072
  attempt: runtimeParams,
@@ -3995,6 +4303,28 @@ function isInvalidCodexImagePayloadError(message) {
3995
4303
  return /\b(?:invalid|malformed)\b[\s\S]{0,120}\b(?:image|image url|base64)\b/iu.test(normalizedMessage) || /\b(?:image|image url|base64)\b[\s\S]{0,120}\b(?:invalid|malformed)\b/iu.test(normalizedMessage);
3996
4304
  }
3997
4305
  //#endregion
4306
+ //#region extensions/codex/src/app-server/run-attempt-reply-media.ts
4307
+ async function settleReplyMedia(activeTurn, result, { state, settlementExpired }, signal) {
4308
+ if (activeTurn.prepareReplyMedia && !signal.aborted) {
4309
+ state.pendingSettlementStage = "reply/media";
4310
+ const transferAbort = new AbortController();
4311
+ settlementExpired.then(() => transferAbort.abort(/* @__PURE__ */ new Error("Reply media settlement expired")));
4312
+ try {
4313
+ const prepared = await activeTurn.prepareReplyMedia({
4314
+ kind: "attempt",
4315
+ attempt: result
4316
+ }, transferAbort.signal);
4317
+ if (prepared.kind !== "attempt") throw new Error("Reply media preparation returned the wrong result kind");
4318
+ result.preparedReplyMedia = prepared.preparedMedia;
4319
+ } catch (error) {
4320
+ if (!signal.aborted) throw error;
4321
+ } finally {
4322
+ transferAbort.abort();
4323
+ }
4324
+ }
4325
+ if (signal.aborted) await state.abortCleanup;
4326
+ }
4327
+ //#endregion
3998
4328
  //#region extensions/codex/src/app-server/trajectory.ts
3999
4329
  /** Creates a trajectory recorder when the host exposes its capture capability. */
4000
4330
  function createCodexTrajectoryRecorder(params) {
@@ -4296,7 +4626,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
4296
4626
  degradedSettlement
4297
4627
  ]);
4298
4628
  }
4299
- if (runAbortController.signal.aborted) await state.abortCleanup;
4629
+ await settleReplyMedia(activeTurn, result, turnRuntime, runAbortController.signal);
4300
4630
  } finally {
4301
4631
  closeSettlement();
4302
4632
  }
@@ -4696,7 +5026,7 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
4696
5026
  const { attemptTools, runtime } = context;
4697
5027
  const { appServer, runAbortController } = runtime.connection;
4698
5028
  const { allocateCodexToolOutcomeOrdinal } = attemptTools;
4699
- const { state, turnIdRef, userInputBridgeRef, steeringQueueRef, activeTurnItemIds, pendingOpenClawDynamicToolCompletionIds, openClawDynamicToolExecutions, completeTurn, noteProgress, deadlines } = turnRuntime;
5029
+ const { state, turnIdRef, steeringQueueRef, activeTurnItemIds, pendingOpenClawDynamicToolCompletionIds, openClawDynamicToolExecutions, completeTurn, noteProgress, deadlines } = turnRuntime;
4700
5030
  const { scheduleTerminalDynamicToolReleaseCheck, reportExecutionNotification, maybeAnnounceFastModeAutoOff } = lifecycle;
4701
5031
  const pendingNativeCommandItems = /* @__PURE__ */ new Set();
4702
5032
  const nativeItemObservers = /* @__PURE__ */ new Set();
@@ -4723,7 +5053,6 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
4723
5053
  if (state.projectionClosed) return;
4724
5054
  const projector = projectorRef.current;
4725
5055
  const turnId = turnIdRef.current;
4726
- userInputBridgeRef.current?.handleNotification(notification);
4727
5056
  if (!projector || !turnId) {
4728
5057
  if (notification.method === "error") state.latestStartupErrorNotification = notification;
4729
5058
  return;
@@ -5102,7 +5431,7 @@ async function prepareCodexAttemptPrompt(context) {
5102
5431
  return projected;
5103
5432
  };
5104
5433
  const applyNoContextEngineContinuityProjection = async (action, binding) => {
5105
- const hasContinuity = historyState.messages.some((message) => message.role === "user" || isCodexDurableCustomMessage(message) || action === "started" && (message.role === "compactionSummary" || message.role === "branchSummary"));
5434
+ const hasContinuity = historyState.messages.some((message) => message.role === "user" || isCodexDurableCustomMessage(message) || action === "started" && (message.role === "compactionSummary" || message.role === "branchSummary" || message.role === "assistant" && message.content.some((part) => part.type === "text" && part.text.trim())));
5106
5435
  if (activeContextEngine || !hasContinuity && !params.pluginRuntimeRefreshMessages?.length) return false;
5107
5436
  if (action === "resumed" && promptState.precomputedStaleBindingContinuityProjectionApplied) return true;
5108
5437
  if (action === "started" && promptState.staleBindingContinuityForcedFreshStart) return true;
@@ -5125,9 +5454,8 @@ async function prepareCodexAttemptPrompt(context) {
5125
5454
  binding,
5126
5455
  bindingStore,
5127
5456
  identity: bindingIdentity,
5128
- sessionFile: params.sessionFile,
5129
5457
  agentDir,
5130
- codexHome: appServer.start.env?.CODEX_HOME,
5458
+ codexHome: appServer.start.codexHome ?? appServer.start.env?.CODEX_HOME,
5131
5459
  config: params.config,
5132
5460
  contextEngineActive: Boolean(activeContextEngine),
5133
5461
  expectedSessionRuntimeOwnership: params.expectedSessionRuntimeOwnership,
@@ -5221,6 +5549,13 @@ function prepareCodexAttemptResources(prompt) {
5221
5549
  const { connection, hookChannelId } = runtime;
5222
5550
  const { appServer, params, effectiveCwd, sessionAgentId, contextSessionKey, runAbortController, sandbox, options, nativeHookRelayEvents } = connection;
5223
5551
  const { toolBridge } = attemptTools;
5552
+ let nativeProcessAuthorityReleased = false;
5553
+ const releaseNativeProcessAuthority = () => {
5554
+ if (!nativeProcessAuthorityReleased) {
5555
+ nativeProcessAuthorityReleased = true;
5556
+ nativeProcessAuthority?.release();
5557
+ }
5558
+ };
5224
5559
  const trajectoryRecorder = createCodexTrajectoryRecorder({
5225
5560
  attempt: params,
5226
5561
  cwd: effectiveCwd,
@@ -5245,6 +5580,7 @@ function prepareCodexAttemptResources(prompt) {
5245
5580
  nativePreToolUseFailureFallbackTerminalReason: void 0,
5246
5581
  releaseSharedClientLease: void 0,
5247
5582
  startupClientUnsafe: false,
5583
+ turnStartAttempted: false,
5248
5584
  sharedCodexClientRetiredForOneShotCleanup: false,
5249
5585
  sandboxExecEnvironment: void 0,
5250
5586
  executionDisconnectError: void 0,
@@ -5414,6 +5750,88 @@ function prepareCodexAttemptResources(prompt) {
5414
5750
  state.routeActivated = false;
5415
5751
  await unregisterNativeSubagentMonitor();
5416
5752
  };
5753
+ let subscriptionSettlement;
5754
+ const retainThreadSubscription = async () => {
5755
+ const { client, thread } = state;
5756
+ if (subscriptionSettlement?.thread === thread) return subscriptionSettlement.retained;
5757
+ if (!thread || thread.clientId !== resolveCodexAppServerClientInstanceId(client)) return false;
5758
+ const { bindingStore, bindingIdentity } = connection;
5759
+ const retained = await bindingStore.withLease(bindingIdentity, async () => {
5760
+ if (!isSameCodexAppServerThreadOwner(bindingStore.read(bindingIdentity), thread)) return false;
5761
+ try {
5762
+ if (!state.turnStartAttempted) runAbortController.signal.throwIfAborted();
5763
+ if (!hasCodexNativeBackgroundProcesses(client, thread.threadId)) {
5764
+ params.hostCapabilities.assertActive();
5765
+ connection.assertCurrent();
5766
+ }
5767
+ thread.liveThreadOwnership?.assertCurrent();
5768
+ } catch {
5769
+ return false;
5770
+ }
5771
+ return await retainCodexAppServerBindingSubscription(client, thread.threadId, {
5772
+ release: thread.liveThreadOwnership?.release,
5773
+ configFingerprint: thread.liveThreadConfigFingerprint,
5774
+ serviceTier: state.turnStartAttempted ? connection.mutable.pluginAppServer.serviceTier : thread.liveThreadOwnership?.serviceTier,
5775
+ ephemeralPolicy: thread.liveThreadEphemeralPolicy
5776
+ });
5777
+ });
5778
+ if (retained) subscriptionSettlement = {
5779
+ thread,
5780
+ retained: true
5781
+ };
5782
+ return retained;
5783
+ };
5784
+ const releaseThreadSubscription = async (assertCurrent) => {
5785
+ const { client, thread } = state;
5786
+ if (!thread || subscriptionSettlement?.thread === thread) return true;
5787
+ subscriptionSettlement = {
5788
+ thread,
5789
+ retained: false
5790
+ };
5791
+ if (thread.liveThreadOwnership) try {
5792
+ await thread.liveThreadOwnership.release(thread.threadId, assertCurrent);
5793
+ return true;
5794
+ } catch (error) {
5795
+ await closeCodexStartupClientBestEffort(client);
5796
+ throw error;
5797
+ }
5798
+ const released = await unsubscribeCodexThreadBestEffort(client, {
5799
+ threadId: thread.threadId,
5800
+ timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS,
5801
+ assertCurrent
5802
+ });
5803
+ if (!released) await closeCodexStartupClientBestEffort(client);
5804
+ return released;
5805
+ };
5806
+ const cleanupBeforeActiveTurn = async () => {
5807
+ await runCleanupStep("codex-pre-turn-hook-fallback", activateNativePreToolUseFailureFallback);
5808
+ await runCleanupStep("codex-pre-turn-subscription", async () => {
5809
+ const { thread } = state;
5810
+ if (!thread || subscriptionSettlement?.thread === thread || state.startupClientUnsafe) return;
5811
+ let retained = false;
5812
+ try {
5813
+ retained = Boolean(!state.turnStartAttempted && !runAbortController.signal.aborted && params.cleanupBundleMcpOnRunEnd !== true && thread.liveThreadOwnership && await retainThreadSubscription());
5814
+ } finally {
5815
+ if (!retained) {
5816
+ if (!isIncognitoSessionKey(params.sessionKey) || await connection.bindingStore.mutate(connection.bindingIdentity, {
5817
+ kind: "clear",
5818
+ threadId: thread.threadId
5819
+ })) await releaseThreadSubscription();
5820
+ }
5821
+ }
5822
+ });
5823
+ await runCleanupStep("codex-pre-turn-route-release", releaseCurrentRoute);
5824
+ const relay = state.nativeHookRelay;
5825
+ state.nativeHookRelay = void 0;
5826
+ await runCleanupStep("codex-pre-turn-native-hook-relay", async () => {
5827
+ relay?.unregister();
5828
+ await relay?.drain();
5829
+ });
5830
+ await runCleanupStep("codex-pre-turn-sandbox-release", releaseSandboxExecEnvironment);
5831
+ await runCleanupStep("codex-pre-turn-source-release", releaseNativeProcessAuthority);
5832
+ await runCleanupStep("codex-pre-turn-trajectory-flush", () => trajectoryRecorder?.flush());
5833
+ await runCleanupStep("codex-pre-turn-shared-client-release", releaseSharedClientLeaseAndRetireOneShotClient);
5834
+ };
5417
5835
  const startupTimeoutMs = resolveCodexStartupTimeoutMs({
5418
5836
  timeoutMs: params.timeoutMs,
5419
5837
  timeoutFloorMs: options.startupTimeoutFloorMs
@@ -5425,6 +5843,8 @@ function prepareCodexAttemptResources(prompt) {
5425
5843
  previousRelay?.unregister();
5426
5844
  await previousRelay?.drain();
5427
5845
  connection.assertCurrent();
5846
+ const requiresProcessAdmission = nativeProcessAuthority && runtime.nativeToolSurfaceEnabled;
5847
+ const relayEvents = requiresProcessAdmission && !nativeHookRelayEvents.includes("pre_tool_use") ? [...nativeHookRelayEvents, "pre_tool_use"] : nativeHookRelayEvents;
5428
5848
  if (params.pluginHarnessToolPolicyRestricted === true) {
5429
5849
  state.nativeHookRelay = void 0;
5430
5850
  return {
@@ -5433,10 +5853,13 @@ function prepareCodexAttemptResources(prompt) {
5433
5853
  };
5434
5854
  }
5435
5855
  state.nativeHookRelay = createCodexNativeHookRelay({
5436
- options: options.nativeHookRelay,
5856
+ options: requiresProcessAdmission ? {
5857
+ ...options.nativeHookRelay,
5858
+ enabled: true
5859
+ } : options.nativeHookRelay,
5437
5860
  generation: decision.action === "resume" ? decision.binding.nativeHookRelayGeneration : void 0,
5438
5861
  generationMismatchGraceMs: decision.action === "resume" && !decision.binding.nativeHookRelayGeneration ? CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS : void 0,
5439
- events: nativeHookRelayEvents,
5862
+ events: relayEvents,
5440
5863
  agentId: sessionAgentId,
5441
5864
  sessionId: params.sessionId,
5442
5865
  sessionKey: contextSessionKey,
@@ -5460,6 +5883,10 @@ function prepareCodexAttemptResources(prompt) {
5460
5883
  loopDetectionPreToolUseRelay: appServer.loopDetectionPreToolUseRelay,
5461
5884
  signal: runAbortController.signal,
5462
5885
  hostCapabilities: params.hostCapabilities,
5886
+ nativeProcessAuthority: requiresProcessAdmission ? {
5887
+ owner: nativeProcessAuthority,
5888
+ client: () => state.client
5889
+ } : void 0,
5463
5890
  assertCurrent: connection.assertCurrent,
5464
5891
  onPreToolUseFailure: (failure) => {
5465
5892
  const projector = projectorRef.current;
@@ -5473,18 +5900,35 @@ function prepareCodexAttemptResources(prompt) {
5473
5900
  return {
5474
5901
  configPatch: state.nativeHookRelay ? buildCodexNativeHookRelayConfig({
5475
5902
  relay: state.nativeHookRelay,
5476
- events: nativeHookRelayEvents,
5903
+ events: relayEvents,
5477
5904
  hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec
5478
5905
  }) : options.nativeHookRelay?.enabled === false ? buildCodexNativeHookRelayDisabledConfig() : void 0,
5479
5906
  nativeHookRelayGeneration: state.nativeHookRelay?.generation
5480
5907
  };
5481
5908
  };
5909
+ const nativeProcessAuthority = sandbox?.enabled && sandbox.backend && params.hostCapabilities.retainSourceAuthority ? new CodexNativeProcessAuthority(params.hostCapabilities, (error) => {
5910
+ const message = formatErrorMessage(error);
5911
+ embeddedAgentLog.warn("codex native background work remains unsettled", {
5912
+ runId: params.runId,
5913
+ sessionId: params.sessionId,
5914
+ error: message
5915
+ });
5916
+ emitCodexAppServerEvent(params, {
5917
+ stream: "codex_app_server.lifecycle",
5918
+ data: {
5919
+ phase: "background_cleanup_failed",
5920
+ error: message
5921
+ }
5922
+ });
5923
+ }) : void 0;
5482
5924
  return {
5483
5925
  prompt,
5484
5926
  trajectoryRecorder,
5485
5927
  state,
5486
5928
  projectorRef,
5487
5929
  pendingNativePreToolUseFailures,
5930
+ nativeProcessAuthority,
5931
+ releaseNativeProcessAuthority,
5488
5932
  markTrajectoryEndRecorded: () => {
5489
5933
  state.trajectoryEndRecorded = true;
5490
5934
  },
@@ -5495,6 +5939,9 @@ function prepareCodexAttemptResources(prompt) {
5495
5939
  runCleanupStep,
5496
5940
  registerNativeSubagentMonitor,
5497
5941
  releaseCurrentRoute,
5942
+ retainThreadSubscription,
5943
+ releaseThreadSubscription,
5944
+ cleanupBeforeActiveTurn,
5498
5945
  startupTimeoutMs,
5499
5946
  buildNativeHookRelayFinalConfigPatch
5500
5947
  };
@@ -5502,7 +5949,7 @@ function prepareCodexAttemptResources(prompt) {
5502
5949
  //#endregion
5503
5950
  //#region extensions/codex/src/app-server/run-attempt-route.ts
5504
5951
  async function prepareCodexAttemptRoute(resources, turnRuntime, notifications, handleServerRequest) {
5505
- const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, registerNativeSubagentMonitor, activateNativePreToolUseFailureFallback, releaseSandboxExecEnvironment, releaseSharedClientLeaseOnce, runCleanupStep } = resources;
5952
+ const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, registerNativeSubagentMonitor } = resources;
5506
5953
  const { connection } = prompt.context.runtime;
5507
5954
  const { runAbortController } = connection;
5508
5955
  const { state, turnIdRef, completeTurn } = turnRuntime;
@@ -5551,26 +5998,7 @@ async function prepareCodexAttemptRoute(resources, turnRuntime, notifications, h
5551
5998
  }
5552
5999
  return resourceState.turnRoute;
5553
6000
  };
5554
- try {
5555
- await ensureCurrentThreadRoute();
5556
- } catch (error) {
5557
- activateNativePreToolUseFailureFallback();
5558
- await runCleanupStep("codex-route-failure-route-release", releaseCurrentRoute);
5559
- const relay = resourceState.nativeHookRelay;
5560
- relay?.unregister();
5561
- await runAgentCleanupStep({
5562
- runId: connection.params.runId,
5563
- sessionId: connection.params.sessionId,
5564
- step: "codex-route-failure-native-hook-relay",
5565
- log: embeddedAgentLog,
5566
- cleanup: async () => {
5567
- await relay?.drain();
5568
- }
5569
- });
5570
- await releaseSandboxExecEnvironment();
5571
- releaseSharedClientLeaseOnce();
5572
- throw error;
5573
- }
6001
+ await ensureCurrentThreadRoute();
5574
6002
  return { ensureCurrentThreadRoute };
5575
6003
  }
5576
6004
  //#endregion
@@ -5713,25 +6141,64 @@ async function prepareCodexAttemptRuntime(connection) {
5713
6141
  });
5714
6142
  preDynamicStartupStages.mark("bundle-mcp");
5715
6143
  const sandboxExecServerEnabled = isCodexSandboxExecServerEnabled(pluginConfig, sandbox);
5716
- const nativeToolSurfaceEnabled = shouldEnableCodexAppServerNativeToolSurface(runtimeParams, sandbox, {
6144
+ let nativeToolSurfaceEnabled = shouldEnableCodexAppServerNativeToolSurface(runtimeParams, sandbox, {
5717
6145
  agentId: policyAgentId,
5718
6146
  runtimeSessionKey: sandboxSessionKey,
5719
6147
  sandboxExecServerEnabled
5720
6148
  });
6149
+ if (nativeToolSurfaceEnabled && sandbox?.enabled && sandbox.backend && params.hostCapabilities.retainSourceAuthority) {
6150
+ const client = await attemptClientFactory({
6151
+ assertCurrent: connection.assertCurrent,
6152
+ startOptions: appServer.start,
6153
+ pluginConfig,
6154
+ ...startupPreparedAuth ? { preparedAuth: startupPreparedAuth } : { authProfileId: startupClientAuthProfileId },
6155
+ authRequirement: connection.startupAuthRequirement,
6156
+ authProfileStore: attemptAuthProfileStore,
6157
+ authBindingFingerprint: preparedAuthBinding?.fingerprint,
6158
+ ...connection.runtimeArtifactRequest ? {
6159
+ runtimeArtifactMode: "capture",
6160
+ ...connection.runtimeArtifactRequest.expected ? { expectedRuntimeArtifact: connection.runtimeArtifactRequest.expected } : {}
6161
+ } : {},
6162
+ agentId: sessionAgentId,
6163
+ agentDir,
6164
+ config: params.config,
6165
+ abandonSignal: runAbortController.signal,
6166
+ timeoutMs: appServer.requestTimeoutMs
6167
+ });
6168
+ try {
6169
+ connection.assertCurrent();
6170
+ await assertCodexNativeHookRelayAllowed(client, runAbortController.signal, appServer.requestTimeoutMs);
6171
+ connection.assertCurrent();
6172
+ } catch (error) {
6173
+ if (!(error instanceof CodexManagedHooksOnlyError)) throw error;
6174
+ connection.assertCurrent();
6175
+ nativeToolSurfaceEnabled = false;
6176
+ embeddedAgentLog.info("Codex managed-only hooks require sandbox-backed OpenClaw tools");
6177
+ } finally {
6178
+ if (attemptClientFactory === createIsolatedCodexAppServerClient) await client.closeAndWait();
6179
+ else releaseLeasedSharedCodexAppServerClient(client);
6180
+ }
6181
+ }
5721
6182
  const configuredMcpSurface = scheduledConfiguredMcpSurface ? "scheduled" : !nativeToolSurfaceEnabled && bundleMcpThreadConfig.staticServerNames.length > 0 ? "transient" : void 0;
5722
6183
  preDynamicStartupStages.mark("native-tool-surface");
5723
- const nativeProviderWebSearchSupport = resolveCodexWebSearchPlan({
6184
+ const webSearchPlan = resolveCodexWebSearchPlan({
5724
6185
  config: params.config,
5725
6186
  disableTools: params.disableTools,
5726
6187
  nativeToolSurfaceEnabled
5727
- }).kind === "native-hosted" ? await resolveCodexProviderWebSearchSupport({
6188
+ });
6189
+ const supervisedSearchFingerprint = usesSupervisionConnection && !mutable.startupBinding?.pendingSupervisionBranch ? mutable.startupBinding?.webSearchThreadConfigFingerprint : void 0;
6190
+ let nativeProviderWebSearchSupport;
6191
+ if (webSearchPlan.kind !== "native-hosted" || supervisedSearchFingerprint === fingerprintJsonObject(resolveCodexWebSearchPlan({ disableTools: true }).threadConfig)) nativeProviderWebSearchSupport = "unsupported";
6192
+ else if (supervisedSearchFingerprint === fingerprintJsonObject(webSearchPlan.threadConfig)) nativeProviderWebSearchSupport = "supported";
6193
+ else nativeProviderWebSearchSupport = await resolveCodexProviderWebSearchSupport({
5728
6194
  clientFactory: attemptClientFactory,
5729
6195
  appServer,
5730
6196
  authProfileId: startupClientAuthProfileId,
5731
6197
  preparedAuth: startupPreparedAuth,
5732
6198
  agentDir,
5733
6199
  config: params.config,
5734
- modelProviderOverride: usesSupervisionConnection ? mutable.startupBinding?.modelProvider : resolveCodexAppServerThreadModelSelection({
6200
+ expectedNativeModelProvider: usesSupervisionConnection ? mutable.startupBinding?.modelProvider : void 0,
6201
+ modelProviderOverride: usesSupervisionConnection ? void 0 : resolveCodexAppServerThreadModelSelection({
5735
6202
  provider: params.provider,
5736
6203
  model: params.modelId,
5737
6204
  binding: mutable.startupBinding,
@@ -5741,7 +6208,7 @@ async function prepareCodexAttemptRuntime(connection) {
5741
6208
  config: params.config
5742
6209
  }).modelProvider,
5743
6210
  signal: runAbortController.signal
5744
- }) : "unsupported";
6211
+ });
5745
6212
  preDynamicStartupStages.mark("provider-capabilities");
5746
6213
  for (const diagnostic of bundleMcpThreadConfig.diagnostics) embeddedAgentLog.warn(`bundle-mcp: ${diagnostic.pluginId}: ${diagnostic.message}`);
5747
6214
  if (activeContextEngine) assertContextEngineHostSupport({
@@ -5925,17 +6392,11 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
5925
6392
  signal
5926
6393
  });
5927
6394
  if (approvalResult.kind === "handled") return approvalResult.response;
5928
- return await userInputBridgeRef.current?.handleElicitationRequest({
5929
- id: request.id,
5930
- params: request.params
5931
- });
6395
+ return await userInputBridgeRef.current?.handleElicitationRequest(request, signal);
5932
6396
  }
5933
6397
  if (request.method === "item/tool/requestUserInput") {
5934
6398
  if (scope.turnId === turnId) markCurrentTurnRequestProgress();
5935
- return await userInputBridgeRef.current?.handleRequest({
5936
- id: request.id,
5937
- params: request.params
5938
- });
6399
+ return await userInputBridgeRef.current?.handleRequest(request, signal);
5939
6400
  }
5940
6401
  if (request.method !== "item/tool/call") {
5941
6402
  if (isCodexAppServerApprovalRequest(request.method)) {
@@ -5986,19 +6447,32 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
5986
6447
  const toolMeta = inferCodexDynamicToolMeta(call, resolveCodexToolProgressDetailMode(params.toolProgressDetail));
5987
6448
  const toolArgs = sanitizeCodexToolArguments(call.arguments);
5988
6449
  const commandBearing = isCodexCommandBearingToolCall(call.tool, toolArgs);
5989
- const shouldEmitDynamicToolProgress = shouldEmitTranscriptToolProgress(call.tool, toolArgs);
5990
- if (shouldEmitDynamicToolProgress) emitCodexAppServerEvent(params, {
5991
- stream: "tool",
5992
- data: {
5993
- phase: "start",
5994
- name: call.tool,
5995
- itemId: call.callId,
6450
+ const shouldEmitDynamicToolProgress = shouldEmitTranscriptToolProgress(call.tool);
6451
+ if (shouldEmitDynamicToolProgress) {
6452
+ const activity = projectAgentToolActivity({
5996
6453
  toolCallId: call.callId,
5997
- ...toolMeta ? { meta: toolMeta } : {},
5998
- ...toolArgs ? { args: toolArgs } : {},
5999
- ...commandBearing ? { commandBearing: true } : {}
6000
- }
6001
- });
6454
+ name: call.tool,
6455
+ phase: "start",
6456
+ args: toolArgs,
6457
+ meta: toolMeta
6458
+ });
6459
+ emitCodexAppServerEvent(params, {
6460
+ stream: "item",
6461
+ data: activity
6462
+ });
6463
+ emitCodexAppServerEvent(params, {
6464
+ stream: "tool",
6465
+ data: {
6466
+ phase: "start",
6467
+ name: call.tool,
6468
+ itemId: call.callId,
6469
+ toolCallId: call.callId,
6470
+ ...toolMeta ? { meta: toolMeta } : {},
6471
+ ...toolArgs ? { args: toolArgs } : {},
6472
+ ...commandBearing ? { commandBearing: true } : {}
6473
+ }
6474
+ });
6475
+ }
6002
6476
  const dynamicToolTimeoutMs = resolveDynamicToolCallTimeoutMs({
6003
6477
  call,
6004
6478
  config: params.config,
@@ -6081,6 +6555,14 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
6081
6555
  }
6082
6556
  if (shouldEmitDynamicToolProgress) {
6083
6557
  const progressResponse = toCodexDynamicToolProgressResponse(response, protocolResponse);
6558
+ const activity = projectAgentToolActivity({
6559
+ toolCallId: call.callId,
6560
+ name: call.tool,
6561
+ phase: "result",
6562
+ args: response.executedArguments ?? call.arguments,
6563
+ result: toTranscriptToolResult(progressResponse),
6564
+ isError: !protocolResponse.success
6565
+ });
6084
6566
  emitCodexAppServerEvent(params, {
6085
6567
  stream: "tool",
6086
6568
  data: {
@@ -6094,6 +6576,10 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
6094
6576
  result: toTranscriptToolResult(progressResponse)
6095
6577
  }
6096
6578
  });
6579
+ emitCodexAppServerEvent(params, {
6580
+ stream: "item",
6581
+ data: activity
6582
+ });
6097
6583
  }
6098
6584
  if (!terminalDiagnosticObserved && !hasPendingDynamicToolTerminalDiagnostic({
6099
6585
  call,
@@ -6157,7 +6643,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
6157
6643
  //#region extensions/codex/src/app-server/attempt-runtime-artifact.ts
6158
6644
  async function verifyStartupArtifact(params) {
6159
6645
  if (!params.request) return;
6160
- const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-Dy38Z5iU.mjs");
6646
+ const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-CLZ8udh-.mjs");
6161
6647
  const runtimeArtifact = readCodexAppServerClientRuntimeArtifact(params.client);
6162
6648
  const expected = params.request.expected;
6163
6649
  const matchesExpected = !expected || runtimeArtifact?.id === expected.id && runtimeArtifact.fingerprint === expected.fingerprint;
@@ -6223,9 +6709,13 @@ async function runCodexComputerUseHealthProbe(client, config, monitor, tools) {
6223
6709
  monitor.running = true;
6224
6710
  try {
6225
6711
  const { liveTest, repair } = await runCodexComputerUseLiveTest({
6712
+ client,
6226
6713
  config,
6227
6714
  tools,
6228
- request: async (method, requestParams, requestOptions) => await client.request(method, requestParams, { timeoutMs: requestOptions?.timeoutMs ?? config.liveTestTimeoutMs })
6715
+ request: async (method, requestParams, requestOptions) => await client.request(method, requestParams, {
6716
+ timeoutMs: requestOptions?.timeoutMs ?? config.liveTestTimeoutMs,
6717
+ ...requestOptions?.signal ? { signal: requestOptions.signal } : {}
6718
+ })
6229
6719
  });
6230
6720
  if (!liveTest.ok) {
6231
6721
  embeddedAgentLog.warn("codex computer-use periodic health failed", {
@@ -6547,7 +7037,8 @@ async function startCodexAttemptThread(params) {
6547
7037
  appServerStartOptions: params.appServer.start,
6548
7038
  timeoutMs: params.appServer.requestTimeoutMs,
6549
7039
  signal: AbortSignal.any([params.signal, startupAbandonController.signal]),
6550
- onExecutionDisconnect: params.onExecutionDisconnect
7040
+ onExecutionDisconnect: params.onExecutionDisconnect,
7041
+ requireProcessAuthority: Boolean(attemptParams.hostCapabilities.retainSourceAuthority)
6551
7042
  }) : void 0;
6552
7043
  startupSandboxEnvironmentAcquired = Boolean(startupSandboxEnvironment);
6553
7044
  if (startupAbandonController.signal.aborted) throw new CodexAppServerStartupError("aborted");
@@ -6752,7 +7243,7 @@ async function startCodexAttemptThread(params) {
6752
7243
  //#endregion
6753
7244
  //#region extensions/codex/src/app-server/run-attempt-start.ts
6754
7245
  async function startCodexAttemptRuntime(resources) {
6755
- const { prompt, state, trajectoryRecorder, activateNativePreToolUseFailureFallback, releaseSandboxExecEnvironment, releaseSharedClientLeaseAndRetireOneShotClient, releaseCurrentRoute, runCleanupStep, startupTimeoutMs, buildNativeHookRelayFinalConfigPatch } = resources;
7246
+ const { prompt, state, trajectoryRecorder, startupTimeoutMs, buildNativeHookRelayFinalConfigPatch } = resources;
6756
7247
  const { context, turnState, rebuildCodexTurnPromptTextFromCurrentProjection, applyNoContextEngineContinuityProjection } = prompt;
6757
7248
  const { runtime, attemptTools, promptState } = context;
6758
7249
  const { connection, runtimeParams, preparedAuthBinding, buildActiveRunAttemptParams, startupAuthAccountCacheKey, startupEnvApiKeyCacheKey, bundleMcpThreadConfig, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, effectiveRuntimeModelId, sandboxExecServerEnabled } = runtime;
@@ -6796,7 +7287,7 @@ async function startCodexAttemptRuntime(resources) {
6796
7287
  developerInstructions,
6797
7288
  agentWorkspaceDeveloperInstructions: context.agentWorkspaceDeveloperInstructions,
6798
7289
  buildFinalConfigPatch: buildNativeHookRelayFinalConfigPatch,
6799
- nativeHookRelayRequired: connection.options.nativeHookRelay?.enabled !== false && params.pluginHarnessToolPolicyRestricted !== true && connection.nativeHookRelayEvents.includes("pre_tool_use") && (hasBeforeToolCallPolicy() || appServer.loopDetectionPreToolUseRelay && Boolean(connection.sandboxSessionKey) && loopDetectionEnabled),
7290
+ nativeHookRelayRequired: Boolean(resources.nativeProcessAuthority && nativeToolSurfaceEnabled) || connection.options.nativeHookRelay?.enabled !== false && params.pluginHarnessToolPolicyRestricted !== true && connection.nativeHookRelayEvents.includes("pre_tool_use") && (hasBeforeToolCallPolicy() || appServer.loopDetectionPreToolUseRelay && Boolean(connection.sandboxSessionKey) && loopDetectionEnabled),
6800
7291
  bundleMcpThreadConfig,
6801
7292
  configuredMcpDynamicSurface: attemptTools.configuredMcp !== void 0,
6802
7293
  configuredMcpOwnershipVersion: attemptTools.configuredMcpOwnershipVersion,
@@ -6883,16 +7374,6 @@ async function startCodexAttemptRuntime(resources) {
6883
7374
  connection.mutable.pluginAppServer = pluginAppServer;
6884
7375
  await resources.registerNativeSubagentMonitor(state.thread.threadId);
6885
7376
  } catch (error) {
6886
- await runCleanupStep("codex-start-failure-hook-fallback", activateNativePreToolUseFailureFallback);
6887
- await runCleanupStep("codex-start-failure-route-release", releaseCurrentRoute);
6888
- const nativeHookRelay = state.nativeHookRelay;
6889
- state.nativeHookRelay = void 0;
6890
- await runCleanupStep("codex-start-failure-native-hook-relay", async () => {
6891
- nativeHookRelay?.unregister();
6892
- await nativeHookRelay?.drain();
6893
- });
6894
- await runCleanupStep("codex-start-failure-sandbox-release", releaseSandboxExecEnvironment);
6895
- await runCleanupStep("codex-start-failure-shared-client-release", releaseSharedClientLeaseAndRetireOneShotClient);
6896
7377
  throw error instanceof CodexThreadPolicyHandoffError ? error : state.executionDisconnectError ?? error;
6897
7378
  }
6898
7379
  }
@@ -7043,137 +7524,20 @@ async function prepareCodexAttemptTools(runtime) {
7043
7524
  }
7044
7525
  }
7045
7526
  let requireExplicitMessageTarget;
7046
- const tools = await buildDynamicTools({
7047
- ...commonToolParams,
7048
- registerRunCleanup: (cleanup) => runCleanups.push(cleanup),
7049
- onMessageToolTargetResolved: (required) => {
7050
- requireExplicitMessageTarget = required;
7051
- },
7052
- cronCreatorToolAllowlistRef: cronCreatorToolAllowlist,
7053
- cronCreatorToolAllowlistCaptureRef,
7054
- onPersistentWebSearchPolicyResolved: (allowed) => {
7055
- toolState.persistentWebSearchAllowed = allowed;
7056
- },
7057
- onWebSearchPolicyResolved: (allowed) => {
7058
- toolState.webSearchAllowed = allowed;
7059
- }
7060
- });
7061
- const registeredTools = nativeSpecs ? [] : await buildDynamicTools({
7062
- ...commonToolParams,
7063
- forceHeartbeatTool: true,
7064
- ignoreDisableMessageTool: true,
7065
- ignoreRuntimePlan: true
7066
- });
7067
- const policyContext = {
7068
- config: params.config,
7069
- sessionKey: sandboxSessionKey,
7070
- runSessionKey: params.sessionKey && params.sessionKey !== sandboxSessionKey ? params.sessionKey : void 0,
7071
- sessionId: params.sessionId,
7072
- runId: params.runId,
7073
- agentId: policyAgentId,
7074
- agentDir: agentDir ?? resolveAgentDir$2(params.config ?? {}, sessionAgentId),
7075
- agentAccountId: params.agentAccountId,
7076
- messageProvider: params.messageProvider ?? params.messageChannel,
7077
- messageChannel: params.messageChannel,
7078
- chatType: params.chatType,
7079
- messageTo: params.messageTo,
7080
- messageThreadId: params.messageThreadId,
7081
- currentChannelId: params.currentChannelId,
7082
- currentMessagingTarget: params.currentMessagingTarget,
7083
- currentThreadTs: params.currentThreadTs,
7084
- currentMessageId: params.currentMessageId,
7085
- groupId: params.groupId,
7086
- groupChannel: params.groupChannel,
7087
- groupSpace: params.groupSpace,
7088
- memberRoleIds: params.memberRoleIds,
7089
- spawnedBy: params.spawnedBy,
7090
- senderId: params.senderId,
7091
- senderName: params.senderName,
7092
- senderUsername: params.senderUsername,
7093
- senderE164: params.senderE164,
7094
- senderIsOwner: params.senderIsOwner,
7095
- modelProvider: params.provider,
7096
- modelId: params.modelId,
7097
- modelApi: params.model.api,
7098
- modelContextWindowTokens: params.model.contextWindow,
7099
- modelHasVision: params.model.input?.includes("image") ?? false,
7100
- workspaceDir: effectiveWorkspace,
7101
- cwd: effectiveCwd ?? effectiveWorkspace,
7102
- sandboxToolPolicy: sandbox?.tools,
7103
- conversationToolPolicy: params.conversationToolPolicy,
7104
- inputProvenance: params.inputProvenance,
7105
- trustedInternalHandoff: params.trustedInternalHandoff,
7106
- scheduledToolPolicy: params.scheduledToolPolicy
7107
- };
7108
- const reservedToolNames = [...tools.map((tool) => tool.name), ...registeredTools.map((tool) => tool.name)];
7109
- const turnSourceChannel = params.messageChannel ?? params.messageProvider;
7110
- const turnSourceTo = params.currentMessagingTarget ?? params.currentChannelId;
7111
- const requester = {
7112
- ...turnSourceChannel ? { channel: turnSourceChannel } : {},
7113
- ...params.agentAccountId ? { accountId: params.agentAccountId } : {},
7114
- ...params.senderId ? { senderId: params.senderId } : {},
7115
- ...params.senderIsOwner !== void 0 ? { senderIsOwner: params.senderIsOwner } : {},
7116
- ...params.memberRoleIds?.length ? { roleIds: [...params.memberRoleIds] } : {}
7117
- };
7118
- const hasRequester = Object.keys(requester).length > 0;
7119
- const requestInteractiveMcpApproval = async (approval) => {
7120
- const allowedDecisions = approval.mode === "prompt" ? ["allow-once", "deny"] : [
7121
- "allow-once",
7122
- "allow-always",
7123
- "deny"
7124
- ];
7125
- const outcome = await requestPluginApprovalOutcome({
7126
- hostCapabilities: params.hostCapabilities,
7127
- signal: approval.signal,
7128
- title: `Run MCP tool ${approval.serverName}/${approval.toolName}`,
7129
- description: `Codex approval mode "${approval.mode}" requires an operator decision before this MCP tool runs. ${formatMcpCodexApprovalRemedy(approval.serverName)}`,
7130
- allowedDecisions,
7131
- toolName: approval.safeToolName,
7132
- toolCallId: approval.toolCallId,
7133
- mcpTool: {
7134
- server: approval.serverName,
7135
- tool: approval.toolName
7136
- },
7137
- isMcpToolApprovalActive: approval.isActive
7138
- });
7139
- if (outcome !== "approved-once" && outcome !== "approved-session") throw new Error(`${approval.serverName}/${approval.toolName}: interactive Codex approval (${approval.mode}) was not granted: ${outcome}`);
7140
- };
7141
- const requestRequesterMcpApproval = async (approval) => {
7142
- const outcome = await requestPluginApprovalOutcome({
7143
- hostCapabilities: params.hostCapabilities,
7144
- signal: approval.signal,
7145
- title: `Run MCP tool ${approval.serverName}/${approval.toolName}`,
7146
- description: `Codex approval mode "${approval.mode}" requires an operator decision before this MCP tool runs. ${formatMcpCodexApprovalRemedy(approval.serverName)}`,
7147
- allowedDecisions: ["allow-once", "deny"],
7148
- toolName: approval.safeToolName,
7149
- toolCallId: approval.toolCallId,
7150
- mcpTool: {
7151
- server: approval.serverName,
7152
- tool: approval.toolName
7153
- },
7154
- isMcpToolApprovalActive: approval.isActive
7527
+ let configuredMcp;
7528
+ let scopedMcpTools;
7529
+ let toolDisposal;
7530
+ const disposeTools = (reason) => toolDisposal ??= (async () => {
7531
+ await runAgentCleanupStep({
7532
+ runId: params.runId,
7533
+ sessionId: params.sessionId,
7534
+ step: "codex-dynamic-tool-cleanup",
7535
+ log: embeddedAgentLog,
7536
+ cleanup: async () => {
7537
+ const errors = (await Promise.allSettled(runCleanups.splice(0).map(async (cleanup) => await cleanup(reason)))).flatMap((result) => result.status === "rejected" ? [result.reason] : []);
7538
+ if (params.oneShotCliRun && errors.length) throw new AggregateError(errors, "Codex tool cleanup failed");
7539
+ }
7155
7540
  });
7156
- if (outcome !== "approved-once" && outcome !== "approved-session") throw new Error(`${approval.serverName}/${approval.toolName}: interactive Codex approval (${approval.mode}) was not granted: ${outcome}`);
7157
- };
7158
- const configuredMcp = configuredMcpSurface ? await materializeStaticMcpToolsForHarnessRun({
7159
- sessionId: params.sessionId,
7160
- sessionKey: params.sessionKey,
7161
- agentId: sessionAgentId,
7162
- workspaceDir: effectiveWorkspace,
7163
- agentDir: policyContext.agentDir,
7164
- cfg: params.config,
7165
- manifestRegistry: bundleManifestRegistry,
7166
- reservedToolNames,
7167
- toolsAllow: params.toolsAllow,
7168
- toolOverrides: codexMcpToolOverrides,
7169
- autoApproveCodexAppServerApprovals: shouldAutoApproveCodexAppServerApprovals(connection.appServer),
7170
- projectedMcpServers: bundleMcpThreadConfig.configPatch?.mcp_servers,
7171
- ...configuredMcpSurface === "transient" ? { requestInteractiveCodexApproval: requestInteractiveMcpApproval } : {},
7172
- policyContext,
7173
- warn: (message) => embeddedAgentLog.warn(message)
7174
- }) : void 0;
7175
- let scopedMcpTools = void 0;
7176
- const disposeMcpTools = async () => {
7177
7541
  for (const [step, materialized] of [["codex-scoped-mcp-dispose", scopedMcpTools], ["codex-configured-mcp-dispose", configuredMcp]]) await runAgentCleanupStep({
7178
7542
  runId: params.runId,
7179
7543
  sessionId: params.sessionId,
@@ -7181,8 +7545,137 @@ async function prepareCodexAttemptTools(runtime) {
7181
7545
  log: embeddedAgentLog,
7182
7546
  cleanup: async () => materialized?.dispose()
7183
7547
  });
7184
- };
7548
+ })();
7185
7549
  try {
7550
+ const tools = await buildDynamicTools({
7551
+ ...commonToolParams,
7552
+ registerRunCleanup: (cleanup) => runCleanups.push(cleanup),
7553
+ onMessageToolTargetResolved: (required) => {
7554
+ requireExplicitMessageTarget = required;
7555
+ },
7556
+ cronCreatorToolAllowlistRef: cronCreatorToolAllowlist,
7557
+ cronCreatorToolAllowlistCaptureRef,
7558
+ onPersistentWebSearchPolicyResolved: (allowed) => {
7559
+ toolState.persistentWebSearchAllowed = allowed;
7560
+ },
7561
+ onWebSearchPolicyResolved: (allowed) => {
7562
+ toolState.webSearchAllowed = allowed;
7563
+ }
7564
+ });
7565
+ const registeredTools = nativeSpecs ? [] : await buildDynamicTools({
7566
+ ...commonToolParams,
7567
+ forceHeartbeatTool: true,
7568
+ ignoreDisableMessageTool: true,
7569
+ ignoreRuntimePlan: true
7570
+ });
7571
+ const policyContext = {
7572
+ config: params.config,
7573
+ sessionKey: sandboxSessionKey,
7574
+ runSessionKey: params.sessionKey && params.sessionKey !== sandboxSessionKey ? params.sessionKey : void 0,
7575
+ sessionId: params.sessionId,
7576
+ runId: params.runId,
7577
+ agentId: policyAgentId,
7578
+ agentDir: agentDir ?? resolveAgentDir$2(params.config ?? {}, sessionAgentId),
7579
+ agentAccountId: params.agentAccountId,
7580
+ messageProvider: params.messageProvider ?? params.messageChannel,
7581
+ messageChannel: params.messageChannel,
7582
+ chatType: params.chatType,
7583
+ messageTo: params.messageTo,
7584
+ messageThreadId: params.messageThreadId,
7585
+ currentChannelId: params.currentChannelId,
7586
+ currentMessagingTarget: params.currentMessagingTarget,
7587
+ currentThreadTs: params.currentThreadTs,
7588
+ currentMessageId: params.currentMessageId,
7589
+ groupId: params.groupId,
7590
+ groupChannel: params.groupChannel,
7591
+ groupSpace: params.groupSpace,
7592
+ memberRoleIds: params.memberRoleIds,
7593
+ spawnedBy: params.spawnedBy,
7594
+ senderId: params.senderId,
7595
+ senderName: params.senderName,
7596
+ senderUsername: params.senderUsername,
7597
+ senderE164: params.senderE164,
7598
+ senderIsOwner: params.senderIsOwner,
7599
+ modelProvider: params.provider,
7600
+ modelId: params.modelId,
7601
+ modelApi: params.model.api,
7602
+ modelContextWindowTokens: params.model.contextWindow,
7603
+ modelHasVision: params.model.input?.includes("image") ?? false,
7604
+ workspaceDir: effectiveWorkspace,
7605
+ cwd: effectiveCwd ?? effectiveWorkspace,
7606
+ sandboxToolPolicy: sandbox?.tools,
7607
+ conversationToolPolicy: params.conversationToolPolicy,
7608
+ inputProvenance: params.inputProvenance,
7609
+ trustedInternalHandoff: params.trustedInternalHandoff,
7610
+ scheduledToolPolicy: params.scheduledToolPolicy
7611
+ };
7612
+ const reservedToolNames = [...tools.map((tool) => tool.name), ...registeredTools.map((tool) => tool.name)];
7613
+ const turnSourceChannel = params.messageChannel ?? params.messageProvider;
7614
+ const turnSourceTo = params.currentMessagingTarget ?? params.currentChannelId;
7615
+ const requester = {
7616
+ ...turnSourceChannel ? { channel: turnSourceChannel } : {},
7617
+ ...params.agentAccountId ? { accountId: params.agentAccountId } : {},
7618
+ ...params.senderId ? { senderId: params.senderId } : {},
7619
+ ...params.senderIsOwner !== void 0 ? { senderIsOwner: params.senderIsOwner } : {},
7620
+ ...params.memberRoleIds?.length ? { roleIds: [...params.memberRoleIds] } : {}
7621
+ };
7622
+ const hasRequester = Object.keys(requester).length > 0;
7623
+ const requestInteractiveMcpApproval = async (approval) => {
7624
+ const allowedDecisions = approval.mode === "prompt" ? ["allow-once", "deny"] : [
7625
+ "allow-once",
7626
+ "allow-always",
7627
+ "deny"
7628
+ ];
7629
+ const outcome = await requestPluginApprovalOutcome({
7630
+ hostCapabilities: params.hostCapabilities,
7631
+ signal: approval.signal,
7632
+ title: `Run MCP tool ${approval.serverName}/${approval.toolName}`,
7633
+ description: `Codex approval mode "${approval.mode}" requires an operator decision before this MCP tool runs. ${formatMcpCodexApprovalRemedy(approval.serverName)}`,
7634
+ allowedDecisions,
7635
+ toolName: approval.safeToolName,
7636
+ toolCallId: approval.toolCallId,
7637
+ mcpTool: {
7638
+ server: approval.serverName,
7639
+ tool: approval.toolName
7640
+ },
7641
+ isMcpToolApprovalActive: approval.isActive
7642
+ });
7643
+ if (outcome !== "approved-once" && outcome !== "approved-session") throw new Error(`${approval.serverName}/${approval.toolName}: interactive Codex approval (${approval.mode}) was not granted: ${outcome}`);
7644
+ };
7645
+ const requestRequesterMcpApproval = async (approval) => {
7646
+ const outcome = await requestPluginApprovalOutcome({
7647
+ hostCapabilities: params.hostCapabilities,
7648
+ signal: approval.signal,
7649
+ title: `Run MCP tool ${approval.serverName}/${approval.toolName}`,
7650
+ description: `Codex approval mode "${approval.mode}" requires an operator decision before this MCP tool runs. ${formatMcpCodexApprovalRemedy(approval.serverName)}`,
7651
+ allowedDecisions: ["allow-once", "deny"],
7652
+ toolName: approval.safeToolName,
7653
+ toolCallId: approval.toolCallId,
7654
+ mcpTool: {
7655
+ server: approval.serverName,
7656
+ tool: approval.toolName
7657
+ },
7658
+ isMcpToolApprovalActive: approval.isActive
7659
+ });
7660
+ if (outcome !== "approved-once" && outcome !== "approved-session") throw new Error(`${approval.serverName}/${approval.toolName}: interactive Codex approval (${approval.mode}) was not granted: ${outcome}`);
7661
+ };
7662
+ configuredMcp = configuredMcpSurface ? await materializeStaticMcpToolsForHarnessRun({
7663
+ sessionId: params.sessionId,
7664
+ sessionKey: params.sessionKey,
7665
+ agentId: sessionAgentId,
7666
+ workspaceDir: effectiveWorkspace,
7667
+ agentDir: policyContext.agentDir,
7668
+ cfg: params.config,
7669
+ manifestRegistry: bundleManifestRegistry,
7670
+ reservedToolNames,
7671
+ toolsAllow: params.toolsAllow,
7672
+ toolOverrides: codexMcpToolOverrides,
7673
+ autoApproveCodexAppServerApprovals: shouldAutoApproveCodexAppServerApprovals(connection.appServer),
7674
+ projectedMcpServers: bundleMcpThreadConfig.configPatch?.mcp_servers,
7675
+ ...configuredMcpSurface === "transient" ? { requestInteractiveCodexApproval: requestInteractiveMcpApproval } : {},
7676
+ policyContext,
7677
+ warn: (message) => embeddedAgentLog.warn(message)
7678
+ }) : void 0;
7186
7679
  scopedMcpTools = authenticatedScheduledMode ? void 0 : await materializeRequesterScopedMcpToolsForHarnessRun({
7187
7680
  sessionId: params.sessionId,
7188
7681
  sessionKey: params.sessionKey,
@@ -7270,7 +7763,7 @@ async function prepareCodexAttemptTools(runtime) {
7270
7763
  agentDir: policyContext.agentDir,
7271
7764
  cfg: params.config,
7272
7765
  manifestRegistry: bundleManifestRegistry,
7273
- reservedToolNames: toolBridge.availableTools.map((tool) => tool.name),
7766
+ reservedToolNames: configuredMcp ? reservedToolNames : toolBridge.availableTools.map((tool) => tool.name),
7274
7767
  toolsAllow: params.toolsAllow,
7275
7768
  toolOverrides: codexMcpToolOverrides,
7276
7769
  autoApproveCodexAppServerApprovals: shouldAutoApproveCodexAppServerApprovals(connection.appServer),
@@ -7309,14 +7802,13 @@ async function prepareCodexAttemptTools(runtime) {
7309
7802
  requireExplicitMessageTarget,
7310
7803
  scopedMcpTools,
7311
7804
  configuredMcp,
7312
- disposeMcpTools,
7805
+ disposeTools,
7313
7806
  configuredMcpOwnershipVersion: configuredMcpSurface === "scheduled" ? 1 : void 0,
7314
7807
  captureCronCreatorToolAllowlist,
7315
7808
  scheduledAppAuthoritySourceRef,
7316
7809
  dynamicToolParams,
7317
7810
  compactionPlanState,
7318
7811
  computerContextEpoch,
7319
- runCleanups,
7320
7812
  toolBridge,
7321
7813
  toolState,
7322
7814
  toolOutcomeOrdinals,
@@ -7326,7 +7818,7 @@ async function prepareCodexAttemptTools(runtime) {
7326
7818
  runtimeYieldCompletionClaim
7327
7819
  };
7328
7820
  } catch (error) {
7329
- await disposeMcpTools();
7821
+ await disposeTools("error");
7330
7822
  throw error;
7331
7823
  }
7332
7824
  }
@@ -7360,6 +7852,98 @@ async function resolveCodexExplicitSkillInputs(params) {
7360
7852
  }
7361
7853
  }
7362
7854
  //#endregion
7855
+ //#region extensions/codex/src/app-server/provider-review-continuation.ts
7856
+ /** Reconcile the acknowledged failure with the native thread immediately before turn/start. */
7857
+ async function prepareCodexProviderReviewContinuation(params) {
7858
+ const acknowledgment = params.acknowledgment;
7859
+ if (!acknowledgment) return;
7860
+ let nativeChanged = false;
7861
+ let dispatched = false;
7862
+ let dispose = () => {};
7863
+ const assertCurrent = () => {
7864
+ params.signal.throwIfAborted();
7865
+ params.assertCurrent();
7866
+ acknowledgment.read();
7867
+ if (nativeChanged) throw new Error("The native provider review changed before dispatch");
7868
+ };
7869
+ assertCurrent();
7870
+ const snapshot = acknowledgment.read();
7871
+ if (snapshot.phase === "accepted") throw new Error("Provider review continuation cannot start another native turn");
7872
+ const assertWorkStart = () => acknowledgment.assertRuntime({
7873
+ provider: params.provider,
7874
+ model: params.model,
7875
+ runtimeId: "codex",
7876
+ api: params.api,
7877
+ assertCurrent
7878
+ });
7879
+ await assertWorkStart();
7880
+ assertCurrent();
7881
+ const { review } = snapshot;
7882
+ if (review.nativeThreadId !== params.turnStartParams.threadId || !review.review?.continuation) throw new Error("Provider review no longer matches the native thread");
7883
+ dispose = params.client.addNotificationHandler((notification) => {
7884
+ const event = notification.params;
7885
+ if (!isJsonObject(event) || event.threadId !== review.nativeThreadId) return;
7886
+ if (notification.method === "turn/started") nativeChanged = true;
7887
+ else if (notification.method === "turn/completed" || notification.method === "error" && event.willRetry !== true) {
7888
+ const turn = isJsonObject(event.turn) ? event.turn : void 0;
7889
+ const turnId = turn?.id ?? event.turnId;
7890
+ const error = isJsonObject(turn?.error) ? turn.error : isJsonObject(event.error) ? event.error : void 0;
7891
+ const failure = readCodexProviderRefusal(typeof error?.message === "string" ? error.message : void 0, error?.codexErrorInfo, { misalignment: error?.misalignment });
7892
+ if (turnId !== review.nativeTurnId || turn && turn.status !== "failed" || failure?.category !== "misalignment" || error?.misalignment != null && !isDeepStrictEqual(failure.review, review.review)) nativeChanged = true;
7893
+ }
7894
+ });
7895
+ try {
7896
+ const page = await params.client.request("thread/turns/list", {
7897
+ threadId: params.turnStartParams.threadId,
7898
+ limit: 1,
7899
+ sortDirection: "desc",
7900
+ itemsView: "notLoaded"
7901
+ }, {
7902
+ signal: params.signal,
7903
+ timeoutMs: params.timeoutMs,
7904
+ assertCurrent
7905
+ });
7906
+ assertCurrent();
7907
+ const latest = page.data[0];
7908
+ const refusal = latest && readCodexProviderRefusal(latest.error?.message, latest.error?.codexErrorInfo, { misalignment: latest.error?.misalignment });
7909
+ if (page.data.length !== 1 || !latest || latest.id !== review.nativeTurnId || latest.threadId !== void 0 && latest.threadId !== params.turnStartParams.threadId || latest.status !== "failed" || refusal?.category !== "misalignment" || latest.error?.misalignment != null && !isDeepStrictEqual(refusal.review, review.review)) throw new Error("The native provider review changed; refresh the findings before continuing");
7910
+ await assertWorkStart();
7911
+ assertCurrent();
7912
+ const message = review.review.continuation.message;
7913
+ params.turnStartParams.input = [{
7914
+ type: "text",
7915
+ text: message,
7916
+ text_elements: []
7917
+ }];
7918
+ params.turnStartParams.responsesapiClientMetadata = {
7919
+ ...params.turnStartParams.responsesapiClientMetadata,
7920
+ misalignment_override: JSON.stringify({ timestamp: Date.now() })
7921
+ };
7922
+ return {
7923
+ dispose,
7924
+ dispatch: () => {
7925
+ assertCurrent();
7926
+ if (dispatched) throw new Error("Provider review continuation already dispatched");
7927
+ dispatched = true;
7928
+ dispose();
7929
+ },
7930
+ accept: async (turnId) => {
7931
+ assertCurrent();
7932
+ if (!dispatched) throw new Error("Provider review continuation has not dispatched");
7933
+ await acknowledgment.acceptNativeTurn({
7934
+ nativeThreadId: params.turnStartParams.threadId,
7935
+ nativeTurnId: turnId,
7936
+ assertCurrent
7937
+ });
7938
+ assertCurrent();
7939
+ }
7940
+ };
7941
+ } catch (error) {
7942
+ dispose();
7943
+ throw error;
7944
+ }
7945
+ }
7946
+ //#endregion
7363
7947
  //#region extensions/codex/src/app-server/run-attempt-turn-request.ts
7364
7948
  async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurrentThreadRoute, waitForActiveNativeTurnCompletion) {
7365
7949
  const { prompt, state: resourceState, releaseCurrentRoute } = resources;
@@ -7417,10 +8001,17 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
7417
8001
  const startCodexTurn = async () => {
7418
8002
  const activeTurnRoute = await ensureCurrentThreadRoute();
7419
8003
  assertCodexSessionRuntimeOwnership(resourceState.thread, params.expectedSessionRuntimeOwnership);
8004
+ const selectedThread = resourceState.thread;
8005
+ const { threadId, liveThreadOwnership, model, modelProvider } = selectedThread;
8006
+ const turnClient = resourceState.client;
8007
+ const assertTurnCurrent = () => {
8008
+ connection.assertCurrent();
8009
+ liveThreadOwnership?.assertCurrent();
8010
+ if (resourceState.thread !== selectedThread || selectedThread.threadId !== threadId || selectedThread.liveThreadOwnership !== liveThreadOwnership || selectedThread.model !== model || selectedThread.modelProvider !== modelProvider) throw new Error("Codex native model or thread ownership changed during turn start.");
8011
+ };
7420
8012
  const turnAppServer = withCodexAppServerFastModeServiceTier(connection.mutable.pluginAppServer, runtimeParams);
7421
8013
  connection.mutable.pluginAppServer = turnAppServer;
7422
8014
  const references = prepareWorkspaceReferences();
7423
- const referencesRetained = turnState.codexTurnPromptText.includes(workspaceBootstrapContext.promptContext ?? "");
7424
8015
  const inferenceRoute = usesSupervisionConnection ? void 0 : getCodexInferenceThread(resourceState.client, resourceState.thread.threadId);
7425
8016
  const turnStartParams = buildTurnStartParams(runtimeParams, {
7426
8017
  threadId: resourceState.thread.threadId,
@@ -7484,6 +8075,17 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
7484
8075
  truncated: null
7485
8076
  } : file);
7486
8077
  }
8078
+ const continuation = await prepareCodexProviderReviewContinuation({
8079
+ acknowledgment: params.providerReviewAcknowledgment,
8080
+ client: resourceState.client,
8081
+ turnStartParams,
8082
+ provider: params.provider,
8083
+ model: params.modelId,
8084
+ api: runtimeParams.model.api,
8085
+ signal: runAbortController.signal,
8086
+ timeoutMs: params.timeoutMs,
8087
+ assertCurrent: assertTurnCurrent
8088
+ });
7487
8089
  codexModelCallDiagnostics.setRequestPayloadBytes(utf8JsonByteLength(turnStartParams));
7488
8090
  recordCodexTrajectoryContext(resources.trajectoryRecorder, {
7489
8091
  attempt: params,
@@ -7507,29 +8109,41 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
7507
8109
  }
7508
8110
  });
7509
8111
  let acceptedTurnId;
8112
+ const upstreamUserText = turnStartParams.input.flatMap((item) => item.type === "text" ? [item.text] : []).join("\n");
7510
8113
  try {
7511
- const startedTurn = assertCodexTurnStartResponse(await resourceState.client.request("turn/start", turnStartParams, {
8114
+ const startedTurn = assertCodexTurnStartResponse(await turnClient.request("turn/start", turnStartParams, {
7512
8115
  timeoutMs: params.timeoutMs,
7513
8116
  signal: runAbortController.signal,
7514
- assertCurrent: connection.assertCurrent
8117
+ assertCurrent: () => {
8118
+ assertTurnCurrent();
8119
+ continuation?.dispatch();
8120
+ }
7515
8121
  }));
7516
8122
  acceptedTurnId = startedTurn.turn.id;
7517
- connection.assertCurrent();
7518
- if (referencesRetained) references.accepted();
8123
+ resources.nativeProcessAuthority?.bindTurn(turnClient, threadId, acceptedTurnId);
8124
+ assertTurnCurrent();
8125
+ if (upstreamUserText.includes(workspaceBootstrapContext.promptContext ?? "")) references.accepted();
7519
8126
  throwIfTurnStartAcceptedAfterAbort();
7520
- return startedTurn;
8127
+ await continuation?.accept(acceptedTurnId);
8128
+ return {
8129
+ turn: startedTurn,
8130
+ upstreamUserText
8131
+ };
7521
8132
  } catch (error) {
7522
8133
  if (acceptedTurnId || isCodexAppServerIndeterminateRequestCancellationError(error)) try {
7523
- resourceState.startupClientUnsafe = !await interruptCodexTurnAndWaitBestEffort(resourceState.client, {
7524
- threadId: resourceState.thread.threadId,
8134
+ resourceState.startupClientUnsafe = !await interruptCodexTurnAndWaitBestEffort(turnClient, {
8135
+ threadId,
7525
8136
  turnId: acceptedTurnId ?? ""
7526
8137
  });
7527
- if (resourceState.startupClientUnsafe) await retireUnsafeCodexTurnClientBestEffort(resourceState.client, "startup interrupt");
8138
+ if (resourceState.startupClientUnsafe) await retireUnsafeCodexTurnClientBestEffort(turnClient, "startup interrupt");
7528
8139
  } finally {
7529
8140
  await releaseCurrentRoute();
7530
8141
  }
7531
8142
  else await activeTurnRoute.cancelTurn();
8143
+ if (params.providerReviewAcknowledgment) throw new Error("Could not continue this chat. Review its latest status before trying again.");
7532
8144
  throw error;
8145
+ } finally {
8146
+ continuation?.dispose();
7533
8147
  }
7534
8148
  };
7535
8149
  if (resourceState.thread.lifecycle.action === "resumed" && (resourceState.thread.lifecycle.activeTurnIds?.length ?? 0) > 0) {
@@ -7565,7 +8179,7 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
7565
8179
  //#endregion
7566
8180
  //#region extensions/codex/src/app-server/run-attempt-turn-start.ts
7567
8181
  async function startCodexAttemptTurn(resources, turnRuntime, notifications, requestRuntime) {
7568
- const { prompt, state: resourceState, trajectoryRecorder, markTrajectoryEndRecorded, activateNativePreToolUseFailureFallback, releaseCurrentRoute, releaseSandboxExecEnvironment, releaseSharedClientLeaseAndRetireOneShotClient } = resources;
8182
+ const { prompt, state: resourceState, trajectoryRecorder, markTrajectoryEndRecorded } = resources;
7569
8183
  const { context, turnState, systemPromptReport } = prompt;
7570
8184
  const { runtime, historyState, hookContext, hookContextWindowFields, hookRunner } = context;
7571
8185
  const { connection, runtimeParams, effectiveRuntimeProviderId, effectiveRuntimeModelId } = runtime;
@@ -7573,7 +8187,8 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
7573
8187
  const { state, turnIdRef } = turnRuntime;
7574
8188
  const { waitForActiveNativeTurnCompletion } = notifications;
7575
8189
  const { codexModelCallDiagnostics, startCodexTurn, buildLlmInputEvent } = requestRuntime;
7576
- let turn;
8190
+ let started;
8191
+ resourceState.turnStartAttempted = true;
7577
8192
  try {
7578
8193
  codexModelCallDiagnostics.emitStarted();
7579
8194
  runAgentHarnessLlmInputHook({
@@ -7581,10 +8196,10 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
7581
8196
  ctx: hookContext,
7582
8197
  hookRunner
7583
8198
  });
7584
- turn = await startCodexTurn();
8199
+ started = await startCodexTurn();
7585
8200
  } catch (error) {
7586
8201
  let turnStartError = error;
7587
- if (isCodexActiveCompactTurnError(turnStartError)) {
8202
+ if (!params.providerReviewAcknowledgment && isCodexActiveCompactTurnError(turnStartError)) {
7588
8203
  embeddedAgentLog.info("codex app-server turn/start blocked by active compact turn; waiting to retry", { threadId: resourceState.thread.threadId });
7589
8204
  if (await waitForActiveNativeTurnCompletion() && !runAbortController.signal.aborted) {
7590
8205
  emitCodexAppServerEvent(params, {
@@ -7595,13 +8210,13 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
7595
8210
  }
7596
8211
  });
7597
8212
  try {
7598
- turn = await startCodexTurn();
8213
+ started = await startCodexTurn();
7599
8214
  } catch (retryError) {
7600
8215
  turnStartError = retryError;
7601
8216
  }
7602
8217
  }
7603
8218
  }
7604
- if (turn === void 0 && resourceState.thread.connectionScope !== "supervision" && shouldUseFreshCodexThreadAfterContextEngineOverflow({
8219
+ if (started === void 0 && !params.providerReviewAcknowledgment && resourceState.thread.connectionScope !== "supervision" && shouldUseFreshCodexThreadAfterContextEngineOverflow({
7605
8220
  error: turnStartError,
7606
8221
  contextEngineActive: Boolean(activeContextEngine),
7607
8222
  thread: resourceState.thread
@@ -7643,7 +8258,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
7643
8258
  }
7644
8259
  });
7645
8260
  try {
7646
- turn = await startCodexTurn();
8261
+ started = await startCodexTurn();
7647
8262
  } catch (retryError) {
7648
8263
  turnStartError = retryError;
7649
8264
  }
@@ -7651,7 +8266,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
7651
8266
  } catch (retrySetupError) {
7652
8267
  turnStartError = retrySetupError;
7653
8268
  }
7654
- if (turn === void 0) {
8269
+ if (started === void 0) {
7655
8270
  const usageLimitError = await formatCodexTurnStartUsageLimitError({
7656
8271
  client: resourceState.client,
7657
8272
  error: turnStartError,
@@ -7661,7 +8276,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
7661
8276
  signal: runAbortController.signal
7662
8277
  });
7663
8278
  const message = usageLimitError?.message ?? formatErrorMessage(turnStartError);
7664
- if (isInvalidCodexImagePayloadError(message)) await clearCodexBindingAfterInvalidImagePayload(bindingStore, bindingIdentity, {
8279
+ if (!params.providerReviewAcknowledgment && isInvalidCodexImagePayloadError(message)) await clearCodexBindingAfterInvalidImagePayload(bindingStore, bindingIdentity, {
7665
8280
  phase: "turn_start",
7666
8281
  threadId: resourceState.thread.threadId,
7667
8282
  error: message
@@ -7718,43 +8333,6 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
7718
8333
  ctx: hookContext,
7719
8334
  hookRunner
7720
8335
  });
7721
- if ((isIncognitoSessionKey(params.sessionKey) ? await bindingStore.mutate(bindingIdentity, {
7722
- kind: "clear",
7723
- threadId: resourceState.thread.threadId
7724
- }) : true) && !resourceState.startupClientUnsafe) {
7725
- if (!await unsubscribeCodexThreadBestEffort(resourceState.client, {
7726
- threadId: resourceState.thread.threadId,
7727
- timeoutMs: 5e3
7728
- })) await runAgentCleanupStep({
7729
- runId: params.runId,
7730
- sessionId: params.sessionId,
7731
- step: "codex-retire-unsafe-startup-client",
7732
- log: embeddedAgentLog,
7733
- cleanup: async () => closeCodexStartupClientBestEffort(resourceState.client)
7734
- });
7735
- }
7736
- await releaseCurrentRoute();
7737
- activateNativePreToolUseFailureFallback();
7738
- const relay = resourceState.nativeHookRelay;
7739
- relay?.unregister();
7740
- await runAgentCleanupStep({
7741
- runId: params.runId,
7742
- sessionId: params.sessionId,
7743
- step: "codex-turn-start-failure-native-hook-relay",
7744
- log: embeddedAgentLog,
7745
- cleanup: async () => {
7746
- await relay?.drain();
7747
- }
7748
- });
7749
- await releaseSandboxExecEnvironment();
7750
- await runAgentCleanupStep({
7751
- runId: params.runId,
7752
- sessionId: params.sessionId,
7753
- step: "codex-trajectory-flush-startup-failure",
7754
- log: embeddedAgentLog,
7755
- cleanup: async () => trajectoryRecorder?.flush()
7756
- });
7757
- await releaseSharedClientLeaseAndRetireOneShotClient();
7758
8336
  if (usageLimitError) {
7759
8337
  await markCodexAuthProfileBlockedFromRateLimits({
7760
8338
  params,
@@ -7786,11 +8364,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
7786
8364
  throw turnStartError;
7787
8365
  }
7788
8366
  }
7789
- if (!turn) {
7790
- activateNativePreToolUseFailureFallback();
7791
- await releaseSharedClientLeaseAndRetireOneShotClient();
7792
- throw new Error("codex app-server turn/start failed without an error");
7793
- }
8367
+ if (!started) throw new Error("codex app-server turn/start failed without an error");
7794
8368
  const authoritySourceRef = context.attemptTools.scheduledAppAuthoritySourceRef;
7795
8369
  if (resourceState.thread.pluginAppPolicyContext) authoritySourceRef.current = {
7796
8370
  client: resourceState.client,
@@ -7798,9 +8372,9 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
7798
8372
  policyContext: resourceState.thread.pluginAppPolicyContext,
7799
8373
  configCwd: connection.effectiveCwd
7800
8374
  };
7801
- turnIdRef.current = turn.turn.id;
7802
- resourceState.nativeSubagentMonitor?.bindTurn(turn.turn.id);
7803
- return { turn };
8375
+ turnIdRef.current = started.turn.turn.id;
8376
+ resourceState.nativeSubagentMonitor?.bindTurn(started.turn.turn.id);
8377
+ return started;
7804
8378
  }
7805
8379
  //#endregion
7806
8380
  //#region extensions/codex/src/app-server/attempt-deadlines.ts
@@ -8018,44 +8592,50 @@ async function runCodexAppServerAttempt(params, options) {
8018
8592
  const attemptContext = await preparation.measure("context", () => prepareCodexAttemptContext(runtime, attemptTools));
8019
8593
  const resources = prepareCodexAttemptResources(await preparation.measure("prompt", () => prepareCodexAttemptPrompt(attemptContext)));
8020
8594
  attemptTools.runtimeYieldCompletionClaim.current = () => resources.state.nativeHookRelay?.hasClaimedDirectChild() ?? false;
8021
- await preparation.measure("runtime-start", () => startCodexAttemptRuntime(resources));
8022
- const turnRuntime = createCodexAttemptTurnState(resources);
8595
+ let activeTurnOwnsCleanup = false;
8023
8596
  try {
8024
- const lifecycle = createCodexAttemptLifecycleController(resources, turnRuntime);
8025
- const notifications = createCodexAttemptNotificationController(resources, turnRuntime, lifecycle);
8026
- const serverRequests = createCodexAttemptServerRequestController(resources, turnRuntime, lifecycle, notifications.waitForNativeTerminalItems);
8027
- const { ensureCurrentThreadRoute } = await preparation.measure("thread-route", () => prepareCodexAttemptRoute(resources, turnRuntime, notifications, serverRequests.handleServerRequest));
8028
- const turnRequest = await preparation.measure("turn-request", () => prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurrentThreadRoute, notifications.waitForActiveNativeTurnCompletion));
8029
- preparation.ready();
8030
- const turnStart = await startCodexAttemptTurn(resources, turnRuntime, notifications, turnRequest);
8031
- if ("result" in turnStart) return turnStart.result;
8032
- const activeTurn = activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, turnStart.turn);
8033
- let finalizedResult;
8597
+ await preparation.measure("runtime-start", () => startCodexAttemptRuntime(resources));
8598
+ const turnRuntime = createCodexAttemptTurnState(resources);
8034
8599
  try {
8600
+ const lifecycle = createCodexAttemptLifecycleController(resources, turnRuntime);
8601
+ const notifications = createCodexAttemptNotificationController(resources, turnRuntime, lifecycle);
8602
+ const serverRequests = createCodexAttemptServerRequestController(resources, turnRuntime, lifecycle, notifications.waitForNativeTerminalItems);
8603
+ const { ensureCurrentThreadRoute } = await preparation.measure("thread-route", () => prepareCodexAttemptRoute(resources, turnRuntime, notifications, serverRequests.handleServerRequest));
8604
+ const turnRequest = await preparation.measure("turn-request", () => prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurrentThreadRoute, notifications.waitForActiveNativeTurnCompletion));
8605
+ preparation.ready();
8606
+ const turnStart = await startCodexAttemptTurn(resources, turnRuntime, notifications, turnRequest);
8607
+ if ("result" in turnStart) return turnStart.result;
8608
+ const activeTurn = activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, turnStart);
8609
+ activeTurnOwnsCleanup = true;
8610
+ let finalizedResult;
8035
8611
  try {
8036
- await activeTurn.ready;
8037
- finalizedResult = await finalizeCodexAttempt(resources, turnRuntime, lifecycle, notifications, turnRequest, activeTurn);
8038
- } finally {
8039
- await cleanupCodexAttempt(resources, turnRuntime, lifecycle, turnRequest, activeTurn);
8612
+ try {
8613
+ await activeTurn.ready;
8614
+ finalizedResult = await finalizeCodexAttempt(resources, turnRuntime, lifecycle, notifications, turnRequest, activeTurn);
8615
+ } finally {
8616
+ await cleanupCodexAttempt(resources, turnRuntime, lifecycle, turnRequest, activeTurn);
8617
+ }
8618
+ } catch (error) {
8619
+ if (!finalizedResult || !turnRuntime.state.pluginRuntimeRefreshStop) throw error;
8620
+ const original = attemptTerminal.project(finalizedResult.terminal).promptError;
8621
+ finalizedResult.terminal = attemptTerminal.merge(finalizedResult.terminal, {
8622
+ kind: "failed",
8623
+ source: "prompt",
8624
+ error: new AggregateError(original ? [original, error] : [error], "Plugin runtime changed, but native continuation failed. Inspect the existing thread before continuing; do not repeat completed actions.")
8625
+ });
8626
+ delete finalizedResult.pluginRuntimeRefreshMessages;
8627
+ delete finalizedResult.settledTurnFinalizationContext;
8040
8628
  }
8041
- } catch (error) {
8042
- if (!finalizedResult || !turnRuntime.state.pluginRuntimeRefreshStop) throw error;
8043
- const original = attemptTerminal.project(finalizedResult.terminal).promptError;
8044
- finalizedResult.terminal = attemptTerminal.merge(finalizedResult.terminal, {
8045
- kind: "failed",
8046
- source: "prompt",
8047
- error: new AggregateError(original ? [original, error] : [error], "Plugin runtime changed, but native continuation failed. Inspect the existing thread before continuing; do not repeat completed actions.")
8048
- });
8049
- delete finalizedResult.pluginRuntimeRefreshMessages;
8050
- delete finalizedResult.settledTurnFinalizationContext;
8629
+ if (resources.state.executionDisconnectError && !connection.terminalState.explicitCancellationObserved) throw resources.state.executionDisconnectError;
8630
+ return finalizedResult;
8631
+ } finally {
8632
+ turnRuntime.deadlines.dispose();
8051
8633
  }
8052
- if (resources.state.executionDisconnectError && !connection.terminalState.explicitCancellationObserved) throw resources.state.executionDisconnectError;
8053
- return finalizedResult;
8054
8634
  } finally {
8055
- turnRuntime.deadlines.dispose();
8635
+ if (!activeTurnOwnsCleanup) await resources.cleanupBeforeActiveTurn();
8056
8636
  }
8057
8637
  } finally {
8058
- await attemptTools.disposeMcpTools();
8638
+ await attemptTools.disposeTools(connection.runAbortController.signal.aborted ? "cancel" : "error");
8059
8639
  }
8060
8640
  } finally {
8061
8641
  params.abortSignal?.removeEventListener("abort", connection.abortFromUpstream);