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