@openclaw/codex 2026.9.1-beta.1 → 2026.9.1
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/api.js +5 -6
- package/dist/{attempt-client-cleanup-bfsmcQ6m.js → attempt-client-cleanup-DYHcRQAa.js} +31 -45
- package/dist/attempt-context-DmQUNWwT.js +634 -0
- package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
- package/dist/{binding-connection-BMvPX73o.js → binding-connection-E6uDsPlx.js} +2 -2
- package/dist/{bounded-turn-B7iBUcuP.js → bounded-turn-wzJrwKKe.js} +15 -20
- package/dist/{capabilities-BRMh0aIq.js → capabilities-dIjNVCYH.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-DEsIufkt.js → command-formatters-CLHhEB1Q.js} +5 -4
- package/dist/{command-handlers-D_-1_qRp.js → command-handlers-CTGb2csu.js} +124 -101
- package/dist/{compact-BglNFZrQ.js → compact-_t0HQrUS.js} +38 -29
- package/dist/{config-giW8X0QA.js → config-BhmfC1s6.js} +294 -282
- package/dist/{context-compaction-activity-BOeJf7yo.js → context-compaction-activity-CMla5FPJ.js} +4 -1
- package/dist/{conversation-binding-data-CW2GuupV.js → conversation-binding-data-BiodpIzq.js} +2 -1
- package/dist/doctor-contract-api.js +143 -12
- package/dist/{dynamic-tools-Dnlfa--w.js → dynamic-tools-BU9tmlYm.js} +599 -655
- package/dist/{effective-mcp-catalog-CTeGrnfO.js → effective-mcp-catalog-DzYBW4h1.js} +2 -2
- package/dist/{event-projector-assistant-message-C5-Ds8mA.js → event-projector-assistant-message-DHRFXKbS.js} +4 -4
- package/dist/{event-projector-usage-Bk1I90Bg.js → event-projector-usage-C5mcrGjp.js} +15 -148
- package/dist/{harness-Csz0F-DK.js → harness-DXVZ5II5.js} +42 -52
- package/dist/harness.js +1 -1
- package/dist/index.js +458 -404
- package/dist/{isolated-completion-Cv6FqygM.js → isolated-completion-kg9kv4iH.js} +4 -4
- package/dist/launch-args-RXQwn8zV.js +90 -0
- package/dist/{managed-binary-DFYK4DWq.js → managed-binary-4-Vjz5GH.js} +14 -9
- package/dist/media-understanding-provider.js +1 -1
- package/dist/model-catalog-CUM68Hkl.js +101 -0
- package/dist/{models-TS3HBU-q.js → models-sYnEc0gd.js} +25 -28
- package/dist/{native-subagent-monitor-4Mfq2HDs.js → native-subagent-monitor-CnH147jH.js} +55 -115
- package/dist/{node-exec-server.runtime-BpWqJO1V.js → node-exec-server.runtime-CstNHCmC.js} +9 -6
- package/dist/{plugin-approval-roundtrip-bUm777tR.js → plugin-approval-roundtrip-CNe-Xrjx.js} +30 -3
- package/dist/{plugin-marketplace-discovery-B9DvaAG-.js → plugin-marketplace-discovery-CfFlKqDl.js} +15 -14
- package/dist/{plugin-metadata-cache-CTCT3w5L.js → plugin-metadata-cache-BFrPhb2c.js} +6 -6
- package/dist/provider-capabilities-DW5p4k9w.js +101 -0
- package/dist/{rate-limits-C5_D8Gmb.js → rate-limits-CawQJfUS.js} +3 -2
- package/dist/{sandbox-guard-kuWTn9C5.js → request-DYAI5FQE.js} +195 -2
- package/dist/{run-attempt-DYc0QCBF.js → run-attempt-D1hJO4fX.js} +828 -2100
- package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-C3jVimFn.js} +21 -14
- package/dist/{session-binding-Bcynfd-_.js → session-binding-BHuTCRZQ.js} +198 -127
- package/dist/{session-catalog-DaLKVtpH.js → session-catalog-yyvTWFOw.js} +564 -408
- package/dist/{session-cli-DMc4oS2w.js → session-cli-CmFEXMAM.js} +1 -1
- package/dist/session-history-C5J1AKzG.js +87 -0
- package/dist/session-initialization-BeWzjGiR.js +74 -0
- package/dist/{session-permission-policy-BrNH1bjy.js → session-permission-policy-DeWVTCMj.js} +2 -2
- package/dist/session-retirement-BujDjXVF.js +97 -0
- package/dist/{session-upstream-marker-BIkusb95.js → session-upstream-marker-C351-5Qw.js} +19 -4
- package/dist/settled-turn-context-D3SNWtUn.js +268 -0
- package/dist/settled-turn-finalizer-BVJx4yoc.js +104 -0
- package/dist/{shared-client-DKz23hHY.js → shared-client-DxcfF9KX.js} +3480 -679
- package/dist/{side-question-DjA_jsNe.js → side-question-BTZAII4l.js} +108 -70
- package/dist/{thread-lifecycle-L7oEkTlq.js → thread-lifecycle-DAcEJ_Om.js} +2188 -1915
- package/dist/{thread-ownership-DZeuKH1j.js → thread-ownership-zGokd8i1.js} +25 -14
- package/dist/thread-policy-g4KbJPzp.js +54 -0
- package/dist/{plugin-app-cache-key-C1CAdfcP.js → thread-resume-C7pyVKeW.js} +59 -7
- package/dist/{transcript-mirror-DsCMWBca.js → transcript-mirror-DTUxFWa_.js} +79 -17
- package/dist/transport-stdio-CyPldczm.js +726 -0
- package/dist/{upstream-prompt-provenance-CFmsKwr9.js → upstream-prompt-provenance-LphB8slG.js} +8 -4
- package/dist/upstream-session-fork-CYlBIGVt.js +966 -0
- package/dist/{usage-ROIaW3wo.js → usage-Bj-rrzkR.js} +3 -3
- package/dist/{web-search-provider.runtime-ClaNPV7N.js → web-search-provider.runtime-D2FWSK4w.js} +3 -3
- package/openclaw.plugin.json +1 -30
- package/package.json +6 -6
- package/dist/command-rpc-CCeCkf_v.js +0 -90
- package/dist/incognito-session-ET_ufDH-.js +0 -2
- package/dist/model-catalog-i9rNBthX.js +0 -48
- package/dist/protocol-validators-VeJxxJ0U.js +0 -2421
- package/dist/request-DXXGHko0.js +0 -157
- package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
- package/dist/session-retirement-CcNC3YSY.js +0 -36
- package/dist/settled-turn-finalizer-Dc3ApjU4.js +0 -328
- package/dist/thread-resume-BE9qNEW0.js +0 -30
- package/dist/transport-stdio-DhoGy33Z.js +0 -99
- package/dist/upstream-session-fork-DlaHxSLC.js +0 -326
|
@@ -1,49 +1,54 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, i as createCodexSessionGenerationSupersededError, l as resolveCodexRunSessionBindingAuthority, u as scopeCodexRunBindingStore } from "./session-binding-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { n as
|
|
8
|
-
import {
|
|
9
|
-
import { t as
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { t as CODEX_CONTROL_METHODS } from "./capabilities-
|
|
13
|
-
import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-
|
|
14
|
-
import {
|
|
15
|
-
import { a as resolveCodexAppServerForModelProvider, i as resolveCodexSessionPermissionCwd, n as applyCodexSessionPermissionPolicy, r as resolveCodexEffectiveSessionPermissionPolicy } from "./session-permission-policy-
|
|
16
|
-
import { n as resolveCodexBindingAppServerConnection } from "./binding-connection-
|
|
17
|
-
import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-
|
|
18
|
-
import { t as persistCodexContextCompactionActivity } from "./context-compaction-activity-
|
|
19
|
-
import { i as
|
|
20
|
-
import { a as
|
|
21
|
-
import {
|
|
22
|
-
import { a as
|
|
23
|
-
import {
|
|
1
|
+
import { $t as isJsonObject, A as TURN_FINALIZE_DRAIN_ABORT_GRACE_MS, B as isCodexAppServerIndeterminateRequestCancellationError, Bt as resolveCodexAppServerAuthProfileIdForAgent, Ct as ensureCodexAppServerClientRuntime, Dt as protectCodexAppServerLiveThread, F as withCodexStartupTimeout, Ft as readRecentCodexRateLimits, H as isCodexAppServerOverloadError, Ht as resolveCodexAppServerFallbackApiKeyCacheKey, I as getCodexAppServerClientInstanceId, It as rememberCodexRateLimitsRead, K as resolveCodexAppServerClientInstanceId, L as isCodexAppServerApprovalRequest, M as isCodexAppServerStartupError, Mt as withAbortableTimeout, P as resolveCodexStartupTimeoutMs, Pt as readCodexRateLimitsRevision, Qt as flattenCodexDynamicToolFunctions, R as isCodexAppServerBrokenPipeError, Rt as resolveCodexAppServerAuthAccountCacheKey, Ut as resolveCodexAppServerPreparedApiKeyCacheKey, V as isCodexAppServerIndeterminateTransportError, W as isCodexAppServerRequestTimeoutError, Wt as resolveCodexAppServerPreparedAuthHandoff, _t as resolveCodexToolAbortTerminalReason, a as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, at as readCodexTurnCompletedNotification, c as getLeasedSharedCodexAppServerClient, ct as hasPendingDynamicToolTerminalDiagnostic, dt as resolveDynamicToolCallTimeoutMs, f as readCodexAppServerClientDesktopGenerationFingerprint, ft as resolveTerminalDynamicToolBatchAction, gt as toCodexDynamicToolProtocolResponse, h as releaseLeasedSharedCodexAppServerClient, ht as toCodexDynamicToolProgressResponse, i as clearSharedCodexAppServerClientIfCurrent, it as readCodexTurn, j as TURN_TERMINAL_SETTLEMENT_TIMEOUT_MS, k as CodexAppServerStartupError, l as getSharedCodexAppServerClient, lt as isDynamicToolTerminalDiagnosticEvent, mt as shouldReleaseTurnAfterTerminalDynamicTool, nt as readCodexDynamicToolCallParams, ot as createCodexElicitationResponse, pt as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult, q as CodexAppServerRpcError, s as createIsolatedCodexAppServerClient, st as handleDynamicToolCallWithTimeout, tt as assertCodexTurnStartResponse, u as isCodexAppServerStartSelectionChangedError, ut as isMatchingDynamicToolTerminalDiagnostic, v as retainSharedCodexAppServerClientIfCurrent, y as retireSharedCodexAppServerClientIfCurrent, z as isCodexAppServerConnectionClosedError, zt as resolveCodexAppServerAuthProfileId } from "./shared-client-DxcfF9KX.js";
|
|
2
|
+
import { C as isCodexPairedNodeRemoteExecPlacementSandbox, D as resolveCodexPluginsPolicy, E as readCodexPluginConfig, F as resolveCodexAppServerHomeDir, O as resolveOpenClawExecPolicyForCodexAppServer, T as isCodexSandboxExecServerEnabled, d as shouldAutoApproveCodexAppServerApprovals, f as withMcpElicitationsApprovalPolicy, h as resolveCodexModelBackedReviewerPolicyContext, l as hasCodexMcpToolApprovalOverrides, m as canUseCodexModelBackedApprovalsReviewerForModel, o as resolveCodexComputerUseConfig, r as resolveCodexAppServerHomeScope, w as isCodexRemoteExecPlacementSandbox, y as readCodexRequirementsToml } from "./config-BhmfC1s6.js";
|
|
3
|
+
import { c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, i as createCodexSessionGenerationSupersededError, l as resolveCodexRunSessionBindingAuthority, u as scopeCodexRunBindingStore } from "./session-binding-BHuTCRZQ.js";
|
|
4
|
+
import { B as readNonNegativeInteger, E as itemStatus, H as splitPlanText, I as readItem, L as readItemString, M as extractRawAssistantText, O as matchesCodexSnapshotTurn, P as readCodexErrorNotificationMessage, T as itemName, V as readNullableString, a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, f as CODEX_APP_SERVER_NATIVE_TURN_WAIT_TIMEOUT_MS, g as readCodexNotificationThreadId, h as isCodexNotificationForTurn, j as shouldSynthesizeToolProgressForItem, k as shouldClearTerminalPresentationForNativeItem, l as retireUnsafeCodexTurnClientBestEffort, m as CodexProjectionDiagnostics, o as interruptCodexTurnAndWaitBestEffort, p as getCodexAppServerTurnRouter, r as CodexAppServerUnsafeSubscriptionError, u as terminateCodexBackgroundTerminals } from "./attempt-client-cleanup-DYHcRQAa.js";
|
|
5
|
+
import { a as codexExecutionToolName, c as isPendingOpenClawDynamicToolCompletionNotification, d as isTerminalTurnStatus, f as readCodexNotificationItem, h as updateActiveTurnItemIds, l as isRawFunctionToolOutputCompletionNotification, m as readRawResponseToolCallId, p as readNotificationItemId, r as projectCodexThreadUsageUpdate, s as isCodexTurnAbortMarkerNotification, t as CodexResponseCompletionProjection } from "./event-projector-usage-C5mcrGjp.js";
|
|
6
|
+
import { i as buildCodexPluginAppCacheKey, r as buildCodexAppServerRuntimeFingerprint, s as defaultCodexAppInventoryCache } from "./thread-resume-C7pyVKeW.js";
|
|
7
|
+
import { A as readCodexMcpToolConnectorId, B as emitCodexNativePreToolUseFailureDiagnostic, C as buildDeveloperInstructions, Ct as buildCodexPluginThreadConfig, D as resolveCodexAppServerThreadModelSelection, Dt as mergeCodexThreadConfigs, H as resolveCodexNativeHookRelayTtlMs, I as buildCodexNativeHookRelayConfig, L as buildCodexNativeHookRelayDisabledConfig, M as isCodexAppServerProfilerEnabled, Ot as shouldBuildCodexPluginThreadConfig, P as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, Pt as resolveRecoverableCodexPluginConfigKeys, S as resolveCodexWebSearchPlan, Tt as buildCodexPluginThreadConfigTimeoutFallback, U as scheduleCodexNativeHookRelayUnregister, V as resolveCodexNativeHookRelayEvents, X as loadCodexNativeToolCatalog, Y as hasCodexNativeToolCatalog, _t as neutralizeCodexExplicitMentionSigils, at as filterCodexDynamicTools, bt as resolveCodexContextEngineProjectionReserveTokens, c as assertScheduledCodexAppAuthorityRuntime, d as buildScheduledCodexAppServerConnectionIdentity, f as captureScheduledCodexAppAuthority, ft as resolveCodexDynamicToolsLoadingForRuntime, gt as fitCodexProjectedContextForTurnStart, h as resolveScheduledCodexAppCreatorCaptureDecision, ht as buildCodexContinuityCalibration, i as buildCodexUserInput, j as readCodexMcpToolUiVisibility, l as buildLegacyScheduledCodexAppRecoveryPrompt, lt as isSystemAgentOnlyCodexDynamicToolAllowlist, m as readCurrentCodexScheduledAppPolicy$1, n as buildTurnCollaborationMode, nt as codexLegacyDynamicToolsFingerprint, p as intersectCodexPluginThreadConfigWithScheduledAuthority, pt as buildContextEngineBinding, r as buildTurnStartParams, s as startOrResumeThread, tt as codexDynamicToolsFingerprint, u as buildScheduledCodexAppAuthorityInputFingerprint, vt as projectContextEngineAssemblyForCodex, wt as buildCodexPluginThreadConfigInputFingerprint, xt as resolveCodexContinuityProjectionMaxChars, yt as resolveCodexContextEngineProjectionMaxChars, z as createCodexNativeHookRelay } from "./thread-lifecycle-DAcEJ_Om.js";
|
|
8
|
+
import { l as isIncognitoSessionKey, r as retainCodexAppServerBindingSubscription } from "./thread-ownership-zGokd8i1.js";
|
|
9
|
+
import { a as buildCodexUserPromptMessage, i as mirrorPromptAtTurnStartBestEffort, l as hasCodexMirrorOrigin, n as createCodexAppServerUserMessagePersistenceNotifier, o as promptSnapshot, s as applyCodexTranscriptTaint, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-DTUxFWa_.js";
|
|
10
|
+
import { n as CodexThreadPolicyHandoffError } from "./thread-policy-g4KbJPzp.js";
|
|
11
|
+
import { r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-LphB8slG.js";
|
|
12
|
+
import { t as CODEX_CONTROL_METHODS } from "./capabilities-dIjNVCYH.js";
|
|
13
|
+
import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-CawQJfUS.js";
|
|
14
|
+
import { a as formatCodexDisplayText } from "./command-formatters-CLHhEB1Q.js";
|
|
15
|
+
import { a as resolveCodexAppServerForModelProvider, i as resolveCodexSessionPermissionCwd, n as applyCodexSessionPermissionPolicy, r as resolveCodexEffectiveSessionPermissionPolicy } from "./session-permission-policy-DeWVTCMj.js";
|
|
16
|
+
import { n as resolveCodexBindingAppServerConnection } from "./binding-connection-E6uDsPlx.js";
|
|
17
|
+
import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-Ds_QVm-X.js";
|
|
18
|
+
import { t as persistCodexContextCompactionActivity } from "./context-compaction-activity-CMla5FPJ.js";
|
|
19
|
+
import { i as createAssistantReasoningMessage, n as createAssistantCommentaryMessage, r as createAssistantMessage, t as createAssistantAsyncMessage } from "./event-projector-assistant-message-DHRFXKbS.js";
|
|
20
|
+
import { a as CodexToolProgressProjection, c as isCodexCommandBearingToolCall, d as sanitizeCodexToolResponse, i as CodexToolTranscriptProjection, l as resolveCodexToolProgressDetailMode, n as CodexEventProjection, o as shouldEmitTranscriptToolProgress, r as emitCodexAgentEvent, s as inferCodexDynamicToolMeta, t as codexNativeSubagentMonitorRuntime, u as sanitizeCodexToolArguments } from "./native-subagent-monitor-CnH147jH.js";
|
|
21
|
+
import { a as requestPluginApprovalOutcome } from "./plugin-approval-roundtrip-CNe-Xrjx.js";
|
|
22
|
+
import { S as shouldWarnCodexDynamicToolBuildStageSummary, T as CodexNativeToolLifecycleProjector, _ as resolveCodexMessageToolProvider, a as emitDynamicToolStartedDiagnostic, b as shouldEnableCodexAppServerNativeToolSurface, c as ensureCodexSandboxExecServerEnvironment, d as createCodexDynamicToolBuildStageTracker, f as disableCodexPluginThreadConfig, g as resolveCodexExternalSandboxPolicyForOpenClawSandbox, h as resolveCodexAppServerHookChannelId, i as emitDynamicToolErrorDiagnostic, l as releaseCodexSandboxExecServerEnvironment, m as resolveCodexAppServerExecutionCwd, n as projectCodexExecutableDynamicTools, o as emitDynamicToolTerminalDiagnostic, p as formatCodexDynamicToolBuildStageSummary, r as routeCodexAppServerElicitationRequest, s as handleCodexAppServerApprovalRequest, t as createCodexDynamicToolBridge, u as buildDynamicTools, w as readBoundedCodexRemoteWorkspaceFile, x as shouldRequireCodexSandboxExecServerEnvironment, y as resolveCodexSandboxEnvironmentSelection } from "./dynamic-tools-BU9tmlYm.js";
|
|
23
|
+
import { t as resolveCodexProviderWebSearchSupport } from "./provider-capabilities-DW5p4k9w.js";
|
|
24
|
+
import { a as getCodexWorkspaceMemoryToolNames, c as readContextEngineThreadBootstrapProjection, d as resolveCodexDeliveryHintPreservedInputRange, f as resolveContextEngineBootstrapProjectionDecision, i as buildCodexWorkspaceBootstrapContext, l as readMirroredSessionHistoryMessages, n as buildCodexSystemPromptReport, r as buildCodexWatchedSessionsContext, s as prependCodexOpenClawPromptContext, t as buildCodexOpenClawPromptContext, u as renderCodexSkillsCollaborationInstructions } from "./attempt-context-DmQUNWwT.js";
|
|
25
|
+
import { n as captureCodexSettledTurnFinalizationContext } from "./settled-turn-context-D3SNWtUn.js";
|
|
26
|
+
import { a as runCodexComputerUseLiveTest, n as ensureCodexComputerUse, t as defaultCodexPluginMetadataCache } from "./plugin-metadata-cache-BFrPhb2c.js";
|
|
27
|
+
import { asOptionalRecord, normalizeOptionalString, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
24
28
|
import fs from "node:fs/promises";
|
|
25
29
|
import path from "node:path";
|
|
26
30
|
import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
|
|
27
|
-
import { asDateTimestampMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
28
|
-
import { AgentHarnessPreflightError, CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, agentHarnessAttemptTerminal, agentHarnessStructuredInput, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine,
|
|
29
|
-
import
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
31
|
+
import { MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
32
|
+
import { AgentHarnessPreflightError, CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, agentHarnessAttemptTerminal, agentHarnessStructuredInput, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildAgentHookContextChannelFields, buildEmbeddedForegroundPromptContext, buildHarnessContextEngineRuntimeContext, callGatewayTool, cancelPendingAgentQuestionForSession, claimPendingAgentQuestionAnswer, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, detectAndLoadAgentHarnessPromptImages, embeddedAgentLog, emitAgentEvent, emptyAgentHarnessUserInputAnswers, formatErrorMessage, formatFastModeAutoProgressText, getAgentHarnessHookRunner, hasBeforeToolCallPolicy, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, prepareHarnessNativeMcpAppPreview, projectAgentHarnessTranscriptMessageForDisplay, resolveAgentDir, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveAttemptFsWorkspaceOnly, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessAfterCompactionHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
33
|
+
import { isPathStrictlyInside, root } from "openclaw/plugin-sdk/file-access-runtime";
|
|
34
|
+
import { createHash } from "node:crypto";
|
|
35
|
+
import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
|
|
36
|
+
import { resolveAgentConfig as resolveAgentConfig$1, resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
32
37
|
import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
33
38
|
import { parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
|
|
39
|
+
import { addAbortListener } from "node:events";
|
|
34
40
|
import { truncateUtf16Safe, truncateUtf8Prefix } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
35
|
-
import { isPathStrictlyInside, root } from "openclaw/plugin-sdk/file-access-runtime";
|
|
36
|
-
import { captureFinalCodexCronCreatorToolAllowlist, materializeStaticMcpToolsForScheduledHarnessRun, resolveCodexMcpToolOverridesForAgent } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
37
41
|
import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
42
|
+
import { captureFinalCodexCronCreatorToolAllowlist, formatMcpCodexApprovalRemedy, materializeStaticMcpToolsForHarnessRun, resolveCodexMcpToolOverridesForAgent, resolveCodexTtsProvenanceTransfer } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
43
|
+
import { hasPromptImageInput } from "openclaw/plugin-sdk/session-transcript-runtime";
|
|
38
44
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
39
45
|
import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
|
|
40
|
-
import {
|
|
46
|
+
import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-local-roots";
|
|
41
47
|
import { isSilentReplyPayloadText } from "openclaw/plugin-sdk/reply-chunking";
|
|
42
48
|
import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
|
|
43
49
|
import { resolveGeneratedMediaMaxBytes } from "openclaw/plugin-sdk/media-generation-runtime";
|
|
44
50
|
import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
45
51
|
import { stripInvisibleUnicode } from "openclaw/plugin-sdk/web-content-extractor";
|
|
46
|
-
import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
|
|
47
52
|
//#region extensions/codex/src/app-server/attempt-steering.ts
|
|
48
53
|
/**
|
|
49
54
|
* Debounced steering queue for forwarding user messages to an active Codex
|
|
@@ -69,6 +74,12 @@ function createCodexSteeringQueue(params) {
|
|
|
69
74
|
let sendChain = Promise.resolve();
|
|
70
75
|
let sealedError;
|
|
71
76
|
let closedError;
|
|
77
|
+
const assertActive = () => {
|
|
78
|
+
const unavailableError = closedError ?? sealedError;
|
|
79
|
+
if (unavailableError) throw unavailableError;
|
|
80
|
+
params.signal.throwIfAborted();
|
|
81
|
+
params.assertActive();
|
|
82
|
+
};
|
|
72
83
|
const clearBatchTimer = () => {
|
|
73
84
|
if (batchTimer) {
|
|
74
85
|
clearTimeout(batchTimer);
|
|
@@ -121,19 +132,20 @@ function createCodexSteeringQueue(params) {
|
|
|
121
132
|
const sendBatch = async (items) => {
|
|
122
133
|
const liveItems = items.filter((item) => !item.settled);
|
|
123
134
|
if (liveItems.length === 0) return;
|
|
124
|
-
|
|
125
|
-
if (unavailableError) {
|
|
126
|
-
for (const item of liveItems) rejectItem(item, unavailableError);
|
|
127
|
-
throw unavailableError;
|
|
128
|
-
}
|
|
129
|
-
const clientUserMessageId = `openclaw:${params.turnId}:steer:${++batchSequence}`;
|
|
130
|
-
const batch = { items: liveItems };
|
|
131
|
-
dispatchedBatches.set(clientUserMessageId, batch);
|
|
135
|
+
let clientUserMessageId;
|
|
132
136
|
try {
|
|
137
|
+
assertActive();
|
|
138
|
+
const input = [];
|
|
139
|
+
for (const item of liveItems) {
|
|
140
|
+
input.push(...await params.prepareMessage(item.text, item));
|
|
141
|
+
assertActive();
|
|
142
|
+
}
|
|
143
|
+
clientUserMessageId = `openclaw:${params.turnId}:steer:${++batchSequence}`;
|
|
144
|
+
dispatchedBatches.set(clientUserMessageId, { items: liveItems });
|
|
133
145
|
await params.client.request("turn/steer", {
|
|
134
146
|
threadId: params.threadId,
|
|
135
147
|
expectedTurnId: params.turnId,
|
|
136
|
-
input
|
|
148
|
+
input,
|
|
137
149
|
clientUserMessageId
|
|
138
150
|
}, {
|
|
139
151
|
timeoutMs: params.requestTimeoutMs,
|
|
@@ -141,8 +153,8 @@ function createCodexSteeringQueue(params) {
|
|
|
141
153
|
});
|
|
142
154
|
for (const item of liveItems) reportItemAcceptance(item, true);
|
|
143
155
|
} catch (error) {
|
|
144
|
-
dispatchedBatches.delete(clientUserMessageId);
|
|
145
|
-
const acceptedUnconfirmed = isCodexAppServerIndeterminateRequestCancellationError(error) || isCodexAppServerIndeterminateTransportError(error);
|
|
156
|
+
if (clientUserMessageId) dispatchedBatches.delete(clientUserMessageId);
|
|
157
|
+
const acceptedUnconfirmed = clientUserMessageId !== void 0 && (isCodexAppServerIndeterminateRequestCancellationError(error) || isCodexAppServerIndeterminateTransportError(error));
|
|
146
158
|
for (const item of liveItems) {
|
|
147
159
|
if (acceptedUnconfirmed) reportItemAcceptance(item, true);
|
|
148
160
|
rejectItem(item, error);
|
|
@@ -176,15 +188,12 @@ function createCodexSteeringQueue(params) {
|
|
|
176
188
|
rejectDelivery = reject;
|
|
177
189
|
});
|
|
178
190
|
const item = {
|
|
191
|
+
...options,
|
|
179
192
|
acceptance: "open",
|
|
180
193
|
text,
|
|
181
|
-
images: options?.images,
|
|
182
|
-
isInboundUserMessage: options?.isInboundUserMessage,
|
|
183
|
-
onQueueAccepted: options?.onQueueAccepted,
|
|
184
194
|
resolve: resolveDelivery,
|
|
185
195
|
reject: rejectDelivery,
|
|
186
|
-
settled: false
|
|
187
|
-
userTurnTranscriptRecorder: options?.userTurnTranscriptRecorder
|
|
196
|
+
settled: false
|
|
188
197
|
};
|
|
189
198
|
pendingMessages.add(item);
|
|
190
199
|
return {
|
|
@@ -196,10 +205,11 @@ function createCodexSteeringQueue(params) {
|
|
|
196
205
|
if (params.signal.aborted) abortQueue();
|
|
197
206
|
return {
|
|
198
207
|
async queue(text, options) {
|
|
199
|
-
|
|
200
|
-
|
|
208
|
+
try {
|
|
209
|
+
assertActive();
|
|
210
|
+
} catch (error) {
|
|
201
211
|
options?.onQueueAccepted?.(false);
|
|
202
|
-
throw
|
|
212
|
+
throw error;
|
|
203
213
|
}
|
|
204
214
|
const { item, delivery } = createPendingMessage(text, options);
|
|
205
215
|
batchedMessages.push(item);
|
|
@@ -243,20 +253,20 @@ function normalizeCodexSteerDebounceMs(value) {
|
|
|
243
253
|
//#endregion
|
|
244
254
|
//#region extensions/codex/src/app-server/event-projector-assistant.ts
|
|
245
255
|
var CodexAssistantProjection = class {
|
|
246
|
-
constructor(params, emitAgentEvent, matchesToolProgressEcho, nextTranscriptTimestamp) {
|
|
256
|
+
constructor(params, emitAgentEvent, matchesToolProgressEcho, nextTranscriptTimestamp, checkpointCommentary) {
|
|
247
257
|
this.params = params;
|
|
248
258
|
this.emitAgentEvent = emitAgentEvent;
|
|
249
259
|
this.matchesToolProgressEcho = matchesToolProgressEcho;
|
|
250
260
|
this.nextTranscriptTimestamp = nextTranscriptTimestamp;
|
|
261
|
+
this.checkpointCommentary = checkpointCommentary;
|
|
251
262
|
this.assistantTextByItem = /* @__PURE__ */ new Map();
|
|
252
263
|
this.assistantItemOrder = [];
|
|
253
264
|
this.assistantTimestampByItem = /* @__PURE__ */ new Map();
|
|
254
265
|
this.assistantPhaseByItem = /* @__PURE__ */ new Map();
|
|
255
266
|
this.assistantDeliveryByItem = /* @__PURE__ */ new Map();
|
|
256
267
|
this.latestTerminalAssistantCandidateSuperseded = false;
|
|
257
|
-
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
|
|
258
268
|
this.terminalAssistantCandidateEarlierActiveItemIds = /* @__PURE__ */ new Set();
|
|
259
|
-
this.
|
|
269
|
+
this.lastCommentaryProgressEventByItem = /* @__PURE__ */ new Map();
|
|
260
270
|
this.lastAnswerCandidateEventByItem = /* @__PURE__ */ new Map();
|
|
261
271
|
this.pendingRawCommentaryEchoes = 0;
|
|
262
272
|
this.rawPromotedAssistantItemIds = /* @__PURE__ */ new Set();
|
|
@@ -265,27 +275,7 @@ var CodexAssistantProjection = class {
|
|
|
265
275
|
this.persistableAssistantBarrier = 0;
|
|
266
276
|
this.persistedAssistantBoundary = false;
|
|
267
277
|
this.persistableAssistantBarrierItemIds = /* @__PURE__ */ new Set();
|
|
268
|
-
|
|
269
|
-
hasCompletedTerminalAssistantText(completedItemIds) {
|
|
270
|
-
const latestCompletedItemId = this.latestCompletedTerminalAssistantItemId;
|
|
271
|
-
if (!latestCompletedItemId) return false;
|
|
272
|
-
const finalItem = this.resolveFinalAssistantTextItem();
|
|
273
|
-
return this.latestCompletedItemId === latestCompletedItemId && finalItem?.itemId === latestCompletedItemId && completedItemIds.has(latestCompletedItemId);
|
|
274
|
-
}
|
|
275
|
-
getLatestTerminalAssistantCandidate() {
|
|
276
|
-
const itemId = this.latestTerminalAssistantCandidateItemId;
|
|
277
|
-
if (!itemId) return;
|
|
278
|
-
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
279
|
-
return {
|
|
280
|
-
itemId,
|
|
281
|
-
hasText: Boolean(text && !this.isToolProgressEchoText(itemId, text))
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
hasLatestTerminalAssistantCandidateText() {
|
|
285
|
-
return !this.latestTerminalAssistantCandidateSuperseded && this.getLatestTerminalAssistantCandidate()?.hasText === true;
|
|
286
|
-
}
|
|
287
|
-
canReleaseLatestTerminalAssistantAfterToolHandoff() {
|
|
288
|
-
return this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff && this.hasLatestTerminalAssistantCandidateText();
|
|
278
|
+
this.completedAssistantItemIds = /* @__PURE__ */ new Set();
|
|
289
279
|
}
|
|
290
280
|
handleNotification(method, params) {
|
|
291
281
|
if (method === "model/rerouted") this.responseModel = readStringField(params, "toModel") ?? this.responseModel;
|
|
@@ -309,12 +299,13 @@ var CodexAssistantProjection = class {
|
|
|
309
299
|
if (isCommentary) {
|
|
310
300
|
this.emitCommentaryProgress({
|
|
311
301
|
itemId,
|
|
312
|
-
text
|
|
302
|
+
text,
|
|
303
|
+
phase: "update"
|
|
313
304
|
});
|
|
314
305
|
return;
|
|
315
306
|
}
|
|
316
|
-
|
|
317
|
-
|
|
307
|
+
const knownFinalAnswer = this.isFinalAnswerAssistantItem(itemId);
|
|
308
|
+
if (knownFinalAnswer) this.emitAnswerCandidate(itemId, "candidate");
|
|
318
309
|
const replace = this.streamedPartialAssistantItemId !== void 0 && this.streamedPartialAssistantItemId !== itemId;
|
|
319
310
|
if (replace && (!knownFinalAnswer || this.streamedPartialAssistantItemReplaceable)) this.streamedPartialAssistantItemReplaceable = true;
|
|
320
311
|
else if (this.streamedPartialAssistantItemId === void 0) this.streamedPartialAssistantItemReplaceable = !knownFinalAnswer;
|
|
@@ -346,12 +337,11 @@ var CodexAssistantProjection = class {
|
|
|
346
337
|
}
|
|
347
338
|
}
|
|
348
339
|
recordItemCompleted(item, itemId, activeItemIds) {
|
|
340
|
+
if (itemId && item?.type === "agentMessage") this.completedAssistantItemIds.add(itemId);
|
|
349
341
|
this.noteNativeWorkBarrier(item);
|
|
350
342
|
this.rememberAssistantPhase(item);
|
|
351
343
|
if (item?.type === "agentMessage" && itemId && !this.isNonTerminalAssistantItem(itemId) && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
352
|
-
if (itemId && !this.isNonTerminalAssistantItem(itemId)) this.latestCompletedItemId = itemId;
|
|
353
344
|
if (item?.type === "agentMessage" && !this.isNonTerminalAssistantItem(item.id)) {
|
|
354
|
-
this.latestCompletedTerminalAssistantItemId = item.id;
|
|
355
345
|
this.markLatestTerminalAssistantCandidate(item.id, activeItemIds);
|
|
356
346
|
this.pendingRawTerminalAssistantEchoItemId = item.id;
|
|
357
347
|
} else if (itemId && !this.isNonTerminalAssistantItem(itemId)) {
|
|
@@ -364,7 +354,8 @@ var CodexAssistantProjection = class {
|
|
|
364
354
|
if (item.text && this.isCommentaryAssistantItem(item.id)) {
|
|
365
355
|
this.emitCommentaryProgress({
|
|
366
356
|
itemId: item.id,
|
|
367
|
-
text: item.text
|
|
357
|
+
text: item.text,
|
|
358
|
+
phase: "end"
|
|
368
359
|
});
|
|
369
360
|
this.pendingRawCommentaryEchoes += 1;
|
|
370
361
|
} else if (item.text && !this.isAsyncAssistantItem(item.id) && this.isFinalAnswerAssistantItem(item.id)) this.emitAnswerCandidate(item.id, "candidate");
|
|
@@ -372,6 +363,7 @@ var CodexAssistantProjection = class {
|
|
|
372
363
|
}
|
|
373
364
|
}
|
|
374
365
|
recordSnapshotItem(item) {
|
|
366
|
+
if (item.type === "agentMessage") this.completedAssistantItemIds.add(item.id);
|
|
375
367
|
this.rememberAssistantPhase(item);
|
|
376
368
|
if (item.type === "agentMessage" && typeof item.text === "string") {
|
|
377
369
|
this.rememberAssistantItem(item.id);
|
|
@@ -387,10 +379,7 @@ var CodexAssistantProjection = class {
|
|
|
387
379
|
const pendingTerminalAssistantEchoItemId = this.pendingRawTerminalAssistantEchoItemId;
|
|
388
380
|
const isPendingTerminalAssistantEcho = role === "assistant" && phase !== "commentary" && pendingTerminalAssistantEchoItemId !== void 0 && (rawItemId === void 0 || rawItemId === pendingTerminalAssistantEchoItemId);
|
|
389
381
|
if (pendingTerminalAssistantEchoItemId !== void 0 && !isPendingTerminalAssistantEcho) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
390
|
-
if (!isPendingTerminalAssistantEcho)
|
|
391
|
-
this.latestCompletedItemId = void 0;
|
|
392
|
-
this.markTerminalAssistantCandidateSupersededBy(rawItemId);
|
|
393
|
-
}
|
|
382
|
+
if (!isPendingTerminalAssistantEcho) this.markTerminalAssistantCandidateSupersededBy(rawItemId);
|
|
394
383
|
if (role !== "assistant") return;
|
|
395
384
|
if (phase === "commentary" && this.pendingRawCommentaryEchoes > 0) {
|
|
396
385
|
this.pendingRawCommentaryEchoes -= 1;
|
|
@@ -410,15 +399,17 @@ var CodexAssistantProjection = class {
|
|
|
410
399
|
const isIdlessTerminalAssistantAfterCompletedWork = candidateWasSupersededBeforeRaw && rawItemId === void 0 && pendingTerminalAssistantEchoItemId === void 0 && activeItemIds.size === 0;
|
|
411
400
|
if (text && phase !== "commentary" && candidateWasSupersededBeforeRaw && itemId !== this.streamedPartialAssistantItemId && !isIdlessTerminalAssistantAfterCompletedWork) return;
|
|
412
401
|
if (phase) this.assistantPhaseByItem.set(itemId, phase);
|
|
402
|
+
this.completedAssistantItemIds.add(itemId);
|
|
413
403
|
this.rememberAssistantItem(itemId);
|
|
414
404
|
this.assistantTextByItem.set(itemId, text);
|
|
415
405
|
if (!text) return;
|
|
416
406
|
this.rawPromotedAssistantItemIds.add(itemId);
|
|
417
407
|
if (phase === "commentary") this.emitCommentaryProgress({
|
|
418
408
|
itemId,
|
|
419
|
-
text
|
|
409
|
+
text,
|
|
410
|
+
phase: "end"
|
|
420
411
|
});
|
|
421
|
-
else this.markLatestTerminalAssistantCandidate(itemId, activeItemIds
|
|
412
|
+
else this.markLatestTerminalAssistantCandidate(itemId, activeItemIds);
|
|
422
413
|
}
|
|
423
414
|
collectAssistantTexts() {
|
|
424
415
|
const afterHandoff = this.collectPersistableAssistantTexts(this.persistableAssistantBarrier);
|
|
@@ -433,16 +424,18 @@ var CodexAssistantProjection = class {
|
|
|
433
424
|
}
|
|
434
425
|
collectCommentaryMessages() {
|
|
435
426
|
return this.assistantItemOrder.flatMap((itemId) => {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
const timestamp = this.assistantTimestampByItem.get(itemId);
|
|
439
|
-
if (!text || timestamp === void 0) return [];
|
|
440
|
-
return [{
|
|
427
|
+
const message = this.readCommentaryMessage(itemId);
|
|
428
|
+
return message ? [{
|
|
441
429
|
itemId,
|
|
442
|
-
message
|
|
443
|
-
}];
|
|
430
|
+
message
|
|
431
|
+
}] : [];
|
|
444
432
|
});
|
|
445
433
|
}
|
|
434
|
+
readCommentaryMessage(itemId) {
|
|
435
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
436
|
+
const timestamp = this.assistantTimestampByItem.get(itemId);
|
|
437
|
+
return this.isCommentaryAssistantItem(itemId) && text && timestamp !== void 0 ? createAssistantCommentaryMessage(this.params, text, itemId, timestamp) : void 0;
|
|
438
|
+
}
|
|
446
439
|
collectAsyncMessages() {
|
|
447
440
|
return this.assistantItemOrder.flatMap((itemId) => {
|
|
448
441
|
if (!this.isAsyncAssistantItem(itemId)) return [];
|
|
@@ -455,19 +448,20 @@ var CodexAssistantProjection = class {
|
|
|
455
448
|
}];
|
|
456
449
|
});
|
|
457
450
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
451
|
+
collectCompletedAssistantMessages(completedItemIds, options) {
|
|
452
|
+
return this.assistantItemOrder.flatMap((itemId) => {
|
|
453
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
454
|
+
if (!completedItemIds.has(itemId) || this.isNonTerminalAssistantItem(itemId) || !text || isSilentReplyPayloadText(text) || this.isToolProgressEchoText(itemId, text)) return [];
|
|
455
|
+
const message = this.createAssistantMessage(text, options);
|
|
456
|
+
const timestamp = this.assistantTimestampByItem.get(itemId) ?? message.timestamp;
|
|
457
|
+
return [{
|
|
458
|
+
itemId,
|
|
459
|
+
message: {
|
|
460
|
+
...message,
|
|
461
|
+
timestamp
|
|
462
|
+
}
|
|
463
|
+
}];
|
|
464
|
+
});
|
|
471
465
|
}
|
|
472
466
|
markAssistantBoundaryPersisted(itemId) {
|
|
473
467
|
const index = this.assistantItemOrder.indexOf(itemId);
|
|
@@ -526,9 +520,6 @@ var CodexAssistantProjection = class {
|
|
|
526
520
|
responseModel: this.responseModel
|
|
527
521
|
} : message;
|
|
528
522
|
}
|
|
529
|
-
createAssistantMirrorMessage(title, text) {
|
|
530
|
-
return createAssistantMirrorMessage(this.params, title, text);
|
|
531
|
-
}
|
|
532
523
|
rememberAssistantPhase(item) {
|
|
533
524
|
if (item?.type !== "agentMessage") return;
|
|
534
525
|
const phase = readItemString(item, "phase");
|
|
@@ -548,20 +539,21 @@ var CodexAssistantProjection = class {
|
|
|
548
539
|
isFinalAnswerAssistantItem(itemId) {
|
|
549
540
|
return this.assistantPhaseByItem.get(itemId) === "final_answer";
|
|
550
541
|
}
|
|
551
|
-
shouldStreamAssistantPartial(itemId) {
|
|
552
|
-
return this.assistantPhaseByItem.get(itemId) === "final_answer";
|
|
553
|
-
}
|
|
554
542
|
emitCommentaryProgress(params) {
|
|
555
543
|
const progressText = params.text.trim();
|
|
556
|
-
|
|
557
|
-
|
|
544
|
+
const previous = this.lastCommentaryProgressEventByItem.get(params.itemId);
|
|
545
|
+
if (!progressText || previous?.phase === params.phase && previous.text === progressText) return;
|
|
546
|
+
this.lastCommentaryProgressEventByItem.set(params.itemId, {
|
|
547
|
+
phase: params.phase,
|
|
548
|
+
text: progressText
|
|
549
|
+
});
|
|
558
550
|
this.emitAgentEvent({
|
|
559
551
|
stream: "item",
|
|
560
552
|
data: {
|
|
561
553
|
itemId: params.itemId,
|
|
562
554
|
kind: "preamble",
|
|
563
555
|
title: "Preamble",
|
|
564
|
-
phase:
|
|
556
|
+
phase: params.phase,
|
|
565
557
|
progressText,
|
|
566
558
|
source: "codex-app-server"
|
|
567
559
|
}
|
|
@@ -574,9 +566,12 @@ var CodexAssistantProjection = class {
|
|
|
574
566
|
this.supersedeVisibleAnswerCandidate();
|
|
575
567
|
this.visibleAnswerCandidateItemId = itemId;
|
|
576
568
|
}
|
|
577
|
-
const
|
|
578
|
-
if (
|
|
579
|
-
this.lastAnswerCandidateEventByItem.set(itemId,
|
|
569
|
+
const previous = this.lastAnswerCandidateEventByItem.get(itemId);
|
|
570
|
+
if (previous?.status === status && previous.text === text) return;
|
|
571
|
+
this.lastAnswerCandidateEventByItem.set(itemId, {
|
|
572
|
+
status,
|
|
573
|
+
text
|
|
574
|
+
});
|
|
580
575
|
this.emitAgentEvent({
|
|
581
576
|
stream: "item",
|
|
582
577
|
data: {
|
|
@@ -597,10 +592,9 @@ var CodexAssistantProjection = class {
|
|
|
597
592
|
this.emitAnswerCandidate(itemId, "superseded");
|
|
598
593
|
this.visibleAnswerCandidateItemId = void 0;
|
|
599
594
|
}
|
|
600
|
-
markLatestTerminalAssistantCandidate(itemId, activeItemIds
|
|
595
|
+
markLatestTerminalAssistantCandidate(itemId, activeItemIds) {
|
|
601
596
|
this.latestTerminalAssistantCandidateItemId = itemId;
|
|
602
597
|
this.latestTerminalAssistantCandidateSuperseded = false;
|
|
603
|
-
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = options?.canReleaseAfterToolHandoff === true;
|
|
604
598
|
this.terminalAssistantCandidateEarlierActiveItemIds = new Set(activeItemIds);
|
|
605
599
|
}
|
|
606
600
|
markTerminalAssistantCandidateSupersededBy(itemId, options) {
|
|
@@ -610,7 +604,6 @@ var CodexAssistantProjection = class {
|
|
|
610
604
|
return;
|
|
611
605
|
}
|
|
612
606
|
this.latestTerminalAssistantCandidateSuperseded = true;
|
|
613
|
-
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
|
|
614
607
|
this.terminalAssistantCandidateEarlierActiveItemIds.clear();
|
|
615
608
|
this.supersedeVisibleAnswerCandidate();
|
|
616
609
|
}
|
|
@@ -655,9 +648,15 @@ var CodexAssistantProjection = class {
|
|
|
655
648
|
this.persistableAssistantBarrier = this.assistantItemOrder.length;
|
|
656
649
|
}
|
|
657
650
|
rememberAssistantItem(itemId) {
|
|
658
|
-
if (!itemId
|
|
659
|
-
this.
|
|
660
|
-
|
|
651
|
+
if (!itemId) return;
|
|
652
|
+
if (!this.assistantTimestampByItem.has(itemId)) {
|
|
653
|
+
this.assistantItemOrder.push(itemId);
|
|
654
|
+
this.assistantTimestampByItem.set(itemId, this.nextTranscriptTimestamp());
|
|
655
|
+
}
|
|
656
|
+
if (this.isCommentaryAssistantItem(itemId)) this.checkpointCommentary?.(itemId, {
|
|
657
|
+
read: () => this.readCommentaryMessage(itemId),
|
|
658
|
+
ready: () => this.completedAssistantItemIds.has(itemId)
|
|
659
|
+
});
|
|
661
660
|
}
|
|
662
661
|
createAsyncDelivery(itemId) {
|
|
663
662
|
if (!this.isAsyncAssistantItem(itemId)) return;
|
|
@@ -1005,49 +1004,29 @@ function reasoningMethodOrder(method) {
|
|
|
1005
1004
|
const attemptTerminal = agentHarnessAttemptTerminal;
|
|
1006
1005
|
//#endregion
|
|
1007
1006
|
//#region extensions/codex/src/app-server/event-projector-snapshot.ts
|
|
1008
|
-
const CODEX_META_KEY$1 = "__openclaw";
|
|
1009
|
-
function readTurnTaintMetadata(message) {
|
|
1010
|
-
return asOptionalRecord(CODEX_META_KEY$1 in message ? message[CODEX_META_KEY$1] : void 0);
|
|
1011
|
-
}
|
|
1012
|
-
function applyStickyTurnTaint(messages) {
|
|
1013
|
-
let tainted = false;
|
|
1014
|
-
return messages.map((message) => {
|
|
1015
|
-
if (message.role === "user") {
|
|
1016
|
-
tainted = false;
|
|
1017
|
-
return message;
|
|
1018
|
-
}
|
|
1019
|
-
const metadata = readTurnTaintMetadata(message);
|
|
1020
|
-
tainted ||= metadata?.turnTainted === true || metadata?.resultContentSource === "network";
|
|
1021
|
-
return message.role === "assistant" && tainted ? {
|
|
1022
|
-
...message,
|
|
1023
|
-
__openclaw: {
|
|
1024
|
-
...metadata,
|
|
1025
|
-
turnTainted: true
|
|
1026
|
-
}
|
|
1027
|
-
} : message;
|
|
1028
|
-
});
|
|
1029
|
-
}
|
|
1030
1007
|
function buildCodexMessagesSnapshot(params) {
|
|
1031
1008
|
const messages = promptSnapshot(params.runParams, params.turnId, params.upstreamUserText);
|
|
1032
|
-
if (params.reasoningText) messages.push(attachCodexMirrorIdentity(params.
|
|
1009
|
+
if (params.reasoningText) messages.push(attachCodexMirrorIdentity(createAssistantReasoningMessage(params.runParams, params.reasoningText), `${params.turnId}:reasoning`));
|
|
1033
1010
|
const commentaryMessages = params.runParams.config?.ui?.prefs?.chatPersistCommentary === false ? [] : params.commentaryMessages.map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:commentary:${itemId}`));
|
|
1034
1011
|
const asyncMessages = params.asyncMessages.map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:async:${itemId}`));
|
|
1035
1012
|
const visibleWorkMessages = [
|
|
1036
1013
|
...commentaryMessages,
|
|
1037
1014
|
...asyncMessages,
|
|
1015
|
+
...(params.assistantMessages ?? []).map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:assistant:${itemId}`)),
|
|
1038
1016
|
...params.toolMessages
|
|
1039
1017
|
].toSorted((left, right) => (asDateTimestampMs(left.timestamp) ?? 0) - (asDateTimestampMs(right.timestamp) ?? 0));
|
|
1040
1018
|
messages.push(...visibleWorkMessages);
|
|
1041
|
-
if (params.lastAssistant) messages.push(attachCodexMirrorIdentity(params.lastAssistant,
|
|
1042
|
-
|
|
1019
|
+
if (params.lastAssistant) messages.push(attachCodexMirrorIdentity(params.lastAssistant, `${params.turnId}:assistant`));
|
|
1020
|
+
const taint = { tainted: false };
|
|
1021
|
+
return messages.map((message) => projectAgentHarnessTranscriptMessageForDisplay({
|
|
1043
1022
|
hidden: params.runParams.trigger === "memory",
|
|
1044
|
-
message
|
|
1023
|
+
message: applyCodexTranscriptTaint(message, taint)
|
|
1045
1024
|
}));
|
|
1046
1025
|
}
|
|
1047
1026
|
function buildCodexSteeringMessagesSnapshot(params) {
|
|
1048
1027
|
const asyncMessages = params.assistantProjection.collectAsyncMessages().filter(({ itemId }) => params.completedItemIds.has(itemId));
|
|
1049
1028
|
const commentaryMessages = params.assistantProjection.collectCommentaryMessages().filter(({ itemId }) => params.completedItemIds.has(itemId));
|
|
1050
|
-
const
|
|
1029
|
+
const assistantMessages = params.assistantProjection.collectCompletedAssistantMessages(params.completedItemIds, {
|
|
1051
1030
|
tokenUsage: void 0,
|
|
1052
1031
|
aborted: false,
|
|
1053
1032
|
promptError: void 0
|
|
@@ -1060,12 +1039,11 @@ function buildCodexSteeringMessagesSnapshot(params) {
|
|
|
1060
1039
|
reasoningText: void 0,
|
|
1061
1040
|
asyncMessages,
|
|
1062
1041
|
commentaryMessages,
|
|
1042
|
+
assistantMessages,
|
|
1063
1043
|
toolMessages: params.toolMessages,
|
|
1064
|
-
lastAssistant:
|
|
1065
|
-
...assistantBoundary ? { lastAssistantIdentity: `${params.turnId}:assistant:${assistantBoundary.itemId}` } : {},
|
|
1066
|
-
createAssistantMirrorMessage: (title, text) => params.assistantProjection.createAssistantMirrorMessage(title, text)
|
|
1044
|
+
lastAssistant: void 0
|
|
1067
1045
|
}).filter((message) => message.role !== "user"),
|
|
1068
|
-
|
|
1046
|
+
assistantBoundaryItemId: assistantMessages.at(-1)?.itemId
|
|
1069
1047
|
};
|
|
1070
1048
|
}
|
|
1071
1049
|
//#endregion
|
|
@@ -1111,8 +1089,7 @@ function buildCodexAttemptResult(input) {
|
|
|
1111
1089
|
asyncMessages,
|
|
1112
1090
|
commentaryMessages,
|
|
1113
1091
|
toolMessages: input.toolTranscriptProjection.transcriptMessages,
|
|
1114
|
-
lastAssistant
|
|
1115
|
-
createAssistantMirrorMessage: (title, text) => input.assistantProjection.createAssistantMirrorMessage(title, text)
|
|
1092
|
+
lastAssistant
|
|
1116
1093
|
});
|
|
1117
1094
|
const turnFailed = input.completedTurn?.status === "failed";
|
|
1118
1095
|
const promptError = input.promptError ?? storedMissingToolResultError ?? (turnFailed ? input.completedTurn?.error?.message ?? "codex app-server turn failed" : null);
|
|
@@ -1125,7 +1102,9 @@ function buildCodexAttemptResult(input) {
|
|
|
1125
1102
|
});
|
|
1126
1103
|
const toolMetas = input.toolProgressProjection.toolMetas;
|
|
1127
1104
|
const hadPotentialSideEffects = input.toolTelemetry.didSendViaMessagingTool || Boolean(input.toolTelemetry.successfulCronAdds || input.toolTelemetry.acceptedSessionSpawns?.length) || input.generatedMediaProjection.hasGeneratedMedia() || input.toolProgressProjection.hasPotentialSideEffects;
|
|
1128
|
-
|
|
1105
|
+
const sentMediaUrls = new Set(input.toolTelemetry.messagingToolSentMediaUrls.map((url) => url.trim()));
|
|
1106
|
+
const toolAutoDeliveryMediaUrls = input.toolTelemetry.toolAutoDeliveryMediaUrls?.filter((url) => !sentMediaUrls.has(url.trim()));
|
|
1107
|
+
const result = {
|
|
1129
1108
|
terminal: attemptTerminal.normalize({
|
|
1130
1109
|
aborted: input.aborted,
|
|
1131
1110
|
promptError,
|
|
@@ -1172,8 +1151,83 @@ function buildCodexAttemptResult(input) {
|
|
|
1172
1151
|
yieldDetected: input.yieldDetected || false,
|
|
1173
1152
|
didSendDeterministicApprovalPrompt: input.guardianReviewCount > 0 ? false : void 0
|
|
1174
1153
|
};
|
|
1154
|
+
const transferTtsProvenance = resolveCodexTtsProvenanceTransfer(input.runParams.hostCapabilities);
|
|
1155
|
+
for (const toolResult of input.toolTelemetry.coreTtsToolResults ?? []) transferTtsProvenance?.(toolResult, result, toolAutoDeliveryMediaUrls ?? []);
|
|
1156
|
+
return result;
|
|
1175
1157
|
}
|
|
1176
1158
|
//#endregion
|
|
1159
|
+
//#region extensions/codex/src/app-server/transcript-checkpoint.ts
|
|
1160
|
+
/** Commits completed work in receipt order without waiting for the enclosing turn. */
|
|
1161
|
+
var CodexTranscriptCheckpoint = class {
|
|
1162
|
+
constructor(params, threadId, turnId) {
|
|
1163
|
+
this.params = params;
|
|
1164
|
+
this.threadId = threadId;
|
|
1165
|
+
this.turnId = turnId;
|
|
1166
|
+
this.pending = [];
|
|
1167
|
+
this.commentaryItemIds = /* @__PURE__ */ new Set();
|
|
1168
|
+
this.lastTimestamp = 0;
|
|
1169
|
+
this.writing = Promise.resolve();
|
|
1170
|
+
this.tainted = false;
|
|
1171
|
+
this.closed = false;
|
|
1172
|
+
this.nextTimestamp = () => {
|
|
1173
|
+
this.lastTimestamp = Math.max(Date.now(), this.lastTimestamp + 1);
|
|
1174
|
+
return this.lastTimestamp;
|
|
1175
|
+
};
|
|
1176
|
+
this.enqueueCommentary = (itemId, entry) => {
|
|
1177
|
+
if (this.params.config?.ui?.prefs?.chatPersistCommentary === false || this.commentaryItemIds.has(itemId)) return;
|
|
1178
|
+
this.commentaryItemIds.add(itemId);
|
|
1179
|
+
this.enqueue({
|
|
1180
|
+
...entry,
|
|
1181
|
+
read: () => {
|
|
1182
|
+
const message = entry.read();
|
|
1183
|
+
return message ? attachCodexMirrorIdentity(message, `${this.turnId}:commentary:${itemId}`) : void 0;
|
|
1184
|
+
}
|
|
1185
|
+
});
|
|
1186
|
+
};
|
|
1187
|
+
this.enqueue = (entry) => {
|
|
1188
|
+
if (this.params.sessionTarget && !this.closed) this.pending.push(entry);
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
flush(close = false) {
|
|
1192
|
+
if (this.closed) return this.writing;
|
|
1193
|
+
this.closed = close;
|
|
1194
|
+
this.writing = this.writing.then(async () => {
|
|
1195
|
+
const blocked = close ? -1 : this.pending.findIndex((entry) => entry.ready?.() === false);
|
|
1196
|
+
const count = blocked < 0 ? this.pending.length : blocked;
|
|
1197
|
+
if (count === 0) return;
|
|
1198
|
+
const taint = { tainted: this.tainted };
|
|
1199
|
+
const messages = this.pending.slice(0, count).flatMap((entry) => {
|
|
1200
|
+
const message = entry.read();
|
|
1201
|
+
return message ? [projectAgentHarnessTranscriptMessageForDisplay({
|
|
1202
|
+
hidden: this.params.trigger === "memory",
|
|
1203
|
+
message: applyCodexTranscriptTaint(message, taint)
|
|
1204
|
+
})] : [];
|
|
1205
|
+
});
|
|
1206
|
+
try {
|
|
1207
|
+
await codexTranscriptMirrorRuntime.mirror({
|
|
1208
|
+
...this.params.sessionTarget,
|
|
1209
|
+
sessionId: this.params.sessionId,
|
|
1210
|
+
cwd: this.params.workspaceDir,
|
|
1211
|
+
messages,
|
|
1212
|
+
idempotencyScope: `codex-app-server:${this.threadId}`,
|
|
1213
|
+
runId: this.params.runId,
|
|
1214
|
+
runMirrorIdentityPrefix: `${this.turnId}:`,
|
|
1215
|
+
config: this.params.config
|
|
1216
|
+
});
|
|
1217
|
+
this.pending.splice(0, count);
|
|
1218
|
+
this.tainted = taint.tainted;
|
|
1219
|
+
} catch (error) {
|
|
1220
|
+
embeddedAgentLog.warn("failed to checkpoint codex app-server transcript", {
|
|
1221
|
+
runId: this.params.runId,
|
|
1222
|
+
sessionId: this.params.sessionId,
|
|
1223
|
+
error: formatErrorMessage(error)
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1226
|
+
});
|
|
1227
|
+
return this.writing;
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
//#endregion
|
|
1177
1231
|
//#region extensions/codex/src/app-server/usage-limit-error.ts
|
|
1178
1232
|
/**
|
|
1179
1233
|
* Enriches Codex usage-limit failures with current rate-limit information and
|
|
@@ -1183,6 +1237,10 @@ const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
|
|
|
1183
1237
|
function createCodexUsageLimitPromptError(message) {
|
|
1184
1238
|
return Object.assign(new Error(message), { status: 429 });
|
|
1185
1239
|
}
|
|
1240
|
+
function resolveCodexPromptError(source) {
|
|
1241
|
+
const usageLimitMessage = formatCodexUsageLimitErrorMessage(source);
|
|
1242
|
+
return usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : source.message ?? void 0;
|
|
1243
|
+
}
|
|
1186
1244
|
function isCodexUsageLimitPromptError(error) {
|
|
1187
1245
|
return error instanceof Error && "status" in error && error.status === 429;
|
|
1188
1246
|
}
|
|
@@ -1322,13 +1380,14 @@ var CodexAppServerEventProjector = class {
|
|
|
1322
1380
|
this.activeCompactionItemIds = /* @__PURE__ */ new Set();
|
|
1323
1381
|
this.terminalPresentationClearedItemIds = /* @__PURE__ */ new Set();
|
|
1324
1382
|
this.nativeToolOutcomeOrdinals = /* @__PURE__ */ new Map();
|
|
1383
|
+
this.projectionClosed = false;
|
|
1325
1384
|
this.settledTurnFailureFinalizationAllowed = false;
|
|
1326
1385
|
this.promptErrorSource = null;
|
|
1327
1386
|
this.synthesizedMissingToolResultError = null;
|
|
1328
1387
|
this.aborted = false;
|
|
1329
1388
|
this.responseCompletions = new CodexResponseCompletionProjection();
|
|
1330
1389
|
this.completedCompactionCount = 0;
|
|
1331
|
-
this.
|
|
1390
|
+
this.transcriptCheckpoint = new CodexTranscriptCheckpoint(params, threadId, turnId);
|
|
1332
1391
|
this.asyncDeliveryProjection = new CodexAsyncDeliveryProjection(params, threadId, turnId, options);
|
|
1333
1392
|
this.contextTokens = options.initialContextTokens;
|
|
1334
1393
|
this.contextTokensSource = options.initialContextTokens === void 0 ? void 0 : "resolved";
|
|
@@ -1341,22 +1400,26 @@ var CodexAppServerEventProjector = class {
|
|
|
1341
1400
|
signal: options.runAbortSignal
|
|
1342
1401
|
});
|
|
1343
1402
|
this.toolProgressProjection = new CodexToolProgressProjection(params);
|
|
1344
|
-
this.toolTranscriptProjection = new CodexToolTranscriptProjection(params, threadId, turnId, this.toolProgressProjection,
|
|
1403
|
+
this.toolTranscriptProjection = new CodexToolTranscriptProjection(params, threadId, turnId, this.toolProgressProjection, this.transcriptCheckpoint.nextTimestamp, {
|
|
1345
1404
|
nativePostToolUseRelayEnabled: options.nativePostToolUseRelayEnabled,
|
|
1346
1405
|
prepareNativeMcpAppResultDetails: options.prepareNativeMcpAppResultDetails,
|
|
1347
|
-
trajectoryRecorder: options.trajectoryRecorder
|
|
1406
|
+
trajectoryRecorder: options.trajectoryRecorder,
|
|
1407
|
+
checkpointMessage: this.transcriptCheckpoint.enqueue
|
|
1348
1408
|
});
|
|
1349
1409
|
this.eventProjection = new CodexEventProjection(threadId, turnId, (event) => this.emitAgentEvent(event), this.toolProgressProjection, this.toolTranscriptProjection, options.onNativeToolResultRecorded);
|
|
1350
|
-
this.assistantProjection = new CodexAssistantProjection(params, (event) => this.emitAgentEvent(event), (text) => this.toolProgressProjection.matchesEcho(text),
|
|
1410
|
+
this.assistantProjection = new CodexAssistantProjection(params, (event) => this.emitAgentEvent(event), (text) => this.toolProgressProjection.matchesEcho(text), this.transcriptCheckpoint.nextTimestamp, this.transcriptCheckpoint.enqueueCommentary);
|
|
1351
1411
|
this.reasoningProjection = new CodexReasoningProjection(params, (event) => this.emitAgentEvent(event), options.onNativePlanUpdate);
|
|
1352
1412
|
}
|
|
1353
|
-
nextTranscriptTimestamp() {
|
|
1354
|
-
this.lastTranscriptTimestamp = Math.max(Date.now(), this.lastTranscriptTimestamp + 1);
|
|
1355
|
-
return this.lastTranscriptTimestamp;
|
|
1356
|
-
}
|
|
1357
1413
|
getCompletedTurnStatus() {
|
|
1358
1414
|
return this.completedTurn?.status;
|
|
1359
1415
|
}
|
|
1416
|
+
getActiveMcpToolCall(serverName) {
|
|
1417
|
+
if (this.projectionClosed || this.aborted) return;
|
|
1418
|
+
return this.nativeToolLifecycleProjector.getActiveMcpToolCall(serverName);
|
|
1419
|
+
}
|
|
1420
|
+
recordMcpToolCallReceipt(notification) {
|
|
1421
|
+
if (!this.projectionClosed) this.nativeToolLifecycleProjector.recordMcpToolCallReceipt(notification);
|
|
1422
|
+
}
|
|
1360
1423
|
buildSteeringTranscriptPrefix() {
|
|
1361
1424
|
const snapshot = buildCodexSteeringMessagesSnapshot({
|
|
1362
1425
|
runParams: this.params,
|
|
@@ -1376,25 +1439,10 @@ var CodexAppServerEventProjector = class {
|
|
|
1376
1439
|
this.pendingSteeringAssistantBoundaryItemId = void 0;
|
|
1377
1440
|
}
|
|
1378
1441
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
return this.assistantProjection.getLatestTerminalAssistantCandidate();
|
|
1384
|
-
}
|
|
1385
|
-
hasLatestTerminalAssistantCandidateText() {
|
|
1386
|
-
return this.assistantProjection.hasLatestTerminalAssistantCandidateText();
|
|
1387
|
-
}
|
|
1388
|
-
canReleaseLatestTerminalAssistantAfterToolHandoff() {
|
|
1389
|
-
return this.assistantProjection.canReleaseLatestTerminalAssistantAfterToolHandoff();
|
|
1390
|
-
}
|
|
1391
|
-
/** Restores a completed final item after only the enclosing turn timeout fired. */
|
|
1392
|
-
recoverCompletedTerminalAssistantAfterTurnWatchTimeout() {
|
|
1393
|
-
if (!this.aborted || this.promptError !== "codex app-server attempt timed out" || !this.hasCompletedTerminalAssistantText()) return false;
|
|
1394
|
-
this.aborted = false;
|
|
1395
|
-
this.promptError = void 0;
|
|
1396
|
-
this.promptErrorSource = null;
|
|
1397
|
-
return true;
|
|
1442
|
+
/** Fence delayed projections before the turn's final snapshot leaves its owner. */
|
|
1443
|
+
closeProjection() {
|
|
1444
|
+
this.projectionClosed = true;
|
|
1445
|
+
return this.transcriptCheckpoint.flush(true);
|
|
1398
1446
|
}
|
|
1399
1447
|
/** Resolves the shared model-order position for a native tool item. */
|
|
1400
1448
|
recordNativeToolOutcome(item) {
|
|
@@ -1410,6 +1458,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1410
1458
|
this.nativeToolLifecycleProjector.recordPreToolUseFailure(failure);
|
|
1411
1459
|
}
|
|
1412
1460
|
async handleNotification(notification) {
|
|
1461
|
+
if (this.projectionClosed) return;
|
|
1413
1462
|
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
1414
1463
|
if (!params) return;
|
|
1415
1464
|
if (notification.method === "hook/started" || notification.method === "hook/completed") {
|
|
@@ -1437,9 +1486,11 @@ var CodexAppServerEventProjector = class {
|
|
|
1437
1486
|
break;
|
|
1438
1487
|
case "item/started":
|
|
1439
1488
|
await this.handleItemStarted(params);
|
|
1489
|
+
await this.transcriptCheckpoint.flush();
|
|
1440
1490
|
break;
|
|
1441
1491
|
case "item/completed":
|
|
1442
1492
|
await this.handleItemCompleted(params);
|
|
1493
|
+
await this.transcriptCheckpoint.flush();
|
|
1443
1494
|
break;
|
|
1444
1495
|
case "item/commandExecution/outputDelta":
|
|
1445
1496
|
this.toolProgressProjection.handleOutputDelta(params, "bash");
|
|
@@ -1478,10 +1529,11 @@ var CodexAppServerEventProjector = class {
|
|
|
1478
1529
|
await this.handleTurnCompleted(params);
|
|
1479
1530
|
break;
|
|
1480
1531
|
case "rawResponse/completed":
|
|
1481
|
-
this.responseCompletions.record(params);
|
|
1532
|
+
this.responseCompletions.record(params, this.params.hostCapabilities.reportOutputTokens);
|
|
1482
1533
|
break;
|
|
1483
1534
|
case "rawResponseItem/completed":
|
|
1484
1535
|
await this.handleRawResponseItemCompleted(params);
|
|
1536
|
+
await this.transcriptCheckpoint.flush();
|
|
1485
1537
|
break;
|
|
1486
1538
|
case "model/rerouted":
|
|
1487
1539
|
this.eventProjection.handleModelRerouted(params);
|
|
@@ -1492,7 +1544,11 @@ var CodexAppServerEventProjector = class {
|
|
|
1492
1544
|
const codexErrorInfo = isJsonObject(params.error) ? params.error.codexErrorInfo : void 0;
|
|
1493
1545
|
const compactionFailure = codexErrorInfo === "other" && this.isCompacting();
|
|
1494
1546
|
this.settledTurnFailureFinalizationAllowed = codexErrorInfo === "serverOverloaded" || compactionFailure;
|
|
1495
|
-
this.promptError =
|
|
1547
|
+
this.promptError = resolveCodexPromptError({
|
|
1548
|
+
message: readCodexErrorNotificationMessage(params),
|
|
1549
|
+
codexErrorInfo,
|
|
1550
|
+
rateLimits: this.options.readRecentRateLimits?.()
|
|
1551
|
+
}) ?? "codex app-server error";
|
|
1496
1552
|
this.promptErrorSource = compactionFailure ? "compaction" : "prompt";
|
|
1497
1553
|
break;
|
|
1498
1554
|
}
|
|
@@ -1507,9 +1563,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1507
1563
|
case "model/verification":
|
|
1508
1564
|
case "turn/moderationMetadata":
|
|
1509
1565
|
case "model/safetyBuffering/updated": break;
|
|
1510
|
-
default:
|
|
1511
|
-
this.diagnostics.warnUnknownEvent(notification, params);
|
|
1512
|
-
break;
|
|
1566
|
+
default: this.diagnostics.warnUnknownEvent(notification, params);
|
|
1513
1567
|
}
|
|
1514
1568
|
}
|
|
1515
1569
|
buildResult(toolTelemetry, options) {
|
|
@@ -1583,16 +1637,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1583
1637
|
await runAgentHarnessBeforeCompactionHook({
|
|
1584
1638
|
sessionFile: this.params.sessionFile,
|
|
1585
1639
|
messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
|
|
1586
|
-
ctx: {
|
|
1587
|
-
runId: this.params.runId,
|
|
1588
|
-
agentId: this.params.agentId,
|
|
1589
|
-
sessionKey: this.params.sessionKey,
|
|
1590
|
-
sessionId: this.params.sessionId,
|
|
1591
|
-
workspaceDir: this.params.workspaceDir,
|
|
1592
|
-
messageProvider: this.params.messageProvider ?? void 0,
|
|
1593
|
-
trigger: this.params.trigger,
|
|
1594
|
-
channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
|
|
1595
|
-
}
|
|
1640
|
+
ctx: this.options.agentHookContext ?? {}
|
|
1596
1641
|
});
|
|
1597
1642
|
this.emitAgentEvent({
|
|
1598
1643
|
stream: "compaction",
|
|
@@ -1614,6 +1659,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1614
1659
|
phase: "start",
|
|
1615
1660
|
item
|
|
1616
1661
|
});
|
|
1662
|
+
if (this.projectionClosed) return;
|
|
1617
1663
|
this.toolTranscriptProjection.recordNativeToolCall(item);
|
|
1618
1664
|
this.toolProgressProjection.emitToolResultSummary(item);
|
|
1619
1665
|
this.emitAgentEvent({
|
|
@@ -1638,27 +1684,22 @@ var CodexAppServerEventProjector = class {
|
|
|
1638
1684
|
if (!this.asyncDeliveryProjection.allows(item, true)) return;
|
|
1639
1685
|
const asyncMessage = this.assistantProjection.recordItemCompleted(item, itemId, this.activeItemIds);
|
|
1640
1686
|
if (asyncMessage) await this.asyncDeliveryProjection.deliver(asyncMessage);
|
|
1687
|
+
if (this.projectionClosed) return;
|
|
1641
1688
|
this.reasoningProjection.recordItem(item);
|
|
1642
1689
|
await this.generatedMediaProjection.recordNative(item);
|
|
1690
|
+
if (this.projectionClosed) return;
|
|
1643
1691
|
if (item?.type === "contextCompaction" && itemId) {
|
|
1644
1692
|
this.activeCompactionItemIds.delete(itemId);
|
|
1645
1693
|
this.completedCompactionCount += 1;
|
|
1646
1694
|
await this.options.onContextCompacted?.();
|
|
1695
|
+
if (this.projectionClosed) return;
|
|
1647
1696
|
await runAgentHarnessAfterCompactionHook({
|
|
1648
1697
|
sessionFile: this.params.sessionFile,
|
|
1649
1698
|
messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
|
|
1650
1699
|
compactedCount: -1,
|
|
1651
|
-
ctx: {
|
|
1652
|
-
runId: this.params.runId,
|
|
1653
|
-
agentId: this.params.agentId,
|
|
1654
|
-
sessionKey: this.params.sessionKey,
|
|
1655
|
-
sessionId: this.params.sessionId,
|
|
1656
|
-
workspaceDir: this.params.workspaceDir,
|
|
1657
|
-
messageProvider: this.params.messageProvider ?? void 0,
|
|
1658
|
-
trigger: this.params.trigger,
|
|
1659
|
-
channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
|
|
1660
|
-
}
|
|
1700
|
+
ctx: this.options.agentHookContext ?? {}
|
|
1661
1701
|
});
|
|
1702
|
+
if (this.projectionClosed) return;
|
|
1662
1703
|
await persistCodexContextCompactionActivity({
|
|
1663
1704
|
sessionTarget: this.params.sessionTarget,
|
|
1664
1705
|
config: this.params.config,
|
|
@@ -1667,7 +1708,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1667
1708
|
threadId: this.threadId,
|
|
1668
1709
|
turnId: this.turnId,
|
|
1669
1710
|
itemId,
|
|
1670
|
-
timestamp: this.
|
|
1711
|
+
timestamp: this.transcriptCheckpoint.nextTimestamp()
|
|
1671
1712
|
});
|
|
1672
1713
|
this.eventProjection.emitCompactionEnd(itemId, true);
|
|
1673
1714
|
}
|
|
@@ -1681,8 +1722,10 @@ var CodexAppServerEventProjector = class {
|
|
|
1681
1722
|
phase: "result",
|
|
1682
1723
|
item
|
|
1683
1724
|
});
|
|
1725
|
+
if (this.projectionClosed) return;
|
|
1684
1726
|
this.toolTranscriptProjection.recordNativeToolCall(item);
|
|
1685
1727
|
await this.toolTranscriptProjection.recordNativeToolResultWithDetails(item);
|
|
1728
|
+
if (this.projectionClosed) return;
|
|
1686
1729
|
this.toolProgressProjection.emitToolResultSummary(item);
|
|
1687
1730
|
this.toolProgressProjection.emitToolResultOutput(item);
|
|
1688
1731
|
this.emitAgentEvent({
|
|
@@ -1702,12 +1745,11 @@ var CodexAppServerEventProjector = class {
|
|
|
1702
1745
|
this.settledTurnFailureFinalizationAllowed = turn.status === "failed" && (turn.error?.codexErrorInfo === "serverOverloaded" || compactionFailure);
|
|
1703
1746
|
if (turn.status !== "completed") this.responseCompletions.clear();
|
|
1704
1747
|
if (turn.status === "failed") {
|
|
1705
|
-
|
|
1748
|
+
this.promptError = resolveCodexPromptError({
|
|
1706
1749
|
message: turn.error?.message,
|
|
1707
1750
|
codexErrorInfo: turn.error?.codexErrorInfo,
|
|
1708
1751
|
rateLimits: this.options.readRecentRateLimits?.()
|
|
1709
|
-
});
|
|
1710
|
-
this.promptError = usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : turn.error?.message ?? "codex app-server turn failed";
|
|
1752
|
+
}) ?? "codex app-server turn failed";
|
|
1711
1753
|
this.promptErrorSource = compactionFailure ? "compaction" : "prompt";
|
|
1712
1754
|
}
|
|
1713
1755
|
if (compactionFailure) {
|
|
@@ -1720,39 +1762,40 @@ var CodexAppServerEventProjector = class {
|
|
|
1720
1762
|
}
|
|
1721
1763
|
const turnItems = turn.items ?? [];
|
|
1722
1764
|
const unsettledAsyncDeliveries = this.asyncDeliveryProjection.pending();
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
if (!item || !this.isCurrentTurnSnapshotItem(item)) continue;
|
|
1726
|
-
if (item?.type === "dynamicToolCall") break;
|
|
1727
|
-
if (shouldClearTerminalPresentationForNativeItem(item)) {
|
|
1728
|
-
this.clearTerminalPresentationForNativeItem(item);
|
|
1729
|
-
break;
|
|
1730
|
-
}
|
|
1731
|
-
}
|
|
1765
|
+
const lastToolItem = turnItems.findLast((item) => matchesCodexSnapshotTurn(item, this.turnId) && (item.type === "dynamicToolCall" || shouldClearTerminalPresentationForNativeItem(item)));
|
|
1766
|
+
if (lastToolItem?.type !== "dynamicToolCall") this.clearTerminalPresentationForNativeItem(lastToolItem);
|
|
1732
1767
|
for (const item of turnItems) {
|
|
1733
1768
|
if (!this.asyncDeliveryProjection.allows(item)) continue;
|
|
1734
1769
|
this.diagnostics.warnUnknownItemStatus(item);
|
|
1735
1770
|
const asyncMessage = this.assistantProjection.recordSnapshotItem(item);
|
|
1736
1771
|
if (asyncMessage) await this.asyncDeliveryProjection.deliver(asyncMessage);
|
|
1772
|
+
if (this.projectionClosed) return;
|
|
1737
1773
|
this.reasoningProjection.recordItem(item);
|
|
1738
1774
|
await this.generatedMediaProjection.recordNative(item);
|
|
1775
|
+
if (this.projectionClosed) return;
|
|
1739
1776
|
this.toolProgressProjection.recordToolMeta(item);
|
|
1740
1777
|
this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
|
|
1741
1778
|
await this.emitSnapshotOnlyNativeToolProgress(item);
|
|
1779
|
+
if (this.projectionClosed) return;
|
|
1742
1780
|
this.toolTranscriptProjection.recordNativeToolCall(item);
|
|
1743
1781
|
await this.toolTranscriptProjection.recordNativeToolResultWithDetails(item);
|
|
1782
|
+
if (this.projectionClosed) return;
|
|
1744
1783
|
this.toolTranscriptProjection.emitAfterToolCallObservation(item);
|
|
1745
1784
|
this.toolProgressProjection.emitToolResultSummary(item);
|
|
1746
1785
|
this.toolProgressProjection.emitToolResultOutput(item);
|
|
1747
1786
|
}
|
|
1748
1787
|
this.toolProgressProjection.approvalTimeoutKinds.clear();
|
|
1749
|
-
for (const delivery of unsettledAsyncDeliveries)
|
|
1788
|
+
for (const delivery of unsettledAsyncDeliveries) {
|
|
1789
|
+
if (this.projectionClosed) return;
|
|
1790
|
+
await this.asyncDeliveryProjection.deliver(delivery);
|
|
1791
|
+
}
|
|
1792
|
+
if (this.projectionClosed) return;
|
|
1750
1793
|
this.assistantProjection.finalizeAnswerCandidate(turn);
|
|
1751
1794
|
this.activeCompactionItemIds.clear();
|
|
1752
1795
|
await this.reasoningProjection.maybeEndReasoning();
|
|
1753
1796
|
}
|
|
1754
1797
|
async emitSnapshotOnlyNativeToolProgress(item) {
|
|
1755
|
-
if (!shouldSynthesizeToolProgressForItem(item) || !this.
|
|
1798
|
+
if (!shouldSynthesizeToolProgressForItem(item) || !matchesCodexSnapshotTurn(item, this.turnId) || this.completedItemIds.has(item.id) || itemStatus(item) === "running") return;
|
|
1756
1799
|
if (!this.activeItemIds.has(item.id)) {
|
|
1757
1800
|
this.eventProjection.emitStandardItemEvent({
|
|
1758
1801
|
phase: "start",
|
|
@@ -1763,6 +1806,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1763
1806
|
item
|
|
1764
1807
|
});
|
|
1765
1808
|
}
|
|
1809
|
+
if (this.projectionClosed) return;
|
|
1766
1810
|
this.activeItemIds.delete(item.id);
|
|
1767
1811
|
this.eventProjection.emitStandardItemEvent({
|
|
1768
1812
|
phase: "end",
|
|
@@ -1774,10 +1818,6 @@ var CodexAppServerEventProjector = class {
|
|
|
1774
1818
|
});
|
|
1775
1819
|
this.completedItemIds.add(item.id);
|
|
1776
1820
|
}
|
|
1777
|
-
isCurrentTurnSnapshotItem(item) {
|
|
1778
|
-
const itemTurnId = readItemString(item, "turnId");
|
|
1779
|
-
return itemTurnId === void 0 || itemTurnId === this.turnId;
|
|
1780
|
-
}
|
|
1781
1821
|
async handleRawResponseItemCompleted(params) {
|
|
1782
1822
|
const item = isJsonObject(params.item) ? params.item : void 0;
|
|
1783
1823
|
if (!item) return;
|
|
@@ -1798,17 +1838,8 @@ var CodexAppServerEventProjector = class {
|
|
|
1798
1838
|
presentationOnly: true
|
|
1799
1839
|
});
|
|
1800
1840
|
}
|
|
1801
|
-
formatCodexErrorMessage(params) {
|
|
1802
|
-
const error = isJsonObject(params.error) ? params.error : void 0;
|
|
1803
|
-
const usageLimitMessage = formatCodexUsageLimitErrorMessage({
|
|
1804
|
-
message: error ? readStringField(error, "message") : void 0,
|
|
1805
|
-
codexErrorInfo: error?.codexErrorInfo,
|
|
1806
|
-
rateLimits: this.options.readRecentRateLimits?.()
|
|
1807
|
-
});
|
|
1808
|
-
return usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : readCodexErrorNotificationMessage(params);
|
|
1809
|
-
}
|
|
1810
1841
|
emitAgentEvent(event) {
|
|
1811
|
-
emitCodexAgentEvent(this.params, event);
|
|
1842
|
+
if (!this.projectionClosed) emitCodexAgentEvent(this.params, event);
|
|
1812
1843
|
}
|
|
1813
1844
|
isHookNotificationForCurrentThread(params) {
|
|
1814
1845
|
const threadId = readStringField(params, "threadId");
|
|
@@ -1817,23 +1848,11 @@ var CodexAppServerEventProjector = class {
|
|
|
1817
1848
|
}
|
|
1818
1849
|
};
|
|
1819
1850
|
//#endregion
|
|
1820
|
-
//#region extensions/codex/src/app-server/mcp-tool-metadata.ts
|
|
1821
|
-
/** Hosted app ownership is authoritative only on metadata supplied by Codex. */
|
|
1822
|
-
function readCodexMcpToolConnectorId(tool) {
|
|
1823
|
-
const metadata = asOptionalRecord(asOptionalRecord(tool)?.["_meta"]);
|
|
1824
|
-
return normalizeOptionalString(metadata?.connector_id) ?? normalizeOptionalString(metadata?.connectorId);
|
|
1825
|
-
}
|
|
1826
|
-
/** Preserve MCP App visibility so model-only tools cannot become widget authority. */
|
|
1827
|
-
function readCodexMcpToolUiVisibility(tool) {
|
|
1828
|
-
const visibility = asOptionalRecord(asOptionalRecord(asOptionalRecord(tool)?.["_meta"])?.ui)?.visibility;
|
|
1829
|
-
if (!Array.isArray(visibility)) return;
|
|
1830
|
-
return [...new Set(visibility.filter((value) => value === "app" || value === "model"))].toSorted();
|
|
1831
|
-
}
|
|
1832
|
-
//#endregion
|
|
1833
1851
|
//#region extensions/codex/src/app-server/native-mcp-app.ts
|
|
1834
|
-
const CODEX_APPS_MCP_SERVER
|
|
1852
|
+
const CODEX_APPS_MCP_SERVER = "codex_apps";
|
|
1835
1853
|
function readMcpAppResourceUri(item) {
|
|
1836
|
-
const
|
|
1854
|
+
const appContext = asOptionalRecord(item.appContext);
|
|
1855
|
+
const uri = normalizeOptionalString(appContext?.resourceUri) ?? normalizeOptionalString(item.mcpAppResourceUri);
|
|
1837
1856
|
return uri?.startsWith("ui://") ? uri : void 0;
|
|
1838
1857
|
}
|
|
1839
1858
|
function readMcpAppConnectorId(item) {
|
|
@@ -1914,7 +1933,7 @@ function createNativeMcpRuntime(params) {
|
|
|
1914
1933
|
return { tools: status ? statusTools(status) : [] };
|
|
1915
1934
|
},
|
|
1916
1935
|
readResource: async (serverName, uri) => {
|
|
1917
|
-
const isCodexAppsServer = serverName === CODEX_APPS_MCP_SERVER
|
|
1936
|
+
const isCodexAppsServer = serverName === CODEX_APPS_MCP_SERVER;
|
|
1918
1937
|
const response = await params.client.request("mcpServer/resource/read", {
|
|
1919
1938
|
threadId: params.threadId,
|
|
1920
1939
|
...isCodexAppsServer ? { originCallId: params.originCallId } : {},
|
|
@@ -1944,7 +1963,7 @@ function createCodexNativeMcpAppResultDetailsPreparer(params) {
|
|
|
1944
1963
|
const connectorId = readMcpAppConnectorId(item);
|
|
1945
1964
|
const toolResult = readMcpToolResult(item);
|
|
1946
1965
|
if (!serverName || !toolName || !uiResourceUri || !toolResult) return;
|
|
1947
|
-
if (serverName === CODEX_APPS_MCP_SERVER
|
|
1966
|
+
if (serverName === CODEX_APPS_MCP_SERVER && !connectorId) return;
|
|
1948
1967
|
const runtime = createNativeMcpRuntime({
|
|
1949
1968
|
...params,
|
|
1950
1969
|
originCallId: item.id,
|
|
@@ -1953,7 +1972,7 @@ function createCodexNativeMcpAppResultDetailsPreparer(params) {
|
|
|
1953
1972
|
const tools = (await runtime.listTools?.(serverName))?.tools ?? [];
|
|
1954
1973
|
const allowedAppToolNames = new Set(tools.filter((tool) => {
|
|
1955
1974
|
const uiVisibility = readCodexMcpToolUiVisibility(tool);
|
|
1956
|
-
return (uiVisibility === void 0 || uiVisibility.includes("app")) && (serverName !== CODEX_APPS_MCP_SERVER
|
|
1975
|
+
return (uiVisibility === void 0 || uiVisibility.includes("app")) && (serverName !== CODEX_APPS_MCP_SERVER || readCodexMcpToolConnectorId(tool) === connectorId);
|
|
1957
1976
|
}).map((tool) => tool.name));
|
|
1958
1977
|
if (!allowedAppToolNames.has(toolName)) return;
|
|
1959
1978
|
return await prepareHarnessNativeMcpAppPreview({
|
|
@@ -1974,9 +1993,9 @@ function createCodexNativeMcpAppResultDetailsPreparer(params) {
|
|
|
1974
1993
|
const RESTORED_PLAN_PREAMBLE = "OpenClaw restored the session progress card after context compaction. This is application state, not a new user request. Continue the current task and call progress_card whenever the status meaningfully changes.";
|
|
1975
1994
|
const PROGRESS_CARD_MAX_STEPS = 50;
|
|
1976
1995
|
const PROGRESS_CARD_MAX_STEP_UTF8_BYTES = 512;
|
|
1977
|
-
const PROGRESS_CARD_MAX_UTF8_BYTES =
|
|
1978
|
-
const RESTORED_PLAN_MAX_MARKDOWN_BYTES =
|
|
1979
|
-
const RESTORED_PLAN_MAX_PAYLOAD_BYTES =
|
|
1996
|
+
const PROGRESS_CARD_MAX_UTF8_BYTES = 8192;
|
|
1997
|
+
const RESTORED_PLAN_MAX_MARKDOWN_BYTES = 2048;
|
|
1998
|
+
const RESTORED_PLAN_MAX_PAYLOAD_BYTES = 32768;
|
|
1980
1999
|
const RESTORED_PLAN_TRUNCATION_SUFFIX = "…";
|
|
1981
2000
|
function canonicalizeNativeProgressCardInput(input) {
|
|
1982
2001
|
const markdown = input.markdown === void 0 ? void 0 : truncateUtf8(stripInvisibleUnicode(input.markdown), PROGRESS_CARD_MAX_UTF8_BYTES);
|
|
@@ -1986,8 +2005,10 @@ function canonicalizeNativeProgressCardInput(input) {
|
|
|
1986
2005
|
const text = truncateUtf8(stripInvisibleUnicode(step.step), PROGRESS_CARD_MAX_STEP_UTF8_BYTES);
|
|
1987
2006
|
if (!text.trim()) continue;
|
|
1988
2007
|
let status = step.status;
|
|
1989
|
-
if (status === "in_progress")
|
|
1990
|
-
|
|
2008
|
+
if (status === "in_progress") {
|
|
2009
|
+
if (hasInProgressStep) status = "pending";
|
|
2010
|
+
else hasInProgressStep = true;
|
|
2011
|
+
}
|
|
1991
2012
|
plan.push({
|
|
1992
2013
|
step: text,
|
|
1993
2014
|
status
|
|
@@ -2056,7 +2077,8 @@ function serializePlan(plan) {
|
|
|
2056
2077
|
}
|
|
2057
2078
|
function truncateUtf8(value, maxBytes) {
|
|
2058
2079
|
if (Buffer$1.byteLength(value, "utf8") <= maxBytes) return value;
|
|
2059
|
-
|
|
2080
|
+
const suffixBytes = Buffer$1.byteLength(RESTORED_PLAN_TRUNCATION_SUFFIX, "utf8");
|
|
2081
|
+
return `${truncateUtf8Prefix(value, maxBytes - suffixBytes)}${RESTORED_PLAN_TRUNCATION_SUFFIX}`;
|
|
2060
2082
|
}
|
|
2061
2083
|
function readPlanSteps(value) {
|
|
2062
2084
|
if (!Array.isArray(value)) return [];
|
|
@@ -2076,7 +2098,7 @@ function isPlanStatus(value) {
|
|
|
2076
2098
|
//#endregion
|
|
2077
2099
|
//#region extensions/codex/src/app-server/user-input-bridge.ts
|
|
2078
2100
|
/** Owns per-turn Codex request_user_input and ordinary MCP elicitation lifecycles. */
|
|
2079
|
-
const DEFAULT_USER_INPUT_TIMEOUT_MS =
|
|
2101
|
+
const DEFAULT_USER_INPUT_TIMEOUT_MS = 9e5;
|
|
2080
2102
|
const NONBLOCKING_USER_INPUT_TIMEOUT_MS = 12e4;
|
|
2081
2103
|
const MAX_USER_INPUT_QUESTIONS = 3;
|
|
2082
2104
|
const MAX_USER_INPUT_OPTIONS = 4;
|
|
@@ -2200,7 +2222,10 @@ function createCodexUserInputBridge(params) {
|
|
|
2200
2222
|
failureValue: declineElicitation("OpenClaw could not handle this elicitation."),
|
|
2201
2223
|
run: async (signal) => {
|
|
2202
2224
|
const result = await execute(compiled.input, timeoutMs, signal);
|
|
2203
|
-
if (result.status === "answered")
|
|
2225
|
+
if (result.status === "answered") {
|
|
2226
|
+
const content = compiled.input.kind === "ready" && compiled.input.plan.kind === "url" ? null : result.content;
|
|
2227
|
+
return createCodexElicitationResponse("accept", content);
|
|
2228
|
+
}
|
|
2204
2229
|
if (result.status === "declined") return declineElicitation(result.message);
|
|
2205
2230
|
if (result.status === "unsupported") return declineElicitation(result.message);
|
|
2206
2231
|
return cancelValue;
|
|
@@ -2314,14 +2339,14 @@ function declineElicitation(message) {
|
|
|
2314
2339
|
}
|
|
2315
2340
|
//#endregion
|
|
2316
2341
|
//#region extensions/codex/src/app-server/run-attempt-active-turn.ts
|
|
2317
|
-
|
|
2342
|
+
function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, turn) {
|
|
2318
2343
|
const { prompt, state: resourceState, projectorRef, trajectoryRecorder, pendingNativePreToolUseFailures } = resources;
|
|
2319
2344
|
const { context, turnState } = prompt;
|
|
2320
|
-
const { runtime, attemptTools } = context;
|
|
2345
|
+
const { runtime, attemptTools, hookContext } = context;
|
|
2321
2346
|
const { connection } = runtime;
|
|
2322
|
-
const { params, runAbortController, terminalState, abortExplicitly, abortFromUpstream,
|
|
2347
|
+
const { params, runAbortController, terminalState, abortExplicitly, abortFromUpstream, sessionAgentId, contextSessionKey, effectiveCwd } = connection;
|
|
2323
2348
|
const { dynamicToolParams, compactionPlanState, computerContextEpoch, toolBridge } = attemptTools;
|
|
2324
|
-
const { state, userInputBridgeRef, steeringQueueRef,
|
|
2349
|
+
const { state, completion, userInputBridgeRef, steeringQueueRef, deadlines, noteProgress, completeTurn, interruptTurn } = turnRuntime;
|
|
2325
2350
|
const { emitExecutionPhaseOnce, emitLifecycleStart, maybeAnnounceFastModeAutoOff } = lifecycle;
|
|
2326
2351
|
const { enqueueNotification } = notifications;
|
|
2327
2352
|
const activeTurnId = turn.turn.id;
|
|
@@ -2359,6 +2384,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2359
2384
|
return dynamicToolParams.onAgentEvent?.(event);
|
|
2360
2385
|
}
|
|
2361
2386
|
}, resourceState.thread.threadId, activeTurnId, {
|
|
2387
|
+
agentHookContext: hookContext,
|
|
2362
2388
|
initialContextTokens: connection.mutable.startupContextTokens,
|
|
2363
2389
|
nativePostToolUseRelayEnabled: resourceState.nativeHookRelay?.allowedEvents.includes("post_tool_use") === true && resourceState.nativeHookRelay.shouldRelayEvent("post_tool_use"),
|
|
2364
2390
|
asyncUserMessageAllowed: params.disableTools !== true && (params.toolsAllow === void 0 || toolBridge.availableTools.some((tool) => tool.name === "message")),
|
|
@@ -2420,59 +2446,111 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2420
2446
|
}
|
|
2421
2447
|
}
|
|
2422
2448
|
});
|
|
2423
|
-
if (isTerminalTurnStatus(turn.turn.status))
|
|
2449
|
+
if (isTerminalTurnStatus(turn.turn.status)) {
|
|
2450
|
+
state.terminalTurnNotificationQueued = true;
|
|
2451
|
+
deadlines.beginSettlement(Date.now());
|
|
2452
|
+
}
|
|
2424
2453
|
emitLifecycleStart();
|
|
2425
2454
|
const activeProjector = projectorRef.current;
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2455
|
+
noteProgress("turn:start");
|
|
2456
|
+
const abortListener = () => {
|
|
2457
|
+
state.abortCleanup = interruptTurn(activeTurnId).then(async (confirmed) => {
|
|
2458
|
+
if (!terminalState.explicitCancellationObserved && !state.permissionChangeRestart && !state.timeout) return;
|
|
2459
|
+
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.");
|
|
2460
|
+
await terminateCodexBackgroundTerminals(resourceState.client, resourceState.thread.threadId);
|
|
2461
|
+
if (state.permissionChangeRestart) state.permissionChangeRestart = "confirmed";
|
|
2462
|
+
});
|
|
2463
|
+
state.abortCleanup.then(completeTurn, (error) => {
|
|
2464
|
+
embeddedAgentLog.warn("codex app-server cancellation cleanup failed", { error });
|
|
2465
|
+
completeTurn();
|
|
2466
|
+
});
|
|
2467
|
+
};
|
|
2468
|
+
runAbortController.signal.addEventListener("abort", abortListener, { once: true });
|
|
2469
|
+
if (runAbortController.signal.aborted) abortListener();
|
|
2430
2470
|
for (const failure of pendingNativePreToolUseFailures.splice(0)) activeProjector.recordNativeToolPreToolUseFailure(failure);
|
|
2431
2471
|
const notifyUserMessagePersisted = createCodexAppServerUserMessagePersistenceNotifier(params);
|
|
2432
2472
|
const promptMirrorPromise = mirrorPromptAtTurnStartBestEffort({
|
|
2433
2473
|
params,
|
|
2434
2474
|
agentId: sessionAgentId,
|
|
2435
2475
|
notifyUserMessagePersisted,
|
|
2436
|
-
sessionKey:
|
|
2476
|
+
sessionKey: contextSessionKey,
|
|
2437
2477
|
cwd: effectiveCwd,
|
|
2438
2478
|
threadId: resourceState.thread.threadId,
|
|
2439
2479
|
turnId: activeTurnId,
|
|
2440
2480
|
upstreamUserText: turnState.codexTurnPromptText
|
|
2441
2481
|
});
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
if (!state.completed && isTerminalTurnStatus(turn.turn.status)) {
|
|
2454
|
-
if (!isJsonObject(turn.turn)) throw new Error("Codex turn completion payload is not a JSON object");
|
|
2455
|
-
await enqueueNotification({
|
|
2456
|
-
method: "turn/completed",
|
|
2457
|
-
params: {
|
|
2458
|
-
threadId: resourceState.thread.threadId,
|
|
2459
|
-
turnId: activeTurnId,
|
|
2460
|
-
turn: turn.turn
|
|
2482
|
+
const bindProjection = async () => {
|
|
2483
|
+
state.activeLocalProjections += 1;
|
|
2484
|
+
try {
|
|
2485
|
+
await Promise.race([promptMirrorPromise, completion]);
|
|
2486
|
+
if (state.completed) return;
|
|
2487
|
+
if (resourceState.turnRoute) try {
|
|
2488
|
+
await Promise.race([resourceState.turnRoute.bindTurn(activeTurnId), completion]);
|
|
2489
|
+
} catch (error) {
|
|
2490
|
+
if (!state.terminalTurnNotificationQueued && !runAbortController.signal.aborted) throw error;
|
|
2491
|
+
await Promise.race([resourceState.turnRoute.drain(), completion]);
|
|
2492
|
+
if (!state.completed) throw error;
|
|
2461
2493
|
}
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2494
|
+
if (!state.completed && isTerminalTurnStatus(turn.turn.status)) {
|
|
2495
|
+
if (!isJsonObject(turn.turn)) throw new Error("Codex turn completion payload is not a JSON object");
|
|
2496
|
+
await enqueueNotification({
|
|
2497
|
+
method: "turn/completed",
|
|
2498
|
+
params: {
|
|
2499
|
+
threadId: resourceState.thread.threadId,
|
|
2500
|
+
turnId: activeTurnId,
|
|
2501
|
+
turn: turn.turn
|
|
2502
|
+
}
|
|
2503
|
+
}, {
|
|
2504
|
+
threadId: resourceState.thread.threadId,
|
|
2505
|
+
turnId: activeTurnId
|
|
2506
|
+
});
|
|
2507
|
+
}
|
|
2508
|
+
} finally {
|
|
2509
|
+
state.activeLocalProjections -= 1;
|
|
2510
|
+
}
|
|
2511
|
+
};
|
|
2512
|
+
const assertSteeringActive = () => {
|
|
2513
|
+
params.hostCapabilities.assertActive();
|
|
2514
|
+
runAbortController.signal.throwIfAborted();
|
|
2515
|
+
if (state.completed || state.terminalTurnNotificationQueued) throw new Error("codex app-server turn is no longer accepting steering");
|
|
2516
|
+
};
|
|
2517
|
+
const workspaceOnly = resolveAttemptFsWorkspaceOnly({
|
|
2518
|
+
config: params.config,
|
|
2519
|
+
sessionAgentId
|
|
2520
|
+
});
|
|
2521
|
+
const imageContext = {
|
|
2522
|
+
workspaceDir: connection.effectiveWorkspace,
|
|
2523
|
+
model: params.model,
|
|
2524
|
+
config: params.config,
|
|
2525
|
+
workspaceOnly,
|
|
2526
|
+
localRoots: workspaceOnly ? void 0 : getAgentScopedMediaLocalRoots(params.config ?? {}, sessionAgentId),
|
|
2527
|
+
sandbox: connection.sandbox?.enabled && connection.sandbox.fsBridge ? {
|
|
2528
|
+
root: connection.sandbox.workspaceDir,
|
|
2529
|
+
bridge: connection.sandbox.fsBridge
|
|
2530
|
+
} : void 0
|
|
2531
|
+
};
|
|
2467
2532
|
const activeSteeringQueue = createCodexSteeringQueue({
|
|
2468
2533
|
client: resourceState.client,
|
|
2469
2534
|
threadId: resourceState.thread.threadId,
|
|
2470
2535
|
turnId: activeTurnId,
|
|
2471
2536
|
requestTimeoutMs: connection.appServer.requestTimeoutMs,
|
|
2472
2537
|
signal: runAbortController.signal,
|
|
2538
|
+
assertActive: assertSteeringActive,
|
|
2539
|
+
prepareMessage: async (text, options) => {
|
|
2540
|
+
const result = await detectAndLoadAgentHarnessPromptImages({
|
|
2541
|
+
...imageContext,
|
|
2542
|
+
prompt: text,
|
|
2543
|
+
existingImages: options.images,
|
|
2544
|
+
imageOrder: options.imageOrder,
|
|
2545
|
+
media: options.media,
|
|
2546
|
+
userTurnTranscriptRecorder: options.userTurnTranscriptRecorder
|
|
2547
|
+
});
|
|
2548
|
+
if (result.failedMediaCount) throw new Error(`failed to hydrate ${result.failedMediaCount} structured image attachment(s) for Codex steering`);
|
|
2549
|
+
return buildCodexUserInput(text, result.images);
|
|
2550
|
+
},
|
|
2473
2551
|
beforeConfirmConsumed: async (items) => {
|
|
2474
|
-
const
|
|
2475
|
-
if (
|
|
2552
|
+
const transcriptItems = items.filter((item) => item.isInboundUserMessage === true || item.userTurnTranscriptRecorder !== void 0);
|
|
2553
|
+
if (transcriptItems.length === 0) return;
|
|
2476
2554
|
await promptMirrorPromise;
|
|
2477
2555
|
const messages = activeProjector.buildSteeringTranscriptPrefix();
|
|
2478
2556
|
if (params.sessionTarget && messages.length > 0) {
|
|
@@ -2490,7 +2568,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2490
2568
|
});
|
|
2491
2569
|
activeProjector.markSteeringTranscriptPersisted();
|
|
2492
2570
|
}
|
|
2493
|
-
for (const item of
|
|
2571
|
+
for (const item of transcriptItems) {
|
|
2494
2572
|
const recorder = item.userTurnTranscriptRecorder;
|
|
2495
2573
|
if (!recorder) continue;
|
|
2496
2574
|
await recorder.persistApproved();
|
|
@@ -2500,7 +2578,8 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2500
2578
|
});
|
|
2501
2579
|
steeringQueueRef.current = activeSteeringQueue;
|
|
2502
2580
|
const claimPendingUserInputAnswer = async (text, optionsLocal) => {
|
|
2503
|
-
if (optionsLocal?.isInboundUserMessage !== true || optionsLocal
|
|
2581
|
+
if (optionsLocal?.isInboundUserMessage !== true || hasPromptImageInput(optionsLocal)) return false;
|
|
2582
|
+
assertSteeringActive();
|
|
2504
2583
|
return await claimPendingAgentQuestionAnswer({
|
|
2505
2584
|
sessionKey: params.sessionKey ?? params.sessionId,
|
|
2506
2585
|
text,
|
|
@@ -2514,14 +2593,17 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2514
2593
|
resolvedBy
|
|
2515
2594
|
});
|
|
2516
2595
|
const queueMessage = async (text, optionsLocal) => {
|
|
2517
|
-
const isInboundUserMessage = optionsLocal?.isInboundUserMessage === true;
|
|
2518
2596
|
if (await claimPendingUserInputAnswer(text, optionsLocal)) {
|
|
2519
2597
|
optionsLocal?.onQueueAccepted?.(true);
|
|
2520
2598
|
return;
|
|
2521
|
-
}
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2599
|
+
}
|
|
2600
|
+
if (optionsLocal?.isInboundUserMessage === true && hasPromptImageInput(optionsLocal)) {
|
|
2601
|
+
assertSteeringActive();
|
|
2602
|
+
try {
|
|
2603
|
+
await cancelPendingUserInput("image-reply");
|
|
2604
|
+
} catch (error) {
|
|
2605
|
+
embeddedAgentLog.warn("failed to cancel codex gateway question before image steering", { error });
|
|
2606
|
+
}
|
|
2525
2607
|
}
|
|
2526
2608
|
try {
|
|
2527
2609
|
await activeSteeringQueue.queue(text, optionsLocal);
|
|
@@ -2536,21 +2618,32 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2536
2618
|
const handle = {
|
|
2537
2619
|
kind: "embedded",
|
|
2538
2620
|
runId: params.runId,
|
|
2621
|
+
startedAtMs: params.startedAtMs,
|
|
2539
2622
|
toolAuthorityFingerprint: params.toolAuthorityFingerprint,
|
|
2623
|
+
permissionChangeOwner: params.permissionChange?.owner,
|
|
2624
|
+
applyPermissionMode: async (mode, revokeApprovals) => {
|
|
2625
|
+
if (!params.permissionChange || terminalState.terminalOutcomeFrozen || params.abortSignal?.aborted || !state.permissionChangeRestart && (state.completed || runAbortController.signal.aborted)) return false;
|
|
2626
|
+
const applied = params.permissionChange.request(mode);
|
|
2627
|
+
state.permissionChangeRestart ??= "requested";
|
|
2628
|
+
runAbortController.abort("permission-change");
|
|
2629
|
+
revokeApprovals();
|
|
2630
|
+
return await applied;
|
|
2631
|
+
},
|
|
2540
2632
|
claimPendingUserInputAnswer,
|
|
2541
2633
|
cancelPendingUserInput,
|
|
2542
2634
|
queueMessage,
|
|
2543
2635
|
messageInjection: {
|
|
2544
|
-
isAvailable: () => !state.completed && !state.terminalTurnNotificationQueued && !
|
|
2636
|
+
isAvailable: () => !state.completed && !state.terminalTurnNotificationQueued && !runAbortController.signal.aborted,
|
|
2545
2637
|
queueMessage
|
|
2546
2638
|
},
|
|
2547
2639
|
isStreaming: () => !state.completed && !runAbortController.signal.aborted,
|
|
2548
2640
|
isAborted: () => runAbortController.signal.aborted,
|
|
2549
|
-
isStopped: () => state.completed ||
|
|
2641
|
+
isStopped: () => state.completed || runAbortController.signal.aborted,
|
|
2642
|
+
ownsLiveness: () => deadlines.ownsExecutionWait() && resourceState.turnRoute?.signal.aborted === false && !state.completed && !state.terminalTurnNotificationQueued && state.activeAppServerTurnRequests === 0 && state.activeLocalProjections === 0,
|
|
2550
2643
|
isAbortable: () => !terminalState.terminalOutcomeFrozen || terminalState.sharedAbortAllowedAfterTerminalOutcome,
|
|
2551
2644
|
isCompacting: () => projectorRef.current?.isCompacting() ?? false,
|
|
2552
2645
|
supportsTranscriptCommitWait: true,
|
|
2553
|
-
supportsQueueMessageImages:
|
|
2646
|
+
supportsQueueMessageImages: params.model.input.includes("image"),
|
|
2554
2647
|
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
|
2555
2648
|
taskSuggestionDeliveryMode: params.taskSuggestionDeliveryMode,
|
|
2556
2649
|
cancel: () => abortExplicitly("cancelled"),
|
|
@@ -2563,26 +2656,10 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2563
2656
|
terminalState.terminalOutcomeFrozen = true;
|
|
2564
2657
|
params.abortSignal?.removeEventListener("abort", abortFromUpstream);
|
|
2565
2658
|
};
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
kind: "clear",
|
|
2571
|
-
threadId: resourceState.thread.threadId
|
|
2572
|
-
});
|
|
2573
|
-
await retireCodexAppServerClientAfterTimedOutTurn(resourceState.client, {
|
|
2574
|
-
threadId: resourceState.thread.threadId,
|
|
2575
|
-
turnId: activeTurnId,
|
|
2576
|
-
reason: String(runAbortController.signal.reason ?? "timeout"),
|
|
2577
|
-
suspectPhysicalClient: state.turnWatchTimeoutKind === "terminal"
|
|
2578
|
-
});
|
|
2579
|
-
})().finally(completeTurn);
|
|
2580
|
-
return;
|
|
2581
|
-
}
|
|
2582
|
-
interruptTurn(activeTurnId).finally(completeTurn);
|
|
2583
|
-
};
|
|
2584
|
-
runAbortController.signal.addEventListener("abort", abortListener, { once: true });
|
|
2585
|
-
if (runAbortController.signal.aborted) abortListener();
|
|
2659
|
+
if (!runAbortController.signal.aborted && params.permissionChange && !params.permissionChange.applied()) {
|
|
2660
|
+
state.permissionChangeRestart = "requested";
|
|
2661
|
+
runAbortController.abort("permission-change");
|
|
2662
|
+
}
|
|
2586
2663
|
return {
|
|
2587
2664
|
activeTurnId,
|
|
2588
2665
|
activeProjector,
|
|
@@ -2590,7 +2667,8 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2590
2667
|
handle,
|
|
2591
2668
|
freezeRunTerminalOutcome,
|
|
2592
2669
|
notifyUserMessagePersisted,
|
|
2593
|
-
abortListener
|
|
2670
|
+
abortListener,
|
|
2671
|
+
ready: bindProjection()
|
|
2594
2672
|
};
|
|
2595
2673
|
}
|
|
2596
2674
|
//#endregion
|
|
@@ -2599,11 +2677,16 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2599
2677
|
const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, releaseSharedClientLeaseAndRetireOneShotClient, releaseSandboxExecEnvironment, runCleanupStep } = resources;
|
|
2600
2678
|
const { connection } = prompt.context.runtime;
|
|
2601
2679
|
const { params, options, runAbortController, terminalState, bindingStore, bindingIdentity } = connection;
|
|
2602
|
-
const { state, steeringQueueRef, userInputBridgeRef,
|
|
2680
|
+
const { state, steeringQueueRef, userInputBridgeRef, deadlines } = turnRuntime;
|
|
2603
2681
|
const { maybeEmitFastModeAutoResetBestEffort, emitLifecycleTerminal, buildLifecycleTerminalMeta } = lifecycle;
|
|
2604
2682
|
const { codexModelCallDiagnostics } = requestRuntime;
|
|
2605
2683
|
const { activeTurnId, abortListener, handle, freezeRunTerminalOutcome } = activeTurn;
|
|
2606
2684
|
prompt.context.attemptTools.scheduledAppAuthoritySourceRef.current = void 0;
|
|
2685
|
+
freezeRunTerminalOutcome();
|
|
2686
|
+
const projectionClose = state.projectionClosed ? void 0 : activeTurn.activeProjector.closeProjection();
|
|
2687
|
+
state.projectionClosed = true;
|
|
2688
|
+
const checkpointCleanup = projectionClose ? runCleanupStep("codex-transcript-checkpoint", () => projectionClose) : void 0;
|
|
2689
|
+
await state.abortCleanup.catch(() => void 0);
|
|
2607
2690
|
try {
|
|
2608
2691
|
steeringQueueRef.current?.cancel();
|
|
2609
2692
|
if (params.isFinalFallbackAttempt !== false) await maybeEmitFastModeAutoResetBestEffort();
|
|
@@ -2613,36 +2696,32 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2613
2696
|
error: "codex app-server run completed without lifecycle terminal event",
|
|
2614
2697
|
...buildLifecycleTerminalMeta({
|
|
2615
2698
|
aborted: runAbortController.signal.aborted && !state.clientClosedAbort,
|
|
2616
|
-
timedOut: state.
|
|
2699
|
+
timedOut: state.timeout !== void 0
|
|
2617
2700
|
})
|
|
2618
2701
|
});
|
|
2619
2702
|
if (trajectoryRecorder && !resourceState.trajectoryEndRecorded) trajectoryRecorder.recordEvent("session.ended", {
|
|
2620
|
-
status: state.
|
|
2703
|
+
status: state.timeout || runAbortController.signal.aborted && !state.clientClosedAbort ? "interrupted" : "cleanup",
|
|
2621
2704
|
threadId: resourceState.thread.threadId,
|
|
2622
2705
|
turnId: activeTurnId,
|
|
2623
|
-
timedOut: state.
|
|
2706
|
+
timedOut: state.timeout !== void 0,
|
|
2624
2707
|
aborted: runAbortController.signal.aborted && !state.clientClosedAbort
|
|
2625
2708
|
});
|
|
2626
2709
|
await runCleanupStep("codex-trajectory-flush", () => trajectoryRecorder?.flush());
|
|
2627
|
-
const retainLiveIncognitoThread = terminalState.turnSucceeded && isIncognitoSessionKey(params.sessionKey);
|
|
2628
|
-
const
|
|
2710
|
+
const retainLiveIncognitoThread = (terminalState.turnSucceeded || state.permissionChangeRestart === "confirmed" && !params.abortSignal?.aborted) && isIncognitoSessionKey(params.sessionKey);
|
|
2711
|
+
const retainLiveThread = ((retainLiveIncognitoThread && resourceState.thread.liveThreadEphemeralPolicy !== void 0 || terminalState.turnSucceeded && !isIncognitoSessionKey(params.sessionKey) && params.cleanupBundleMcpOnRunEnd !== true && resourceState.thread.liveThreadConfigFingerprint !== void 0 && resourceState.thread.preserveNativeModel !== true && resourceState.thread.connectionScope !== "supervision" && !resourceState.thread.ringZeroConfigFingerprint) && resourceState.thread.clientId === resolveCodexAppServerClientInstanceId(resourceState.client) ? (await bindingStore.read(bindingIdentity))?.threadId === resourceState.thread.threadId && await bindingStore.withLease(bindingIdentity, async () => {
|
|
2629
2712
|
if ((await bindingStore.read(bindingIdentity))?.threadId !== resourceState.thread.threadId) return false;
|
|
2630
|
-
return await
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
}), resourceState.thread.liveThreadConfigFingerprint, connection.mutable.pluginAppServer.serviceTier);
|
|
2639
|
-
}) : false;
|
|
2640
|
-
const retainLiveThread = retainLiveIncognitoThread || retainedPersistentThread;
|
|
2641
|
-
const bindingReleased = isIncognitoSessionKey(params.sessionKey) && !retainLiveIncognitoThread ? await bindingStore.mutate(bindingIdentity, {
|
|
2713
|
+
return await retainCodexAppServerBindingSubscription(resourceState.client, resourceState.thread.threadId, {
|
|
2714
|
+
release: resourceState.thread.liveThreadOwnership?.release,
|
|
2715
|
+
configFingerprint: resourceState.thread.liveThreadConfigFingerprint,
|
|
2716
|
+
serviceTier: connection.mutable.pluginAppServer.serviceTier,
|
|
2717
|
+
ephemeralPolicy: resourceState.thread.liveThreadEphemeralPolicy
|
|
2718
|
+
});
|
|
2719
|
+
}) : false) || retainLiveIncognitoThread && resourceState.thread.liveThreadEphemeralPolicy === void 0;
|
|
2720
|
+
const bindingReleased = isIncognitoSessionKey(params.sessionKey) && !retainLiveThread ? await bindingStore.mutate(bindingIdentity, {
|
|
2642
2721
|
kind: "clear",
|
|
2643
2722
|
threadId: resourceState.thread.threadId
|
|
2644
2723
|
}) : true;
|
|
2645
|
-
if (!
|
|
2724
|
+
if (!retainLiveThread) {
|
|
2646
2725
|
if (bindingReleased) {
|
|
2647
2726
|
if (!await unsubscribeCodexThreadBestEffort(resourceState.client, {
|
|
2648
2727
|
threadId: resourceState.thread.threadId,
|
|
@@ -2652,8 +2731,14 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2652
2731
|
}
|
|
2653
2732
|
} finally {
|
|
2654
2733
|
await runCleanupStep("codex-user-input-cancel", () => userInputBridgeRef.current?.cancelPending());
|
|
2655
|
-
await runCleanupStep("codex-turn-
|
|
2734
|
+
await runCleanupStep("codex-turn-deadline-clear", () => deadlines.dispose());
|
|
2735
|
+
await runCleanupStep("codex-dynamic-tool-cleanup", async () => {
|
|
2736
|
+
const cleanupReason = terminalState.turnSucceeded ? "completion" : state.timeout ? "timeout" : runAbortController.signal.aborted ? "cancel" : "error";
|
|
2737
|
+
const cleanups = prompt.context.attemptTools.runCleanups.splice(0);
|
|
2738
|
+
await Promise.allSettled(cleanups.map(async (cleanup) => await cleanup(cleanupReason)));
|
|
2739
|
+
});
|
|
2656
2740
|
await runCleanupStep("codex-route-release", releaseCurrentRoute);
|
|
2741
|
+
await checkpointCleanup;
|
|
2657
2742
|
await runCleanupStep("codex-shared-client-release", releaseSharedClientLeaseAndRetireOneShotClient);
|
|
2658
2743
|
const nativeHookRelay = resourceState.nativeHookRelay;
|
|
2659
2744
|
resourceState.nativeHookRelay = void 0;
|
|
@@ -2667,17 +2752,17 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2667
2752
|
});
|
|
2668
2753
|
await runCleanupStep("codex-sandbox-release", releaseSandboxExecEnvironment);
|
|
2669
2754
|
await runCleanupStep("codex-scoped-mcp-dispose", () => prompt.context.attemptTools.scopedMcpTools?.dispose());
|
|
2670
|
-
await runCleanupStep("codex-
|
|
2755
|
+
await runCleanupStep("codex-configured-mcp-dispose", () => prompt.context.attemptTools.configuredMcp?.dispose());
|
|
2671
2756
|
await runCleanupStep("codex-abort-listener-remove", () => {
|
|
2672
2757
|
runAbortController.signal.removeEventListener("abort", abortListener);
|
|
2673
2758
|
});
|
|
2674
2759
|
await runCleanupStep("codex-steering-cancel", () => steeringQueueRef.current?.cancel());
|
|
2675
|
-
await runCleanupStep("codex-terminal-freeze", freezeRunTerminalOutcome);
|
|
2676
2760
|
await runCleanupStep("codex-reply-backend-detach", () => params.replyOperation?.detachBackend(handle));
|
|
2677
2761
|
await runCleanupStep("codex-active-run-clear", () => {
|
|
2678
2762
|
clearActiveEmbeddedRun(params.sessionId, handle, params.sessionKey, params.sessionFile);
|
|
2679
2763
|
});
|
|
2680
2764
|
}
|
|
2765
|
+
await state.abortCleanup;
|
|
2681
2766
|
}
|
|
2682
2767
|
//#endregion
|
|
2683
2768
|
//#region extensions/codex/src/app-server/workspace-dir-cache.ts
|
|
@@ -2751,21 +2836,21 @@ const CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS = 3e5;
|
|
|
2751
2836
|
const CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS = 2e4;
|
|
2752
2837
|
const CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_TOKENS = 8e3;
|
|
2753
2838
|
const CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_RATIO = .5;
|
|
2754
|
-
const CODEX_APP_SERVER_ROLLOUT_TAIL_READ_BYTES =
|
|
2839
|
+
const CODEX_APP_SERVER_ROLLOUT_TAIL_READ_BYTES = 65536;
|
|
2755
2840
|
const CODEX_APP_SERVER_BYTE_UNITS = {
|
|
2756
2841
|
b: 1,
|
|
2757
2842
|
k: 1024,
|
|
2758
2843
|
kb: 1024,
|
|
2759
2844
|
kib: 1024,
|
|
2760
|
-
m:
|
|
2761
|
-
mb:
|
|
2762
|
-
mib:
|
|
2763
|
-
g:
|
|
2764
|
-
gb:
|
|
2765
|
-
gib:
|
|
2766
|
-
t:
|
|
2767
|
-
tb:
|
|
2768
|
-
tib:
|
|
2845
|
+
m: 1048576,
|
|
2846
|
+
mb: 1048576,
|
|
2847
|
+
mib: 1048576,
|
|
2848
|
+
g: 1073741824,
|
|
2849
|
+
gb: 1073741824,
|
|
2850
|
+
gib: 1073741824,
|
|
2851
|
+
t: 1099511627776,
|
|
2852
|
+
tb: 1099511627776,
|
|
2853
|
+
tib: 1099511627776
|
|
2769
2854
|
};
|
|
2770
2855
|
const codexSessionRecordCache = /* @__PURE__ */ new Map();
|
|
2771
2856
|
function parseCodexAppServerByteLimit(value) {
|
|
@@ -3062,11 +3147,12 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3062
3147
|
const pluginConfig = readCodexPluginConfig(options.pluginConfig);
|
|
3063
3148
|
const requirementsToml = readCodexRequirementsToml({});
|
|
3064
3149
|
const computerUseConfig = resolveCodexComputerUseConfig({ pluginConfig });
|
|
3065
|
-
const { sessionAgentId } =
|
|
3150
|
+
const { sessionAgentId } = resolveSessionAgentIdsStrict({
|
|
3066
3151
|
sessionKey: params.sessionKey,
|
|
3067
3152
|
config: params.config,
|
|
3068
3153
|
agentId: params.agentId
|
|
3069
3154
|
});
|
|
3155
|
+
const policyAgentId = params.sandboxAgentId ?? sessionAgentId;
|
|
3070
3156
|
preDynamicStartupStages.mark("config");
|
|
3071
3157
|
const resolvedWorkspace = resolveUserPath(params.workspaceDir);
|
|
3072
3158
|
await ensureCodexWorkspaceDirOnce(resolvedWorkspace);
|
|
@@ -3075,6 +3161,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3075
3161
|
const contextSessionKey = params.sessionKey?.trim() || sandboxSessionKey;
|
|
3076
3162
|
const sandbox = params.sandbox !== void 0 ? params.sandbox : await resolveSandboxContext({
|
|
3077
3163
|
config: params.config,
|
|
3164
|
+
agentId: params.sandboxAgentId,
|
|
3078
3165
|
sessionKey: sandboxSessionKey,
|
|
3079
3166
|
workspaceDir: resolvedWorkspace
|
|
3080
3167
|
});
|
|
@@ -3085,18 +3172,24 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3085
3172
|
execOverrides: params.execOverrides,
|
|
3086
3173
|
approvals: params.permissionMode === "full" ? void 0 : loadExecApprovals(),
|
|
3087
3174
|
config: params.config,
|
|
3088
|
-
agentId:
|
|
3175
|
+
agentId: policyAgentId
|
|
3089
3176
|
});
|
|
3090
3177
|
const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId);
|
|
3091
3178
|
const preparedEnvironment = params.hostCapabilities.preparedEnvironment?.();
|
|
3092
3179
|
const remoteExec = isCodexRemoteExecPlacementSandbox(sandbox);
|
|
3180
|
+
const assertLocalTargetSupported = (unsupported) => {
|
|
3181
|
+
if (preparedEnvironment?.localProcessEnv && unsupported) throw new Error("This runtime cannot target the diagnosed local installation. Use the saved prompt with a suggested external or manual handoff on this machine.");
|
|
3182
|
+
};
|
|
3183
|
+
assertLocalTargetSupported(sandbox?.enabled === true || remoteExec);
|
|
3093
3184
|
const preparedShellEnvironment = preparedEnvironment ? {
|
|
3094
3185
|
...preparedEnvironment.credentialScrubEnv,
|
|
3095
|
-
|
|
3186
|
+
...sandbox?.enabled || remoteExec ? void 0 : preparedEnvironment.localIdentityEnv,
|
|
3187
|
+
...preparedEnvironment.localProcessEnv
|
|
3096
3188
|
} : void 0;
|
|
3097
3189
|
const shellEnvironment = preparedShellEnvironment && Object.keys(preparedShellEnvironment).length > 0 ? preparedShellEnvironment : void 0;
|
|
3098
|
-
const disableLoginShell = remoteExec || preparedEnvironment?.managedLocalIdentity === true || preparedEnvironment !== void 0 && Object.keys(preparedEnvironment.credentialScrubEnv).length > 0;
|
|
3190
|
+
const disableLoginShell = remoteExec || preparedEnvironment?.localProcessEnv !== void 0 || preparedEnvironment?.managedLocalIdentity === true || preparedEnvironment !== void 0 && Object.keys(preparedEnvironment.credentialScrubEnv).length > 0;
|
|
3099
3191
|
const withPreparedProcessEnv = (appServer) => {
|
|
3192
|
+
assertLocalTargetSupported(appServer.start.transport === "websocket" || Boolean(appServer.remoteWorkspaceRoot));
|
|
3100
3193
|
return shellEnvironment ? {
|
|
3101
3194
|
...appServer,
|
|
3102
3195
|
start: {
|
|
@@ -3118,7 +3211,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3118
3211
|
preDynamicStartupStages.mark("session-agent");
|
|
3119
3212
|
let activeContextEngine = isActiveHarnessContextEngine(params.contextEngine) ? params.contextEngine : void 0;
|
|
3120
3213
|
const isInactiveThreadBootstrapBinding = (binding) => !activeContextEngine && binding?.contextEngine?.projection?.mode === "thread_bootstrap";
|
|
3121
|
-
if (bindingIdentity.kind === "session" && bindingIdentity.sessionKey
|
|
3214
|
+
if (bindingIdentity.kind === "session" && bindingIdentity.sessionKey) {
|
|
3122
3215
|
const authority = resolveCodexRunSessionBindingAuthority({
|
|
3123
3216
|
identity: bindingIdentity,
|
|
3124
3217
|
config: params.config,
|
|
@@ -3361,6 +3454,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3361
3454
|
pluginConfig,
|
|
3362
3455
|
computerUseConfig,
|
|
3363
3456
|
sessionAgentId,
|
|
3457
|
+
policyAgentId,
|
|
3364
3458
|
resolvedWorkspace,
|
|
3365
3459
|
sandboxSessionKey,
|
|
3366
3460
|
contextSessionKey,
|
|
@@ -3378,629 +3472,21 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3378
3472
|
startupPreparedAuth,
|
|
3379
3473
|
startupClientAuthProfileId,
|
|
3380
3474
|
effectiveWorkspace,
|
|
3381
|
-
effectiveCwd,
|
|
3382
|
-
appServer,
|
|
3383
|
-
sessionPermissionPolicy,
|
|
3384
|
-
nativeHookRelayEvents,
|
|
3385
|
-
runAbortController,
|
|
3386
|
-
terminalState,
|
|
3387
|
-
abortExplicitly,
|
|
3388
|
-
abortFromUpstream,
|
|
3389
|
-
resolveReviewerPolicyContext,
|
|
3390
|
-
resolveRuntimeOptionsForCurrentBinding,
|
|
3391
|
-
mutable,
|
|
3392
|
-
initialStartupBindingHadInactiveThreadBootstrap,
|
|
3393
|
-
initialInactiveThreadBootstrapBindingForcedFreshStart
|
|
3394
|
-
};
|
|
3395
|
-
}
|
|
3396
|
-
//#endregion
|
|
3397
|
-
//#region extensions/codex/src/app-server/attempt-context.ts
|
|
3398
|
-
/**
|
|
3399
|
-
* Builds Codex app-server prompt context, workspace bootstrap injections,
|
|
3400
|
-
* system-prompt reports, and context-engine projection decisions.
|
|
3401
|
-
*/
|
|
3402
|
-
const CODEX_NATIVE_PROJECT_DOC_BASENAMES = /* @__PURE__ */ new Set(["agents.md"]);
|
|
3403
|
-
const CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = /* @__PURE__ */ new Set([
|
|
3404
|
-
"identity.md",
|
|
3405
|
-
"soul.md",
|
|
3406
|
-
"user.md"
|
|
3407
|
-
]);
|
|
3408
|
-
const CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = new Set(CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES);
|
|
3409
|
-
const CODEX_MEMORY_CONTEXT_BASENAME = "memory.md";
|
|
3410
|
-
const CODEX_MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set(["memory_search", "memory_get"]);
|
|
3411
|
-
const CODEX_BOOTSTRAP_CONTEXT_ORDER = /* @__PURE__ */ new Map([
|
|
3412
|
-
["soul.md", 10],
|
|
3413
|
-
["identity.md", 20],
|
|
3414
|
-
["user.md", 30],
|
|
3415
|
-
["bootstrap.md", 50],
|
|
3416
|
-
["memory.md", 60]
|
|
3417
|
-
]);
|
|
3418
|
-
/** Reads mirrored Codex session history for harness hooks. */
|
|
3419
|
-
async function readMirroredSessionHistoryMessages(params) {
|
|
3420
|
-
const { admission, ...target } = params;
|
|
3421
|
-
const messages = await readCodexMirroredSessionHistoryMessages(target, admission);
|
|
3422
|
-
if (!messages) embeddedAgentLog.warn("failed to read mirrored session history for codex harness hooks", { sessionFile: params.sessionFile });
|
|
3423
|
-
return messages;
|
|
3424
|
-
}
|
|
3425
|
-
/** Reads a valid thread-bootstrap projection request from context-engine output. */
|
|
3426
|
-
function readContextEngineThreadBootstrapProjection(projection) {
|
|
3427
|
-
if (projection?.mode !== "thread_bootstrap") return;
|
|
3428
|
-
const epoch = projection.epoch?.trim();
|
|
3429
|
-
if (!epoch) {
|
|
3430
|
-
embeddedAgentLog.warn("context engine requested Codex thread-bootstrap projection without an epoch; using per-turn projection");
|
|
3431
|
-
return;
|
|
3432
|
-
}
|
|
3433
|
-
const fingerprint = projection.fingerprint?.trim();
|
|
3434
|
-
return {
|
|
3435
|
-
mode: "thread_bootstrap",
|
|
3436
|
-
epoch,
|
|
3437
|
-
...fingerprint ? { fingerprint } : {}
|
|
3438
|
-
};
|
|
3439
|
-
}
|
|
3440
|
-
/**
|
|
3441
|
-
* Decides whether an existing Codex thread can reuse its context-engine
|
|
3442
|
-
* bootstrap projection or must be reprojected.
|
|
3443
|
-
*/
|
|
3444
|
-
function resolveContextEngineBootstrapProjectionDecision(params) {
|
|
3445
|
-
const bindingProjection = params.startupBinding?.contextEngine?.projection;
|
|
3446
|
-
if (!params.startupBinding?.threadId || !bindingProjection) return {
|
|
3447
|
-
project: true,
|
|
3448
|
-
reason: !params.startupBinding?.threadId ? "missing-thread-binding" : "missing-projection-binding"
|
|
3449
|
-
};
|
|
3450
|
-
if (!params.expectedBinding || !isContextEngineBindingCompatible(params.startupBinding.contextEngine, params.expectedBinding)) return {
|
|
3451
|
-
project: true,
|
|
3452
|
-
reason: "context-engine-binding-mismatch"
|
|
3453
|
-
};
|
|
3454
|
-
if (!areCodexDynamicToolFingerprintsCompatible({
|
|
3455
|
-
previous: params.startupBinding.dynamicToolsFingerprint,
|
|
3456
|
-
next: params.dynamicToolsFingerprint,
|
|
3457
|
-
nextLegacy: params.legacyDynamicToolsFingerprint
|
|
3458
|
-
})) return {
|
|
3459
|
-
project: true,
|
|
3460
|
-
reason: "dynamic-tools-mismatch"
|
|
3461
|
-
};
|
|
3462
|
-
return bindingProjection.mode !== "thread_bootstrap" || bindingProjection.epoch !== params.projection.epoch || bindingProjection.fingerprint !== params.projection.fingerprint ? {
|
|
3463
|
-
project: true,
|
|
3464
|
-
reason: "projection-mismatch"
|
|
3465
|
-
} : {
|
|
3466
|
-
project: false,
|
|
3467
|
-
reason: "matching-thread-bootstrap-binding"
|
|
3468
|
-
};
|
|
3469
|
-
}
|
|
3470
|
-
/**
|
|
3471
|
-
* Loads workspace bootstrap files and partitions them into Codex-native prompt,
|
|
3472
|
-
* developer-instruction, heartbeat, and memory-tool contexts.
|
|
3473
|
-
*/
|
|
3474
|
-
async function buildCodexWorkspaceBootstrapContext(params) {
|
|
3475
|
-
try {
|
|
3476
|
-
const inheritsAgentWorkspace = (params.executionWorkspace ?? params.resolvedWorkspace) !== params.resolvedWorkspace;
|
|
3477
|
-
const promptWorkspace = inheritsAgentWorkspace ? params.resolvedWorkspace : params.effectiveWorkspace;
|
|
3478
|
-
const memoryToolsAvailable = params.memoryToolNames.length > 0 && canRouteCodexWorkspaceMemoryThroughTools({
|
|
3479
|
-
config: params.params.config,
|
|
3480
|
-
agentId: params.params.agentId ?? params.sessionAgentId,
|
|
3481
|
-
workspaceDir: inheritsAgentWorkspace ? params.resolvedWorkspace : params.effectiveWorkspace
|
|
3482
|
-
});
|
|
3483
|
-
const bootstrapFiles = await resolveBootstrapFilesForRun({
|
|
3484
|
-
workspaceDir: params.resolvedWorkspace,
|
|
3485
|
-
config: params.params.config,
|
|
3486
|
-
sessionKey: params.sessionKey,
|
|
3487
|
-
sessionId: params.params.sessionId,
|
|
3488
|
-
chatType: params.params.chatType,
|
|
3489
|
-
agentId: params.params.agentId ?? params.sessionAgentId,
|
|
3490
|
-
warn: (message) => embeddedAgentLog.warn(message),
|
|
3491
|
-
contextMode: params.params.bootstrapContextMode,
|
|
3492
|
-
runKind: params.params.bootstrapContextRunKind
|
|
3493
|
-
});
|
|
3494
|
-
const memoryToolRoutedBootstrapFiles = memoryToolsAvailable ? selectCodexWorkspaceMemoryReferenceFiles({
|
|
3495
|
-
bootstrapFiles,
|
|
3496
|
-
workspaceDir: params.resolvedWorkspace
|
|
3497
|
-
}) : [];
|
|
3498
|
-
const memoryReferenceFiles = memoryToolRoutedBootstrapFiles.map((file) => remapCodexContextFilePath({
|
|
3499
|
-
file: toCodexEmbeddedContextFile(file),
|
|
3500
|
-
sourceWorkspaceDir: params.resolvedWorkspace,
|
|
3501
|
-
targetWorkspaceDir: promptWorkspace
|
|
3502
|
-
}));
|
|
3503
|
-
const contextFiles = buildBootstrapContextForFiles(memoryToolsAvailable ? bootstrapFiles.filter((file) => !isCodexWorkspaceRootMemoryBootstrapFile({
|
|
3504
|
-
file,
|
|
3505
|
-
workspaceDir: params.resolvedWorkspace
|
|
3506
|
-
})) : bootstrapFiles, {
|
|
3507
|
-
config: params.params.config,
|
|
3508
|
-
agentId: params.params.agentId ?? params.sessionAgentId,
|
|
3509
|
-
warn: (message) => embeddedAgentLog.warn(message)
|
|
3510
|
-
}).map((file) => remapCodexContextFilePath({
|
|
3511
|
-
file,
|
|
3512
|
-
sourceWorkspaceDir: params.resolvedWorkspace,
|
|
3513
|
-
targetWorkspaceDir: promptWorkspace
|
|
3514
|
-
}));
|
|
3515
|
-
const promptContextFiles = selectCodexWorkspacePromptContextFiles(contextFiles, {
|
|
3516
|
-
excludeMemory: memoryToolsAvailable,
|
|
3517
|
-
memoryWorkspaceDir: params.effectiveWorkspace
|
|
3518
|
-
});
|
|
3519
|
-
const injectOpenClawContext = shouldInjectCodexOpenClawPromptContext(params.params);
|
|
3520
|
-
const restrictedProjectDocNeedsOpenClawCarrier = params.params.pluginHarnessToolPolicyRestricted === true && !params.params.disableTools && !isMessageOnlyCodexSourceReply(params.params) && params.params.bootstrapContextMode !== "lightweight";
|
|
3521
|
-
const threadDeveloperInstructionFiles = injectOpenClawContext && !params.ringZeroActive && (inheritsAgentWorkspace || restrictedProjectDocNeedsOpenClawCarrier) ? selectCodexWorkspaceAgentProjectInstructionFiles(contextFiles, params.resolvedWorkspace) : [];
|
|
3522
|
-
const turnScopedDeveloperInstructionFiles = injectOpenClawContext ? selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) : [];
|
|
3523
|
-
return {
|
|
3524
|
-
bootstrapFiles,
|
|
3525
|
-
contextFiles,
|
|
3526
|
-
inheritsAgentWorkspace,
|
|
3527
|
-
promptContextFiles,
|
|
3528
|
-
threadDeveloperInstructionFiles,
|
|
3529
|
-
turnScopedDeveloperInstructionFiles,
|
|
3530
|
-
memoryReferenceFiles,
|
|
3531
|
-
memoryToolRoutedBootstrapFiles,
|
|
3532
|
-
memoryToolNames: [...params.memoryToolNames],
|
|
3533
|
-
memoryToolRouted: memoryToolsAvailable,
|
|
3534
|
-
promptContext: renderCodexWorkspaceBootstrapPromptContext(promptContextFiles),
|
|
3535
|
-
threadDeveloperInstructions: renderCodexWorkspaceDeveloperInstructions({
|
|
3536
|
-
files: threadDeveloperInstructionFiles,
|
|
3537
|
-
header: "## OpenClaw Agent Workspace Instructions",
|
|
3538
|
-
preamble: "OpenClaw loaded this bounded snapshot from the configured agent workspace."
|
|
3539
|
-
}),
|
|
3540
|
-
turnScopedDeveloperInstructions: renderCodexWorkspaceCollaborationDeveloperInstructions(turnScopedDeveloperInstructionFiles),
|
|
3541
|
-
memoryCollaborationInstructions: shouldInjectCodexOpenClawPromptContext(params.params) ? await renderCodexWorkspaceMemoryCollaborationInstructions({
|
|
3542
|
-
files: memoryReferenceFiles,
|
|
3543
|
-
toolNames: params.memoryToolNames,
|
|
3544
|
-
memoryToolRouted: memoryToolsAvailable,
|
|
3545
|
-
citationsMode: params.params.config?.memory?.citations,
|
|
3546
|
-
agentId: params.params.agentId ?? params.sessionAgentId,
|
|
3547
|
-
agentSessionKey: params.sessionKey,
|
|
3548
|
-
sandboxed: params.sandboxed
|
|
3549
|
-
}) : void 0
|
|
3550
|
-
};
|
|
3551
|
-
} catch (error) {
|
|
3552
|
-
embeddedAgentLog.warn("failed to load codex workspace bootstrap instructions", { error });
|
|
3553
|
-
return {
|
|
3554
|
-
bootstrapFiles: [],
|
|
3555
|
-
contextFiles: [],
|
|
3556
|
-
inheritsAgentWorkspace: false
|
|
3557
|
-
};
|
|
3558
|
-
}
|
|
3559
|
-
}
|
|
3560
|
-
/**
|
|
3561
|
-
* Builds the prompt-size, bootstrap-file, skill, and tool-schema accounting
|
|
3562
|
-
* report for a Codex run.
|
|
3563
|
-
*/
|
|
3564
|
-
function buildCodexSystemPromptReport(params) {
|
|
3565
|
-
const toolEntries = flattenCodexDynamicToolFunctions(params.tools).map(buildCodexToolReportEntry);
|
|
3566
|
-
const schemaChars = toolEntries.reduce((sum, tool) => sum + tool.schemaChars, 0);
|
|
3567
|
-
const skillsPrompt = params.skillsPrompt.trim();
|
|
3568
|
-
const bootstrapMaxChars = readPositiveNumber(params.attempt.config?.agents?.defaults?.bootstrapMaxChars);
|
|
3569
|
-
const bootstrapTotalMaxChars = readPositiveNumber(params.attempt.config?.agents?.defaults?.bootstrapTotalMaxChars);
|
|
3570
|
-
return {
|
|
3571
|
-
source: "run",
|
|
3572
|
-
generatedAt: Date.now(),
|
|
3573
|
-
sessionId: params.attempt.sessionId,
|
|
3574
|
-
sessionKey: params.sessionKey,
|
|
3575
|
-
provider: params.attempt.provider,
|
|
3576
|
-
model: params.attempt.modelId,
|
|
3577
|
-
workspaceDir: params.workspaceDir,
|
|
3578
|
-
...bootstrapMaxChars ? { bootstrapMaxChars } : {},
|
|
3579
|
-
...bootstrapTotalMaxChars ? { bootstrapTotalMaxChars } : {},
|
|
3580
|
-
systemPrompt: {
|
|
3581
|
-
chars: params.developerInstructions.length,
|
|
3582
|
-
projectContextChars: 0,
|
|
3583
|
-
nonProjectContextChars: params.developerInstructions.length,
|
|
3584
|
-
hash: sha256Text(params.developerInstructions)
|
|
3585
|
-
},
|
|
3586
|
-
injectedWorkspaceFiles: buildCodexBootstrapInjectionStats({
|
|
3587
|
-
bootstrapFiles: params.workspaceBootstrapContext.bootstrapFiles,
|
|
3588
|
-
injectedFiles: params.workspaceBootstrapContext.promptContextFiles ?? [],
|
|
3589
|
-
developerInstructionFiles: [...params.workspaceBootstrapContext.threadDeveloperInstructionFiles ?? [], ...params.workspaceBootstrapContext.turnScopedDeveloperInstructionFiles ?? []],
|
|
3590
|
-
memoryToolRoutedBootstrapFiles: params.workspaceBootstrapContext.memoryToolRoutedBootstrapFiles ?? [],
|
|
3591
|
-
memoryToolRouted: params.workspaceBootstrapContext.memoryToolRouted === true
|
|
3592
|
-
}),
|
|
3593
|
-
skills: {
|
|
3594
|
-
promptChars: skillsPrompt.length,
|
|
3595
|
-
hash: sha256Text(skillsPrompt),
|
|
3596
|
-
entries: buildCodexSkillReportEntries(skillsPrompt)
|
|
3597
|
-
},
|
|
3598
|
-
tools: {
|
|
3599
|
-
listChars: 0,
|
|
3600
|
-
schemaChars,
|
|
3601
|
-
entries: toolEntries
|
|
3602
|
-
}
|
|
3603
|
-
};
|
|
3604
|
-
}
|
|
3605
|
-
function buildCodexSkillReportEntries(skillsPrompt) {
|
|
3606
|
-
if (!skillsPrompt) return [];
|
|
3607
|
-
return Array.from(skillsPrompt.matchAll(/<skill>[\s\S]*?<\/skill>/gi)).map((match) => match[0] ?? "").map((block) => ({
|
|
3608
|
-
name: block.match(/<name>\s*([^<]+?)\s*<\/name>/i)?.[1]?.trim() || "(unknown)",
|
|
3609
|
-
blockChars: block.length
|
|
3610
|
-
})).filter((entry) => entry.blockChars > 0);
|
|
3611
|
-
}
|
|
3612
|
-
function buildCodexToolReportEntry(tool) {
|
|
3613
|
-
const summary = tool.description.trim();
|
|
3614
|
-
if (tool.deferLoading === true) return {
|
|
3615
|
-
name: tool.name,
|
|
3616
|
-
summaryChars: summary.length,
|
|
3617
|
-
summaryHash: sha256Text(summary),
|
|
3618
|
-
schemaChars: 0,
|
|
3619
|
-
schemaHash: stableJsonHash(null),
|
|
3620
|
-
propertiesCount: null
|
|
3621
|
-
};
|
|
3622
|
-
return {
|
|
3623
|
-
name: tool.name,
|
|
3624
|
-
summaryChars: summary.length,
|
|
3625
|
-
summaryHash: sha256Text(summary),
|
|
3626
|
-
...buildCodexToolSchemaStats(tool.inputSchema)
|
|
3627
|
-
};
|
|
3628
|
-
}
|
|
3629
|
-
function buildCodexToolSchemaStats(schema) {
|
|
3630
|
-
const schemaChars = (() => {
|
|
3631
|
-
try {
|
|
3632
|
-
return JSON.stringify(schema).length;
|
|
3633
|
-
} catch {
|
|
3634
|
-
return 0;
|
|
3635
|
-
}
|
|
3636
|
-
})();
|
|
3637
|
-
const properties = isJsonObject(schema) && isJsonObject(schema.properties) ? schema.properties : null;
|
|
3638
|
-
return {
|
|
3639
|
-
schemaChars,
|
|
3640
|
-
schemaHash: stableJsonHash(schema),
|
|
3641
|
-
propertiesCount: properties ? Object.keys(properties).length : null
|
|
3642
|
-
};
|
|
3643
|
-
}
|
|
3644
|
-
function sha256Text(value) {
|
|
3645
|
-
return createHash("sha256").update(value).digest("hex");
|
|
3646
|
-
}
|
|
3647
|
-
function normalizeForStableHash(value) {
|
|
3648
|
-
if (Array.isArray(value)) return value.map((entry) => normalizeForStableHash(entry));
|
|
3649
|
-
if (value && typeof value === "object") {
|
|
3650
|
-
const record = value;
|
|
3651
|
-
return Object.fromEntries(Object.keys(record).toSorted((left, right) => left.localeCompare(right)).map((key) => [key, normalizeForStableHash(record[key])]));
|
|
3652
|
-
}
|
|
3653
|
-
return value;
|
|
3654
|
-
}
|
|
3655
|
-
function stableJsonHash(value) {
|
|
3656
|
-
return sha256Text(JSON.stringify(normalizeForStableHash(value)) ?? "null");
|
|
3657
|
-
}
|
|
3658
|
-
function buildCodexBootstrapInjectionStats(params) {
|
|
3659
|
-
const injectedIndex = indexCodexContextFileContent(params.injectedFiles);
|
|
3660
|
-
const developerInstructionIndex = indexCodexContextFileContent(params.developerInstructionFiles ?? []);
|
|
3661
|
-
const memoryToolRoutedPaths = new Set((params.memoryToolRoutedBootstrapFiles ?? []).map((file) => readNonBlankString(file.path)).filter(isNonEmptyString$1).map(normalizeCodexContextFilePath));
|
|
3662
|
-
return params.bootstrapFiles.map((file) => {
|
|
3663
|
-
const fileName = readNonBlankString(file.name);
|
|
3664
|
-
const pathValue = readNonBlankString(file.path) ?? fileName ?? "";
|
|
3665
|
-
const displayName = (fileName ?? getCodexContextFileDisplayBasename(pathValue)) || pathValue;
|
|
3666
|
-
const baseName = getCodexContextFileBasename(pathValue || fileName || "");
|
|
3667
|
-
const rawChars = file.missing ? 0 : (file.content ?? "").trimEnd().length;
|
|
3668
|
-
const memoryToolRoutedFile = baseName === CODEX_MEMORY_CONTEXT_BASENAME && params.memoryToolRouted === true && memoryToolRoutedPaths.has(normalizeCodexContextFilePath(pathValue));
|
|
3669
|
-
const injected = memoryToolRoutedFile ? void 0 : readCodexIndexedContextFileContent(injectedIndex, pathValue, fileName) ?? readCodexIndexedContextFileContent(developerInstructionIndex, pathValue, fileName);
|
|
3670
|
-
if (!file.missing && injected === void 0 && CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName)) return {
|
|
3671
|
-
name: displayName,
|
|
3672
|
-
path: pathValue,
|
|
3673
|
-
missing: false,
|
|
3674
|
-
rawChars,
|
|
3675
|
-
injectionStatus: "native_unverified",
|
|
3676
|
-
injectedChars: null,
|
|
3677
|
-
truncated: null
|
|
3678
|
-
};
|
|
3679
|
-
const injectedChars = memoryToolRoutedFile ? 0 : injected?.length ?? 0;
|
|
3680
|
-
const truncated = memoryToolRoutedFile ? false : !file.missing && injectedChars < rawChars;
|
|
3681
|
-
return {
|
|
3682
|
-
name: displayName,
|
|
3683
|
-
path: pathValue,
|
|
3684
|
-
missing: file.missing,
|
|
3685
|
-
rawChars,
|
|
3686
|
-
injectedChars,
|
|
3687
|
-
truncated
|
|
3688
|
-
};
|
|
3689
|
-
});
|
|
3690
|
-
}
|
|
3691
|
-
function indexCodexContextFileContent(files) {
|
|
3692
|
-
const byPath = /* @__PURE__ */ new Map();
|
|
3693
|
-
const byBaseName = /* @__PURE__ */ new Map();
|
|
3694
|
-
for (const file of files) {
|
|
3695
|
-
const pathValue = readNonBlankString(file.path);
|
|
3696
|
-
if (!pathValue) continue;
|
|
3697
|
-
if (!byPath.has(pathValue)) byPath.set(pathValue, file.content);
|
|
3698
|
-
const baseName = getCodexContextFileBasename(pathValue);
|
|
3699
|
-
if (baseName && !byBaseName.has(baseName)) byBaseName.set(baseName, file.content);
|
|
3700
|
-
}
|
|
3701
|
-
return {
|
|
3702
|
-
byPath,
|
|
3703
|
-
byBaseName
|
|
3704
|
-
};
|
|
3705
|
-
}
|
|
3706
|
-
function readCodexIndexedContextFileContent(index, pathValue, fileName) {
|
|
3707
|
-
const pathContent = index.byPath.get(pathValue);
|
|
3708
|
-
if (pathContent !== void 0) return pathContent;
|
|
3709
|
-
if (fileName) {
|
|
3710
|
-
const nameContent = index.byPath.get(fileName);
|
|
3711
|
-
if (nameContent !== void 0) return nameContent;
|
|
3712
|
-
}
|
|
3713
|
-
const baseName = getCodexContextFileBasename(fileName ?? pathValue);
|
|
3714
|
-
return baseName ? index.byBaseName.get(baseName) : void 0;
|
|
3715
|
-
}
|
|
3716
|
-
function readPositiveNumber(value) {
|
|
3717
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : void 0;
|
|
3718
|
-
}
|
|
3719
|
-
/**
|
|
3720
|
-
* Builds OpenClaw-provided workspace prompt context for the current Codex turn.
|
|
3721
|
-
*/
|
|
3722
|
-
function buildCodexOpenClawPromptContext(params) {
|
|
3723
|
-
if (!shouldInjectCodexOpenClawPromptContext(params.params)) return;
|
|
3724
|
-
const sections = [params.workspacePromptContext?.trim() ? [
|
|
3725
|
-
"## OpenClaw Workspace Context",
|
|
3726
|
-
"",
|
|
3727
|
-
params.workspacePromptContext.trim()
|
|
3728
|
-
].join("\n") : void 0, params.watchedSessionsContext?.trim() || void 0].filter(isNonEmptyString$1);
|
|
3729
|
-
if (sections.length === 0) return;
|
|
3730
|
-
return [
|
|
3731
|
-
"OpenClaw runtime context for this turn:",
|
|
3732
|
-
"Treat this OpenClaw-provided context as supporting project/user reference for the current request.",
|
|
3733
|
-
"",
|
|
3734
|
-
...sections
|
|
3735
|
-
].join("\n");
|
|
3736
|
-
}
|
|
3737
|
-
/**
|
|
3738
|
-
* Renders the watched-sessions block for the Codex per-turn runtime context.
|
|
3739
|
-
* Codex builds its own instruction layers, so the embedded prompt's Watched
|
|
3740
|
-
* Sessions section must be re-surfaced here or Codex-backed main sessions
|
|
3741
|
-
* keep refusing cross-session questions (openclaw#114797).
|
|
3742
|
-
*/
|
|
3743
|
-
function buildCodexWatchedSessionsContext(params) {
|
|
3744
|
-
if (!shouldInjectCodexOpenClawPromptContext(params.attempt)) return;
|
|
3745
|
-
return buildWatchedSessionsHarnessContext({
|
|
3746
|
-
config: params.attempt.config,
|
|
3747
|
-
sessionKey: params.sessionKey,
|
|
3748
|
-
sandboxed: params.sandboxed,
|
|
3749
|
-
toolNames: flattenCodexDynamicToolFunctions(params.dynamicTools).map((tool) => normalizeCodexDynamicToolName(tool.name))
|
|
3750
|
-
});
|
|
3751
|
-
}
|
|
3752
|
-
function shouldInjectCodexOpenClawPromptContext(params) {
|
|
3753
|
-
return !(params.bootstrapContextMode === "lightweight" && params.bootstrapContextRunKind === "cron");
|
|
3754
|
-
}
|
|
3755
|
-
/** Renders loaded OpenClaw skill prompts as Codex collaboration instructions. */
|
|
3756
|
-
function renderCodexSkillsCollaborationInstructions(params) {
|
|
3757
|
-
if (!shouldInjectCodexOpenClawPromptContext(params.attempt)) return;
|
|
3758
|
-
return params.skillsPrompt?.trim() ? [
|
|
3759
|
-
"## OpenClaw Skills",
|
|
3760
|
-
"",
|
|
3761
|
-
params.skillsPrompt.trim()
|
|
3762
|
-
].join("\n") : void 0;
|
|
3763
|
-
}
|
|
3764
|
-
/**
|
|
3765
|
-
* Prepends OpenClaw context while preserving leading delivery metadata as
|
|
3766
|
-
* routing guidance instead of user request text.
|
|
3767
|
-
*/
|
|
3768
|
-
function prependCodexOpenClawPromptContext(prompt, context, options = {}) {
|
|
3769
|
-
const { deliveryHint, prompt: promptWithoutDeliveryHint } = splitLeadingCodexDeliveryHint(prompt);
|
|
3770
|
-
if (!context?.trim() && (!deliveryHint || options.preservePromptWithoutContext)) return prompt;
|
|
3771
|
-
const promptSection = promptWithoutDeliveryHint.startsWith("OpenClaw assembled context for this turn:") ? promptWithoutDeliveryHint : ["Current user request:", promptWithoutDeliveryHint].join("\n");
|
|
3772
|
-
const deliverySection = deliveryHint ? [
|
|
3773
|
-
"OpenClaw delivery metadata:",
|
|
3774
|
-
"This delivery metadata is runtime routing guidance, not the user's request.",
|
|
3775
|
-
deliveryHint
|
|
3776
|
-
].join("\n") : void 0;
|
|
3777
|
-
return [
|
|
3778
|
-
context?.trim(),
|
|
3779
|
-
deliverySection,
|
|
3780
|
-
promptSection
|
|
3781
|
-
].filter(Boolean).join("\n\n");
|
|
3782
|
-
}
|
|
3783
|
-
/**
|
|
3784
|
-
* Maps the surviving user-request portion of an input range after delivery
|
|
3785
|
-
* metadata has been relocated before the request.
|
|
3786
|
-
*/
|
|
3787
|
-
function resolveCodexDeliveryHintPreservedInputRange(params) {
|
|
3788
|
-
const { prompt, promptInputRange, decoratedPrompt } = params;
|
|
3789
|
-
const { deliveryHint, prompt: promptWithoutDeliveryHint } = splitLeadingCodexDeliveryHint(prompt);
|
|
3790
|
-
if (!deliveryHint || !promptInputRange || promptInputRange.start < 0 || promptInputRange.end < promptInputRange.start || promptInputRange.end > prompt.length || !decoratedPrompt.endsWith(promptWithoutDeliveryHint)) return;
|
|
3791
|
-
const promptWithoutDeliveryHintStart = prompt.length - promptWithoutDeliveryHint.length;
|
|
3792
|
-
const inputStart = Math.max(promptInputRange.start, promptWithoutDeliveryHintStart);
|
|
3793
|
-
const inputEnd = Math.max(inputStart, Math.min(promptInputRange.end, promptWithoutDeliveryHint.length + promptWithoutDeliveryHintStart));
|
|
3794
|
-
const decoratedPromptSuffixStart = decoratedPrompt.length - promptWithoutDeliveryHint.length;
|
|
3795
|
-
const requestHeader = "Current user request:\n";
|
|
3796
|
-
const requestHeaderStart = decoratedPromptSuffixStart - 22;
|
|
3797
|
-
return {
|
|
3798
|
-
start: inputStart === promptWithoutDeliveryHintStart && decoratedPrompt.slice(requestHeaderStart, decoratedPromptSuffixStart) === requestHeader ? requestHeaderStart : decoratedPromptSuffixStart + inputStart - promptWithoutDeliveryHintStart,
|
|
3799
|
-
end: decoratedPromptSuffixStart + inputEnd - promptWithoutDeliveryHintStart
|
|
3800
|
-
};
|
|
3801
|
-
}
|
|
3802
|
-
function splitLeadingCodexDeliveryHint(prompt) {
|
|
3803
|
-
const trimmedStart = prompt.trimStart();
|
|
3804
|
-
const matchedHint = MESSAGE_TOOL_DELIVERY_HINTS.find((hint) => trimmedStart.startsWith(hint));
|
|
3805
|
-
if (!matchedHint) return { prompt };
|
|
3806
|
-
return {
|
|
3807
|
-
deliveryHint: matchedHint,
|
|
3808
|
-
prompt: trimmedStart.slice(matchedHint.length).replace(/^\s*\n/, "").trimStart()
|
|
3809
|
-
};
|
|
3810
|
-
}
|
|
3811
|
-
function renderCodexWorkspaceBootstrapPromptContext(contextFiles) {
|
|
3812
|
-
const files = contextFiles;
|
|
3813
|
-
if (files.length === 0) return;
|
|
3814
|
-
const lines = [
|
|
3815
|
-
"OpenClaw loaded these user-editable workspace files for the current turn. Codex loads project-local AGENTS.md natively. When execution uses another folder, OpenClaw supplies the agent workspace AGENTS.md as thread-level developer instructions. SOUL.md, IDENTITY.md, and USER.md remain turn-scoped collaboration instructions. Those files are not repeated here.",
|
|
3816
|
-
"",
|
|
3817
|
-
"# Project Context",
|
|
3818
|
-
"",
|
|
3819
|
-
"The following project context files have been loaded:"
|
|
3820
|
-
];
|
|
3821
|
-
lines.push("");
|
|
3822
|
-
for (const file of files) lines.push(`## ${file.path}`, "", file.content, "");
|
|
3823
|
-
return lines.join("\n").trim();
|
|
3824
|
-
}
|
|
3825
|
-
function selectCodexWorkspacePromptContextFiles(contextFiles, options = {}) {
|
|
3826
|
-
const excludeMemory = options.excludeMemory ?? true;
|
|
3827
|
-
return contextFiles.filter((file) => {
|
|
3828
|
-
const baseName = getCodexContextFileBasename(file.path);
|
|
3829
|
-
return baseName && !CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName) && !CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES.has(baseName) && (!excludeMemory || !isCodexWorkspaceRootMemoryContextFile({
|
|
3830
|
-
file,
|
|
3831
|
-
workspaceDir: options.memoryWorkspaceDir
|
|
3832
|
-
})) && !isMissingCodexBootstrapContextFile(file);
|
|
3833
|
-
}).toSorted(compareCodexContextFiles);
|
|
3834
|
-
}
|
|
3835
|
-
function selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) {
|
|
3836
|
-
return selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES);
|
|
3837
|
-
}
|
|
3838
|
-
function selectCodexWorkspaceAgentProjectInstructionFiles(contextFiles, agentWorkspaceDir) {
|
|
3839
|
-
const agentProjectDocPath = path.join(path.resolve(agentWorkspaceDir), "AGENTS.md");
|
|
3840
|
-
return selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, CODEX_NATIVE_PROJECT_DOC_BASENAMES).filter((file) => path.resolve(file.path) === agentProjectDocPath);
|
|
3841
|
-
}
|
|
3842
|
-
function selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, basenames) {
|
|
3843
|
-
return contextFiles.filter((file) => {
|
|
3844
|
-
const baseName = getCodexContextFileBasename(file.path);
|
|
3845
|
-
return baseName && basenames.has(baseName) && !isMissingCodexBootstrapContextFile(file) && file.content.trim().length > 0;
|
|
3846
|
-
}).toSorted(compareCodexContextFiles);
|
|
3847
|
-
}
|
|
3848
|
-
function renderCodexWorkspaceCollaborationDeveloperInstructions(files) {
|
|
3849
|
-
return renderCodexWorkspaceDeveloperInstructions({
|
|
3850
|
-
files,
|
|
3851
|
-
header: "## OpenClaw Agent Soul",
|
|
3852
|
-
preamble: "OpenClaw loaded these workspace instruction files from the active agent workspace. They are the canonical definitions of who you are, how you think and work, and the human you work alongside. Internalize and follow them accordingly.",
|
|
3853
|
-
wrapperTag: "AGENT_SOUL"
|
|
3854
|
-
});
|
|
3855
|
-
}
|
|
3856
|
-
function renderCodexWorkspaceDeveloperInstructions(params) {
|
|
3857
|
-
const { files, header, preamble, wrapperTag } = params;
|
|
3858
|
-
if (files.length === 0) return;
|
|
3859
|
-
const lines = [
|
|
3860
|
-
header,
|
|
3861
|
-
"",
|
|
3862
|
-
preamble,
|
|
3863
|
-
""
|
|
3864
|
-
];
|
|
3865
|
-
if (wrapperTag) lines.push(`<${wrapperTag}>`, "");
|
|
3866
|
-
for (const file of files) lines.push(`### ${file.path}`, "", file.content, "");
|
|
3867
|
-
if (wrapperTag) lines.push(`</${wrapperTag}>`);
|
|
3868
|
-
return lines.join("\n").trim();
|
|
3869
|
-
}
|
|
3870
|
-
function selectCodexWorkspaceMemoryReferenceFiles(params) {
|
|
3871
|
-
return params.bootstrapFiles.filter((file) => {
|
|
3872
|
-
return isCodexWorkspaceRootMemoryBootstrapFile({
|
|
3873
|
-
file,
|
|
3874
|
-
workspaceDir: params.workspaceDir
|
|
3875
|
-
}) && !file.missing && (file.content ?? "").trim().length > 0;
|
|
3876
|
-
}).toSorted(compareCodexBootstrapFiles);
|
|
3877
|
-
}
|
|
3878
|
-
/**
|
|
3879
|
-
* Renders a memory-file reference that points Codex at memory tools instead of
|
|
3880
|
-
* embedding MEMORY.md contents.
|
|
3881
|
-
*/
|
|
3882
|
-
function renderCodexWorkspaceMemoryReference(params) {
|
|
3883
|
-
if (params.files.length === 0) return;
|
|
3884
|
-
const lines = [
|
|
3885
|
-
"## OpenClaw Workspace Memory",
|
|
3886
|
-
"",
|
|
3887
|
-
`MEMORY.md exists in the active agent workspace as a memory file, not an instruction file. OpenClaw does not paste its contents into native Codex turns; use ${(params.toolNames?.length ? params.toolNames : Array.from(CODEX_MEMORY_TOOL_NAMES)).join(" or ")} when durable memory is relevant and the tools are available.`,
|
|
3888
|
-
""
|
|
3889
|
-
];
|
|
3890
|
-
for (const file of params.files) lines.push(`- ${file.path}`);
|
|
3891
|
-
return lines.join("\n").trim();
|
|
3892
|
-
}
|
|
3893
|
-
async function renderCodexWorkspaceMemoryCollaborationInstructions(params) {
|
|
3894
|
-
const sections = [params.memoryToolRouted ? await renderCodexMemoryRecallInstructions({
|
|
3895
|
-
toolNames: params.toolNames,
|
|
3896
|
-
citationsMode: params.citationsMode,
|
|
3897
|
-
agentId: params.agentId,
|
|
3898
|
-
agentSessionKey: params.agentSessionKey,
|
|
3899
|
-
sandboxed: params.sandboxed
|
|
3900
|
-
}) : void 0, renderCodexWorkspaceMemoryReference({
|
|
3901
|
-
files: params.files,
|
|
3902
|
-
toolNames: params.toolNames
|
|
3903
|
-
})].filter(isNonEmptyString$1);
|
|
3904
|
-
return sections.length > 0 ? sections.join("\n\n") : void 0;
|
|
3905
|
-
}
|
|
3906
|
-
async function renderCodexMemoryRecallInstructions(params) {
|
|
3907
|
-
const memoryPrompt = await prepareMemorySystemPromptAddition({
|
|
3908
|
-
availableTools: new Set(params.toolNames),
|
|
3909
|
-
citationsMode: params.citationsMode,
|
|
3910
|
-
agentId: params.agentId,
|
|
3911
|
-
agentSessionKey: params.agentSessionKey,
|
|
3912
|
-
sandboxed: params.sandboxed
|
|
3913
|
-
});
|
|
3914
|
-
if (!memoryPrompt) return;
|
|
3915
|
-
return [memoryPrompt, renderCodexMemoryToolSearchBridge(params.toolNames)].filter(isNonEmptyString$1).join("\n").trim();
|
|
3916
|
-
}
|
|
3917
|
-
function renderCodexMemoryToolSearchBridge(toolNames) {
|
|
3918
|
-
const memoryToolNames = toolNames.map((name) => normalizeCodexDynamicToolName(name)).filter((name) => CODEX_MEMORY_TOOL_NAMES.has(name)).toSorted();
|
|
3919
|
-
if (memoryToolNames.length === 0) return;
|
|
3920
|
-
return `Codex may expose ${memoryToolNames.join(" and ")} as deferred tools. When the memory guidance above calls for memory recall, use an already-loaded memory tool directly. If the needed memory tool is deferred and not currently callable, use \`tool_search\` to load it, then call that memory tool.`;
|
|
3921
|
-
}
|
|
3922
|
-
/** Lists available memory tool names understood by Codex workspace memory routing. */
|
|
3923
|
-
function getCodexWorkspaceMemoryToolNames(tools) {
|
|
3924
|
-
const availableToolNames = new Set(flattenCodexDynamicToolFunctions(tools).map((tool) => normalizeCodexDynamicToolName(tool.name)));
|
|
3925
|
-
return Array.from(CODEX_MEMORY_TOOL_NAMES).filter((name) => availableToolNames.has(name));
|
|
3926
|
-
}
|
|
3927
|
-
function canRouteCodexWorkspaceMemoryThroughTools(params) {
|
|
3928
|
-
if (!params.config) return false;
|
|
3929
|
-
return isSameCodexWorkspacePath(resolveAgentWorkspaceDir(params.config, params.agentId), params.workspaceDir);
|
|
3930
|
-
}
|
|
3931
|
-
function isMissingCodexBootstrapContextFile(file) {
|
|
3932
|
-
return file.content.trimStart().startsWith("[MISSING] Expected at:");
|
|
3933
|
-
}
|
|
3934
|
-
function toCodexEmbeddedContextFile(file) {
|
|
3935
|
-
return {
|
|
3936
|
-
path: readNonBlankString(file.path) ?? readNonBlankString(file.name) ?? "",
|
|
3937
|
-
content: file.content ?? ""
|
|
3938
|
-
};
|
|
3939
|
-
}
|
|
3940
|
-
function isCodexWorkspaceRootMemoryBootstrapFile(params) {
|
|
3941
|
-
return isCodexWorkspaceRootMemoryPath({
|
|
3942
|
-
filePath: readNonBlankString(params.file.path) ?? readNonBlankString(params.file.name) ?? "",
|
|
3943
|
-
workspaceDir: params.workspaceDir
|
|
3944
|
-
});
|
|
3945
|
-
}
|
|
3946
|
-
function isCodexWorkspaceRootMemoryContextFile(params) {
|
|
3947
|
-
if (!params.workspaceDir) return false;
|
|
3948
|
-
return isCodexWorkspaceRootMemoryPath({
|
|
3949
|
-
filePath: params.file.path,
|
|
3950
|
-
workspaceDir: params.workspaceDir
|
|
3951
|
-
});
|
|
3952
|
-
}
|
|
3953
|
-
function isCodexWorkspaceRootMemoryPath(params) {
|
|
3954
|
-
const filePath = params.filePath.trim();
|
|
3955
|
-
if (!filePath) return false;
|
|
3956
|
-
return (path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(params.workspaceDir, filePath)) === path.join(path.resolve(params.workspaceDir), "MEMORY.md");
|
|
3957
|
-
}
|
|
3958
|
-
function isSameCodexWorkspacePath(left, right) {
|
|
3959
|
-
return path.resolve(left) === path.resolve(right);
|
|
3960
|
-
}
|
|
3961
|
-
/**
|
|
3962
|
-
* Remaps bootstrap file paths from the resolved workspace to the effective Codex
|
|
3963
|
-
* workspace while preserving platform path separators.
|
|
3964
|
-
*/
|
|
3965
|
-
function remapCodexContextFilePath(params) {
|
|
3966
|
-
const relativePath = path.relative(params.sourceWorkspaceDir, params.file.path);
|
|
3967
|
-
if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath) || params.sourceWorkspaceDir === params.targetWorkspaceDir) return params.file;
|
|
3968
|
-
const targetUsesPosixSeparators = params.targetWorkspaceDir.includes("/") && !params.targetWorkspaceDir.includes("\\");
|
|
3969
|
-
const normalizedRelativePath = targetUsesPosixSeparators ? relativePath.replaceAll("\\", "/") : relativePath.replaceAll("/", "\\");
|
|
3970
|
-
return {
|
|
3971
|
-
...params.file,
|
|
3972
|
-
path: targetUsesPosixSeparators ? path.posix.join(params.targetWorkspaceDir, normalizedRelativePath) : path.win32.join(params.targetWorkspaceDir, normalizedRelativePath)
|
|
3475
|
+
effectiveCwd,
|
|
3476
|
+
appServer,
|
|
3477
|
+
sessionPermissionPolicy,
|
|
3478
|
+
nativeHookRelayEvents,
|
|
3479
|
+
runAbortController,
|
|
3480
|
+
terminalState,
|
|
3481
|
+
abortExplicitly,
|
|
3482
|
+
abortFromUpstream,
|
|
3483
|
+
resolveReviewerPolicyContext,
|
|
3484
|
+
resolveRuntimeOptionsForCurrentBinding,
|
|
3485
|
+
mutable,
|
|
3486
|
+
initialStartupBindingHadInactiveThreadBootstrap,
|
|
3487
|
+
initialInactiveThreadBootstrapBindingForcedFreshStart
|
|
3973
3488
|
};
|
|
3974
3489
|
}
|
|
3975
|
-
function compareCodexContextFiles(left, right) {
|
|
3976
|
-
const leftPath = normalizeCodexContextFilePath(left.path);
|
|
3977
|
-
const rightPath = normalizeCodexContextFilePath(right.path);
|
|
3978
|
-
const leftBase = getCodexContextFileBasename(left.path);
|
|
3979
|
-
const rightBase = getCodexContextFileBasename(right.path);
|
|
3980
|
-
const leftOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(leftBase) ?? Number.MAX_SAFE_INTEGER;
|
|
3981
|
-
const rightOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(rightBase) ?? Number.MAX_SAFE_INTEGER;
|
|
3982
|
-
if (leftOrder !== rightOrder) return leftOrder - rightOrder;
|
|
3983
|
-
if (leftBase !== rightBase) return leftBase.localeCompare(rightBase);
|
|
3984
|
-
return leftPath.localeCompare(rightPath);
|
|
3985
|
-
}
|
|
3986
|
-
function compareCodexBootstrapFiles(left, right) {
|
|
3987
|
-
return compareCodexContextFiles(toCodexEmbeddedContextFile(left), toCodexEmbeddedContextFile(right));
|
|
3988
|
-
}
|
|
3989
|
-
function normalizeCodexContextFilePath(filePath) {
|
|
3990
|
-
return filePath.trim().replaceAll("\\", "/").toLowerCase();
|
|
3991
|
-
}
|
|
3992
|
-
function getCodexContextFileDisplayBasename(filePath) {
|
|
3993
|
-
return filePath.trim().replaceAll("\\", "/").split("/").pop()?.trim() ?? "";
|
|
3994
|
-
}
|
|
3995
|
-
function getCodexContextFileBasename(filePath) {
|
|
3996
|
-
return normalizeCodexContextFilePath(filePath).split("/").pop() ?? "";
|
|
3997
|
-
}
|
|
3998
|
-
function normalizeCodexDynamicToolName(name) {
|
|
3999
|
-
return name.trim().toLowerCase();
|
|
4000
|
-
}
|
|
4001
|
-
function isNonEmptyString$1(value) {
|
|
4002
|
-
return typeof value === "string" && value.length > 0;
|
|
4003
|
-
}
|
|
4004
3490
|
//#endregion
|
|
4005
3491
|
//#region extensions/codex/src/app-server/run-attempt-state.ts
|
|
4006
3492
|
async function clearCodexBindingAfterInvalidImagePayload(bindingStore, identity, fields) {
|
|
@@ -4048,21 +3534,6 @@ function isCodexActiveCompactTurnError(error) {
|
|
|
4048
3534
|
const codexErrorInfo = isJsonObject(data?.codexErrorInfo) ? data.codexErrorInfo : void 0;
|
|
4049
3535
|
return (isJsonObject(codexErrorInfo?.activeTurnNotSteerable) ? codexErrorInfo.activeTurnNotSteerable : void 0)?.turnKind === "compact";
|
|
4050
3536
|
}
|
|
4051
|
-
function readCodexFinalizationHookNotification(notification, threadId, turnId) {
|
|
4052
|
-
if (notification.method !== "hook/started" && notification.method !== "hook/completed") return;
|
|
4053
|
-
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
4054
|
-
const run = params && isJsonObject(params.run) ? params.run : void 0;
|
|
4055
|
-
if (params?.threadId !== threadId || params.turnId !== turnId || run?.eventName !== "stop" && run?.eventName !== "subagentStop" || typeof run.id !== "string" || !run.id) return;
|
|
4056
|
-
if (notification.method === "hook/started") return {
|
|
4057
|
-
phase: "started",
|
|
4058
|
-
runId: run.id
|
|
4059
|
-
};
|
|
4060
|
-
return {
|
|
4061
|
-
phase: "completed",
|
|
4062
|
-
runId: run.id,
|
|
4063
|
-
status: typeof run.status === "string" ? run.status : void 0
|
|
4064
|
-
};
|
|
4065
|
-
}
|
|
4066
3537
|
function joinPresentSections(...sections) {
|
|
4067
3538
|
return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
|
|
4068
3539
|
}
|
|
@@ -4070,39 +3541,11 @@ function prependCurrentInboundContext(prompt, context) {
|
|
|
4070
3541
|
const text = context?.text.trim();
|
|
4071
3542
|
return text ? [neutralizeCodexExplicitMentionSigils(text), prompt].filter(Boolean).join("\n\n") : prompt;
|
|
4072
3543
|
}
|
|
4073
|
-
function buildCodexAppServerTimeoutDiagnostics(params) {
|
|
4074
|
-
const readNonBlankDetailString = (key) => {
|
|
4075
|
-
const value = params.details?.[key];
|
|
4076
|
-
return hasNonEmptyString(value) ? value : void 0;
|
|
4077
|
-
};
|
|
4078
|
-
const activeAppServerTurnRequests = asFiniteNumber(params.details?.activeAppServerTurnRequests);
|
|
4079
|
-
const activeTurnItemCount = asFiniteNumber(params.details?.activeTurnItemCount);
|
|
4080
|
-
const terminalTurnNotificationQueued = asBoolean(params.details?.terminalTurnNotificationQueued);
|
|
4081
|
-
const completionIdleWatchArmed = asBoolean(params.details?.completionIdleWatchArmed);
|
|
4082
|
-
const assistantCompletionIdleWatchArmed = asBoolean(params.details?.assistantCompletionIdleWatchArmed);
|
|
4083
|
-
const terminalIdleWatchArmed = asBoolean(params.details?.terminalIdleWatchArmed);
|
|
4084
|
-
return {
|
|
4085
|
-
...params.idleMs !== void 0 ? { idleMs: params.idleMs } : {},
|
|
4086
|
-
...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
|
|
4087
|
-
...params.lastActivityReason ? { lastActivityReason: params.lastActivityReason } : {},
|
|
4088
|
-
...readNonBlankDetailString("lastNotificationMethod") ? { lastNotificationMethod: readNonBlankDetailString("lastNotificationMethod") } : {},
|
|
4089
|
-
...readNonBlankDetailString("lastNotificationItemId") ? { lastNotificationItemId: readNonBlankDetailString("lastNotificationItemId") } : {},
|
|
4090
|
-
...readNonBlankDetailString("lastNotificationItemType") ? { lastNotificationItemType: readNonBlankDetailString("lastNotificationItemType") } : {},
|
|
4091
|
-
...readNonBlankDetailString("lastNotificationItemRole") ? { lastNotificationItemRole: readNonBlankDetailString("lastNotificationItemRole") } : {},
|
|
4092
|
-
...readNonBlankDetailString("lastAssistantTextPreview") ? { lastAssistantTextPreview: readNonBlankDetailString("lastAssistantTextPreview") } : {},
|
|
4093
|
-
...activeAppServerTurnRequests !== void 0 ? { activeAppServerTurnRequests } : {},
|
|
4094
|
-
...activeTurnItemCount !== void 0 ? { activeTurnItemCount } : {},
|
|
4095
|
-
...terminalTurnNotificationQueued !== void 0 ? { terminalTurnNotificationQueued } : {},
|
|
4096
|
-
...completionIdleWatchArmed !== void 0 ? { completionIdleWatchArmed } : {},
|
|
4097
|
-
...assistantCompletionIdleWatchArmed !== void 0 ? { assistantCompletionIdleWatchArmed } : {},
|
|
4098
|
-
...terminalIdleWatchArmed !== void 0 ? { terminalIdleWatchArmed } : {}
|
|
4099
|
-
};
|
|
4100
|
-
}
|
|
4101
3544
|
//#endregion
|
|
4102
3545
|
//#region extensions/codex/src/app-server/run-attempt-context.ts
|
|
4103
3546
|
async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
4104
3547
|
const { connection, runtimeParams, activeSessionId, activeSessionFile, buildActiveRunAttemptParams, effectiveContextWindowInfo, effectiveContextTokenBudget, effectiveRuntimeProviderId, effectiveRuntimeModelId, hookChannelId } = runtime;
|
|
4105
|
-
const { params, sessionAgentId, contextSessionKey, activeContextEngine, initialStartupBindingHadInactiveThreadBootstrap,
|
|
3548
|
+
const { params, sessionAgentId, contextSessionKey, activeContextEngine, initialStartupBindingHadInactiveThreadBootstrap, effectiveWorkspace, effectiveCwd, agentDir, usesSupervisionConnection, resolvedWorkspace, initialInactiveThreadBootstrapBindingForcedFreshStart, sandbox } = connection;
|
|
4106
3549
|
const { toolBridge } = attemptTools;
|
|
4107
3550
|
const activeTranscriptTarget = {
|
|
4108
3551
|
agentId: sessionAgentId,
|
|
@@ -4128,12 +3571,20 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
|
4128
3571
|
const hookContext = {
|
|
4129
3572
|
runId: params.runId,
|
|
4130
3573
|
agentId: sessionAgentId,
|
|
4131
|
-
sessionKey:
|
|
3574
|
+
sessionKey: contextSessionKey,
|
|
4132
3575
|
sessionId: params.sessionId,
|
|
4133
3576
|
workspaceDir: params.workspaceDir,
|
|
4134
|
-
messageProvider: params.messageProvider ?? void 0,
|
|
4135
3577
|
trigger: params.trigger,
|
|
4136
|
-
|
|
3578
|
+
...buildAgentHookContextChannelFields({
|
|
3579
|
+
sessionKey: contextSessionKey,
|
|
3580
|
+
messageChannel: params.messageChannel,
|
|
3581
|
+
messageProvider: params.messageProvider,
|
|
3582
|
+
currentChannelId: hookChannelId,
|
|
3583
|
+
messageTo: params.messageTo,
|
|
3584
|
+
senderId: params.senderId,
|
|
3585
|
+
agentAccountId: params.agentAccountId
|
|
3586
|
+
}),
|
|
3587
|
+
channelContext: params.channelContext,
|
|
4137
3588
|
...hookContextWindowFields
|
|
4138
3589
|
};
|
|
4139
3590
|
const hookRunner = getAgentHarnessHookRunner();
|
|
@@ -4349,7 +3800,7 @@ function createCodexModelCallDiagnosticEmitter(params) {
|
|
|
4349
3800
|
}
|
|
4350
3801
|
/** Classifies model-call failures into timeout/abort buckets for diagnostics. */
|
|
4351
3802
|
function classifyCodexModelCallFailureKind(params) {
|
|
4352
|
-
if (params.timedOut
|
|
3803
|
+
if (params.timedOut) return "timeout";
|
|
4353
3804
|
const errorMessage = params.error ? params.formatError(params.error).toLowerCase() : "";
|
|
4354
3805
|
if (errorMessage.includes("timed out") || errorMessage.includes("timeout")) return "timeout";
|
|
4355
3806
|
if (params.runAborted && !params.clientClosedAbort) return (typeof params.abortReason === "string" ? params.abortReason.toLowerCase() : params.abortReason ? params.formatError(params.abortReason).toLowerCase() : "").includes("timeout") ? "timeout" : "aborted";
|
|
@@ -4357,38 +3808,17 @@ function classifyCodexModelCallFailureKind(params) {
|
|
|
4357
3808
|
}
|
|
4358
3809
|
//#endregion
|
|
4359
3810
|
//#region extensions/codex/src/app-server/attempt-results.ts
|
|
4360
|
-
const CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_USER_MESSAGE = "Codex stopped before confirming the turn was complete. The response may be incomplete; retry if needed.";
|
|
4361
|
-
const CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_SIDE_EFFECT_USER_MESSAGE = "Codex stopped before confirming the turn was complete. Some work may already have been performed; verify the current state before retrying.";
|
|
4362
|
-
const CODEX_APP_SERVER_TERMINAL_IDLE_USER_MESSAGE = "Codex stopped responding: no activity arrived for the turn's liveness window, so the turn was ended and the connection was replaced. Retry to continue on a fresh session.";
|
|
4363
3811
|
/** Joins terminal assistant text blocks into the final attempt answer. */
|
|
4364
3812
|
function collectTerminalAssistantText(result) {
|
|
4365
3813
|
return result.assistantTexts.join("\n\n").trim();
|
|
4366
3814
|
}
|
|
4367
|
-
/**
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
*/
|
|
4371
|
-
function buildCodexAppServerPromptTimeoutOutcome(params) {
|
|
4372
|
-
if (!params.turnCompletionIdleTimedOut) return;
|
|
4373
|
-
if (params.turnWatchTimeoutKind === "terminal") {
|
|
4374
|
-
if (collectTerminalAssistantText(params.result)) return;
|
|
4375
|
-
const terminalReplayBlockedReason = resolveCodexAppServerReplayBlockedReason(params.result);
|
|
4376
|
-
return {
|
|
4377
|
-
message: CODEX_APP_SERVER_TERMINAL_IDLE_USER_MESSAGE,
|
|
4378
|
-
...terminalReplayBlockedReason ? {
|
|
4379
|
-
replayInvalid: true,
|
|
4380
|
-
livenessState: "abandoned"
|
|
4381
|
-
} : {}
|
|
4382
|
-
};
|
|
4383
|
-
}
|
|
4384
|
-
if (params.turnWatchTimeoutKind !== void 0 && params.turnWatchTimeoutKind !== "completion") return;
|
|
4385
|
-
const replayBlockedReason = resolveCodexAppServerReplayBlockedReason(params.result);
|
|
3815
|
+
/** Reports the owner's deadline without guessing whether native work finished. */
|
|
3816
|
+
function buildCodexAppServerPromptTimeoutOutcome(timeout) {
|
|
3817
|
+
if (!timeout) return;
|
|
4386
3818
|
return {
|
|
4387
|
-
message:
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
livenessState: "abandoned"
|
|
4391
|
-
} : {}
|
|
3819
|
+
message: timeout.kind === "execution" ? "Codex reached the configured execution time limit. Some work may already have been performed; verify the current state before continuing." : "Codex finished its turn, but OpenClaw could not finish processing the result. Some work may already have been performed; verify the current state before continuing.",
|
|
3820
|
+
replayInvalid: true,
|
|
3821
|
+
livenessState: "abandoned"
|
|
4392
3822
|
};
|
|
4393
3823
|
}
|
|
4394
3824
|
/** Explains why an incomplete app-server turn cannot be safely replayed. */
|
|
@@ -4436,101 +3866,17 @@ function isInvalidCodexImagePayloadError(message) {
|
|
|
4436
3866
|
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);
|
|
4437
3867
|
}
|
|
4438
3868
|
//#endregion
|
|
4439
|
-
//#region extensions/codex/src/app-server/settled-turn-context.ts
|
|
4440
|
-
function collectUniqueMessageIdentities(messages) {
|
|
4441
|
-
const identities = /* @__PURE__ */ new Map();
|
|
4442
|
-
for (const [index, message] of messages.entries()) {
|
|
4443
|
-
const identity = readMirrorIdentity(message);
|
|
4444
|
-
if (!identity) continue;
|
|
4445
|
-
if (identities.has(identity)) return;
|
|
4446
|
-
identities.set(identity, index);
|
|
4447
|
-
}
|
|
4448
|
-
return identities;
|
|
4449
|
-
}
|
|
4450
|
-
function adoptPersistedHostPrompt(params) {
|
|
4451
|
-
const promptIdentity = `${params.turnId}:prompt`;
|
|
4452
|
-
if (params.mirroredMessages.some((message) => readMirrorIdentity(message) === promptIdentity)) return params;
|
|
4453
|
-
const sourcePrompt = params.settledMessages[0];
|
|
4454
|
-
const sourceKey = sourcePrompt?.idempotencyKey;
|
|
4455
|
-
if (sourcePrompt?.role !== "user" || readMirrorIdentity(sourcePrompt) !== promptIdentity || typeof sourceKey !== "string" || sourceKey.trim().length === 0) return params;
|
|
4456
|
-
const matches = params.historyMessages.flatMap((message, index) => message.role === "user" && message.idempotencyKey === sourceKey ? [{
|
|
4457
|
-
index,
|
|
4458
|
-
message
|
|
4459
|
-
}] : []);
|
|
4460
|
-
const persistedPrompt = matches.length === 1 ? matches[0] : void 0;
|
|
4461
|
-
const persistedMetadata = persistedPrompt?.message;
|
|
4462
|
-
if (!persistedPrompt || readMirrorIdentity(persistedPrompt.message) !== void 0 || readCodexMirrorSourceFingerprint(persistedPrompt.message) !== void 0 || persistedMetadata?.["__openclaw"]?.mirrorOrigin === "codex-app-server") return params;
|
|
4463
|
-
const sourceUpstreamText = readUpstreamUserText(sourcePrompt);
|
|
4464
|
-
const persistedUpstreamText = readUpstreamUserText(persistedPrompt.message);
|
|
4465
|
-
if (persistedUpstreamText !== void 0 && persistedUpstreamText !== sourceUpstreamText) return params;
|
|
4466
|
-
let logicalPrompt = attachCodexMirrorIdentity(persistedPrompt.message, promptIdentity);
|
|
4467
|
-
if (sourceUpstreamText !== void 0) logicalPrompt = attachUpstreamUserText(logicalPrompt, sourceUpstreamText);
|
|
4468
|
-
if (serializeCodexMirrorSourceEvidence(logicalPrompt) !== serializeCodexMirrorSourceEvidence(sourcePrompt)) return params;
|
|
4469
|
-
const historyMessages = [...params.historyMessages];
|
|
4470
|
-
historyMessages[persistedPrompt.index] = logicalPrompt;
|
|
4471
|
-
return {
|
|
4472
|
-
historyMessages,
|
|
4473
|
-
mirroredMessages: [logicalPrompt, ...params.mirroredMessages]
|
|
4474
|
-
};
|
|
4475
|
-
}
|
|
4476
|
-
/** Freezes one complete active transcript branch through the settled tool-result boundary. */
|
|
4477
|
-
function buildCodexSettledTurnFinalizationContext(params) {
|
|
4478
|
-
const { historyMessages, mirroredMessages } = adoptPersistedHostPrompt(params);
|
|
4479
|
-
const boundaryMessage = params.settledMessages.findLast((message) => message.role === "toolResult");
|
|
4480
|
-
const boundaryIdentity = boundaryMessage ? readMirrorIdentity(boundaryMessage) : void 0;
|
|
4481
|
-
if (!boundaryMessage || !boundaryIdentity || !boundaryIdentity.startsWith(`${params.turnId}:tool:`)) return;
|
|
4482
|
-
const settledBoundaryIndex = params.settledMessages.indexOf(boundaryMessage);
|
|
4483
|
-
const requiredIdentities = params.settledMessages.slice(0, settledBoundaryIndex + 1).map(readMirrorIdentity);
|
|
4484
|
-
if (requiredIdentities.length === 0 || requiredIdentities.some((identity) => !identity) || new Set(requiredIdentities).size !== requiredIdentities.length || !requiredIdentities.includes(`${params.turnId}:prompt`)) return;
|
|
4485
|
-
const historyIdentities = collectUniqueMessageIdentities(historyMessages);
|
|
4486
|
-
const mirroredIdentities = collectUniqueMessageIdentities(mirroredMessages);
|
|
4487
|
-
if (!historyIdentities || !mirroredIdentities) return;
|
|
4488
|
-
const mirroredBoundaryIndex = mirroredIdentities.get(boundaryIdentity);
|
|
4489
|
-
if (mirroredBoundaryIndex === void 0) return;
|
|
4490
|
-
const mirroredThroughBoundary = mirroredMessages.slice(0, mirroredBoundaryIndex + 1);
|
|
4491
|
-
if (mirroredThroughBoundary.length !== requiredIdentities.length || mirroredThroughBoundary.some((message, index) => readMirrorIdentity(message) !== requiredIdentities[index])) return;
|
|
4492
|
-
const historyBoundaryIndex = historyIdentities.get(boundaryIdentity);
|
|
4493
|
-
if (historyBoundaryIndex === void 0) return;
|
|
4494
|
-
let previousHistoryIndex = -1;
|
|
4495
|
-
for (const mirroredMessage of mirroredThroughBoundary) {
|
|
4496
|
-
const identity = readMirrorIdentity(mirroredMessage);
|
|
4497
|
-
const historyIndex = identity ? historyIdentities.get(identity) : void 0;
|
|
4498
|
-
const historyMessage = historyIndex === void 0 ? void 0 : historyMessages[historyIndex];
|
|
4499
|
-
if (historyIndex === void 0 || historyIndex <= previousHistoryIndex || historyIndex > historyBoundaryIndex || !historyMessage || serializeCodexMirrorSourceEvidence(historyMessage) !== serializeCodexMirrorSourceEvidence(mirroredMessage)) return;
|
|
4500
|
-
previousHistoryIndex = historyIndex;
|
|
4501
|
-
}
|
|
4502
|
-
return {
|
|
4503
|
-
source: "openclaw-transcript",
|
|
4504
|
-
messages: Object.freeze(structuredClone(params.historyMessages.slice(0, historyBoundaryIndex + 1)))
|
|
4505
|
-
};
|
|
4506
|
-
}
|
|
4507
|
-
/** Reads and freezes the current active transcript branch after mirroring has settled. */
|
|
4508
|
-
async function captureCodexSettledTurnFinalizationContext(params) {
|
|
4509
|
-
try {
|
|
4510
|
-
const historyMessages = await readCodexMirroredSessionHistoryMessages(params);
|
|
4511
|
-
if (!historyMessages) return;
|
|
4512
|
-
return buildCodexSettledTurnFinalizationContext({
|
|
4513
|
-
historyMessages,
|
|
4514
|
-
mirroredMessages: params.mirroredMessages,
|
|
4515
|
-
settledMessages: params.settledMessages,
|
|
4516
|
-
turnId: params.turnId
|
|
4517
|
-
});
|
|
4518
|
-
} catch (error) {
|
|
4519
|
-
embeddedAgentLog.warn("codex settled-turn finalization context capture failed", {
|
|
4520
|
-
error: formatErrorMessage(error),
|
|
4521
|
-
turnId: params.turnId
|
|
4522
|
-
});
|
|
4523
|
-
return;
|
|
4524
|
-
}
|
|
4525
|
-
}
|
|
4526
|
-
//#endregion
|
|
4527
3869
|
//#region extensions/codex/src/app-server/trajectory.ts
|
|
4528
3870
|
/** Creates a trajectory recorder when the host exposes its capture capability. */
|
|
4529
3871
|
function createCodexTrajectoryRecorder(params) {
|
|
4530
3872
|
if (!params.trajectory) return null;
|
|
4531
3873
|
const trajectory = params.trajectory;
|
|
4532
3874
|
return {
|
|
4533
|
-
recordEvent:
|
|
3875
|
+
recordEvent: (type, data) => {
|
|
3876
|
+
try {
|
|
3877
|
+
trajectory.recordEvent(type, data);
|
|
3878
|
+
} catch {}
|
|
3879
|
+
},
|
|
4534
3880
|
flush: trajectory.flush
|
|
4535
3881
|
};
|
|
4536
3882
|
}
|
|
@@ -4594,39 +3940,44 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4594
3940
|
const { effectiveRuntimeProviderId, effectiveRuntimeModelId } = runtime;
|
|
4595
3941
|
const { params, terminalState, runAbortController, activeContextEngine, bindingStore, bindingIdentity, appServer, usesSupervisionConnection, sessionAgentId, contextSessionKey, effectiveCwd, agentDir, attemptStartedAt, startupAuthProfileId } = connection;
|
|
4596
3942
|
const { toolBridge, toolState } = attemptTools;
|
|
4597
|
-
const { state, completion,
|
|
3943
|
+
const { state, completion, deadlines } = turnRuntime;
|
|
4598
3944
|
const { emitLifecycleTerminal, buildLifecycleTerminalMeta } = lifecycle;
|
|
4599
3945
|
const { drainNotificationQueue } = notifications;
|
|
4600
3946
|
const { codexModelCallDiagnostics } = requestRuntime;
|
|
4601
3947
|
const { activeTurnId, activeProjector, streamState, freezeRunTerminalOutcome, notifyUserMessagePersisted } = activeTurn;
|
|
4602
3948
|
await completion;
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
const
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
3949
|
+
const abortGraceElapsed = createDeferred();
|
|
3950
|
+
let settlementClosed = false;
|
|
3951
|
+
let abortGraceTimer;
|
|
3952
|
+
const beginAbortGrace = () => {
|
|
3953
|
+
if (settlementClosed) return;
|
|
3954
|
+
abortGraceTimer = setTimeout(() => abortGraceElapsed.resolve(), TURN_FINALIZE_DRAIN_ABORT_GRACE_MS);
|
|
3955
|
+
abortGraceTimer.unref?.();
|
|
3956
|
+
};
|
|
3957
|
+
const abortListener = addAbortListener(runAbortController.signal, () => {
|
|
3958
|
+
state.abortCleanup.then(beginAbortGrace, beginAbortGrace);
|
|
3959
|
+
});
|
|
3960
|
+
const closeProjection = () => {
|
|
3961
|
+
state.projectionClosed = true;
|
|
3962
|
+
return activeProjector.closeProjection();
|
|
3963
|
+
};
|
|
3964
|
+
const settlement = drainNotificationQueue().then(closeProjection);
|
|
3965
|
+
try {
|
|
3966
|
+
await Promise.race([settlement, abortGraceElapsed.promise]);
|
|
3967
|
+
if (runAbortController.signal.aborted) await state.abortCleanup;
|
|
3968
|
+
} finally {
|
|
3969
|
+
settlementClosed = true;
|
|
3970
|
+
abortListener[Symbol.dispose]();
|
|
3971
|
+
clearTimeout(abortGraceTimer);
|
|
3972
|
+
deadlines.dispose();
|
|
3973
|
+
if (!state.projectionClosed) await resources.runCleanupStep("codex-transcript-checkpoint", closeProjection);
|
|
4622
3974
|
}
|
|
4623
3975
|
const result = activeProjector.buildResult(toolBridge.telemetry, { yieldDetected: toolState.yieldDetected });
|
|
4624
3976
|
const projectedTerminal = attemptTerminal.project(result.terminal);
|
|
4625
|
-
const effectiveTimedOut = state.
|
|
4626
|
-
const
|
|
4627
|
-
const
|
|
4628
|
-
|
|
4629
|
-
let finalPromptError = resourceState.executionDisconnectError ?? clientClosedPromptErrorForFinal ?? (effectiveTurnCompletionIdleTimedOut ? state.turnCompletionIdleTimeoutMessage : effectiveTimedOut ? "codex app-server attempt timed out" : projectedTerminal.promptError);
|
|
3977
|
+
const effectiveTimedOut = state.timeout !== void 0;
|
|
3978
|
+
const isFinalAborted = () => terminalState.explicitCancellationObserved || !resourceState.executionDisconnectError && (projectedTerminal.aborted || runAbortController.signal.aborted && !state.clientClosedAbort);
|
|
3979
|
+
const clientClosedPromptErrorForFinal = state.clientClosedPromptError;
|
|
3980
|
+
let finalPromptError = resourceState.executionDisconnectError ?? clientClosedPromptErrorForFinal ?? (state.timeout?.kind === "settlement" ? "codex app-server terminal settlement timed out" : state.timeout?.kind === "execution" ? "codex app-server execution budget timed out" : projectedTerminal.promptError);
|
|
4630
3981
|
const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError instanceof Error ? finalPromptError.message : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
|
|
4631
3982
|
if (isInvalidCodexImagePayloadError(finalPromptErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(bindingStore, bindingIdentity, {
|
|
4632
3983
|
phase: "turn_completed",
|
|
@@ -4669,33 +4020,23 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4669
4020
|
});
|
|
4670
4021
|
finalPromptError = resourceState.executionDisconnectError ?? finalPromptError;
|
|
4671
4022
|
const finalPromptErrorSource = effectiveTimedOut || clientClosedPromptErrorForFinal ? "prompt" : projectedTerminal.promptErrorSource;
|
|
4672
|
-
const codexAppServerFailureKind = clientClosedPromptErrorForFinal ? "client_closed_before_turn_completed" :
|
|
4023
|
+
const codexAppServerFailureKind = clientClosedPromptErrorForFinal ? "client_closed_before_turn_completed" : state.timeout?.kind === "settlement" ? "turn_settlement_timeout" : void 0;
|
|
4673
4024
|
const replayBlockedReason = codexAppServerFailureKind ? resolveCodexAppServerReplayBlockedReason(result) : void 0;
|
|
4674
|
-
const promptTimeoutOutcome = buildCodexAppServerPromptTimeoutOutcome(
|
|
4675
|
-
|
|
4676
|
-
turnCompletionIdleTimedOut: effectiveTurnCompletionIdleTimedOut,
|
|
4677
|
-
turnWatchTimeoutKind: state.turnWatchTimeoutKind
|
|
4678
|
-
});
|
|
4679
|
-
const failureDiagnostics = codexAppServerFailureKind === "client_closed_before_turn_completed" && state.clientClosedDiagnostic ? { transportError: state.clientClosedDiagnostic } : codexAppServerFailureKind === "turn_completion_idle_timeout" && state.turnWatchTimeoutKind === "completion" ? buildCodexAppServerTimeoutDiagnostics({
|
|
4680
|
-
idleMs: state.turnWatchTimeoutIdleMs,
|
|
4681
|
-
timeoutMs: state.turnWatchTimeoutMs,
|
|
4682
|
-
lastActivityReason: state.turnWatchTimeoutLastActivityReason,
|
|
4683
|
-
details: state.turnWatchTimeoutDetails
|
|
4684
|
-
}) : void 0;
|
|
4025
|
+
const promptTimeoutOutcome = buildCodexAppServerPromptTimeoutOutcome(state.timeout);
|
|
4026
|
+
const failureDiagnostics = codexAppServerFailureKind === "client_closed_before_turn_completed" && state.clientClosedDiagnostic ? { transportError: state.clientClosedDiagnostic } : state.timeout?.kind === "settlement" ? { timeoutMs: state.timeout.timeoutMs } : void 0;
|
|
4685
4027
|
const codexAppServerFailure = codexAppServerFailureKind ? {
|
|
4686
4028
|
kind: codexAppServerFailureKind,
|
|
4687
|
-
...codexAppServerFailureKind === "turn_completion_idle_timeout" && state.turnWatchTimeoutKind ? { turnWatchTimeoutKind: state.turnWatchTimeoutKind } : {},
|
|
4688
4029
|
transport: appServer.start.transport,
|
|
4689
4030
|
threadId: resourceState.thread.threadId,
|
|
4690
4031
|
turnId: activeTurnId,
|
|
4691
|
-
replaySafe: replayBlockedReason === void 0,
|
|
4032
|
+
replaySafe: codexAppServerFailureKind === "client_closed_before_turn_completed" && replayBlockedReason === void 0,
|
|
4692
4033
|
...replayBlockedReason ? { replayBlockedReason } : {},
|
|
4693
4034
|
...failureDiagnostics ? { diagnostics: failureDiagnostics } : {}
|
|
4694
4035
|
} : void 0;
|
|
4695
4036
|
const finalAborted = isFinalAborted();
|
|
4696
4037
|
const completedTurnStatus = activeProjector.getCompletedTurnStatus();
|
|
4697
|
-
const locallyCompletedTurn = state.completed &&
|
|
4698
|
-
const turnSucceeded = !finalAborted && !effectiveTimedOut && (finalPromptError === null || finalPromptError === void 0) && (completedTurnStatus === "completed" ||
|
|
4038
|
+
const locallyCompletedTurn = state.completed && state.localCompletionRequested && !state.timeout && clientClosedPromptErrorForFinal === void 0;
|
|
4039
|
+
const turnSucceeded = !finalAborted && !effectiveTimedOut && (finalPromptError === null || finalPromptError === void 0) && (completedTurnStatus === "completed" || locallyCompletedTurn);
|
|
4699
4040
|
if (toolBridge.telemetry.messagingToolSentTargets.some((target) => target.sourceReplyFinal === true)) result.agentHarnessResultClassification = void 0;
|
|
4700
4041
|
const attemptSucceeded = turnSucceeded && result.agentHarnessResultClassification === void 0;
|
|
4701
4042
|
terminalState.turnSucceeded = turnSucceeded;
|
|
@@ -4709,7 +4050,6 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4709
4050
|
const modelCallFailureKind = classifyCodexModelCallFailureKind({
|
|
4710
4051
|
error: finalPromptError,
|
|
4711
4052
|
timedOut: effectiveTimedOut,
|
|
4712
|
-
turnCompletionIdleTimedOut: effectiveTurnCompletionIdleTimedOut,
|
|
4713
4053
|
runAborted: finalAborted,
|
|
4714
4054
|
abortReason: terminalState.explicitCancellationReason ?? runAbortController.signal.reason,
|
|
4715
4055
|
clientClosedAbort: state.clientClosedAbort,
|
|
@@ -4729,14 +4069,13 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4729
4069
|
turnId: activeTurnId
|
|
4730
4070
|
});
|
|
4731
4071
|
const { assistantTranscriptOwned, assistantTranscriptIdempotencyKey, terminalAnchor } = mirrorOutcome;
|
|
4732
|
-
const
|
|
4733
|
-
const settledTurnFinalizationContext = shouldCaptureSettledTurnFinalizationContext ? await captureCodexSettledTurnFinalizationContext({
|
|
4072
|
+
const settledTurnFinalizationContext = result.assistantTexts.every((text) => !text.trim()) && result.messagesSnapshot.some((message) => message.role === "toolResult") && (!finalPromptError || activeProjector.settledTurnFailureFinalizationAllowed) ? await captureCodexSettledTurnFinalizationContext({
|
|
4734
4073
|
...activeTranscriptTarget,
|
|
4735
4074
|
mirroredMessages: mirrorOutcome.mirroredMessages,
|
|
4736
4075
|
settledMessages: result.messagesSnapshot,
|
|
4737
4076
|
turnId: activeTurnId
|
|
4738
|
-
}) : void 0;
|
|
4739
|
-
if (
|
|
4077
|
+
}) ?? Object.freeze({ source: "unavailable" }) : void 0;
|
|
4078
|
+
if (settledTurnFinalizationContext?.source === "unavailable") embeddedAgentLog.warn("codex settled-turn finalization context is unavailable", {
|
|
4740
4079
|
threadId: resourceState.thread.threadId,
|
|
4741
4080
|
turnId: activeTurnId
|
|
4742
4081
|
});
|
|
@@ -4839,8 +4178,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4839
4178
|
yielded: toolState.yieldDetected
|
|
4840
4179
|
})
|
|
4841
4180
|
});
|
|
4842
|
-
const finalizedResult = {
|
|
4843
|
-
...result,
|
|
4181
|
+
const finalizedResult = Object.assign(result, {
|
|
4844
4182
|
...toolState.yieldAcknowledgment ? { yieldAcknowledgment: toolState.yieldAcknowledgment } : {},
|
|
4845
4183
|
terminal: attemptTerminal.normalize({
|
|
4846
4184
|
timedOut: effectiveTimedOut,
|
|
@@ -4858,15 +4196,12 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4858
4196
|
...resourceState.runtimeContinuationStarted ? { runtimeContinuationStarted: true } : {},
|
|
4859
4197
|
...!finalAborted && !effectiveTimedOut && !finalPromptError && preparedAuthBinding ? { authBindingFingerprint: preparedAuthBinding.fingerprint } : {},
|
|
4860
4198
|
systemPromptReport
|
|
4861
|
-
};
|
|
4199
|
+
});
|
|
4862
4200
|
if (turnSucceeded && toolState.yieldDetected && !runAbortController.signal.aborted) resourceState.nativeHookRelay?.authorizeRetentionAfterSuccessfulYield();
|
|
4863
4201
|
return finalizedResult;
|
|
4864
4202
|
}
|
|
4865
4203
|
//#endregion
|
|
4866
4204
|
//#region extensions/codex/src/app-server/attempt-notification-state.ts
|
|
4867
|
-
/**
|
|
4868
|
-
* State machine for Codex app-server turn notifications and idle-watch updates.
|
|
4869
|
-
*/
|
|
4870
4205
|
/** Emits coarse execution phases exactly once from app-server notifications. */
|
|
4871
4206
|
function reportCodexExecutionNotification(params) {
|
|
4872
4207
|
const { notification } = params;
|
|
@@ -4890,81 +4225,7 @@ function reportCodexExecutionNotification(params) {
|
|
|
4890
4225
|
}
|
|
4891
4226
|
/** Returns true when a notification ends the current app-server turn. */
|
|
4892
4227
|
function isTerminalCodexTurnNotificationForTurn(params) {
|
|
4893
|
-
|
|
4894
|
-
return params.notification.method === "turn/completed";
|
|
4895
|
-
}
|
|
4896
|
-
/**
|
|
4897
|
-
* Applies one notification to active item tracking, idle watches, and terminal
|
|
4898
|
-
* turn state.
|
|
4899
|
-
*/
|
|
4900
|
-
function applyCodexTurnNotificationState(params) {
|
|
4901
|
-
const { notification, turnWatches } = params;
|
|
4902
|
-
const isCurrentTurnNotification = isCodexNotificationForTurn(notification.params, params.threadId, params.turnId);
|
|
4903
|
-
const isTurnCompletion = notification.method === "turn/completed" && isCurrentTurnNotification;
|
|
4904
|
-
let turnCrossedToolHandoff = params.turnCrossedToolHandoff;
|
|
4905
|
-
if (isCurrentTurnNotification) {
|
|
4906
|
-
updateActiveTurnItemIds(notification, params.activeTurnItemIds);
|
|
4907
|
-
updateActiveCompletionBlockerItemIds(notification, params.activeCompletionBlockerItemIds);
|
|
4908
|
-
turnWatches.touchActivity(`notification:${notification.method}`, {
|
|
4909
|
-
details: describeNotificationActivity(notification),
|
|
4910
|
-
attemptProgress: true
|
|
4911
|
-
});
|
|
4912
|
-
params.onReportExecutionNotification(notification);
|
|
4913
|
-
if (notification.method === "item/completed" && params.activeTurnItemIds.size === 0) params.onScheduleTerminalDynamicToolReleaseCheck();
|
|
4914
|
-
}
|
|
4915
|
-
const unblockedAssistantCompletionRelease = isCurrentTurnNotification && turnWatches.isAssistantCompletionIdleWatchArmed() && notification.method === "item/completed" && params.activeTurnItemIds.size === 0;
|
|
4916
|
-
const trackedDynamicToolCompletion = isPendingOpenClawDynamicToolCompletionNotification(notification, params.pendingOpenClawDynamicToolCompletionIds);
|
|
4917
|
-
const rawToolOutputCompletion = isRawToolOutputCompletionNotification(notification);
|
|
4918
|
-
if (isCurrentTurnNotification && (rawToolOutputCompletion || isNativeToolProgressNotification(notification))) turnCrossedToolHandoff = true;
|
|
4919
|
-
const assistantCompletionCanRelease = isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff);
|
|
4920
|
-
const postToolProgressNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && ((isRawAssistantProgressNotification(notification) || isRawReasoningCompletionNotification(notification)) && params.activeTurnItemIds.size === 0 || isReasoningProgressNotification(notification));
|
|
4921
|
-
const postToolPatchUpdateNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && isFileChangePatchUpdatedNotification(notification);
|
|
4922
|
-
const rawResponseItemCompletedWithNoActiveItems = isCurrentTurnNotification && notification.method === "rawResponseItem/completed" && params.activeTurnItemIds.size === 0 && params.activeAppServerTurnRequests === 0 && !assistantCompletionCanRelease && !postToolProgressNeedsTerminalGuard && !rawToolOutputCompletion;
|
|
4923
|
-
const shouldArmNoToolPostProgressReplyWatch = isCurrentTurnNotification && !turnCrossedToolHandoff && params.activeTurnItemIds.size === 0 && (isReasoningItemCompletionNotification(notification) || isAssistantCommentaryCompletionNotification(notification));
|
|
4924
|
-
const shouldArmNoToolPostRawProgressReplyWatch = !turnCrossedToolHandoff && rawResponseItemCompletedWithNoActiveItems && (isRawReasoningCompletionNotification(notification) || isRawAssistantProgressNotification(notification));
|
|
4925
|
-
const shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem = isCurrentTurnNotification && notification.method === "item/completed" && params.activeTurnItemIds.size === 0 && !trackedDynamicToolCompletion && !assistantCompletionCanRelease && !shouldArmNoToolPostProgressReplyWatch;
|
|
4926
|
-
const shouldUsePostToolContinuationWatch = turnCrossedToolHandoff && (postToolProgressNeedsTerminalGuard || postToolPatchUpdateNeedsTerminalGuard || rawToolOutputCompletion || trackedDynamicToolCompletion || shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem);
|
|
4927
|
-
const armPostToolContinuationWatch = () => {
|
|
4928
|
-
turnWatches.armCompletionIdleWatch({ timeoutMs: params.postToolRawAssistantCompletionIdleTimeoutMs });
|
|
4929
|
-
turnWatches.extendAttemptIdleWatch(params.postToolRawAssistantCompletionIdleTimeoutMs);
|
|
4930
|
-
};
|
|
4931
|
-
const armPostProgressReplyWatch = () => {
|
|
4932
|
-
turnWatches.armCompletionIdleWatch({ timeoutMs: CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS });
|
|
4933
|
-
turnWatches.extendAttemptIdleWatch(CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS);
|
|
4934
|
-
};
|
|
4935
|
-
if (isCurrentTurnNotification && notification.method === "error") {
|
|
4936
|
-
if (isRetryableErrorNotification(notification.params)) turnWatches.disarmCompletionIdleWatch();
|
|
4937
|
-
else turnWatches.armCompletionIdleWatch({ pinnedByTerminalError: true });
|
|
4938
|
-
turnWatches.disarmAssistantCompletionIdleWatch();
|
|
4939
|
-
} else if (isTurnCompletion) turnWatches.disarmAssistantCompletionIdleWatch();
|
|
4940
|
-
else if (isCurrentTurnNotification && assistantCompletionCanRelease) turnWatches.armAssistantCompletionIdleWatch(describeNotificationActivity(notification));
|
|
4941
|
-
else if (postToolProgressNeedsTerminalGuard || postToolPatchUpdateNeedsTerminalGuard) armPostToolContinuationWatch();
|
|
4942
|
-
else if (shouldArmNoToolPostProgressReplyWatch || shouldArmNoToolPostRawProgressReplyWatch) armPostProgressReplyWatch();
|
|
4943
|
-
else if (trackedDynamicToolCompletion) armPostToolContinuationWatch();
|
|
4944
|
-
else if (unblockedAssistantCompletionRelease) turnWatches.armAssistantCompletionIdleWatch(describeNotificationActivity(notification));
|
|
4945
|
-
else if (shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) if (shouldUsePostToolContinuationWatch) armPostToolContinuationWatch();
|
|
4946
|
-
else turnWatches.armCompletionIdleWatch();
|
|
4947
|
-
else if (rawResponseItemCompletedWithNoActiveItems) turnWatches.armCompletionIdleWatch();
|
|
4948
|
-
else if (isCurrentTurnNotification && rawToolOutputCompletion) armPostToolContinuationWatch();
|
|
4949
|
-
else if (isCurrentTurnNotification && shouldDisarmAssistantCompletionIdleWatch(notification)) turnWatches.disarmAssistantCompletionIdleWatch();
|
|
4950
|
-
if (turnWatches.isCompletionIdleWatchArmed() && !turnWatches.isCompletionIdleWatchPinnedByTerminalError() && notification.method !== "turn/completed" && isCurrentTurnNotification && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !postToolProgressNeedsTerminalGuard && !postToolPatchUpdateNeedsTerminalGuard && !rawResponseItemCompletedWithNoActiveItems && !shouldArmNoToolPostProgressReplyWatch && !shouldArmNoToolPostRawProgressReplyWatch && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) turnWatches.disarmCompletionIdleWatch();
|
|
4951
|
-
if (trackedDynamicToolCompletion) {
|
|
4952
|
-
const itemId = readNotificationItemId(notification);
|
|
4953
|
-
if (itemId) {
|
|
4954
|
-
params.pendingOpenClawDynamicToolCompletionIds.delete(itemId);
|
|
4955
|
-
params.onScheduleTerminalDynamicToolReleaseCheck();
|
|
4956
|
-
}
|
|
4957
|
-
}
|
|
4958
|
-
return {
|
|
4959
|
-
isCurrentTurnNotification,
|
|
4960
|
-
isTurnAbortMarker: isCurrentTurnNotification && isCodexTurnAbortMarkerNotification(notification, { currentPromptTexts: params.currentPromptTexts }),
|
|
4961
|
-
isTurnTerminal: isTerminalCodexTurnNotificationForTurn({
|
|
4962
|
-
notification,
|
|
4963
|
-
threadId: params.threadId,
|
|
4964
|
-
turnId: params.turnId
|
|
4965
|
-
}),
|
|
4966
|
-
turnCrossedToolHandoff
|
|
4967
|
-
};
|
|
4228
|
+
return params.notification.method === "turn/completed" && isCodexNotificationForTurn(params.notification.params, params.threadId, params.turnId) && readCodexTurnCompletedNotification(params.notification.params) !== void 0;
|
|
4968
4229
|
}
|
|
4969
4230
|
//#endregion
|
|
4970
4231
|
//#region extensions/codex/src/app-server/run-attempt-lifecycle-terminal.ts
|
|
@@ -5058,7 +4319,7 @@ function createCodexAttemptLifecycleController(resources, turnRuntime) {
|
|
|
5058
4319
|
state.lifecycleStarted = true;
|
|
5059
4320
|
};
|
|
5060
4321
|
const emitLifecycleTerminal = (data) => {
|
|
5061
|
-
if (!state.lifecycleStarted || state.lifecycleTerminalEmitted) return;
|
|
4322
|
+
if (!state.lifecycleStarted || state.lifecycleTerminalEmitted || state.permissionChangeRestart) return;
|
|
5062
4323
|
emitCodexAppServerEvent(params, {
|
|
5063
4324
|
stream: "lifecycle",
|
|
5064
4325
|
data: {
|
|
@@ -5159,10 +4420,9 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
5159
4420
|
const { prompt, state: resourceState, projectorRef, registerNativeSubagentMonitor } = resources;
|
|
5160
4421
|
const { context, turnState } = prompt;
|
|
5161
4422
|
const { attemptTools, runtime } = context;
|
|
5162
|
-
const {
|
|
5163
|
-
const { appServer, runAbortController } = connection;
|
|
4423
|
+
const { appServer, runAbortController } = runtime.connection;
|
|
5164
4424
|
const { allocateCodexToolOutcomeOrdinal } = attemptTools;
|
|
5165
|
-
const { state, turnIdRef, userInputBridgeRef, steeringQueueRef,
|
|
4425
|
+
const { state, turnIdRef, userInputBridgeRef, steeringQueueRef, activeTurnItemIds, pendingOpenClawDynamicToolCompletionIds, completeTurn, noteProgress, deadlines } = turnRuntime;
|
|
5166
4426
|
const { scheduleTerminalDynamicToolReleaseCheck, reportExecutionNotification, maybeAnnounceFastModeAutoOff } = lifecycle;
|
|
5167
4427
|
const isTerminalTurnNotificationForTurn = (notification, notificationTurnId) => isTerminalCodexTurnNotificationForTurn({
|
|
5168
4428
|
notification,
|
|
@@ -5170,81 +4430,47 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
5170
4430
|
turnId: notificationTurnId
|
|
5171
4431
|
});
|
|
5172
4432
|
const handleNotification = async (notification) => {
|
|
4433
|
+
if (state.projectionClosed) return;
|
|
5173
4434
|
const projector = projectorRef.current;
|
|
5174
4435
|
const turnId = turnIdRef.current;
|
|
5175
|
-
const steeringQueue = steeringQueueRef.current;
|
|
5176
4436
|
userInputBridgeRef.current?.handleNotification(notification);
|
|
5177
4437
|
if (!projector || !turnId) {
|
|
5178
4438
|
if (notification.method === "error") state.latestStartupErrorNotification = notification;
|
|
5179
4439
|
return;
|
|
5180
4440
|
}
|
|
5181
|
-
|
|
4441
|
+
const isCurrentTurn = isCodexNotificationForTurn(notification.params, resourceState.thread.threadId, turnId);
|
|
4442
|
+
const isTerminal = isTerminalTurnNotificationForTurn(notification, turnId);
|
|
4443
|
+
if ((state.timeout || state.localCompletionRequested) && isTerminal && readCodexTurnCompletedNotification(notification.params)?.turn.status === "interrupted") {
|
|
5182
4444
|
completeTurn();
|
|
5183
4445
|
return;
|
|
5184
4446
|
}
|
|
5185
|
-
|
|
5186
|
-
notification,
|
|
5187
|
-
threadId: resourceState.thread.threadId,
|
|
5188
|
-
turnId,
|
|
5189
|
-
currentPromptTexts: [turnState.codexTurnPromptText],
|
|
5190
|
-
turnWatches,
|
|
5191
|
-
activeTurnItemIds,
|
|
5192
|
-
activeCompletionBlockerItemIds,
|
|
5193
|
-
activeAppServerTurnRequests: state.activeAppServerTurnRequests,
|
|
5194
|
-
pendingOpenClawDynamicToolCompletionIds,
|
|
5195
|
-
turnCrossedToolHandoff: state.turnCrossedToolHandoff,
|
|
5196
|
-
postToolRawAssistantCompletionIdleTimeoutMs,
|
|
5197
|
-
onScheduleTerminalDynamicToolReleaseCheck: scheduleTerminalDynamicToolReleaseCheck,
|
|
5198
|
-
onReportExecutionNotification: reportExecutionNotification
|
|
5199
|
-
});
|
|
5200
|
-
state.turnCrossedToolHandoff = notificationState.turnCrossedToolHandoff;
|
|
5201
|
-
if (notificationState.isCurrentTurnNotification && notification.method === "item/completed") {
|
|
5202
|
-
const item = readCodexNotificationItem(notification.params);
|
|
5203
|
-
if (item?.type === "userMessage" && typeof item.clientId === "string") await steeringQueue?.confirmConsumed(item.clientId);
|
|
5204
|
-
}
|
|
5205
|
-
if (notificationState.isTurnAbortMarker) state.sawCodexInterruptMarker = true;
|
|
5206
|
-
const hookNotification = readCodexFinalizationHookNotification(notification, resourceState.thread.threadId, turnId);
|
|
5207
|
-
if (hookNotification?.phase === "started") {
|
|
5208
|
-
if (activeFinalizationHookRunIds.size === 0) finalizationHookBatchStatuses.clear();
|
|
5209
|
-
activeFinalizationHookRunIds.add(hookNotification.runId);
|
|
5210
|
-
turnWatches.disarmAssistantCompletionIdleWatch();
|
|
5211
|
-
}
|
|
5212
|
-
if (notificationState.isTurnTerminal) state.terminalTurnNotificationQueued = true;
|
|
4447
|
+
state.activeLocalProjections += 1;
|
|
5213
4448
|
try {
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
if (
|
|
5219
|
-
|
|
5220
|
-
|
|
4449
|
+
if (isCurrentTurn) {
|
|
4450
|
+
updateActiveTurnItemIds(notification, activeTurnItemIds);
|
|
4451
|
+
noteProgress(`notification:${notification.method}`);
|
|
4452
|
+
reportExecutionNotification(notification);
|
|
4453
|
+
if (isPendingOpenClawDynamicToolCompletionNotification(notification, pendingOpenClawDynamicToolCompletionIds)) {
|
|
4454
|
+
const itemId = readNotificationItemId(notification);
|
|
4455
|
+
if (itemId) pendingOpenClawDynamicToolCompletionIds.delete(itemId);
|
|
4456
|
+
}
|
|
4457
|
+
if (notification.method === "item/completed") {
|
|
4458
|
+
if (activeTurnItemIds.size === 0) scheduleTerminalDynamicToolReleaseCheck();
|
|
4459
|
+
const item = readCodexNotificationItem(notification.params);
|
|
4460
|
+
if (item?.type === "userMessage" && typeof item.clientId === "string") await steeringQueueRef.current?.confirmConsumed(item.clientId);
|
|
4461
|
+
}
|
|
4462
|
+
if (isCodexTurnAbortMarkerNotification(notification, { currentPromptTexts: [turnState.codexTurnPromptText] })) state.sawCodexInterruptMarker = true;
|
|
5221
4463
|
}
|
|
5222
|
-
|
|
4464
|
+
await projector.handleNotification(notification);
|
|
4465
|
+
if (isCurrentTurn && activeTurnItemIds.size === 0 && isRawFunctionToolOutputCompletionNotification(notification)) await maybeAnnounceFastModeAutoOff();
|
|
5223
4466
|
} catch (error) {
|
|
5224
4467
|
embeddedAgentLog.debug("codex app-server projector notification threw", {
|
|
5225
4468
|
method: notification.method,
|
|
5226
4469
|
error
|
|
5227
4470
|
});
|
|
5228
4471
|
} finally {
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
activeFinalizationHookRunIds.delete(hookNotification.runId);
|
|
5232
|
-
finalizationHookBatchStatuses.set(hookNotification.runId, hookNotification.status);
|
|
5233
|
-
if (activeFinalizationHookRunIds.size === 0) {
|
|
5234
|
-
const statuses = new Set(finalizationHookBatchStatuses.values());
|
|
5235
|
-
if (statuses.has("blocked") && !statuses.has("stopped")) {
|
|
5236
|
-
const itemId = projector.getLatestTerminalAssistantCandidate()?.itemId;
|
|
5237
|
-
state.rejectedFinalizationHookAssistant = itemId ? { itemId } : {};
|
|
5238
|
-
turnWatches.disarmAssistantCompletionIdleWatch();
|
|
5239
|
-
} else state.rejectedFinalizationHookAssistant = void 0;
|
|
5240
|
-
}
|
|
5241
|
-
if (activeFinalizationHookRunIds.size === 0 && state.rejectedFinalizationHookAssistant === void 0 && !state.terminalTurnNotificationQueued && state.activeAppServerTurnRequests === 0 && activeTurnItemIds.size === 0 && activeCompletionBlockerItemIds.size === 0 && pendingOpenClawDynamicToolCompletionIds.size === 0 && projector.hasLatestTerminalAssistantCandidateText()) turnWatches.armAssistantCompletionIdleWatch({
|
|
5242
|
-
lastNotificationMethod: notification.method,
|
|
5243
|
-
hookRunId: hookNotification.runId,
|
|
5244
|
-
hookStatus: hookNotification.status
|
|
5245
|
-
});
|
|
5246
|
-
}
|
|
5247
|
-
if (notificationState.isTurnTerminal) {
|
|
4472
|
+
state.activeLocalProjections -= 1;
|
|
4473
|
+
if (isTerminal) {
|
|
5248
4474
|
if ((readCodexTurnCompletedNotification(notification.params)?.turn)?.status === "interrupted" && state.sawCodexInterruptMarker) projector.markAborted();
|
|
5249
4475
|
completeTurn();
|
|
5250
4476
|
}
|
|
@@ -5269,10 +4495,12 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
5269
4495
|
const noteNotificationReceived = (notification, scope, receivedAtMs) => {
|
|
5270
4496
|
const projector = projectorRef.current;
|
|
5271
4497
|
const turnId = turnIdRef.current;
|
|
5272
|
-
if (!projector || !turnId) return;
|
|
4498
|
+
if (!projector || !turnId || state.projectionClosed) return;
|
|
4499
|
+
projector.recordMcpToolCallReceipt(notification);
|
|
5273
4500
|
if (isTerminalTurnNotificationForTurn(notification, turnId)) {
|
|
5274
4501
|
state.terminalTurnNotificationQueued = true;
|
|
5275
4502
|
steeringQueueRef.current?.sealAdmission();
|
|
4503
|
+
deadlines.beginSettlement(receivedAtMs);
|
|
5276
4504
|
}
|
|
5277
4505
|
if (scope.turnId === turnId) {
|
|
5278
4506
|
const modelToolCallId = readRawResponseToolCallId(notification);
|
|
@@ -5280,11 +4508,6 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
5280
4508
|
const nativeItem = readCodexNotificationItem(notification.params);
|
|
5281
4509
|
if (nativeItem?.type === "webSearch") projector.recordNativeToolOutcome(nativeItem);
|
|
5282
4510
|
}
|
|
5283
|
-
if (readCodexFinalizationHookNotification(notification, resourceState.thread.threadId, turnId)?.phase === "started") {
|
|
5284
|
-
state.unsettledFinalizationHookCount += 1;
|
|
5285
|
-
turnWatches.disarmAssistantCompletionIdleWatch();
|
|
5286
|
-
}
|
|
5287
|
-
turnWatches.noteNotificationReceived(notification.method, { receivedAtMs });
|
|
5288
4511
|
};
|
|
5289
4512
|
const enqueueNotification = async (notification, scope) => {
|
|
5290
4513
|
embeddedAgentLog.trace("codex app-server raw notification received", {
|
|
@@ -5306,7 +4529,6 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
5306
4529
|
}
|
|
5307
4530
|
//#endregion
|
|
5308
4531
|
//#region extensions/codex/src/app-server/run-attempt-prompt.ts
|
|
5309
|
-
const CODEX_META_KEY = "__openclaw";
|
|
5310
4532
|
function isRestrictivePromptToolsAllow(toolsAllow) {
|
|
5311
4533
|
return toolsAllow !== void 0 && !toolsAllow.some((name) => name.trim() === "*");
|
|
5312
4534
|
}
|
|
@@ -5405,7 +4627,7 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
5405
4627
|
if (isRestrictivePromptToolsAllow(toolsAllow)) throw new Error("Codex app-server cannot enforce before_prompt_build toolsAllow; use the embedded or Copilot runtime for turn-scoped tool policy.");
|
|
5406
4628
|
return promptState.developerInstructions;
|
|
5407
4629
|
} },
|
|
5408
|
-
messages:
|
|
4630
|
+
messages: historyState.messages,
|
|
5409
4631
|
ctx: hookContext,
|
|
5410
4632
|
bootstrapContextRunKind: params.bootstrapContextRunKind,
|
|
5411
4633
|
toolAuthority: {
|
|
@@ -5483,11 +4705,9 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
5483
4705
|
const cutoff = Date.parse(binding.historyCoveredThrough ?? "");
|
|
5484
4706
|
return historyState.messages.filter((message) => {
|
|
5485
4707
|
if (message.role !== "user" && message.role !== "assistant") return false;
|
|
5486
|
-
const
|
|
5487
|
-
const mirrorIdentity = meta && typeof meta === "object" && !Array.isArray(meta) ? meta.mirrorIdentity : void 0;
|
|
5488
|
-
const mirrorOrigin = meta && typeof meta === "object" && !Array.isArray(meta) ? meta.mirrorOrigin : void 0;
|
|
4708
|
+
const mirrorIdentity = readMirrorIdentity(message);
|
|
5489
4709
|
const timestamp = typeof message.timestamp === "number" ? message.timestamp : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
|
|
5490
|
-
return !("idempotencyKey" in message && typeof message.idempotencyKey === "string" && message.idempotencyKey.startsWith("codex-app-server:")) &&
|
|
4710
|
+
return !("idempotencyKey" in message && typeof message.idempotencyKey === "string" && message.idempotencyKey.startsWith("codex-app-server:")) && !hasCodexMirrorOrigin(message) && !mirrorIdentity?.startsWith("codex-app-server:") && Number.isFinite(timestamp) && timestamp > (Number.isFinite(cutoff) ? cutoff : 0);
|
|
5491
4711
|
});
|
|
5492
4712
|
};
|
|
5493
4713
|
const applyResumeStaleBindingContinuityProjection = (binding) => {
|
|
@@ -5519,7 +4739,8 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
5519
4739
|
return projected;
|
|
5520
4740
|
};
|
|
5521
4741
|
const applyNoContextEngineContinuityProjection = (action, binding) => {
|
|
5522
|
-
|
|
4742
|
+
const hasContinuity = historyState.messages.some((message) => message.role === "user" || action === "started" && (message.role === "compactionSummary" || message.role === "branchSummary"));
|
|
4743
|
+
if (activeContextEngine || !hasContinuity) return false;
|
|
5523
4744
|
if (action === "resumed" && promptState.precomputedStaleBindingContinuityProjectionApplied) return true;
|
|
5524
4745
|
if (action === "started" && promptState.staleBindingContinuityForcedFreshStart) return true;
|
|
5525
4746
|
if (action === "started" && promptState.inactiveThreadBootstrapBindingForcedFreshStart) return false;
|
|
@@ -5612,7 +4833,7 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5612
4833
|
const { context, turnState, buildRenderedCodexDeveloperInstructions } = prompt;
|
|
5613
4834
|
const { runtime, attemptTools } = context;
|
|
5614
4835
|
const { connection, hookChannelId } = runtime;
|
|
5615
|
-
const { appServer, params, effectiveCwd, sessionAgentId,
|
|
4836
|
+
const { appServer, params, effectiveCwd, sessionAgentId, contextSessionKey, runAbortController, sandbox, options, nativeHookRelayEvents } = connection;
|
|
5616
4837
|
const { toolBridge } = attemptTools;
|
|
5617
4838
|
const trajectoryRecorder = createCodexTrajectoryRecorder({
|
|
5618
4839
|
attempt: params,
|
|
@@ -5652,7 +4873,7 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5652
4873
|
emitCodexNativePreToolUseFailureDiagnostic({
|
|
5653
4874
|
agentId: sessionAgentId,
|
|
5654
4875
|
sessionId: params.sessionId,
|
|
5655
|
-
sessionKey:
|
|
4876
|
+
sessionKey: contextSessionKey,
|
|
5656
4877
|
runId: params.runId,
|
|
5657
4878
|
signal: runAbortController.signal,
|
|
5658
4879
|
failure,
|
|
@@ -5774,8 +4995,10 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5774
4995
|
events: nativeHookRelayEvents,
|
|
5775
4996
|
agentId: sessionAgentId,
|
|
5776
4997
|
sessionId: params.sessionId,
|
|
5777
|
-
sessionKey:
|
|
4998
|
+
sessionKey: contextSessionKey,
|
|
5778
4999
|
config: params.config,
|
|
5000
|
+
autoApproveMcpTools: shouldAutoApproveCodexAppServerApprovals(appServer),
|
|
5001
|
+
projectedMcpServers: runtime.bundleMcpThreadConfig.configPatch?.mcp_servers,
|
|
5779
5002
|
runId: params.runId,
|
|
5780
5003
|
channelId: hookChannelId,
|
|
5781
5004
|
...requester ? { requester } : {},
|
|
@@ -5917,295 +5140,6 @@ function prewarmCodexAttemptClient(params) {
|
|
|
5917
5140
|
});
|
|
5918
5141
|
}
|
|
5919
5142
|
//#endregion
|
|
5920
|
-
//#region extensions/codex/src/app-server/scheduled-app-authority.ts
|
|
5921
|
-
const CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE = "codex.apps";
|
|
5922
|
-
const CODEX_APPS_MCP_SERVER = "codex_apps";
|
|
5923
|
-
const MCP_STATUS_PAGE_SIZE = 100;
|
|
5924
|
-
const MCP_STATUS_MAX_PAGES = 100;
|
|
5925
|
-
const CODEX_APP_AUTHORITY_CAPTURE_TIMEOUT_MS = 6e4;
|
|
5926
|
-
const CODEX_APP_AUTHORITY_CAPTURE_MIN_TIMEOUT_MS = 100;
|
|
5927
|
-
function resolveScheduledCodexAppCreatorCaptureDecision(params) {
|
|
5928
|
-
if (!params.appsMayBeVisible) return {
|
|
5929
|
-
required: false,
|
|
5930
|
-
supported: false
|
|
5931
|
-
};
|
|
5932
|
-
const unavailableReason = params.authenticatedScheduledMode ? "A scheduled Codex continuation cannot create new app-authorized automations. Recreate it from a fresh authenticated owner turn; no automation changes were saved." : params.usesSupervisionConnection ? "Codex apps are visible through a supervised connection that cannot capture creator authority. Use an isolated prepared-profile Codex creator turn; no automation changes were saved." : params.homeScope === "user" ? "Codex apps are visible through a user-home runtime that cannot capture isolated creator authority. Use an agent-scoped prepared-profile Codex creator turn; no automation changes were saved." : !params.hasPreparedAccountIdentity ? "Codex app authority requires a genuine ChatGPT account identity. Reauthenticate the selected Codex profile, then retry; no automation changes were saved." : void 0;
|
|
5933
|
-
return {
|
|
5934
|
-
required: true,
|
|
5935
|
-
supported: !unavailableReason,
|
|
5936
|
-
...unavailableReason ? { unavailableReason } : {}
|
|
5937
|
-
};
|
|
5938
|
-
}
|
|
5939
|
-
function normalizeApprovalMode(value) {
|
|
5940
|
-
return value === "allow" || value === "deny" || value === "auto" || value === "ask" ? value : void 0;
|
|
5941
|
-
}
|
|
5942
|
-
function normalizeAppToolApprovalMode(value) {
|
|
5943
|
-
return value === "auto" || value === "prompt" || value === "writes" || value === "approve" ? value : void 0;
|
|
5944
|
-
}
|
|
5945
|
-
function defaultApprovalMode(entry) {
|
|
5946
|
-
return entry.destructiveApprovalMode ?? (entry.allowDestructiveActions ? "allow" : "deny");
|
|
5947
|
-
}
|
|
5948
|
-
function parseScheduledCodexAppAuthority(authority) {
|
|
5949
|
-
if (!authority || authority.runtimeId !== "codex") return;
|
|
5950
|
-
if (authority.version !== 1) throw new Error("Unsupported Codex scheduled authority version; reauthorize this automation.");
|
|
5951
|
-
if (authority.namespace !== CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE) throw new Error(`Unsupported Codex scheduled authority namespace ${authority.namespace}; reauthorize this automation.`);
|
|
5952
|
-
const payload = asOptionalRecord(authority.payload);
|
|
5953
|
-
const auth = asOptionalRecord(payload?.auth);
|
|
5954
|
-
const profileId = normalizeOptionalString(auth?.profileId);
|
|
5955
|
-
const accountId = normalizeOptionalString(auth?.accountId);
|
|
5956
|
-
if (payload?.version !== 1 || !profileId || !accountId || !Array.isArray(payload.apps)) throw new Error("Stored Codex app authority is invalid; reauthorize this automation.");
|
|
5957
|
-
const seen = /* @__PURE__ */ new Set();
|
|
5958
|
-
const apps = payload.apps.map((raw) => {
|
|
5959
|
-
const app = asOptionalRecord(raw);
|
|
5960
|
-
const id = normalizeOptionalString(app?.id);
|
|
5961
|
-
const destructiveApprovalMode = normalizeApprovalMode(app?.destructiveApprovalMode);
|
|
5962
|
-
const rawTools = asOptionalRecord(app?.tools);
|
|
5963
|
-
if (!id || seen.has(id) || typeof app?.allowDestructiveActions !== "boolean" || typeof app.allowOpenWorld !== "boolean" || !destructiveApprovalMode || !rawTools) throw new Error("Stored Codex app authority is invalid; reauthorize this automation.");
|
|
5964
|
-
seen.add(id);
|
|
5965
|
-
const tools = {};
|
|
5966
|
-
for (const [name, rawMode] of Object.entries(rawTools)) {
|
|
5967
|
-
const toolName = normalizeOptionalString(name);
|
|
5968
|
-
const mode = normalizeAppToolApprovalMode(rawMode);
|
|
5969
|
-
if (!toolName || !mode) throw new Error("Stored Codex app authority is invalid; reauthorize this automation.");
|
|
5970
|
-
tools[toolName] = mode;
|
|
5971
|
-
}
|
|
5972
|
-
return {
|
|
5973
|
-
id,
|
|
5974
|
-
allowDestructiveActions: app.allowDestructiveActions,
|
|
5975
|
-
allowOpenWorld: app.allowOpenWorld,
|
|
5976
|
-
destructiveApprovalMode,
|
|
5977
|
-
tools
|
|
5978
|
-
};
|
|
5979
|
-
});
|
|
5980
|
-
return {
|
|
5981
|
-
version: 1,
|
|
5982
|
-
auth: {
|
|
5983
|
-
profileId,
|
|
5984
|
-
accountId
|
|
5985
|
-
},
|
|
5986
|
-
apps
|
|
5987
|
-
};
|
|
5988
|
-
}
|
|
5989
|
-
async function readCodexScheduledAppToolNamesByApp(params) {
|
|
5990
|
-
const toolNamesByApp = /* @__PURE__ */ new Map();
|
|
5991
|
-
const seenCursors = /* @__PURE__ */ new Set();
|
|
5992
|
-
let cursor;
|
|
5993
|
-
for (let page = 0; page < MCP_STATUS_MAX_PAGES; page += 1) {
|
|
5994
|
-
const response = await params.request("mcpServerStatus/list", {
|
|
5995
|
-
...params.threadId ? { threadId: params.threadId } : {},
|
|
5996
|
-
detail: "toolsAndAuthOnly",
|
|
5997
|
-
limit: MCP_STATUS_PAGE_SIZE,
|
|
5998
|
-
...cursor ? { cursor } : {}
|
|
5999
|
-
});
|
|
6000
|
-
if (!isJsonObject(response) || !Array.isArray(response.data)) throw new Error("Codex mcpServerStatus/list returned invalid scheduled app inventory");
|
|
6001
|
-
for (const status of response.data) {
|
|
6002
|
-
if (!isJsonObject(status) || !isJsonObject(status.tools)) throw new Error("Codex scheduled app inventory contained an invalid server status");
|
|
6003
|
-
if (status.name !== CODEX_APPS_MCP_SERVER) continue;
|
|
6004
|
-
for (const [toolName, tool] of Object.entries(status.tools)) {
|
|
6005
|
-
const connectorId = readCodexMcpToolConnectorId(tool);
|
|
6006
|
-
if (connectorId) {
|
|
6007
|
-
const names = toolNamesByApp.get(connectorId) ?? /* @__PURE__ */ new Set();
|
|
6008
|
-
names.add(toolName);
|
|
6009
|
-
toolNamesByApp.set(connectorId, names);
|
|
6010
|
-
}
|
|
6011
|
-
}
|
|
6012
|
-
}
|
|
6013
|
-
if (response.nextCursor !== void 0 && response.nextCursor !== null && typeof response.nextCursor !== "string") throw new Error("Codex scheduled app inventory returned an invalid pagination cursor");
|
|
6014
|
-
cursor = response.nextCursor;
|
|
6015
|
-
if (!cursor) return toolNamesByApp;
|
|
6016
|
-
if (seenCursors.has(cursor)) throw new Error("Codex app connector inventory repeated its pagination cursor");
|
|
6017
|
-
seenCursors.add(cursor);
|
|
6018
|
-
}
|
|
6019
|
-
throw new Error("Codex app connector inventory exceeded its bounded page limit");
|
|
6020
|
-
}
|
|
6021
|
-
/** Reads the current account policy and connector-backed tool names under one caller deadline. */
|
|
6022
|
-
async function readCurrentCodexScheduledAppPolicy$1(params) {
|
|
6023
|
-
const [configResponse, toolNamesByApp] = await Promise.all([params.request("config/read", {
|
|
6024
|
-
includeLayers: false,
|
|
6025
|
-
...params.configCwd ? { cwd: params.configCwd } : {}
|
|
6026
|
-
}), readCodexScheduledAppToolNamesByApp(params)]);
|
|
6027
|
-
if (!isJsonObject(configResponse)) throw new Error("Codex config/read returned an invalid scheduled app policy response");
|
|
6028
|
-
return {
|
|
6029
|
-
config: isJsonObject(configResponse.config) ? configResponse.config : {},
|
|
6030
|
-
toolNamesByApp
|
|
6031
|
-
};
|
|
6032
|
-
}
|
|
6033
|
-
function readToolApprovalMode(config, appId, toolName, fallback = "auto") {
|
|
6034
|
-
return normalizeAppToolApprovalMode(asOptionalRecord(asOptionalRecord(asOptionalRecord(asOptionalRecord(config.apps)?.[appId])?.tools)?.[toolName])?.approval_mode) ?? fallback;
|
|
6035
|
-
}
|
|
6036
|
-
/** Captures only apps callable on the exact active Codex client/thread. */
|
|
6037
|
-
async function captureScheduledCodexAppAuthority(params) {
|
|
6038
|
-
const requestedTimeoutMs = params.timeoutMs ?? CODEX_APP_AUTHORITY_CAPTURE_TIMEOUT_MS;
|
|
6039
|
-
const timeoutMs = Math.min(CODEX_APP_AUTHORITY_CAPTURE_TIMEOUT_MS, Math.max(CODEX_APP_AUTHORITY_CAPTURE_MIN_TIMEOUT_MS, Number.isFinite(requestedTimeoutMs) ? Math.floor(requestedTimeoutMs) : CODEX_APP_AUTHORITY_CAPTURE_TIMEOUT_MS));
|
|
6040
|
-
const deadlineMs = Date.now() + timeoutMs;
|
|
6041
|
-
const boundedClient = { request: ((method, requestParams) => {
|
|
6042
|
-
const remainingTimeoutMs = deadlineMs - Date.now();
|
|
6043
|
-
if (remainingTimeoutMs <= 0) throw new CodexScheduledAppAuthorityCaptureTimeoutError();
|
|
6044
|
-
return params.client.request(method, requestParams, {
|
|
6045
|
-
timeoutMs: remainingTimeoutMs,
|
|
6046
|
-
signal: params.signal
|
|
6047
|
-
});
|
|
6048
|
-
}) };
|
|
6049
|
-
let installed;
|
|
6050
|
-
let currentPolicy;
|
|
6051
|
-
try {
|
|
6052
|
-
[installed, currentPolicy] = await withAbortableTimeout({
|
|
6053
|
-
promise: Promise.all([boundedClient.request("app/installed", {
|
|
6054
|
-
threadId: params.threadId,
|
|
6055
|
-
forceRefresh: false
|
|
6056
|
-
}), readCurrentCodexScheduledAppPolicy$1({
|
|
6057
|
-
request: (method, requestParams) => boundedClient.request(method, requestParams),
|
|
6058
|
-
threadId: params.threadId,
|
|
6059
|
-
configCwd: params.configCwd
|
|
6060
|
-
})]),
|
|
6061
|
-
timeoutMs,
|
|
6062
|
-
signal: params.signal,
|
|
6063
|
-
timeoutMessage: "Codex scheduled app authority capture deadline elapsed",
|
|
6064
|
-
createTimeoutError: () => new CodexScheduledAppAuthorityCaptureTimeoutError()
|
|
6065
|
-
});
|
|
6066
|
-
} catch (error) {
|
|
6067
|
-
if (params.signal?.aborted || !(error instanceof CodexScheduledAppAuthorityCaptureTimeoutError) && !isCodexAppServerRequestTimeoutError(error)) throw error;
|
|
6068
|
-
throw new Error(`Codex app authority capture exceeded its ${timeoutMs} ms total budget. No automation changes were saved; retry after Codex app inventory is responsive.`, { cause: error });
|
|
6069
|
-
}
|
|
6070
|
-
const callableIds = new Set(installed.apps.filter((app) => app.enabled && app.callable).map((app) => app.id));
|
|
6071
|
-
const apps = Object.entries(params.policyContext.apps).filter(([id]) => callableIds.has(id) && currentPolicy.toolNamesByApp.has(id)).map(([id, policy]) => ({
|
|
6072
|
-
id,
|
|
6073
|
-
allowDestructiveActions: policy.allowDestructiveActions,
|
|
6074
|
-
allowOpenWorld: policy.allowOpenWorld !== false,
|
|
6075
|
-
destructiveApprovalMode: defaultApprovalMode(policy),
|
|
6076
|
-
tools: Object.fromEntries([...currentPolicy.toolNamesByApp.get(id) ?? []].toSorted().map((toolName) => [toolName, readToolApprovalMode(currentPolicy.config, id, toolName, appApprovalCeiling(defaultApprovalMode(policy)))]))
|
|
6077
|
-
})).toSorted((left, right) => left.id.localeCompare(right.id));
|
|
6078
|
-
if (apps.length === 0) return;
|
|
6079
|
-
return {
|
|
6080
|
-
version: 1,
|
|
6081
|
-
runtimeId: "codex",
|
|
6082
|
-
namespace: CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE,
|
|
6083
|
-
payload: {
|
|
6084
|
-
version: 1,
|
|
6085
|
-
auth: {
|
|
6086
|
-
profileId: params.profileId,
|
|
6087
|
-
accountId: params.accountId
|
|
6088
|
-
},
|
|
6089
|
-
apps
|
|
6090
|
-
}
|
|
6091
|
-
};
|
|
6092
|
-
}
|
|
6093
|
-
var CodexScheduledAppAuthorityCaptureTimeoutError = class extends Error {
|
|
6094
|
-
constructor() {
|
|
6095
|
-
super("Codex scheduled app authority capture deadline elapsed");
|
|
6096
|
-
this.name = "CodexScheduledAppAuthorityCaptureTimeoutError";
|
|
6097
|
-
}
|
|
6098
|
-
};
|
|
6099
|
-
const APPROVAL_RANK = {
|
|
6100
|
-
deny: 0,
|
|
6101
|
-
ask: 1,
|
|
6102
|
-
auto: 2,
|
|
6103
|
-
allow: 3
|
|
6104
|
-
};
|
|
6105
|
-
function stricterApprovalMode(left, right) {
|
|
6106
|
-
return APPROVAL_RANK[left] <= APPROVAL_RANK[right] ? left : right;
|
|
6107
|
-
}
|
|
6108
|
-
function intersectToolApprovalMode(captured, current) {
|
|
6109
|
-
if (captured === current) return captured;
|
|
6110
|
-
if (captured === "prompt" || current === "prompt") return "prompt";
|
|
6111
|
-
if (captured === "approve") return current;
|
|
6112
|
-
if (current === "approve") return captured;
|
|
6113
|
-
return "prompt";
|
|
6114
|
-
}
|
|
6115
|
-
function appApprovalCeiling(mode) {
|
|
6116
|
-
if (mode === "allow") return "approve";
|
|
6117
|
-
return mode === "ask" ? "prompt" : "auto";
|
|
6118
|
-
}
|
|
6119
|
-
function stableStringify(value) {
|
|
6120
|
-
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
6121
|
-
if (value && typeof value === "object") return `{${Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`).join(",")}}`;
|
|
6122
|
-
return JSON.stringify(value);
|
|
6123
|
-
}
|
|
6124
|
-
/** Intersects a stored app-ID cap with current policy without admitting new apps. */
|
|
6125
|
-
function intersectCodexPluginThreadConfigWithScheduledAuthority(config, authority, currentPolicy = {
|
|
6126
|
-
config: {},
|
|
6127
|
-
toolNamesByApp: /* @__PURE__ */ new Map()
|
|
6128
|
-
}) {
|
|
6129
|
-
const scheduled = parseScheduledCodexAppAuthority(authority);
|
|
6130
|
-
if (!scheduled) return config;
|
|
6131
|
-
const omittedAppIds = scheduled.apps.map((app) => app.id).filter((id) => {
|
|
6132
|
-
const currentTools = currentPolicy.toolNamesByApp.get(id);
|
|
6133
|
-
return !Object.hasOwn(config.policyContext.apps, id) || !currentTools || currentTools.size === 0;
|
|
6134
|
-
}).toSorted();
|
|
6135
|
-
if (omittedAppIds.length > 0) {
|
|
6136
|
-
const visibleIds = omittedAppIds.slice(0, 10).join(", ");
|
|
6137
|
-
const remaining = omittedAppIds.length - Math.min(omittedAppIds.length, 10);
|
|
6138
|
-
throw new AgentHarnessPreflightError(`Scheduled Codex apps are unavailable under the current policy or account: ${visibleIds}${remaining > 0 ? ` (and ${remaining} more)` : ""}. Restore access or reauthorize the automation from a fresh authenticated Codex owner turn.`);
|
|
6139
|
-
}
|
|
6140
|
-
const capturedById = new Map(scheduled.apps.map((app) => [app.id, app]));
|
|
6141
|
-
const apps = {};
|
|
6142
|
-
for (const [id, current] of Object.entries(config.policyContext.apps)) {
|
|
6143
|
-
const captured = capturedById.get(id);
|
|
6144
|
-
if (!captured) continue;
|
|
6145
|
-
apps[id] = {
|
|
6146
|
-
...current,
|
|
6147
|
-
allowDestructiveActions: current.allowDestructiveActions && captured.allowDestructiveActions,
|
|
6148
|
-
allowOpenWorld: current.allowOpenWorld !== false && captured.allowOpenWorld,
|
|
6149
|
-
destructiveApprovalMode: stricterApprovalMode(defaultApprovalMode(current), captured.destructiveApprovalMode)
|
|
6150
|
-
};
|
|
6151
|
-
}
|
|
6152
|
-
const policyContext = buildPluginAppPolicyContext(apps, Object.fromEntries(Object.entries(config.policyContext.pluginAppIds).map(([key, ids]) => [key, ids.filter((id) => Object.hasOwn(apps, id))]).filter(([, ids]) => ids.length > 0)));
|
|
6153
|
-
const configPatch = buildCodexPluginAppsConfigPatchFromPolicyContext(policyContext);
|
|
6154
|
-
const appsPatch = asOptionalRecord(configPatch.apps);
|
|
6155
|
-
for (const [appId, captured] of capturedById) {
|
|
6156
|
-
const appPatch = asOptionalRecord(appsPatch?.[appId]);
|
|
6157
|
-
if (!appPatch || !Object.hasOwn(apps, appId)) continue;
|
|
6158
|
-
const currentApp = apps[appId];
|
|
6159
|
-
if (!currentApp) continue;
|
|
6160
|
-
const storedAppCeiling = appApprovalCeiling(captured.destructiveApprovalMode);
|
|
6161
|
-
const currentAppCeiling = appApprovalCeiling(defaultApprovalMode(currentApp));
|
|
6162
|
-
const toolNames = currentPolicy.toolNamesByApp.get(appId) ?? /* @__PURE__ */ new Set();
|
|
6163
|
-
appPatch.tools = Object.fromEntries([...toolNames].toSorted().map((toolName) => {
|
|
6164
|
-
return [toolName, { approval_mode: intersectToolApprovalMode(intersectToolApprovalMode(captured.tools[toolName] ?? storedAppCeiling, storedAppCeiling), intersectToolApprovalMode(readToolApprovalMode(currentPolicy.config, appId, toolName, currentAppCeiling), currentAppCeiling)) }];
|
|
6165
|
-
}));
|
|
6166
|
-
}
|
|
6167
|
-
const fingerprint = crypto.createHash("sha256").update(stableStringify({
|
|
6168
|
-
version: 1,
|
|
6169
|
-
namespace: CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE,
|
|
6170
|
-
authority: scheduled,
|
|
6171
|
-
inputFingerprint: config.inputFingerprint,
|
|
6172
|
-
policyContext,
|
|
6173
|
-
configPatch
|
|
6174
|
-
})).digest("hex");
|
|
6175
|
-
return {
|
|
6176
|
-
...config,
|
|
6177
|
-
fingerprint,
|
|
6178
|
-
configPatch,
|
|
6179
|
-
provisionalAppIds: Object.keys(apps).toSorted(),
|
|
6180
|
-
policyContext
|
|
6181
|
-
};
|
|
6182
|
-
}
|
|
6183
|
-
function readScheduledCodexAppAuthorityAuth(authority) {
|
|
6184
|
-
return parseScheduledCodexAppAuthority(authority)?.auth;
|
|
6185
|
-
}
|
|
6186
|
-
function assertScheduledCodexAppAuthorityRuntime(connection, params) {
|
|
6187
|
-
const scheduledAuth = readScheduledCodexAppAuthorityAuth(params.scheduledRuntimeAuthority);
|
|
6188
|
-
if (!scheduledAuth) return;
|
|
6189
|
-
if (params.trigger !== "cron" || connection.usesSupervisionConnection || connection.appServer.start.homeScope === "user") throw new AgentHarnessPreflightError("This automation's Codex app authority requires an isolated scheduled prepared-profile runtime. Reauthorize it from a supported Codex creator turn.");
|
|
6190
|
-
const prepared = connection.startupPreparedAuth;
|
|
6191
|
-
if (prepared?.kind !== "profile" || prepared.profileId !== scheduledAuth.profileId || prepared.snapshot?.loginParams.type !== "chatgptAuthTokens" || prepared.snapshot.chatgptAccountId !== scheduledAuth.accountId) throw new AgentHarnessPreflightError(`This automation was authorized for Codex profile ${scheduledAuth.profileId}, but that exact prepared account is not active. Restore the profile or reauthorize the automation from a fresh owner turn.`);
|
|
6192
|
-
}
|
|
6193
|
-
function buildLegacyScheduledCodexAppRecoveryPrompt(params) {
|
|
6194
|
-
if (params.trigger !== "cron" || !params.scheduledRuntimeAuthorityRecoveryRequired || params.scheduledRuntimeAuthority) return;
|
|
6195
|
-
return "Scheduled Codex app access is unavailable because this automation predates runtime-specific app authority capture. Tell the operator to recreate or reauthorize it from a fresh authenticated Codex owner turn; do not claim an app action succeeded.";
|
|
6196
|
-
}
|
|
6197
|
-
/** Makes stored-cap identity part of thread reuse admission, including cap removal. */
|
|
6198
|
-
function buildScheduledCodexAppAuthorityInputFingerprint(baseFingerprint, authority) {
|
|
6199
|
-
const scheduled = parseScheduledCodexAppAuthority(authority);
|
|
6200
|
-
if (!scheduled) return baseFingerprint;
|
|
6201
|
-
return crypto.createHash("sha256").update(stableStringify({
|
|
6202
|
-
version: 1,
|
|
6203
|
-
namespace: CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE,
|
|
6204
|
-
baseFingerprint,
|
|
6205
|
-
authority: scheduled
|
|
6206
|
-
})).digest("hex");
|
|
6207
|
-
}
|
|
6208
|
-
//#endregion
|
|
6209
5143
|
//#region extensions/codex/src/app-server/scheduled-configured-mcp-authority.ts
|
|
6210
5144
|
/** Limits fresh scheduled-authority capture to authenticated local durable operator turns. */
|
|
6211
5145
|
function canResolveScheduledConfiguredMcpCreatorAuthority(params) {
|
|
@@ -6218,7 +5152,7 @@ function resolveCodexAttemptBundleManifestRegistry(preparedModelRuntime) {
|
|
|
6218
5152
|
return metadataSnapshot?.pluginIds === void 0 ? metadataSnapshot?.manifestRegistry : void 0;
|
|
6219
5153
|
}
|
|
6220
5154
|
async function prepareCodexAttemptRuntime(connection) {
|
|
6221
|
-
const { params, pluginConfig, usesSupervisionConnection, appServer, startupAuthProfileId, startupPreparedAuth, startupClientAuthProfileId, agentDir, preDynamicStartupStages, effectiveWorkspace, contextSessionKey, sandboxSessionKey, sessionAgentId, sandbox, attemptClientFactory, runAbortController, activeContextEngine, mutable } = connection;
|
|
5155
|
+
const { params, pluginConfig, usesSupervisionConnection, appServer, startupAuthProfileId, startupPreparedAuth, startupClientAuthProfileId, agentDir, preDynamicStartupStages, effectiveWorkspace, contextSessionKey, sandboxSessionKey, sessionAgentId, policyAgentId, sandbox, attemptClientFactory, runAbortController, activeContextEngine, mutable } = connection;
|
|
6222
5156
|
const preparedAuthBinding = !usesSupervisionConnection && appServer.start.homeScope !== "user" && startupAuthProfileId ? await prepareCodexAppServerAuthBinding({
|
|
6223
5157
|
authProfileId: startupAuthProfileId,
|
|
6224
5158
|
authProfileStore: params.authProfileStore,
|
|
@@ -6291,6 +5225,7 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
6291
5225
|
const bundleManifestRegistry = resolveCodexAttemptBundleManifestRegistry(params.preparedModelRuntime);
|
|
6292
5226
|
const bundleMcpThreadConfig = await loadCodexBundleMcpThreadConfig({
|
|
6293
5227
|
workspaceDir: effectiveWorkspace,
|
|
5228
|
+
agentId: sessionAgentId,
|
|
6294
5229
|
cfg: params.config,
|
|
6295
5230
|
toolsEnabled: usesSupervisionConnection || supportsModelTools(params.model),
|
|
6296
5231
|
disableTools: params.disableTools,
|
|
@@ -6299,7 +5234,7 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
6299
5234
|
toolOverrides: codexMcpToolOverrides
|
|
6300
5235
|
});
|
|
6301
5236
|
const authenticatedScheduledMode = params.trigger === "cron" && params.scheduledToolPolicy !== void 0 && Array.isArray(params.toolsAllow);
|
|
6302
|
-
const
|
|
5237
|
+
const scheduledConfiguredMcpSurface = authenticatedScheduledMode && (bundleMcpThreadConfig.staticServerNames.length > 0 || mutable.startupBinding?.configuredMcpOwnershipVersion === 1);
|
|
6303
5238
|
const cronCreatorAuthorityCapability = params.cronCreatorAuthorityCapability;
|
|
6304
5239
|
const hasFreshCreatorAuthority = cronCreatorAuthorityCapability?.active === true && cronCreatorAuthorityCapability.runId === params.runId && !cronCreatorAuthorityCapability.signal.aborted;
|
|
6305
5240
|
const mayResolveScheduledConfiguredMcpCreatorAuthority = !authenticatedScheduledMode && canResolveScheduledConfiguredMcpCreatorAuthority({
|
|
@@ -6322,10 +5257,11 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
6322
5257
|
preDynamicStartupStages.mark("bundle-mcp");
|
|
6323
5258
|
const sandboxExecServerEnabled = isCodexSandboxExecServerEnabled(pluginConfig, sandbox);
|
|
6324
5259
|
const nativeToolSurfaceEnabled = shouldEnableCodexAppServerNativeToolSurface(runtimeParams, sandbox, {
|
|
6325
|
-
agentId:
|
|
5260
|
+
agentId: policyAgentId,
|
|
6326
5261
|
runtimeSessionKey: sandboxSessionKey,
|
|
6327
5262
|
sandboxExecServerEnabled
|
|
6328
5263
|
});
|
|
5264
|
+
const configuredMcpSurface = scheduledConfiguredMcpSurface ? "scheduled" : !nativeToolSurfaceEnabled && bundleMcpThreadConfig.staticServerNames.length > 0 ? "transient" : void 0;
|
|
6329
5265
|
preDynamicStartupStages.mark("native-tool-surface");
|
|
6330
5266
|
const nativeProviderWebSearchSupport = resolveCodexWebSearchPlan({
|
|
6331
5267
|
config: params.config,
|
|
@@ -6375,7 +5311,7 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
6375
5311
|
bundleMcpThreadConfig,
|
|
6376
5312
|
bundleManifestRegistry,
|
|
6377
5313
|
authenticatedScheduledMode,
|
|
6378
|
-
|
|
5314
|
+
configuredMcpSurface,
|
|
6379
5315
|
canResolveScheduledConfiguredMcpCreatorAuthority: mayResolveScheduledConfiguredMcpCreatorAuthority,
|
|
6380
5316
|
codexMcpToolOverrides,
|
|
6381
5317
|
sandboxExecServerEnabled,
|
|
@@ -6469,7 +5405,6 @@ function resolveCodexDynamicToolDirectNames(params, hostSystemAgentActive = fals
|
|
|
6469
5405
|
const names = [];
|
|
6470
5406
|
if (hostSystemAgentActive && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow)) names.push("openclaw");
|
|
6471
5407
|
if (params.sourceReplyDeliveryMode === "message_tool_only") names.push("message");
|
|
6472
|
-
names.push("progress_card");
|
|
6473
5408
|
return names;
|
|
6474
5409
|
}
|
|
6475
5410
|
//#endregion
|
|
@@ -6485,37 +5420,32 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6485
5420
|
const { runtime, attemptTools } = context;
|
|
6486
5421
|
const { connection } = runtime;
|
|
6487
5422
|
const { params, computerUseConfig, runAbortController, appServer, sessionAgentId } = connection;
|
|
5423
|
+
const autoApprove = shouldAutoApproveCodexAppServerApprovals(appServer);
|
|
6488
5424
|
const { compactionPlanState, toolBridge, toolOutcomeOrdinals, suppressedDynamicToolOutcomeOrdinals, allocateCodexToolOutcomeOrdinal } = attemptTools;
|
|
6489
|
-
const { state, turnIdRef, userInputBridgeRef, openClawDynamicToolExecutions, pendingOpenClawDynamicToolCompletionIds,
|
|
5425
|
+
const { state, turnIdRef, userInputBridgeRef, openClawDynamicToolExecutions, pendingOpenClawDynamicToolCompletionIds, noteProgress } = turnRuntime;
|
|
6490
5426
|
const { emitExecutionPhaseOnce, scheduleTurnReleaseAfterTerminalDynamicTool, scheduleTerminalDynamicToolReleaseCheck } = lifecycle;
|
|
6491
5427
|
const handleServerRequest = async (request, scope, requestSignal = new AbortController().signal) => {
|
|
6492
5428
|
const signal = AbortSignal.any([runAbortController.signal, requestSignal]);
|
|
6493
5429
|
const turnId = turnIdRef.current;
|
|
6494
5430
|
const projector = projectorRef.current;
|
|
6495
|
-
let armCompletionWatchOnResponse = false;
|
|
6496
5431
|
let requestCountsAsTurnActivity = false;
|
|
6497
|
-
|
|
6498
|
-
const markCurrentTurnRequestProgress = (options) => {
|
|
5432
|
+
const markCurrentTurnRequestProgress = () => {
|
|
6499
5433
|
state.activeAppServerTurnRequests += 1;
|
|
6500
|
-
requestKeepsAttemptWatchArmed = options?.hasIndependentTimeout !== true;
|
|
6501
|
-
if (requestKeepsAttemptWatchArmed) state.activeAppServerTurnRequestsWithoutTimeout += 1;
|
|
6502
|
-
turnWatches.clearCompletionIdleTimer();
|
|
6503
|
-
turnWatches.disarmAssistantCompletionIdleWatch();
|
|
6504
5434
|
requestCountsAsTurnActivity = true;
|
|
6505
|
-
|
|
5435
|
+
noteProgress(`request:${request.method}:start`);
|
|
6506
5436
|
};
|
|
6507
5437
|
try {
|
|
6508
5438
|
if (!turnId) return;
|
|
6509
5439
|
if (request.method === "mcpServer/elicitation/request") {
|
|
6510
|
-
if (!scope.turnId || scope.turnId === turnId)
|
|
6511
|
-
armCompletionWatchOnResponse = true;
|
|
6512
|
-
markCurrentTurnRequestProgress();
|
|
6513
|
-
}
|
|
5440
|
+
if (!scope.turnId || scope.turnId === turnId) markCurrentTurnRequestProgress();
|
|
6514
5441
|
const approvalResult = await routeCodexAppServerElicitationRequest({
|
|
6515
5442
|
requestParams: request.params,
|
|
6516
5443
|
paramsForRun: params,
|
|
6517
5444
|
threadId: resourceState.thread.threadId,
|
|
6518
5445
|
turnId,
|
|
5446
|
+
autoApproveMcpTools: autoApprove,
|
|
5447
|
+
projectedMcpServers: runtime.bundleMcpThreadConfig.configPatch?.mcp_servers,
|
|
5448
|
+
getActiveMcpToolCall: (serverName) => projector?.getActiveMcpToolCall(serverName),
|
|
6519
5449
|
pluginAppPolicyContext: resourceState.thread.pluginAppPolicyContext,
|
|
6520
5450
|
...computerUseConfig.enabled ? { computerUseMcpServerName: computerUseConfig.mcpServerName } : {},
|
|
6521
5451
|
signal
|
|
@@ -6527,10 +5457,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6527
5457
|
});
|
|
6528
5458
|
}
|
|
6529
5459
|
if (request.method === "item/tool/requestUserInput") {
|
|
6530
|
-
if (scope.turnId === turnId)
|
|
6531
|
-
armCompletionWatchOnResponse = true;
|
|
6532
|
-
markCurrentTurnRequestProgress();
|
|
6533
|
-
}
|
|
5460
|
+
if (scope.turnId === turnId) markCurrentTurnRequestProgress();
|
|
6534
5461
|
return await userInputBridgeRef.current?.handleRequest({
|
|
6535
5462
|
id: request.id,
|
|
6536
5463
|
params: request.params
|
|
@@ -6538,10 +5465,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6538
5465
|
}
|
|
6539
5466
|
if (request.method !== "item/tool/call") {
|
|
6540
5467
|
if (isCodexAppServerApprovalRequest(request.method)) {
|
|
6541
|
-
if (scope.turnId === turnId)
|
|
6542
|
-
armCompletionWatchOnResponse = true;
|
|
6543
|
-
markCurrentTurnRequestProgress();
|
|
6544
|
-
}
|
|
5468
|
+
if (scope.turnId === turnId) markCurrentTurnRequestProgress();
|
|
6545
5469
|
return await handleCodexAppServerApprovalRequest({
|
|
6546
5470
|
method: request.method,
|
|
6547
5471
|
requestParams: request.params,
|
|
@@ -6549,7 +5473,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6549
5473
|
threadId: resourceState.thread.threadId,
|
|
6550
5474
|
turnId,
|
|
6551
5475
|
nativeHookRelay: resourceState.nativeHookRelay,
|
|
6552
|
-
autoApprove
|
|
5476
|
+
autoApprove,
|
|
6553
5477
|
signal,
|
|
6554
5478
|
onNativeToolFailureDisposition: (itemId, disposition, approvalKind) => projector?.recordNativeToolApprovalFailure(itemId, disposition, approvalKind)
|
|
6555
5479
|
});
|
|
@@ -6560,15 +5484,11 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6560
5484
|
if (!call || call.threadId !== resourceState.thread.threadId || call.turnId !== turnId) return;
|
|
6561
5485
|
const replayedExecution = openClawDynamicToolExecutions.get(call);
|
|
6562
5486
|
if (replayedExecution) {
|
|
6563
|
-
|
|
6564
|
-
markCurrentTurnRequestProgress({ hasIndependentTimeout: true });
|
|
6565
|
-
state.turnCrossedToolHandoff = true;
|
|
5487
|
+
markCurrentTurnRequestProgress();
|
|
6566
5488
|
return toCodexDynamicToolProtocolResponse(await replayedExecution);
|
|
6567
5489
|
}
|
|
6568
5490
|
const toolCallOrdinal = allocateCodexToolOutcomeOrdinal?.(call.callId);
|
|
6569
|
-
|
|
6570
|
-
markCurrentTurnRequestProgress({ hasIndependentTimeout: true });
|
|
6571
|
-
state.turnCrossedToolHandoff = true;
|
|
5491
|
+
markCurrentTurnRequestProgress();
|
|
6572
5492
|
pendingOpenClawDynamicToolCompletionIds.add(call.callId);
|
|
6573
5493
|
trajectoryRecorder?.recordEvent("tool.call", {
|
|
6574
5494
|
threadId: call.threadId,
|
|
@@ -6596,6 +5516,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6596
5516
|
data: {
|
|
6597
5517
|
phase: "start",
|
|
6598
5518
|
name: call.tool,
|
|
5519
|
+
itemId: call.callId,
|
|
6599
5520
|
toolCallId: call.callId,
|
|
6600
5521
|
...toolMeta ? { meta: toolMeta } : {},
|
|
6601
5522
|
...toolArgs ? { args: toolArgs } : {},
|
|
@@ -6618,7 +5539,8 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6618
5539
|
})) terminalDiagnosticObserved = true;
|
|
6619
5540
|
}, { include: DYNAMIC_TOOL_TERMINAL_DIAGNOSTIC_TYPES });
|
|
6620
5541
|
try {
|
|
6621
|
-
const { execution } = openClawDynamicToolExecutions.claim(call, () => {
|
|
5542
|
+
const { execution } = openClawDynamicToolExecutions.claim(call, async () => {
|
|
5543
|
+
await projector?.transcriptCheckpoint.flush();
|
|
6622
5544
|
emitDynamicToolStartedDiagnostic({
|
|
6623
5545
|
call,
|
|
6624
5546
|
agentId: sessionAgentId,
|
|
@@ -6626,7 +5548,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6626
5548
|
sessionId: params.sessionId,
|
|
6627
5549
|
sessionKey: params.sessionKey
|
|
6628
5550
|
});
|
|
6629
|
-
|
|
5551
|
+
const response = await handleDynamicToolCallWithTimeout({
|
|
6630
5552
|
call,
|
|
6631
5553
|
toolBridge,
|
|
6632
5554
|
signal,
|
|
@@ -6648,6 +5570,9 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6648
5570
|
});
|
|
6649
5571
|
}
|
|
6650
5572
|
});
|
|
5573
|
+
recordCodexDynamicToolResult(projector, call, response, toCodexDynamicToolProtocolResponse(response));
|
|
5574
|
+
await projector?.transcriptCheckpoint.flush();
|
|
5575
|
+
return response;
|
|
6651
5576
|
});
|
|
6652
5577
|
const response = await execution;
|
|
6653
5578
|
const protocolResponse = toCodexDynamicToolProtocolResponse(response);
|
|
@@ -6671,7 +5596,6 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6671
5596
|
success: protocolResponse.success,
|
|
6672
5597
|
contentItems: protocolResponse.contentItems
|
|
6673
5598
|
});
|
|
6674
|
-
recordCodexDynamicToolResult(projector, call, response, protocolResponse);
|
|
6675
5599
|
if (protocolResponse.success && call.tool === "progress_card") {
|
|
6676
5600
|
const progressCardInput = response.executedArguments ?? call.arguments;
|
|
6677
5601
|
await projector?.recordDynamicProgressCardUpdate(progressCardInput);
|
|
@@ -6684,6 +5608,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6684
5608
|
data: {
|
|
6685
5609
|
phase: "result",
|
|
6686
5610
|
name: call.tool,
|
|
5611
|
+
itemId: call.callId,
|
|
6687
5612
|
toolCallId: call.callId,
|
|
6688
5613
|
...toolMeta ? { meta: toolMeta } : {},
|
|
6689
5614
|
...commandBearing ? { commandBearing: true } : {},
|
|
@@ -6740,17 +5665,10 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6740
5665
|
}
|
|
6741
5666
|
} finally {
|
|
6742
5667
|
if (requestCountsAsTurnActivity) {
|
|
6743
|
-
state.activeAppServerTurnRequests
|
|
6744
|
-
|
|
6745
|
-
const postToolContinuationTimeoutMs = request.method === "item/tool/call" && state.turnCrossedToolHandoff ? postToolRawAssistantCompletionIdleTimeoutMs : void 0;
|
|
6746
|
-
turnWatches.touchActivity(`request:${request.method}:response`, {
|
|
6747
|
-
arm: armCompletionWatchOnResponse,
|
|
6748
|
-
attemptProgress: true,
|
|
6749
|
-
...postToolContinuationTimeoutMs !== void 0 ? { attemptTimeoutMs: postToolContinuationTimeoutMs } : {}
|
|
6750
|
-
});
|
|
6751
|
-
if (armCompletionWatchOnResponse && postToolContinuationTimeoutMs !== void 0) turnWatches.armCompletionIdleWatch({ timeoutMs: postToolContinuationTimeoutMs });
|
|
5668
|
+
state.activeAppServerTurnRequests -= 1;
|
|
5669
|
+
noteProgress(`request:${request.method}:response`);
|
|
6752
5670
|
scheduleTerminalDynamicToolReleaseCheck();
|
|
6753
|
-
}
|
|
5671
|
+
}
|
|
6754
5672
|
}
|
|
6755
5673
|
};
|
|
6756
5674
|
return { handleServerRequest };
|
|
@@ -6759,7 +5677,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6759
5677
|
//#region extensions/codex/src/app-server/attempt-runtime-artifact.ts
|
|
6760
5678
|
async function verifyStartupArtifact(params) {
|
|
6761
5679
|
if (!params.request) return;
|
|
6762
|
-
const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-
|
|
5680
|
+
const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-C3jVimFn.js");
|
|
6763
5681
|
const runtimeArtifact = readCodexAppServerClientRuntimeArtifact(params.client);
|
|
6764
5682
|
const expected = params.request.expected;
|
|
6765
5683
|
const matchesExpected = !expected || runtimeArtifact?.id === expected.id && runtimeArtifact.fingerprint === expected.fingerprint;
|
|
@@ -7006,14 +5924,13 @@ async function startCodexAttemptThread(params) {
|
|
|
7006
5924
|
startupClientForAbandonedRequestCleanup = void 0;
|
|
7007
5925
|
},
|
|
7008
5926
|
operation: async () => {
|
|
7009
|
-
const threadConfig = mergeCodexThreadConfigs(params.
|
|
5927
|
+
const threadConfig = mergeCodexThreadConfigs(params.configuredMcpDynamicSurface ? void 0 : params.bundleMcpThreadConfig?.configPatch);
|
|
7010
5928
|
const { pluginThreadConfigRequired, pluginThreadConfigPluginConfig, resolvedPluginPolicy, enabledPluginConfigKeys } = resolveCodexPluginThreadConfigStartupPolicy({
|
|
7011
5929
|
pluginConfig: params.pluginConfig,
|
|
7012
5930
|
nativeToolSurfaceEnabled: params.nativeToolSurfaceEnabled,
|
|
7013
5931
|
scheduledRuntimeAuthority: params.buildAttemptParams().scheduledRuntimeAuthority
|
|
7014
5932
|
});
|
|
7015
|
-
|
|
7016
|
-
pluginAppServer = resolvedPluginPolicy?.enabled === true || computerUseMcpElicitationDelegationRequired ? {
|
|
5933
|
+
pluginAppServer = resolvedPluginPolicy?.enabled === true || params.computerUseConfig.enabled || params.nativeToolSurfaceEnabled && params.configuredMcpOwnershipVersion !== 1 && hasCodexMcpToolApprovalOverrides(params.config?.mcp?.servers, params.bundleMcpThreadConfig.userStaticServerNames, params.bundleMcpThreadConfig.configPatch?.mcp_servers) ? {
|
|
7017
5934
|
...params.appServer,
|
|
7018
5935
|
approvalPolicy: withMcpElicitationsApprovalPolicy(params.appServer.approvalPolicy)
|
|
7019
5936
|
} : params.appServer;
|
|
@@ -7205,9 +6122,9 @@ async function startCodexAttemptThread(params) {
|
|
|
7205
6122
|
nativeCodeModeEnabled: params.nativeToolSurfaceEnabled,
|
|
7206
6123
|
nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
|
|
7207
6124
|
nativeCodeModeOnlyEnabled: params.appServer.codeModeOnly,
|
|
7208
|
-
userMcpServersEnabled: params.
|
|
7209
|
-
mcpServersFingerprint: params.
|
|
7210
|
-
mcpServersFingerprintEvaluated: params.
|
|
6125
|
+
userMcpServersEnabled: params.configuredMcpDynamicSurface ? false : params.nativeToolSurfaceEnabled,
|
|
6126
|
+
mcpServersFingerprint: params.configuredMcpDynamicSurface ? void 0 : params.bundleMcpThreadConfig.fingerprint,
|
|
6127
|
+
mcpServersFingerprintEvaluated: params.configuredMcpDynamicSurface || params.bundleMcpThreadConfig.evaluated,
|
|
7211
6128
|
configuredMcpOwnershipVersion: params.configuredMcpOwnershipVersion,
|
|
7212
6129
|
environmentSelection: startupEnvironmentSelection,
|
|
7213
6130
|
appServerRuntimeFingerprint,
|
|
@@ -7286,10 +6203,7 @@ async function startCodexAttemptThread(params) {
|
|
|
7286
6203
|
if (startupAbandoned || params.signal.aborted) {
|
|
7287
6204
|
if (startupClientForAbandonedRequestCleanup === startupClient) startupClientForAbandonedRequestCleanup = void 0;
|
|
7288
6205
|
await closeCodexStartupClientBestEffort(startupClient);
|
|
7289
|
-
} else if (!isCodexAppServerStartSelectionChangedError(startupAttemptError) && (shouldClearSharedClientAfterStartupRace(startupAttemptError) || shouldClearSharedClientAfterStartupFailure({
|
|
7290
|
-
error: startupAttemptError,
|
|
7291
|
-
spawnedBy: params.spawnedBy
|
|
7292
|
-
}))) {
|
|
6206
|
+
} else if (!isCodexAppServerStartSelectionChangedError(startupAttemptError) && (shouldClearSharedClientAfterStartupRace(startupAttemptError) || shouldClearSharedClientAfterStartupFailure(startupAttemptError, params.spawnedBy))) {
|
|
7293
6207
|
if (startupClientForAbandonedRequestCleanup === startupClient) startupClientForAbandonedRequestCleanup = void 0;
|
|
7294
6208
|
await closeCodexStartupClientBestEffort(startupClient);
|
|
7295
6209
|
}
|
|
@@ -7333,15 +6247,12 @@ async function startCodexAttemptThread(params) {
|
|
|
7333
6247
|
releaseSharedClientLease
|
|
7334
6248
|
};
|
|
7335
6249
|
} catch (error) {
|
|
7336
|
-
if (params.signal.aborted ||
|
|
6250
|
+
if (params.signal.aborted || isCodexAppServerStartupError(error)) {
|
|
7337
6251
|
releaseSharedClientLease?.();
|
|
7338
6252
|
releaseSharedClientLease = void 0;
|
|
7339
6253
|
await closeCodexStartupClientBestEffort(startupClientForAbandonedRequestCleanup);
|
|
7340
6254
|
startupClientForAbandonedRequestCleanup = void 0;
|
|
7341
|
-
} else if (!isCodexAppServerStartSelectionChangedError(error) && (shouldClearSharedClientAfterStartupRace(error) || shouldClearSharedClientAfterStartupFailure({
|
|
7342
|
-
error,
|
|
7343
|
-
spawnedBy: params.spawnedBy
|
|
7344
|
-
}))) {
|
|
6255
|
+
} else if (!isCodexAppServerStartSelectionChangedError(error) && (shouldClearSharedClientAfterStartupRace(error) || shouldClearSharedClientAfterStartupFailure(error, params.spawnedBy))) {
|
|
7345
6256
|
releaseSharedClientLease?.();
|
|
7346
6257
|
releaseSharedClientLease = void 0;
|
|
7347
6258
|
await closeCodexStartupClientBestEffort(startupClientForAbandonedRequestCleanup);
|
|
@@ -7352,14 +6263,11 @@ async function startCodexAttemptThread(params) {
|
|
|
7352
6263
|
params.signal.removeEventListener("abort", abandonStartupAcquire);
|
|
7353
6264
|
}
|
|
7354
6265
|
}
|
|
7355
|
-
function shouldClearSharedClientAfterStartupAbandon(error) {
|
|
7356
|
-
return isCodexAppServerStartupError(error);
|
|
7357
|
-
}
|
|
7358
6266
|
function shouldClearSharedClientAfterStartupRace(error) {
|
|
7359
|
-
return
|
|
6267
|
+
return isCodexAppServerStartupError(error) || isCodexAppServerRequestTimeoutError(error);
|
|
7360
6268
|
}
|
|
7361
|
-
function shouldClearSharedClientAfterStartupFailure(
|
|
7362
|
-
return isCodexAppServerBrokenPipeError(
|
|
6269
|
+
function shouldClearSharedClientAfterStartupFailure(error, spawnedBy) {
|
|
6270
|
+
return !isCodexAppServerOverloadError(error) && !(error instanceof AgentHarnessPreflightError && error.scope === void 0) && (isCodexAppServerBrokenPipeError(error) || !spawnedBy);
|
|
7363
6271
|
}
|
|
7364
6272
|
//#endregion
|
|
7365
6273
|
//#region extensions/codex/src/app-server/run-attempt-start.ts
|
|
@@ -7369,7 +6277,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
7369
6277
|
const { runtime, attemptTools, promptState } = context;
|
|
7370
6278
|
const { connection, runtimeParams, preparedAuthBinding, buildActiveRunAttemptParams, startupAuthAccountCacheKey, startupEnvApiKeyCacheKey, bundleMcpThreadConfig, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, effectiveRuntimeModelId, sandboxExecServerEnabled } = runtime;
|
|
7371
6279
|
const { toolBridge, toolState } = attemptTools;
|
|
7372
|
-
const developerInstructions = joinPresentSections(turnState.promptBuild.developerInstructions, attemptTools.
|
|
6280
|
+
const developerInstructions = joinPresentSections(turnState.promptBuild.developerInstructions, attemptTools.configuredMcp?.diagnosticNotice);
|
|
7373
6281
|
const { params, attemptClientFactory, bindingStore, appServer, pluginConfig, computerUseConfig, startupClientAuthProfileId, runtimeArtifactRequest, startupPreparedAuth, agentDir, sessionAgentId, effectiveWorkspace, effectiveCwd, sandbox, runAbortController, usesSupervisionConnection, resolveReviewerPolicyContext, resolveRuntimeOptionsForCurrentBinding, startupAuthProfileId, startupAuthRequirement, abortFromUpstream } = connection;
|
|
7374
6282
|
let pluginAppServer = withCodexAppServerFastModeServiceTier(appServer, runtimeParams);
|
|
7375
6283
|
const loopDetectionEnabled = (sessionAgentId && params.config ? resolveAgentConfig$1(params.config, sessionAgentId)?.tools?.loopDetection?.enabled : void 0) ?? params.config?.tools?.loopDetection?.enabled ?? false;
|
|
@@ -7409,6 +6317,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
7409
6317
|
buildFinalConfigPatch: buildNativeHookRelayFinalConfigPatch,
|
|
7410
6318
|
nativeHookRelayRequired: connection.options.nativeHookRelay?.enabled !== false && params.pluginHarnessToolPolicyRestricted !== true && connection.nativeHookRelayEvents.includes("pre_tool_use") && (hasBeforeToolCallPolicy() || appServer.loopDetectionPreToolUseRelay && Boolean(connection.sandboxSessionKey) && loopDetectionEnabled),
|
|
7411
6319
|
bundleMcpThreadConfig,
|
|
6320
|
+
configuredMcpDynamicSurface: attemptTools.configuredMcp !== void 0,
|
|
7412
6321
|
configuredMcpOwnershipVersion: attemptTools.configuredMcpOwnershipVersion,
|
|
7413
6322
|
nativeToolSurfaceEnabled,
|
|
7414
6323
|
nativeProviderWebSearchSupport,
|
|
@@ -7445,11 +6354,12 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
7445
6354
|
if (usesSupervisionConnection && (state.thread.connectionScope !== "supervision" || state.thread.supervisionSourceThreadId !== connection.mutable.startupBinding?.supervisionSourceThreadId)) throw new Error("Codex supervised thread lost its private connection ownership");
|
|
7446
6355
|
if (state.thread.lifecycle.action === "started" || state.thread.lifecycle.action === "forked") {
|
|
7447
6356
|
const activePolicy = resolveReviewerPolicyContext(state.thread);
|
|
6357
|
+
const activeConfig = resolveRuntimeOptionsForCurrentBinding({
|
|
6358
|
+
modelProvider: activePolicy.modelProvider,
|
|
6359
|
+
model: activePolicy.model
|
|
6360
|
+
});
|
|
7448
6361
|
const activeAppServer = resolveCodexAppServerForModelProvider({
|
|
7449
|
-
appServer:
|
|
7450
|
-
modelProvider: activePolicy.modelProvider,
|
|
7451
|
-
model: activePolicy.model
|
|
7452
|
-
}),
|
|
6362
|
+
appServer: activeConfig,
|
|
7453
6363
|
provider: activePolicy.modelProvider,
|
|
7454
6364
|
model: activePolicy.model,
|
|
7455
6365
|
config: params.config,
|
|
@@ -7490,7 +6400,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
7490
6400
|
recordCodexTrajectoryContext(trajectoryRecorder, {
|
|
7491
6401
|
attempt: params,
|
|
7492
6402
|
cwd: effectiveCwd,
|
|
7493
|
-
developerInstructions: joinPresentSections(buildRenderedCodexDeveloperInstructions(), attemptTools.
|
|
6403
|
+
developerInstructions: joinPresentSections(buildRenderedCodexDeveloperInstructions(), attemptTools.configuredMcp?.diagnosticNotice),
|
|
7494
6404
|
prompt: turnState.codexTurnPromptText,
|
|
7495
6405
|
tools: toolBridge.availableSpecs
|
|
7496
6406
|
});
|
|
@@ -7504,7 +6414,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
7504
6414
|
await runCleanupStep("codex-start-failure-sandbox-release", releaseSandboxExecEnvironment);
|
|
7505
6415
|
await runCleanupStep("codex-start-failure-shared-client-release", releaseSharedClientLeaseAndRetireOneShotClient);
|
|
7506
6416
|
await runCleanupStep("codex-start-failure-abort-listener", () => params.abortSignal?.removeEventListener("abort", abortFromUpstream));
|
|
7507
|
-
throw state.executionDisconnectError ?? error;
|
|
6417
|
+
throw error instanceof CodexThreadPolicyHandoffError ? error : state.executionDisconnectError ?? error;
|
|
7508
6418
|
}
|
|
7509
6419
|
}
|
|
7510
6420
|
//#endregion
|
|
@@ -7513,8 +6423,8 @@ function isAuthorityResolutionOperationAbort(error, signal) {
|
|
|
7513
6423
|
return signal?.aborted === true && error === signal.reason;
|
|
7514
6424
|
}
|
|
7515
6425
|
async function prepareCodexAttemptTools(runtime) {
|
|
7516
|
-
const { connection, bundleMcpThreadConfig, bundleManifestRegistry, runtimeParams, effectiveRuntimeModelId, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, hookChannelId, codexMcpToolOverrides, authenticatedScheduledMode,
|
|
7517
|
-
const { params, preDynamicStartupStages, mutable, startupAuthProfileId, resolvedWorkspace, effectiveWorkspace, effectiveCwd, sandboxSessionKey, sandbox, sessionPermissionPolicy, runAbortController, sessionAgentId, pluginConfig, profilerEnabled, agentDir } = connection;
|
|
6426
|
+
const { connection, bundleMcpThreadConfig, bundleManifestRegistry, runtimeParams, effectiveRuntimeModelId, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, hookChannelId, codexMcpToolOverrides, authenticatedScheduledMode, configuredMcpSurface, canResolveScheduledConfiguredMcpCreatorAuthority } = runtime;
|
|
6427
|
+
const { params, preDynamicStartupStages, mutable, startupAuthProfileId, resolvedWorkspace, effectiveWorkspace, effectiveCwd, sandboxSessionKey, contextSessionKey, sandbox, sessionPermissionPolicy, runAbortController, sessionAgentId, policyAgentId, pluginConfig, profilerEnabled, agentDir } = connection;
|
|
7518
6428
|
const preDynamicSummary = preDynamicStartupStages.snapshot();
|
|
7519
6429
|
if (shouldWarnCodexDynamicToolBuildStageSummary(preDynamicSummary)) embeddedAgentLog.warn(`codex app-server pre-dynamic startup timings runId=${params.runId} sessionId=${params.sessionId} totalMs=${preDynamicSummary.totalMs} stages=${formatCodexDynamicToolBuildStageSummary(preDynamicSummary)}`, {
|
|
7520
6430
|
runId: params.runId,
|
|
@@ -7557,20 +6467,29 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7557
6467
|
...onCodexToolOutcome ? { onToolOutcome: onCodexToolOutcome } : {}
|
|
7558
6468
|
};
|
|
7559
6469
|
const computerContextEpoch = { value: 0 };
|
|
6470
|
+
const runCleanups = [];
|
|
7560
6471
|
const cronCreatorToolAllowlist = [];
|
|
7561
6472
|
const cronCreatorToolAllowlistCaptureRef = {};
|
|
7562
6473
|
const scheduledAppAuthoritySourceRef = {};
|
|
7563
6474
|
const preparedChatgptAuth = connection.startupPreparedAuth?.kind === "profile" && connection.startupPreparedAuth.snapshot?.loginParams.type === "chatgptAuthTokens" && connection.startupPreparedAuth.snapshot.chatgptAccountId ? {
|
|
6475
|
+
kind: "prepared-profile",
|
|
7564
6476
|
profileId: connection.startupPreparedAuth.profileId,
|
|
7565
6477
|
accountId: connection.startupPreparedAuth.snapshot.chatgptAccountId
|
|
7566
6478
|
} : void 0;
|
|
6479
|
+
const configuredAppServerAuth = !preparedChatgptAuth && connection.appServer.start.transport !== "stdio" ? {
|
|
6480
|
+
kind: "configured-app-server",
|
|
6481
|
+
connectionFingerprint: buildScheduledCodexAppServerConnectionIdentity(connection.appServer)
|
|
6482
|
+
} : void 0;
|
|
6483
|
+
const scheduledCodexAppAuth = preparedChatgptAuth ?? configuredAppServerAuth;
|
|
7567
6484
|
const appPolicy = resolveCodexPluginsPolicy(pluginConfig);
|
|
6485
|
+
const codexAppsMayBeVisible = appPolicy.enabled && (appPolicy.allowAllPlugins || appPolicy.pluginPolicies.some((entry) => entry.enabled));
|
|
7568
6486
|
const appCreatorCapture = resolveScheduledCodexAppCreatorCaptureDecision({
|
|
7569
|
-
appsMayBeVisible:
|
|
6487
|
+
appsMayBeVisible: codexAppsMayBeVisible,
|
|
7570
6488
|
authenticatedScheduledMode,
|
|
7571
6489
|
usesSupervisionConnection: connection.usesSupervisionConnection,
|
|
7572
6490
|
homeScope: connection.appServer.start.homeScope,
|
|
7573
|
-
hasPreparedAccountIdentity: Boolean(preparedChatgptAuth)
|
|
6491
|
+
hasPreparedAccountIdentity: Boolean(preparedChatgptAuth),
|
|
6492
|
+
hasConfiguredAppServerIdentity: Boolean(configuredAppServerAuth)
|
|
7574
6493
|
});
|
|
7575
6494
|
const codexAppAuthorityUnavailableReason = appCreatorCapture.unavailableReason;
|
|
7576
6495
|
const canResolveScheduledCodexAppAuthority = appCreatorCapture.supported;
|
|
@@ -7581,6 +6500,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7581
6500
|
let resolveCreatorAuthorityImpl;
|
|
7582
6501
|
const runtimeYieldCompletionClaim = {};
|
|
7583
6502
|
const commonToolParams = {
|
|
6503
|
+
nodeExecAvailability: {},
|
|
7584
6504
|
params: dynamicToolParams,
|
|
7585
6505
|
resolvedWorkspace,
|
|
7586
6506
|
effectiveWorkspace,
|
|
@@ -7592,6 +6512,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7592
6512
|
nativeProviderWebSearchSupport,
|
|
7593
6513
|
runAbortController,
|
|
7594
6514
|
sessionAgentId,
|
|
6515
|
+
policyAgentId,
|
|
7595
6516
|
pluginConfig,
|
|
7596
6517
|
profilerEnabled,
|
|
7597
6518
|
...params.cronCreatorAuthorityUnavailableReason === "queued-local-operator" && bundleMcpThreadConfig.staticServerNames.length > 0 ? { cronCreatorAuthorityUnavailableReason: "queued-local-operator-configured-mcp" } : {},
|
|
@@ -7616,8 +6537,35 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7616
6537
|
return pending;
|
|
7617
6538
|
} } : {}
|
|
7618
6539
|
};
|
|
6540
|
+
let nativeSpecs;
|
|
6541
|
+
if (hasCodexNativeToolCatalog(mutable.startupBinding)) {
|
|
6542
|
+
runAbortController.signal.throwIfAborted();
|
|
6543
|
+
params.hostCapabilities.assertActive();
|
|
6544
|
+
const client = await connection.attemptClientFactory({
|
|
6545
|
+
startOptions: connection.appServer.start,
|
|
6546
|
+
authProfileId: connection.startupClientAuthProfileId,
|
|
6547
|
+
agentDir,
|
|
6548
|
+
config: params.config,
|
|
6549
|
+
timeoutMs: connection.appServer.requestTimeoutMs
|
|
6550
|
+
});
|
|
6551
|
+
try {
|
|
6552
|
+
nativeSpecs = await loadCodexNativeToolCatalog({
|
|
6553
|
+
client,
|
|
6554
|
+
binding: mutable.startupBinding,
|
|
6555
|
+
appServer: connection.appServer,
|
|
6556
|
+
agentDir,
|
|
6557
|
+
assertCurrent: () => {
|
|
6558
|
+
runAbortController.signal.throwIfAborted();
|
|
6559
|
+
params.hostCapabilities.assertActive();
|
|
6560
|
+
}
|
|
6561
|
+
});
|
|
6562
|
+
} finally {
|
|
6563
|
+
releaseLeasedSharedCodexAppServerClient(client);
|
|
6564
|
+
}
|
|
6565
|
+
}
|
|
7619
6566
|
const tools = await buildDynamicTools({
|
|
7620
6567
|
...commonToolParams,
|
|
6568
|
+
registerRunCleanup: (cleanup) => runCleanups.push(cleanup),
|
|
7621
6569
|
cronCreatorToolAllowlistRef: cronCreatorToolAllowlist,
|
|
7622
6570
|
cronCreatorToolAllowlistCaptureRef,
|
|
7623
6571
|
onPersistentWebSearchPolicyResolved: (allowed) => {
|
|
@@ -7627,7 +6575,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7627
6575
|
toolState.webSearchAllowed = allowed;
|
|
7628
6576
|
}
|
|
7629
6577
|
});
|
|
7630
|
-
const registeredTools = await buildDynamicTools({
|
|
6578
|
+
const registeredTools = nativeSpecs ? [] : await buildDynamicTools({
|
|
7631
6579
|
...commonToolParams,
|
|
7632
6580
|
forceHeartbeatTool: true,
|
|
7633
6581
|
ignoreDisableMessageTool: true,
|
|
@@ -7639,7 +6587,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7639
6587
|
runSessionKey: params.sessionKey && params.sessionKey !== sandboxSessionKey ? params.sessionKey : void 0,
|
|
7640
6588
|
sessionId: params.sessionId,
|
|
7641
6589
|
runId: params.runId,
|
|
7642
|
-
agentId:
|
|
6590
|
+
agentId: policyAgentId,
|
|
7643
6591
|
agentDir: agentDir ?? resolveAgentDir(params.config ?? {}, sessionAgentId),
|
|
7644
6592
|
agentAccountId: params.agentAccountId,
|
|
7645
6593
|
messageProvider: params.messageProvider ?? params.messageChannel,
|
|
@@ -7685,9 +6633,10 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7685
6633
|
...params.memberRoleIds?.length ? { roleIds: [...params.memberRoleIds] } : {}
|
|
7686
6634
|
};
|
|
7687
6635
|
const hasRequester = Object.keys(requester).length > 0;
|
|
7688
|
-
const
|
|
6636
|
+
const configuredMcp = configuredMcpSurface ? await materializeStaticMcpToolsForHarnessRun({
|
|
7689
6637
|
sessionId: params.sessionId,
|
|
7690
6638
|
sessionKey: params.sessionKey,
|
|
6639
|
+
agentId: sessionAgentId,
|
|
7691
6640
|
workspaceDir: effectiveWorkspace,
|
|
7692
6641
|
agentDir: policyContext.agentDir,
|
|
7693
6642
|
cfg: params.config,
|
|
@@ -7696,6 +6645,29 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7696
6645
|
toolsAllow: params.toolsAllow,
|
|
7697
6646
|
toolOverrides: codexMcpToolOverrides,
|
|
7698
6647
|
autoApproveCodexAppServerApprovals: shouldAutoApproveCodexAppServerApprovals(connection.appServer),
|
|
6648
|
+
projectedMcpServers: bundleMcpThreadConfig.configPatch?.mcp_servers,
|
|
6649
|
+
...configuredMcpSurface === "transient" ? { requestInteractiveCodexApproval: async (approval) => {
|
|
6650
|
+
const allowedDecisions = approval.mode === "prompt" ? ["allow-once", "deny"] : [
|
|
6651
|
+
"allow-once",
|
|
6652
|
+
"allow-always",
|
|
6653
|
+
"deny"
|
|
6654
|
+
];
|
|
6655
|
+
const outcome = await requestPluginApprovalOutcome({
|
|
6656
|
+
hostCapabilities: params.hostCapabilities,
|
|
6657
|
+
signal: approval.signal,
|
|
6658
|
+
title: `Run MCP tool ${approval.serverName}/${approval.toolName}`,
|
|
6659
|
+
description: `Codex approval mode "${approval.mode}" requires an operator decision before this MCP tool runs. ${formatMcpCodexApprovalRemedy(approval.serverName)}`,
|
|
6660
|
+
allowedDecisions,
|
|
6661
|
+
toolName: approval.safeToolName,
|
|
6662
|
+
toolCallId: approval.toolCallId,
|
|
6663
|
+
mcpTool: {
|
|
6664
|
+
server: approval.serverName,
|
|
6665
|
+
tool: approval.toolName
|
|
6666
|
+
},
|
|
6667
|
+
isMcpToolApprovalActive: approval.isActive
|
|
6668
|
+
});
|
|
6669
|
+
if (outcome !== "approved-once" && outcome !== "approved-session") throw new Error(`${approval.serverName}/${approval.toolName}: interactive Codex approval (${approval.mode}) was not granted: ${outcome}`);
|
|
6670
|
+
} } : {},
|
|
7699
6671
|
policyContext,
|
|
7700
6672
|
warn: (message) => embeddedAgentLog.warn(message)
|
|
7701
6673
|
}) : void 0;
|
|
@@ -7712,13 +6684,13 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7712
6684
|
requesterSenderId: params.senderId,
|
|
7713
6685
|
agentAccountId: params.agentAccountId,
|
|
7714
6686
|
messageChannel: params.messageChannel ?? params.messageProvider,
|
|
7715
|
-
reservedToolNames,
|
|
6687
|
+
reservedToolNames: [...reservedToolNames, ...configuredMcp?.tools.map((tool) => tool.name) ?? []],
|
|
7716
6688
|
toolsAllow: params.toolsAllow,
|
|
7717
6689
|
policyContext,
|
|
7718
6690
|
warn: (message) => embeddedAgentLog.warn(message)
|
|
7719
6691
|
});
|
|
7720
|
-
const scopedExecutable = filterCodexDynamicTools(
|
|
7721
|
-
const scopedAdvertised = filterCodexDynamicTools(
|
|
6692
|
+
const scopedExecutable = filterCodexDynamicTools([...configuredMcp?.tools ?? [], ...scopedMcpTools?.tools ?? []], pluginConfig);
|
|
6693
|
+
const scopedAdvertised = filterCodexDynamicTools([...configuredMcp?.tools ?? [], ...scopedMcpTools?.advertisedTools ?? []], pluginConfig);
|
|
7722
6694
|
const toolsWithScopedMcp = scopedExecutable.length > 0 ? [...tools, ...scopedExecutable] : tools;
|
|
7723
6695
|
const registeredWithScopedMcp = scopedAdvertised.length > 0 ? [...registeredTools, ...scopedAdvertised] : registeredTools;
|
|
7724
6696
|
const hookContext = {
|
|
@@ -7729,7 +6701,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7729
6701
|
remoteWorkspaceRoot: connection.appServer.remoteWorkspaceRoot,
|
|
7730
6702
|
remoteWorkspaceRequestTimeoutMs: connection.appServer.requestTimeoutMs,
|
|
7731
6703
|
sessionId: params.sessionId,
|
|
7732
|
-
sessionKey:
|
|
6704
|
+
sessionKey: contextSessionKey,
|
|
7733
6705
|
runId: params.runId,
|
|
7734
6706
|
channelId: hookChannelId,
|
|
7735
6707
|
currentChannelProvider: resolveCodexMessageToolProvider(params),
|
|
@@ -7753,6 +6725,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7753
6725
|
toolBridge = createCodexDynamicToolBridge({
|
|
7754
6726
|
tools: toolsWithScopedMcp,
|
|
7755
6727
|
registeredTools: registeredWithScopedMcp,
|
|
6728
|
+
registeredSpecs: nativeSpecs,
|
|
7756
6729
|
signal: runAbortController.signal,
|
|
7757
6730
|
computerContextEpoch,
|
|
7758
6731
|
loading: resolveCodexDynamicToolsLoadingForRuntime(pluginConfig, effectiveRuntimeModelId, { connectionClass: connection.appServer.connectionClass }),
|
|
@@ -7771,9 +6744,9 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7771
6744
|
await captureFinalCodexCronCreatorToolAllowlist(authorityTools, captureRef, toolBridge.availableTools);
|
|
7772
6745
|
if (!captureRef.value) throw new Error("cron creator authority snapshot did not produce provenance");
|
|
7773
6746
|
const appSource = scheduledAppAuthoritySourceRef.current;
|
|
7774
|
-
const runtimeAuthority = canResolveScheduledCodexAppAuthority &&
|
|
6747
|
+
const runtimeAuthority = canResolveScheduledCodexAppAuthority && scheduledCodexAppAuth ? appSource ? await captureScheduledCodexAppAuthority({
|
|
7775
6748
|
...appSource,
|
|
7776
|
-
|
|
6749
|
+
auth: scheduledCodexAppAuth,
|
|
7777
6750
|
signal: options?.signal
|
|
7778
6751
|
}) : (() => {
|
|
7779
6752
|
throw new Error("Codex app authority is unavailable before the exact creator thread is active. Retry this automation mutation from the current owner turn.");
|
|
@@ -7789,8 +6762,9 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7789
6762
|
const authorityRuntimeId = `cron-authority:${params.runId}`;
|
|
7790
6763
|
let materialized;
|
|
7791
6764
|
try {
|
|
7792
|
-
materialized = await
|
|
6765
|
+
materialized = await materializeStaticMcpToolsForHarnessRun({
|
|
7793
6766
|
sessionId: authorityRuntimeId,
|
|
6767
|
+
agentId: sessionAgentId,
|
|
7794
6768
|
workspaceDir: effectiveWorkspace,
|
|
7795
6769
|
agentDir: policyContext.agentDir,
|
|
7796
6770
|
cfg: params.config,
|
|
@@ -7799,6 +6773,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7799
6773
|
toolsAllow: params.toolsAllow,
|
|
7800
6774
|
toolOverrides: codexMcpToolOverrides,
|
|
7801
6775
|
autoApproveCodexAppServerApprovals: shouldAutoApproveCodexAppServerApprovals(connection.appServer),
|
|
6776
|
+
projectedMcpServers: bundleMcpThreadConfig.configPatch?.mcp_servers,
|
|
7802
6777
|
policyContext,
|
|
7803
6778
|
warn: (message) => embeddedAgentLog.warn(message),
|
|
7804
6779
|
retireSessionRuntimeAfterDispose: true
|
|
@@ -7830,14 +6805,15 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7830
6805
|
tools: toolsWithScopedMcp,
|
|
7831
6806
|
registeredTools: registeredWithScopedMcp,
|
|
7832
6807
|
scopedMcpTools,
|
|
7833
|
-
|
|
7834
|
-
configuredMcpOwnershipVersion:
|
|
6808
|
+
configuredMcp,
|
|
6809
|
+
configuredMcpOwnershipVersion: configuredMcpSurface === "scheduled" ? 1 : void 0,
|
|
7835
6810
|
cronCreatorToolAllowlist,
|
|
7836
6811
|
cronCreatorToolAllowlistCaptureRef,
|
|
7837
6812
|
scheduledAppAuthoritySourceRef,
|
|
7838
6813
|
dynamicToolParams,
|
|
7839
6814
|
compactionPlanState,
|
|
7840
6815
|
computerContextEpoch,
|
|
6816
|
+
runCleanups,
|
|
7841
6817
|
toolBridge,
|
|
7842
6818
|
toolState,
|
|
7843
6819
|
toolOutcomeOrdinals,
|
|
@@ -7848,7 +6824,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7848
6824
|
};
|
|
7849
6825
|
} catch (error) {
|
|
7850
6826
|
await scopedMcpTools?.dispose();
|
|
7851
|
-
await
|
|
6827
|
+
await configuredMcp?.dispose();
|
|
7852
6828
|
throw error;
|
|
7853
6829
|
}
|
|
7854
6830
|
}
|
|
@@ -7888,7 +6864,7 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
|
|
|
7888
6864
|
const { context, turnState, buildRenderedCodexDeveloperInstructions } = prompt;
|
|
7889
6865
|
const { runtime, attemptTools, hookContextWindowFields, workspaceBootstrapContext } = context;
|
|
7890
6866
|
const { connection, runtimeParams, effectiveRuntimeProviderId, effectiveRuntimeModelId } = runtime;
|
|
7891
|
-
const { tools } = attemptTools;
|
|
6867
|
+
const { tools, toolBridge } = attemptTools;
|
|
7892
6868
|
const { params, usesSupervisionConnection, codexModelCallId, codexModelCallTrace, codexModelContentCapture, appServer, runAbortController } = connection;
|
|
7893
6869
|
const { state } = turnRuntime;
|
|
7894
6870
|
const explicitSkillInputs = await resolveCodexExplicitSkillInputs({
|
|
@@ -7951,7 +6927,8 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
|
|
|
7951
6927
|
turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
|
|
7952
6928
|
skillsCollaborationInstructions: context.skillsCollaborationInstructions,
|
|
7953
6929
|
memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
|
|
7954
|
-
preserveNativeTurnSettings: usesSupervisionConnection
|
|
6930
|
+
preserveNativeTurnSettings: usesSupervisionConnection,
|
|
6931
|
+
sessionStatusAvailable: toolBridge.availableTools.some((tool) => tool.name === "session_status")
|
|
7955
6932
|
});
|
|
7956
6933
|
codexModelCallDiagnostics.setRequestPayloadBytes(utf8JsonByteLength(turnStartParams));
|
|
7957
6934
|
state.latestStartupErrorNotification = void 0;
|
|
@@ -8135,7 +7112,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
8135
7112
|
trajectoryRecorder?.recordEvent("session.ended", {
|
|
8136
7113
|
status: "error",
|
|
8137
7114
|
threadId: resourceState.thread.threadId,
|
|
8138
|
-
timedOut: state.
|
|
7115
|
+
timedOut: state.timeout !== void 0,
|
|
8139
7116
|
aborted: runAbortController.signal.aborted,
|
|
8140
7117
|
promptError: message
|
|
8141
7118
|
});
|
|
@@ -8156,8 +7133,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
8156
7133
|
});
|
|
8157
7134
|
const failureKind = classifyCodexModelCallFailureKind({
|
|
8158
7135
|
error: turnStartError,
|
|
8159
|
-
timedOut: state.
|
|
8160
|
-
turnCompletionIdleTimedOut: state.turnCompletionIdleTimedOut,
|
|
7136
|
+
timedOut: state.timeout !== void 0,
|
|
8161
7137
|
runAborted: runAbortController.signal.aborted,
|
|
8162
7138
|
abortReason: runAbortController.signal.reason,
|
|
8163
7139
|
clientClosedAbort: state.clientClosedAbort,
|
|
@@ -8178,11 +7154,10 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
8178
7154
|
ctx: hookContext,
|
|
8179
7155
|
hookRunner
|
|
8180
7156
|
});
|
|
8181
|
-
|
|
7157
|
+
if ((isIncognitoSessionKey(params.sessionKey) ? await bindingStore.mutate(bindingIdentity, {
|
|
8182
7158
|
kind: "clear",
|
|
8183
7159
|
threadId: resourceState.thread.threadId
|
|
8184
|
-
}) : true
|
|
8185
|
-
if (!state.timedOut && bindingReleased && !resourceState.startupClientUnsafe) {
|
|
7160
|
+
}) : true) && !resourceState.startupClientUnsafe) {
|
|
8186
7161
|
if (!await unsubscribeCodexThreadBestEffort(resourceState.client, {
|
|
8187
7162
|
threadId: resourceState.thread.threadId,
|
|
8188
7163
|
timeoutMs: 5e3
|
|
@@ -8255,268 +7230,56 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
8255
7230
|
return { turn };
|
|
8256
7231
|
}
|
|
8257
7232
|
//#endregion
|
|
8258
|
-
//#region extensions/codex/src/app-server/attempt-
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
|
|
8263
|
-
|
|
8264
|
-
|
|
8265
|
-
|
|
8266
|
-
|
|
8267
|
-
|
|
8268
|
-
|
|
8269
|
-
let completionIdleWatchArmed = false;
|
|
8270
|
-
let completionIdleWatchPinnedByTerminalError = false;
|
|
8271
|
-
let completionIdleTimeoutOverrideMs;
|
|
8272
|
-
let assistantCompletionIdleWatchArmed = false;
|
|
8273
|
-
let assistantCompletionLastActivityAt = Date.now();
|
|
8274
|
-
let assistantCompletionLastActivityDetails;
|
|
8275
|
-
let attemptIdleWatchArmed = false;
|
|
8276
|
-
let terminalIdleWatchArmed = false;
|
|
8277
|
-
let completionLastActivityAt = Date.now();
|
|
8278
|
-
let completionLastActivityReason = "startup";
|
|
8279
|
-
let completionLastActivityDetails;
|
|
8280
|
-
let attemptIdleTimeoutOverrideMs;
|
|
8281
|
-
let attemptLastProgressAt = Date.now();
|
|
8282
|
-
let attemptLastProgressReason = "startup";
|
|
8283
|
-
let attemptLastProgressDetails;
|
|
8284
|
-
const turnCompletionIdleTimeoutMs = resolveTimerTimeoutMs(params.turnCompletionIdleTimeoutMs, 1);
|
|
8285
|
-
const turnAssistantCompletionIdleTimeoutMs = resolveTimerTimeoutMs(params.turnAssistantCompletionIdleTimeoutMs, 1);
|
|
8286
|
-
const turnAttemptIdleTimeoutMs = resolveTimerTimeoutMs(params.turnAttemptIdleTimeoutMs, 1);
|
|
8287
|
-
const turnTerminalIdleTimeoutMs = resolveTimerTimeoutMs(params.turnTerminalIdleTimeoutMs, 1);
|
|
8288
|
-
const interruptTimeoutMs = resolveTimerTimeoutMs(params.interruptTimeoutMs, 1);
|
|
8289
|
-
const resolveWatchTimeoutMs = (timeoutMs) => resolveTimerTimeoutMs(timeoutMs, 1);
|
|
8290
|
-
const clearTimer = (kind) => {
|
|
8291
|
-
const timer = timers[kind];
|
|
8292
|
-
if (timer) {
|
|
8293
|
-
clearTimeout(timer);
|
|
8294
|
-
delete timers[kind];
|
|
8295
|
-
}
|
|
8296
|
-
};
|
|
8297
|
-
const clearCompletionIdleTimer = () => clearTimer("completion");
|
|
8298
|
-
const clearAllTimers = () => {
|
|
8299
|
-
for (const kind of Object.keys(timers)) clearTimer(kind);
|
|
8300
|
-
};
|
|
8301
|
-
function scheduleWatch(kind, callback, lastActivityAt, timeoutMs, ready) {
|
|
8302
|
-
clearTimer(kind);
|
|
8303
|
-
if (!ready || params.isCompleted() || params.signal.aborted) return;
|
|
8304
|
-
const elapsedMs = Math.max(0, Date.now() - lastActivityAt);
|
|
8305
|
-
const timer = setTimeout(callback, Math.max(1, timeoutMs - elapsedMs));
|
|
8306
|
-
timer.unref?.();
|
|
8307
|
-
timers[kind] = timer;
|
|
8308
|
-
}
|
|
8309
|
-
function scheduleCompletionIdleWatch() {
|
|
8310
|
-
scheduleWatch("completion", fireCompletionIdleTimeout, completionLastActivityAt, completionIdleTimeoutOverrideMs ?? turnCompletionIdleTimeoutMs, completionIdleWatchArmed && params.getActiveAppServerTurnRequests() === 0 && params.getActiveCompletionBlockerItemCount() === 0);
|
|
8311
|
-
}
|
|
8312
|
-
function scheduleAssistantCompletionIdleWatch() {
|
|
8313
|
-
scheduleWatch("assistant", fireAssistantCompletionIdleRelease, assistantCompletionLastActivityAt, turnAssistantCompletionIdleTimeoutMs, assistantCompletionIdleWatchArmed && params.getActiveFinalizationHookCount() === 0);
|
|
8314
|
-
}
|
|
8315
|
-
function shouldPauseAttemptIdleWatch() {
|
|
8316
|
-
if (params.getActiveAppServerTurnRequestsWithoutTimeout() > 0) return false;
|
|
8317
|
-
return params.getActiveCompletionBlockerItemCount() > 0 || params.getActiveAppServerTurnRequests() > 0;
|
|
8318
|
-
}
|
|
8319
|
-
function scheduleAttemptIdleWatch() {
|
|
8320
|
-
scheduleWatch("attempt", fireAttemptIdleTimeout, attemptLastProgressAt, attemptIdleTimeoutOverrideMs ?? turnAttemptIdleTimeoutMs, attemptIdleWatchArmed && !shouldPauseAttemptIdleWatch());
|
|
8321
|
-
}
|
|
8322
|
-
function scheduleTerminalIdleWatch() {
|
|
8323
|
-
scheduleWatch("terminal", fireTerminalIdleTimeout, completionLastActivityAt, turnTerminalIdleTimeoutMs, terminalIdleWatchArmed && params.getActiveAppServerTurnRequests() === 0);
|
|
8324
|
-
}
|
|
8325
|
-
function scheduleProgressWatches() {
|
|
8326
|
-
scheduleAttemptIdleWatch();
|
|
8327
|
-
scheduleCompletionIdleWatch();
|
|
8328
|
-
scheduleTerminalIdleWatch();
|
|
8329
|
-
}
|
|
8330
|
-
function isCompletionIdleTimeoutDueBeforeAttempt(timeoutMs) {
|
|
8331
|
-
if (params.isCompleted() || params.isTerminalTurnNotificationQueued() || params.signal.aborted || !completionIdleWatchArmed || params.getActiveAppServerTurnRequests() > 0 || params.getActiveCompletionBlockerItemCount() > 0) return false;
|
|
8332
|
-
const completionTimeoutMs = completionIdleTimeoutOverrideMs ?? turnCompletionIdleTimeoutMs;
|
|
8333
|
-
if (completionTimeoutMs > timeoutMs) return false;
|
|
8334
|
-
return Math.max(0, Date.now() - completionLastActivityAt) >= completionTimeoutMs;
|
|
8335
|
-
}
|
|
8336
|
-
function recordAttemptProgress(reason, options) {
|
|
8337
|
-
attemptIdleTimeoutOverrideMs = options?.attemptTimeoutMs !== void 0 ? resolveWatchTimeoutMs(options.attemptTimeoutMs) : void 0;
|
|
8338
|
-
attemptLastProgressAt = completionLastActivityAt;
|
|
8339
|
-
attemptLastProgressReason = reason;
|
|
8340
|
-
attemptLastProgressDetails = options?.details;
|
|
8341
|
-
params.onAttemptProgress(reason, options?.details);
|
|
8342
|
-
scheduleAttemptIdleWatch();
|
|
8343
|
-
}
|
|
8344
|
-
function fireAssistantCompletionIdleRelease() {
|
|
8345
|
-
if (params.isCompleted() || params.signal.aborted || !assistantCompletionIdleWatchArmed) return;
|
|
8346
|
-
if (params.getActiveAppServerTurnRequests() > 0 || params.getActiveTurnItemCount() > 0 || params.getActiveFinalizationHookCount() > 0) {
|
|
8347
|
-
scheduleAssistantCompletionIdleWatch();
|
|
8348
|
-
return;
|
|
8349
|
-
}
|
|
8350
|
-
if (!params.canReleaseAssistantCompletionIdle()) {
|
|
8351
|
-
assistantCompletionIdleWatchArmed = false;
|
|
8352
|
-
assistantCompletionLastActivityDetails = void 0;
|
|
8353
|
-
clearTimer("assistant");
|
|
8354
|
-
return;
|
|
8355
|
-
}
|
|
8356
|
-
const idleMs = Math.max(0, Date.now() - assistantCompletionLastActivityAt);
|
|
8357
|
-
if (idleMs < turnAssistantCompletionIdleTimeoutMs) {
|
|
8358
|
-
scheduleAssistantCompletionIdleWatch();
|
|
8359
|
-
return;
|
|
8360
|
-
}
|
|
8361
|
-
assistantCompletionIdleWatchArmed = false;
|
|
8362
|
-
clearCompletionIdleTimer();
|
|
8363
|
-
clearTimer("terminal");
|
|
8364
|
-
const turnId = params.getTurnId();
|
|
8365
|
-
const fields = {
|
|
8366
|
-
threadId: params.threadId,
|
|
8367
|
-
turnId,
|
|
8368
|
-
idleMs,
|
|
8369
|
-
timeoutMs: turnAssistantCompletionIdleTimeoutMs,
|
|
8370
|
-
...assistantCompletionLastActivityDetails
|
|
8371
|
-
};
|
|
8372
|
-
params.onRecordEvent("turn.assistant_completion_idle_release", fields);
|
|
8373
|
-
embeddedAgentLog.warn("codex app-server turn released after completed assistant item without terminal event", fields);
|
|
8374
|
-
if (turnId) {
|
|
8375
|
-
params.onInterruptTurn({
|
|
8376
|
-
threadId: params.threadId,
|
|
8377
|
-
turnId,
|
|
8378
|
-
timeoutMs: interruptTimeoutMs
|
|
8379
|
-
}).finally(params.onCompleted);
|
|
8380
|
-
return;
|
|
8381
|
-
}
|
|
8382
|
-
params.onCompleted();
|
|
8383
|
-
}
|
|
8384
|
-
function reportTimeout(timeout) {
|
|
8385
|
-
params.onTimeout(timeout);
|
|
8386
|
-
const fields = {
|
|
8387
|
-
threadId: params.threadId,
|
|
8388
|
-
turnId: params.getTurnId(),
|
|
8389
|
-
idleMs: timeout.idleMs,
|
|
8390
|
-
timeoutMs: timeout.timeoutMs,
|
|
8391
|
-
lastActivityReason: timeout.lastActivityReason,
|
|
8392
|
-
...timeout.details
|
|
8393
|
-
};
|
|
8394
|
-
params.onRecordEvent(`turn.${timeout.kind}_idle_timeout`, fields);
|
|
8395
|
-
embeddedAgentLog.warn(`codex app-server turn idle timed out waiting for ${timeout.kind === "terminal" ? "terminal event" : timeout.kind}`, fields);
|
|
8396
|
-
params.onAbort(`turn_${timeout.kind}_idle_timeout`);
|
|
8397
|
-
}
|
|
8398
|
-
function fireAttemptIdleTimeout() {
|
|
8399
|
-
if (params.isCompleted() || params.signal.aborted || !attemptIdleWatchArmed || shouldPauseAttemptIdleWatch()) return;
|
|
8400
|
-
const idleMs = Math.max(0, Date.now() - attemptLastProgressAt);
|
|
8401
|
-
const timeoutMs = attemptIdleTimeoutOverrideMs ?? turnAttemptIdleTimeoutMs;
|
|
8402
|
-
if (idleMs < timeoutMs) {
|
|
8403
|
-
scheduleAttemptIdleWatch();
|
|
8404
|
-
return;
|
|
8405
|
-
}
|
|
8406
|
-
if (isCompletionIdleTimeoutDueBeforeAttempt(timeoutMs)) {
|
|
8407
|
-
fireCompletionIdleTimeout();
|
|
8408
|
-
return;
|
|
8409
|
-
}
|
|
8410
|
-
reportTimeout({
|
|
8411
|
-
kind: "progress",
|
|
8412
|
-
idleMs,
|
|
8413
|
-
timeoutMs,
|
|
8414
|
-
lastActivityReason: attemptLastProgressReason,
|
|
8415
|
-
details: attemptLastProgressDetails
|
|
8416
|
-
});
|
|
8417
|
-
}
|
|
8418
|
-
function fireCompletionIdleTimeout() {
|
|
8419
|
-
if (params.isCompleted() || params.isTerminalTurnNotificationQueued() || params.signal.aborted || !completionIdleWatchArmed || params.getActiveAppServerTurnRequests() > 0 || params.getActiveCompletionBlockerItemCount() > 0) return;
|
|
8420
|
-
const timeoutMs = completionIdleTimeoutOverrideMs ?? turnCompletionIdleTimeoutMs;
|
|
8421
|
-
const idleMs = Math.max(0, Date.now() - completionLastActivityAt);
|
|
8422
|
-
if (idleMs < timeoutMs) {
|
|
8423
|
-
scheduleCompletionIdleWatch();
|
|
8424
|
-
return;
|
|
8425
|
-
}
|
|
8426
|
-
const details = {
|
|
8427
|
-
...completionLastActivityDetails,
|
|
8428
|
-
activeAppServerTurnRequests: params.getActiveAppServerTurnRequests(),
|
|
8429
|
-
activeTurnItemCount: params.getActiveTurnItemCount(),
|
|
8430
|
-
terminalTurnNotificationQueued: params.isTerminalTurnNotificationQueued(),
|
|
8431
|
-
completionIdleWatchArmed,
|
|
8432
|
-
assistantCompletionIdleWatchArmed,
|
|
8433
|
-
terminalIdleWatchArmed
|
|
8434
|
-
};
|
|
8435
|
-
reportTimeout({
|
|
8436
|
-
kind: "completion",
|
|
8437
|
-
idleMs,
|
|
8438
|
-
timeoutMs,
|
|
8439
|
-
lastActivityReason: completionLastActivityReason,
|
|
8440
|
-
details
|
|
7233
|
+
//#region extensions/codex/src/app-server/attempt-deadlines.ts
|
|
7234
|
+
function createCodexAttemptDeadlineController(params) {
|
|
7235
|
+
let deadline = { kind: "closed" };
|
|
7236
|
+
let timer;
|
|
7237
|
+
const armDeadline = (next) => {
|
|
7238
|
+
clearTimeout(timer);
|
|
7239
|
+
deadline = next;
|
|
7240
|
+
const deadlineAtMs = next.startedAtMs + next.timeoutMs;
|
|
7241
|
+
params.onDeadlineChanged?.({
|
|
7242
|
+
kind: "bounded",
|
|
7243
|
+
deadlineAtMs
|
|
8441
7244
|
});
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
7245
|
+
timer = setTimeout(() => {
|
|
7246
|
+
if (deadline !== next || params.signal.aborted) return;
|
|
7247
|
+
deadline = { kind: "closed" };
|
|
7248
|
+
params.onTimeout({
|
|
7249
|
+
kind: next.kind,
|
|
7250
|
+
elapsedMs: Math.max(0, Date.now() - next.startedAtMs),
|
|
7251
|
+
timeoutMs: next.timeoutMs
|
|
7252
|
+
});
|
|
7253
|
+
}, resolveTimerTimeoutMs(Math.max(1, deadlineAtMs - Date.now()), 1));
|
|
7254
|
+
timer.unref?.();
|
|
7255
|
+
};
|
|
7256
|
+
const dispose = () => {
|
|
7257
|
+
deadline = { kind: "closed" };
|
|
7258
|
+
clearTimeout(timer);
|
|
7259
|
+
params.signal.removeEventListener("abort", dispose);
|
|
7260
|
+
};
|
|
7261
|
+
if (!params.signal.aborted) {
|
|
7262
|
+
params.signal.addEventListener("abort", dispose, { once: true });
|
|
7263
|
+
if (params.timeoutMs >= MAX_TIMER_TIMEOUT_MS) {
|
|
7264
|
+
deadline = { kind: "unlimited" };
|
|
7265
|
+
params.onDeadlineChanged?.({ kind: "unlimited" });
|
|
7266
|
+
} else armDeadline({
|
|
7267
|
+
kind: "execution",
|
|
7268
|
+
startedAtMs: params.startedAtMs,
|
|
7269
|
+
timeoutMs: params.timeoutMs
|
|
8456
7270
|
});
|
|
8457
7271
|
}
|
|
8458
7272
|
return {
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
terminalIdleWatchArmed = true;
|
|
8468
|
-
scheduleTerminalIdleWatch();
|
|
8469
|
-
},
|
|
8470
|
-
armCompletionIdleWatch: (options) => {
|
|
8471
|
-
completionIdleWatchArmed = true;
|
|
8472
|
-
completionIdleWatchPinnedByTerminalError = options?.pinnedByTerminalError === true;
|
|
8473
|
-
completionIdleTimeoutOverrideMs = options?.timeoutMs !== void 0 ? resolveWatchTimeoutMs(options.timeoutMs) : void 0;
|
|
8474
|
-
scheduleCompletionIdleWatch();
|
|
8475
|
-
},
|
|
8476
|
-
disarmCompletionIdleWatch: () => {
|
|
8477
|
-
completionIdleWatchArmed = false;
|
|
8478
|
-
completionIdleWatchPinnedByTerminalError = false;
|
|
8479
|
-
completionIdleTimeoutOverrideMs = void 0;
|
|
8480
|
-
clearCompletionIdleTimer();
|
|
8481
|
-
},
|
|
8482
|
-
armAssistantCompletionIdleWatch: (details) => {
|
|
8483
|
-
assistantCompletionIdleWatchArmed = true;
|
|
8484
|
-
assistantCompletionLastActivityAt = Date.now();
|
|
8485
|
-
assistantCompletionLastActivityDetails = details;
|
|
8486
|
-
scheduleAssistantCompletionIdleWatch();
|
|
8487
|
-
},
|
|
8488
|
-
disarmAssistantCompletionIdleWatch: () => {
|
|
8489
|
-
assistantCompletionIdleWatchArmed = false;
|
|
8490
|
-
assistantCompletionLastActivityDetails = void 0;
|
|
8491
|
-
clearTimer("assistant");
|
|
8492
|
-
},
|
|
8493
|
-
touchActivity: (reason, options) => {
|
|
8494
|
-
completionLastActivityAt = Date.now();
|
|
8495
|
-
completionLastActivityReason = reason;
|
|
8496
|
-
completionLastActivityDetails = options?.details;
|
|
8497
|
-
completionIdleTimeoutOverrideMs = void 0;
|
|
8498
|
-
if (options?.attemptProgress) recordAttemptProgress(reason, options);
|
|
8499
|
-
params.onProgressDiagnostic(reason);
|
|
8500
|
-
if (options?.arm) {
|
|
8501
|
-
completionIdleWatchArmed = true;
|
|
8502
|
-
completionIdleWatchPinnedByTerminalError = false;
|
|
8503
|
-
}
|
|
8504
|
-
scheduleProgressWatches();
|
|
8505
|
-
},
|
|
8506
|
-
noteNotificationReceived: (method, options) => {
|
|
8507
|
-
const now = Date.now();
|
|
8508
|
-
completionLastActivityAt = Math.max(completionLastActivityAt, Math.min(now, options?.receivedAtMs ?? now));
|
|
8509
|
-
completionLastActivityReason = `notification:${method}`;
|
|
8510
|
-
if (options?.details !== void 0) completionLastActivityDetails = options.details;
|
|
8511
|
-
if (options?.attemptProgress) recordAttemptProgress(completionLastActivityReason, options);
|
|
8512
|
-
},
|
|
8513
|
-
extendAttemptIdleWatch: (timeoutMs) => {
|
|
8514
|
-
attemptIdleTimeoutOverrideMs = resolveWatchTimeoutMs(timeoutMs);
|
|
8515
|
-
scheduleAttemptIdleWatch();
|
|
7273
|
+
ownsExecutionWait: () => deadline.kind === "unlimited" || deadline.kind === "execution" && Date.now() < deadline.startedAtMs + deadline.timeoutMs,
|
|
7274
|
+
beginSettlement: (startedAtMs) => {
|
|
7275
|
+
if (deadline.kind === "closed" || deadline.kind === "settlement") return;
|
|
7276
|
+
armDeadline({
|
|
7277
|
+
kind: "settlement",
|
|
7278
|
+
startedAtMs,
|
|
7279
|
+
timeoutMs: TURN_TERMINAL_SETTLEMENT_TIMEOUT_MS
|
|
7280
|
+
});
|
|
8516
7281
|
},
|
|
8517
|
-
|
|
8518
|
-
clearCompletionIdleTimer,
|
|
8519
|
-
clearAllTimers
|
|
7282
|
+
dispose
|
|
8520
7283
|
};
|
|
8521
7284
|
}
|
|
8522
7285
|
//#endregion
|
|
@@ -8524,24 +7287,18 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
8524
7287
|
const CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS = 6e4;
|
|
8525
7288
|
function createCodexAttemptTurnState(resources) {
|
|
8526
7289
|
const { prompt, state: resourceState, projectorRef, trajectoryRecorder, startupTimeoutMs } = resources;
|
|
8527
|
-
const {
|
|
8528
|
-
const {
|
|
8529
|
-
const { params, options, appServer, runAbortController } = connection;
|
|
7290
|
+
const { connection } = prompt.context.runtime;
|
|
7291
|
+
const { params, options, runAbortController } = connection;
|
|
8530
7292
|
const state = {
|
|
8531
7293
|
latestStartupErrorNotification: void 0,
|
|
8532
7294
|
rateLimitsRevisionBeforeLastTurnStart: void 0,
|
|
8533
7295
|
completed: false,
|
|
7296
|
+
abortCleanup: Promise.resolve(),
|
|
7297
|
+
permissionChangeRestart: void 0,
|
|
8534
7298
|
localCompletionRequested: false,
|
|
8535
7299
|
terminalTurnNotificationQueued: false,
|
|
8536
7300
|
sawCodexInterruptMarker: false,
|
|
8537
|
-
|
|
8538
|
-
turnCompletionIdleTimedOut: false,
|
|
8539
|
-
turnWatchTimeoutKind: void 0,
|
|
8540
|
-
turnWatchTimeoutIdleMs: void 0,
|
|
8541
|
-
turnWatchTimeoutMs: void 0,
|
|
8542
|
-
turnWatchTimeoutLastActivityReason: void 0,
|
|
8543
|
-
turnWatchTimeoutDetails: void 0,
|
|
8544
|
-
turnCompletionIdleTimeoutMessage: void 0,
|
|
7301
|
+
timeout: void 0,
|
|
8545
7302
|
clientClosedPromptError: void 0,
|
|
8546
7303
|
clientClosedDiagnostic: void 0,
|
|
8547
7304
|
clientClosedAbort: false,
|
|
@@ -8550,26 +7307,16 @@ function createCodexAttemptTurnState(resources) {
|
|
|
8550
7307
|
lifecycleTerminalEmitted: false,
|
|
8551
7308
|
nativeHookRelayLastRenewedAt: 0,
|
|
8552
7309
|
activeAppServerTurnRequests: 0,
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
rejectedFinalizationHookAssistant: void 0,
|
|
8556
|
-
turnCrossedToolHandoff: false,
|
|
7310
|
+
activeLocalProjections: 0,
|
|
7311
|
+
projectionClosed: false,
|
|
8557
7312
|
pendingTerminalDynamicToolRelease: void 0,
|
|
8558
7313
|
terminalDynamicToolReleaseCheckScheduled: false,
|
|
8559
7314
|
currentTurnHadNonTerminalDynamicToolResult: false
|
|
8560
7315
|
};
|
|
8561
7316
|
const { promise: completion, resolve: resolveCompletion } = createDeferred();
|
|
8562
|
-
const turnCompletionIdleTimeoutMs = resolveCodexTurnCompletionIdleTimeoutMs(options.turnCompletionIdleTimeoutMs ?? appServer.turnCompletionIdleTimeoutMs);
|
|
8563
|
-
const turnAssistantCompletionIdleTimeoutMs = resolveCodexTurnAssistantCompletionIdleTimeoutMs(options.turnAssistantCompletionIdleTimeoutMs ?? appServer.turnAssistantCompletionIdleTimeoutMs);
|
|
8564
|
-
const postToolRawAssistantCompletionIdleTimeoutMs = resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs(options.postToolRawAssistantCompletionIdleTimeoutMs ?? appServer.postToolRawAssistantCompletionIdleTimeoutMs, turnAssistantCompletionIdleTimeoutMs);
|
|
8565
|
-
const turnTerminalIdleTimeoutMs = resolveCodexTurnTerminalIdleTimeoutMs(options.turnTerminalIdleTimeoutMs, params.runTimeoutOverrideMs);
|
|
8566
|
-
const turnAttemptIdleTimeoutMs = Math.max(100, Math.floor(params.timeoutMs));
|
|
8567
7317
|
const pendingOpenClawDynamicToolCompletionIds = /* @__PURE__ */ new Set();
|
|
8568
7318
|
const openClawDynamicToolExecutions = createCodexDynamicToolExecutionRegistry();
|
|
8569
7319
|
const activeTurnItemIds = /* @__PURE__ */ new Set();
|
|
8570
|
-
const activeCompletionBlockerItemIds = /* @__PURE__ */ new Set();
|
|
8571
|
-
const activeFinalizationHookRunIds = /* @__PURE__ */ new Set();
|
|
8572
|
-
const finalizationHookBatchStatuses = /* @__PURE__ */ new Map();
|
|
8573
7320
|
const turnIdRef = {};
|
|
8574
7321
|
const userInputBridgeRef = {};
|
|
8575
7322
|
const steeringQueueRef = {};
|
|
@@ -8577,7 +7324,7 @@ function createCodexAttemptTurnState(resources) {
|
|
|
8577
7324
|
if (state.completed) return;
|
|
8578
7325
|
state.completed = true;
|
|
8579
7326
|
steeringQueueRef.current?.cancel();
|
|
8580
|
-
|
|
7327
|
+
deadlines.beginSettlement(Date.now());
|
|
8581
7328
|
resolveCompletion();
|
|
8582
7329
|
};
|
|
8583
7330
|
const interruptTurn = async (turnId, completionOptions) => {
|
|
@@ -8599,86 +7346,62 @@ function createCodexAttemptTurnState(resources) {
|
|
|
8599
7346
|
state.nativeHookRelayLastRenewedAt = now;
|
|
8600
7347
|
resourceState.nativeHookRelay.renew(resolveCodexNativeHookRelayTtlMs({
|
|
8601
7348
|
explicitTtlMs: void 0,
|
|
8602
|
-
attemptTimeoutMs:
|
|
7349
|
+
attemptTimeoutMs: params.timeoutMs,
|
|
8603
7350
|
startupTimeoutMs,
|
|
8604
7351
|
turnStartTimeoutMs: params.timeoutMs
|
|
8605
7352
|
}));
|
|
8606
7353
|
};
|
|
8607
|
-
const
|
|
8608
|
-
|
|
7354
|
+
const noteProgress = (reason) => {
|
|
7355
|
+
if (state.completed || state.projectionClosed || runAbortController.signal.aborted) return;
|
|
7356
|
+
renewNativeHookRelayForTurnProgress();
|
|
7357
|
+
params.onRunProgress?.({
|
|
7358
|
+
reason,
|
|
7359
|
+
provider: params.provider,
|
|
7360
|
+
model: params.modelId,
|
|
7361
|
+
backend: "codex-app-server"
|
|
7362
|
+
});
|
|
7363
|
+
emitTrustedDiagnosticEvent({
|
|
7364
|
+
type: "run.progress",
|
|
7365
|
+
runId: params.runId,
|
|
7366
|
+
sessionId: params.sessionId,
|
|
7367
|
+
sessionKey: params.sessionKey,
|
|
7368
|
+
reason: `codex_app_server:${reason}`
|
|
7369
|
+
});
|
|
7370
|
+
};
|
|
7371
|
+
const deadlines = createCodexAttemptDeadlineController({
|
|
7372
|
+
startedAtMs: connection.attemptStartedAt,
|
|
7373
|
+
timeoutMs: params.timeoutMs,
|
|
8609
7374
|
signal: runAbortController.signal,
|
|
8610
|
-
|
|
8611
|
-
isCompleted: () => state.completed,
|
|
8612
|
-
isTerminalTurnNotificationQueued: () => state.terminalTurnNotificationQueued,
|
|
8613
|
-
getActiveAppServerTurnRequests: () => state.activeAppServerTurnRequests,
|
|
8614
|
-
getActiveAppServerTurnRequestsWithoutTimeout: () => state.activeAppServerTurnRequestsWithoutTimeout,
|
|
8615
|
-
getActiveTurnItemCount: () => activeTurnItemIds.size,
|
|
8616
|
-
getActiveCompletionBlockerItemCount: () => activeCompletionBlockerItemIds.size,
|
|
8617
|
-
getActiveFinalizationHookCount: () => state.unsettledFinalizationHookCount,
|
|
8618
|
-
canReleaseAssistantCompletionIdle: () => projectorRef.current?.hasLatestTerminalAssistantCandidateText() === true,
|
|
8619
|
-
turnCompletionIdleTimeoutMs,
|
|
8620
|
-
turnAssistantCompletionIdleTimeoutMs,
|
|
8621
|
-
turnAttemptIdleTimeoutMs,
|
|
8622
|
-
turnTerminalIdleTimeoutMs,
|
|
8623
|
-
interruptTimeoutMs: CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS,
|
|
8624
|
-
onInterruptTurn: ({ turnId, timeoutMs }) => interruptTurn(turnId, {
|
|
8625
|
-
locallyCompleted: true,
|
|
8626
|
-
timeoutMs
|
|
8627
|
-
}),
|
|
7375
|
+
onDeadlineChanged: params.onAttemptDeadlineChanged,
|
|
8628
7376
|
onTimeout: (timeout) => {
|
|
8629
|
-
state.
|
|
8630
|
-
state.turnCompletionIdleTimedOut = true;
|
|
8631
|
-
state.turnWatchTimeoutKind = timeout.kind;
|
|
8632
|
-
state.turnWatchTimeoutIdleMs = timeout.idleMs;
|
|
8633
|
-
state.turnWatchTimeoutMs = timeout.timeoutMs;
|
|
8634
|
-
state.turnWatchTimeoutLastActivityReason = timeout.lastActivityReason;
|
|
8635
|
-
state.turnWatchTimeoutDetails = timeout.details;
|
|
8636
|
-
state.turnCompletionIdleTimeoutMessage = "codex app-server turn idle timed out waiting for turn/completed";
|
|
7377
|
+
state.timeout = timeout;
|
|
8637
7378
|
projectorRef.current?.markTimedOut();
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
|
|
8647
|
-
|
|
8648
|
-
backend: "codex-app-server"
|
|
8649
|
-
});
|
|
8650
|
-
},
|
|
8651
|
-
onProgressDiagnostic: (reason) => {
|
|
8652
|
-
emitTrustedDiagnosticEvent({
|
|
8653
|
-
type: "run.progress",
|
|
8654
|
-
runId: params.runId,
|
|
8655
|
-
sessionId: params.sessionId,
|
|
8656
|
-
sessionKey: params.sessionKey,
|
|
8657
|
-
reason: `codex_app_server:${reason}`
|
|
8658
|
-
});
|
|
7379
|
+
const error = /* @__PURE__ */ new Error(timeout.kind === "execution" ? "codex app-server execution budget timed out" : "codex app-server terminal settlement timed out");
|
|
7380
|
+
const fields = {
|
|
7381
|
+
threadId: resourceState.thread.threadId,
|
|
7382
|
+
turnId: turnIdRef.current,
|
|
7383
|
+
...timeout
|
|
7384
|
+
};
|
|
7385
|
+
trajectoryRecorder?.recordEvent(`turn.${timeout.kind}_timeout`, fields);
|
|
7386
|
+
embeddedAgentLog.warn(error.message, fields);
|
|
7387
|
+
params.onAttemptTimeout?.(error);
|
|
7388
|
+
runAbortController.abort(error);
|
|
8659
7389
|
}
|
|
8660
7390
|
});
|
|
8661
7391
|
return {
|
|
8662
7392
|
state,
|
|
8663
7393
|
completion,
|
|
8664
|
-
turnCompletionIdleTimeoutMs,
|
|
8665
|
-
turnAssistantCompletionIdleTimeoutMs,
|
|
8666
|
-
postToolRawAssistantCompletionIdleTimeoutMs,
|
|
8667
|
-
turnTerminalIdleTimeoutMs,
|
|
8668
|
-
turnAttemptIdleTimeoutMs,
|
|
8669
7394
|
pendingOpenClawDynamicToolCompletionIds,
|
|
8670
7395
|
openClawDynamicToolExecutions,
|
|
8671
7396
|
activeTurnItemIds,
|
|
8672
|
-
activeCompletionBlockerItemIds,
|
|
8673
|
-
activeFinalizationHookRunIds,
|
|
8674
|
-
finalizationHookBatchStatuses,
|
|
8675
7397
|
turnIdRef,
|
|
8676
7398
|
userInputBridgeRef,
|
|
8677
7399
|
steeringQueueRef,
|
|
8678
7400
|
completeTurn,
|
|
8679
7401
|
interruptTurn,
|
|
8680
7402
|
renewNativeHookRelayForTurnProgress,
|
|
8681
|
-
|
|
7403
|
+
noteProgress,
|
|
7404
|
+
deadlines
|
|
8682
7405
|
};
|
|
8683
7406
|
}
|
|
8684
7407
|
//#endregion
|
|
@@ -8694,21 +7417,26 @@ async function runCodexAppServerAttempt(params, options) {
|
|
|
8694
7417
|
attemptTools.runtimeYieldCompletionClaim.current = () => resources.state.nativeHookRelay?.hasClaimedDirectChild() ?? false;
|
|
8695
7418
|
await startCodexAttemptRuntime(resources);
|
|
8696
7419
|
const turnRuntime = createCodexAttemptTurnState(resources);
|
|
8697
|
-
const lifecycle = createCodexAttemptLifecycleController(resources, turnRuntime);
|
|
8698
|
-
const notifications = createCodexAttemptNotificationController(resources, turnRuntime, lifecycle);
|
|
8699
|
-
const { ensureCurrentThreadRoute } = await prepareCodexAttemptRoute(resources, turnRuntime, notifications, createCodexAttemptServerRequestController(resources, turnRuntime, lifecycle).handleServerRequest);
|
|
8700
|
-
const turnRequest = await prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurrentThreadRoute, notifications.waitForActiveNativeTurnCompletion);
|
|
8701
|
-
const turnStart = await startCodexAttemptTurn(resources, turnRuntime, notifications, turnRequest);
|
|
8702
|
-
if ("result" in turnStart) return turnStart.result;
|
|
8703
|
-
const activeTurn = await activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, turnStart.turn);
|
|
8704
|
-
let finalizedResult;
|
|
8705
7420
|
try {
|
|
8706
|
-
|
|
7421
|
+
const lifecycle = createCodexAttemptLifecycleController(resources, turnRuntime);
|
|
7422
|
+
const notifications = createCodexAttemptNotificationController(resources, turnRuntime, lifecycle);
|
|
7423
|
+
const { ensureCurrentThreadRoute } = await prepareCodexAttemptRoute(resources, turnRuntime, notifications, createCodexAttemptServerRequestController(resources, turnRuntime, lifecycle).handleServerRequest);
|
|
7424
|
+
const turnRequest = await prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurrentThreadRoute, notifications.waitForActiveNativeTurnCompletion);
|
|
7425
|
+
const turnStart = await startCodexAttemptTurn(resources, turnRuntime, notifications, turnRequest);
|
|
7426
|
+
if ("result" in turnStart) return turnStart.result;
|
|
7427
|
+
const activeTurn = activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, turnStart.turn);
|
|
7428
|
+
let finalizedResult;
|
|
7429
|
+
try {
|
|
7430
|
+
await activeTurn.ready;
|
|
7431
|
+
finalizedResult = await finalizeCodexAttempt(resources, turnRuntime, lifecycle, notifications, turnRequest, activeTurn);
|
|
7432
|
+
} finally {
|
|
7433
|
+
await cleanupCodexAttempt(resources, turnRuntime, lifecycle, turnRequest, activeTurn);
|
|
7434
|
+
}
|
|
7435
|
+
if (resources.state.executionDisconnectError && !connection.terminalState.explicitCancellationObserved) throw resources.state.executionDisconnectError;
|
|
7436
|
+
return finalizedResult;
|
|
8707
7437
|
} finally {
|
|
8708
|
-
|
|
7438
|
+
turnRuntime.deadlines.dispose();
|
|
8709
7439
|
}
|
|
8710
|
-
if (resources.state.executionDisconnectError && !connection.terminalState.explicitCancellationObserved) throw resources.state.executionDisconnectError;
|
|
8711
|
-
return finalizedResult;
|
|
8712
7440
|
}
|
|
8713
7441
|
//#endregion
|
|
8714
7442
|
export { runCodexAppServerAttempt };
|