@openclaw/codex 2026.9.4 → 2026.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/activity.svg +30 -0
- package/assets/icon.png +0 -0
- package/dist/.setup/account-usage-runtime-Eem_WGqY.mjs +75 -0
- package/dist/{apply-CvT8tW5i.js → .setup/apply-DDOi8uNx.mjs} +24 -30
- package/dist/.setup/async-questions-DdhOCwGi.mjs +27 -0
- package/dist/{attempt-client-cleanup-DKHzbwt5.js → .setup/attempt-client-cleanup-CEv1cKwF.mjs} +79 -49
- package/dist/.setup/attempt-terminal-gZrxQ35N.mjs +5 -0
- package/dist/.setup/attempt-workspace-context-DUVEn_CS.mjs +331 -0
- package/dist/{auth-binding-CWlKVccJ.js → .setup/auth-binding-DhLWa_7K.mjs} +1 -1
- package/dist/{auth-cache-key-7orQae_j.js → .setup/auth-cache-key-B2mpaI9D.mjs} +9 -81
- package/dist/{auth-profile-CwzO4_RG.js → .setup/auth-profile-WqZtZfXN.mjs} +1 -1
- package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
- package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
- package/dist/.setup/binding-connection-ThoatDcb.mjs +50 -0
- package/dist/.setup/binding-connection.runtime-yoHrABt-.mjs +48 -0
- package/dist/{bounded-turn-C_Hneydj.js → .setup/bounded-turn-B2HScEgT.mjs} +143 -32
- package/dist/{build-state-BCmg9-5p.js → .setup/build-state-C7EnDVgr.mjs} +1 -1
- package/dist/{capabilities-8vx68WLH.js → .setup/capabilities-CDXOOFdZ.mjs} +1 -1
- package/dist/{client-B57KWPQx.js → .setup/client-Cs08OXVQ.mjs} +705 -512
- package/dist/.setup/client-catalog-response-BMgt_4q4.mjs +285 -0
- package/dist/{command-dispatch-BpduNGVf.js → .setup/command-dispatch-B4JuOsOk.mjs} +8 -4
- package/dist/{command-formatters-lxlkNZgU.js → .setup/command-formatters-Bmqvr9tO.mjs} +8 -4
- package/dist/{command-handlers-tiL9iWj7.js → .setup/command-handlers-DW7Lx9oH.mjs} +137 -186
- package/dist/{command-rpc-CR5EOEZX.js → .setup/command-rpc-DixIj3HW.mjs} +47 -23
- package/dist/{compact-B_H3AOd7.js → .setup/compact-Du5UvtxA.mjs} +29 -51
- package/dist/{config-oIORaQ5T.js → .setup/config-BoTP_mrL.mjs} +5 -4
- package/dist/{config-options-CXMq1T-C.js → .setup/config-options-BvaRs51b.mjs} +50 -446
- package/dist/{protocol-5bh1G-H7.js → .setup/config-parsing-CcB9iPoq.mjs} +9 -51
- package/dist/{config-runtime-D0zGNIHu.js → .setup/config-runtime-C8Rw1m1m.mjs} +2 -2
- package/dist/.setup/config-security-BEReZ6go.mjs +380 -0
- package/dist/{conversation-binding-DsB4-O7U.js → .setup/conversation-binding-DP-gMrBP.mjs} +29 -38
- package/dist/{conversation-binding-data-BiodpIzq.js → .setup/conversation-binding-data-CrcyZk6O.mjs} +1 -1
- package/dist/{conversation-control-CtUu1b3m.js → .setup/conversation-control-uK9Jomlc.mjs} +32 -67
- package/dist/.setup/cyber-failover-DYwbmf1o.mjs +123 -0
- package/dist/.setup/cyber-failover-notice-e9G3J9-e.mjs +17 -0
- package/dist/{dynamic-tools-CmN5RAip.js → .setup/dynamic-tools-BDXl-8Cw.mjs} +936 -620
- package/dist/{effective-mcp-catalog-Bd73bqA8.js → .setup/effective-mcp-catalog-CvnvnGIe.mjs} +3 -3
- package/dist/{ephemeral-turn-D78_VmzO.js → .setup/ephemeral-turn-poidXgek.mjs} +9 -7
- package/dist/{event-projector-assistant-message-BmBM4qBV.js → .setup/event-projector-assistant-message-BsruvNrH.mjs} +8 -7
- package/dist/{event-projector-items-5VhsECCO.js → .setup/event-projector-items-C6L_5ZiT.mjs} +42 -8
- package/dist/{attempt-notifications-C9XufG6l.js → .setup/event-projector-usage-CnBS8Wa3.mjs} +102 -9
- package/dist/{harness-C7rRa7bm.js → .setup/harness-a_MsE4-_.mjs} +81 -21
- package/dist/{inference-context-Dr_mzvk4.js → .setup/inference-context-D96l9-ew.mjs} +1 -1
- package/dist/.setup/inference-proxy-b-aJMSxm.mjs +601 -0
- package/dist/{isolated-completion-DWVb5U2J.js → .setup/isolated-completion-BIZFhTNG.mjs} +18 -11
- package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
- package/dist/{managed-binary-D22rNEcR.js → .setup/managed-binary-BnshlFag.mjs} +14 -3
- package/dist/{managed-thread-store-D1t5jh3G.js → .setup/managed-thread-store-BMqgThVL.mjs} +48 -14
- package/dist/{model-catalog-Dq2n8f_p.js → .setup/model-catalog-CfXJf9Ay.mjs} +36 -12
- package/dist/{models-PCKOim-h.js → .setup/models-KnqBv0hE.mjs} +3 -3
- package/dist/.setup/native-auth-rWbGbMn3.mjs +57 -0
- package/dist/{native-subagent-history-DjtPloaU.js → .setup/native-subagent-history-0nYYgo0k.mjs} +43 -35
- package/dist/.setup/native-subagent-monitor-D3filLY2.mjs +4859 -0
- package/dist/{native-subagent-task-ids-BzTdT0Uw.js → .setup/native-subagent-task-ids-wb8CKZGN.mjs} +98 -44
- package/dist/{node-cli-sessions-DKaOmVUh.js → .setup/node-cli-sessions-r3avj02l.mjs} +86 -68
- package/dist/.setup/node-exec-server.runtime-BDwWXVpK.mjs +247 -0
- package/dist/{plan-7uG-Fp36.js → .setup/plan-CN3VwfNU.mjs} +133 -119
- package/dist/{plugin-activation-BYQculil.js → .setup/plugin-activation-DT3MNtqj.mjs} +7 -16
- package/dist/{plugin-app-cache-key-d0eKxy7b.js → .setup/plugin-app-cache-key-B2CsSdnV.mjs} +32 -44
- package/dist/{plugin-approval-roundtrip-Bz3FT8W5.js → .setup/plugin-approval-roundtrip-C0MZzCuP.mjs} +1 -1
- package/dist/{plugin-inventory-oL4Na1ZG.js → .setup/plugin-inventory-BoRei8Z4.mjs} +21 -11
- package/dist/{plugin-marketplace-discovery-P-Vndfqq.js → .setup/plugin-marketplace-discovery-CDOi8IFs.mjs} +4 -1
- package/dist/{plugin-metadata-cache-ClPJpRio.js → .setup/plugin-metadata-cache-Ctmo83k_.mjs} +226 -141
- package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
- package/dist/{provider-MQ8PVkuE.js → .setup/provider-BOsxQHOM.mjs} +9 -5
- package/dist/{provider-capabilities-BvCUL69A.js → .setup/provider-capabilities-BfE88FZ5.mjs} +31 -3
- package/dist/{rate-limits-CBMmWBr9.js → .setup/rate-limits-CMU3DUD0.mjs} +174 -151
- package/dist/{request-B7hEkBGq.js → .setup/request-D2L0zMrq.mjs} +130 -42
- package/dist/{run-attempt-CvsAAGa0.js → .setup/run-attempt-BHu11r7h.mjs} +1628 -966
- package/dist/.setup/run-attempt-lifecycle-B7JbY4-F.mjs +71 -0
- package/dist/{runtime-artifact-BJ0rXBZ_.js → .setup/runtime-artifact-CLZ8udh-.mjs} +29 -45
- package/dist/{sandbox-guard-BxgyoM8M.js → .setup/sandbox-guard-C2sRMOEY.mjs} +3 -3
- package/dist/{session-binding-CI8UuilT.js → .setup/session-binding-Cm0apEbd.mjs} +36 -83
- package/dist/{session-binding-record-Bcvslnhf.js → .setup/session-binding-record-BGoz8wOK.mjs} +202 -5
- package/dist/.setup/session-binding-sidecars-BlB5EvIS.mjs +546 -0
- package/dist/.setup/session-catalog-Pno1xGcl.mjs +2764 -0
- package/dist/{session-catalog-adoption-tcZi1IfX.js → .setup/session-catalog-adoption-BI6UTDZT.mjs} +58 -26
- package/dist/{session-catalog-archive-CwKg8Xz2.js → .setup/session-catalog-archive-lHBqzhaO.mjs} +6 -6
- package/dist/.setup/session-catalog-events-Bj6j94E_.mjs +347 -0
- package/dist/.setup/session-catalog-index-B9_VQIUz.mjs +1170 -0
- package/dist/.setup/session-catalog-index-order-hcdz07yN.mjs +48 -0
- package/dist/.setup/session-catalog-index-state-Dgh8ORJm.mjs +183 -0
- package/dist/{thread-history-page-D0JIp48V.js → .setup/session-catalog-native-projection-DowriLid.mjs} +223 -95
- package/dist/{session-catalog-node-adoption-B1tgDW-m.js → .setup/session-catalog-node-adoption-ITddWx_X.mjs} +25 -13
- package/dist/{session-catalog-node-continue-Ci-DXyJP.js → .setup/session-catalog-node-continue-6g6qi4A9.mjs} +24 -15
- package/dist/.setup/session-catalog-projection-zK_PUsiE.mjs +422 -0
- package/dist/{session-cli-DNN_jhGc.js → .setup/session-cli-irrD-uo7.mjs} +3 -3
- package/dist/{session-history-Cz-tOOYj.js → .setup/session-history-BrqhSCf9.mjs} +19 -19
- package/dist/{session-history-import-DwyijFI6.js → .setup/session-history-import-D-3wAgOP.mjs} +4 -4
- package/dist/{session-history-read-cxPUxyVV.js → .setup/session-history-read-B3ZfSUbF.mjs} +2 -2
- package/dist/{session-history.worker-BeK1YOyT.js → .setup/session-history.worker-CaCh0xF_.mjs} +10 -24
- package/dist/{session-initialization-Ct0_Hzmg.js → .setup/session-initialization-rcgbZiid.mjs} +2 -2
- package/dist/{session-permission-policy-BBmXA8Eg.js → .setup/session-permission-policy-BI1QK_98.mjs} +2 -2
- package/dist/{session-retirement-B2YfbAAT.js → .setup/session-retirement-BH-S6qkJ.mjs} +26 -7
- package/dist/{settled-turn-context-Du6gdUDd.js → .setup/settled-turn-context-fmwouT5I.mjs} +2 -2
- package/dist/{settled-turn-finalizer-Dn91stmc.js → .setup/settled-turn-finalizer-DiAi6Kx6.mjs} +12 -12
- package/dist/{shared-client-CscigXXL.js → .setup/shared-client-DA4VR4Eb.mjs} +332 -221
- package/dist/{side-question-BGMJQf4U.js → .setup/side-question-BJ1wSDcB.mjs} +183 -230
- package/dist/{source-CElXU0Oy.js → .setup/source-CUzJq5WN.mjs} +11 -10
- package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
- package/dist/{thread-archive-guard-DfpBr-Sz.js → .setup/thread-archive-guard-C9frICzX.mjs} +10 -3
- package/dist/.setup/thread-history-page-DoVpnHim.mjs +83 -0
- package/dist/{thread-lifecycle-DXl1-I6b.js → .setup/thread-lifecycle-B3mfz1TG.mjs} +347 -2318
- package/dist/{thread-ownership-BsDRTsyp.js → .setup/thread-ownership-DcTtAcXj.mjs} +6 -4
- package/dist/{thread-policy-BuEQfE0g.js → .setup/thread-policy-DGuQsuFC.mjs} +19 -3
- package/dist/.setup/thread-requests-BLvGkP2R.mjs +2205 -0
- package/dist/{thread-resume-DsDOZpFg.js → .setup/thread-resume-DIBXwOpE.mjs} +8 -5
- package/dist/.setup/timeout-C910MdAB.mjs +80 -0
- package/dist/{transcript-history-projection-v17wXgdK.js → .setup/transcript-history-projection-ZZpkFkJ_.mjs} +96 -61
- package/dist/{transcript-mirror-C5CKgNy6.js → .setup/transcript-mirror-BtHDBp1G.mjs} +224 -195
- package/dist/{transcript-mirror-attestation-DibE0krH.js → .setup/transcript-mirror-attestation-CzM-94NC.mjs} +4 -1
- package/dist/{transport-stdio-BGjHoYLr.js → .setup/transport-stdio-h2VHOskC.mjs} +274 -89
- package/dist/{upstream-session-fork-BZerMte_.js → .setup/upstream-session-fork-BUr4OUbC.mjs} +51 -42
- package/dist/{usage-tCk-mg_x.js → .setup/usage-BML0r-ua.mjs} +5 -4
- package/dist/.setup/usage-limit-error-DUMbefVY.mjs +166 -0
- package/dist/{web-search-provider.runtime-B7bGbGWq.js → .setup/web-search-provider.runtime-CDKlN-Rv.mjs} +4 -3
- package/dist/api.js +23 -12
- package/dist/catalog-page-worker-entrypoint.js +12 -0
- package/dist/catalog-page.worker.js +9 -0
- package/dist/cli-metadata.js +1 -1
- package/dist/doctor-contract-api.js +8 -528
- package/dist/harness.js +1 -1
- package/dist/index.js +306 -215
- package/dist/media-understanding-provider.js +3 -3
- package/dist/migration-provider-api.js +1 -1
- package/dist/native-tool-policy.js +12 -0
- package/dist/provider-discovery.js +18 -0
- package/dist/session-history-worker-runtime.js +36 -35
- package/dist/session-history.worker.js +2 -2
- package/dist/web-search-contract-api.js +1 -1
- package/openclaw.plugin.json +354 -69
- package/package.json +14 -8
- package/dist/attempt-context-D44yeDII.js +0 -636
- package/dist/binding-connection-D3udKbIE.js +0 -60
- package/dist/event-projector-usage-BfXmpOec.js +0 -102
- package/dist/inference-proxy-HGXKUIre.js +0 -311
- package/dist/launch-args-RXQwn8zV.js +0 -90
- package/dist/native-subagent-history-owner-Pcp7JuVF.js +0 -34
- package/dist/native-subagent-monitor-fQ7eIXEf.js +0 -2978
- package/dist/node-exec-server.runtime-Cl2vapEi.js +0 -226
- package/dist/rpc-error-ttN_QjEm.js +0 -30
- package/dist/session-catalog-ct-AH01I.js +0 -1477
- package/dist/session-catalog-home-id-CwhLdC03.js +0 -18
- package/dist/session-catalog-provenance-D-dIfRAH.js +0 -96
- package/dist/timeout-BVw8aaM1.js +0 -33
- package/dist/version-omm6IPI3.js +0 -12
- /package/dist/{auth-profile-selection-DFu9e167.js → .setup/auth-profile-selection-DFu9e167.mjs} +0 -0
- /package/dist/{config-utils-DujwEnhg.js → .setup/config-utils-DujwEnhg.mjs} +0 -0
- /package/dist/{context-compaction-activity-CMla5FPJ.js → .setup/context-compaction-activity-CMla5FPJ.mjs} +0 -0
- /package/dist/{elicitation-input-DPoK8F7w.js → .setup/elicitation-input-DPoK8F7w.mjs} +0 -0
- /package/dist/{history-rejection-B4nOXNXF.js → .setup/history-rejection-B4nOXNXF.mjs} +0 -0
- /package/dist/{image-payload-sanitizer-tupAr-2o.js → .setup/image-payload-sanitizer-tupAr-2o.mjs} +0 -0
- /package/dist/{incognito-session-uhrBF6wJ.js → .setup/incognito-session-uhrBF6wJ.mjs} +0 -0
- /package/dist/{local-runtime-attribution-B_2mnqhb.js → .setup/local-runtime-attribution-B_2mnqhb.mjs} +0 -0
- /package/dist/{native-execution-policy-umd0tgh4.js → .setup/native-execution-policy-umd0tgh4.mjs} +0 -0
- /package/dist/{rolldown-runtime-8H4AJuhK.js → .setup/rolldown-runtime-8H4AJuhK.mjs} +0 -0
- /package/dist/{session-binding-meta-B7aEMU7g.js → .setup/session-binding-meta-B7aEMU7g.mjs} +0 -0
- /package/dist/{session-upstream-marker-D15C9NHp.js → .setup/session-upstream-marker-D15C9NHp.mjs} +0 -0
- /package/dist/{upstream-prompt-provenance-LphB8slG.js → .setup/upstream-prompt-provenance-LphB8slG.mjs} +0 -0
- /package/dist/{web-search-provider.shared-BrZmlqyR.js → .setup/web-search-provider.shared-BrZmlqyR.mjs} +0 -0
|
@@ -1,72 +1,78 @@
|
|
|
1
|
-
import { s as resolveRecoverableCodexPluginConfigKeys } from "./plugin-inventory-
|
|
2
|
-
import {
|
|
3
|
-
import { n as defineCodexBuildState } from "./build-state-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import { i as resolveCodexAppServerAuthProfileIdForAgent, r as resolveCodexAppServerAuthProfileId } from "./auth-profile-
|
|
22
|
-
import { A as
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import { n as
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import { t as
|
|
32
|
-
import { t as
|
|
33
|
-
import { i as
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import { t as
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import { a as
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import { a as
|
|
44
|
-
import {
|
|
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
|
+
import { c as isCodexPairedNodeRemoteExecPlacementSandbox, d as readCodexPluginConfig, f as resolveCodexPluginsPolicy, l as isCodexRemoteExecPlacementSandbox, u as isCodexSandboxExecServerEnabled } from "./config-parsing-CcB9iPoq.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";
|
|
10
|
+
import { t as isIncognitoSessionKey } from "./incognito-session-uhrBF6wJ.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";
|
|
13
|
+
import { t as readCodexAsyncQuestions } from "./async-questions-DdhOCwGi.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";
|
|
15
|
+
import { r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-LphB8slG.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";
|
|
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";
|
|
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";
|
|
25
|
+
import { r as prepareCodexAppServerAuthBinding } from "./auth-binding-DhLWa_7K.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";
|
|
34
|
+
import { t as persistCodexContextCompactionActivity } from "./context-compaction-activity-CMla5FPJ.mjs";
|
|
35
|
+
import { t as attemptTerminal } from "./attempt-terminal-gZrxQ35N.mjs";
|
|
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";
|
|
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";
|
|
46
|
+
import { n as captureCodexSettledTurnFinalizationContext } from "./settled-turn-context-fmwouT5I.mjs";
|
|
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";
|
|
50
|
+
import { isDeepStrictEqual } from "node:util";
|
|
46
51
|
import { resolveAgentConfig, resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
47
52
|
import { MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
48
53
|
import path from "node:path";
|
|
49
54
|
import fs from "node:fs/promises";
|
|
55
|
+
import { isPathStrictlyInside, readFileWindowFully, root } from "openclaw/plugin-sdk/file-access-runtime";
|
|
50
56
|
import { addAbortListener } from "node:events";
|
|
51
57
|
import { truncateUtf16Safe, truncateUtf8Prefix } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
52
|
-
import {
|
|
58
|
+
import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
53
59
|
import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import { AgentHarnessPreflightError, CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND,
|
|
60
|
+
import { Buffer as Buffer$1 } from "node:buffer";
|
|
61
|
+
import { resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-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";
|
|
57
63
|
import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
58
|
-
import {
|
|
59
|
-
import {
|
|
60
|
-
import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
64
|
+
import { getSessionEntry } from "openclaw/plugin-sdk/session-store-runtime";
|
|
65
|
+
import { acknowledgeInternalToolResult } from "openclaw/plugin-sdk/agent-harness-tool-runtime";
|
|
61
66
|
import { captureFinalCodexCronCreatorToolAllowlist, formatMcpCodexApprovalRemedy, materializeStaticMcpToolsForHarnessRun, resolveCodexMcpToolOverridesForAgent, resolveCodexTtsProvenanceTransfer } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
62
67
|
import { appendSessionYieldContext, hasPromptImageInput } from "openclaw/plugin-sdk/session-transcript-runtime";
|
|
68
|
+
import { prepareAgentWorkspaceAttachments } from "openclaw/plugin-sdk/agent-workspace-runtime";
|
|
63
69
|
import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-local-roots";
|
|
64
70
|
import { isSilentReplyPayloadText } from "openclaw/plugin-sdk/reply-chunking";
|
|
65
71
|
import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
|
|
66
72
|
import { resolveGeneratedMediaMaxBytes } from "openclaw/plugin-sdk/media-generation-runtime";
|
|
67
|
-
import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
73
|
+
import { normalizeMediaReferenceForComparison, saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
68
74
|
import { stripInvisibleUnicode } from "openclaw/plugin-sdk/web-content-extractor";
|
|
69
|
-
import {
|
|
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. */
|
|
@@ -126,6 +132,7 @@ var CodexSteeringAcceptedUnconfirmedError = class extends Error {
|
|
|
126
132
|
* app-server `turn/steer` requests.
|
|
127
133
|
*/
|
|
128
134
|
function createCodexSteeringQueue(params) {
|
|
135
|
+
const acceptedMessages = [];
|
|
129
136
|
let batchedMessages = [];
|
|
130
137
|
const dispatchedBatches = /* @__PURE__ */ new Map();
|
|
131
138
|
const pendingMessages = /* @__PURE__ */ new Set();
|
|
@@ -151,9 +158,13 @@ function createCodexSteeringQueue(params) {
|
|
|
151
158
|
item.acceptance = accepted ? "accepted" : "rejected";
|
|
152
159
|
item.onQueueAccepted?.(accepted);
|
|
153
160
|
};
|
|
161
|
+
const acceptItem = (item) => {
|
|
162
|
+
if (item.acceptance === "open") acceptedMessages.push(item.prepared.message);
|
|
163
|
+
reportItemAcceptance(item, true);
|
|
164
|
+
};
|
|
154
165
|
const resolveItem = (item) => {
|
|
155
166
|
if (item.settled) return;
|
|
156
|
-
|
|
167
|
+
acceptItem(item);
|
|
157
168
|
item.settled = true;
|
|
158
169
|
pendingMessages.delete(item);
|
|
159
170
|
item.resolve();
|
|
@@ -171,7 +182,7 @@ function createCodexSteeringQueue(params) {
|
|
|
171
182
|
params.signal.removeEventListener("abort", abortQueue);
|
|
172
183
|
clearBatchTimer();
|
|
173
184
|
batchedMessages = [];
|
|
174
|
-
for (const batch of dispatchedBatches.values()) for (const item of batch.items)
|
|
185
|
+
for (const batch of dispatchedBatches.values()) for (const item of batch.items) acceptItem(item);
|
|
175
186
|
dispatchedBatches.clear();
|
|
176
187
|
for (const item of pendingMessages) rejectItem(item, error);
|
|
177
188
|
};
|
|
@@ -190,13 +201,14 @@ function createCodexSteeringQueue(params) {
|
|
|
190
201
|
closeQueue(/* @__PURE__ */ new Error("codex app-server steering queue cancelled"));
|
|
191
202
|
};
|
|
192
203
|
const sendBatch = async (items) => {
|
|
193
|
-
|
|
194
|
-
|
|
204
|
+
const pendingItems = items.filter((item) => !item.settled);
|
|
205
|
+
let liveItems = [];
|
|
206
|
+
if (pendingItems.length === 0) return;
|
|
195
207
|
let clientUserMessageId;
|
|
196
208
|
let skippedRevokedBatch = false;
|
|
197
209
|
try {
|
|
198
210
|
assertActive();
|
|
199
|
-
const prepared =
|
|
211
|
+
const prepared = [];
|
|
200
212
|
const isCurrent = (item) => {
|
|
201
213
|
if (item.settled) return false;
|
|
202
214
|
try {
|
|
@@ -207,17 +219,20 @@ function createCodexSteeringQueue(params) {
|
|
|
207
219
|
return false;
|
|
208
220
|
}
|
|
209
221
|
};
|
|
210
|
-
for (const item of
|
|
222
|
+
for (const item of pendingItems) {
|
|
211
223
|
if (!isCurrent(item)) continue;
|
|
212
224
|
try {
|
|
213
|
-
prepared.
|
|
225
|
+
prepared.push(Object.assign(item, { prepared: await params.prepareMessage(item.text, item, () => {
|
|
226
|
+
assertActive();
|
|
227
|
+
item.assertCurrent();
|
|
228
|
+
}) }));
|
|
214
229
|
} catch (error) {
|
|
215
230
|
if (isCurrent(item)) throw error;
|
|
216
231
|
}
|
|
217
232
|
assertActive();
|
|
218
233
|
isCurrent(item);
|
|
219
234
|
}
|
|
220
|
-
liveItems =
|
|
235
|
+
liveItems = prepared.filter(isCurrent);
|
|
221
236
|
if (liveItems.length === 0) return;
|
|
222
237
|
if (params.beforeSubmit) {
|
|
223
238
|
await params.beforeSubmit(liveItems);
|
|
@@ -230,7 +245,7 @@ function createCodexSteeringQueue(params) {
|
|
|
230
245
|
const request = {
|
|
231
246
|
threadId: params.threadId,
|
|
232
247
|
expectedTurnId: params.turnId,
|
|
233
|
-
input: liveItems.flatMap((item) => prepared.
|
|
248
|
+
input: liveItems.flatMap((item) => item.prepared.input),
|
|
234
249
|
clientUserMessageId
|
|
235
250
|
};
|
|
236
251
|
await params.client.request("turn/steer", request, {
|
|
@@ -239,7 +254,7 @@ function createCodexSteeringQueue(params) {
|
|
|
239
254
|
assertCurrent: () => {
|
|
240
255
|
assertActive();
|
|
241
256
|
liveItems = liveItems.filter(isCurrent);
|
|
242
|
-
request.input = liveItems.flatMap((item) => prepared.
|
|
257
|
+
request.input = liveItems.flatMap((item) => item.prepared.input);
|
|
243
258
|
dispatchedBatches.set(request.clientUserMessageId, { items: liveItems });
|
|
244
259
|
if (liveItems.length === 0) {
|
|
245
260
|
skippedRevokedBatch = true;
|
|
@@ -247,15 +262,12 @@ function createCodexSteeringQueue(params) {
|
|
|
247
262
|
}
|
|
248
263
|
}
|
|
249
264
|
});
|
|
250
|
-
for (const item of liveItems)
|
|
265
|
+
for (const item of liveItems) acceptItem(item);
|
|
251
266
|
} catch (error) {
|
|
252
267
|
if (clientUserMessageId) dispatchedBatches.delete(clientUserMessageId);
|
|
253
268
|
if (skippedRevokedBatch) return;
|
|
254
|
-
|
|
255
|
-
for (const item of
|
|
256
|
-
if (acceptedUnconfirmed) reportItemAcceptance(item, true);
|
|
257
|
-
rejectItem(item, error);
|
|
258
|
-
}
|
|
269
|
+
if (clientUserMessageId !== void 0 && (isCodexAppServerIndeterminateRequestCancellationError(error) || isCodexAppServerIndeterminateTransportError(error))) for (const item of liveItems) acceptItem(item);
|
|
270
|
+
for (const item of items) rejectItem(item, error);
|
|
259
271
|
throw error;
|
|
260
272
|
}
|
|
261
273
|
};
|
|
@@ -328,6 +340,7 @@ function createCodexSteeringQueue(params) {
|
|
|
328
340
|
for (const item of batch.items) resolveItem(item);
|
|
329
341
|
return true;
|
|
330
342
|
},
|
|
343
|
+
getAcceptedMessages: () => acceptedMessages.slice(),
|
|
331
344
|
sealAdmission: sealQueueAdmission,
|
|
332
345
|
cancel: cancelQueue
|
|
333
346
|
};
|
|
@@ -337,9 +350,6 @@ function normalizeCodexSteerDebounceMs(value) {
|
|
|
337
350
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : CODEX_STEER_ALL_DEBOUNCE_MS;
|
|
338
351
|
}
|
|
339
352
|
//#endregion
|
|
340
|
-
//#region extensions/codex/src/app-server/attempt-terminal.ts
|
|
341
|
-
const attemptTerminal = agentHarnessAttemptTerminal;
|
|
342
|
-
//#endregion
|
|
343
353
|
//#region extensions/codex/src/app-server/event-projector-assistant.ts
|
|
344
354
|
var CodexAssistantProjection = class {
|
|
345
355
|
constructor(params, emitAgentEvent, matchesToolProgressEcho, nextTranscriptTimestamp, checkpointCommentary) {
|
|
@@ -353,6 +363,7 @@ var CodexAssistantProjection = class {
|
|
|
353
363
|
this.assistantTimestampByItem = /* @__PURE__ */ new Map();
|
|
354
364
|
this.assistantPhaseByItem = /* @__PURE__ */ new Map();
|
|
355
365
|
this.assistantDeliveryByItem = /* @__PURE__ */ new Map();
|
|
366
|
+
this.assistantQuestionsByItem = /* @__PURE__ */ new Map();
|
|
356
367
|
this.latestTerminalAssistantCandidateSuperseded = false;
|
|
357
368
|
this.terminalAssistantCandidateEarlierActiveItemIds = /* @__PURE__ */ new Set();
|
|
358
369
|
this.lastCommentaryProgressEventByItem = /* @__PURE__ */ new Map();
|
|
@@ -416,7 +427,7 @@ var CodexAssistantProjection = class {
|
|
|
416
427
|
});
|
|
417
428
|
if (knownFinalAnswer && !replaceable) await this.params.onPartialReply?.(streamPayload);
|
|
418
429
|
}
|
|
419
|
-
recordItemStarted(item, itemId) {
|
|
430
|
+
async recordItemStarted(item, itemId) {
|
|
420
431
|
this.noteNativeWorkBarrier(item);
|
|
421
432
|
this.rememberAssistantPhase(item);
|
|
422
433
|
if (item?.type === "agentMessage" && itemId && !this.isNonTerminalAssistantItem(itemId) && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
@@ -425,6 +436,10 @@ var CodexAssistantProjection = class {
|
|
|
425
436
|
this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
|
|
426
437
|
if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
427
438
|
}
|
|
439
|
+
if (item?.type === "agentMessage" && itemId && item.text && !this.assistantTextByItem.has(itemId)) await this.handleAssistantDelta({
|
|
440
|
+
itemId,
|
|
441
|
+
delta: item.text
|
|
442
|
+
});
|
|
428
443
|
}
|
|
429
444
|
recordItemCompleted(item, itemId, activeItemIds) {
|
|
430
445
|
if (itemId && item?.type === "agentMessage") this.completedAssistantItemIds.add(itemId);
|
|
@@ -441,7 +456,7 @@ var CodexAssistantProjection = class {
|
|
|
441
456
|
if (item?.type === "agentMessage" && typeof item.text === "string") {
|
|
442
457
|
this.rememberAssistantItem(item.id);
|
|
443
458
|
this.assistantTextByItem.set(item.id, item.text);
|
|
444
|
-
if (
|
|
459
|
+
if (this.isCommentaryAssistantItem(item.id)) {
|
|
445
460
|
this.emitCommentaryProgress({
|
|
446
461
|
itemId: item.id,
|
|
447
462
|
text: item.text,
|
|
@@ -475,15 +490,11 @@ var CodexAssistantProjection = class {
|
|
|
475
490
|
this.pendingRawCommentaryEchoes -= 1;
|
|
476
491
|
return;
|
|
477
492
|
}
|
|
478
|
-
const text = extractRawAssistantText(item);
|
|
479
493
|
if (isPendingTerminalAssistantEcho) {
|
|
480
|
-
const typedItemId = pendingTerminalAssistantEchoItemId;
|
|
481
494
|
this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
482
|
-
if (this.assistantTextByItem.get(typedItemId)?.trim() || !text) return;
|
|
483
|
-
this.rememberAssistantItem(typedItemId);
|
|
484
|
-
this.assistantTextByItem.set(typedItemId, text);
|
|
485
495
|
return;
|
|
486
496
|
}
|
|
497
|
+
const text = extractRawAssistantText(item);
|
|
487
498
|
if (text === void 0 || !text && (phase === "commentary" || activeItemIds.size > 0 || readStringField(item, "type") !== "message")) return;
|
|
488
499
|
const itemId = rawItemId ?? `raw-assistant-${this.assistantItemOrder.length + 1}`;
|
|
489
500
|
const isIdlessTerminalAssistantAfterCompletedWork = candidateWasSupersededBeforeRaw && rawItemId === void 0 && pendingTerminalAssistantEchoItemId === void 0 && activeItemIds.size === 0;
|
|
@@ -528,14 +539,11 @@ var CodexAssistantProjection = class {
|
|
|
528
539
|
}
|
|
529
540
|
collectAsyncMessages() {
|
|
530
541
|
return this.assistantItemOrder.flatMap((itemId) => {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
const timestamp = this.assistantTimestampByItem.get(itemId);
|
|
534
|
-
if (!text || timestamp === void 0) return [];
|
|
535
|
-
return [{
|
|
542
|
+
const delivery = this.createAsyncDelivery(itemId);
|
|
543
|
+
return delivery ? [{
|
|
536
544
|
itemId,
|
|
537
|
-
message:
|
|
538
|
-
}];
|
|
545
|
+
message: delivery.message
|
|
546
|
+
}] : [];
|
|
539
547
|
});
|
|
540
548
|
}
|
|
541
549
|
collectCompletedAssistantMessages(completedItemIds, options) {
|
|
@@ -616,6 +624,11 @@ var CodexAssistantProjection = class {
|
|
|
616
624
|
if (phase) this.assistantPhaseByItem.set(item.id, phase);
|
|
617
625
|
const delivery = readItemString(item, "delivery");
|
|
618
626
|
if (delivery) this.assistantDeliveryByItem.set(item.id, delivery);
|
|
627
|
+
if (item.questions !== void 0) {
|
|
628
|
+
const questions = readCodexAsyncQuestions(item.questions);
|
|
629
|
+
if (questions && delivery === "async") this.assistantQuestionsByItem.set(item.id, questions);
|
|
630
|
+
else this.assistantQuestionsByItem.delete(item.id);
|
|
631
|
+
}
|
|
619
632
|
}
|
|
620
633
|
isCommentaryAssistantItem(itemId) {
|
|
621
634
|
return this.assistantPhaseByItem.get(itemId) === "commentary";
|
|
@@ -755,7 +768,7 @@ var CodexAssistantProjection = class {
|
|
|
755
768
|
if (!text?.trim() || timestamp === void 0) return;
|
|
756
769
|
return {
|
|
757
770
|
itemId,
|
|
758
|
-
message: createAssistantAsyncMessage(this.params, text, itemId, timestamp),
|
|
771
|
+
message: createAssistantAsyncMessage(this.params, text, itemId, timestamp, this.assistantQuestionsByItem.get(itemId)),
|
|
759
772
|
text
|
|
760
773
|
};
|
|
761
774
|
}
|
|
@@ -808,7 +821,7 @@ var CodexGeneratedMediaProjection = class {
|
|
|
808
821
|
this.config = config;
|
|
809
822
|
this.remote = remote;
|
|
810
823
|
this.itemIds = /* @__PURE__ */ new Set();
|
|
811
|
-
this.
|
|
824
|
+
this.mediaByItemId = /* @__PURE__ */ new Map();
|
|
812
825
|
this.gatewayMaterializedItemIds = /* @__PURE__ */ new Set();
|
|
813
826
|
this.pendingMaterializationsByItemId = /* @__PURE__ */ new Map();
|
|
814
827
|
}
|
|
@@ -818,6 +831,11 @@ var CodexGeneratedMediaProjection = class {
|
|
|
818
831
|
async recordNative(item) {
|
|
819
832
|
if (item?.type !== "imageGeneration") return;
|
|
820
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
|
+
});
|
|
821
839
|
const result = readItemString(item, "result");
|
|
822
840
|
if (result) {
|
|
823
841
|
await this.recordImage({
|
|
@@ -828,7 +846,6 @@ var CodexGeneratedMediaProjection = class {
|
|
|
828
846
|
});
|
|
829
847
|
return;
|
|
830
848
|
}
|
|
831
|
-
const savedPath = readItemString(item, "savedPath")?.trim();
|
|
832
849
|
if (savedPath) {
|
|
833
850
|
if (this.remote?.remoteWorkspaceRoot) {
|
|
834
851
|
if (!this.remote.readFile) {
|
|
@@ -929,22 +946,53 @@ var CodexGeneratedMediaProjection = class {
|
|
|
929
946
|
});
|
|
930
947
|
}
|
|
931
948
|
}
|
|
932
|
-
|
|
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
|
+
}
|
|
933
971
|
const mediaUrls = new Set(params.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []);
|
|
934
|
-
|
|
935
|
-
return
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
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
|
+
};
|
|
941
985
|
}
|
|
942
986
|
recordUrl(params) {
|
|
943
|
-
|
|
987
|
+
const existing = this.mediaByItemId.get(params.itemId);
|
|
988
|
+
if (existing?.mediaUrl && params.replaceExisting !== true) {
|
|
944
989
|
this.itemIds.add(params.itemId);
|
|
945
990
|
return;
|
|
946
991
|
}
|
|
947
|
-
this.
|
|
992
|
+
this.mediaByItemId.set(params.itemId, {
|
|
993
|
+
...existing,
|
|
994
|
+
mediaUrl: params.mediaUrl
|
|
995
|
+
});
|
|
948
996
|
this.itemIds.add(params.itemId);
|
|
949
997
|
}
|
|
950
998
|
};
|
|
@@ -974,8 +1022,7 @@ var CodexReasoningProjection = class {
|
|
|
974
1022
|
this.params = params;
|
|
975
1023
|
this.emitAgentEvent = emitAgentEvent;
|
|
976
1024
|
this.onNativePlanUpdate = onNativePlanUpdate;
|
|
977
|
-
this.
|
|
978
|
-
this.reasoningItemOrder = /* @__PURE__ */ new Map();
|
|
1025
|
+
this.reasoningTextByItem = /* @__PURE__ */ new Map();
|
|
979
1026
|
this.planTextByItem = /* @__PURE__ */ new Map();
|
|
980
1027
|
this.reasoningStarted = false;
|
|
981
1028
|
this.reasoningEnded = false;
|
|
@@ -985,16 +1032,14 @@ var CodexReasoningProjection = class {
|
|
|
985
1032
|
const delta = readStringField(params, "delta") ?? "";
|
|
986
1033
|
if (!delta) return;
|
|
987
1034
|
this.reasoningStarted = true;
|
|
988
|
-
|
|
1035
|
+
const item = this.reasoningTextByItem.get(itemId) ?? {
|
|
1036
|
+
summary: /* @__PURE__ */ new Map(),
|
|
1037
|
+
content: /* @__PURE__ */ new Map()
|
|
1038
|
+
};
|
|
1039
|
+
this.reasoningTextByItem.set(itemId, item);
|
|
989
1040
|
const groupIndex = method === "item/reasoning/textDelta" ? readNonNegativeInteger(params, "contentIndex") ?? 0 : readNonNegativeInteger(params, "summaryIndex") ?? 0;
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
this.reasoningTextByGroup.set(groupKey, {
|
|
993
|
-
itemId,
|
|
994
|
-
method,
|
|
995
|
-
index: groupIndex,
|
|
996
|
-
text: `${current?.text ?? ""}${delta}`
|
|
997
|
-
});
|
|
1041
|
+
const sections = method === "item/reasoning/textDelta" ? item.content : item.summary;
|
|
1042
|
+
sections.set(groupIndex, `${sections.get(groupIndex) ?? ""}${delta}`);
|
|
998
1043
|
await this.params.onReasoningStream?.({
|
|
999
1044
|
text: this.reasoningText(),
|
|
1000
1045
|
isReasoningSnapshot: true
|
|
@@ -1034,10 +1079,27 @@ var CodexReasoningProjection = class {
|
|
|
1034
1079
|
});
|
|
1035
1080
|
this.emitPlanUpdate({
|
|
1036
1081
|
explanation,
|
|
1082
|
+
...params.explanationFormat === "plain" ? { explanationFormat: "plain" } : {},
|
|
1037
1083
|
steps: plan
|
|
1038
1084
|
}, source);
|
|
1039
1085
|
}
|
|
1040
|
-
recordItem(item) {
|
|
1086
|
+
async recordItem(item) {
|
|
1087
|
+
if (item?.type === "reasoning") {
|
|
1088
|
+
const previousText = this.reasoningText();
|
|
1089
|
+
this.reasoningTextByItem.set(item.id, {
|
|
1090
|
+
summary: readReasoningSections(item.summary),
|
|
1091
|
+
content: readReasoningSections(item.content)
|
|
1092
|
+
});
|
|
1093
|
+
const text = this.reasoningText();
|
|
1094
|
+
if (text !== previousText) {
|
|
1095
|
+
this.reasoningStarted = true;
|
|
1096
|
+
await this.params.onReasoningStream?.({
|
|
1097
|
+
text,
|
|
1098
|
+
isReasoningSnapshot: true
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1041
1103
|
if (item?.type === "plan" && typeof item.text === "string" && item.text) {
|
|
1042
1104
|
this.planTextByItem.set(item.id, item.text);
|
|
1043
1105
|
this.emitPlanUpdate({
|
|
@@ -1055,7 +1117,7 @@ var CodexReasoningProjection = class {
|
|
|
1055
1117
|
await this.params.onReasoningEnd?.();
|
|
1056
1118
|
}
|
|
1057
1119
|
reasoningText() {
|
|
1058
|
-
return
|
|
1120
|
+
return [...this.reasoningTextByItem.values()].flatMap(({ summary, content }) => [summary, content]).flatMap((sections) => [...sections].toSorted(([left], [right]) => left - right)).map(([, text]) => text).filter((text) => text.trim().length > 0).join("\n\n");
|
|
1059
1121
|
}
|
|
1060
1122
|
planText() {
|
|
1061
1123
|
return this.turnPlanText ?? [...this.planTextByItem.values()].filter((text) => text.trim().length > 0).join("\n\n");
|
|
@@ -1069,6 +1131,7 @@ var CodexReasoningProjection = class {
|
|
|
1069
1131
|
title: "Plan updated",
|
|
1070
1132
|
source,
|
|
1071
1133
|
...params.explanation ? { explanation: params.explanation } : {},
|
|
1134
|
+
...params.explanationFormat ? { explanationFormat: params.explanationFormat } : {},
|
|
1072
1135
|
...params.steps ? { steps: params.steps } : {}
|
|
1073
1136
|
}
|
|
1074
1137
|
});
|
|
@@ -1078,16 +1141,12 @@ function normalizePlanStepStatus(status) {
|
|
|
1078
1141
|
if (status === "inProgress" || status === "in_progress") return "in_progress";
|
|
1079
1142
|
return status === "completed" ? "completed" : "pending";
|
|
1080
1143
|
}
|
|
1081
|
-
function
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
if (
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
}).map((group) => group.text).filter((text) => text.trim().length > 0);
|
|
1088
|
-
}
|
|
1089
|
-
function reasoningMethodOrder(method) {
|
|
1090
|
-
return method === "item/reasoning/summaryTextDelta" ? 0 : 1;
|
|
1144
|
+
function readReasoningSections(value) {
|
|
1145
|
+
const sections = /* @__PURE__ */ new Map();
|
|
1146
|
+
if (Array.isArray(value)) value.forEach((text, index) => {
|
|
1147
|
+
if (typeof text === "string") sections.set(index, text);
|
|
1148
|
+
});
|
|
1149
|
+
return sections;
|
|
1091
1150
|
}
|
|
1092
1151
|
//#endregion
|
|
1093
1152
|
//#region extensions/codex/src/app-server/event-projector-settlement.ts
|
|
@@ -1156,7 +1215,8 @@ function buildCodexMessagesSnapshot(params) {
|
|
|
1156
1215
|
...commentaryMessages,
|
|
1157
1216
|
...asyncMessages,
|
|
1158
1217
|
...(params.assistantMessages ?? []).map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:assistant:${itemId}`)),
|
|
1159
|
-
...params.toolMessages
|
|
1218
|
+
...params.toolMessages,
|
|
1219
|
+
...params.steeringMessages ?? []
|
|
1160
1220
|
].toSorted((left, right) => (asDateTimestampMs(left.timestamp) ?? 0) - (asDateTimestampMs(right.timestamp) ?? 0));
|
|
1161
1221
|
messages.push(...visibleWorkMessages);
|
|
1162
1222
|
if (params.lastAssistant) {
|
|
@@ -1166,6 +1226,7 @@ function buildCodexMessagesSnapshot(params) {
|
|
|
1166
1226
|
const taint = { tainted: false };
|
|
1167
1227
|
return messages.map((message) => projectAgentHarnessTranscriptMessageForDisplay({
|
|
1168
1228
|
hidden: params.runParams.trigger === "memory",
|
|
1229
|
+
inputProvenance: params.runParams.inputProvenance,
|
|
1169
1230
|
message: applyCodexTranscriptTaint(message, taint)
|
|
1170
1231
|
}));
|
|
1171
1232
|
}
|
|
@@ -1193,171 +1254,14 @@ function buildCodexSteeringMessagesSnapshot(params) {
|
|
|
1193
1254
|
};
|
|
1194
1255
|
}
|
|
1195
1256
|
//#endregion
|
|
1196
|
-
//#region extensions/codex/src/app-server/usage-limit-error.ts
|
|
1197
|
-
/**
|
|
1198
|
-
* Enriches Codex usage-limit failures with current rate-limit information and
|
|
1199
|
-
* marks blocked auth profiles when Codex exposes a reset time.
|
|
1200
|
-
*/
|
|
1201
|
-
const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
|
|
1202
|
-
var CodexUsageLimitPromptError = class extends Error {
|
|
1203
|
-
constructor(..._args) {
|
|
1204
|
-
super(..._args);
|
|
1205
|
-
this.status = 429;
|
|
1206
|
-
}
|
|
1207
|
-
};
|
|
1208
|
-
function resolveCodexPromptError(source) {
|
|
1209
|
-
const usageLimitMessage = formatCodexUsageLimitErrorMessage(source);
|
|
1210
|
-
if (usageLimitMessage) return new CodexUsageLimitPromptError(usageLimitMessage);
|
|
1211
|
-
const info = source.codexErrorInfo;
|
|
1212
|
-
let status = info === "rateLimitExceeded" ? 429 : info === "serverOverloaded" ? 503 : info === "internalServerError" ? 500 : void 0;
|
|
1213
|
-
if (isJsonObject(info)) for (const variant of [
|
|
1214
|
-
"httpConnectionFailed",
|
|
1215
|
-
"responseStreamConnectionFailed",
|
|
1216
|
-
"responseStreamDisconnected",
|
|
1217
|
-
"responseTooManyFailedAttempts"
|
|
1218
|
-
]) {
|
|
1219
|
-
const detail = info[variant];
|
|
1220
|
-
if (isJsonObject(detail) && typeof detail.httpStatusCode === "number") {
|
|
1221
|
-
status = detail.httpStatusCode;
|
|
1222
|
-
break;
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
return status === void 0 ? source.message ?? void 0 : Object.assign(new Error(source.message ?? "codex app-server error"), {
|
|
1226
|
-
status,
|
|
1227
|
-
...info === "serverOverloaded" ? { code: "OVERLOADED" } : {}
|
|
1228
|
-
});
|
|
1229
|
-
}
|
|
1230
|
-
/** Marks a Codex auth profile blocked until the reset time advertised by rate limits. */
|
|
1231
|
-
async function markCodexAuthProfileBlockedFromRateLimits(params) {
|
|
1232
|
-
const authProfileId = params.authProfileId?.trim();
|
|
1233
|
-
if (!authProfileId || !params.params.authProfileStore) return;
|
|
1234
|
-
const blockedUntil = resolveCodexUsageLimitResetAtMs(params.rateLimits);
|
|
1235
|
-
if (!blockedUntil) return;
|
|
1236
|
-
try {
|
|
1237
|
-
await markAuthProfileBlockedUntil({
|
|
1238
|
-
store: params.params.authProfileStore,
|
|
1239
|
-
profileId: authProfileId,
|
|
1240
|
-
blockedUntil,
|
|
1241
|
-
source: "codex_rate_limits",
|
|
1242
|
-
agentDir: params.params.agentDir,
|
|
1243
|
-
runId: params.params.runId,
|
|
1244
|
-
modelId: params.params.modelId
|
|
1245
|
-
});
|
|
1246
|
-
} catch (error) {
|
|
1247
|
-
embeddedAgentLog.debug("failed to mark Codex auth profile blocked from app-server limits", {
|
|
1248
|
-
authProfileId,
|
|
1249
|
-
error: formatErrorMessage(error)
|
|
1250
|
-
});
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
/** Formats a turn-start usage-limit error, refreshing rate limits when needed. */
|
|
1254
|
-
async function formatCodexTurnStartUsageLimitError(params) {
|
|
1255
|
-
return refreshCodexUsageLimitError({
|
|
1256
|
-
client: params.client,
|
|
1257
|
-
source: readCodexTurnStartUsageLimitErrorSource(params.client, params.error, params.errorNotification, params.rateLimitsRevisionBeforeTurnStart),
|
|
1258
|
-
timeoutMs: params.timeoutMs,
|
|
1259
|
-
signal: params.signal
|
|
1260
|
-
});
|
|
1261
|
-
}
|
|
1262
|
-
/** Refreshes a generic prompt usage-limit message into a reset-aware message. */
|
|
1263
|
-
async function refreshCodexUsageLimitPromptError(params) {
|
|
1264
|
-
if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(params.message)) return;
|
|
1265
|
-
return refreshCodexUsageLimitError({
|
|
1266
|
-
client: params.client,
|
|
1267
|
-
source: {
|
|
1268
|
-
message: params.message,
|
|
1269
|
-
codexErrorInfo: "usageLimitExceeded",
|
|
1270
|
-
rateLimits: readRecentCodexRateLimits(params.client)
|
|
1271
|
-
},
|
|
1272
|
-
timeoutMs: params.timeoutMs,
|
|
1273
|
-
signal: params.signal
|
|
1274
|
-
});
|
|
1275
|
-
}
|
|
1276
|
-
async function refreshCodexUsageLimitError(params) {
|
|
1277
|
-
const initialMessage = formatCodexUsageLimitErrorMessage(params.source);
|
|
1278
|
-
if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(initialMessage)) return initialMessage ? {
|
|
1279
|
-
message: initialMessage,
|
|
1280
|
-
...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
|
|
1281
|
-
} : void 0;
|
|
1282
|
-
const rateLimits = await readCodexRateLimitsFromAppServerForUsageLimitError({
|
|
1283
|
-
client: params.client,
|
|
1284
|
-
timeoutMs: params.timeoutMs,
|
|
1285
|
-
signal: params.signal
|
|
1286
|
-
});
|
|
1287
|
-
if (!rateLimits) return initialMessage ? {
|
|
1288
|
-
message: initialMessage,
|
|
1289
|
-
...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
|
|
1290
|
-
} : void 0;
|
|
1291
|
-
const message = formatCodexUsageLimitErrorMessage({
|
|
1292
|
-
message: params.source.message,
|
|
1293
|
-
codexErrorInfo: params.source.codexErrorInfo,
|
|
1294
|
-
rateLimits,
|
|
1295
|
-
rateLimitsAuthoritative: true
|
|
1296
|
-
}) ?? initialMessage;
|
|
1297
|
-
return message ? {
|
|
1298
|
-
message,
|
|
1299
|
-
rateLimitsForProfile: rateLimits
|
|
1300
|
-
} : void 0;
|
|
1301
|
-
}
|
|
1302
|
-
async function readCodexRateLimitsFromAppServerForUsageLimitError(params) {
|
|
1303
|
-
if (params.signal?.aborted) return;
|
|
1304
|
-
try {
|
|
1305
|
-
const rateLimits = await params.client.request(CODEX_CONTROL_METHODS.rateLimits, void 0, {
|
|
1306
|
-
timeoutMs: resolveCodexUsageLimitRateLimitRefreshTimeoutMs(params.timeoutMs),
|
|
1307
|
-
signal: params.signal
|
|
1308
|
-
});
|
|
1309
|
-
rememberCodexRateLimitsRead(params.client, rateLimits);
|
|
1310
|
-
return rateLimits;
|
|
1311
|
-
} catch (error) {
|
|
1312
|
-
embeddedAgentLog.debug("codex app-server rate-limit refresh failed after usage-limit error", { error: formatErrorMessage(error) });
|
|
1313
|
-
return;
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
function resolveCodexUsageLimitRateLimitRefreshTimeoutMs(timeoutMs) {
|
|
1317
|
-
if (timeoutMs === void 0 || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS;
|
|
1318
|
-
return Math.max(100, Math.min(timeoutMs, CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS));
|
|
1319
|
-
}
|
|
1320
|
-
function readCodexTurnStartUsageLimitErrorSource(client, error, errorNotification, rateLimitsRevisionBeforeTurnStart) {
|
|
1321
|
-
const notificationError = readCodexErrorNotification(errorNotification);
|
|
1322
|
-
const errorPayload = readCodexErrorPayload(error);
|
|
1323
|
-
const rateLimits = errorPayload.rateLimits ?? readRecentCodexRateLimits(client);
|
|
1324
|
-
const cacheUpdatedDuringTurnStart = rateLimitsRevisionBeforeTurnStart !== void 0 && readCodexRateLimitsRevision(client) > rateLimitsRevisionBeforeTurnStart;
|
|
1325
|
-
return {
|
|
1326
|
-
message: notificationError?.message ?? errorPayload.message ?? formatErrorMessage(error),
|
|
1327
|
-
codexErrorInfo: notificationError?.codexErrorInfo ?? errorPayload.codexErrorInfo,
|
|
1328
|
-
rateLimits,
|
|
1329
|
-
rateLimitsTrustedForProfile: errorPayload.rateLimits !== void 0 || cacheUpdatedDuringTurnStart
|
|
1330
|
-
};
|
|
1331
|
-
}
|
|
1332
|
-
function readCodexErrorNotification(notification) {
|
|
1333
|
-
if (notification?.method !== "error" || !isJsonObject(notification.params)) return;
|
|
1334
|
-
const error = notification.params.error;
|
|
1335
|
-
return isJsonObject(error) ? {
|
|
1336
|
-
message: readStringField(error, "message"),
|
|
1337
|
-
codexErrorInfo: error.codexErrorInfo
|
|
1338
|
-
} : void 0;
|
|
1339
|
-
}
|
|
1340
|
-
function readCodexErrorPayload(error) {
|
|
1341
|
-
const message = error instanceof Error ? error.message : void 0;
|
|
1342
|
-
if (!error || typeof error !== "object" || !("data" in error)) return { message };
|
|
1343
|
-
const data = error.data;
|
|
1344
|
-
if (!isJsonObject(data)) return { message };
|
|
1345
|
-
const nestedError = isJsonObject(data.error) ? data.error : data;
|
|
1346
|
-
const rateLimits = nestedError.rateLimits ?? data.rateLimits;
|
|
1347
|
-
return {
|
|
1348
|
-
message: readStringField(nestedError, "message") ?? message,
|
|
1349
|
-
codexErrorInfo: nestedError.codexErrorInfo,
|
|
1350
|
-
rateLimits
|
|
1351
|
-
};
|
|
1352
|
-
}
|
|
1353
|
-
//#endregion
|
|
1354
1257
|
//#region extensions/codex/src/app-server/event-projector-terminal-failure.ts
|
|
1355
1258
|
var CodexTerminalFailureProjection = class {
|
|
1356
1259
|
constructor() {
|
|
1357
1260
|
this.promptErrorSource = null;
|
|
1358
1261
|
}
|
|
1359
1262
|
record(params) {
|
|
1360
|
-
|
|
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;
|
|
1361
1265
|
if (this.providerRefusal) return;
|
|
1362
1266
|
this.promptError = resolveCodexPromptError({
|
|
1363
1267
|
message: params.message,
|
|
@@ -1417,6 +1321,7 @@ var CodexTranscriptCheckpoint = class {
|
|
|
1417
1321
|
const message = entry.read();
|
|
1418
1322
|
return message ? [projectAgentHarnessTranscriptMessageForDisplay({
|
|
1419
1323
|
hidden: this.params.trigger === "memory",
|
|
1324
|
+
inputProvenance: this.params.inputProvenance,
|
|
1420
1325
|
message: applyCodexTranscriptTaint(message, taint)
|
|
1421
1326
|
})] : [];
|
|
1422
1327
|
});
|
|
@@ -1486,7 +1391,7 @@ var CodexTurnProjection = class {
|
|
|
1486
1391
|
trajectoryRecorder: options.trajectoryRecorder,
|
|
1487
1392
|
checkpointMessage: this.transcriptCheckpoint.enqueue
|
|
1488
1393
|
});
|
|
1489
|
-
this.eventProjection = new CodexEventProjection(threadId, turnId, (event) => this.emitAgentEvent(event), this.toolProgressProjection, this.toolTranscriptProjection, options.onNativeToolResultRecorded);
|
|
1394
|
+
this.eventProjection = new CodexEventProjection(params.provider, threadId, turnId, (event) => this.emitAgentEvent(event), this.toolProgressProjection, this.toolTranscriptProjection, options.onNativeToolResultRecorded);
|
|
1490
1395
|
this.assistantProjection = new CodexAssistantProjection(this.settlement.params, (event) => this.emitAgentEvent(event), (text) => this.toolProgressProjection.matchesEcho(text), this.transcriptCheckpoint.nextTimestamp, this.transcriptCheckpoint.enqueueCommentary);
|
|
1491
1396
|
this.reasoningProjection = new CodexReasoningProjection(this.settlement.params, (event) => this.emitAgentEvent(event), options.onNativePlanUpdate);
|
|
1492
1397
|
}
|
|
@@ -1543,6 +1448,7 @@ var CodexTurnProjection = class {
|
|
|
1543
1448
|
asyncMessages,
|
|
1544
1449
|
commentaryMessages,
|
|
1545
1450
|
toolMessages: this.toolTranscriptProjection.transcriptMessages,
|
|
1451
|
+
steeringMessages: options?.steeringMessages,
|
|
1546
1452
|
lastAssistant,
|
|
1547
1453
|
turnTainted
|
|
1548
1454
|
});
|
|
@@ -1557,7 +1463,8 @@ var CodexTurnProjection = class {
|
|
|
1557
1463
|
});
|
|
1558
1464
|
const toolMetas = this.toolProgressProjection.toolMetas;
|
|
1559
1465
|
const hadPotentialSideEffects = toolTelemetry.didSendViaMessagingTool || Boolean(toolTelemetry.successfulCronAdds || toolTelemetry.acceptedSessionSpawns?.length) || this.generatedMediaProjection.hasGeneratedMedia() || this.toolProgressProjection.hasPotentialSideEffects;
|
|
1560
|
-
const
|
|
1466
|
+
const mediaDelivery = this.generatedMediaProjection.projectDelivery(toolTelemetry);
|
|
1467
|
+
const sentMediaUrls = new Set(mediaDelivery.messagingToolSentMediaUrls.map((url) => url.trim()));
|
|
1561
1468
|
const toolAutoDeliveryMediaUrls = toolTelemetry.toolAutoDeliveryMediaUrls?.filter((url) => !sentMediaUrls.has(url.trim()));
|
|
1562
1469
|
const result = {
|
|
1563
1470
|
terminal: attemptTerminal.normalize({
|
|
@@ -1581,12 +1488,9 @@ var CodexTurnProjection = class {
|
|
|
1581
1488
|
didDeliverSourceReplyViaMessageTool: toolTelemetry.didDeliverSourceReplyViaMessageTool === true,
|
|
1582
1489
|
sourceReplyDelivered: toolTelemetry.sourceReplyDelivered,
|
|
1583
1490
|
messagingToolSentTexts: toolTelemetry.messagingToolSentTexts,
|
|
1584
|
-
|
|
1585
|
-
messagingToolSentTargets: toolTelemetry.messagingToolSentTargets,
|
|
1491
|
+
...mediaDelivery,
|
|
1586
1492
|
messagingToolSourceReplyPayloads: toolTelemetry.messagingToolSourceReplyPayloads ?? [],
|
|
1587
1493
|
heartbeatToolResponse: toolTelemetry.heartbeatToolResponse,
|
|
1588
|
-
toolMediaUrls: this.generatedMediaProjection.buildToolMediaUrls(toolTelemetry),
|
|
1589
|
-
hostOwnedToolMediaUrls: this.generatedMediaProjection.buildHostOwnedMediaUrls(toolTelemetry),
|
|
1590
1494
|
toolAudioAsVoice: toolTelemetry.toolAudioAsVoice,
|
|
1591
1495
|
successfulCronAdds: toolTelemetry.successfulCronAdds,
|
|
1592
1496
|
acceptedSessionSpawns: toolTelemetry.acceptedSessionSpawns,
|
|
@@ -1617,6 +1521,7 @@ var CodexTurnProjection = class {
|
|
|
1617
1521
|
};
|
|
1618
1522
|
//#endregion
|
|
1619
1523
|
//#region extensions/codex/src/app-server/event-projector.ts
|
|
1524
|
+
const optedOutNotificationMethods = new Set(CODEX_APP_SERVER_OPT_OUT_NOTIFICATION_METHODS);
|
|
1620
1525
|
var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
1621
1526
|
getCompletedTurnStatus() {
|
|
1622
1527
|
return this.completedTurn?.status;
|
|
@@ -1689,6 +1594,7 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
|
1689
1594
|
this.assistantProjection.handleNotification(notification.method, params);
|
|
1690
1595
|
switch (notification.method) {
|
|
1691
1596
|
case "item/agentMessage/delta":
|
|
1597
|
+
if (readStringField(params, "delta")) this.eventProjection.markSafetyBufferingAssistantStarted();
|
|
1692
1598
|
await this.assistantProjection.handleAssistantDelta(params);
|
|
1693
1599
|
break;
|
|
1694
1600
|
case "item/reasoning/summaryTextDelta":
|
|
@@ -1752,6 +1658,9 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
|
1752
1658
|
case "model/rerouted":
|
|
1753
1659
|
this.eventProjection.handleModelRerouted(params);
|
|
1754
1660
|
break;
|
|
1661
|
+
case "model/safetyBuffering/updated":
|
|
1662
|
+
this.eventProjection.handleSafetyBuffering(params);
|
|
1663
|
+
break;
|
|
1755
1664
|
case "error": {
|
|
1756
1665
|
this.usageProjection.invalidateContext();
|
|
1757
1666
|
if (params.willRetry === true) {
|
|
@@ -1759,29 +1668,29 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
|
1759
1668
|
break;
|
|
1760
1669
|
}
|
|
1761
1670
|
const codexErrorInfo = isJsonObject(params.error) ? params.error.codexErrorInfo : void 0;
|
|
1671
|
+
this.eventProjection.handleCyberPolicyError(codexErrorInfo, this.params.modelId);
|
|
1762
1672
|
const compactionFailure = codexErrorInfo === "other" && this.isCompacting();
|
|
1763
1673
|
this.settledTurnFailureFinalizationAllowed = codexErrorInfo === "serverOverloaded" || compactionFailure;
|
|
1764
1674
|
this.terminalFailure.record({
|
|
1765
1675
|
message: readCodexErrorNotificationMessage(params),
|
|
1766
1676
|
codexErrorInfo,
|
|
1677
|
+
misalignment: isJsonObject(params.error) ? params.error.misalignment : void 0,
|
|
1678
|
+
nativeThreadId: this.threadId,
|
|
1679
|
+
nativeTurnId: this.turnId,
|
|
1767
1680
|
rateLimits: this.options.readRecentRateLimits?.(),
|
|
1768
1681
|
fallbackMessage: "codex app-server error",
|
|
1769
1682
|
promptErrorSource: compactionFailure ? "compaction" : "prompt"
|
|
1770
1683
|
});
|
|
1771
1684
|
break;
|
|
1772
1685
|
}
|
|
1773
|
-
case "thread/compacted":
|
|
1774
1686
|
case "turn/started":
|
|
1775
|
-
case "turn/diff/updated":
|
|
1776
1687
|
case "item/reasoning/summaryPartAdded":
|
|
1777
1688
|
case "item/commandExecution/terminalInteraction":
|
|
1778
|
-
case "item/fileChange/outputDelta":
|
|
1779
1689
|
case "item/fileChange/patchUpdated":
|
|
1780
1690
|
case "item/mcpToolCall/progress":
|
|
1781
1691
|
case "model/verification":
|
|
1782
|
-
case "turn/moderationMetadata":
|
|
1783
|
-
|
|
1784
|
-
default: this.diagnostics.warnUnknownEvent(notification, params);
|
|
1692
|
+
case "turn/moderationMetadata": break;
|
|
1693
|
+
default: if (!optedOutNotificationMethods.has(notification.method)) this.diagnostics.warnUnknownEvent(notification, params);
|
|
1785
1694
|
}
|
|
1786
1695
|
if (!this.projectionClosed && [
|
|
1787
1696
|
"item/started",
|
|
@@ -1789,6 +1698,23 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
|
1789
1698
|
"rawResponseItem/completed"
|
|
1790
1699
|
].includes(notification.method)) await this.settlement.project("transcript/checkpoint", () => this.transcriptCheckpoint.flush());
|
|
1791
1700
|
}
|
|
1701
|
+
recordUserInputResponse(params) {
|
|
1702
|
+
if (this.projectionClosed) return;
|
|
1703
|
+
this.toolTranscriptProjection.recordToolCall({
|
|
1704
|
+
id: params.itemId,
|
|
1705
|
+
name: "request_user_input",
|
|
1706
|
+
arguments: { questions: params.questions }
|
|
1707
|
+
});
|
|
1708
|
+
this.toolTranscriptProjection.recordToolResult({
|
|
1709
|
+
id: params.itemId,
|
|
1710
|
+
name: "request_user_input",
|
|
1711
|
+
text: JSON.stringify({
|
|
1712
|
+
response: params.response,
|
|
1713
|
+
request: { questions: params.questions }
|
|
1714
|
+
}),
|
|
1715
|
+
isError: false
|
|
1716
|
+
});
|
|
1717
|
+
}
|
|
1792
1718
|
recordDynamicToolCall(params) {
|
|
1793
1719
|
this.toolTranscriptProjection.recordDynamicToolCall(params);
|
|
1794
1720
|
}
|
|
@@ -1798,7 +1724,8 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
|
1798
1724
|
if (update) {
|
|
1799
1725
|
const projected = {
|
|
1800
1726
|
plan: update.steps,
|
|
1801
|
-
...update.explanation ? { explanation: update.explanation } : {}
|
|
1727
|
+
...update.explanation ? { explanation: update.explanation } : {},
|
|
1728
|
+
...update.explanationFormat ? { explanationFormat: update.explanationFormat } : {}
|
|
1802
1729
|
};
|
|
1803
1730
|
await this.reasoningProjection.handleTurnPlanUpdated(projected, "openclaw");
|
|
1804
1731
|
}
|
|
@@ -1825,8 +1752,9 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
|
1825
1752
|
}
|
|
1826
1753
|
async handleItemStarted(params) {
|
|
1827
1754
|
const item = readItem(params.item);
|
|
1755
|
+
if (item?.type === "agentMessage" && item.text) this.eventProjection.markSafetyBufferingAssistantStarted();
|
|
1828
1756
|
const itemId = item?.id ?? readStringField(params, "itemId");
|
|
1829
|
-
this.assistantProjection.recordItemStarted(item, itemId);
|
|
1757
|
+
await this.assistantProjection.recordItemStarted(item, itemId);
|
|
1830
1758
|
if (itemId) this.activeItemIds.add(itemId);
|
|
1831
1759
|
this.recordNativeToolOutcome(item);
|
|
1832
1760
|
if (item?.type === "contextCompaction" && itemId) {
|
|
@@ -1874,10 +1802,12 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
|
1874
1802
|
}
|
|
1875
1803
|
async handleItemCompleted(params) {
|
|
1876
1804
|
const item = readItem(params.item);
|
|
1805
|
+
const itemId = item?.id ?? readStringField(params, "itemId");
|
|
1806
|
+
if (item?.type === "contextCompaction" && itemId && this.completedItemIds.has(itemId)) return;
|
|
1807
|
+
if (item?.type === "agentMessage" && item.text) this.eventProjection.markSafetyBufferingAssistantStarted();
|
|
1877
1808
|
this.diagnostics.warnUnknownItemStatus(item);
|
|
1878
1809
|
this.recordNativeToolOutcome(item);
|
|
1879
1810
|
this.nativeToolLifecycleProjector.clearTerminalPresentationForNativeItem(item);
|
|
1880
|
-
const itemId = item?.id ?? readStringField(params, "itemId");
|
|
1881
1811
|
if (itemId) {
|
|
1882
1812
|
this.activeItemIds.delete(itemId);
|
|
1883
1813
|
this.completedItemIds.add(itemId);
|
|
@@ -1886,7 +1816,7 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
|
1886
1816
|
const asyncMessage = this.assistantProjection.recordItemCompleted(item, itemId, this.activeItemIds);
|
|
1887
1817
|
if (asyncMessage) await this.asyncDeliveryProjection.deliver(asyncMessage);
|
|
1888
1818
|
if (this.projectionClosed) return;
|
|
1889
|
-
this.reasoningProjection.recordItem(item);
|
|
1819
|
+
await this.reasoningProjection.recordItem(item);
|
|
1890
1820
|
await this.settlement.project("media_projection", () => this.generatedMediaProjection.recordNative(item));
|
|
1891
1821
|
if (this.projectionClosed) return;
|
|
1892
1822
|
if (item?.type === "contextCompaction" && itemId) {
|
|
@@ -1944,17 +1874,22 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
|
1944
1874
|
});
|
|
1945
1875
|
}
|
|
1946
1876
|
async handleTurnCompleted(params) {
|
|
1947
|
-
const turn =
|
|
1877
|
+
const turn = readCodexTurnCompletedNotification(params)?.turn;
|
|
1948
1878
|
if (!turn || turn.id !== this.turnId) return;
|
|
1949
1879
|
this.completedTurn = turn;
|
|
1880
|
+
this.eventProjection.endSafetyBuffering();
|
|
1950
1881
|
const compactionFailure = turn.status === "failed" && (this.terminalFailure.promptErrorSource === "compaction" || turn.error?.codexErrorInfo === "other" && this.isCompacting());
|
|
1951
1882
|
this.settledTurnFailureFinalizationAllowed = turn.status === "failed" && (turn.error?.codexErrorInfo === "serverOverloaded" || compactionFailure);
|
|
1952
1883
|
if (turn.status !== "completed") this.usageProjection.invalidateContext();
|
|
1953
1884
|
if (turn.status === "failed") {
|
|
1954
1885
|
const codexErrorInfo = turn.error?.codexErrorInfo;
|
|
1886
|
+
this.eventProjection.handleCyberPolicyError(codexErrorInfo, this.params.modelId);
|
|
1955
1887
|
this.terminalFailure.record({
|
|
1956
1888
|
message: turn.error?.message,
|
|
1957
1889
|
codexErrorInfo,
|
|
1890
|
+
misalignment: turn.error?.misalignment,
|
|
1891
|
+
nativeThreadId: this.threadId,
|
|
1892
|
+
nativeTurnId: this.turnId,
|
|
1958
1893
|
rateLimits: this.options.readRecentRateLimits?.(),
|
|
1959
1894
|
fallbackMessage: "codex app-server turn failed",
|
|
1960
1895
|
promptErrorSource: compactionFailure ? "compaction" : "prompt"
|
|
@@ -1968,7 +1903,7 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
|
1968
1903
|
this.eventProjection.emitCompactionEnd(itemId, false);
|
|
1969
1904
|
}
|
|
1970
1905
|
}
|
|
1971
|
-
const turnItems = turn.items
|
|
1906
|
+
const turnItems = turn.items;
|
|
1972
1907
|
const unsettledAsyncDeliveries = this.asyncDeliveryProjection.pending();
|
|
1973
1908
|
const lastToolItem = turnItems.findLast((item) => matchesCodexSnapshotTurn(item, this.turnId) && (item.type === "dynamicToolCall" || shouldClearTerminalPresentationForNativeItem(item)));
|
|
1974
1909
|
if (lastToolItem?.type !== "dynamicToolCall") this.nativeToolLifecycleProjector.clearTerminalPresentationForNativeItem(lastToolItem);
|
|
@@ -1978,7 +1913,7 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
|
1978
1913
|
const asyncMessage = this.assistantProjection.recordSnapshotItem(item);
|
|
1979
1914
|
if (asyncMessage) await this.asyncDeliveryProjection.deliver(asyncMessage);
|
|
1980
1915
|
if (this.projectionClosed) return;
|
|
1981
|
-
this.reasoningProjection.recordItem(item);
|
|
1916
|
+
await this.reasoningProjection.recordItem(item);
|
|
1982
1917
|
await this.settlement.project("media_projection", () => this.generatedMediaProjection.recordNative(item));
|
|
1983
1918
|
if (this.projectionClosed) return;
|
|
1984
1919
|
this.toolProgressProjection.recordToolMeta(item);
|
|
@@ -2011,6 +1946,7 @@ var CodexAppServerEventProjector = class extends CodexTurnProjection {
|
|
|
2011
1946
|
async handleRawResponseItemCompleted(params) {
|
|
2012
1947
|
const item = isJsonObject(params.item) ? params.item : void 0;
|
|
2013
1948
|
if (!item) return;
|
|
1949
|
+
if (item.role === "assistant" && extractRawAssistantText(item)) this.eventProjection.markSafetyBufferingAssistantStarted();
|
|
2014
1950
|
this.toolTranscriptProjection.recordRawNativeToolItem(item);
|
|
2015
1951
|
this.assistantProjection.handleRawResponseItemCompleted(item, this.activeItemIds);
|
|
2016
1952
|
await this.settlement.project("media_projection", () => this.generatedMediaProjection.recordRaw(item));
|
|
@@ -2282,50 +2218,31 @@ const MAX_USER_INPUT_HEADER = 64;
|
|
|
2282
2218
|
const MAX_USER_INPUT_TEXT = 4096;
|
|
2283
2219
|
/** Creates the single per-turn owner for Codex operator input. */
|
|
2284
2220
|
function createCodexUserInputBridge(params) {
|
|
2285
|
-
const
|
|
2286
|
-
|
|
2221
|
+
const cleanup = new AbortController();
|
|
2222
|
+
const bridgeSignal = params.signal ? AbortSignal.any([params.signal, cleanup.signal]) : cleanup.signal;
|
|
2223
|
+
let completion = Promise.resolve();
|
|
2287
2224
|
const inputSessionKey = params.paramsForRun.sessionKey ?? params.paramsForRun.sessionId;
|
|
2288
|
-
const
|
|
2289
|
-
const
|
|
2290
|
-
if (
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
resolve
|
|
2308
|
-
});
|
|
2309
|
-
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);
|
|
2310
2244
|
});
|
|
2311
2245
|
};
|
|
2312
|
-
const cancelJob = (job) => {
|
|
2313
|
-
const index = jobs.indexOf(job);
|
|
2314
|
-
if (index < 0) return;
|
|
2315
|
-
if (index === 0) {
|
|
2316
|
-
job.abort.abort(/* @__PURE__ */ new Error("Codex operator input request cancelled"));
|
|
2317
|
-
return;
|
|
2318
|
-
}
|
|
2319
|
-
jobs.splice(index, 1);
|
|
2320
|
-
job.resolve(job.cancelValue);
|
|
2321
|
-
};
|
|
2322
|
-
const cancelPending = async () => {
|
|
2323
|
-
const pendingCompletion = activeCompletion;
|
|
2324
|
-
const queuedJobs = jobs.splice(1);
|
|
2325
|
-
for (const job of queuedJobs) job.resolve(job.cancelValue);
|
|
2326
|
-
jobs[0]?.abort.abort(/* @__PURE__ */ new Error("Codex operator input request cancelled"));
|
|
2327
|
-
await pendingCompletion;
|
|
2328
|
-
};
|
|
2329
2246
|
const execute = (input, timeoutMs, signal) => agentHarnessStructuredInput.run({
|
|
2330
2247
|
input,
|
|
2331
2248
|
sessionKey: inputSessionKey,
|
|
@@ -2341,9 +2258,8 @@ function createCodexUserInputBridge(params) {
|
|
|
2341
2258
|
urlIntro: "Codex needs confirmation:"
|
|
2342
2259
|
}
|
|
2343
2260
|
});
|
|
2344
|
-
params.signal?.addEventListener("abort", () => void cancelPending(), { once: true });
|
|
2345
2261
|
return {
|
|
2346
|
-
async handleRequest(request) {
|
|
2262
|
+
async handleRequest(request, requestSignal) {
|
|
2347
2263
|
const requestParams = readUserInputParams(request.params);
|
|
2348
2264
|
if (!requestParams || requestParams.threadId !== params.threadId || requestParams.turnId !== params.turnId) return;
|
|
2349
2265
|
if (requestParams.questions.length === 0) return emptyUserInputResponse();
|
|
@@ -2351,47 +2267,38 @@ function createCodexUserInputBridge(params) {
|
|
|
2351
2267
|
const input = compileUserInputQuestions(requestParams.questions);
|
|
2352
2268
|
const cancelValue = emptyUserInputResponse();
|
|
2353
2269
|
return await enqueue({
|
|
2354
|
-
requestId: request.id,
|
|
2355
|
-
abort: new AbortController(),
|
|
2356
2270
|
cancelValue,
|
|
2357
2271
|
failureValue: cancelValue,
|
|
2272
|
+
onResponse: requestParams.questions.some((question) => question.isSecret) ? void 0 : (response) => params.onOrdinaryResponse?.({
|
|
2273
|
+
itemId: requestParams.itemId,
|
|
2274
|
+
questions: requestParams.questions,
|
|
2275
|
+
response
|
|
2276
|
+
}),
|
|
2358
2277
|
run: async (signal) => {
|
|
2359
2278
|
const result = await execute(input, timeoutMs, signal);
|
|
2360
2279
|
return result.status === "answered" ? gatewayAnswersToCodexResponse(result.answers) : cancelValue;
|
|
2361
2280
|
}
|
|
2362
|
-
});
|
|
2281
|
+
}, requestSignal);
|
|
2363
2282
|
},
|
|
2364
|
-
async handleElicitationRequest(request) {
|
|
2283
|
+
async handleElicitationRequest(request, requestSignal) {
|
|
2365
2284
|
if (readOwnDataString(request.params, "threadId") !== params.threadId) return;
|
|
2366
2285
|
const requestSnapshot = agentHarnessStructuredInput.snapshot(request.params);
|
|
2367
|
-
if (
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
requestId: request.id,
|
|
2371
|
-
abort: new AbortController(),
|
|
2372
|
-
cancelValue,
|
|
2373
|
-
failureValue: declineElicitation("OpenClaw could not handle this elicitation."),
|
|
2374
|
-
run: async (signal) => {
|
|
2375
|
-
const result = await execute({
|
|
2376
|
-
kind: "unsupported",
|
|
2377
|
-
message: "OpenClaw declined a malformed or over-limit MCP elicitation request."
|
|
2378
|
-
}, params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS, signal);
|
|
2379
|
-
return result.status === "unsupported" ? declineElicitation(result.message) : cancelValue;
|
|
2380
|
-
}
|
|
2381
|
-
});
|
|
2382
|
-
}
|
|
2383
|
-
if (readOwnDataString(requestSnapshot, "threadId") !== params.threadId) return;
|
|
2384
|
-
const { compileCodexOrdinaryElicitation } = await import("./elicitation-input-DPoK8F7w.js");
|
|
2385
|
-
const compiled = compileCodexOrdinaryElicitation({
|
|
2286
|
+
if (agentHarnessStructuredInput.isRecord(requestSnapshot) && readOwnDataString(requestSnapshot, "threadId") !== params.threadId) return;
|
|
2287
|
+
const { compileCodexOrdinaryElicitation } = await import("./elicitation-input-DPoK8F7w.mjs");
|
|
2288
|
+
const compiled = agentHarnessStructuredInput.isRecord(requestSnapshot) ? compileCodexOrdinaryElicitation({
|
|
2386
2289
|
snapshot: requestSnapshot,
|
|
2387
2290
|
turnId: params.turnId
|
|
2388
|
-
})
|
|
2291
|
+
}) : {
|
|
2292
|
+
kind: "compiled",
|
|
2293
|
+
input: {
|
|
2294
|
+
kind: "unsupported",
|
|
2295
|
+
message: "OpenClaw declined a malformed or over-limit MCP elicitation request."
|
|
2296
|
+
}
|
|
2297
|
+
};
|
|
2389
2298
|
if (compiled.kind === "ignored") return;
|
|
2390
2299
|
const cancelValue = createCodexElicitationResponse("cancel");
|
|
2391
2300
|
const timeoutMs = params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS;
|
|
2392
2301
|
return await enqueue({
|
|
2393
|
-
requestId: request.id,
|
|
2394
|
-
abort: new AbortController(),
|
|
2395
2302
|
cancelValue,
|
|
2396
2303
|
failureValue: declineElicitation("OpenClaw could not handle this elicitation."),
|
|
2397
2304
|
run: async (signal) => {
|
|
@@ -2400,20 +2307,15 @@ function createCodexUserInputBridge(params) {
|
|
|
2400
2307
|
const content = compiled.input.kind === "ready" && compiled.input.plan.kind === "url" ? null : result.content;
|
|
2401
2308
|
return createCodexElicitationResponse("accept", content);
|
|
2402
2309
|
}
|
|
2403
|
-
if (result.status === "declined") return declineElicitation(result.message);
|
|
2404
|
-
if (result.status === "unsupported") return declineElicitation(result.message);
|
|
2310
|
+
if (result.status === "declined" || result.status === "unsupported") return declineElicitation(result.message);
|
|
2405
2311
|
return cancelValue;
|
|
2406
2312
|
}
|
|
2407
|
-
});
|
|
2313
|
+
}, requestSignal);
|
|
2408
2314
|
},
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
const job = jobs.find((candidate) => typeof candidate.requestId === typeof requestId && candidate.requestId === requestId);
|
|
2414
|
-
if (job) cancelJob(job);
|
|
2415
|
-
},
|
|
2416
|
-
cancelPending
|
|
2315
|
+
async cancelPending() {
|
|
2316
|
+
cleanup.abort(/* @__PURE__ */ new Error("Codex operator input request cancelled"));
|
|
2317
|
+
await completion;
|
|
2318
|
+
}
|
|
2417
2319
|
};
|
|
2418
2320
|
}
|
|
2419
2321
|
function compileUserInputQuestions(questions) {
|
|
@@ -2439,6 +2341,7 @@ function readUserInputParams(value) {
|
|
|
2439
2341
|
return {
|
|
2440
2342
|
threadId,
|
|
2441
2343
|
turnId,
|
|
2344
|
+
itemId,
|
|
2442
2345
|
questions: parsed,
|
|
2443
2346
|
isBlocking: readValue(snapshot, "isBlocking") !== false
|
|
2444
2347
|
};
|
|
@@ -2493,11 +2396,6 @@ function readOwnDataString(value, key) {
|
|
|
2493
2396
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
2494
2397
|
return descriptor && "value" in descriptor && typeof descriptor.value === "string" ? descriptor.value : void 0;
|
|
2495
2398
|
}
|
|
2496
|
-
function readRequestId(record) {
|
|
2497
|
-
const descriptor = Object.getOwnPropertyDescriptor(record, "requestId");
|
|
2498
|
-
const value = descriptor && "value" in descriptor ? descriptor.value : void 0;
|
|
2499
|
-
return typeof value === "string" || typeof value === "number" ? value : void 0;
|
|
2500
|
-
}
|
|
2501
2399
|
function gatewayAnswersToCodexResponse(answers) {
|
|
2502
2400
|
return { answers: Object.fromEntries(Object.entries(answers).map(([questionId, values]) => [questionId, { answers: values }])) };
|
|
2503
2401
|
}
|
|
@@ -2509,7 +2407,7 @@ function declineElicitation(message) {
|
|
|
2509
2407
|
}
|
|
2510
2408
|
//#endregion
|
|
2511
2409
|
//#region extensions/codex/src/app-server/run-attempt-active-turn.ts
|
|
2512
|
-
function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, turn) {
|
|
2410
|
+
function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, { turn, upstreamUserText }) {
|
|
2513
2411
|
const { prompt, state: resourceState, projectorRef, trajectoryRecorder, pendingNativePreToolUseFailures } = resources;
|
|
2514
2412
|
const { context, turnState } = prompt;
|
|
2515
2413
|
const { runtime, attemptTools, hookContext } = context;
|
|
@@ -2536,6 +2434,31 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
|
|
|
2536
2434
|
provider: runtimeModelSelection.provider
|
|
2537
2435
|
}
|
|
2538
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;
|
|
2539
2462
|
const progressCardTool = toolBridge.availableTools.find((tool) => tool.name === "progress_card");
|
|
2540
2463
|
let nativePlanUpdateOrdinal = 0;
|
|
2541
2464
|
const prepareNativeMcpAppResultDetails = createCodexNativeMcpAppResultDetailsPreparer({
|
|
@@ -2547,19 +2470,6 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
|
|
|
2547
2470
|
eventEmitted: false,
|
|
2548
2471
|
needsTerminalSnapshot: false
|
|
2549
2472
|
};
|
|
2550
|
-
emitExecutionPhaseOnce("turn_accepted", { phase: "turn_accepted" });
|
|
2551
|
-
userInputBridgeRef.current = createCodexUserInputBridge({
|
|
2552
|
-
paramsForRun: params,
|
|
2553
|
-
threadId: resourceState.thread.threadId,
|
|
2554
|
-
turnId: activeTurnId,
|
|
2555
|
-
signal: runAbortController.signal
|
|
2556
|
-
});
|
|
2557
|
-
trajectoryRecorder?.recordEvent("prompt.submitted", {
|
|
2558
|
-
threadId: resourceState.thread.threadId,
|
|
2559
|
-
turnId: activeTurnId,
|
|
2560
|
-
prompt: turnState.codexTurnPromptText,
|
|
2561
|
-
imagesCount: params.images?.length ?? 0
|
|
2562
|
-
});
|
|
2563
2473
|
projectorRef.current = new CodexAppServerEventProjector({
|
|
2564
2474
|
...projectionParams,
|
|
2565
2475
|
onAgentEvent: (event) => {
|
|
@@ -2576,7 +2486,17 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
|
|
|
2576
2486
|
asyncUserMessageAllowed: params.disableTools !== true && (params.toolsAllow === void 0 || toolBridge.availableTools.some((tool) => tool.name === "message")),
|
|
2577
2487
|
onAsyncDelivery: async (delivery) => {
|
|
2578
2488
|
return await codexTranscriptMirrorRuntime.deliverAsyncMessageBestEffort({
|
|
2579
|
-
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,
|
|
2580
2500
|
cwd: effectiveCwd,
|
|
2581
2501
|
threadId: resourceState.thread.threadId,
|
|
2582
2502
|
turnId: activeTurnId,
|
|
@@ -2587,9 +2507,9 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
|
|
|
2587
2507
|
runAbortSignal: runAbortController.signal,
|
|
2588
2508
|
remoteWorkspaceRoot: connection.appServer.remoteWorkspaceRoot,
|
|
2589
2509
|
remoteWorkspaceRequestTimeoutMs: connection.appServer.requestTimeoutMs,
|
|
2590
|
-
readRemoteWorkspaceFile: ({ path, maxBytes, signal, timeoutMs }) => readBoundedCodexRemoteWorkspaceFile({
|
|
2510
|
+
readRemoteWorkspaceFile: ({ path: remotePath, maxBytes, signal, timeoutMs }) => readBoundedCodexRemoteWorkspaceFile({
|
|
2591
2511
|
client: resourceState.client,
|
|
2592
|
-
path,
|
|
2512
|
+
path: remotePath,
|
|
2593
2513
|
maxBytes,
|
|
2594
2514
|
signal,
|
|
2595
2515
|
timeoutMs
|
|
@@ -2611,7 +2531,7 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
|
|
|
2611
2531
|
}
|
|
2612
2532
|
} } : {},
|
|
2613
2533
|
...prepareNativeMcpAppResultDetails ? { prepareNativeMcpAppResultDetails } : {},
|
|
2614
|
-
upstreamUserText
|
|
2534
|
+
upstreamUserText,
|
|
2615
2535
|
onContextCompacted: async () => {
|
|
2616
2536
|
computerContextEpoch.value += 1;
|
|
2617
2537
|
delete computerContextEpoch.frameToolCallId;
|
|
@@ -2632,19 +2552,14 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
|
|
|
2632
2552
|
}
|
|
2633
2553
|
}
|
|
2634
2554
|
});
|
|
2635
|
-
if (isTerminalTurnStatus(turn.turn.status)) {
|
|
2636
|
-
projectorRef.current.settlement.terminalReceipt = turn.turn;
|
|
2637
|
-
state.terminalTurnNotificationQueued = true;
|
|
2638
|
-
deadlines.beginSettlement(Date.now());
|
|
2639
|
-
}
|
|
2640
|
-
emitLifecycleStart();
|
|
2641
2555
|
const activeProjector = projectorRef.current;
|
|
2642
|
-
|
|
2556
|
+
let activationFailed = false;
|
|
2643
2557
|
const abortListener = () => {
|
|
2644
2558
|
state.abortCleanup = interruptTurn(activeTurnId).then(async (confirmed) => {
|
|
2645
|
-
if (!terminalState.explicitCancellationObserved && !state.permissionChangeRestart && !state.timeout) return;
|
|
2559
|
+
if (!activationFailed && !terminalState.explicitCancellationObserved && !state.permissionChangeRestart && !state.timeout) return;
|
|
2646
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.");
|
|
2647
|
-
await
|
|
2561
|
+
if (resources.nativeProcessAuthority) await resources.nativeProcessAuthority.cancelTurn(resourceState.client, resourceState.thread.threadId, activeTurnId);
|
|
2562
|
+
else await terminateCodexBackgroundTerminals(resourceState.client, resourceState.thread.threadId);
|
|
2648
2563
|
if (state.permissionChangeRestart) state.permissionChangeRestart = "confirmed";
|
|
2649
2564
|
});
|
|
2650
2565
|
state.abortCleanup.then(completeTurn, (error) => {
|
|
@@ -2652,32 +2567,18 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
|
|
|
2652
2567
|
completeTurn();
|
|
2653
2568
|
});
|
|
2654
2569
|
};
|
|
2655
|
-
runAbortController.signal.addEventListener("abort", abortListener, { once: true });
|
|
2656
|
-
if (runAbortController.signal.aborted) abortListener();
|
|
2657
|
-
for (const failure of pendingNativePreToolUseFailures.splice(0)) activeProjector.recordNativeToolPreToolUseFailure(failure);
|
|
2658
2570
|
const notifyUserMessagePersisted = createCodexAppServerUserMessagePersistenceNotifier(params);
|
|
2659
|
-
const
|
|
2660
|
-
params,
|
|
2661
|
-
agentId: sessionAgentId,
|
|
2662
|
-
notifyUserMessagePersisted,
|
|
2663
|
-
sessionKey: contextSessionKey,
|
|
2664
|
-
cwd: effectiveCwd,
|
|
2665
|
-
threadId: resourceState.thread.threadId,
|
|
2666
|
-
turnId: activeTurnId,
|
|
2667
|
-
upstreamUserText: turnState.codexTurnPromptText
|
|
2668
|
-
});
|
|
2669
|
-
const bindProjection = async () => {
|
|
2571
|
+
const bindProjection = async (promptMirrorPromise) => {
|
|
2670
2572
|
state.activeLocalProjections += 1;
|
|
2671
2573
|
try {
|
|
2672
|
-
await Promise.race([promptMirrorPromise, completion]);
|
|
2673
|
-
if (state.completed) return;
|
|
2674
2574
|
if (resourceState.turnRoute) try {
|
|
2675
|
-
await Promise.race([resourceState.turnRoute.bindTurn(activeTurnId), completion]);
|
|
2575
|
+
await Promise.race([resourceState.turnRoute.bindTurn(activeTurnId, { beforeNotifications: promptMirrorPromise }), completion]);
|
|
2676
2576
|
} catch (error) {
|
|
2677
2577
|
if (!state.terminalTurnNotificationQueued && !runAbortController.signal.aborted) throw error;
|
|
2678
2578
|
await Promise.race([resourceState.turnRoute.drain(), completion]);
|
|
2679
2579
|
if (!state.completed) throw error;
|
|
2680
2580
|
}
|
|
2581
|
+
else await Promise.race([promptMirrorPromise, completion]);
|
|
2681
2582
|
if (!state.completed && isTerminalTurnStatus(turn.turn.status)) {
|
|
2682
2583
|
if (!isJsonObject(turn.turn)) throw new Error("Codex turn completion payload is not a JSON object");
|
|
2683
2584
|
await enqueueNotification({
|
|
@@ -2707,6 +2608,7 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
|
|
|
2707
2608
|
});
|
|
2708
2609
|
const imageContext = {
|
|
2709
2610
|
workspaceDir: connection.effectiveWorkspace,
|
|
2611
|
+
agentWorkspaceDir: params.workspaceDir,
|
|
2710
2612
|
model: params.model,
|
|
2711
2613
|
config: params.config,
|
|
2712
2614
|
workspaceOnly,
|
|
@@ -2723,7 +2625,18 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
|
|
|
2723
2625
|
requestTimeoutMs: connection.appServer.requestTimeoutMs,
|
|
2724
2626
|
signal: runAbortController.signal,
|
|
2725
2627
|
assertActive: assertSteeringActive,
|
|
2726
|
-
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
|
+
});
|
|
2727
2640
|
const result = await detectAndLoadAgentHarnessPromptImages({
|
|
2728
2641
|
...imageContext,
|
|
2729
2642
|
prompt: text,
|
|
@@ -2733,12 +2646,33 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
|
|
|
2733
2646
|
userTurnTranscriptRecorder: options.userTurnTranscriptRecorder
|
|
2734
2647
|
});
|
|
2735
2648
|
if (result.failedMediaCount) throw new Error(`failed to hydrate ${result.failedMediaCount} structured image attachment(s) for Codex steering`);
|
|
2736
|
-
|
|
2649
|
+
const source = await buildResolvedCodexUserPromptMessage({
|
|
2650
|
+
...params,
|
|
2651
|
+
prompt: text,
|
|
2652
|
+
transcriptPrompt: text,
|
|
2653
|
+
userTurnTranscriptRecorder: options.userTurnTranscriptRecorder
|
|
2654
|
+
});
|
|
2655
|
+
return {
|
|
2656
|
+
input: buildCodexUserInput(attachmentNote ? `${text}\n\n${attachmentNote}` : text, result.images),
|
|
2657
|
+
message: {
|
|
2658
|
+
...source,
|
|
2659
|
+
role: "user",
|
|
2660
|
+
content: result.images.length ? [{
|
|
2661
|
+
type: "text",
|
|
2662
|
+
text
|
|
2663
|
+
}, ...result.images] : text,
|
|
2664
|
+
...result.images.length ? { __openclaw: {
|
|
2665
|
+
...asOptionalRecord(Reflect.get(source, "__openclaw")),
|
|
2666
|
+
mediaImageBlockFactIndexes: result.imageFactIndexes
|
|
2667
|
+
} } : {}
|
|
2668
|
+
}
|
|
2669
|
+
};
|
|
2737
2670
|
},
|
|
2738
2671
|
beforeSubmit: async (items) => {
|
|
2739
2672
|
const transcriptItems = items.filter((item) => item.isInboundUserMessage === true || item.userTurnTranscriptRecorder !== void 0);
|
|
2740
2673
|
if (transcriptItems.length === 0) return;
|
|
2741
|
-
await
|
|
2674
|
+
await projectionReady;
|
|
2675
|
+
await notifications.drainNotificationQueue();
|
|
2742
2676
|
assertSteeringActive();
|
|
2743
2677
|
const messages = activeProjector.buildSteeringTranscriptPrefix();
|
|
2744
2678
|
if (params.sessionTarget && messages.length > 0) {
|
|
@@ -2862,33 +2796,83 @@ function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notificatio
|
|
|
2862
2796
|
cancel: () => abortExplicitly("cancelled"),
|
|
2863
2797
|
abort: () => abortExplicitly("aborted")
|
|
2864
2798
|
};
|
|
2865
|
-
params.replyOperation?.attachBackend(handle);
|
|
2866
|
-
setActiveEmbeddedRun(params.sessionId, handle, params.sessionKey, params.sessionFile, sessionAgentId);
|
|
2867
2799
|
const freezeRunTerminalOutcome = () => {
|
|
2868
2800
|
if (terminalState.terminalOutcomeFrozen) return;
|
|
2869
2801
|
terminalState.terminalOutcomeFrozen = true;
|
|
2870
2802
|
params.abortSignal?.removeEventListener("abort", abortFromUpstream);
|
|
2871
2803
|
};
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
runAbortController.
|
|
2875
|
-
|
|
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
|
+
});
|
|
2876
2859
|
return {
|
|
2877
2860
|
activeTurnId,
|
|
2878
2861
|
activeProjector,
|
|
2879
2862
|
runtimeModelSelection,
|
|
2880
2863
|
streamState,
|
|
2864
|
+
prepareReplyMedia,
|
|
2881
2865
|
handle,
|
|
2882
2866
|
freezeRunTerminalOutcome,
|
|
2883
2867
|
notifyUserMessagePersisted,
|
|
2884
2868
|
abortListener,
|
|
2885
|
-
ready:
|
|
2869
|
+
ready: projectionReady
|
|
2886
2870
|
};
|
|
2887
2871
|
}
|
|
2888
2872
|
//#endregion
|
|
2889
2873
|
//#region extensions/codex/src/app-server/run-attempt-cleanup.ts
|
|
2890
2874
|
async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRuntime, activeTurn) {
|
|
2891
|
-
const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, releaseSharedClientLeaseAndRetireOneShotClient, releaseSandboxExecEnvironment, runCleanupStep } = resources;
|
|
2875
|
+
const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, releaseSharedClientLeaseAndRetireOneShotClient, releaseSandboxExecEnvironment, releaseNativeProcessAuthority, retainThreadSubscription, releaseThreadSubscription, runCleanupStep } = resources;
|
|
2892
2876
|
const { connection } = prompt.context.runtime;
|
|
2893
2877
|
const { params, options, runAbortController, terminalState, bindingStore, bindingIdentity } = connection;
|
|
2894
2878
|
const { state, steeringQueueRef, userInputBridgeRef, deadlines } = turnRuntime;
|
|
@@ -2906,6 +2890,7 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2906
2890
|
else await state.abortCleanup?.catch(() => {});
|
|
2907
2891
|
if (params.oneShotCliRun) await runCleanupStep("codex-one-shot-terminals", () => terminateCodexBackgroundTerminals(resourceState.client, resourceState.thread.threadId, true));
|
|
2908
2892
|
try {
|
|
2893
|
+
await state.pluginRuntimeRefreshStop;
|
|
2909
2894
|
steeringQueueRef.current?.cancel();
|
|
2910
2895
|
if (params.isFinalFallbackAttempt !== false) await maybeEmitFastModeAutoResetBestEffort();
|
|
2911
2896
|
codexModelCallDiagnostics.emitError("codex app-server run completed without model-call terminal event");
|
|
@@ -2925,56 +2910,60 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2925
2910
|
aborted: runAbortController.signal.aborted && !state.clientClosedAbort
|
|
2926
2911
|
});
|
|
2927
2912
|
await runCleanupStep("codex-trajectory-flush", () => trajectoryRecorder?.flush());
|
|
2928
|
-
const
|
|
2929
|
-
const
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2913
|
+
const pluginRuntimeRefreshing = state.pluginRuntimeRefreshStop !== void 0 && !runAbortController.signal.aborted && terminalState.settledTurnStatus === "completed";
|
|
2914
|
+
const retainLiveIncognitoThread = !pluginRuntimeRefreshing && (terminalState.settledTurnStatus === "completed" || state.permissionChangeRestart === "confirmed" && !params.abortSignal?.aborted) && isIncognitoSessionKey(params.sessionKey);
|
|
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;
|
|
2916
|
+
if (pluginRuntimeRefreshing) await withExclusiveCodexAppServerThread({
|
|
2917
|
+
bindingStore,
|
|
2918
|
+
identity: bindingIdentity,
|
|
2919
|
+
threadId: resourceState.thread.threadId,
|
|
2920
|
+
run: () => bindingStore.withLease(bindingIdentity, async () => {
|
|
2921
|
+
if (!isSameCodexAppServerThreadOwner(bindingStore.read(bindingIdentity), resourceState.thread)) throw new Error("Codex plugin refresh lost its managed thread binding.");
|
|
2922
|
+
if (!await releaseThreadSubscription(connection.assertCurrent)) throw new Error("Plugin reload could not release the previous Codex thread.");
|
|
2923
|
+
if (!await bindingStore.mutate(bindingIdentity, {
|
|
2924
|
+
kind: "clear",
|
|
2925
|
+
threadId: resourceState.thread.threadId
|
|
2926
|
+
}, connection.assertCurrent)) throw new Error("Codex plugin refresh lost its managed thread binding.");
|
|
2927
|
+
})
|
|
2928
|
+
});
|
|
2929
|
+
else {
|
|
2930
|
+
const bindingReleased = isIncognitoSessionKey(params.sessionKey) && !retainLiveThread ? await bindingStore.mutate(bindingIdentity, {
|
|
2931
|
+
kind: "clear",
|
|
2932
|
+
threadId: resourceState.thread.threadId
|
|
2933
|
+
}) : true;
|
|
2934
|
+
if (!retainLiveThread) {
|
|
2935
|
+
if (bindingReleased) {
|
|
2936
|
+
if (!await releaseThreadSubscription()) {
|
|
2937
|
+
if (params.oneShotCliRun) await runCleanupStep("codex-one-shot-unsubscribe", async () => {
|
|
2938
|
+
throw new Error("Codex one-shot thread unsubscribe was not confirmed");
|
|
2939
|
+
});
|
|
2940
|
+
}
|
|
2952
2941
|
}
|
|
2953
2942
|
}
|
|
2954
2943
|
}
|
|
2955
2944
|
} finally {
|
|
2945
|
+
if (resourceState.thread.liveThreadOwnership) await runCleanupStep("codex-unsettled-subscription", async () => {
|
|
2946
|
+
await releaseThreadSubscription();
|
|
2947
|
+
});
|
|
2956
2948
|
await runCleanupStep("codex-user-input-cancel", () => userInputBridgeRef.current?.cancelPending());
|
|
2957
2949
|
await runCleanupStep("codex-turn-deadline-clear", () => deadlines.dispose());
|
|
2958
|
-
await
|
|
2959
|
-
const cleanupReason = terminalState.settledTurnStatus === "completed" ? "completion" : state.timeout ? "timeout" : runAbortController.signal.aborted ? "cancel" : "error";
|
|
2960
|
-
const cleanups = prompt.context.attemptTools.runCleanups.splice(0);
|
|
2961
|
-
const errors = (await Promise.allSettled(cleanups.map(async (cleanup) => await cleanup(cleanupReason)))).filter((result) => result.status === "rejected");
|
|
2962
|
-
if (params.oneShotCliRun && errors.length) throw new AggregateError(errors.map((result) => result.reason), "Codex tool cleanup failed");
|
|
2963
|
-
});
|
|
2950
|
+
await prompt.context.attemptTools.disposeTools(terminalState.settledTurnStatus === "completed" ? "completion" : state.timeout ? "timeout" : runAbortController.signal.aborted ? "cancel" : "error");
|
|
2964
2951
|
await runCleanupStep("codex-route-release", releaseCurrentRoute);
|
|
2965
2952
|
await checkpointCleanup;
|
|
2966
2953
|
await runCleanupStep("codex-shared-client-release", releaseSharedClientLeaseAndRetireOneShotClient);
|
|
2967
2954
|
const nativeHookRelay = resourceState.nativeHookRelay;
|
|
2968
2955
|
resourceState.nativeHookRelay = void 0;
|
|
2969
|
-
await runCleanupStep("codex-native-hook-relay-release", () => {
|
|
2956
|
+
await runCleanupStep("codex-native-hook-relay-release", async () => {
|
|
2970
2957
|
if (!nativeHookRelay) return;
|
|
2971
2958
|
if (state.shouldDelayNativeHookRelayUnregister && !params.oneShotCliRun) scheduleCodexNativeHookRelayUnregister({
|
|
2972
2959
|
relay: nativeHookRelay,
|
|
2973
2960
|
hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec
|
|
2974
2961
|
});
|
|
2975
2962
|
else nativeHookRelay.unregister();
|
|
2963
|
+
await nativeHookRelay.drain();
|
|
2976
2964
|
});
|
|
2977
2965
|
await runCleanupStep("codex-sandbox-release", releaseSandboxExecEnvironment);
|
|
2966
|
+
await runCleanupStep("codex-native-process-source-release", releaseNativeProcessAuthority);
|
|
2978
2967
|
await runCleanupStep("codex-abort-listener-remove", () => {
|
|
2979
2968
|
runAbortController.signal.removeEventListener("abort", abortListener);
|
|
2980
2969
|
});
|
|
@@ -2987,70 +2976,37 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2987
2976
|
await state.abortCleanup;
|
|
2988
2977
|
}
|
|
2989
2978
|
//#endregion
|
|
2990
|
-
//#region extensions/codex/src/app-server/
|
|
2991
|
-
/**
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
const
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
}
|
|
3001
|
-
|
|
3002
|
-
const
|
|
3003
|
-
const serviceTier = fastMode === void 0 ? appServer.serviceTier : fastMode ? "priority" : void 0;
|
|
3004
|
-
if (serviceTier === appServer.serviceTier) return appServer;
|
|
3005
|
-
if (serviceTier) return {
|
|
3006
|
-
...appServer,
|
|
3007
|
-
serviceTier
|
|
3008
|
-
};
|
|
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);
|
|
3009
2992
|
return {
|
|
3010
|
-
...
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
emitAgentEvent({
|
|
3027
|
-
runId: params.runId,
|
|
3028
|
-
stream: event.stream,
|
|
3029
|
-
data: event.data,
|
|
3030
|
-
...params.sessionKey ? { sessionKey: params.sessionKey } : {}
|
|
3031
|
-
});
|
|
3032
|
-
} catch (error) {
|
|
3033
|
-
embeddedAgentLog.debug("codex app-server global agent event emit failed", { error });
|
|
3034
|
-
}
|
|
3035
|
-
try {
|
|
3036
|
-
await params.onAgentEvent?.(event);
|
|
3037
|
-
} catch (error) {
|
|
3038
|
-
embeddedAgentLog.debug("codex app-server agent event handler threw", { error });
|
|
3039
|
-
}
|
|
3040
|
-
}
|
|
3041
|
-
async function runCodexAgentEndHook(params, hookParams) {
|
|
3042
|
-
const sideEffectParams = {
|
|
3043
|
-
...hookParams,
|
|
3044
|
-
ctx: {
|
|
3045
|
-
...hookParams.ctx,
|
|
3046
|
-
config: params.config
|
|
3047
|
-
}
|
|
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)
|
|
3048
3009
|
};
|
|
3049
|
-
if (!params.messageChannel && !params.messageProvider) {
|
|
3050
|
-
await awaitAgentEndSideEffects(sideEffectParams);
|
|
3051
|
-
return;
|
|
3052
|
-
}
|
|
3053
|
-
runAgentEndSideEffects(sideEffectParams);
|
|
3054
3010
|
}
|
|
3055
3011
|
//#endregion
|
|
3056
3012
|
//#region extensions/codex/src/app-server/startup-binding.ts
|
|
@@ -3074,7 +3030,6 @@ const CODEX_APP_SERVER_BYTE_UNITS = {
|
|
|
3074
3030
|
tb: 1099511627776,
|
|
3075
3031
|
tib: 1099511627776
|
|
3076
3032
|
};
|
|
3077
|
-
const codexSessionRecordCache = /* @__PURE__ */ new Map();
|
|
3078
3033
|
function parseCodexAppServerByteLimit(value) {
|
|
3079
3034
|
if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.floor(value);
|
|
3080
3035
|
if (typeof value !== "string") return;
|
|
@@ -3142,51 +3097,6 @@ async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codex
|
|
|
3142
3097
|
}
|
|
3143
3098
|
return files;
|
|
3144
3099
|
}
|
|
3145
|
-
async function readCodexSessionRecordForSessionFile(sessionFile) {
|
|
3146
|
-
if (isSqliteSessionFileMarker(sessionFile)) return;
|
|
3147
|
-
const sessionsFile = path.join(path.dirname(sessionFile), "sessions.json");
|
|
3148
|
-
const resolvedSessionFile = path.resolve(sessionFile);
|
|
3149
|
-
let stat;
|
|
3150
|
-
try {
|
|
3151
|
-
stat = await fs.stat(sessionsFile);
|
|
3152
|
-
} catch {
|
|
3153
|
-
codexSessionRecordCache.delete(resolvedSessionFile);
|
|
3154
|
-
return;
|
|
3155
|
-
}
|
|
3156
|
-
const cached = codexSessionRecordCache.get(resolvedSessionFile);
|
|
3157
|
-
if (cached?.sessionsFile === sessionsFile && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) return cached.record;
|
|
3158
|
-
let store;
|
|
3159
|
-
try {
|
|
3160
|
-
store = JSON.parse(await fs.readFile(sessionsFile, "utf8"));
|
|
3161
|
-
} catch {
|
|
3162
|
-
codexSessionRecordCache.delete(resolvedSessionFile);
|
|
3163
|
-
return;
|
|
3164
|
-
}
|
|
3165
|
-
if (!isJsonObject(store)) {
|
|
3166
|
-
codexSessionRecordCache.delete(resolvedSessionFile);
|
|
3167
|
-
return;
|
|
3168
|
-
}
|
|
3169
|
-
let found;
|
|
3170
|
-
for (const [sessionKey, record] of Object.entries(store)) {
|
|
3171
|
-
if (!isJsonObject(record) || typeof record.sessionFile !== "string") continue;
|
|
3172
|
-
if (path.resolve(record.sessionFile) !== resolvedSessionFile) continue;
|
|
3173
|
-
found = {
|
|
3174
|
-
sessionKey,
|
|
3175
|
-
...record
|
|
3176
|
-
};
|
|
3177
|
-
break;
|
|
3178
|
-
}
|
|
3179
|
-
codexSessionRecordCache.set(resolvedSessionFile, {
|
|
3180
|
-
sessionsFile,
|
|
3181
|
-
mtimeMs: stat.mtimeMs,
|
|
3182
|
-
size: stat.size,
|
|
3183
|
-
record: found
|
|
3184
|
-
});
|
|
3185
|
-
return found;
|
|
3186
|
-
}
|
|
3187
|
-
function isSqliteSessionFileMarker(sessionFile) {
|
|
3188
|
-
return parseSqliteSessionFileMarker(sessionFile) !== void 0;
|
|
3189
|
-
}
|
|
3190
3100
|
async function readCodexAppServerRolloutTokenSnapshot(file, openedHandle) {
|
|
3191
3101
|
let handle = openedHandle;
|
|
3192
3102
|
if (!handle) try {
|
|
@@ -3210,12 +3120,8 @@ async function readCodexAppServerRolloutTokenSnapshot(file, openedHandle) {
|
|
|
3210
3120
|
const bytesToRead = Math.min(position, CODEX_APP_SERVER_ROLLOUT_TAIL_READ_BYTES);
|
|
3211
3121
|
const nextPosition = position - bytesToRead;
|
|
3212
3122
|
const chunk = Buffer.allocUnsafe(bytesToRead);
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
const result = await handle.read(chunk, bytesRead, bytesToRead - bytesRead, nextPosition + bytesRead);
|
|
3216
|
-
if (result.bytesRead === 0) return snapshot;
|
|
3217
|
-
bytesRead += result.bytesRead;
|
|
3218
|
-
}
|
|
3123
|
+
const bytesRead = await readFileWindowFully(handle, chunk, nextPosition);
|
|
3124
|
+
if (bytesRead < bytesToRead) return snapshot;
|
|
3219
3125
|
let lineEnd = bytesRead;
|
|
3220
3126
|
while (lineEnd > 0) {
|
|
3221
3127
|
const index = chunk.lastIndexOf(10, lineEnd - 1);
|
|
@@ -3258,9 +3164,6 @@ function readCodexAppServerRolloutTokenSnapshotLine(line) {
|
|
|
3258
3164
|
function readCompactionConfig(config) {
|
|
3259
3165
|
return isJsonObject(config?.agents?.defaults?.compaction) ? config.agents.defaults.compaction : void 0;
|
|
3260
3166
|
}
|
|
3261
|
-
function resolveCodexAppServerNativeThreadReserveTokens(_config) {
|
|
3262
|
-
return CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS;
|
|
3263
|
-
}
|
|
3264
3167
|
function resolveCodexAppServerNativeThreadTokenFuse(params) {
|
|
3265
3168
|
const projectedTurnTokens = typeof params.projectedTurnTokens === "number" && Number.isFinite(params.projectedTurnTokens) && params.projectedTurnTokens > 0 ? Math.floor(params.projectedTurnTokens) : 0;
|
|
3266
3169
|
const contextWindow = params.modelContextWindow ?? CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS;
|
|
@@ -3273,11 +3176,6 @@ function maxFiniteNumber(values) {
|
|
|
3273
3176
|
if (nums.length === 0) return;
|
|
3274
3177
|
return Math.max(...nums);
|
|
3275
3178
|
}
|
|
3276
|
-
function minFiniteNumber(values) {
|
|
3277
|
-
const nums = values.filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
3278
|
-
if (nums.length === 0) return;
|
|
3279
|
-
return Math.min(...nums);
|
|
3280
|
-
}
|
|
3281
3179
|
function hasContextEngineThreadBootstrapProjection(binding) {
|
|
3282
3180
|
return binding.contextEngine?.projection?.mode === "thread_bootstrap";
|
|
3283
3181
|
}
|
|
@@ -3286,7 +3184,6 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
|
3286
3184
|
const binding = params.binding;
|
|
3287
3185
|
if (!binding?.threadId) return { binding };
|
|
3288
3186
|
if (binding.connectionScope === "supervision") return { binding };
|
|
3289
|
-
const sessionRecord = await readCodexSessionRecordForSessionFile(params.sessionFile);
|
|
3290
3187
|
const rolloutFiles = await listCodexAppServerRolloutFilesForThread(params.agentDir, binding.threadId, params.codexHome, binding.rolloutPath);
|
|
3291
3188
|
const maxBytes = parseCodexAppServerByteLimit(readCompactionConfig(params.config)?.maxActiveTranscriptBytes);
|
|
3292
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", {
|
|
@@ -3320,25 +3217,19 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
|
3320
3217
|
const nativeTokenSnapshots = await Promise.all(rolloutFiles.map(async (file) => readCodexAppServerRolloutTokenSnapshot(file.path, file.handle)));
|
|
3321
3218
|
const nativeTokens = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.totalTokens));
|
|
3322
3219
|
const nativeModelContextWindow = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.modelContextWindow));
|
|
3323
|
-
const
|
|
3324
|
-
const reserveTokens = resolveCodexAppServerNativeThreadReserveTokens(params.config);
|
|
3220
|
+
const reserveTokens = CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS;
|
|
3325
3221
|
const maxTokens = resolveCodexAppServerNativeThreadTokenFuse({
|
|
3326
|
-
modelContextWindow:
|
|
3222
|
+
modelContextWindow: nativeModelContextWindow,
|
|
3327
3223
|
reserveTokens,
|
|
3328
3224
|
projectedTurnTokens: params.projectedTurnTokens
|
|
3329
3225
|
});
|
|
3330
|
-
|
|
3331
|
-
const tokenCount = maxFiniteNumber([sessionTokens, nativeTokens]);
|
|
3332
|
-
if (tokenCount !== void 0 && tokenCount >= maxTokens) {
|
|
3226
|
+
if (nativeTokens !== void 0 && nativeTokens >= maxTokens) {
|
|
3333
3227
|
assertCodexBindingMayBeReplaced(binding, "rotating a full native context", params.expectedSessionRuntimeOwnership);
|
|
3334
3228
|
embeddedAgentLog.warn("codex app-server native transcript exceeded active token limit; starting a fresh thread", {
|
|
3335
3229
|
threadId: binding.threadId,
|
|
3336
3230
|
maxTokens,
|
|
3337
|
-
sessionKey: sessionRecord?.sessionKey,
|
|
3338
|
-
sessionTokens,
|
|
3339
3231
|
nativeTokens,
|
|
3340
3232
|
nativeModelContextWindow,
|
|
3341
|
-
sessionModelContextWindow,
|
|
3342
3233
|
reserveTokens,
|
|
3343
3234
|
projectedTurnTokens: params.projectedTurnTokens
|
|
3344
3235
|
});
|
|
@@ -3348,10 +3239,9 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
|
3348
3239
|
}, params.assertCurrent);
|
|
3349
3240
|
return { binding: void 0 };
|
|
3350
3241
|
}
|
|
3351
|
-
const startupContextTokens = nativeModelContextWindow ?? sessionModelContextWindow;
|
|
3352
3242
|
return {
|
|
3353
3243
|
binding,
|
|
3354
|
-
...
|
|
3244
|
+
...nativeModelContextWindow ? { startupContextTokens: nativeModelContextWindow } : {}
|
|
3355
3245
|
};
|
|
3356
3246
|
}
|
|
3357
3247
|
//#endregion
|
|
@@ -3473,7 +3363,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3473
3363
|
const usesSupervisionConnection = startupBinding?.connectionScope === "supervision";
|
|
3474
3364
|
if (usesSupervisionConnection) activeContextEngine = void 0;
|
|
3475
3365
|
if (usesSupervisionConnection && pluginConfig.supervision?.enabled !== true) throw new Error("Codex supervision is disabled; refusing to open a native user-home supervised session");
|
|
3476
|
-
const resolveRuntimeOptionsForBinding = (binding, selection) => resolveCodexBindingAppServerConnection({
|
|
3366
|
+
const resolveRuntimeOptionsForBinding = async (binding, selection) => (await resolveCodexBindingAppServerConnection({
|
|
3477
3367
|
binding,
|
|
3478
3368
|
pluginConfig,
|
|
3479
3369
|
execPolicy,
|
|
@@ -3483,8 +3373,9 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3483
3373
|
agentDir,
|
|
3484
3374
|
requirementsToml,
|
|
3485
3375
|
openClawSandboxActive: sandbox?.enabled === true,
|
|
3486
|
-
sessionPermissionMode: params.permissionMode
|
|
3487
|
-
|
|
3376
|
+
sessionPermissionMode: params.permissionMode,
|
|
3377
|
+
assertCurrent
|
|
3378
|
+
})).appServer;
|
|
3488
3379
|
const initialStartupBindingHadInactiveThreadBootstrap = isInactiveThreadBootstrapBinding(startupBinding);
|
|
3489
3380
|
const appServerHomeScope = resolveCodexAppServerHomeScope({ appServer: pluginConfig.appServer });
|
|
3490
3381
|
const preparedAuthRoute = usesSupervisionConnection ? void 0 : params.runtimePlan?.auth.modelRoute;
|
|
@@ -3527,7 +3418,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3527
3418
|
};
|
|
3528
3419
|
let reviewerPolicyContext = resolveReviewerPolicyContext(startupBinding);
|
|
3529
3420
|
preDynamicStartupStages.mark("auth-profile");
|
|
3530
|
-
let configuredAppServer = resolveRuntimeOptionsForBinding(startupBinding, {
|
|
3421
|
+
let configuredAppServer = await resolveRuntimeOptionsForBinding(startupBinding, {
|
|
3531
3422
|
modelProvider: reviewerPolicyContext.modelProvider,
|
|
3532
3423
|
model: reviewerPolicyContext.model
|
|
3533
3424
|
});
|
|
@@ -3626,9 +3517,8 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3626
3517
|
binding: startupBinding,
|
|
3627
3518
|
bindingStore,
|
|
3628
3519
|
identity: bindingIdentity,
|
|
3629
|
-
sessionFile: params.sessionFile,
|
|
3630
3520
|
agentDir,
|
|
3631
|
-
codexHome: appServer.start.env?.CODEX_HOME,
|
|
3521
|
+
codexHome: appServer.start.codexHome ?? appServer.start.env?.CODEX_HOME,
|
|
3632
3522
|
config: params.config,
|
|
3633
3523
|
contextEngineActive: Boolean(activeContextEngine),
|
|
3634
3524
|
expectedSessionRuntimeOwnership: params.expectedSessionRuntimeOwnership
|
|
@@ -3638,7 +3528,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3638
3528
|
preDynamicStartupStages.mark("rotate-binding");
|
|
3639
3529
|
if (startupBinding !== startupBindingBeforeRotation) {
|
|
3640
3530
|
reviewerPolicyContext = resolveReviewerPolicyContext(startupBinding);
|
|
3641
|
-
configuredAppServer = resolveRuntimeOptionsForBinding(startupBinding, {
|
|
3531
|
+
configuredAppServer = await resolveRuntimeOptionsForBinding(startupBinding, {
|
|
3642
3532
|
modelProvider: reviewerPolicyContext.modelProvider,
|
|
3643
3533
|
model: reviewerPolicyContext.model
|
|
3644
3534
|
});
|
|
@@ -3666,7 +3556,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3666
3556
|
pluginAppServer: appServer,
|
|
3667
3557
|
continuityCalibration: startupBindingBeforeRotation?.continuityCalibration
|
|
3668
3558
|
};
|
|
3669
|
-
const resolveRuntimeOptionsForCurrentBinding = (selection) => resolveFinalAppServer(resolveRuntimeOptionsForBinding(mutable.startupBinding, selection), selection).appServer;
|
|
3559
|
+
const resolveRuntimeOptionsForCurrentBinding = async (selection) => resolveFinalAppServer(await resolveRuntimeOptionsForBinding(mutable.startupBinding, selection), selection).appServer;
|
|
3670
3560
|
assertCurrent();
|
|
3671
3561
|
return {
|
|
3672
3562
|
params,
|
|
@@ -3723,19 +3613,327 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3723
3613
|
}
|
|
3724
3614
|
}
|
|
3725
3615
|
//#endregion
|
|
3726
|
-
//#region extensions/codex/src/app-server/
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
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");
|
|
3736
3634
|
return;
|
|
3737
3635
|
}
|
|
3738
|
-
|
|
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
|
|
3924
|
+
//#region extensions/codex/src/app-server/run-attempt-state.ts
|
|
3925
|
+
async function clearCodexBindingAfterInvalidImagePayload(bindingStore, identity, fields, expected) {
|
|
3926
|
+
const currentBinding = bindingStore.read(identity);
|
|
3927
|
+
const expectedThreadId = fields.threadId ?? currentBinding?.threadId;
|
|
3928
|
+
if (!expectedThreadId) return;
|
|
3929
|
+
if (currentBinding && currentBinding.threadId !== expectedThreadId) {
|
|
3930
|
+
embeddedAgentLog.warn("codex app-server image payload error detected for unbound thread; preserving thread binding", {
|
|
3931
|
+
...fields,
|
|
3932
|
+
boundThreadId: currentBinding.threadId
|
|
3933
|
+
});
|
|
3934
|
+
return;
|
|
3935
|
+
}
|
|
3936
|
+
if (expected || currentBinding?.connectionScope === "supervision") {
|
|
3739
3937
|
embeddedAgentLog.warn("codex app-server image payload error detected for native-owned thread; preserving binding", fields);
|
|
3740
3938
|
return;
|
|
3741
3939
|
}
|
|
@@ -3784,6 +3982,7 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
|
3784
3982
|
const messages = await readMirroredSessionHistoryMessages({
|
|
3785
3983
|
...activeTranscriptTarget,
|
|
3786
3984
|
signal: connection.runAbortController.signal,
|
|
3985
|
+
contextTokenBudget: effectiveContextTokenBudget,
|
|
3787
3986
|
...transcriptReadFence ? { admission: transcriptReadFence } : {}
|
|
3788
3987
|
});
|
|
3789
3988
|
connection.runAbortController.signal.throwIfAborted();
|
|
@@ -3853,9 +4052,11 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
|
3853
4052
|
});
|
|
3854
4053
|
historyState.messages = await readFencedHistory() ?? historyState.messages;
|
|
3855
4054
|
}
|
|
4055
|
+
historyState.messages.push(...params.pluginRuntimeRefreshMessages ?? []);
|
|
3856
4056
|
const memoryToolNames = getCodexWorkspaceMemoryToolNames(toolBridge.availableSpecs);
|
|
3857
4057
|
const workspaceBootstrapContext = await buildCodexWorkspaceBootstrapContext({
|
|
3858
4058
|
params: runtimeParams,
|
|
4059
|
+
agentWorkspaceDeveloperInstructions: connection.mutable.startupBinding?.agentWorkspaceDeveloperInstructions,
|
|
3859
4060
|
resolvedWorkspace: runtimeParams.bootstrapWorkspaceDir ?? resolvedWorkspace,
|
|
3860
4061
|
executionWorkspace: resolvedWorkspace,
|
|
3861
4062
|
effectiveWorkspace,
|
|
@@ -3865,7 +4066,7 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
|
3865
4066
|
ringZeroActive: isHostScopedAgentToolActive("openclaw") && isSystemAgentOnlyCodexDynamicToolAllowlist(runtimeParams.toolsAllow),
|
|
3866
4067
|
sandboxed: sandbox?.enabled === true
|
|
3867
4068
|
});
|
|
3868
|
-
const agentWorkspaceDeveloperInstructions = workspaceBootstrapContext.threadDeveloperInstructions
|
|
4069
|
+
const agentWorkspaceDeveloperInstructions = workspaceBootstrapContext.threadDeveloperInstructions;
|
|
3869
4070
|
const baseDeveloperInstructions = joinPresentSections(buildDeveloperInstructions(runtimeParams, { dynamicTools: toolBridge.availableSpecs }), agentWorkspaceDeveloperInstructions);
|
|
3870
4071
|
const watchedSessionsContext = buildCodexWatchedSessionsContext({
|
|
3871
4072
|
attempt: runtimeParams,
|
|
@@ -4102,6 +4303,28 @@ function isInvalidCodexImagePayloadError(message) {
|
|
|
4102
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);
|
|
4103
4304
|
}
|
|
4104
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
|
|
4105
4328
|
//#region extensions/codex/src/app-server/trajectory.ts
|
|
4106
4329
|
/** Creates a trajectory recorder when the host exposes its capture capability. */
|
|
4107
4330
|
function createCodexTrajectoryRecorder(params) {
|
|
@@ -4219,6 +4442,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4219
4442
|
clearTimeout(drainGraceTimer);
|
|
4220
4443
|
deadlines.dispose();
|
|
4221
4444
|
};
|
|
4445
|
+
if (state.pluginRuntimeRefreshStop) await state.pluginRuntimeRefreshStop.catch(() => void 0);
|
|
4222
4446
|
const settlement = drainNotificationQueue().then(async () => {
|
|
4223
4447
|
await closeProjection();
|
|
4224
4448
|
await activeProjector.settlement.drain();
|
|
@@ -4238,7 +4462,10 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4238
4462
|
} finally {
|
|
4239
4463
|
if (!state.projectionClosed) await resources.runCleanupStep("codex-transcript-checkpoint", closeProjection);
|
|
4240
4464
|
}
|
|
4241
|
-
const result = activeProjector.buildResult(toolBridge.telemetry, {
|
|
4465
|
+
const result = activeProjector.buildResult(toolBridge.telemetry, {
|
|
4466
|
+
yieldDetected: toolState.yieldDetected,
|
|
4467
|
+
steeringMessages: params.pluginRuntimeRefreshPending?.() ? turnRuntime.steeringQueueRef.current?.getAcceptedMessages() : void 0
|
|
4468
|
+
});
|
|
4242
4469
|
const projectedTerminal = attemptTerminal.project(result.terminal);
|
|
4243
4470
|
const isFinalAborted = () => terminalState.explicitCancellationObserved || !resourceState.executionDisconnectError && (projectedTerminal.aborted || runAbortController.signal.aborted && !state.clientClosedAbort);
|
|
4244
4471
|
const currentPromptError = (fallback) => resourceState.executionDisconnectError ?? state.clientClosedPromptError ?? (state.timeout ? `codex app-server ${state.timeout.kind === "execution" ? "execution budget" : "terminal settlement"} timed out` : fallback);
|
|
@@ -4399,7 +4626,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4399
4626
|
degradedSettlement
|
|
4400
4627
|
]);
|
|
4401
4628
|
}
|
|
4402
|
-
|
|
4629
|
+
await settleReplyMedia(activeTurn, result, turnRuntime, runAbortController.signal);
|
|
4403
4630
|
} finally {
|
|
4404
4631
|
closeSettlement();
|
|
4405
4632
|
}
|
|
@@ -4483,7 +4710,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4483
4710
|
hookRunner
|
|
4484
4711
|
});
|
|
4485
4712
|
state.shouldDelayNativeHookRelayUnregister = completedTurnStatus === "completed" && !effectiveTimedOut && !runAbortController.signal.aborted && !finalAborted && !finalPromptError;
|
|
4486
|
-
if (turnSucceeded && !runAbortController.signal.aborted) try {
|
|
4713
|
+
if (turnSucceeded && !runAbortController.signal.aborted && !state.pluginRuntimeRefreshStop) try {
|
|
4487
4714
|
const continuityCalibration = context.promptState.noEngineContinuityProjectionApplied ? buildCodexContinuityCalibration({
|
|
4488
4715
|
promptChars: prompt.turnState.codexTurnPromptText.length,
|
|
4489
4716
|
inputTokens: result.attemptUsage?.contextUsage?.state === "available" ? result.attemptUsage.contextUsage.promptTokens ?? 0 : 0
|
|
@@ -4528,27 +4755,30 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4528
4755
|
});
|
|
4529
4756
|
markTrajectoryEndRecorded();
|
|
4530
4757
|
const terminalAssistantText = collectTerminalAssistantText(result);
|
|
4531
|
-
if (terminalAssistantText && (!streamState.eventEmitted || streamState.needsTerminalSnapshot) && !finalAborted && !finalPromptError) emitCodexAppServerEvent(params, {
|
|
4758
|
+
if (terminalAssistantText && (assistantTranscriptIdempotencyKey || (!streamState.eventEmitted || streamState.needsTerminalSnapshot) && !finalAborted && !finalPromptError)) emitCodexAppServerEvent(params, {
|
|
4532
4759
|
stream: "assistant",
|
|
4533
|
-
data: {
|
|
4760
|
+
data: {
|
|
4761
|
+
text: terminalAssistantText,
|
|
4762
|
+
...assistantTranscriptIdempotencyKey ? {
|
|
4763
|
+
itemId: assistantTranscriptIdempotencyKey,
|
|
4764
|
+
replace: true,
|
|
4765
|
+
replaceable: true
|
|
4766
|
+
} : {}
|
|
4767
|
+
}
|
|
4534
4768
|
});
|
|
4535
|
-
emitLifecycleTerminal(
|
|
4536
|
-
phase: "error",
|
|
4537
|
-
error: formatErrorMessage(finalPromptError),
|
|
4538
|
-
...
|
|
4539
|
-
aborted: finalAborted,
|
|
4540
|
-
timedOut: effectiveTimedOut
|
|
4541
|
-
})
|
|
4542
|
-
} : {
|
|
4543
|
-
phase: "end",
|
|
4769
|
+
emitLifecycleTerminal({
|
|
4770
|
+
phase: finalPromptError ? "error" : "end",
|
|
4771
|
+
...finalPromptError ? { error: formatErrorMessage(finalPromptError) } : {},
|
|
4772
|
+
...assistantTranscriptIdempotencyKey ? { assistantTranscriptIdempotencyKey } : {},
|
|
4544
4773
|
...buildLifecycleTerminalMeta({
|
|
4545
4774
|
aborted: finalAborted,
|
|
4546
4775
|
timedOut: effectiveTimedOut,
|
|
4547
|
-
yielded: toolState.yieldDetected
|
|
4776
|
+
yielded: finalPromptError ? void 0 : toolState.yieldDetected
|
|
4548
4777
|
})
|
|
4549
4778
|
});
|
|
4550
4779
|
const finalizedResult = Object.assign(result, {
|
|
4551
4780
|
...runtimeModelSelection ? { runtimeModelSelection } : {},
|
|
4781
|
+
...turnSucceeded && params.pluginRuntimeRefreshPending?.() ? { pluginRuntimeRefreshMessages: params.suppressNextUserMessagePersistence && !params.pluginRuntimeRefreshMessages ? [params.userTurnTranscriptRecorder?.getPersistedMessage?.() ?? buildCodexUserPromptMessage(params), ...result.messagesSnapshot] : result.messagesSnapshot } : {},
|
|
4552
4782
|
...toolState.yieldAcknowledgment ? { yieldAcknowledgment: toolState.yieldAcknowledgment } : {},
|
|
4553
4783
|
...codexAppServerFailure ? { codexAppServerFailure } : {},
|
|
4554
4784
|
...promptTimeoutOutcome ? { promptTimeoutOutcome } : {},
|
|
@@ -4675,7 +4905,7 @@ function createCodexAttemptLifecycleController(resources, turnRuntime) {
|
|
|
4675
4905
|
state.pendingTerminalDynamicToolRelease = value;
|
|
4676
4906
|
scheduleTerminalDynamicToolReleaseCheck();
|
|
4677
4907
|
};
|
|
4678
|
-
const emitLifecycleStart = () => {
|
|
4908
|
+
const emitLifecycleStart = (model) => {
|
|
4679
4909
|
emitCodexAppServerEvent(params, {
|
|
4680
4910
|
stream: "lifecycle",
|
|
4681
4911
|
data: {
|
|
@@ -4683,10 +4913,17 @@ function createCodexAttemptLifecycleController(resources, turnRuntime) {
|
|
|
4683
4913
|
startedAt: attemptStartedAt
|
|
4684
4914
|
}
|
|
4685
4915
|
});
|
|
4916
|
+
emitCodexAppServerEvent(params, {
|
|
4917
|
+
stream: "lifecycle",
|
|
4918
|
+
data: {
|
|
4919
|
+
phase: "model",
|
|
4920
|
+
...model
|
|
4921
|
+
}
|
|
4922
|
+
});
|
|
4686
4923
|
state.lifecycleStarted = true;
|
|
4687
4924
|
};
|
|
4688
4925
|
const emitLifecycleTerminal = (data) => {
|
|
4689
|
-
if (!state.lifecycleStarted || state.lifecycleTerminalEmitted || state.permissionChangeRestart) return;
|
|
4926
|
+
if (!state.lifecycleStarted || state.lifecycleTerminalEmitted || state.permissionChangeRestart || params.pluginRuntimeRefreshPending?.()) return;
|
|
4690
4927
|
emitCodexAppServerEvent(params, {
|
|
4691
4928
|
stream: "lifecycle",
|
|
4692
4929
|
data: {
|
|
@@ -4784,13 +5021,29 @@ function createCodexAttemptLifecycleController(resources, turnRuntime) {
|
|
|
4784
5021
|
//#endregion
|
|
4785
5022
|
//#region extensions/codex/src/app-server/run-attempt-notification-controller.ts
|
|
4786
5023
|
function createCodexAttemptNotificationController(resources, turnRuntime, lifecycle) {
|
|
4787
|
-
const { prompt, state: resourceState, projectorRef
|
|
5024
|
+
const { prompt, state: resourceState, projectorRef } = resources;
|
|
4788
5025
|
const { context, turnState } = prompt;
|
|
4789
5026
|
const { attemptTools, runtime } = context;
|
|
4790
5027
|
const { appServer, runAbortController } = runtime.connection;
|
|
4791
5028
|
const { allocateCodexToolOutcomeOrdinal } = attemptTools;
|
|
4792
|
-
const { state, turnIdRef,
|
|
5029
|
+
const { state, turnIdRef, steeringQueueRef, activeTurnItemIds, pendingOpenClawDynamicToolCompletionIds, openClawDynamicToolExecutions, completeTurn, noteProgress, deadlines } = turnRuntime;
|
|
4793
5030
|
const { scheduleTerminalDynamicToolReleaseCheck, reportExecutionNotification, maybeAnnounceFastModeAutoOff } = lifecycle;
|
|
5031
|
+
const pendingNativeCommandItems = /* @__PURE__ */ new Set();
|
|
5032
|
+
const nativeItemObservers = /* @__PURE__ */ new Set();
|
|
5033
|
+
const waitForNativeTerminalItems = async (signal) => {
|
|
5034
|
+
if (pendingNativeCommandItems.size === 0) return;
|
|
5035
|
+
const completion = createDeferred();
|
|
5036
|
+
const observe = () => {
|
|
5037
|
+
if (pendingNativeCommandItems.size === 0) completion.resolve();
|
|
5038
|
+
};
|
|
5039
|
+
nativeItemObservers.add(observe);
|
|
5040
|
+
try {
|
|
5041
|
+
observe();
|
|
5042
|
+
if (!await waitForPromiseOrAbort(completion.promise, signal)) signal.throwIfAborted();
|
|
5043
|
+
} finally {
|
|
5044
|
+
nativeItemObservers.delete(observe);
|
|
5045
|
+
}
|
|
5046
|
+
};
|
|
4794
5047
|
const isTerminalTurnNotificationForTurn = (notification, notificationTurnId) => isTerminalCodexTurnNotificationForTurn({
|
|
4795
5048
|
notification,
|
|
4796
5049
|
threadId: resourceState.thread.threadId,
|
|
@@ -4800,7 +5053,6 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
4800
5053
|
if (state.projectionClosed) return;
|
|
4801
5054
|
const projector = projectorRef.current;
|
|
4802
5055
|
const turnId = turnIdRef.current;
|
|
4803
|
-
userInputBridgeRef.current?.handleNotification(notification);
|
|
4804
5056
|
if (!projector || !turnId) {
|
|
4805
5057
|
if (notification.method === "error") state.latestStartupErrorNotification = notification;
|
|
4806
5058
|
return;
|
|
@@ -4845,6 +5097,11 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
4845
5097
|
});
|
|
4846
5098
|
} finally {
|
|
4847
5099
|
state.activeLocalProjections -= 1;
|
|
5100
|
+
if (isCurrentTurn && notification.method === "item/completed") {
|
|
5101
|
+
const item = readCodexNotificationItem(notification.params);
|
|
5102
|
+
if (item?.type === "commandExecution" && typeof item.id === "string") pendingNativeCommandItems.delete(item.id);
|
|
5103
|
+
}
|
|
5104
|
+
for (const observe of nativeItemObservers) observe();
|
|
4848
5105
|
if (isTerminal) {
|
|
4849
5106
|
if ((readCodexTurnCompletedNotification(notification.params)?.turn)?.status === "interrupted" && state.sawCodexInterruptMarker) projector.markAborted();
|
|
4850
5107
|
completeTurn();
|
|
@@ -4883,6 +5140,7 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
4883
5140
|
const modelToolCallId = readRawResponseToolCallId(notification);
|
|
4884
5141
|
if (modelToolCallId) allocateCodexToolOutcomeOrdinal?.(modelToolCallId);
|
|
4885
5142
|
const nativeItem = readCodexNotificationItem(notification.params);
|
|
5143
|
+
if (notification.method === "item/started" && nativeItem?.type === "commandExecution" && typeof nativeItem.id === "string") pendingNativeCommandItems.add(nativeItem.id);
|
|
4886
5144
|
if (nativeItem?.type === "webSearch") {
|
|
4887
5145
|
projector.settlement.turnTainted ||= notification.method === "item/completed";
|
|
4888
5146
|
projector.recordNativeToolOutcome(nativeItem);
|
|
@@ -4899,9 +5157,9 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
4899
5157
|
const drainNotificationQueue = async () => {
|
|
4900
5158
|
await resourceState.turnRoute?.drain();
|
|
4901
5159
|
};
|
|
4902
|
-
registerNativeSubagentMonitor(resourceState.thread.threadId);
|
|
4903
5160
|
return {
|
|
4904
5161
|
waitForActiveNativeTurnCompletion,
|
|
5162
|
+
waitForNativeTerminalItems,
|
|
4905
5163
|
noteNotificationReceived,
|
|
4906
5164
|
enqueueNotification,
|
|
4907
5165
|
drainNotificationQueue
|
|
@@ -4917,13 +5175,24 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
4917
5175
|
const { connection, buildActiveRunAttemptParams, effectiveContextTokenBudget, effectiveRuntimeModelId, effectiveRuntimeProviderId } = runtime;
|
|
4918
5176
|
const { params, activeContextEngine, usesSupervisionConnection, mutable, isInactiveThreadBootstrapBinding, bindingStore, bindingIdentity, agentDir, appServer, contextSessionKey, effectiveWorkspace, sandbox } = connection;
|
|
4919
5177
|
const { toolBridge } = attemptTools;
|
|
4920
|
-
|
|
4921
|
-
const
|
|
5178
|
+
const nativeHistoryProvenancePrefix = params.trigger === "user" ? buildCodexHistoryProvenancePrefix(params) : void 0;
|
|
5179
|
+
const forkedSession = !mutable.startupBinding?.threadId && params.sessionTarget ? getSessionEntry({
|
|
5180
|
+
...params.sessionTarget,
|
|
5181
|
+
sessionKey: contextSessionKey,
|
|
5182
|
+
hydrateSkillPromptRefs: false,
|
|
5183
|
+
readConsistency: "latest"
|
|
5184
|
+
}) : void 0;
|
|
5185
|
+
const preserveForkedToolResults = Boolean(forkedSession?.sessionId === params.sessionId && forkedSession.createdVia === "spawn" && forkedSession.parentSessionKey && forkedSession.parentSessionKey !== contextSessionKey && forkedSession.forkSource?.sessionKey === forkedSession.parentSessionKey && forkedSession.forkSource.sessionId !== params.sessionId);
|
|
5186
|
+
let contextImageGroups = [];
|
|
5187
|
+
let turnContextImageGroups = [];
|
|
4922
5188
|
const assertProjectionCurrent = () => {
|
|
4923
5189
|
params.hostCapabilities.assertActive();
|
|
4924
5190
|
connection.assertCurrent();
|
|
4925
5191
|
connection.runAbortController.signal.throwIfAborted();
|
|
4926
5192
|
};
|
|
5193
|
+
const admittedMessage = params.userTurnTranscriptRecorder?.message ?? await params.userTurnTranscriptRecorder?.resolveMessage();
|
|
5194
|
+
assertProjectionCurrent();
|
|
5195
|
+
const currentUserTurnIdempotencyKey = params.pluginRuntimeRefreshMessages ? void 0 : admittedMessage?.idempotencyKey;
|
|
4927
5196
|
const prepareFileContext = async (message, maxChars) => {
|
|
4928
5197
|
const prepare = params.hostCapabilities.prepareContextMedia;
|
|
4929
5198
|
if (!prepare) {
|
|
@@ -4949,11 +5218,12 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
4949
5218
|
originalHistoryMessages: historyState.messages,
|
|
4950
5219
|
prompt: params.prompt,
|
|
4951
5220
|
maxRenderedContextChars: codexContinuityProjectionMaxChars,
|
|
5221
|
+
toolPayloadMode: params.pluginRuntimeRefreshMessages || preserveForkedToolResults ? "preserve" : "elide",
|
|
4952
5222
|
prepareFileContext,
|
|
4953
5223
|
currentUserTurnIdempotencyKey
|
|
4954
5224
|
});
|
|
4955
5225
|
assertProjectionCurrent();
|
|
4956
|
-
|
|
5226
|
+
contextImageGroups = projection.imageGroups ?? [];
|
|
4957
5227
|
promptState.promptText = projection.promptText;
|
|
4958
5228
|
promptState.promptContextRange = projection.promptContextRange;
|
|
4959
5229
|
promptState.prePromptMessageCount = projection.prePromptMessageCount;
|
|
@@ -4998,12 +5268,12 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
4998
5268
|
prompt: params.prompt,
|
|
4999
5269
|
systemPromptAddition: assembled.systemPromptAddition,
|
|
5000
5270
|
maxRenderedContextChars: codexContextProjectionMaxChars,
|
|
5001
|
-
toolPayloadMode: contextEngineProjection ? "preserve" : "elide",
|
|
5271
|
+
toolPayloadMode: contextEngineProjection || params.pluginRuntimeRefreshMessages || preserveForkedToolResults ? "preserve" : "elide",
|
|
5002
5272
|
...projectionDecision.project ? { prepareFileContext } : {},
|
|
5003
5273
|
currentUserTurnIdempotencyKey
|
|
5004
5274
|
});
|
|
5005
5275
|
assertProjectionCurrent();
|
|
5006
|
-
|
|
5276
|
+
contextImageGroups = projectionDecision.project ? projection.imageGroups ?? [] : [];
|
|
5007
5277
|
const decisionBinding = decisionStartupBinding;
|
|
5008
5278
|
embeddedAgentLog.info("codex app-server context-engine projection decision", {
|
|
5009
5279
|
sessionId: params.sessionId,
|
|
@@ -5031,13 +5301,17 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
5031
5301
|
if (activeContextEngine) try {
|
|
5032
5302
|
await applyActiveContextEngineProjection(runtime.nativeToolSurfaceEnabled ? mutable.startupBinding : void 0);
|
|
5033
5303
|
} catch (assembleErr) {
|
|
5034
|
-
if (assembleErr instanceof CodexContextAttachmentError) throw assembleErr;
|
|
5304
|
+
if (assembleErr instanceof CodexContextAttachmentError || params.pluginRuntimeRefreshMessages) throw assembleErr;
|
|
5035
5305
|
assertProjectionCurrent();
|
|
5036
5306
|
embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
|
|
5037
5307
|
}
|
|
5038
5308
|
const codexModelInputHistoryMessages = [];
|
|
5309
|
+
const admittedContent = admittedMessage?.content;
|
|
5310
|
+
const currentUserMessage = admittedMessage ? typeof admittedContent === "string" ? admittedContent : (admittedContent ?? []).flatMap((part) => part.type === "text" ? [part.text] : []).join("\n") : params.pluginRuntimeRefreshMessages ? "" : params.prompt;
|
|
5039
5311
|
const buildPromptFromCurrentInputs = async () => {
|
|
5040
5312
|
return await resolveAgentHarnessBeforePromptBuildResult({
|
|
5313
|
+
currentUserMessage,
|
|
5314
|
+
currentUserMessageId: admittedMessage?.idempotencyKey,
|
|
5041
5315
|
prompt: prependCurrentInboundContext(promptState.promptText, params.currentInboundContext),
|
|
5042
5316
|
developerInstructions: { build: ({ toolsAllow }) => {
|
|
5043
5317
|
if (isRestrictivePromptToolsAllow(toolsAllow)) throw new Error("Codex app-server cannot enforce before_prompt_build toolsAllow; use the embedded or Copilot runtime for turn-scoped tool policy.");
|
|
@@ -5087,12 +5361,21 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
5087
5361
|
promptInputRange: promptBuildResult.promptInputRange,
|
|
5088
5362
|
decoratedPrompt: turnPromptText
|
|
5089
5363
|
});
|
|
5090
|
-
|
|
5364
|
+
const imageOffset = projectedRanges && promptState.promptContextRange ? projectedRanges.contextRange.start - promptState.promptContextRange.start : void 0;
|
|
5365
|
+
const fitted = fitCodexProjectedContextForTurnStart({
|
|
5091
5366
|
promptText: turnPromptText,
|
|
5367
|
+
maxChars: CODEX_TURN_START_TEXT_INPUT_MAX_CHARS - (nativeHistoryProvenancePrefix?.length ?? 0),
|
|
5092
5368
|
contextRange: projectedRanges?.contextRange,
|
|
5093
5369
|
requestRange: projectedRanges?.requestRange,
|
|
5094
|
-
preservedRange
|
|
5370
|
+
preservedRange,
|
|
5371
|
+
imageGroups: imageOffset === void 0 ? [] : contextImageGroups.map((group) => ({
|
|
5372
|
+
images: group.images,
|
|
5373
|
+
start: group.start + imageOffset,
|
|
5374
|
+
end: group.end + imageOffset
|
|
5375
|
+
}))
|
|
5095
5376
|
});
|
|
5377
|
+
turnContextImageGroups = fitted.imageGroups ?? [];
|
|
5378
|
+
return fitted.promptText;
|
|
5096
5379
|
};
|
|
5097
5380
|
const firstPromptBuild = await buildPromptFromCurrentInputs();
|
|
5098
5381
|
const turnState = {
|
|
@@ -5148,8 +5431,8 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
5148
5431
|
return projected;
|
|
5149
5432
|
};
|
|
5150
5433
|
const applyNoContextEngineContinuityProjection = async (action, binding) => {
|
|
5151
|
-
const hasContinuity = historyState.messages.some((message) => message.role === "user" || isCodexDurableCustomMessage(message) || action === "started" && (message.role === "compactionSummary" || message.role === "branchSummary"));
|
|
5152
|
-
if (activeContextEngine || !hasContinuity) return false;
|
|
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())));
|
|
5435
|
+
if (activeContextEngine || !hasContinuity && !params.pluginRuntimeRefreshMessages?.length) return false;
|
|
5153
5436
|
if (action === "resumed" && promptState.precomputedStaleBindingContinuityProjectionApplied) return true;
|
|
5154
5437
|
if (action === "started" && promptState.staleBindingContinuityForcedFreshStart) return true;
|
|
5155
5438
|
if (action === "started" && promptState.inactiveThreadBootstrapBindingForcedFreshStart) return false;
|
|
@@ -5171,9 +5454,8 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
5171
5454
|
binding,
|
|
5172
5455
|
bindingStore,
|
|
5173
5456
|
identity: bindingIdentity,
|
|
5174
|
-
sessionFile: params.sessionFile,
|
|
5175
5457
|
agentDir,
|
|
5176
|
-
codexHome: appServer.start.env?.CODEX_HOME,
|
|
5458
|
+
codexHome: appServer.start.codexHome ?? appServer.start.env?.CODEX_HOME,
|
|
5177
5459
|
config: params.config,
|
|
5178
5460
|
contextEngineActive: Boolean(activeContextEngine),
|
|
5179
5461
|
expectedSessionRuntimeOwnership: params.expectedSessionRuntimeOwnership,
|
|
@@ -5193,7 +5475,7 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
5193
5475
|
try {
|
|
5194
5476
|
await applyActiveContextEngineProjection(void 0);
|
|
5195
5477
|
} catch (assembleErr) {
|
|
5196
|
-
if (assembleErr instanceof CodexContextAttachmentError) throw assembleErr;
|
|
5478
|
+
if (assembleErr instanceof CodexContextAttachmentError || params.pluginRuntimeRefreshMessages) throw assembleErr;
|
|
5197
5479
|
assertProjectionCurrent();
|
|
5198
5480
|
embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
|
|
5199
5481
|
}
|
|
@@ -5222,10 +5504,11 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
5222
5504
|
let workspaceReferencesIncluded = true;
|
|
5223
5505
|
return {
|
|
5224
5506
|
context,
|
|
5225
|
-
get
|
|
5226
|
-
return
|
|
5507
|
+
get contextImageGroups() {
|
|
5508
|
+
return turnContextImageGroups;
|
|
5227
5509
|
},
|
|
5228
5510
|
codexModelInputHistoryMessages,
|
|
5511
|
+
nativeHistoryProvenancePrefix,
|
|
5229
5512
|
turnState,
|
|
5230
5513
|
refreshWorkspaceReferences: (include) => {
|
|
5231
5514
|
turnState.codexTurnPromptText = decorateCodexTurnPromptText(turnState.promptBuild, include);
|
|
@@ -5266,6 +5549,13 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5266
5549
|
const { connection, hookChannelId } = runtime;
|
|
5267
5550
|
const { appServer, params, effectiveCwd, sessionAgentId, contextSessionKey, runAbortController, sandbox, options, nativeHookRelayEvents } = connection;
|
|
5268
5551
|
const { toolBridge } = attemptTools;
|
|
5552
|
+
let nativeProcessAuthorityReleased = false;
|
|
5553
|
+
const releaseNativeProcessAuthority = () => {
|
|
5554
|
+
if (!nativeProcessAuthorityReleased) {
|
|
5555
|
+
nativeProcessAuthorityReleased = true;
|
|
5556
|
+
nativeProcessAuthority?.release();
|
|
5557
|
+
}
|
|
5558
|
+
};
|
|
5269
5559
|
const trajectoryRecorder = createCodexTrajectoryRecorder({
|
|
5270
5560
|
attempt: params,
|
|
5271
5561
|
cwd: effectiveCwd,
|
|
@@ -5290,6 +5580,7 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5290
5580
|
nativePreToolUseFailureFallbackTerminalReason: void 0,
|
|
5291
5581
|
releaseSharedClientLease: void 0,
|
|
5292
5582
|
startupClientUnsafe: false,
|
|
5583
|
+
turnStartAttempted: false,
|
|
5293
5584
|
sharedCodexClientRetiredForOneShotCleanup: false,
|
|
5294
5585
|
sandboxExecEnvironment: void 0,
|
|
5295
5586
|
executionDisconnectError: void 0,
|
|
@@ -5380,12 +5671,16 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5380
5671
|
await operation();
|
|
5381
5672
|
}
|
|
5382
5673
|
});
|
|
5383
|
-
|
|
5384
|
-
|
|
5674
|
+
let nativeSubagentMonitorSettlement;
|
|
5675
|
+
const unregisterNativeSubagentMonitor = async () => {
|
|
5676
|
+
const registration = state.nativeSubagentMonitor;
|
|
5385
5677
|
state.nativeSubagentMonitor = void 0;
|
|
5678
|
+
if (registration) nativeSubagentMonitorSettlement = registration.unregister();
|
|
5679
|
+
await nativeSubagentMonitorSettlement;
|
|
5386
5680
|
};
|
|
5387
|
-
const registerNativeSubagentMonitor = (parentThreadId) => {
|
|
5388
|
-
unregisterNativeSubagentMonitor();
|
|
5681
|
+
const registerNativeSubagentMonitor = async (parentThreadId) => {
|
|
5682
|
+
await unregisterNativeSubagentMonitor();
|
|
5683
|
+
connection.assertCurrent();
|
|
5389
5684
|
const sessionKey = params.sessionKey;
|
|
5390
5685
|
const storePath = params.sessionTarget?.storePath;
|
|
5391
5686
|
const parentSession = sessionKey && storePath ? getSessionEntry({
|
|
@@ -5395,17 +5690,46 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5395
5690
|
readConsistency: "latest",
|
|
5396
5691
|
hydrateSkillPromptRefs: false
|
|
5397
5692
|
}) : void 0;
|
|
5693
|
+
const historyOwner = createCodexNativeSubagentHistoryOwner({
|
|
5694
|
+
parentThreadId,
|
|
5695
|
+
sessionId: params.sessionId,
|
|
5696
|
+
...parentSession?.sessionId === params.sessionId ? { lifecycleRevision: parentSession.lifecycleRevision } : {},
|
|
5697
|
+
binding: state.thread
|
|
5698
|
+
});
|
|
5699
|
+
const { bindingStore, bindingIdentity } = connection;
|
|
5700
|
+
const submissionStore = historyOwner ? {
|
|
5701
|
+
assertCurrent: () => {
|
|
5702
|
+
const current = bindingStore.read(bindingIdentity);
|
|
5703
|
+
if (!current || !matchesCodexNativeSubagentSubmissionBinding(current, historyOwner)) throw new Error("Native submission binding is no longer current.");
|
|
5704
|
+
if (historyOwner.lifecycleRevision && sessionKey && storePath) {
|
|
5705
|
+
if (getSessionEntry({
|
|
5706
|
+
agentId: sessionAgentId,
|
|
5707
|
+
sessionKey,
|
|
5708
|
+
storePath,
|
|
5709
|
+
readConsistency: "latest",
|
|
5710
|
+
hydrateSkillPromptRefs: false
|
|
5711
|
+
})?.lifecycleRevision !== historyOwner.lifecycleRevision) throw new Error("Native submission session lifecycle is no longer current.");
|
|
5712
|
+
}
|
|
5713
|
+
},
|
|
5714
|
+
read: () => bindingStore.readNativeSubagentSubmissions(bindingIdentity, historyOwner),
|
|
5715
|
+
record: (receipt, assertCurrent) => bindingStore.mutate(bindingIdentity, {
|
|
5716
|
+
kind: "record-native-subagent-submission",
|
|
5717
|
+
owner: historyOwner,
|
|
5718
|
+
receipt
|
|
5719
|
+
}, assertCurrent),
|
|
5720
|
+
consume: (receipt, assertCurrent) => bindingStore.mutate(bindingIdentity, {
|
|
5721
|
+
kind: "consume-native-subagent-submission",
|
|
5722
|
+
owner: historyOwner,
|
|
5723
|
+
receipt
|
|
5724
|
+
}, assertCurrent)
|
|
5725
|
+
} : void 0;
|
|
5398
5726
|
state.nativeSubagentMonitor = codexNativeSubagentMonitorRuntime.register({
|
|
5399
5727
|
client: state.client,
|
|
5400
5728
|
parentThreadId,
|
|
5401
5729
|
requesterSessionKey: params.sessionKey,
|
|
5402
5730
|
taskRuntimeScope: params.agentHarnessTaskRuntimeScope,
|
|
5403
|
-
historyOwner
|
|
5404
|
-
|
|
5405
|
-
sessionId: params.sessionId,
|
|
5406
|
-
...parentSession?.sessionId === params.sessionId ? { lifecycleRevision: parentSession.lifecycleRevision } : {},
|
|
5407
|
-
binding: state.thread
|
|
5408
|
-
}),
|
|
5731
|
+
historyOwner,
|
|
5732
|
+
submissionStore,
|
|
5409
5733
|
agentId: sessionAgentId,
|
|
5410
5734
|
retainClient: () => retainSharedCodexAppServerClientIfCurrent(state.client),
|
|
5411
5735
|
retainParentThread: (protectedThreadId) => protectCodexAppServerLiveThread(state.client, protectedThreadId),
|
|
@@ -5416,7 +5740,7 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5416
5740
|
} } : {}
|
|
5417
5741
|
});
|
|
5418
5742
|
};
|
|
5419
|
-
const releaseCurrentRoute = () => {
|
|
5743
|
+
const releaseCurrentRoute = async () => {
|
|
5420
5744
|
state.releaseInferenceContext?.();
|
|
5421
5745
|
state.releaseInferenceContext = void 0;
|
|
5422
5746
|
state.detachRouteAbort();
|
|
@@ -5424,7 +5748,89 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5424
5748
|
state.turnRoute?.release();
|
|
5425
5749
|
state.turnRoute = void 0;
|
|
5426
5750
|
state.routeActivated = false;
|
|
5427
|
-
unregisterNativeSubagentMonitor();
|
|
5751
|
+
await unregisterNativeSubagentMonitor();
|
|
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);
|
|
5428
5834
|
};
|
|
5429
5835
|
const startupTimeoutMs = resolveCodexStartupTimeoutMs({
|
|
5430
5836
|
timeoutMs: params.timeoutMs,
|
|
@@ -5432,8 +5838,13 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5432
5838
|
});
|
|
5433
5839
|
const requesterChannel = params.messageChannel ?? params.messageProvider;
|
|
5434
5840
|
const requester = buildCodexHookRequester(params);
|
|
5435
|
-
const buildNativeHookRelayFinalConfigPatch = (decision) => {
|
|
5436
|
-
state.nativeHookRelay
|
|
5841
|
+
const buildNativeHookRelayFinalConfigPatch = async (decision) => {
|
|
5842
|
+
const previousRelay = state.nativeHookRelay;
|
|
5843
|
+
previousRelay?.unregister();
|
|
5844
|
+
await previousRelay?.drain();
|
|
5845
|
+
connection.assertCurrent();
|
|
5846
|
+
const requiresProcessAdmission = nativeProcessAuthority && runtime.nativeToolSurfaceEnabled;
|
|
5847
|
+
const relayEvents = requiresProcessAdmission && !nativeHookRelayEvents.includes("pre_tool_use") ? [...nativeHookRelayEvents, "pre_tool_use"] : nativeHookRelayEvents;
|
|
5437
5848
|
if (params.pluginHarnessToolPolicyRestricted === true) {
|
|
5438
5849
|
state.nativeHookRelay = void 0;
|
|
5439
5850
|
return {
|
|
@@ -5442,10 +5853,13 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5442
5853
|
};
|
|
5443
5854
|
}
|
|
5444
5855
|
state.nativeHookRelay = createCodexNativeHookRelay({
|
|
5445
|
-
options:
|
|
5856
|
+
options: requiresProcessAdmission ? {
|
|
5857
|
+
...options.nativeHookRelay,
|
|
5858
|
+
enabled: true
|
|
5859
|
+
} : options.nativeHookRelay,
|
|
5446
5860
|
generation: decision.action === "resume" ? decision.binding.nativeHookRelayGeneration : void 0,
|
|
5447
5861
|
generationMismatchGraceMs: decision.action === "resume" && !decision.binding.nativeHookRelayGeneration ? CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS : void 0,
|
|
5448
|
-
events:
|
|
5862
|
+
events: relayEvents,
|
|
5449
5863
|
agentId: sessionAgentId,
|
|
5450
5864
|
sessionId: params.sessionId,
|
|
5451
5865
|
sessionKey: contextSessionKey,
|
|
@@ -5469,6 +5883,10 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5469
5883
|
loopDetectionPreToolUseRelay: appServer.loopDetectionPreToolUseRelay,
|
|
5470
5884
|
signal: runAbortController.signal,
|
|
5471
5885
|
hostCapabilities: params.hostCapabilities,
|
|
5886
|
+
nativeProcessAuthority: requiresProcessAdmission ? {
|
|
5887
|
+
owner: nativeProcessAuthority,
|
|
5888
|
+
client: () => state.client
|
|
5889
|
+
} : void 0,
|
|
5472
5890
|
assertCurrent: connection.assertCurrent,
|
|
5473
5891
|
onPreToolUseFailure: (failure) => {
|
|
5474
5892
|
const projector = projectorRef.current;
|
|
@@ -5477,21 +5895,40 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5477
5895
|
else pendingNativePreToolUseFailures.push(failure);
|
|
5478
5896
|
}
|
|
5479
5897
|
});
|
|
5898
|
+
await state.nativeHookRelay?.prepareInvocation();
|
|
5899
|
+
connection.assertCurrent();
|
|
5480
5900
|
return {
|
|
5481
5901
|
configPatch: state.nativeHookRelay ? buildCodexNativeHookRelayConfig({
|
|
5482
5902
|
relay: state.nativeHookRelay,
|
|
5483
|
-
events:
|
|
5903
|
+
events: relayEvents,
|
|
5484
5904
|
hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec
|
|
5485
5905
|
}) : options.nativeHookRelay?.enabled === false ? buildCodexNativeHookRelayDisabledConfig() : void 0,
|
|
5486
5906
|
nativeHookRelayGeneration: state.nativeHookRelay?.generation
|
|
5487
5907
|
};
|
|
5488
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;
|
|
5489
5924
|
return {
|
|
5490
5925
|
prompt,
|
|
5491
5926
|
trajectoryRecorder,
|
|
5492
5927
|
state,
|
|
5493
5928
|
projectorRef,
|
|
5494
5929
|
pendingNativePreToolUseFailures,
|
|
5930
|
+
nativeProcessAuthority,
|
|
5931
|
+
releaseNativeProcessAuthority,
|
|
5495
5932
|
markTrajectoryEndRecorded: () => {
|
|
5496
5933
|
state.trajectoryEndRecorded = true;
|
|
5497
5934
|
},
|
|
@@ -5502,6 +5939,9 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5502
5939
|
runCleanupStep,
|
|
5503
5940
|
registerNativeSubagentMonitor,
|
|
5504
5941
|
releaseCurrentRoute,
|
|
5942
|
+
retainThreadSubscription,
|
|
5943
|
+
releaseThreadSubscription,
|
|
5944
|
+
cleanupBeforeActiveTurn,
|
|
5505
5945
|
startupTimeoutMs,
|
|
5506
5946
|
buildNativeHookRelayFinalConfigPatch
|
|
5507
5947
|
};
|
|
@@ -5509,7 +5949,7 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5509
5949
|
//#endregion
|
|
5510
5950
|
//#region extensions/codex/src/app-server/run-attempt-route.ts
|
|
5511
5951
|
async function prepareCodexAttemptRoute(resources, turnRuntime, notifications, handleServerRequest) {
|
|
5512
|
-
const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, registerNativeSubagentMonitor
|
|
5952
|
+
const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, registerNativeSubagentMonitor } = resources;
|
|
5513
5953
|
const { connection } = prompt.context.runtime;
|
|
5514
5954
|
const { runAbortController } = connection;
|
|
5515
5955
|
const { state, turnIdRef, completeTurn } = turnRuntime;
|
|
@@ -5542,12 +5982,12 @@ async function prepareCodexAttemptRoute(resources, turnRuntime, notifications, h
|
|
|
5542
5982
|
};
|
|
5543
5983
|
const ensureCurrentThreadRoute = async () => {
|
|
5544
5984
|
if (resourceState.turnRoute?.threadId !== resourceState.thread.threadId) {
|
|
5545
|
-
releaseCurrentRoute();
|
|
5985
|
+
await releaseCurrentRoute();
|
|
5546
5986
|
resourceState.turnRoute = resourceState.turnRouter.reserveThread({ threadId: resourceState.thread.threadId });
|
|
5547
5987
|
}
|
|
5548
5988
|
if (!resourceState.turnRoute) throw new Error("codex app-server turn route was not reserved");
|
|
5549
5989
|
if (!resourceState.routeActivated) {
|
|
5550
|
-
if (!resourceState.nativeSubagentMonitor) registerNativeSubagentMonitor(resourceState.thread.threadId);
|
|
5990
|
+
if (!resourceState.nativeSubagentMonitor) await registerNativeSubagentMonitor(resourceState.thread.threadId);
|
|
5551
5991
|
resourceState.detachRouteAbort = attachRouteAbort(resourceState.turnRoute);
|
|
5552
5992
|
await resourceState.turnRoute.activate({
|
|
5553
5993
|
onNotificationReceived: noteNotificationReceived,
|
|
@@ -5558,16 +5998,7 @@ async function prepareCodexAttemptRoute(resources, turnRuntime, notifications, h
|
|
|
5558
5998
|
}
|
|
5559
5999
|
return resourceState.turnRoute;
|
|
5560
6000
|
};
|
|
5561
|
-
|
|
5562
|
-
await ensureCurrentThreadRoute();
|
|
5563
|
-
} catch (error) {
|
|
5564
|
-
activateNativePreToolUseFailureFallback();
|
|
5565
|
-
releaseCurrentRoute();
|
|
5566
|
-
resourceState.nativeHookRelay?.unregister();
|
|
5567
|
-
await releaseSandboxExecEnvironment();
|
|
5568
|
-
releaseSharedClientLeaseOnce();
|
|
5569
|
-
throw error;
|
|
5570
|
-
}
|
|
6001
|
+
await ensureCurrentThreadRoute();
|
|
5571
6002
|
return { ensureCurrentThreadRoute };
|
|
5572
6003
|
}
|
|
5573
6004
|
//#endregion
|
|
@@ -5690,7 +6121,7 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
5690
6121
|
const authenticatedScheduledMode = params.trigger === "cron" && params.scheduledToolPolicy !== void 0 && Array.isArray(params.toolsAllow);
|
|
5691
6122
|
const scheduledConfiguredMcpSurface = authenticatedScheduledMode && (bundleMcpThreadConfig.staticServerNames.length > 0 || mutable.startupBinding?.configuredMcpOwnershipVersion === 1);
|
|
5692
6123
|
const cronCreatorAuthorityCapability = params.cronCreatorAuthorityCapability;
|
|
5693
|
-
const hasFreshCreatorAuthority = cronCreatorAuthorityCapability?.active === true && !(cronCreatorAuthorityCapability.
|
|
6124
|
+
const hasFreshCreatorAuthority = cronCreatorAuthorityCapability?.active === true && !(cronCreatorAuthorityCapability.managementEntitlement && cronCreatorAuthorityCapability.callerOrigin.kind === "unknown") && cronCreatorAuthorityCapability.runId === params.runId && !cronCreatorAuthorityCapability.signal.aborted;
|
|
5694
6125
|
const mayResolveScheduledConfiguredMcpCreatorAuthority = !authenticatedScheduledMode && canResolveScheduledConfiguredMcpCreatorAuthority({
|
|
5695
6126
|
trigger: params.trigger,
|
|
5696
6127
|
connectionClass: appServer.connectionClass,
|
|
@@ -5710,25 +6141,64 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
5710
6141
|
});
|
|
5711
6142
|
preDynamicStartupStages.mark("bundle-mcp");
|
|
5712
6143
|
const sandboxExecServerEnabled = isCodexSandboxExecServerEnabled(pluginConfig, sandbox);
|
|
5713
|
-
|
|
6144
|
+
let nativeToolSurfaceEnabled = shouldEnableCodexAppServerNativeToolSurface(runtimeParams, sandbox, {
|
|
5714
6145
|
agentId: policyAgentId,
|
|
5715
6146
|
runtimeSessionKey: sandboxSessionKey,
|
|
5716
6147
|
sandboxExecServerEnabled
|
|
5717
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
|
+
}
|
|
5718
6182
|
const configuredMcpSurface = scheduledConfiguredMcpSurface ? "scheduled" : !nativeToolSurfaceEnabled && bundleMcpThreadConfig.staticServerNames.length > 0 ? "transient" : void 0;
|
|
5719
6183
|
preDynamicStartupStages.mark("native-tool-surface");
|
|
5720
|
-
const
|
|
6184
|
+
const webSearchPlan = resolveCodexWebSearchPlan({
|
|
5721
6185
|
config: params.config,
|
|
5722
6186
|
disableTools: params.disableTools,
|
|
5723
6187
|
nativeToolSurfaceEnabled
|
|
5724
|
-
})
|
|
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({
|
|
5725
6194
|
clientFactory: attemptClientFactory,
|
|
5726
6195
|
appServer,
|
|
5727
6196
|
authProfileId: startupClientAuthProfileId,
|
|
5728
6197
|
preparedAuth: startupPreparedAuth,
|
|
5729
6198
|
agentDir,
|
|
5730
6199
|
config: params.config,
|
|
5731
|
-
|
|
6200
|
+
expectedNativeModelProvider: usesSupervisionConnection ? mutable.startupBinding?.modelProvider : void 0,
|
|
6201
|
+
modelProviderOverride: usesSupervisionConnection ? void 0 : resolveCodexAppServerThreadModelSelection({
|
|
5732
6202
|
provider: params.provider,
|
|
5733
6203
|
model: params.modelId,
|
|
5734
6204
|
binding: mutable.startupBinding,
|
|
@@ -5738,7 +6208,7 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
5738
6208
|
config: params.config
|
|
5739
6209
|
}).modelProvider,
|
|
5740
6210
|
signal: runAbortController.signal
|
|
5741
|
-
})
|
|
6211
|
+
});
|
|
5742
6212
|
preDynamicStartupStages.mark("provider-capabilities");
|
|
5743
6213
|
for (const diagnostic of bundleMcpThreadConfig.diagnostics) embeddedAgentLog.warn(`bundle-mcp: ${diagnostic.pluginId}: ${diagnostic.message}`);
|
|
5744
6214
|
if (activeContextEngine) assertContextEngineHostSupport({
|
|
@@ -5868,7 +6338,7 @@ const DYNAMIC_TOOL_TERMINAL_DIAGNOSTIC_TYPES = [
|
|
|
5868
6338
|
"tool.execution.error",
|
|
5869
6339
|
"tool.execution.blocked"
|
|
5870
6340
|
];
|
|
5871
|
-
function createCodexAttemptServerRequestController(resources, turnRuntime, lifecycle) {
|
|
6341
|
+
function createCodexAttemptServerRequestController(resources, turnRuntime, lifecycle, waitForNativeItems) {
|
|
5872
6342
|
const { prompt, state: resourceState, projectorRef, trajectoryRecorder } = resources;
|
|
5873
6343
|
const { context } = prompt;
|
|
5874
6344
|
const { runtime, attemptTools } = context;
|
|
@@ -5878,7 +6348,24 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
5878
6348
|
const { compactionPlanState, toolBridge, toolOutcomeOrdinals, suppressedDynamicToolOutcomeOrdinals, allocateCodexToolOutcomeOrdinal } = attemptTools;
|
|
5879
6349
|
const { state, turnIdRef, userInputBridgeRef, openClawDynamicToolExecutions, pendingOpenClawDynamicToolCompletionIds, noteProgress } = turnRuntime;
|
|
5880
6350
|
const { emitExecutionPhaseOnce, scheduleTurnReleaseAfterTerminalDynamicTool, scheduleTerminalDynamicToolReleaseCheck } = lifecycle;
|
|
5881
|
-
|
|
6351
|
+
let refreshDrain;
|
|
6352
|
+
let refreshStopping = false;
|
|
6353
|
+
const settlePluginRuntimeRefresh = async (turnId) => {
|
|
6354
|
+
if (!params.pluginRuntimeRefreshPending?.()) return;
|
|
6355
|
+
refreshDrain ??= createDeferred();
|
|
6356
|
+
state.pluginRuntimeRefreshStop = refreshDrain.promise;
|
|
6357
|
+
if (!refreshStopping && pendingOpenClawDynamicToolCompletionIds.size === 0) {
|
|
6358
|
+
refreshStopping = true;
|
|
6359
|
+
state.pendingTerminalDynamicToolRelease = void 0;
|
|
6360
|
+
turnRuntime.steeringQueueRef.current?.cancel();
|
|
6361
|
+
turnRuntime.interruptTurn(turnId, { locallyCompleted: true }).then(async (confirmed) => {
|
|
6362
|
+
if (!confirmed) throw new Error("Plugin reload could not confirm the previous Codex turn stopped.");
|
|
6363
|
+
await terminateCodexBackgroundTerminals(resourceState.client, resourceState.thread.threadId, params.oneShotCliRun === true, waitForNativeItems);
|
|
6364
|
+
}).then(refreshDrain.resolve, refreshDrain.reject).finally(turnRuntime.completeTurn);
|
|
6365
|
+
}
|
|
6366
|
+
await refreshDrain.promise;
|
|
6367
|
+
};
|
|
6368
|
+
const handleServerRequest = async (request, scope, requestSignal = new AbortController().signal, setExecutionTimeoutMs) => {
|
|
5882
6369
|
const signal = AbortSignal.any([runAbortController.signal, requestSignal]);
|
|
5883
6370
|
const turnId = turnIdRef.current;
|
|
5884
6371
|
const projector = projectorRef.current;
|
|
@@ -5905,17 +6392,11 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
5905
6392
|
signal
|
|
5906
6393
|
});
|
|
5907
6394
|
if (approvalResult.kind === "handled") return approvalResult.response;
|
|
5908
|
-
return await userInputBridgeRef.current?.handleElicitationRequest(
|
|
5909
|
-
id: request.id,
|
|
5910
|
-
params: request.params
|
|
5911
|
-
});
|
|
6395
|
+
return await userInputBridgeRef.current?.handleElicitationRequest(request, signal);
|
|
5912
6396
|
}
|
|
5913
6397
|
if (request.method === "item/tool/requestUserInput") {
|
|
5914
6398
|
if (scope.turnId === turnId) markCurrentTurnRequestProgress();
|
|
5915
|
-
return await userInputBridgeRef.current?.handleRequest(
|
|
5916
|
-
id: request.id,
|
|
5917
|
-
params: request.params
|
|
5918
|
-
});
|
|
6399
|
+
return await userInputBridgeRef.current?.handleRequest(request, signal);
|
|
5919
6400
|
}
|
|
5920
6401
|
if (request.method !== "item/tool/call") {
|
|
5921
6402
|
if (isCodexAppServerApprovalRequest(request.method)) {
|
|
@@ -5939,7 +6420,9 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
5939
6420
|
const replayedExecution = openClawDynamicToolExecutions.get(call);
|
|
5940
6421
|
if (replayedExecution) {
|
|
5941
6422
|
markCurrentTurnRequestProgress();
|
|
5942
|
-
|
|
6423
|
+
const response = await replayedExecution;
|
|
6424
|
+
await settlePluginRuntimeRefresh(turnId);
|
|
6425
|
+
return toCodexDynamicToolProtocolResponse(response);
|
|
5943
6426
|
}
|
|
5944
6427
|
const toolCallOrdinal = allocateCodexToolOutcomeOrdinal?.(call.callId);
|
|
5945
6428
|
markCurrentTurnRequestProgress();
|
|
@@ -5964,23 +6447,38 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
5964
6447
|
const toolMeta = inferCodexDynamicToolMeta(call, resolveCodexToolProgressDetailMode(params.toolProgressDetail));
|
|
5965
6448
|
const toolArgs = sanitizeCodexToolArguments(call.arguments);
|
|
5966
6449
|
const commandBearing = isCodexCommandBearingToolCall(call.tool, toolArgs);
|
|
5967
|
-
const shouldEmitDynamicToolProgress = shouldEmitTranscriptToolProgress(call.tool
|
|
5968
|
-
if (shouldEmitDynamicToolProgress)
|
|
5969
|
-
|
|
5970
|
-
data: {
|
|
5971
|
-
phase: "start",
|
|
5972
|
-
name: call.tool,
|
|
5973
|
-
itemId: call.callId,
|
|
6450
|
+
const shouldEmitDynamicToolProgress = shouldEmitTranscriptToolProgress(call.tool);
|
|
6451
|
+
if (shouldEmitDynamicToolProgress) {
|
|
6452
|
+
const activity = projectAgentToolActivity({
|
|
5974
6453
|
toolCallId: call.callId,
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
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
|
+
}
|
|
5980
6476
|
const dynamicToolTimeoutMs = resolveDynamicToolCallTimeoutMs({
|
|
5981
6477
|
call,
|
|
5982
|
-
config: params.config
|
|
6478
|
+
config: params.config,
|
|
6479
|
+
toolBridge
|
|
5983
6480
|
});
|
|
6481
|
+
setExecutionTimeoutMs?.(dynamicToolTimeoutMs);
|
|
5984
6482
|
const toolStartedAt = Date.now();
|
|
5985
6483
|
let terminalDiagnosticObserved = false;
|
|
5986
6484
|
const unsubscribeToolDiagnosticObserver = onInternalDiagnosticEvent((event) => {
|
|
@@ -6057,6 +6555,14 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6057
6555
|
}
|
|
6058
6556
|
if (shouldEmitDynamicToolProgress) {
|
|
6059
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
|
+
});
|
|
6060
6566
|
emitCodexAppServerEvent(params, {
|
|
6061
6567
|
stream: "tool",
|
|
6062
6568
|
data: {
|
|
@@ -6070,6 +6576,10 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6070
6576
|
result: toTranscriptToolResult(progressResponse)
|
|
6071
6577
|
}
|
|
6072
6578
|
});
|
|
6579
|
+
emitCodexAppServerEvent(params, {
|
|
6580
|
+
stream: "item",
|
|
6581
|
+
data: activity
|
|
6582
|
+
});
|
|
6073
6583
|
}
|
|
6074
6584
|
if (!terminalDiagnosticObserved && !hasPendingDynamicToolTerminalDiagnostic({
|
|
6075
6585
|
call,
|
|
@@ -6086,7 +6596,8 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6086
6596
|
durationMs: toolDurationMs
|
|
6087
6597
|
});
|
|
6088
6598
|
pendingOpenClawDynamicToolCompletionIds.delete(call.callId);
|
|
6089
|
-
if (
|
|
6599
|
+
if (params.pluginRuntimeRefreshPending?.()) await settlePluginRuntimeRefresh(turnId);
|
|
6600
|
+
else if (response.terminate === true && response.success) scheduleTurnReleaseAfterTerminalDynamicTool({
|
|
6090
6601
|
call,
|
|
6091
6602
|
response,
|
|
6092
6603
|
durationMs: toolDurationMs
|
|
@@ -6112,6 +6623,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6112
6623
|
sessionKey: params.sessionKey,
|
|
6113
6624
|
durationMs: Math.max(0, Date.now() - toolStartedAt)
|
|
6114
6625
|
});
|
|
6626
|
+
await settlePluginRuntimeRefresh(turnId);
|
|
6115
6627
|
throw error;
|
|
6116
6628
|
} finally {
|
|
6117
6629
|
toolOutcomeOrdinals.delete(call.callId);
|
|
@@ -6131,7 +6643,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6131
6643
|
//#region extensions/codex/src/app-server/attempt-runtime-artifact.ts
|
|
6132
6644
|
async function verifyStartupArtifact(params) {
|
|
6133
6645
|
if (!params.request) return;
|
|
6134
|
-
const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-
|
|
6646
|
+
const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-CLZ8udh-.mjs");
|
|
6135
6647
|
const runtimeArtifact = readCodexAppServerClientRuntimeArtifact(params.client);
|
|
6136
6648
|
const expected = params.request.expected;
|
|
6137
6649
|
const matchesExpected = !expected || runtimeArtifact?.id === expected.id && runtimeArtifact.fingerprint === expected.fingerprint;
|
|
@@ -6154,7 +6666,7 @@ function startCodexComputerUseHealthMonitor(params) {
|
|
|
6154
6666
|
reason: params.config.enabled ? "health_disabled" : "disabled"
|
|
6155
6667
|
};
|
|
6156
6668
|
}
|
|
6157
|
-
const fingerprint = buildComputerUseHealthMonitorFingerprint(params.config);
|
|
6669
|
+
const fingerprint = buildComputerUseHealthMonitorFingerprint(params.config, params.tools);
|
|
6158
6670
|
const intervalMs = params.config.healthCheckIntervalMinutes * 6e4;
|
|
6159
6671
|
if (existing?.fingerprint === fingerprint) return {
|
|
6160
6672
|
started: false,
|
|
@@ -6166,7 +6678,7 @@ function startCodexComputerUseHealthMonitor(params) {
|
|
|
6166
6678
|
fingerprint,
|
|
6167
6679
|
intervalMs,
|
|
6168
6680
|
timer: setInterval(() => {
|
|
6169
|
-
runCodexComputerUseHealthProbe(params.client, params.config, monitor);
|
|
6681
|
+
runCodexComputerUseHealthProbe(params.client, params.config, monitor, params.tools);
|
|
6170
6682
|
}, intervalMs),
|
|
6171
6683
|
disposeCloseHandler: () => void 0,
|
|
6172
6684
|
running: false
|
|
@@ -6182,22 +6694,28 @@ function startCodexComputerUseHealthMonitor(params) {
|
|
|
6182
6694
|
intervalMs
|
|
6183
6695
|
};
|
|
6184
6696
|
}
|
|
6185
|
-
function buildComputerUseHealthMonitorFingerprint(config) {
|
|
6697
|
+
function buildComputerUseHealthMonitorFingerprint(config, tools) {
|
|
6186
6698
|
return JSON.stringify({
|
|
6187
6699
|
autoRepair: config.autoRepair,
|
|
6188
6700
|
healthCheckIntervalMinutes: config.healthCheckIntervalMinutes,
|
|
6189
6701
|
liveTestTimeoutMs: config.liveTestTimeoutMs,
|
|
6190
6702
|
mcpServerName: config.mcpServerName,
|
|
6191
|
-
toolCallTimeoutMs: config.toolCallTimeoutMs
|
|
6703
|
+
toolCallTimeoutMs: config.toolCallTimeoutMs,
|
|
6704
|
+
tools: tools?.toSorted()
|
|
6192
6705
|
});
|
|
6193
6706
|
}
|
|
6194
|
-
async function runCodexComputerUseHealthProbe(client, config, monitor) {
|
|
6707
|
+
async function runCodexComputerUseHealthProbe(client, config, monitor, tools) {
|
|
6195
6708
|
if (monitor.running) return;
|
|
6196
6709
|
monitor.running = true;
|
|
6197
6710
|
try {
|
|
6198
6711
|
const { liveTest, repair } = await runCodexComputerUseLiveTest({
|
|
6712
|
+
client,
|
|
6199
6713
|
config,
|
|
6200
|
-
|
|
6714
|
+
tools,
|
|
6715
|
+
request: async (method, requestParams, requestOptions) => await client.request(method, requestParams, {
|
|
6716
|
+
timeoutMs: requestOptions?.timeoutMs ?? config.liveTestTimeoutMs,
|
|
6717
|
+
...requestOptions?.signal ? { signal: requestOptions.signal } : {}
|
|
6718
|
+
})
|
|
6201
6719
|
});
|
|
6202
6720
|
if (!liveTest.ok) {
|
|
6203
6721
|
embeddedAgentLog.warn("codex computer-use periodic health failed", {
|
|
@@ -6399,6 +6917,7 @@ async function startCodexAttemptThread(params) {
|
|
|
6399
6917
|
try {
|
|
6400
6918
|
const attemptParams = params.buildAttemptParams();
|
|
6401
6919
|
params.assertCurrent?.();
|
|
6920
|
+
if (startupAbandonController.signal.aborted) throw new CodexAppServerStartupError("aborted");
|
|
6402
6921
|
startupClient = await params.attemptClientFactory({
|
|
6403
6922
|
assertCurrent: params.assertCurrent,
|
|
6404
6923
|
startOptions: params.appServer.start,
|
|
@@ -6447,15 +6966,16 @@ async function startCodexAttemptThread(params) {
|
|
|
6447
6966
|
config: params.config
|
|
6448
6967
|
});
|
|
6449
6968
|
const turnRouter = getCodexAppServerTurnRouter(activeStartupClient);
|
|
6969
|
+
let computerUseTools = [];
|
|
6450
6970
|
try {
|
|
6451
|
-
await ensureCodexComputerUse({
|
|
6971
|
+
computerUseTools = (await ensureCodexComputerUse({
|
|
6452
6972
|
client: activeStartupClient,
|
|
6453
6973
|
pluginConfig: params.pluginConfig,
|
|
6454
6974
|
config: params.config,
|
|
6455
6975
|
agentDir: params.agentDir,
|
|
6456
6976
|
timeoutMs: params.appServer.requestTimeoutMs,
|
|
6457
6977
|
signal: startupAbandonController.signal
|
|
6458
|
-
});
|
|
6978
|
+
})).tools;
|
|
6459
6979
|
} catch (error) {
|
|
6460
6980
|
if (startupAbandonController.signal.aborted || isCodexAppServerStartSelectionChangedError(error)) throw error;
|
|
6461
6981
|
throw new AgentHarnessPreflightError(`Codex Computer Use readiness failed: ${formatErrorMessage(error)}`, {
|
|
@@ -6517,7 +7037,8 @@ async function startCodexAttemptThread(params) {
|
|
|
6517
7037
|
appServerStartOptions: params.appServer.start,
|
|
6518
7038
|
timeoutMs: params.appServer.requestTimeoutMs,
|
|
6519
7039
|
signal: AbortSignal.any([params.signal, startupAbandonController.signal]),
|
|
6520
|
-
onExecutionDisconnect: params.onExecutionDisconnect
|
|
7040
|
+
onExecutionDisconnect: params.onExecutionDisconnect,
|
|
7041
|
+
requireProcessAuthority: Boolean(attemptParams.hostCapabilities.retainSourceAuthority)
|
|
6521
7042
|
}) : void 0;
|
|
6522
7043
|
startupSandboxEnvironmentAcquired = Boolean(startupSandboxEnvironment);
|
|
6523
7044
|
if (startupAbandonController.signal.aborted) throw new CodexAppServerStartupError("aborted");
|
|
@@ -6617,7 +7138,8 @@ async function startCodexAttemptThread(params) {
|
|
|
6617
7138
|
startupSandboxEnvironmentAcquired = false;
|
|
6618
7139
|
startCodexComputerUseHealthMonitor({
|
|
6619
7140
|
client: activeStartupClient,
|
|
6620
|
-
config: params.computerUseConfig
|
|
7141
|
+
config: params.computerUseConfig,
|
|
7142
|
+
tools: computerUseTools
|
|
6621
7143
|
});
|
|
6622
7144
|
startupAttemptSucceeded = true;
|
|
6623
7145
|
return {
|
|
@@ -6652,7 +7174,6 @@ async function startCodexAttemptThread(params) {
|
|
|
6652
7174
|
const sharedClient = clearSharedCodexAppServerClientIfCurrentAndUnclaimed(startupClientForAbandonedRequestCleanup);
|
|
6653
7175
|
if (sharedClient.found && !sharedClient.closed) startupClientForAbandonedRequestCleanup = void 0;
|
|
6654
7176
|
}
|
|
6655
|
-
throw error;
|
|
6656
7177
|
} finally {
|
|
6657
7178
|
if (!startupAttemptSucceeded) {
|
|
6658
7179
|
if (releaseSharedClientLease === startupClientLease) releaseSharedClientLease = void 0;
|
|
@@ -6663,13 +7184,20 @@ async function startCodexAttemptThread(params) {
|
|
|
6663
7184
|
}
|
|
6664
7185
|
}
|
|
6665
7186
|
}
|
|
7187
|
+
if (startupAttemptError instanceof CodexThreadClientReplacementError && startupClient) {
|
|
7188
|
+
if (!(await startupClient.closeAndWait()).exited) throw new AgentHarnessPreflightError("The previous conversation process did not confirm shutdown; the conversation was preserved.");
|
|
7189
|
+
}
|
|
7190
|
+
throw startupAttemptError;
|
|
6666
7191
|
};
|
|
7192
|
+
let replacedSettledFailureClient = false;
|
|
6667
7193
|
for (let attempt = 1; attempt <= CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS; attempt += 1) try {
|
|
6668
7194
|
return await startupAttempt();
|
|
6669
7195
|
} catch (error) {
|
|
6670
7196
|
const selectionChanged = isCodexAppServerStartSelectionChangedError(error);
|
|
6671
|
-
|
|
6672
|
-
|
|
7197
|
+
const clientRetired = error instanceof CodexThreadClientReplacementError;
|
|
7198
|
+
if (startupAbandonController.signal.aborted || clientRetired && replacedSettledFailureClient || !clientRetired && !selectionChanged && !isCodexAppServerConnectionClosedError(error)) throw error;
|
|
7199
|
+
replacedSettledFailureClient ||= clientRetired;
|
|
7200
|
+
const refreshedSharedClient = clientRetired ? void 0 : selectionChanged ? retireSharedCodexAppServerClientIfCurrent(attemptedClient) : clearSharedCodexAppServerClientIfCurrent(attemptedClient);
|
|
6673
7201
|
if (startupClientForAbandonedRequestCleanup === attemptedClient) startupClientForAbandonedRequestCleanup = void 0;
|
|
6674
7202
|
if (attempt >= CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS) {
|
|
6675
7203
|
embeddedAgentLog.warn(selectionChanged ? "codex app-server executable selection kept changing during startup; retries exhausted" : "codex app-server connection closed during startup; retries exhausted", {
|
|
@@ -6680,8 +7208,8 @@ async function startCodexAttemptThread(params) {
|
|
|
6680
7208
|
});
|
|
6681
7209
|
throw error;
|
|
6682
7210
|
}
|
|
6683
|
-
const retryDelayMs = selectionChanged ? 0 : 1e3 * 2 ** (attempt - 1);
|
|
6684
|
-
embeddedAgentLog.warn(selectionChanged ? "codex app-server executable selection changed during startup; restarting app-server and retrying" : "codex app-server connection closed during startup; restarting app-server and retrying", {
|
|
7211
|
+
const retryDelayMs = selectionChanged || clientRetired ? 0 : 1e3 * 2 ** (attempt - 1);
|
|
7212
|
+
embeddedAgentLog.warn(clientRetired ? "codex app-server retired a settled failed client; resuming on a fresh client" : selectionChanged ? "codex app-server executable selection changed during startup; restarting app-server and retrying" : "codex app-server connection closed during startup; restarting app-server and retrying", {
|
|
6685
7213
|
attempt,
|
|
6686
7214
|
nextAttempt: attempt + 1,
|
|
6687
7215
|
maxAttempts: CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS,
|
|
@@ -6712,14 +7240,10 @@ async function startCodexAttemptThread(params) {
|
|
|
6712
7240
|
params.signal.removeEventListener("abort", abandonStartupAcquire);
|
|
6713
7241
|
}
|
|
6714
7242
|
}
|
|
6715
|
-
function shouldRetireCodexStartupClient(error, spawnedBy, signal) {
|
|
6716
|
-
if (signal.aborted || isCodexAppServerStartupError(error) || isCodexAppServerRequestTimeoutError(error)) return true;
|
|
6717
|
-
return !isCodexAppServerStartSelectionChangedError(error) && !isCodexAppServerOverloadError(error) && !(error instanceof AgentHarnessPreflightError && error.scope === void 0) && (isCodexAppServerBrokenPipeError(error) || !spawnedBy);
|
|
6718
|
-
}
|
|
6719
7243
|
//#endregion
|
|
6720
7244
|
//#region extensions/codex/src/app-server/run-attempt-start.ts
|
|
6721
7245
|
async function startCodexAttemptRuntime(resources) {
|
|
6722
|
-
const { prompt, state, trajectoryRecorder,
|
|
7246
|
+
const { prompt, state, trajectoryRecorder, startupTimeoutMs, buildNativeHookRelayFinalConfigPatch } = resources;
|
|
6723
7247
|
const { context, turnState, rebuildCodexTurnPromptTextFromCurrentProjection, applyNoContextEngineContinuityProjection } = prompt;
|
|
6724
7248
|
const { runtime, attemptTools, promptState } = context;
|
|
6725
7249
|
const { connection, runtimeParams, preparedAuthBinding, buildActiveRunAttemptParams, startupAuthAccountCacheKey, startupEnvApiKeyCacheKey, bundleMcpThreadConfig, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, effectiveRuntimeModelId, sandboxExecServerEnabled } = runtime;
|
|
@@ -6763,7 +7287,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
6763
7287
|
developerInstructions,
|
|
6764
7288
|
agentWorkspaceDeveloperInstructions: context.agentWorkspaceDeveloperInstructions,
|
|
6765
7289
|
buildFinalConfigPatch: buildNativeHookRelayFinalConfigPatch,
|
|
6766
|
-
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),
|
|
6767
7291
|
bundleMcpThreadConfig,
|
|
6768
7292
|
configuredMcpDynamicSurface: attemptTools.configuredMcp !== void 0,
|
|
6769
7293
|
configuredMcpOwnershipVersion: attemptTools.configuredMcpOwnershipVersion,
|
|
@@ -6803,10 +7327,11 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
6803
7327
|
if (usesSupervisionConnection && (state.thread.connectionScope !== "supervision" || state.thread.supervisionSourceThreadId !== connection.mutable.startupBinding?.supervisionSourceThreadId)) throw new Error("Codex supervised thread lost its private connection ownership");
|
|
6804
7328
|
if (state.thread.lifecycle.action === "started" || state.thread.lifecycle.action === "forked") {
|
|
6805
7329
|
const activePolicy = resolveReviewerPolicyContext(state.thread);
|
|
6806
|
-
const activeConfig = resolveRuntimeOptionsForCurrentBinding({
|
|
7330
|
+
const activeConfig = await resolveRuntimeOptionsForCurrentBinding({
|
|
6807
7331
|
modelProvider: activePolicy.modelProvider,
|
|
6808
7332
|
model: activePolicy.model
|
|
6809
7333
|
});
|
|
7334
|
+
connection.assertCurrent();
|
|
6810
7335
|
const activeAppServer = resolveCodexAppServerForModelProvider({
|
|
6811
7336
|
appServer: activeConfig,
|
|
6812
7337
|
provider: activePolicy.modelProvider,
|
|
@@ -6847,14 +7372,8 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
6847
7372
|
toolCount: flattenCodexDynamicToolFunctions(toolBridge.specs).length
|
|
6848
7373
|
});
|
|
6849
7374
|
connection.mutable.pluginAppServer = pluginAppServer;
|
|
7375
|
+
await resources.registerNativeSubagentMonitor(state.thread.threadId);
|
|
6850
7376
|
} catch (error) {
|
|
6851
|
-
await runCleanupStep("codex-start-failure-hook-fallback", activateNativePreToolUseFailureFallback);
|
|
6852
|
-
await runCleanupStep("codex-start-failure-route-release", releaseCurrentRoute);
|
|
6853
|
-
const nativeHookRelay = state.nativeHookRelay;
|
|
6854
|
-
state.nativeHookRelay = void 0;
|
|
6855
|
-
await runCleanupStep("codex-start-failure-native-hook-relay", () => nativeHookRelay?.unregister());
|
|
6856
|
-
await runCleanupStep("codex-start-failure-sandbox-release", releaseSandboxExecEnvironment);
|
|
6857
|
-
await runCleanupStep("codex-start-failure-shared-client-release", releaseSharedClientLeaseAndRetireOneShotClient);
|
|
6858
7377
|
throw error instanceof CodexThreadPolicyHandoffError ? error : state.executionDisconnectError ?? error;
|
|
6859
7378
|
}
|
|
6860
7379
|
}
|
|
@@ -7005,93 +7524,103 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7005
7524
|
}
|
|
7006
7525
|
}
|
|
7007
7526
|
let requireExplicitMessageTarget;
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
}
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
|
|
7084
|
-
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
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
|
+
}
|
|
7540
|
+
});
|
|
7541
|
+
for (const [step, materialized] of [["codex-scoped-mcp-dispose", scopedMcpTools], ["codex-configured-mcp-dispose", configuredMcp]]) await runAgentCleanupStep({
|
|
7542
|
+
runId: params.runId,
|
|
7543
|
+
sessionId: params.sessionId,
|
|
7544
|
+
step,
|
|
7545
|
+
log: embeddedAgentLog,
|
|
7546
|
+
cleanup: async () => materialized?.dispose()
|
|
7547
|
+
});
|
|
7548
|
+
})();
|
|
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) => {
|
|
7095
7624
|
const allowedDecisions = approval.mode === "prompt" ? ["allow-once", "deny"] : [
|
|
7096
7625
|
"allow-once",
|
|
7097
7626
|
"allow-always",
|
|
@@ -7112,21 +7641,41 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7112
7641
|
isMcpToolApprovalActive: approval.isActive
|
|
7113
7642
|
});
|
|
7114
7643
|
if (outcome !== "approved-once" && outcome !== "approved-session") throw new Error(`${approval.serverName}/${approval.toolName}: interactive Codex approval (${approval.mode}) was not granted: ${outcome}`);
|
|
7115
|
-
}
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
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({
|
|
7123
7663
|
sessionId: params.sessionId,
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
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;
|
|
7130
7679
|
scopedMcpTools = authenticatedScheduledMode ? void 0 : await materializeRequesterScopedMcpToolsForHarnessRun({
|
|
7131
7680
|
sessionId: params.sessionId,
|
|
7132
7681
|
sessionKey: params.sessionKey,
|
|
@@ -7135,6 +7684,8 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7135
7684
|
cfg: params.config,
|
|
7136
7685
|
manifestRegistry: bundleManifestRegistry,
|
|
7137
7686
|
toolOverrides: codexMcpToolOverrides,
|
|
7687
|
+
autoApproveCodexAppServerApprovals: shouldAutoApproveCodexAppServerApprovals(connection.appServer),
|
|
7688
|
+
requestInteractiveCodexApproval: requestRequesterMcpApproval,
|
|
7138
7689
|
requesterSenderId: params.senderId,
|
|
7139
7690
|
agentAccountId: params.agentAccountId,
|
|
7140
7691
|
messageChannel: params.messageChannel ?? params.messageProvider,
|
|
@@ -7212,7 +7763,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7212
7763
|
agentDir: policyContext.agentDir,
|
|
7213
7764
|
cfg: params.config,
|
|
7214
7765
|
manifestRegistry: bundleManifestRegistry,
|
|
7215
|
-
reservedToolNames: toolBridge.availableTools.map((tool) => tool.name),
|
|
7766
|
+
reservedToolNames: configuredMcp ? reservedToolNames : toolBridge.availableTools.map((tool) => tool.name),
|
|
7216
7767
|
toolsAllow: params.toolsAllow,
|
|
7217
7768
|
toolOverrides: codexMcpToolOverrides,
|
|
7218
7769
|
autoApproveCodexAppServerApprovals: shouldAutoApproveCodexAppServerApprovals(connection.appServer),
|
|
@@ -7251,14 +7802,13 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7251
7802
|
requireExplicitMessageTarget,
|
|
7252
7803
|
scopedMcpTools,
|
|
7253
7804
|
configuredMcp,
|
|
7254
|
-
|
|
7805
|
+
disposeTools,
|
|
7255
7806
|
configuredMcpOwnershipVersion: configuredMcpSurface === "scheduled" ? 1 : void 0,
|
|
7256
7807
|
captureCronCreatorToolAllowlist,
|
|
7257
7808
|
scheduledAppAuthoritySourceRef,
|
|
7258
7809
|
dynamicToolParams,
|
|
7259
7810
|
compactionPlanState,
|
|
7260
7811
|
computerContextEpoch,
|
|
7261
|
-
runCleanups,
|
|
7262
7812
|
toolBridge,
|
|
7263
7813
|
toolState,
|
|
7264
7814
|
toolOutcomeOrdinals,
|
|
@@ -7268,7 +7818,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7268
7818
|
runtimeYieldCompletionClaim
|
|
7269
7819
|
};
|
|
7270
7820
|
} catch (error) {
|
|
7271
|
-
await
|
|
7821
|
+
await disposeTools("error");
|
|
7272
7822
|
throw error;
|
|
7273
7823
|
}
|
|
7274
7824
|
}
|
|
@@ -7302,10 +7852,102 @@ async function resolveCodexExplicitSkillInputs(params) {
|
|
|
7302
7852
|
}
|
|
7303
7853
|
}
|
|
7304
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
|
|
7305
7947
|
//#region extensions/codex/src/app-server/run-attempt-turn-request.ts
|
|
7306
7948
|
async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurrentThreadRoute, waitForActiveNativeTurnCompletion) {
|
|
7307
7949
|
const { prompt, state: resourceState, releaseCurrentRoute } = resources;
|
|
7308
|
-
const { context, turnState, buildRenderedCodexDeveloperInstructions } = prompt;
|
|
7950
|
+
const { context, turnState, buildRenderedCodexDeveloperInstructions, nativeHistoryProvenancePrefix } = prompt;
|
|
7309
7951
|
const { runtime, attemptTools, hookContextWindowFields, workspaceBootstrapContext } = context;
|
|
7310
7952
|
const { connection, runtimeParams, effectiveRuntimeProviderId, effectiveRuntimeModelId } = runtime;
|
|
7311
7953
|
const { tools, toolBridge } = attemptTools;
|
|
@@ -7359,19 +8001,25 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
|
|
|
7359
8001
|
const startCodexTurn = async () => {
|
|
7360
8002
|
const activeTurnRoute = await ensureCurrentThreadRoute();
|
|
7361
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
|
+
};
|
|
7362
8012
|
const turnAppServer = withCodexAppServerFastModeServiceTier(connection.mutable.pluginAppServer, runtimeParams);
|
|
7363
8013
|
connection.mutable.pluginAppServer = turnAppServer;
|
|
7364
8014
|
const references = prepareWorkspaceReferences();
|
|
7365
|
-
const referencesRetained = turnState.codexTurnPromptText.includes(workspaceBootstrapContext.promptContext ?? "");
|
|
7366
8015
|
const inferenceRoute = usesSupervisionConnection ? void 0 : getCodexInferenceThread(resourceState.client, resourceState.thread.threadId);
|
|
7367
|
-
const turnStartParams = buildTurnStartParams({
|
|
7368
|
-
...runtimeParams,
|
|
7369
|
-
images: [...prompt.contextImages, ...runtimeParams.images ?? []]
|
|
7370
|
-
}, {
|
|
8016
|
+
const turnStartParams = buildTurnStartParams(runtimeParams, {
|
|
7371
8017
|
threadId: resourceState.thread.threadId,
|
|
7372
8018
|
cwd: resourceState.codexExecutionCwd,
|
|
7373
8019
|
appServer: turnAppServer,
|
|
7374
8020
|
promptText: turnState.codexTurnPromptText,
|
|
8021
|
+
historyProvenancePrefix: nativeHistoryProvenancePrefix,
|
|
8022
|
+
contextImageGroups: prompt.contextImageGroups,
|
|
7375
8023
|
explicitSkillInputs,
|
|
7376
8024
|
sandboxPolicy: resourceState.codexSandboxPolicy,
|
|
7377
8025
|
environmentSelection: resourceState.codexEnvironmentSelection,
|
|
@@ -7427,6 +8075,17 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
|
|
|
7427
8075
|
truncated: null
|
|
7428
8076
|
} : file);
|
|
7429
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
|
+
});
|
|
7430
8089
|
codexModelCallDiagnostics.setRequestPayloadBytes(utf8JsonByteLength(turnStartParams));
|
|
7431
8090
|
recordCodexTrajectoryContext(resources.trajectoryRecorder, {
|
|
7432
8091
|
attempt: params,
|
|
@@ -7450,29 +8109,41 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
|
|
|
7450
8109
|
}
|
|
7451
8110
|
});
|
|
7452
8111
|
let acceptedTurnId;
|
|
8112
|
+
const upstreamUserText = turnStartParams.input.flatMap((item) => item.type === "text" ? [item.text] : []).join("\n");
|
|
7453
8113
|
try {
|
|
7454
|
-
const startedTurn = assertCodexTurnStartResponse(await
|
|
8114
|
+
const startedTurn = assertCodexTurnStartResponse(await turnClient.request("turn/start", turnStartParams, {
|
|
7455
8115
|
timeoutMs: params.timeoutMs,
|
|
7456
8116
|
signal: runAbortController.signal,
|
|
7457
|
-
assertCurrent:
|
|
8117
|
+
assertCurrent: () => {
|
|
8118
|
+
assertTurnCurrent();
|
|
8119
|
+
continuation?.dispatch();
|
|
8120
|
+
}
|
|
7458
8121
|
}));
|
|
7459
8122
|
acceptedTurnId = startedTurn.turn.id;
|
|
7460
|
-
|
|
7461
|
-
|
|
8123
|
+
resources.nativeProcessAuthority?.bindTurn(turnClient, threadId, acceptedTurnId);
|
|
8124
|
+
assertTurnCurrent();
|
|
8125
|
+
if (upstreamUserText.includes(workspaceBootstrapContext.promptContext ?? "")) references.accepted();
|
|
7462
8126
|
throwIfTurnStartAcceptedAfterAbort();
|
|
7463
|
-
|
|
8127
|
+
await continuation?.accept(acceptedTurnId);
|
|
8128
|
+
return {
|
|
8129
|
+
turn: startedTurn,
|
|
8130
|
+
upstreamUserText
|
|
8131
|
+
};
|
|
7464
8132
|
} catch (error) {
|
|
7465
8133
|
if (acceptedTurnId || isCodexAppServerIndeterminateRequestCancellationError(error)) try {
|
|
7466
|
-
resourceState.startupClientUnsafe = !await interruptCodexTurnAndWaitBestEffort(
|
|
7467
|
-
threadId
|
|
8134
|
+
resourceState.startupClientUnsafe = !await interruptCodexTurnAndWaitBestEffort(turnClient, {
|
|
8135
|
+
threadId,
|
|
7468
8136
|
turnId: acceptedTurnId ?? ""
|
|
7469
8137
|
});
|
|
7470
|
-
if (resourceState.startupClientUnsafe) await retireUnsafeCodexTurnClientBestEffort(
|
|
8138
|
+
if (resourceState.startupClientUnsafe) await retireUnsafeCodexTurnClientBestEffort(turnClient, "startup interrupt");
|
|
7471
8139
|
} finally {
|
|
7472
|
-
releaseCurrentRoute();
|
|
8140
|
+
await releaseCurrentRoute();
|
|
7473
8141
|
}
|
|
7474
8142
|
else await activeTurnRoute.cancelTurn();
|
|
8143
|
+
if (params.providerReviewAcknowledgment) throw new Error("Could not continue this chat. Review its latest status before trying again.");
|
|
7475
8144
|
throw error;
|
|
8145
|
+
} finally {
|
|
8146
|
+
continuation?.dispose();
|
|
7476
8147
|
}
|
|
7477
8148
|
};
|
|
7478
8149
|
if (resourceState.thread.lifecycle.action === "resumed" && (resourceState.thread.lifecycle.activeTurnIds?.length ?? 0) > 0) {
|
|
@@ -7496,7 +8167,7 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
|
|
|
7496
8167
|
systemPrompt: buildRenderedCodexDeveloperInstructions(),
|
|
7497
8168
|
prompt: turnState.codexTurnPromptText,
|
|
7498
8169
|
historyMessages: prompt.codexModelInputHistoryMessages,
|
|
7499
|
-
imagesCount: prompt.
|
|
8170
|
+
imagesCount: prompt.contextImageGroups.reduce((count, group) => count + group.images.length, 0) + (params.images?.length ?? 0),
|
|
7500
8171
|
tools
|
|
7501
8172
|
});
|
|
7502
8173
|
return {
|
|
@@ -7508,7 +8179,7 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
|
|
|
7508
8179
|
//#endregion
|
|
7509
8180
|
//#region extensions/codex/src/app-server/run-attempt-turn-start.ts
|
|
7510
8181
|
async function startCodexAttemptTurn(resources, turnRuntime, notifications, requestRuntime) {
|
|
7511
|
-
const { prompt, state: resourceState, trajectoryRecorder, markTrajectoryEndRecorded
|
|
8182
|
+
const { prompt, state: resourceState, trajectoryRecorder, markTrajectoryEndRecorded } = resources;
|
|
7512
8183
|
const { context, turnState, systemPromptReport } = prompt;
|
|
7513
8184
|
const { runtime, historyState, hookContext, hookContextWindowFields, hookRunner } = context;
|
|
7514
8185
|
const { connection, runtimeParams, effectiveRuntimeProviderId, effectiveRuntimeModelId } = runtime;
|
|
@@ -7516,7 +8187,8 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
7516
8187
|
const { state, turnIdRef } = turnRuntime;
|
|
7517
8188
|
const { waitForActiveNativeTurnCompletion } = notifications;
|
|
7518
8189
|
const { codexModelCallDiagnostics, startCodexTurn, buildLlmInputEvent } = requestRuntime;
|
|
7519
|
-
let
|
|
8190
|
+
let started;
|
|
8191
|
+
resourceState.turnStartAttempted = true;
|
|
7520
8192
|
try {
|
|
7521
8193
|
codexModelCallDiagnostics.emitStarted();
|
|
7522
8194
|
runAgentHarnessLlmInputHook({
|
|
@@ -7524,10 +8196,10 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
7524
8196
|
ctx: hookContext,
|
|
7525
8197
|
hookRunner
|
|
7526
8198
|
});
|
|
7527
|
-
|
|
8199
|
+
started = await startCodexTurn();
|
|
7528
8200
|
} catch (error) {
|
|
7529
8201
|
let turnStartError = error;
|
|
7530
|
-
if (isCodexActiveCompactTurnError(turnStartError)) {
|
|
8202
|
+
if (!params.providerReviewAcknowledgment && isCodexActiveCompactTurnError(turnStartError)) {
|
|
7531
8203
|
embeddedAgentLog.info("codex app-server turn/start blocked by active compact turn; waiting to retry", { threadId: resourceState.thread.threadId });
|
|
7532
8204
|
if (await waitForActiveNativeTurnCompletion() && !runAbortController.signal.aborted) {
|
|
7533
8205
|
emitCodexAppServerEvent(params, {
|
|
@@ -7538,13 +8210,13 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
7538
8210
|
}
|
|
7539
8211
|
});
|
|
7540
8212
|
try {
|
|
7541
|
-
|
|
8213
|
+
started = await startCodexTurn();
|
|
7542
8214
|
} catch (retryError) {
|
|
7543
8215
|
turnStartError = retryError;
|
|
7544
8216
|
}
|
|
7545
8217
|
}
|
|
7546
8218
|
}
|
|
7547
|
-
if (
|
|
8219
|
+
if (started === void 0 && !params.providerReviewAcknowledgment && resourceState.thread.connectionScope !== "supervision" && shouldUseFreshCodexThreadAfterContextEngineOverflow({
|
|
7548
8220
|
error: turnStartError,
|
|
7549
8221
|
contextEngineActive: Boolean(activeContextEngine),
|
|
7550
8222
|
thread: resourceState.thread
|
|
@@ -7586,7 +8258,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
7586
8258
|
}
|
|
7587
8259
|
});
|
|
7588
8260
|
try {
|
|
7589
|
-
|
|
8261
|
+
started = await startCodexTurn();
|
|
7590
8262
|
} catch (retryError) {
|
|
7591
8263
|
turnStartError = retryError;
|
|
7592
8264
|
}
|
|
@@ -7594,7 +8266,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
7594
8266
|
} catch (retrySetupError) {
|
|
7595
8267
|
turnStartError = retrySetupError;
|
|
7596
8268
|
}
|
|
7597
|
-
if (
|
|
8269
|
+
if (started === void 0) {
|
|
7598
8270
|
const usageLimitError = await formatCodexTurnStartUsageLimitError({
|
|
7599
8271
|
client: resourceState.client,
|
|
7600
8272
|
error: turnStartError,
|
|
@@ -7604,7 +8276,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
7604
8276
|
signal: runAbortController.signal
|
|
7605
8277
|
});
|
|
7606
8278
|
const message = usageLimitError?.message ?? formatErrorMessage(turnStartError);
|
|
7607
|
-
if (isInvalidCodexImagePayloadError(message)) await clearCodexBindingAfterInvalidImagePayload(bindingStore, bindingIdentity, {
|
|
8279
|
+
if (!params.providerReviewAcknowledgment && isInvalidCodexImagePayloadError(message)) await clearCodexBindingAfterInvalidImagePayload(bindingStore, bindingIdentity, {
|
|
7608
8280
|
phase: "turn_start",
|
|
7609
8281
|
threadId: resourceState.thread.threadId,
|
|
7610
8282
|
error: message
|
|
@@ -7661,33 +8333,6 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
7661
8333
|
ctx: hookContext,
|
|
7662
8334
|
hookRunner
|
|
7663
8335
|
});
|
|
7664
|
-
if ((isIncognitoSessionKey(params.sessionKey) ? await bindingStore.mutate(bindingIdentity, {
|
|
7665
|
-
kind: "clear",
|
|
7666
|
-
threadId: resourceState.thread.threadId
|
|
7667
|
-
}) : true) && !resourceState.startupClientUnsafe) {
|
|
7668
|
-
if (!await unsubscribeCodexThreadBestEffort(resourceState.client, {
|
|
7669
|
-
threadId: resourceState.thread.threadId,
|
|
7670
|
-
timeoutMs: 5e3
|
|
7671
|
-
})) await runAgentCleanupStep({
|
|
7672
|
-
runId: params.runId,
|
|
7673
|
-
sessionId: params.sessionId,
|
|
7674
|
-
step: "codex-retire-unsafe-startup-client",
|
|
7675
|
-
log: embeddedAgentLog,
|
|
7676
|
-
cleanup: async () => closeCodexStartupClientBestEffort(resourceState.client)
|
|
7677
|
-
});
|
|
7678
|
-
}
|
|
7679
|
-
releaseCurrentRoute();
|
|
7680
|
-
activateNativePreToolUseFailureFallback();
|
|
7681
|
-
resourceState.nativeHookRelay?.unregister();
|
|
7682
|
-
await releaseSandboxExecEnvironment();
|
|
7683
|
-
await runAgentCleanupStep({
|
|
7684
|
-
runId: params.runId,
|
|
7685
|
-
sessionId: params.sessionId,
|
|
7686
|
-
step: "codex-trajectory-flush-startup-failure",
|
|
7687
|
-
log: embeddedAgentLog,
|
|
7688
|
-
cleanup: async () => trajectoryRecorder?.flush()
|
|
7689
|
-
});
|
|
7690
|
-
await releaseSharedClientLeaseAndRetireOneShotClient();
|
|
7691
8336
|
if (usageLimitError) {
|
|
7692
8337
|
await markCodexAuthProfileBlockedFromRateLimits({
|
|
7693
8338
|
params,
|
|
@@ -7719,11 +8364,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
7719
8364
|
throw turnStartError;
|
|
7720
8365
|
}
|
|
7721
8366
|
}
|
|
7722
|
-
if (!turn)
|
|
7723
|
-
activateNativePreToolUseFailureFallback();
|
|
7724
|
-
await releaseSharedClientLeaseAndRetireOneShotClient();
|
|
7725
|
-
throw new Error("codex app-server turn/start failed without an error");
|
|
7726
|
-
}
|
|
8367
|
+
if (!started) throw new Error("codex app-server turn/start failed without an error");
|
|
7727
8368
|
const authoritySourceRef = context.attemptTools.scheduledAppAuthoritySourceRef;
|
|
7728
8369
|
if (resourceState.thread.pluginAppPolicyContext) authoritySourceRef.current = {
|
|
7729
8370
|
client: resourceState.client,
|
|
@@ -7731,9 +8372,9 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
7731
8372
|
policyContext: resourceState.thread.pluginAppPolicyContext,
|
|
7732
8373
|
configCwd: connection.effectiveCwd
|
|
7733
8374
|
};
|
|
7734
|
-
turnIdRef.current = turn.turn.id;
|
|
7735
|
-
resourceState.nativeSubagentMonitor?.bindTurn(turn.turn.id);
|
|
7736
|
-
return
|
|
8375
|
+
turnIdRef.current = started.turn.turn.id;
|
|
8376
|
+
resourceState.nativeSubagentMonitor?.bindTurn(started.turn.turn.id);
|
|
8377
|
+
return started;
|
|
7737
8378
|
}
|
|
7738
8379
|
//#endregion
|
|
7739
8380
|
//#region extensions/codex/src/app-server/attempt-deadlines.ts
|
|
@@ -7791,36 +8432,30 @@ function createCodexAttemptDeadlineController(params) {
|
|
|
7791
8432
|
//#endregion
|
|
7792
8433
|
//#region extensions/codex/src/app-server/run-attempt-turn-state.ts
|
|
7793
8434
|
const CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS = 6e4;
|
|
8435
|
+
var CodexAttemptState = class {
|
|
8436
|
+
constructor() {
|
|
8437
|
+
this.completed = false;
|
|
8438
|
+
this.abortCleanup = Promise.resolve();
|
|
8439
|
+
this.localCompletionRequested = false;
|
|
8440
|
+
this.terminalTurnNotificationQueued = false;
|
|
8441
|
+
this.sawCodexInterruptMarker = false;
|
|
8442
|
+
this.clientClosedAbort = false;
|
|
8443
|
+
this.shouldDelayNativeHookRelayUnregister = false;
|
|
8444
|
+
this.lifecycleStarted = false;
|
|
8445
|
+
this.lifecycleTerminalEmitted = false;
|
|
8446
|
+
this.nativeHookRelayLastRenewedAt = 0;
|
|
8447
|
+
this.activeAppServerTurnRequests = 0;
|
|
8448
|
+
this.activeLocalProjections = 0;
|
|
8449
|
+
this.projectionClosed = false;
|
|
8450
|
+
this.terminalDynamicToolReleaseCheckScheduled = false;
|
|
8451
|
+
this.currentTurnHadNonTerminalDynamicToolResult = false;
|
|
8452
|
+
}
|
|
8453
|
+
};
|
|
7794
8454
|
function createCodexAttemptTurnState(resources) {
|
|
7795
8455
|
const { prompt, state: resourceState, projectorRef, trajectoryRecorder, startupTimeoutMs } = resources;
|
|
7796
8456
|
const { connection } = prompt.context.runtime;
|
|
7797
8457
|
const { params, options, runAbortController } = connection;
|
|
7798
|
-
const state =
|
|
7799
|
-
latestStartupErrorNotification: void 0,
|
|
7800
|
-
rateLimitsRevisionBeforeLastTurnStart: void 0,
|
|
7801
|
-
completed: false,
|
|
7802
|
-
abortCleanup: Promise.resolve(),
|
|
7803
|
-
permissionChangeRestart: void 0,
|
|
7804
|
-
localCompletionRequested: false,
|
|
7805
|
-
terminalTurnNotificationQueued: false,
|
|
7806
|
-
sawCodexInterruptMarker: false,
|
|
7807
|
-
timeout: void 0,
|
|
7808
|
-
settlementWarning: void 0,
|
|
7809
|
-
pendingSettlementStage: void 0,
|
|
7810
|
-
clientClosedPromptError: void 0,
|
|
7811
|
-
clientClosedDiagnostic: void 0,
|
|
7812
|
-
clientClosedAbort: false,
|
|
7813
|
-
shouldDelayNativeHookRelayUnregister: false,
|
|
7814
|
-
lifecycleStarted: false,
|
|
7815
|
-
lifecycleTerminalEmitted: false,
|
|
7816
|
-
nativeHookRelayLastRenewedAt: 0,
|
|
7817
|
-
activeAppServerTurnRequests: 0,
|
|
7818
|
-
activeLocalProjections: 0,
|
|
7819
|
-
projectionClosed: false,
|
|
7820
|
-
pendingTerminalDynamicToolRelease: void 0,
|
|
7821
|
-
terminalDynamicToolReleaseCheckScheduled: false,
|
|
7822
|
-
currentTurnHadNonTerminalDynamicToolResult: false
|
|
7823
|
-
};
|
|
8458
|
+
const state = new CodexAttemptState();
|
|
7824
8459
|
const { promise: completion, resolve: resolveCompletion } = createDeferred();
|
|
7825
8460
|
const settlementExpired = createDeferred();
|
|
7826
8461
|
const pendingOpenClawDynamicToolCompletionIds = /* @__PURE__ */ new Set();
|
|
@@ -7846,19 +8481,28 @@ function createCodexAttemptTurnState(resources) {
|
|
|
7846
8481
|
if (!completed) await closeCodexStartupClientBestEffort(resourceState.client);
|
|
7847
8482
|
return completed;
|
|
7848
8483
|
};
|
|
8484
|
+
let pendingNativeHookRenewal;
|
|
7849
8485
|
const renewNativeHookRelayForTurnProgress = () => {
|
|
7850
|
-
if (!resourceState.nativeHookRelay || options.nativeHookRelay?.ttlMs !== void 0) return;
|
|
8486
|
+
if (!resourceState.nativeHookRelay || options.nativeHookRelay?.ttlMs !== void 0 || pendingNativeHookRenewal) return;
|
|
7851
8487
|
const now = Date.now();
|
|
7852
8488
|
const renewsRecently = now - state.nativeHookRelayLastRenewedAt < CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS;
|
|
7853
8489
|
const expiresSoon = now >= resourceState.nativeHookRelay.expiresAtMs - CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS;
|
|
7854
8490
|
if (renewsRecently && !expiresSoon) return;
|
|
7855
|
-
|
|
7856
|
-
|
|
8491
|
+
const relay = resourceState.nativeHookRelay;
|
|
8492
|
+
relay.renew(resolveCodexNativeHookRelayTtlMs({
|
|
7857
8493
|
explicitTtlMs: void 0,
|
|
7858
8494
|
attemptTimeoutMs: params.timeoutMs,
|
|
7859
8495
|
startupTimeoutMs,
|
|
7860
8496
|
turnStartTimeoutMs: params.timeoutMs
|
|
7861
8497
|
}));
|
|
8498
|
+
pendingNativeHookRenewal = relay.drain();
|
|
8499
|
+
pendingNativeHookRenewal.then(() => {
|
|
8500
|
+
pendingNativeHookRenewal = void 0;
|
|
8501
|
+
if (resourceState.nativeHookRelay === relay) state.nativeHookRelayLastRenewedAt = now;
|
|
8502
|
+
}, (error) => {
|
|
8503
|
+
pendingNativeHookRenewal = void 0;
|
|
8504
|
+
embeddedAgentLog.debug("native hook relay renewal did not drain", { error });
|
|
8505
|
+
});
|
|
7862
8506
|
};
|
|
7863
8507
|
const noteProgress = (reason) => {
|
|
7864
8508
|
if (state.completed || state.projectionClosed || runAbortController.signal.aborted) return;
|
|
@@ -7948,32 +8592,50 @@ async function runCodexAppServerAttempt(params, options) {
|
|
|
7948
8592
|
const attemptContext = await preparation.measure("context", () => prepareCodexAttemptContext(runtime, attemptTools));
|
|
7949
8593
|
const resources = prepareCodexAttemptResources(await preparation.measure("prompt", () => prepareCodexAttemptPrompt(attemptContext)));
|
|
7950
8594
|
attemptTools.runtimeYieldCompletionClaim.current = () => resources.state.nativeHookRelay?.hasClaimedDirectChild() ?? false;
|
|
7951
|
-
|
|
7952
|
-
const turnRuntime = createCodexAttemptTurnState(resources);
|
|
8595
|
+
let activeTurnOwnsCleanup = false;
|
|
7953
8596
|
try {
|
|
7954
|
-
|
|
7955
|
-
const
|
|
7956
|
-
const serverRequests = createCodexAttemptServerRequestController(resources, turnRuntime, lifecycle);
|
|
7957
|
-
const { ensureCurrentThreadRoute } = await preparation.measure("thread-route", () => prepareCodexAttemptRoute(resources, turnRuntime, notifications, serverRequests.handleServerRequest));
|
|
7958
|
-
const turnRequest = await preparation.measure("turn-request", () => prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurrentThreadRoute, notifications.waitForActiveNativeTurnCompletion));
|
|
7959
|
-
preparation.ready();
|
|
7960
|
-
const turnStart = await startCodexAttemptTurn(resources, turnRuntime, notifications, turnRequest);
|
|
7961
|
-
if ("result" in turnStart) return turnStart.result;
|
|
7962
|
-
const activeTurn = activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, turnStart.turn);
|
|
7963
|
-
let finalizedResult;
|
|
8597
|
+
await preparation.measure("runtime-start", () => startCodexAttemptRuntime(resources));
|
|
8598
|
+
const turnRuntime = createCodexAttemptTurnState(resources);
|
|
7964
8599
|
try {
|
|
7965
|
-
|
|
7966
|
-
|
|
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;
|
|
8611
|
+
try {
|
|
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;
|
|
8628
|
+
}
|
|
8629
|
+
if (resources.state.executionDisconnectError && !connection.terminalState.explicitCancellationObserved) throw resources.state.executionDisconnectError;
|
|
8630
|
+
return finalizedResult;
|
|
7967
8631
|
} finally {
|
|
7968
|
-
|
|
8632
|
+
turnRuntime.deadlines.dispose();
|
|
7969
8633
|
}
|
|
7970
|
-
if (resources.state.executionDisconnectError && !connection.terminalState.explicitCancellationObserved) throw resources.state.executionDisconnectError;
|
|
7971
|
-
return finalizedResult;
|
|
7972
8634
|
} finally {
|
|
7973
|
-
|
|
8635
|
+
if (!activeTurnOwnsCleanup) await resources.cleanupBeforeActiveTurn();
|
|
7974
8636
|
}
|
|
7975
8637
|
} finally {
|
|
7976
|
-
await attemptTools.
|
|
8638
|
+
await attemptTools.disposeTools(connection.runAbortController.signal.aborted ? "cancel" : "error");
|
|
7977
8639
|
}
|
|
7978
8640
|
} finally {
|
|
7979
8641
|
params.abortSignal?.removeEventListener("abort", connection.abortFromUpstream);
|