@openclaw/codex 2026.8.2 → 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 +3 -3
- package/dist/{attempt-client-cleanup-CpVfwctT.js → attempt-client-cleanup-DYHcRQAa.js} +6 -43
- package/dist/attempt-context-DmQUNWwT.js +634 -0
- package/dist/{binding-connection-CF7BmrDk.js → binding-connection-E6uDsPlx.js} +2 -2
- package/dist/{bounded-turn-DRC3hcjm.js → bounded-turn-wzJrwKKe.js} +8 -9
- package/dist/{capabilities-D6m_TdVy.js → capabilities-dIjNVCYH.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters--UToCokS.js → command-formatters-CLHhEB1Q.js} +3 -3
- package/dist/{command-handlers-CLFx2Ypa.js → command-handlers-CTGb2csu.js} +54 -55
- package/dist/{compact-5xqW1oCh.js → compact-_t0HQrUS.js} +33 -25
- package/dist/{config-CcYL77O6.js → config-BhmfC1s6.js} +12 -8
- package/dist/{context-compaction-activity-BOeJf7yo.js → context-compaction-activity-CMla5FPJ.js} +4 -1
- package/dist/doctor-contract-api.js +31 -4
- package/dist/{dynamic-tools-BmeXjwNZ.js → dynamic-tools-BU9tmlYm.js} +448 -457
- package/dist/{effective-mcp-catalog-XXQKgK1U.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-B2r5vhWH.js → event-projector-usage-C5mcrGjp.js} +9 -137
- package/dist/{harness-BgeB7LnD.js → harness-DXVZ5II5.js} +13 -13
- package/dist/harness.js +1 -1
- package/dist/index.js +323 -313
- package/dist/{isolated-completion-CxTus3vZ.js → isolated-completion-kg9kv4iH.js} +4 -4
- package/dist/{launch-args-sXOAg0SX.js → launch-args-RXQwn8zV.js} +7 -1
- package/dist/{managed-binary-ZkGodW19.js → managed-binary-4-Vjz5GH.js} +14 -9
- package/dist/media-understanding-provider.js +1 -1
- package/dist/{model-catalog-DULBcniB.js → model-catalog-CUM68Hkl.js} +11 -11
- package/dist/{models-DaWfETQk.js → models-sYnEc0gd.js} +3 -3
- package/dist/{native-subagent-monitor-vXYUZH37.js → native-subagent-monitor-CnH147jH.js} +3 -3
- package/dist/{node-exec-server.runtime-DirKVZ5h.js → node-exec-server.runtime-CstNHCmC.js} +2 -2
- package/dist/{plugin-approval-roundtrip-CCWQGlAI.js → plugin-approval-roundtrip-CNe-Xrjx.js} +29 -3
- package/dist/{plugin-marketplace-discovery-BXjIFEiw.js → plugin-marketplace-discovery-CfFlKqDl.js} +6 -6
- package/dist/{plugin-metadata-cache-DQQm4gWT.js → plugin-metadata-cache-BFrPhb2c.js} +5 -5
- package/dist/provider-capabilities-DW5p4k9w.js +101 -0
- package/dist/{rate-limits-BqHEHXQJ.js → rate-limits-CawQJfUS.js} +1 -1
- package/dist/{request-BWxweEdK.js → request-DYAI5FQE.js} +18 -6
- package/dist/{run-attempt-BVLE4Gbi.js → run-attempt-D1hJO4fX.js} +483 -1865
- package/dist/{runtime-artifact-D9pYp4zL.js → runtime-artifact-C3jVimFn.js} +19 -12
- package/dist/{session-binding-D0zinCP1.js → session-binding-BHuTCRZQ.js} +8 -10
- package/dist/{session-catalog-eMhVm0Ql.js → session-catalog-yyvTWFOw.js} +138 -116
- package/dist/{session-cli-B2lyjJA0.js → session-cli-CmFEXMAM.js} +1 -1
- package/dist/session-initialization-BeWzjGiR.js +74 -0
- package/dist/{session-permission-policy-ScnAyG90.js → session-permission-policy-DeWVTCMj.js} +2 -2
- package/dist/{session-retirement-CtUtUTr9.js → session-retirement-BujDjXVF.js} +16 -9
- package/dist/{session-upstream-marker-gqrYIRHk.js → session-upstream-marker-C351-5Qw.js} +18 -2
- package/dist/{settled-turn-context-Bk3IUwod.js → settled-turn-context-D3SNWtUn.js} +6 -28
- package/dist/{settled-turn-finalizer-BXLN9PfJ.js → settled-turn-finalizer-BVJx4yoc.js} +5 -5
- package/dist/{shared-client-B1tT5U6r.js → shared-client-DxcfF9KX.js} +2748 -101
- package/dist/{side-question-CZ-mCw-t.js → side-question-BTZAII4l.js} +97 -63
- package/dist/{thread-lifecycle-CGGKP720.js → thread-lifecycle-DAcEJ_Om.js} +2039 -1487
- package/dist/{thread-ownership-RkaoZCmQ.js → thread-ownership-zGokd8i1.js} +10 -9
- package/dist/thread-policy-g4KbJPzp.js +54 -0
- package/dist/{thread-resume-BFt1-ZDa.js → thread-resume-C7pyVKeW.js} +15 -7
- package/dist/{transcript-mirror-1ep4XjzF.js → transcript-mirror-DTUxFWa_.js} +47 -10
- package/dist/{transport-stdio-NT_Dpd9V.js → transport-stdio-CyPldczm.js} +3 -1
- package/dist/upstream-session-fork-CYlBIGVt.js +966 -0
- package/dist/{usage-DUhd58gI.js → usage-Bj-rrzkR.js} +3 -3
- package/dist/{web-search-provider.runtime-BEmlE7ov.js → web-search-provider.runtime-D2FWSK4w.js} +3 -3
- package/openclaw.plugin.json +0 -30
- package/package.json +5 -5
- package/dist/protocol-validators-Bg5rpNxk.js +0 -2542
- package/dist/session-catalog-home-id-Dt2GiG5o.js +0 -112
- package/dist/upstream-session-fork-Dc8BFExw.js +0 -312
|
@@ -1,54 +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 { i as
|
|
8
|
-
import {
|
|
9
|
-
import { l as
|
|
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";
|
|
10
11
|
import { r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-LphB8slG.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { a as
|
|
14
|
-
import { r as
|
|
15
|
-
import {
|
|
16
|
-
import { n as resolveCodexBindingAppServerConnection } from "./binding-connection-CF7BmrDk.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
17
|
import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-Ds_QVm-X.js";
|
|
18
|
-
import { t as persistCodexContextCompactionActivity } from "./context-compaction-activity-
|
|
19
|
-
import { i as
|
|
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-
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import { a as
|
|
25
|
-
import {
|
|
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";
|
|
26
28
|
import fs from "node:fs/promises";
|
|
27
29
|
import path from "node:path";
|
|
28
30
|
import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
|
|
29
|
-
import { asDateTimestampMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
30
|
-
import { AgentHarnessPreflightError, CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, agentHarnessAttemptTerminal, agentHarnessStructuredInput, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine,
|
|
31
|
-
import
|
|
32
|
-
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";
|
|
33
36
|
import { resolveAgentConfig as resolveAgentConfig$1, resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
34
37
|
import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
35
38
|
import { parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
|
|
36
39
|
import { addAbortListener } from "node:events";
|
|
37
40
|
import { truncateUtf16Safe, truncateUtf8Prefix } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
38
41
|
import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
39
|
-
import {
|
|
40
|
-
import { captureFinalCodexCronCreatorToolAllowlist, materializeStaticMcpToolsForScheduledHarnessRun, resolveCodexMcpToolOverridesForAgent, resolveCodexTtsProvenanceTransfer } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
42
|
+
import { captureFinalCodexCronCreatorToolAllowlist, formatMcpCodexApprovalRemedy, materializeStaticMcpToolsForHarnessRun, resolveCodexMcpToolOverridesForAgent, resolveCodexTtsProvenanceTransfer } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
41
43
|
import { hasPromptImageInput } from "openclaw/plugin-sdk/session-transcript-runtime";
|
|
42
44
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
43
45
|
import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
|
|
44
|
-
import { prepareMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
|
|
45
46
|
import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-local-roots";
|
|
46
47
|
import { isSilentReplyPayloadText } from "openclaw/plugin-sdk/reply-chunking";
|
|
47
48
|
import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
|
|
48
49
|
import { resolveGeneratedMediaMaxBytes } from "openclaw/plugin-sdk/media-generation-runtime";
|
|
49
50
|
import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
50
51
|
import { stripInvisibleUnicode } from "openclaw/plugin-sdk/web-content-extractor";
|
|
51
|
-
import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
|
|
52
52
|
//#region extensions/codex/src/app-server/attempt-steering.ts
|
|
53
53
|
/**
|
|
54
54
|
* Debounced steering queue for forwarding user messages to an active Codex
|
|
@@ -265,9 +265,8 @@ var CodexAssistantProjection = class {
|
|
|
265
265
|
this.assistantPhaseByItem = /* @__PURE__ */ new Map();
|
|
266
266
|
this.assistantDeliveryByItem = /* @__PURE__ */ new Map();
|
|
267
267
|
this.latestTerminalAssistantCandidateSuperseded = false;
|
|
268
|
-
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
|
|
269
268
|
this.terminalAssistantCandidateEarlierActiveItemIds = /* @__PURE__ */ new Set();
|
|
270
|
-
this.
|
|
269
|
+
this.lastCommentaryProgressEventByItem = /* @__PURE__ */ new Map();
|
|
271
270
|
this.lastAnswerCandidateEventByItem = /* @__PURE__ */ new Map();
|
|
272
271
|
this.pendingRawCommentaryEchoes = 0;
|
|
273
272
|
this.rawPromotedAssistantItemIds = /* @__PURE__ */ new Set();
|
|
@@ -278,27 +277,6 @@ var CodexAssistantProjection = class {
|
|
|
278
277
|
this.persistableAssistantBarrierItemIds = /* @__PURE__ */ new Set();
|
|
279
278
|
this.completedAssistantItemIds = /* @__PURE__ */ new Set();
|
|
280
279
|
}
|
|
281
|
-
hasCompletedTerminalAssistantText(completedItemIds) {
|
|
282
|
-
const latestCompletedItemId = this.latestCompletedTerminalAssistantItemId;
|
|
283
|
-
if (!latestCompletedItemId) return false;
|
|
284
|
-
const finalItem = this.resolveFinalAssistantTextItem();
|
|
285
|
-
return this.latestCompletedItemId === latestCompletedItemId && finalItem?.itemId === latestCompletedItemId && completedItemIds.has(latestCompletedItemId);
|
|
286
|
-
}
|
|
287
|
-
getLatestTerminalAssistantCandidate() {
|
|
288
|
-
const itemId = this.latestTerminalAssistantCandidateItemId;
|
|
289
|
-
if (!itemId) return;
|
|
290
|
-
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
291
|
-
return {
|
|
292
|
-
itemId,
|
|
293
|
-
hasText: Boolean(text && !this.isToolProgressEchoText(itemId, text))
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
hasLatestTerminalAssistantCandidateText() {
|
|
297
|
-
return !this.latestTerminalAssistantCandidateSuperseded && this.getLatestTerminalAssistantCandidate()?.hasText === true;
|
|
298
|
-
}
|
|
299
|
-
canReleaseLatestTerminalAssistantAfterToolHandoff() {
|
|
300
|
-
return this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff && this.hasLatestTerminalAssistantCandidateText();
|
|
301
|
-
}
|
|
302
280
|
handleNotification(method, params) {
|
|
303
281
|
if (method === "model/rerouted") this.responseModel = readStringField(params, "toModel") ?? this.responseModel;
|
|
304
282
|
}
|
|
@@ -321,12 +299,13 @@ var CodexAssistantProjection = class {
|
|
|
321
299
|
if (isCommentary) {
|
|
322
300
|
this.emitCommentaryProgress({
|
|
323
301
|
itemId,
|
|
324
|
-
text
|
|
302
|
+
text,
|
|
303
|
+
phase: "update"
|
|
325
304
|
});
|
|
326
305
|
return;
|
|
327
306
|
}
|
|
328
|
-
|
|
329
|
-
|
|
307
|
+
const knownFinalAnswer = this.isFinalAnswerAssistantItem(itemId);
|
|
308
|
+
if (knownFinalAnswer) this.emitAnswerCandidate(itemId, "candidate");
|
|
330
309
|
const replace = this.streamedPartialAssistantItemId !== void 0 && this.streamedPartialAssistantItemId !== itemId;
|
|
331
310
|
if (replace && (!knownFinalAnswer || this.streamedPartialAssistantItemReplaceable)) this.streamedPartialAssistantItemReplaceable = true;
|
|
332
311
|
else if (this.streamedPartialAssistantItemId === void 0) this.streamedPartialAssistantItemReplaceable = !knownFinalAnswer;
|
|
@@ -362,9 +341,7 @@ var CodexAssistantProjection = class {
|
|
|
362
341
|
this.noteNativeWorkBarrier(item);
|
|
363
342
|
this.rememberAssistantPhase(item);
|
|
364
343
|
if (item?.type === "agentMessage" && itemId && !this.isNonTerminalAssistantItem(itemId) && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
365
|
-
if (itemId && !this.isNonTerminalAssistantItem(itemId)) this.latestCompletedItemId = itemId;
|
|
366
344
|
if (item?.type === "agentMessage" && !this.isNonTerminalAssistantItem(item.id)) {
|
|
367
|
-
this.latestCompletedTerminalAssistantItemId = item.id;
|
|
368
345
|
this.markLatestTerminalAssistantCandidate(item.id, activeItemIds);
|
|
369
346
|
this.pendingRawTerminalAssistantEchoItemId = item.id;
|
|
370
347
|
} else if (itemId && !this.isNonTerminalAssistantItem(itemId)) {
|
|
@@ -377,7 +354,8 @@ var CodexAssistantProjection = class {
|
|
|
377
354
|
if (item.text && this.isCommentaryAssistantItem(item.id)) {
|
|
378
355
|
this.emitCommentaryProgress({
|
|
379
356
|
itemId: item.id,
|
|
380
|
-
text: item.text
|
|
357
|
+
text: item.text,
|
|
358
|
+
phase: "end"
|
|
381
359
|
});
|
|
382
360
|
this.pendingRawCommentaryEchoes += 1;
|
|
383
361
|
} else if (item.text && !this.isAsyncAssistantItem(item.id) && this.isFinalAnswerAssistantItem(item.id)) this.emitAnswerCandidate(item.id, "candidate");
|
|
@@ -401,10 +379,7 @@ var CodexAssistantProjection = class {
|
|
|
401
379
|
const pendingTerminalAssistantEchoItemId = this.pendingRawTerminalAssistantEchoItemId;
|
|
402
380
|
const isPendingTerminalAssistantEcho = role === "assistant" && phase !== "commentary" && pendingTerminalAssistantEchoItemId !== void 0 && (rawItemId === void 0 || rawItemId === pendingTerminalAssistantEchoItemId);
|
|
403
381
|
if (pendingTerminalAssistantEchoItemId !== void 0 && !isPendingTerminalAssistantEcho) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
404
|
-
if (!isPendingTerminalAssistantEcho)
|
|
405
|
-
this.latestCompletedItemId = void 0;
|
|
406
|
-
this.markTerminalAssistantCandidateSupersededBy(rawItemId);
|
|
407
|
-
}
|
|
382
|
+
if (!isPendingTerminalAssistantEcho) this.markTerminalAssistantCandidateSupersededBy(rawItemId);
|
|
408
383
|
if (role !== "assistant") return;
|
|
409
384
|
if (phase === "commentary" && this.pendingRawCommentaryEchoes > 0) {
|
|
410
385
|
this.pendingRawCommentaryEchoes -= 1;
|
|
@@ -431,9 +406,10 @@ var CodexAssistantProjection = class {
|
|
|
431
406
|
this.rawPromotedAssistantItemIds.add(itemId);
|
|
432
407
|
if (phase === "commentary") this.emitCommentaryProgress({
|
|
433
408
|
itemId,
|
|
434
|
-
text
|
|
409
|
+
text,
|
|
410
|
+
phase: "end"
|
|
435
411
|
});
|
|
436
|
-
else this.markLatestTerminalAssistantCandidate(itemId, activeItemIds
|
|
412
|
+
else this.markLatestTerminalAssistantCandidate(itemId, activeItemIds);
|
|
437
413
|
}
|
|
438
414
|
collectAssistantTexts() {
|
|
439
415
|
const afterHandoff = this.collectPersistableAssistantTexts(this.persistableAssistantBarrier);
|
|
@@ -544,9 +520,6 @@ var CodexAssistantProjection = class {
|
|
|
544
520
|
responseModel: this.responseModel
|
|
545
521
|
} : message;
|
|
546
522
|
}
|
|
547
|
-
createAssistantMirrorMessage(title, text) {
|
|
548
|
-
return createAssistantMirrorMessage(this.params, title, text);
|
|
549
|
-
}
|
|
550
523
|
rememberAssistantPhase(item) {
|
|
551
524
|
if (item?.type !== "agentMessage") return;
|
|
552
525
|
const phase = readItemString(item, "phase");
|
|
@@ -566,20 +539,21 @@ var CodexAssistantProjection = class {
|
|
|
566
539
|
isFinalAnswerAssistantItem(itemId) {
|
|
567
540
|
return this.assistantPhaseByItem.get(itemId) === "final_answer";
|
|
568
541
|
}
|
|
569
|
-
shouldStreamAssistantPartial(itemId) {
|
|
570
|
-
return this.assistantPhaseByItem.get(itemId) === "final_answer";
|
|
571
|
-
}
|
|
572
542
|
emitCommentaryProgress(params) {
|
|
573
543
|
const progressText = params.text.trim();
|
|
574
|
-
|
|
575
|
-
|
|
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
|
+
});
|
|
576
550
|
this.emitAgentEvent({
|
|
577
551
|
stream: "item",
|
|
578
552
|
data: {
|
|
579
553
|
itemId: params.itemId,
|
|
580
554
|
kind: "preamble",
|
|
581
555
|
title: "Preamble",
|
|
582
|
-
phase:
|
|
556
|
+
phase: params.phase,
|
|
583
557
|
progressText,
|
|
584
558
|
source: "codex-app-server"
|
|
585
559
|
}
|
|
@@ -592,9 +566,12 @@ var CodexAssistantProjection = class {
|
|
|
592
566
|
this.supersedeVisibleAnswerCandidate();
|
|
593
567
|
this.visibleAnswerCandidateItemId = itemId;
|
|
594
568
|
}
|
|
595
|
-
const
|
|
596
|
-
if (
|
|
597
|
-
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
|
+
});
|
|
598
575
|
this.emitAgentEvent({
|
|
599
576
|
stream: "item",
|
|
600
577
|
data: {
|
|
@@ -615,10 +592,9 @@ var CodexAssistantProjection = class {
|
|
|
615
592
|
this.emitAnswerCandidate(itemId, "superseded");
|
|
616
593
|
this.visibleAnswerCandidateItemId = void 0;
|
|
617
594
|
}
|
|
618
|
-
markLatestTerminalAssistantCandidate(itemId, activeItemIds
|
|
595
|
+
markLatestTerminalAssistantCandidate(itemId, activeItemIds) {
|
|
619
596
|
this.latestTerminalAssistantCandidateItemId = itemId;
|
|
620
597
|
this.latestTerminalAssistantCandidateSuperseded = false;
|
|
621
|
-
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = options?.canReleaseAfterToolHandoff === true;
|
|
622
598
|
this.terminalAssistantCandidateEarlierActiveItemIds = new Set(activeItemIds);
|
|
623
599
|
}
|
|
624
600
|
markTerminalAssistantCandidateSupersededBy(itemId, options) {
|
|
@@ -628,7 +604,6 @@ var CodexAssistantProjection = class {
|
|
|
628
604
|
return;
|
|
629
605
|
}
|
|
630
606
|
this.latestTerminalAssistantCandidateSuperseded = true;
|
|
631
|
-
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
|
|
632
607
|
this.terminalAssistantCandidateEarlierActiveItemIds.clear();
|
|
633
608
|
this.supersedeVisibleAnswerCandidate();
|
|
634
609
|
}
|
|
@@ -1031,7 +1006,7 @@ const attemptTerminal = agentHarnessAttemptTerminal;
|
|
|
1031
1006
|
//#region extensions/codex/src/app-server/event-projector-snapshot.ts
|
|
1032
1007
|
function buildCodexMessagesSnapshot(params) {
|
|
1033
1008
|
const messages = promptSnapshot(params.runParams, params.turnId, params.upstreamUserText);
|
|
1034
|
-
if (params.reasoningText) messages.push(attachCodexMirrorIdentity(params.
|
|
1009
|
+
if (params.reasoningText) messages.push(attachCodexMirrorIdentity(createAssistantReasoningMessage(params.runParams, params.reasoningText), `${params.turnId}:reasoning`));
|
|
1035
1010
|
const commentaryMessages = params.runParams.config?.ui?.prefs?.chatPersistCommentary === false ? [] : params.commentaryMessages.map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:commentary:${itemId}`));
|
|
1036
1011
|
const asyncMessages = params.asyncMessages.map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:async:${itemId}`));
|
|
1037
1012
|
const visibleWorkMessages = [
|
|
@@ -1066,8 +1041,7 @@ function buildCodexSteeringMessagesSnapshot(params) {
|
|
|
1066
1041
|
commentaryMessages,
|
|
1067
1042
|
assistantMessages,
|
|
1068
1043
|
toolMessages: params.toolMessages,
|
|
1069
|
-
lastAssistant: void 0
|
|
1070
|
-
createAssistantMirrorMessage: (title, text) => params.assistantProjection.createAssistantMirrorMessage(title, text)
|
|
1044
|
+
lastAssistant: void 0
|
|
1071
1045
|
}).filter((message) => message.role !== "user"),
|
|
1072
1046
|
assistantBoundaryItemId: assistantMessages.at(-1)?.itemId
|
|
1073
1047
|
};
|
|
@@ -1115,8 +1089,7 @@ function buildCodexAttemptResult(input) {
|
|
|
1115
1089
|
asyncMessages,
|
|
1116
1090
|
commentaryMessages,
|
|
1117
1091
|
toolMessages: input.toolTranscriptProjection.transcriptMessages,
|
|
1118
|
-
lastAssistant
|
|
1119
|
-
createAssistantMirrorMessage: (title, text) => input.assistantProjection.createAssistantMirrorMessage(title, text)
|
|
1092
|
+
lastAssistant
|
|
1120
1093
|
});
|
|
1121
1094
|
const turnFailed = input.completedTurn?.status === "failed";
|
|
1122
1095
|
const promptError = input.promptError ?? storedMissingToolResultError ?? (turnFailed ? input.completedTurn?.error?.message ?? "codex app-server turn failed" : null);
|
|
@@ -1264,6 +1237,10 @@ const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
|
|
|
1264
1237
|
function createCodexUsageLimitPromptError(message) {
|
|
1265
1238
|
return Object.assign(new Error(message), { status: 429 });
|
|
1266
1239
|
}
|
|
1240
|
+
function resolveCodexPromptError(source) {
|
|
1241
|
+
const usageLimitMessage = formatCodexUsageLimitErrorMessage(source);
|
|
1242
|
+
return usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : source.message ?? void 0;
|
|
1243
|
+
}
|
|
1267
1244
|
function isCodexUsageLimitPromptError(error) {
|
|
1268
1245
|
return error instanceof Error && "status" in error && error.status === 429;
|
|
1269
1246
|
}
|
|
@@ -1403,6 +1380,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1403
1380
|
this.activeCompactionItemIds = /* @__PURE__ */ new Set();
|
|
1404
1381
|
this.terminalPresentationClearedItemIds = /* @__PURE__ */ new Set();
|
|
1405
1382
|
this.nativeToolOutcomeOrdinals = /* @__PURE__ */ new Map();
|
|
1383
|
+
this.projectionClosed = false;
|
|
1406
1384
|
this.settledTurnFailureFinalizationAllowed = false;
|
|
1407
1385
|
this.promptErrorSource = null;
|
|
1408
1386
|
this.synthesizedMissingToolResultError = null;
|
|
@@ -1435,6 +1413,13 @@ var CodexAppServerEventProjector = class {
|
|
|
1435
1413
|
getCompletedTurnStatus() {
|
|
1436
1414
|
return this.completedTurn?.status;
|
|
1437
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
|
+
}
|
|
1438
1423
|
buildSteeringTranscriptPrefix() {
|
|
1439
1424
|
const snapshot = buildCodexSteeringMessagesSnapshot({
|
|
1440
1425
|
runParams: this.params,
|
|
@@ -1454,25 +1439,10 @@ var CodexAppServerEventProjector = class {
|
|
|
1454
1439
|
this.pendingSteeringAssistantBoundaryItemId = void 0;
|
|
1455
1440
|
}
|
|
1456
1441
|
}
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
return this.assistantProjection.getLatestTerminalAssistantCandidate();
|
|
1462
|
-
}
|
|
1463
|
-
hasLatestTerminalAssistantCandidateText() {
|
|
1464
|
-
return this.assistantProjection.hasLatestTerminalAssistantCandidateText();
|
|
1465
|
-
}
|
|
1466
|
-
canReleaseLatestTerminalAssistantAfterToolHandoff() {
|
|
1467
|
-
return this.assistantProjection.canReleaseLatestTerminalAssistantAfterToolHandoff();
|
|
1468
|
-
}
|
|
1469
|
-
/** Restores a completed final item after only the enclosing turn timeout fired. */
|
|
1470
|
-
recoverCompletedTerminalAssistantAfterTurnWatchTimeout() {
|
|
1471
|
-
if (!this.aborted || this.promptError !== "codex app-server attempt timed out" || !this.hasCompletedTerminalAssistantText()) return false;
|
|
1472
|
-
this.aborted = false;
|
|
1473
|
-
this.promptError = void 0;
|
|
1474
|
-
this.promptErrorSource = null;
|
|
1475
|
-
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);
|
|
1476
1446
|
}
|
|
1477
1447
|
/** Resolves the shared model-order position for a native tool item. */
|
|
1478
1448
|
recordNativeToolOutcome(item) {
|
|
@@ -1488,6 +1458,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1488
1458
|
this.nativeToolLifecycleProjector.recordPreToolUseFailure(failure);
|
|
1489
1459
|
}
|
|
1490
1460
|
async handleNotification(notification) {
|
|
1461
|
+
if (this.projectionClosed) return;
|
|
1491
1462
|
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
1492
1463
|
if (!params) return;
|
|
1493
1464
|
if (notification.method === "hook/started" || notification.method === "hook/completed") {
|
|
@@ -1573,7 +1544,11 @@ var CodexAppServerEventProjector = class {
|
|
|
1573
1544
|
const codexErrorInfo = isJsonObject(params.error) ? params.error.codexErrorInfo : void 0;
|
|
1574
1545
|
const compactionFailure = codexErrorInfo === "other" && this.isCompacting();
|
|
1575
1546
|
this.settledTurnFailureFinalizationAllowed = codexErrorInfo === "serverOverloaded" || compactionFailure;
|
|
1576
|
-
this.promptError =
|
|
1547
|
+
this.promptError = resolveCodexPromptError({
|
|
1548
|
+
message: readCodexErrorNotificationMessage(params),
|
|
1549
|
+
codexErrorInfo,
|
|
1550
|
+
rateLimits: this.options.readRecentRateLimits?.()
|
|
1551
|
+
}) ?? "codex app-server error";
|
|
1577
1552
|
this.promptErrorSource = compactionFailure ? "compaction" : "prompt";
|
|
1578
1553
|
break;
|
|
1579
1554
|
}
|
|
@@ -1662,16 +1637,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1662
1637
|
await runAgentHarnessBeforeCompactionHook({
|
|
1663
1638
|
sessionFile: this.params.sessionFile,
|
|
1664
1639
|
messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
|
|
1665
|
-
ctx: {
|
|
1666
|
-
runId: this.params.runId,
|
|
1667
|
-
agentId: this.params.agentId,
|
|
1668
|
-
sessionKey: this.params.sessionKey,
|
|
1669
|
-
sessionId: this.params.sessionId,
|
|
1670
|
-
workspaceDir: this.params.workspaceDir,
|
|
1671
|
-
messageProvider: this.params.messageProvider ?? void 0,
|
|
1672
|
-
trigger: this.params.trigger,
|
|
1673
|
-
channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
|
|
1674
|
-
}
|
|
1640
|
+
ctx: this.options.agentHookContext ?? {}
|
|
1675
1641
|
});
|
|
1676
1642
|
this.emitAgentEvent({
|
|
1677
1643
|
stream: "compaction",
|
|
@@ -1693,6 +1659,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1693
1659
|
phase: "start",
|
|
1694
1660
|
item
|
|
1695
1661
|
});
|
|
1662
|
+
if (this.projectionClosed) return;
|
|
1696
1663
|
this.toolTranscriptProjection.recordNativeToolCall(item);
|
|
1697
1664
|
this.toolProgressProjection.emitToolResultSummary(item);
|
|
1698
1665
|
this.emitAgentEvent({
|
|
@@ -1717,27 +1684,22 @@ var CodexAppServerEventProjector = class {
|
|
|
1717
1684
|
if (!this.asyncDeliveryProjection.allows(item, true)) return;
|
|
1718
1685
|
const asyncMessage = this.assistantProjection.recordItemCompleted(item, itemId, this.activeItemIds);
|
|
1719
1686
|
if (asyncMessage) await this.asyncDeliveryProjection.deliver(asyncMessage);
|
|
1687
|
+
if (this.projectionClosed) return;
|
|
1720
1688
|
this.reasoningProjection.recordItem(item);
|
|
1721
1689
|
await this.generatedMediaProjection.recordNative(item);
|
|
1690
|
+
if (this.projectionClosed) return;
|
|
1722
1691
|
if (item?.type === "contextCompaction" && itemId) {
|
|
1723
1692
|
this.activeCompactionItemIds.delete(itemId);
|
|
1724
1693
|
this.completedCompactionCount += 1;
|
|
1725
1694
|
await this.options.onContextCompacted?.();
|
|
1695
|
+
if (this.projectionClosed) return;
|
|
1726
1696
|
await runAgentHarnessAfterCompactionHook({
|
|
1727
1697
|
sessionFile: this.params.sessionFile,
|
|
1728
1698
|
messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
|
|
1729
1699
|
compactedCount: -1,
|
|
1730
|
-
ctx: {
|
|
1731
|
-
runId: this.params.runId,
|
|
1732
|
-
agentId: this.params.agentId,
|
|
1733
|
-
sessionKey: this.params.sessionKey,
|
|
1734
|
-
sessionId: this.params.sessionId,
|
|
1735
|
-
workspaceDir: this.params.workspaceDir,
|
|
1736
|
-
messageProvider: this.params.messageProvider ?? void 0,
|
|
1737
|
-
trigger: this.params.trigger,
|
|
1738
|
-
channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
|
|
1739
|
-
}
|
|
1700
|
+
ctx: this.options.agentHookContext ?? {}
|
|
1740
1701
|
});
|
|
1702
|
+
if (this.projectionClosed) return;
|
|
1741
1703
|
await persistCodexContextCompactionActivity({
|
|
1742
1704
|
sessionTarget: this.params.sessionTarget,
|
|
1743
1705
|
config: this.params.config,
|
|
@@ -1760,8 +1722,10 @@ var CodexAppServerEventProjector = class {
|
|
|
1760
1722
|
phase: "result",
|
|
1761
1723
|
item
|
|
1762
1724
|
});
|
|
1725
|
+
if (this.projectionClosed) return;
|
|
1763
1726
|
this.toolTranscriptProjection.recordNativeToolCall(item);
|
|
1764
1727
|
await this.toolTranscriptProjection.recordNativeToolResultWithDetails(item);
|
|
1728
|
+
if (this.projectionClosed) return;
|
|
1765
1729
|
this.toolProgressProjection.emitToolResultSummary(item);
|
|
1766
1730
|
this.toolProgressProjection.emitToolResultOutput(item);
|
|
1767
1731
|
this.emitAgentEvent({
|
|
@@ -1781,12 +1745,11 @@ var CodexAppServerEventProjector = class {
|
|
|
1781
1745
|
this.settledTurnFailureFinalizationAllowed = turn.status === "failed" && (turn.error?.codexErrorInfo === "serverOverloaded" || compactionFailure);
|
|
1782
1746
|
if (turn.status !== "completed") this.responseCompletions.clear();
|
|
1783
1747
|
if (turn.status === "failed") {
|
|
1784
|
-
|
|
1748
|
+
this.promptError = resolveCodexPromptError({
|
|
1785
1749
|
message: turn.error?.message,
|
|
1786
1750
|
codexErrorInfo: turn.error?.codexErrorInfo,
|
|
1787
1751
|
rateLimits: this.options.readRecentRateLimits?.()
|
|
1788
|
-
});
|
|
1789
|
-
this.promptError = usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : turn.error?.message ?? "codex app-server turn failed";
|
|
1752
|
+
}) ?? "codex app-server turn failed";
|
|
1790
1753
|
this.promptErrorSource = compactionFailure ? "compaction" : "prompt";
|
|
1791
1754
|
}
|
|
1792
1755
|
if (compactionFailure) {
|
|
@@ -1799,39 +1762,40 @@ var CodexAppServerEventProjector = class {
|
|
|
1799
1762
|
}
|
|
1800
1763
|
const turnItems = turn.items ?? [];
|
|
1801
1764
|
const unsettledAsyncDeliveries = this.asyncDeliveryProjection.pending();
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
if (!item || !this.isCurrentTurnSnapshotItem(item)) continue;
|
|
1805
|
-
if (item?.type === "dynamicToolCall") break;
|
|
1806
|
-
if (shouldClearTerminalPresentationForNativeItem(item)) {
|
|
1807
|
-
this.clearTerminalPresentationForNativeItem(item);
|
|
1808
|
-
break;
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1765
|
+
const lastToolItem = turnItems.findLast((item) => matchesCodexSnapshotTurn(item, this.turnId) && (item.type === "dynamicToolCall" || shouldClearTerminalPresentationForNativeItem(item)));
|
|
1766
|
+
if (lastToolItem?.type !== "dynamicToolCall") this.clearTerminalPresentationForNativeItem(lastToolItem);
|
|
1811
1767
|
for (const item of turnItems) {
|
|
1812
1768
|
if (!this.asyncDeliveryProjection.allows(item)) continue;
|
|
1813
1769
|
this.diagnostics.warnUnknownItemStatus(item);
|
|
1814
1770
|
const asyncMessage = this.assistantProjection.recordSnapshotItem(item);
|
|
1815
1771
|
if (asyncMessage) await this.asyncDeliveryProjection.deliver(asyncMessage);
|
|
1772
|
+
if (this.projectionClosed) return;
|
|
1816
1773
|
this.reasoningProjection.recordItem(item);
|
|
1817
1774
|
await this.generatedMediaProjection.recordNative(item);
|
|
1775
|
+
if (this.projectionClosed) return;
|
|
1818
1776
|
this.toolProgressProjection.recordToolMeta(item);
|
|
1819
1777
|
this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
|
|
1820
1778
|
await this.emitSnapshotOnlyNativeToolProgress(item);
|
|
1779
|
+
if (this.projectionClosed) return;
|
|
1821
1780
|
this.toolTranscriptProjection.recordNativeToolCall(item);
|
|
1822
1781
|
await this.toolTranscriptProjection.recordNativeToolResultWithDetails(item);
|
|
1782
|
+
if (this.projectionClosed) return;
|
|
1823
1783
|
this.toolTranscriptProjection.emitAfterToolCallObservation(item);
|
|
1824
1784
|
this.toolProgressProjection.emitToolResultSummary(item);
|
|
1825
1785
|
this.toolProgressProjection.emitToolResultOutput(item);
|
|
1826
1786
|
}
|
|
1827
1787
|
this.toolProgressProjection.approvalTimeoutKinds.clear();
|
|
1828
|
-
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;
|
|
1829
1793
|
this.assistantProjection.finalizeAnswerCandidate(turn);
|
|
1830
1794
|
this.activeCompactionItemIds.clear();
|
|
1831
1795
|
await this.reasoningProjection.maybeEndReasoning();
|
|
1832
1796
|
}
|
|
1833
1797
|
async emitSnapshotOnlyNativeToolProgress(item) {
|
|
1834
|
-
if (!shouldSynthesizeToolProgressForItem(item) || !this.
|
|
1798
|
+
if (!shouldSynthesizeToolProgressForItem(item) || !matchesCodexSnapshotTurn(item, this.turnId) || this.completedItemIds.has(item.id) || itemStatus(item) === "running") return;
|
|
1835
1799
|
if (!this.activeItemIds.has(item.id)) {
|
|
1836
1800
|
this.eventProjection.emitStandardItemEvent({
|
|
1837
1801
|
phase: "start",
|
|
@@ -1842,6 +1806,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1842
1806
|
item
|
|
1843
1807
|
});
|
|
1844
1808
|
}
|
|
1809
|
+
if (this.projectionClosed) return;
|
|
1845
1810
|
this.activeItemIds.delete(item.id);
|
|
1846
1811
|
this.eventProjection.emitStandardItemEvent({
|
|
1847
1812
|
phase: "end",
|
|
@@ -1853,10 +1818,6 @@ var CodexAppServerEventProjector = class {
|
|
|
1853
1818
|
});
|
|
1854
1819
|
this.completedItemIds.add(item.id);
|
|
1855
1820
|
}
|
|
1856
|
-
isCurrentTurnSnapshotItem(item) {
|
|
1857
|
-
const itemTurnId = readItemString(item, "turnId");
|
|
1858
|
-
return itemTurnId === void 0 || itemTurnId === this.turnId;
|
|
1859
|
-
}
|
|
1860
1821
|
async handleRawResponseItemCompleted(params) {
|
|
1861
1822
|
const item = isJsonObject(params.item) ? params.item : void 0;
|
|
1862
1823
|
if (!item) return;
|
|
@@ -1877,17 +1838,8 @@ var CodexAppServerEventProjector = class {
|
|
|
1877
1838
|
presentationOnly: true
|
|
1878
1839
|
});
|
|
1879
1840
|
}
|
|
1880
|
-
formatCodexErrorMessage(params) {
|
|
1881
|
-
const error = isJsonObject(params.error) ? params.error : void 0;
|
|
1882
|
-
const usageLimitMessage = formatCodexUsageLimitErrorMessage({
|
|
1883
|
-
message: error ? readStringField(error, "message") : void 0,
|
|
1884
|
-
codexErrorInfo: error?.codexErrorInfo,
|
|
1885
|
-
rateLimits: this.options.readRecentRateLimits?.()
|
|
1886
|
-
});
|
|
1887
|
-
return usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : readCodexErrorNotificationMessage(params);
|
|
1888
|
-
}
|
|
1889
1841
|
emitAgentEvent(event) {
|
|
1890
|
-
emitCodexAgentEvent(this.params, event);
|
|
1842
|
+
if (!this.projectionClosed) emitCodexAgentEvent(this.params, event);
|
|
1891
1843
|
}
|
|
1892
1844
|
isHookNotificationForCurrentThread(params) {
|
|
1893
1845
|
const threadId = readStringField(params, "threadId");
|
|
@@ -1896,22 +1848,8 @@ var CodexAppServerEventProjector = class {
|
|
|
1896
1848
|
}
|
|
1897
1849
|
};
|
|
1898
1850
|
//#endregion
|
|
1899
|
-
//#region extensions/codex/src/app-server/mcp-tool-metadata.ts
|
|
1900
|
-
/** Hosted app ownership is authoritative only on metadata supplied by Codex. */
|
|
1901
|
-
function readCodexMcpToolConnectorId(tool) {
|
|
1902
|
-
const metadata = asOptionalRecord(asOptionalRecord(tool)?.["_meta"]);
|
|
1903
|
-
return normalizeOptionalString(metadata?.connector_id) ?? normalizeOptionalString(metadata?.connectorId);
|
|
1904
|
-
}
|
|
1905
|
-
/** Preserve MCP App visibility so model-only tools cannot become widget authority. */
|
|
1906
|
-
function readCodexMcpToolUiVisibility(tool) {
|
|
1907
|
-
const metadata = asOptionalRecord(asOptionalRecord(tool)?.["_meta"]);
|
|
1908
|
-
const visibility = asOptionalRecord(metadata?.ui)?.visibility;
|
|
1909
|
-
if (!Array.isArray(visibility)) return;
|
|
1910
|
-
return [...new Set(visibility.filter((value) => value === "app" || value === "model"))].toSorted();
|
|
1911
|
-
}
|
|
1912
|
-
//#endregion
|
|
1913
1851
|
//#region extensions/codex/src/app-server/native-mcp-app.ts
|
|
1914
|
-
const CODEX_APPS_MCP_SERVER
|
|
1852
|
+
const CODEX_APPS_MCP_SERVER = "codex_apps";
|
|
1915
1853
|
function readMcpAppResourceUri(item) {
|
|
1916
1854
|
const appContext = asOptionalRecord(item.appContext);
|
|
1917
1855
|
const uri = normalizeOptionalString(appContext?.resourceUri) ?? normalizeOptionalString(item.mcpAppResourceUri);
|
|
@@ -1995,7 +1933,7 @@ function createNativeMcpRuntime(params) {
|
|
|
1995
1933
|
return { tools: status ? statusTools(status) : [] };
|
|
1996
1934
|
},
|
|
1997
1935
|
readResource: async (serverName, uri) => {
|
|
1998
|
-
const isCodexAppsServer = serverName === CODEX_APPS_MCP_SERVER
|
|
1936
|
+
const isCodexAppsServer = serverName === CODEX_APPS_MCP_SERVER;
|
|
1999
1937
|
const response = await params.client.request("mcpServer/resource/read", {
|
|
2000
1938
|
threadId: params.threadId,
|
|
2001
1939
|
...isCodexAppsServer ? { originCallId: params.originCallId } : {},
|
|
@@ -2025,7 +1963,7 @@ function createCodexNativeMcpAppResultDetailsPreparer(params) {
|
|
|
2025
1963
|
const connectorId = readMcpAppConnectorId(item);
|
|
2026
1964
|
const toolResult = readMcpToolResult(item);
|
|
2027
1965
|
if (!serverName || !toolName || !uiResourceUri || !toolResult) return;
|
|
2028
|
-
if (serverName === CODEX_APPS_MCP_SERVER
|
|
1966
|
+
if (serverName === CODEX_APPS_MCP_SERVER && !connectorId) return;
|
|
2029
1967
|
const runtime = createNativeMcpRuntime({
|
|
2030
1968
|
...params,
|
|
2031
1969
|
originCallId: item.id,
|
|
@@ -2034,7 +1972,7 @@ function createCodexNativeMcpAppResultDetailsPreparer(params) {
|
|
|
2034
1972
|
const tools = (await runtime.listTools?.(serverName))?.tools ?? [];
|
|
2035
1973
|
const allowedAppToolNames = new Set(tools.filter((tool) => {
|
|
2036
1974
|
const uiVisibility = readCodexMcpToolUiVisibility(tool);
|
|
2037
|
-
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);
|
|
2038
1976
|
}).map((tool) => tool.name));
|
|
2039
1977
|
if (!allowedAppToolNames.has(toolName)) return;
|
|
2040
1978
|
return await prepareHarnessNativeMcpAppPreview({
|
|
@@ -2401,14 +2339,14 @@ function declineElicitation(message) {
|
|
|
2401
2339
|
}
|
|
2402
2340
|
//#endregion
|
|
2403
2341
|
//#region extensions/codex/src/app-server/run-attempt-active-turn.ts
|
|
2404
|
-
|
|
2342
|
+
function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, turn) {
|
|
2405
2343
|
const { prompt, state: resourceState, projectorRef, trajectoryRecorder, pendingNativePreToolUseFailures } = resources;
|
|
2406
2344
|
const { context, turnState } = prompt;
|
|
2407
|
-
const { runtime, attemptTools } = context;
|
|
2345
|
+
const { runtime, attemptTools, hookContext } = context;
|
|
2408
2346
|
const { connection } = runtime;
|
|
2409
|
-
const { params, runAbortController, terminalState, abortExplicitly, abortFromUpstream,
|
|
2347
|
+
const { params, runAbortController, terminalState, abortExplicitly, abortFromUpstream, sessionAgentId, contextSessionKey, effectiveCwd } = connection;
|
|
2410
2348
|
const { dynamicToolParams, compactionPlanState, computerContextEpoch, toolBridge } = attemptTools;
|
|
2411
|
-
const { state, userInputBridgeRef, steeringQueueRef,
|
|
2349
|
+
const { state, completion, userInputBridgeRef, steeringQueueRef, deadlines, noteProgress, completeTurn, interruptTurn } = turnRuntime;
|
|
2412
2350
|
const { emitExecutionPhaseOnce, emitLifecycleStart, maybeAnnounceFastModeAutoOff } = lifecycle;
|
|
2413
2351
|
const { enqueueNotification } = notifications;
|
|
2414
2352
|
const activeTurnId = turn.turn.id;
|
|
@@ -2446,6 +2384,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2446
2384
|
return dynamicToolParams.onAgentEvent?.(event);
|
|
2447
2385
|
}
|
|
2448
2386
|
}, resourceState.thread.threadId, activeTurnId, {
|
|
2387
|
+
agentHookContext: hookContext,
|
|
2449
2388
|
initialContextTokens: connection.mutable.startupContextTokens,
|
|
2450
2389
|
nativePostToolUseRelayEnabled: resourceState.nativeHookRelay?.allowedEvents.includes("post_tool_use") === true && resourceState.nativeHookRelay.shouldRelayEvent("post_tool_use"),
|
|
2451
2390
|
asyncUserMessageAllowed: params.disableTools !== true && (params.toolsAllow === void 0 || toolBridge.availableTools.some((tool) => tool.name === "message")),
|
|
@@ -2507,13 +2446,27 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2507
2446
|
}
|
|
2508
2447
|
}
|
|
2509
2448
|
});
|
|
2510
|
-
if (isTerminalTurnStatus(turn.turn.status))
|
|
2449
|
+
if (isTerminalTurnStatus(turn.turn.status)) {
|
|
2450
|
+
state.terminalTurnNotificationQueued = true;
|
|
2451
|
+
deadlines.beginSettlement(Date.now());
|
|
2452
|
+
}
|
|
2511
2453
|
emitLifecycleStart();
|
|
2512
2454
|
const activeProjector = projectorRef.current;
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
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();
|
|
2517
2470
|
for (const failure of pendingNativePreToolUseFailures.splice(0)) activeProjector.recordNativeToolPreToolUseFailure(failure);
|
|
2518
2471
|
const notifyUserMessagePersisted = createCodexAppServerUserMessagePersistenceNotifier(params);
|
|
2519
2472
|
const promptMirrorPromise = mirrorPromptAtTurnStartBestEffort({
|
|
@@ -2526,35 +2479,40 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2526
2479
|
turnId: activeTurnId,
|
|
2527
2480
|
upstreamUserText: turnState.codexTurnPromptText
|
|
2528
2481
|
});
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
if (!state.completed && isTerminalTurnStatus(turn.turn.status)) {
|
|
2541
|
-
if (!isJsonObject(turn.turn)) throw new Error("Codex turn completion payload is not a JSON object");
|
|
2542
|
-
await enqueueNotification({
|
|
2543
|
-
method: "turn/completed",
|
|
2544
|
-
params: {
|
|
2545
|
-
threadId: resourceState.thread.threadId,
|
|
2546
|
-
turnId: activeTurnId,
|
|
2547
|
-
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;
|
|
2548
2493
|
}
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
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
|
+
};
|
|
2554
2512
|
const assertSteeringActive = () => {
|
|
2555
2513
|
params.hostCapabilities.assertActive();
|
|
2556
2514
|
runAbortController.signal.throwIfAborted();
|
|
2557
|
-
if (state.completed || state.terminalTurnNotificationQueued
|
|
2515
|
+
if (state.completed || state.terminalTurnNotificationQueued) throw new Error("codex app-server turn is no longer accepting steering");
|
|
2558
2516
|
};
|
|
2559
2517
|
const workspaceOnly = resolveAttemptFsWorkspaceOnly({
|
|
2560
2518
|
config: params.config,
|
|
@@ -2675,12 +2633,13 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2675
2633
|
cancelPendingUserInput,
|
|
2676
2634
|
queueMessage,
|
|
2677
2635
|
messageInjection: {
|
|
2678
|
-
isAvailable: () => !state.completed && !state.terminalTurnNotificationQueued && !
|
|
2636
|
+
isAvailable: () => !state.completed && !state.terminalTurnNotificationQueued && !runAbortController.signal.aborted,
|
|
2679
2637
|
queueMessage
|
|
2680
2638
|
},
|
|
2681
2639
|
isStreaming: () => !state.completed && !runAbortController.signal.aborted,
|
|
2682
2640
|
isAborted: () => runAbortController.signal.aborted,
|
|
2683
|
-
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,
|
|
2684
2643
|
isAbortable: () => !terminalState.terminalOutcomeFrozen || terminalState.sharedAbortAllowedAfterTerminalOutcome,
|
|
2685
2644
|
isCompacting: () => projectorRef.current?.isCompacting() ?? false,
|
|
2686
2645
|
supportsTranscriptCommitWait: true,
|
|
@@ -2697,36 +2656,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2697
2656
|
terminalState.terminalOutcomeFrozen = true;
|
|
2698
2657
|
params.abortSignal?.removeEventListener("abort", abortFromUpstream);
|
|
2699
2658
|
};
|
|
2700
|
-
|
|
2701
|
-
if (state.timedOut) {
|
|
2702
|
-
(async () => {
|
|
2703
|
-
if (resourceState.thread.connectionScope !== "supervision") await bindingStore.mutate(bindingIdentity, {
|
|
2704
|
-
kind: "clear",
|
|
2705
|
-
threadId: resourceState.thread.threadId
|
|
2706
|
-
});
|
|
2707
|
-
await retireCodexAppServerClientAfterTimedOutTurn(resourceState.client, {
|
|
2708
|
-
threadId: resourceState.thread.threadId,
|
|
2709
|
-
turnId: activeTurnId,
|
|
2710
|
-
reason: String(runAbortController.signal.reason ?? "timeout"),
|
|
2711
|
-
suspectPhysicalClient: state.turnWatchTimeoutKind === "terminal"
|
|
2712
|
-
});
|
|
2713
|
-
})().finally(completeTurn);
|
|
2714
|
-
return;
|
|
2715
|
-
}
|
|
2716
|
-
state.abortCleanup = interruptTurn(activeTurnId).then(async (confirmed) => {
|
|
2717
|
-
if (!terminalState.explicitCancellationObserved && !state.permissionChangeRestart) return;
|
|
2718
|
-
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.");
|
|
2719
|
-
await terminateCodexBackgroundTerminals(resourceState.client, resourceState.thread.threadId);
|
|
2720
|
-
if (state.permissionChangeRestart) state.permissionChangeRestart = "confirmed";
|
|
2721
|
-
});
|
|
2722
|
-
state.abortCleanup.then(completeTurn, (error) => {
|
|
2723
|
-
embeddedAgentLog.warn("codex app-server cancellation cleanup failed", { error });
|
|
2724
|
-
completeTurn();
|
|
2725
|
-
});
|
|
2726
|
-
};
|
|
2727
|
-
runAbortController.signal.addEventListener("abort", abortListener, { once: true });
|
|
2728
|
-
if (runAbortController.signal.aborted) abortListener();
|
|
2729
|
-
else if (params.permissionChange && !params.permissionChange.applied()) {
|
|
2659
|
+
if (!runAbortController.signal.aborted && params.permissionChange && !params.permissionChange.applied()) {
|
|
2730
2660
|
state.permissionChangeRestart = "requested";
|
|
2731
2661
|
runAbortController.abort("permission-change");
|
|
2732
2662
|
}
|
|
@@ -2737,7 +2667,8 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2737
2667
|
handle,
|
|
2738
2668
|
freezeRunTerminalOutcome,
|
|
2739
2669
|
notifyUserMessagePersisted,
|
|
2740
|
-
abortListener
|
|
2670
|
+
abortListener,
|
|
2671
|
+
ready: bindProjection()
|
|
2741
2672
|
};
|
|
2742
2673
|
}
|
|
2743
2674
|
//#endregion
|
|
@@ -2746,12 +2677,15 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2746
2677
|
const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, releaseSharedClientLeaseAndRetireOneShotClient, releaseSandboxExecEnvironment, runCleanupStep } = resources;
|
|
2747
2678
|
const { connection } = prompt.context.runtime;
|
|
2748
2679
|
const { params, options, runAbortController, terminalState, bindingStore, bindingIdentity } = connection;
|
|
2749
|
-
const { state, steeringQueueRef, userInputBridgeRef,
|
|
2680
|
+
const { state, steeringQueueRef, userInputBridgeRef, deadlines } = turnRuntime;
|
|
2750
2681
|
const { maybeEmitFastModeAutoResetBestEffort, emitLifecycleTerminal, buildLifecycleTerminalMeta } = lifecycle;
|
|
2751
2682
|
const { codexModelCallDiagnostics } = requestRuntime;
|
|
2752
2683
|
const { activeTurnId, abortListener, handle, freezeRunTerminalOutcome } = activeTurn;
|
|
2753
2684
|
prompt.context.attemptTools.scheduledAppAuthoritySourceRef.current = void 0;
|
|
2754
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;
|
|
2755
2689
|
await state.abortCleanup.catch(() => void 0);
|
|
2756
2690
|
try {
|
|
2757
2691
|
steeringQueueRef.current?.cancel();
|
|
@@ -2762,32 +2696,32 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2762
2696
|
error: "codex app-server run completed without lifecycle terminal event",
|
|
2763
2697
|
...buildLifecycleTerminalMeta({
|
|
2764
2698
|
aborted: runAbortController.signal.aborted && !state.clientClosedAbort,
|
|
2765
|
-
timedOut: state.
|
|
2699
|
+
timedOut: state.timeout !== void 0
|
|
2766
2700
|
})
|
|
2767
2701
|
});
|
|
2768
2702
|
if (trajectoryRecorder && !resourceState.trajectoryEndRecorded) trajectoryRecorder.recordEvent("session.ended", {
|
|
2769
|
-
status: state.
|
|
2703
|
+
status: state.timeout || runAbortController.signal.aborted && !state.clientClosedAbort ? "interrupted" : "cleanup",
|
|
2770
2704
|
threadId: resourceState.thread.threadId,
|
|
2771
2705
|
turnId: activeTurnId,
|
|
2772
|
-
timedOut: state.
|
|
2706
|
+
timedOut: state.timeout !== void 0,
|
|
2773
2707
|
aborted: runAbortController.signal.aborted && !state.clientClosedAbort
|
|
2774
2708
|
});
|
|
2775
2709
|
await runCleanupStep("codex-trajectory-flush", () => trajectoryRecorder?.flush());
|
|
2776
2710
|
const retainLiveIncognitoThread = (terminalState.turnSucceeded || state.permissionChangeRestart === "confirmed" && !params.abortSignal?.aborted) && isIncognitoSessionKey(params.sessionKey);
|
|
2777
|
-
const
|
|
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 () => {
|
|
2778
2712
|
if ((await bindingStore.read(bindingIdentity))?.threadId !== resourceState.thread.threadId) return false;
|
|
2779
2713
|
return await retainCodexAppServerBindingSubscription(resourceState.client, resourceState.thread.threadId, {
|
|
2780
2714
|
release: resourceState.thread.liveThreadOwnership?.release,
|
|
2781
2715
|
configFingerprint: resourceState.thread.liveThreadConfigFingerprint,
|
|
2782
|
-
serviceTier: connection.mutable.pluginAppServer.serviceTier
|
|
2716
|
+
serviceTier: connection.mutable.pluginAppServer.serviceTier,
|
|
2717
|
+
ephemeralPolicy: resourceState.thread.liveThreadEphemeralPolicy
|
|
2783
2718
|
});
|
|
2784
|
-
}) : false;
|
|
2785
|
-
const
|
|
2786
|
-
const bindingReleased = isIncognitoSessionKey(params.sessionKey) && !retainLiveIncognitoThread ? await bindingStore.mutate(bindingIdentity, {
|
|
2719
|
+
}) : false) || retainLiveIncognitoThread && resourceState.thread.liveThreadEphemeralPolicy === void 0;
|
|
2720
|
+
const bindingReleased = isIncognitoSessionKey(params.sessionKey) && !retainLiveThread ? await bindingStore.mutate(bindingIdentity, {
|
|
2787
2721
|
kind: "clear",
|
|
2788
2722
|
threadId: resourceState.thread.threadId
|
|
2789
2723
|
}) : true;
|
|
2790
|
-
if (!
|
|
2724
|
+
if (!retainLiveThread) {
|
|
2791
2725
|
if (bindingReleased) {
|
|
2792
2726
|
if (!await unsubscribeCodexThreadBestEffort(resourceState.client, {
|
|
2793
2727
|
threadId: resourceState.thread.threadId,
|
|
@@ -2797,14 +2731,14 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2797
2731
|
}
|
|
2798
2732
|
} finally {
|
|
2799
2733
|
await runCleanupStep("codex-user-input-cancel", () => userInputBridgeRef.current?.cancelPending());
|
|
2800
|
-
await runCleanupStep("codex-turn-
|
|
2734
|
+
await runCleanupStep("codex-turn-deadline-clear", () => deadlines.dispose());
|
|
2801
2735
|
await runCleanupStep("codex-dynamic-tool-cleanup", async () => {
|
|
2802
|
-
const cleanupReason = terminalState.turnSucceeded ? "completion" : state.
|
|
2736
|
+
const cleanupReason = terminalState.turnSucceeded ? "completion" : state.timeout ? "timeout" : runAbortController.signal.aborted ? "cancel" : "error";
|
|
2803
2737
|
const cleanups = prompt.context.attemptTools.runCleanups.splice(0);
|
|
2804
2738
|
await Promise.allSettled(cleanups.map(async (cleanup) => await cleanup(cleanupReason)));
|
|
2805
2739
|
});
|
|
2806
2740
|
await runCleanupStep("codex-route-release", releaseCurrentRoute);
|
|
2807
|
-
await
|
|
2741
|
+
await checkpointCleanup;
|
|
2808
2742
|
await runCleanupStep("codex-shared-client-release", releaseSharedClientLeaseAndRetireOneShotClient);
|
|
2809
2743
|
const nativeHookRelay = resourceState.nativeHookRelay;
|
|
2810
2744
|
resourceState.nativeHookRelay = void 0;
|
|
@@ -2818,7 +2752,7 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2818
2752
|
});
|
|
2819
2753
|
await runCleanupStep("codex-sandbox-release", releaseSandboxExecEnvironment);
|
|
2820
2754
|
await runCleanupStep("codex-scoped-mcp-dispose", () => prompt.context.attemptTools.scopedMcpTools?.dispose());
|
|
2821
|
-
await runCleanupStep("codex-
|
|
2755
|
+
await runCleanupStep("codex-configured-mcp-dispose", () => prompt.context.attemptTools.configuredMcp?.dispose());
|
|
2822
2756
|
await runCleanupStep("codex-abort-listener-remove", () => {
|
|
2823
2757
|
runAbortController.signal.removeEventListener("abort", abortListener);
|
|
2824
2758
|
});
|
|
@@ -3249,7 +3183,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3249
3183
|
assertLocalTargetSupported(sandbox?.enabled === true || remoteExec);
|
|
3250
3184
|
const preparedShellEnvironment = preparedEnvironment ? {
|
|
3251
3185
|
...preparedEnvironment.credentialScrubEnv,
|
|
3252
|
-
|
|
3186
|
+
...sandbox?.enabled || remoteExec ? void 0 : preparedEnvironment.localIdentityEnv,
|
|
3253
3187
|
...preparedEnvironment.localProcessEnv
|
|
3254
3188
|
} : void 0;
|
|
3255
3189
|
const shellEnvironment = preparedShellEnvironment && Object.keys(preparedShellEnvironment).length > 0 ? preparedShellEnvironment : void 0;
|
|
@@ -3277,7 +3211,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3277
3211
|
preDynamicStartupStages.mark("session-agent");
|
|
3278
3212
|
let activeContextEngine = isActiveHarnessContextEngine(params.contextEngine) ? params.contextEngine : void 0;
|
|
3279
3213
|
const isInactiveThreadBootstrapBinding = (binding) => !activeContextEngine && binding?.contextEngine?.projection?.mode === "thread_bootstrap";
|
|
3280
|
-
if (bindingIdentity.kind === "session" && bindingIdentity.sessionKey
|
|
3214
|
+
if (bindingIdentity.kind === "session" && bindingIdentity.sessionKey) {
|
|
3281
3215
|
const authority = resolveCodexRunSessionBindingAuthority({
|
|
3282
3216
|
identity: bindingIdentity,
|
|
3283
3217
|
config: params.config,
|
|
@@ -3554,615 +3488,6 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
3554
3488
|
};
|
|
3555
3489
|
}
|
|
3556
3490
|
//#endregion
|
|
3557
|
-
//#region extensions/codex/src/app-server/attempt-context.ts
|
|
3558
|
-
/**
|
|
3559
|
-
* Builds Codex app-server prompt context, workspace bootstrap injections,
|
|
3560
|
-
* system-prompt reports, and context-engine projection decisions.
|
|
3561
|
-
*/
|
|
3562
|
-
const CODEX_NATIVE_PROJECT_DOC_BASENAMES = /* @__PURE__ */ new Set(["agents.md"]);
|
|
3563
|
-
const CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = /* @__PURE__ */ new Set([
|
|
3564
|
-
"identity.md",
|
|
3565
|
-
"soul.md",
|
|
3566
|
-
"user.md"
|
|
3567
|
-
]);
|
|
3568
|
-
const CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = new Set(CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES);
|
|
3569
|
-
const CODEX_MEMORY_CONTEXT_BASENAME = "memory.md";
|
|
3570
|
-
const CODEX_MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set(["memory_search", "memory_get"]);
|
|
3571
|
-
const CODEX_BOOTSTRAP_CONTEXT_ORDER = /* @__PURE__ */ new Map([
|
|
3572
|
-
["soul.md", 10],
|
|
3573
|
-
["identity.md", 20],
|
|
3574
|
-
["user.md", 30],
|
|
3575
|
-
["bootstrap.md", 50],
|
|
3576
|
-
["memory.md", 60]
|
|
3577
|
-
]);
|
|
3578
|
-
/** Reads mirrored Codex session history for harness hooks. */
|
|
3579
|
-
async function readMirroredSessionHistoryMessages(params) {
|
|
3580
|
-
const { admission, ...target } = params;
|
|
3581
|
-
const messages = await readCodexMirroredSessionHistoryMessages(target, admission, "model-context");
|
|
3582
|
-
if (!messages) embeddedAgentLog.warn("failed to read mirrored session history for codex harness hooks", { sessionFile: params.sessionFile });
|
|
3583
|
-
return messages;
|
|
3584
|
-
}
|
|
3585
|
-
/** Reads a valid thread-bootstrap projection request from context-engine output. */
|
|
3586
|
-
function readContextEngineThreadBootstrapProjection(projection) {
|
|
3587
|
-
if (projection?.mode !== "thread_bootstrap") return;
|
|
3588
|
-
const epoch = projection.epoch?.trim();
|
|
3589
|
-
if (!epoch) {
|
|
3590
|
-
embeddedAgentLog.warn("context engine requested Codex thread-bootstrap projection without an epoch; using per-turn projection");
|
|
3591
|
-
return;
|
|
3592
|
-
}
|
|
3593
|
-
const fingerprint = projection.fingerprint?.trim();
|
|
3594
|
-
return {
|
|
3595
|
-
mode: "thread_bootstrap",
|
|
3596
|
-
epoch,
|
|
3597
|
-
...fingerprint ? { fingerprint } : {}
|
|
3598
|
-
};
|
|
3599
|
-
}
|
|
3600
|
-
/**
|
|
3601
|
-
* Decides whether an existing Codex thread can reuse its context-engine
|
|
3602
|
-
* bootstrap projection or must be reprojected.
|
|
3603
|
-
*/
|
|
3604
|
-
function resolveContextEngineBootstrapProjectionDecision(params) {
|
|
3605
|
-
const bindingProjection = params.startupBinding?.contextEngine?.projection;
|
|
3606
|
-
if (!params.startupBinding?.threadId || !bindingProjection) return {
|
|
3607
|
-
project: true,
|
|
3608
|
-
reason: !params.startupBinding?.threadId ? "missing-thread-binding" : "missing-projection-binding"
|
|
3609
|
-
};
|
|
3610
|
-
if (!params.expectedBinding || !isContextEngineBindingCompatible(params.startupBinding.contextEngine, params.expectedBinding)) return {
|
|
3611
|
-
project: true,
|
|
3612
|
-
reason: "context-engine-binding-mismatch"
|
|
3613
|
-
};
|
|
3614
|
-
if (!areCodexDynamicToolFingerprintsCompatible({
|
|
3615
|
-
previous: params.startupBinding.dynamicToolsFingerprint,
|
|
3616
|
-
next: params.dynamicToolsFingerprint,
|
|
3617
|
-
nextLegacy: params.legacyDynamicToolsFingerprint
|
|
3618
|
-
})) return {
|
|
3619
|
-
project: true,
|
|
3620
|
-
reason: "dynamic-tools-mismatch"
|
|
3621
|
-
};
|
|
3622
|
-
return bindingProjection.mode !== "thread_bootstrap" || bindingProjection.epoch !== params.projection.epoch || bindingProjection.fingerprint !== params.projection.fingerprint ? {
|
|
3623
|
-
project: true,
|
|
3624
|
-
reason: "projection-mismatch"
|
|
3625
|
-
} : {
|
|
3626
|
-
project: false,
|
|
3627
|
-
reason: "matching-thread-bootstrap-binding"
|
|
3628
|
-
};
|
|
3629
|
-
}
|
|
3630
|
-
/**
|
|
3631
|
-
* Loads workspace bootstrap files and partitions them into Codex-native prompt,
|
|
3632
|
-
* developer-instruction, heartbeat, and memory-tool contexts.
|
|
3633
|
-
*/
|
|
3634
|
-
async function buildCodexWorkspaceBootstrapContext(params) {
|
|
3635
|
-
try {
|
|
3636
|
-
const inheritsAgentWorkspace = (params.executionWorkspace ?? params.resolvedWorkspace) !== params.resolvedWorkspace;
|
|
3637
|
-
const promptWorkspace = inheritsAgentWorkspace ? params.resolvedWorkspace : params.effectiveWorkspace;
|
|
3638
|
-
const memoryToolsAvailable = params.memoryToolNames.length > 0 && canRouteCodexWorkspaceMemoryThroughTools({
|
|
3639
|
-
config: params.params.config,
|
|
3640
|
-
agentId: params.params.agentId ?? params.sessionAgentId,
|
|
3641
|
-
workspaceDir: inheritsAgentWorkspace ? params.resolvedWorkspace : params.effectiveWorkspace
|
|
3642
|
-
});
|
|
3643
|
-
const bootstrapFiles = await resolveBootstrapFilesForRun({
|
|
3644
|
-
workspaceDir: params.resolvedWorkspace,
|
|
3645
|
-
config: params.params.config,
|
|
3646
|
-
sessionKey: params.sessionKey,
|
|
3647
|
-
sessionId: params.params.sessionId,
|
|
3648
|
-
chatType: params.params.chatType,
|
|
3649
|
-
agentId: params.params.agentId ?? params.sessionAgentId,
|
|
3650
|
-
warn: (message) => embeddedAgentLog.warn(message),
|
|
3651
|
-
contextMode: params.params.bootstrapContextMode,
|
|
3652
|
-
runKind: params.params.bootstrapContextRunKind
|
|
3653
|
-
});
|
|
3654
|
-
const memoryToolRoutedBootstrapFiles = memoryToolsAvailable ? selectCodexWorkspaceMemoryReferenceFiles({
|
|
3655
|
-
bootstrapFiles,
|
|
3656
|
-
workspaceDir: params.resolvedWorkspace
|
|
3657
|
-
}) : [];
|
|
3658
|
-
const memoryReferenceFiles = memoryToolRoutedBootstrapFiles.map((file) => remapCodexContextFilePath({
|
|
3659
|
-
file: toCodexEmbeddedContextFile(file),
|
|
3660
|
-
sourceWorkspaceDir: params.resolvedWorkspace,
|
|
3661
|
-
targetWorkspaceDir: promptWorkspace
|
|
3662
|
-
}));
|
|
3663
|
-
const contextFiles = buildBootstrapContextForFiles(memoryToolsAvailable ? bootstrapFiles.filter((file) => !isCodexWorkspaceRootMemoryBootstrapFile({
|
|
3664
|
-
file,
|
|
3665
|
-
workspaceDir: params.resolvedWorkspace
|
|
3666
|
-
})) : bootstrapFiles, {
|
|
3667
|
-
config: params.params.config,
|
|
3668
|
-
agentId: params.params.agentId ?? params.sessionAgentId,
|
|
3669
|
-
warn: (message) => embeddedAgentLog.warn(message)
|
|
3670
|
-
}).map((file) => remapCodexContextFilePath({
|
|
3671
|
-
file,
|
|
3672
|
-
sourceWorkspaceDir: params.resolvedWorkspace,
|
|
3673
|
-
targetWorkspaceDir: promptWorkspace
|
|
3674
|
-
}));
|
|
3675
|
-
const promptContextFiles = selectCodexWorkspacePromptContextFiles(contextFiles, {
|
|
3676
|
-
excludeMemory: memoryToolsAvailable,
|
|
3677
|
-
memoryWorkspaceDir: params.effectiveWorkspace
|
|
3678
|
-
});
|
|
3679
|
-
const injectOpenClawContext = shouldInjectCodexOpenClawPromptContext(params.params);
|
|
3680
|
-
const restrictedProjectDocNeedsOpenClawCarrier = params.params.pluginHarnessToolPolicyRestricted === true && !params.params.disableTools && !isMessageOnlyCodexSourceReply(params.params) && params.params.bootstrapContextMode !== "lightweight";
|
|
3681
|
-
const threadDeveloperInstructionFiles = injectOpenClawContext && !params.ringZeroActive && (inheritsAgentWorkspace || restrictedProjectDocNeedsOpenClawCarrier) ? selectCodexWorkspaceAgentProjectInstructionFiles(contextFiles, params.resolvedWorkspace) : [];
|
|
3682
|
-
const turnScopedDeveloperInstructionFiles = injectOpenClawContext ? selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) : [];
|
|
3683
|
-
return {
|
|
3684
|
-
bootstrapFiles,
|
|
3685
|
-
contextFiles,
|
|
3686
|
-
inheritsAgentWorkspace,
|
|
3687
|
-
promptContextFiles,
|
|
3688
|
-
threadDeveloperInstructionFiles,
|
|
3689
|
-
turnScopedDeveloperInstructionFiles,
|
|
3690
|
-
memoryReferenceFiles,
|
|
3691
|
-
memoryToolRoutedBootstrapFiles,
|
|
3692
|
-
memoryToolNames: [...params.memoryToolNames],
|
|
3693
|
-
memoryToolRouted: memoryToolsAvailable,
|
|
3694
|
-
promptContext: renderCodexWorkspaceBootstrapPromptContext(promptContextFiles),
|
|
3695
|
-
threadDeveloperInstructions: renderCodexWorkspaceDeveloperInstructions({
|
|
3696
|
-
files: threadDeveloperInstructionFiles,
|
|
3697
|
-
header: "## OpenClaw Agent Workspace Instructions",
|
|
3698
|
-
preamble: "OpenClaw loaded this bounded snapshot from the configured agent workspace."
|
|
3699
|
-
}),
|
|
3700
|
-
turnScopedDeveloperInstructions: renderCodexWorkspaceCollaborationDeveloperInstructions(turnScopedDeveloperInstructionFiles),
|
|
3701
|
-
memoryCollaborationInstructions: shouldInjectCodexOpenClawPromptContext(params.params) ? await renderCodexWorkspaceMemoryCollaborationInstructions({
|
|
3702
|
-
files: memoryReferenceFiles,
|
|
3703
|
-
toolNames: params.memoryToolNames,
|
|
3704
|
-
memoryToolRouted: memoryToolsAvailable,
|
|
3705
|
-
citationsMode: params.params.config?.memory?.citations,
|
|
3706
|
-
agentId: params.params.agentId ?? params.sessionAgentId,
|
|
3707
|
-
agentSessionKey: params.sessionKey,
|
|
3708
|
-
sandboxed: params.sandboxed
|
|
3709
|
-
}) : void 0
|
|
3710
|
-
};
|
|
3711
|
-
} catch (error) {
|
|
3712
|
-
embeddedAgentLog.warn("failed to load codex workspace bootstrap instructions", { error });
|
|
3713
|
-
return {
|
|
3714
|
-
bootstrapFiles: [],
|
|
3715
|
-
contextFiles: [],
|
|
3716
|
-
inheritsAgentWorkspace: false
|
|
3717
|
-
};
|
|
3718
|
-
}
|
|
3719
|
-
}
|
|
3720
|
-
/**
|
|
3721
|
-
* Builds the prompt-size, bootstrap-file, skill, and tool-schema accounting
|
|
3722
|
-
* report for a Codex run.
|
|
3723
|
-
*/
|
|
3724
|
-
function buildCodexSystemPromptReport(params) {
|
|
3725
|
-
const toolEntries = flattenCodexDynamicToolFunctions(params.tools).map(buildCodexToolReportEntry);
|
|
3726
|
-
const schemaChars = toolEntries.reduce((sum, tool) => sum + tool.schemaChars, 0);
|
|
3727
|
-
const skillsPrompt = params.skillsPrompt.trim();
|
|
3728
|
-
const bootstrapMaxChars = readPositiveNumber(params.attempt.config?.agents?.defaults?.bootstrapMaxChars);
|
|
3729
|
-
const bootstrapTotalMaxChars = readPositiveNumber(params.attempt.config?.agents?.defaults?.bootstrapTotalMaxChars);
|
|
3730
|
-
return {
|
|
3731
|
-
source: "run",
|
|
3732
|
-
generatedAt: Date.now(),
|
|
3733
|
-
sessionId: params.attempt.sessionId,
|
|
3734
|
-
sessionKey: params.sessionKey,
|
|
3735
|
-
provider: params.attempt.provider,
|
|
3736
|
-
model: params.attempt.modelId,
|
|
3737
|
-
workspaceDir: params.workspaceDir,
|
|
3738
|
-
...bootstrapMaxChars ? { bootstrapMaxChars } : {},
|
|
3739
|
-
...bootstrapTotalMaxChars ? { bootstrapTotalMaxChars } : {},
|
|
3740
|
-
systemPrompt: {
|
|
3741
|
-
chars: params.developerInstructions.length,
|
|
3742
|
-
projectContextChars: 0,
|
|
3743
|
-
nonProjectContextChars: params.developerInstructions.length,
|
|
3744
|
-
hash: sha256Text(params.developerInstructions)
|
|
3745
|
-
},
|
|
3746
|
-
injectedWorkspaceFiles: buildCodexBootstrapInjectionStats({
|
|
3747
|
-
bootstrapFiles: params.workspaceBootstrapContext.bootstrapFiles,
|
|
3748
|
-
injectedFiles: params.workspaceBootstrapContext.promptContextFiles ?? [],
|
|
3749
|
-
developerInstructionFiles: [...params.workspaceBootstrapContext.threadDeveloperInstructionFiles ?? [], ...params.workspaceBootstrapContext.turnScopedDeveloperInstructionFiles ?? []],
|
|
3750
|
-
memoryToolRoutedBootstrapFiles: params.workspaceBootstrapContext.memoryToolRoutedBootstrapFiles ?? [],
|
|
3751
|
-
memoryToolRouted: params.workspaceBootstrapContext.memoryToolRouted === true
|
|
3752
|
-
}),
|
|
3753
|
-
skills: {
|
|
3754
|
-
promptChars: skillsPrompt.length,
|
|
3755
|
-
hash: sha256Text(skillsPrompt),
|
|
3756
|
-
entries: buildCodexSkillReportEntries(skillsPrompt)
|
|
3757
|
-
},
|
|
3758
|
-
tools: {
|
|
3759
|
-
listChars: 0,
|
|
3760
|
-
schemaChars,
|
|
3761
|
-
entries: toolEntries
|
|
3762
|
-
}
|
|
3763
|
-
};
|
|
3764
|
-
}
|
|
3765
|
-
function buildCodexSkillReportEntries(skillsPrompt) {
|
|
3766
|
-
if (!skillsPrompt) return [];
|
|
3767
|
-
return Array.from(skillsPrompt.matchAll(/<skill>[\s\S]*?<\/skill>/gi)).map((match) => match[0] ?? "").map((block) => ({
|
|
3768
|
-
name: block.match(/<name>\s*([^<]+?)\s*<\/name>/i)?.[1]?.trim() || "(unknown)",
|
|
3769
|
-
blockChars: block.length
|
|
3770
|
-
})).filter((entry) => entry.blockChars > 0);
|
|
3771
|
-
}
|
|
3772
|
-
function buildCodexToolReportEntry(tool) {
|
|
3773
|
-
const summary = tool.description.trim();
|
|
3774
|
-
if (tool.deferLoading === true) return {
|
|
3775
|
-
name: tool.name,
|
|
3776
|
-
summaryChars: summary.length,
|
|
3777
|
-
summaryHash: sha256Text(summary),
|
|
3778
|
-
schemaChars: 0,
|
|
3779
|
-
schemaHash: stableJsonHash(null),
|
|
3780
|
-
propertiesCount: null
|
|
3781
|
-
};
|
|
3782
|
-
return {
|
|
3783
|
-
name: tool.name,
|
|
3784
|
-
summaryChars: summary.length,
|
|
3785
|
-
summaryHash: sha256Text(summary),
|
|
3786
|
-
...buildCodexToolSchemaStats(tool.inputSchema)
|
|
3787
|
-
};
|
|
3788
|
-
}
|
|
3789
|
-
function buildCodexToolSchemaStats(schema) {
|
|
3790
|
-
const schemaChars = (() => {
|
|
3791
|
-
try {
|
|
3792
|
-
return JSON.stringify(schema).length;
|
|
3793
|
-
} catch {
|
|
3794
|
-
return 0;
|
|
3795
|
-
}
|
|
3796
|
-
})();
|
|
3797
|
-
const properties = isJsonObject(schema) && isJsonObject(schema.properties) ? schema.properties : null;
|
|
3798
|
-
return {
|
|
3799
|
-
schemaChars,
|
|
3800
|
-
schemaHash: stableJsonHash(schema),
|
|
3801
|
-
propertiesCount: properties ? Object.keys(properties).length : null
|
|
3802
|
-
};
|
|
3803
|
-
}
|
|
3804
|
-
function sha256Text(value) {
|
|
3805
|
-
return createHash("sha256").update(value).digest("hex");
|
|
3806
|
-
}
|
|
3807
|
-
function normalizeForStableHash(value) {
|
|
3808
|
-
if (Array.isArray(value)) return value.map((entry) => normalizeForStableHash(entry));
|
|
3809
|
-
if (value && typeof value === "object") {
|
|
3810
|
-
const record = value;
|
|
3811
|
-
return Object.fromEntries(Object.keys(record).toSorted((left, right) => left.localeCompare(right)).map((key) => [key, normalizeForStableHash(record[key])]));
|
|
3812
|
-
}
|
|
3813
|
-
return value;
|
|
3814
|
-
}
|
|
3815
|
-
function stableJsonHash(value) {
|
|
3816
|
-
return sha256Text(JSON.stringify(normalizeForStableHash(value)) ?? "null");
|
|
3817
|
-
}
|
|
3818
|
-
function buildCodexBootstrapInjectionStats(params) {
|
|
3819
|
-
const injectedIndex = indexCodexContextFileContent(params.injectedFiles);
|
|
3820
|
-
const developerInstructionIndex = indexCodexContextFileContent(params.developerInstructionFiles ?? []);
|
|
3821
|
-
const memoryToolRoutedPaths = new Set((params.memoryToolRoutedBootstrapFiles ?? []).map((file) => readNonBlankString(file.path)).filter(isNonEmptyString$1).map(normalizeCodexContextFilePath));
|
|
3822
|
-
return params.bootstrapFiles.map((file) => {
|
|
3823
|
-
const fileName = readNonBlankString(file.name);
|
|
3824
|
-
const pathValue = readNonBlankString(file.path) ?? fileName ?? "";
|
|
3825
|
-
const displayName = (fileName ?? getCodexContextFileDisplayBasename(pathValue)) || pathValue;
|
|
3826
|
-
const baseName = getCodexContextFileBasename(pathValue || fileName || "");
|
|
3827
|
-
const rawChars = file.missing ? 0 : (file.content ?? "").trimEnd().length;
|
|
3828
|
-
const memoryToolRoutedFile = baseName === CODEX_MEMORY_CONTEXT_BASENAME && params.memoryToolRouted === true && memoryToolRoutedPaths.has(normalizeCodexContextFilePath(pathValue));
|
|
3829
|
-
const injected = memoryToolRoutedFile ? void 0 : readCodexIndexedContextFileContent(injectedIndex, pathValue, fileName) ?? readCodexIndexedContextFileContent(developerInstructionIndex, pathValue, fileName);
|
|
3830
|
-
if (!file.missing && injected === void 0 && CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName)) return {
|
|
3831
|
-
name: displayName,
|
|
3832
|
-
path: pathValue,
|
|
3833
|
-
missing: false,
|
|
3834
|
-
rawChars,
|
|
3835
|
-
injectionStatus: "native_unverified",
|
|
3836
|
-
injectedChars: null,
|
|
3837
|
-
truncated: null
|
|
3838
|
-
};
|
|
3839
|
-
const injectedChars = memoryToolRoutedFile ? 0 : injected?.length ?? 0;
|
|
3840
|
-
const truncated = memoryToolRoutedFile ? false : !file.missing && injectedChars < rawChars;
|
|
3841
|
-
return {
|
|
3842
|
-
name: displayName,
|
|
3843
|
-
path: pathValue,
|
|
3844
|
-
missing: file.missing,
|
|
3845
|
-
rawChars,
|
|
3846
|
-
injectedChars,
|
|
3847
|
-
truncated
|
|
3848
|
-
};
|
|
3849
|
-
});
|
|
3850
|
-
}
|
|
3851
|
-
function indexCodexContextFileContent(files) {
|
|
3852
|
-
const byPath = /* @__PURE__ */ new Map();
|
|
3853
|
-
const byBaseName = /* @__PURE__ */ new Map();
|
|
3854
|
-
for (const file of files) {
|
|
3855
|
-
const pathValue = readNonBlankString(file.path);
|
|
3856
|
-
if (!pathValue) continue;
|
|
3857
|
-
if (!byPath.has(pathValue)) byPath.set(pathValue, file.content);
|
|
3858
|
-
const baseName = getCodexContextFileBasename(pathValue);
|
|
3859
|
-
if (baseName && !byBaseName.has(baseName)) byBaseName.set(baseName, file.content);
|
|
3860
|
-
}
|
|
3861
|
-
return {
|
|
3862
|
-
byPath,
|
|
3863
|
-
byBaseName
|
|
3864
|
-
};
|
|
3865
|
-
}
|
|
3866
|
-
function readCodexIndexedContextFileContent(index, pathValue, fileName) {
|
|
3867
|
-
const pathContent = index.byPath.get(pathValue);
|
|
3868
|
-
if (pathContent !== void 0) return pathContent;
|
|
3869
|
-
if (fileName) {
|
|
3870
|
-
const nameContent = index.byPath.get(fileName);
|
|
3871
|
-
if (nameContent !== void 0) return nameContent;
|
|
3872
|
-
}
|
|
3873
|
-
const baseName = getCodexContextFileBasename(fileName ?? pathValue);
|
|
3874
|
-
return baseName ? index.byBaseName.get(baseName) : void 0;
|
|
3875
|
-
}
|
|
3876
|
-
function readPositiveNumber(value) {
|
|
3877
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : void 0;
|
|
3878
|
-
}
|
|
3879
|
-
/**
|
|
3880
|
-
* Builds OpenClaw-provided workspace prompt context for the current Codex turn.
|
|
3881
|
-
*/
|
|
3882
|
-
function buildCodexOpenClawPromptContext(params) {
|
|
3883
|
-
if (!shouldInjectCodexOpenClawPromptContext(params.params)) return;
|
|
3884
|
-
const sections = [params.workspacePromptContext?.trim() ? [
|
|
3885
|
-
"## OpenClaw Workspace Context",
|
|
3886
|
-
"",
|
|
3887
|
-
params.workspacePromptContext.trim()
|
|
3888
|
-
].join("\n") : void 0, params.watchedSessionsContext?.trim() || void 0].filter(isNonEmptyString$1);
|
|
3889
|
-
if (sections.length === 0) return;
|
|
3890
|
-
return [
|
|
3891
|
-
"OpenClaw runtime context for this turn:",
|
|
3892
|
-
"Treat this OpenClaw-provided context as supporting project/user reference for the current request.",
|
|
3893
|
-
"",
|
|
3894
|
-
...sections
|
|
3895
|
-
].join("\n");
|
|
3896
|
-
}
|
|
3897
|
-
/**
|
|
3898
|
-
* Renders the watched-sessions block for the Codex per-turn runtime context.
|
|
3899
|
-
* Codex builds its own instruction layers, so the embedded prompt's Watched
|
|
3900
|
-
* Sessions section must be re-surfaced here or Codex-backed main sessions
|
|
3901
|
-
* keep refusing cross-session questions (openclaw#114797).
|
|
3902
|
-
*/
|
|
3903
|
-
function buildCodexWatchedSessionsContext(params) {
|
|
3904
|
-
if (!shouldInjectCodexOpenClawPromptContext(params.attempt)) return;
|
|
3905
|
-
return buildWatchedSessionsHarnessContext({
|
|
3906
|
-
config: params.attempt.config,
|
|
3907
|
-
sessionKey: params.sessionKey,
|
|
3908
|
-
sandboxed: params.sandboxed,
|
|
3909
|
-
toolNames: flattenCodexDynamicToolFunctions(params.dynamicTools).map((tool) => normalizeCodexDynamicToolName(tool.name))
|
|
3910
|
-
});
|
|
3911
|
-
}
|
|
3912
|
-
function shouldInjectCodexOpenClawPromptContext(params) {
|
|
3913
|
-
return !(params.bootstrapContextMode === "lightweight" && params.bootstrapContextRunKind === "cron");
|
|
3914
|
-
}
|
|
3915
|
-
/** Renders loaded OpenClaw skill prompts as Codex collaboration instructions. */
|
|
3916
|
-
function renderCodexSkillsCollaborationInstructions(params) {
|
|
3917
|
-
if (!shouldInjectCodexOpenClawPromptContext(params.attempt)) return;
|
|
3918
|
-
return params.skillsPrompt?.trim() ? [
|
|
3919
|
-
"## OpenClaw Skills",
|
|
3920
|
-
"",
|
|
3921
|
-
params.skillsPrompt.trim()
|
|
3922
|
-
].join("\n") : void 0;
|
|
3923
|
-
}
|
|
3924
|
-
/**
|
|
3925
|
-
* Prepends OpenClaw context while preserving leading delivery metadata as
|
|
3926
|
-
* routing guidance instead of user request text.
|
|
3927
|
-
*/
|
|
3928
|
-
function prependCodexOpenClawPromptContext(prompt, context, options = {}) {
|
|
3929
|
-
const { deliveryHint, prompt: promptWithoutDeliveryHint } = splitLeadingCodexDeliveryHint(prompt);
|
|
3930
|
-
if (!context?.trim() && (!deliveryHint || options.preservePromptWithoutContext)) return prompt;
|
|
3931
|
-
const promptSection = promptWithoutDeliveryHint.startsWith("OpenClaw assembled context for this turn:") ? promptWithoutDeliveryHint : ["Current user request:", promptWithoutDeliveryHint].join("\n");
|
|
3932
|
-
const deliverySection = deliveryHint ? [
|
|
3933
|
-
"OpenClaw delivery metadata:",
|
|
3934
|
-
"This delivery metadata is runtime routing guidance, not the user's request.",
|
|
3935
|
-
deliveryHint
|
|
3936
|
-
].join("\n") : void 0;
|
|
3937
|
-
return [
|
|
3938
|
-
context?.trim(),
|
|
3939
|
-
deliverySection,
|
|
3940
|
-
promptSection
|
|
3941
|
-
].filter(Boolean).join("\n\n");
|
|
3942
|
-
}
|
|
3943
|
-
/**
|
|
3944
|
-
* Maps the surviving user-request portion of an input range after delivery
|
|
3945
|
-
* metadata has been relocated before the request.
|
|
3946
|
-
*/
|
|
3947
|
-
function resolveCodexDeliveryHintPreservedInputRange(params) {
|
|
3948
|
-
const { prompt, promptInputRange, decoratedPrompt } = params;
|
|
3949
|
-
const { deliveryHint, prompt: promptWithoutDeliveryHint } = splitLeadingCodexDeliveryHint(prompt);
|
|
3950
|
-
if (!deliveryHint || !promptInputRange || promptInputRange.start < 0 || promptInputRange.end < promptInputRange.start || promptInputRange.end > prompt.length || !decoratedPrompt.endsWith(promptWithoutDeliveryHint)) return;
|
|
3951
|
-
const promptWithoutDeliveryHintStart = prompt.length - promptWithoutDeliveryHint.length;
|
|
3952
|
-
const inputStart = Math.max(promptInputRange.start, promptWithoutDeliveryHintStart);
|
|
3953
|
-
const inputEnd = Math.max(inputStart, Math.min(promptInputRange.end, promptWithoutDeliveryHint.length + promptWithoutDeliveryHintStart));
|
|
3954
|
-
const decoratedPromptSuffixStart = decoratedPrompt.length - promptWithoutDeliveryHint.length;
|
|
3955
|
-
const requestHeader = "Current user request:\n";
|
|
3956
|
-
const requestHeaderStart = decoratedPromptSuffixStart - 22;
|
|
3957
|
-
return {
|
|
3958
|
-
start: inputStart === promptWithoutDeliveryHintStart && decoratedPrompt.slice(requestHeaderStart, decoratedPromptSuffixStart) === requestHeader ? requestHeaderStart : decoratedPromptSuffixStart + inputStart - promptWithoutDeliveryHintStart,
|
|
3959
|
-
end: decoratedPromptSuffixStart + inputEnd - promptWithoutDeliveryHintStart
|
|
3960
|
-
};
|
|
3961
|
-
}
|
|
3962
|
-
function splitLeadingCodexDeliveryHint(prompt) {
|
|
3963
|
-
const trimmedStart = prompt.trimStart();
|
|
3964
|
-
const matchedHint = MESSAGE_TOOL_DELIVERY_HINTS.find((hint) => trimmedStart.startsWith(hint));
|
|
3965
|
-
if (!matchedHint) return { prompt };
|
|
3966
|
-
return {
|
|
3967
|
-
deliveryHint: matchedHint,
|
|
3968
|
-
prompt: trimmedStart.slice(matchedHint.length).replace(/^\s*\n/, "").trimStart()
|
|
3969
|
-
};
|
|
3970
|
-
}
|
|
3971
|
-
function renderCodexWorkspaceBootstrapPromptContext(contextFiles) {
|
|
3972
|
-
const files = contextFiles;
|
|
3973
|
-
if (files.length === 0) return;
|
|
3974
|
-
const lines = [
|
|
3975
|
-
"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.",
|
|
3976
|
-
"",
|
|
3977
|
-
"# Project Context",
|
|
3978
|
-
"",
|
|
3979
|
-
"The following project context files have been loaded:"
|
|
3980
|
-
];
|
|
3981
|
-
lines.push("");
|
|
3982
|
-
for (const file of files) lines.push(`## ${file.path}`, "", file.content, "");
|
|
3983
|
-
return lines.join("\n").trim();
|
|
3984
|
-
}
|
|
3985
|
-
function selectCodexWorkspacePromptContextFiles(contextFiles, options = {}) {
|
|
3986
|
-
const excludeMemory = options.excludeMemory ?? true;
|
|
3987
|
-
return contextFiles.filter((file) => {
|
|
3988
|
-
const baseName = getCodexContextFileBasename(file.path);
|
|
3989
|
-
return baseName && !CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName) && !CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES.has(baseName) && (!excludeMemory || !isCodexWorkspaceRootMemoryContextFile({
|
|
3990
|
-
file,
|
|
3991
|
-
workspaceDir: options.memoryWorkspaceDir
|
|
3992
|
-
})) && !isMissingCodexBootstrapContextFile(file);
|
|
3993
|
-
}).toSorted(compareCodexContextFiles);
|
|
3994
|
-
}
|
|
3995
|
-
function selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) {
|
|
3996
|
-
return selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES);
|
|
3997
|
-
}
|
|
3998
|
-
function selectCodexWorkspaceAgentProjectInstructionFiles(contextFiles, agentWorkspaceDir) {
|
|
3999
|
-
const agentProjectDocPath = path.join(path.resolve(agentWorkspaceDir), "AGENTS.md");
|
|
4000
|
-
return selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, CODEX_NATIVE_PROJECT_DOC_BASENAMES).filter((file) => path.resolve(file.path) === agentProjectDocPath);
|
|
4001
|
-
}
|
|
4002
|
-
function selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, basenames) {
|
|
4003
|
-
return contextFiles.filter((file) => {
|
|
4004
|
-
const baseName = getCodexContextFileBasename(file.path);
|
|
4005
|
-
return baseName && basenames.has(baseName) && !isMissingCodexBootstrapContextFile(file) && file.content.trim().length > 0;
|
|
4006
|
-
}).toSorted(compareCodexContextFiles);
|
|
4007
|
-
}
|
|
4008
|
-
function renderCodexWorkspaceCollaborationDeveloperInstructions(files) {
|
|
4009
|
-
return renderCodexWorkspaceDeveloperInstructions({
|
|
4010
|
-
files,
|
|
4011
|
-
header: "## OpenClaw Agent Soul",
|
|
4012
|
-
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.",
|
|
4013
|
-
wrapperTag: "AGENT_SOUL"
|
|
4014
|
-
});
|
|
4015
|
-
}
|
|
4016
|
-
function renderCodexWorkspaceDeveloperInstructions(params) {
|
|
4017
|
-
const { files, header, preamble, wrapperTag } = params;
|
|
4018
|
-
if (files.length === 0) return;
|
|
4019
|
-
const lines = [
|
|
4020
|
-
header,
|
|
4021
|
-
"",
|
|
4022
|
-
preamble,
|
|
4023
|
-
""
|
|
4024
|
-
];
|
|
4025
|
-
if (wrapperTag) lines.push(`<${wrapperTag}>`, "");
|
|
4026
|
-
for (const file of files) lines.push(`### ${file.path}`, "", file.content, "");
|
|
4027
|
-
if (wrapperTag) lines.push(`</${wrapperTag}>`);
|
|
4028
|
-
return lines.join("\n").trim();
|
|
4029
|
-
}
|
|
4030
|
-
function selectCodexWorkspaceMemoryReferenceFiles(params) {
|
|
4031
|
-
return params.bootstrapFiles.filter((file) => {
|
|
4032
|
-
return isCodexWorkspaceRootMemoryBootstrapFile({
|
|
4033
|
-
file,
|
|
4034
|
-
workspaceDir: params.workspaceDir
|
|
4035
|
-
}) && !file.missing && (file.content ?? "").trim().length > 0;
|
|
4036
|
-
}).toSorted(compareCodexBootstrapFiles);
|
|
4037
|
-
}
|
|
4038
|
-
/**
|
|
4039
|
-
* Renders a memory-file reference that points Codex at memory tools instead of
|
|
4040
|
-
* embedding MEMORY.md contents.
|
|
4041
|
-
*/
|
|
4042
|
-
function renderCodexWorkspaceMemoryReference(params) {
|
|
4043
|
-
if (params.files.length === 0) return;
|
|
4044
|
-
const lines = [
|
|
4045
|
-
"## OpenClaw Workspace Memory",
|
|
4046
|
-
"",
|
|
4047
|
-
`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.`,
|
|
4048
|
-
""
|
|
4049
|
-
];
|
|
4050
|
-
for (const file of params.files) lines.push(`- ${file.path}`);
|
|
4051
|
-
return lines.join("\n").trim();
|
|
4052
|
-
}
|
|
4053
|
-
async function renderCodexWorkspaceMemoryCollaborationInstructions(params) {
|
|
4054
|
-
const sections = [params.memoryToolRouted ? await renderCodexMemoryRecallInstructions({
|
|
4055
|
-
toolNames: params.toolNames,
|
|
4056
|
-
citationsMode: params.citationsMode,
|
|
4057
|
-
agentId: params.agentId,
|
|
4058
|
-
agentSessionKey: params.agentSessionKey,
|
|
4059
|
-
sandboxed: params.sandboxed
|
|
4060
|
-
}) : void 0, renderCodexWorkspaceMemoryReference({
|
|
4061
|
-
files: params.files,
|
|
4062
|
-
toolNames: params.toolNames
|
|
4063
|
-
})].filter(isNonEmptyString$1);
|
|
4064
|
-
return sections.length > 0 ? sections.join("\n\n") : void 0;
|
|
4065
|
-
}
|
|
4066
|
-
async function renderCodexMemoryRecallInstructions(params) {
|
|
4067
|
-
const availableTools = new Set(params.toolNames);
|
|
4068
|
-
const memoryPrompt = await prepareMemorySystemPromptAddition({
|
|
4069
|
-
availableTools,
|
|
4070
|
-
citationsMode: params.citationsMode,
|
|
4071
|
-
agentId: params.agentId,
|
|
4072
|
-
agentSessionKey: params.agentSessionKey,
|
|
4073
|
-
sandboxed: params.sandboxed
|
|
4074
|
-
});
|
|
4075
|
-
if (!memoryPrompt) return;
|
|
4076
|
-
return [memoryPrompt, renderCodexMemoryToolSearchBridge(params.toolNames)].filter(isNonEmptyString$1).join("\n").trim();
|
|
4077
|
-
}
|
|
4078
|
-
function renderCodexMemoryToolSearchBridge(toolNames) {
|
|
4079
|
-
const memoryToolNames = toolNames.map((name) => normalizeCodexDynamicToolName(name)).filter((name) => CODEX_MEMORY_TOOL_NAMES.has(name)).toSorted();
|
|
4080
|
-
if (memoryToolNames.length === 0) return;
|
|
4081
|
-
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.`;
|
|
4082
|
-
}
|
|
4083
|
-
/** Lists available memory tool names understood by Codex workspace memory routing. */
|
|
4084
|
-
function getCodexWorkspaceMemoryToolNames(tools) {
|
|
4085
|
-
const availableToolNames = new Set(flattenCodexDynamicToolFunctions(tools).map((tool) => normalizeCodexDynamicToolName(tool.name)));
|
|
4086
|
-
return Array.from(CODEX_MEMORY_TOOL_NAMES).filter((name) => availableToolNames.has(name));
|
|
4087
|
-
}
|
|
4088
|
-
function canRouteCodexWorkspaceMemoryThroughTools(params) {
|
|
4089
|
-
if (!params.config) return false;
|
|
4090
|
-
return isSameCodexWorkspacePath(resolveAgentWorkspaceDir(params.config, params.agentId), params.workspaceDir);
|
|
4091
|
-
}
|
|
4092
|
-
function isMissingCodexBootstrapContextFile(file) {
|
|
4093
|
-
return file.content.trimStart().startsWith("[MISSING] Expected at:");
|
|
4094
|
-
}
|
|
4095
|
-
function toCodexEmbeddedContextFile(file) {
|
|
4096
|
-
return {
|
|
4097
|
-
path: readNonBlankString(file.path) ?? readNonBlankString(file.name) ?? "",
|
|
4098
|
-
content: file.content ?? ""
|
|
4099
|
-
};
|
|
4100
|
-
}
|
|
4101
|
-
function isCodexWorkspaceRootMemoryBootstrapFile(params) {
|
|
4102
|
-
return isCodexWorkspaceRootMemoryPath({
|
|
4103
|
-
filePath: readNonBlankString(params.file.path) ?? readNonBlankString(params.file.name) ?? "",
|
|
4104
|
-
workspaceDir: params.workspaceDir
|
|
4105
|
-
});
|
|
4106
|
-
}
|
|
4107
|
-
function isCodexWorkspaceRootMemoryContextFile(params) {
|
|
4108
|
-
if (!params.workspaceDir) return false;
|
|
4109
|
-
return isCodexWorkspaceRootMemoryPath({
|
|
4110
|
-
filePath: params.file.path,
|
|
4111
|
-
workspaceDir: params.workspaceDir
|
|
4112
|
-
});
|
|
4113
|
-
}
|
|
4114
|
-
function isCodexWorkspaceRootMemoryPath(params) {
|
|
4115
|
-
const filePath = params.filePath.trim();
|
|
4116
|
-
if (!filePath) return false;
|
|
4117
|
-
return (path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(params.workspaceDir, filePath)) === path.join(path.resolve(params.workspaceDir), "MEMORY.md");
|
|
4118
|
-
}
|
|
4119
|
-
function isSameCodexWorkspacePath(left, right) {
|
|
4120
|
-
return path.resolve(left) === path.resolve(right);
|
|
4121
|
-
}
|
|
4122
|
-
/**
|
|
4123
|
-
* Remaps bootstrap file paths from the resolved workspace to the effective Codex
|
|
4124
|
-
* workspace while preserving platform path separators.
|
|
4125
|
-
*/
|
|
4126
|
-
function remapCodexContextFilePath(params) {
|
|
4127
|
-
const relativePath = path.relative(params.sourceWorkspaceDir, params.file.path);
|
|
4128
|
-
if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath) || params.sourceWorkspaceDir === params.targetWorkspaceDir) return params.file;
|
|
4129
|
-
const targetUsesPosixSeparators = params.targetWorkspaceDir.includes("/") && !params.targetWorkspaceDir.includes("\\");
|
|
4130
|
-
const normalizedRelativePath = targetUsesPosixSeparators ? relativePath.replaceAll("\\", "/") : relativePath.replaceAll("/", "\\");
|
|
4131
|
-
return {
|
|
4132
|
-
...params.file,
|
|
4133
|
-
path: targetUsesPosixSeparators ? path.posix.join(params.targetWorkspaceDir, normalizedRelativePath) : path.win32.join(params.targetWorkspaceDir, normalizedRelativePath)
|
|
4134
|
-
};
|
|
4135
|
-
}
|
|
4136
|
-
function compareCodexContextFiles(left, right) {
|
|
4137
|
-
const leftPath = normalizeCodexContextFilePath(left.path);
|
|
4138
|
-
const rightPath = normalizeCodexContextFilePath(right.path);
|
|
4139
|
-
const leftBase = getCodexContextFileBasename(left.path);
|
|
4140
|
-
const rightBase = getCodexContextFileBasename(right.path);
|
|
4141
|
-
const leftOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(leftBase) ?? Number.MAX_SAFE_INTEGER;
|
|
4142
|
-
const rightOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(rightBase) ?? Number.MAX_SAFE_INTEGER;
|
|
4143
|
-
if (leftOrder !== rightOrder) return leftOrder - rightOrder;
|
|
4144
|
-
if (leftBase !== rightBase) return leftBase.localeCompare(rightBase);
|
|
4145
|
-
return leftPath.localeCompare(rightPath);
|
|
4146
|
-
}
|
|
4147
|
-
function compareCodexBootstrapFiles(left, right) {
|
|
4148
|
-
return compareCodexContextFiles(toCodexEmbeddedContextFile(left), toCodexEmbeddedContextFile(right));
|
|
4149
|
-
}
|
|
4150
|
-
function normalizeCodexContextFilePath(filePath) {
|
|
4151
|
-
return filePath.trim().replaceAll("\\", "/").toLowerCase();
|
|
4152
|
-
}
|
|
4153
|
-
function getCodexContextFileDisplayBasename(filePath) {
|
|
4154
|
-
return filePath.trim().replaceAll("\\", "/").split("/").pop()?.trim() ?? "";
|
|
4155
|
-
}
|
|
4156
|
-
function getCodexContextFileBasename(filePath) {
|
|
4157
|
-
return normalizeCodexContextFilePath(filePath).split("/").pop() ?? "";
|
|
4158
|
-
}
|
|
4159
|
-
function normalizeCodexDynamicToolName(name) {
|
|
4160
|
-
return name.trim().toLowerCase();
|
|
4161
|
-
}
|
|
4162
|
-
function isNonEmptyString$1(value) {
|
|
4163
|
-
return typeof value === "string" && value.length > 0;
|
|
4164
|
-
}
|
|
4165
|
-
//#endregion
|
|
4166
3491
|
//#region extensions/codex/src/app-server/run-attempt-state.ts
|
|
4167
3492
|
async function clearCodexBindingAfterInvalidImagePayload(bindingStore, identity, fields) {
|
|
4168
3493
|
const currentBinding = await bindingStore.read(identity);
|
|
@@ -4209,21 +3534,6 @@ function isCodexActiveCompactTurnError(error) {
|
|
|
4209
3534
|
const codexErrorInfo = isJsonObject(data?.codexErrorInfo) ? data.codexErrorInfo : void 0;
|
|
4210
3535
|
return (isJsonObject(codexErrorInfo?.activeTurnNotSteerable) ? codexErrorInfo.activeTurnNotSteerable : void 0)?.turnKind === "compact";
|
|
4211
3536
|
}
|
|
4212
|
-
function readCodexFinalizationHookNotification(notification, threadId, turnId) {
|
|
4213
|
-
if (notification.method !== "hook/started" && notification.method !== "hook/completed") return;
|
|
4214
|
-
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
4215
|
-
const run = params && isJsonObject(params.run) ? params.run : void 0;
|
|
4216
|
-
if (params?.threadId !== threadId || params.turnId !== turnId || run?.eventName !== "stop" && run?.eventName !== "subagentStop" || typeof run.id !== "string" || !run.id) return;
|
|
4217
|
-
if (notification.method === "hook/started") return {
|
|
4218
|
-
phase: "started",
|
|
4219
|
-
runId: run.id
|
|
4220
|
-
};
|
|
4221
|
-
return {
|
|
4222
|
-
phase: "completed",
|
|
4223
|
-
runId: run.id,
|
|
4224
|
-
status: typeof run.status === "string" ? run.status : void 0
|
|
4225
|
-
};
|
|
4226
|
-
}
|
|
4227
3537
|
function joinPresentSections(...sections) {
|
|
4228
3538
|
return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
|
|
4229
3539
|
}
|
|
@@ -4231,34 +3541,6 @@ function prependCurrentInboundContext(prompt, context) {
|
|
|
4231
3541
|
const text = context?.text.trim();
|
|
4232
3542
|
return text ? [neutralizeCodexExplicitMentionSigils(text), prompt].filter(Boolean).join("\n\n") : prompt;
|
|
4233
3543
|
}
|
|
4234
|
-
function buildCodexAppServerTimeoutDiagnostics(params) {
|
|
4235
|
-
const readNonBlankDetailString = (key) => {
|
|
4236
|
-
const value = params.details?.[key];
|
|
4237
|
-
return hasNonEmptyString(value) ? value : void 0;
|
|
4238
|
-
};
|
|
4239
|
-
const activeAppServerTurnRequests = asFiniteNumber(params.details?.activeAppServerTurnRequests);
|
|
4240
|
-
const activeTurnItemCount = asFiniteNumber(params.details?.activeTurnItemCount);
|
|
4241
|
-
const terminalTurnNotificationQueued = asBoolean(params.details?.terminalTurnNotificationQueued);
|
|
4242
|
-
const completionIdleWatchArmed = asBoolean(params.details?.completionIdleWatchArmed);
|
|
4243
|
-
const assistantCompletionIdleWatchArmed = asBoolean(params.details?.assistantCompletionIdleWatchArmed);
|
|
4244
|
-
const terminalIdleWatchArmed = asBoolean(params.details?.terminalIdleWatchArmed);
|
|
4245
|
-
return {
|
|
4246
|
-
...params.idleMs !== void 0 ? { idleMs: params.idleMs } : {},
|
|
4247
|
-
...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
|
|
4248
|
-
...params.lastActivityReason ? { lastActivityReason: params.lastActivityReason } : {},
|
|
4249
|
-
...readNonBlankDetailString("lastNotificationMethod") ? { lastNotificationMethod: readNonBlankDetailString("lastNotificationMethod") } : {},
|
|
4250
|
-
...readNonBlankDetailString("lastNotificationItemId") ? { lastNotificationItemId: readNonBlankDetailString("lastNotificationItemId") } : {},
|
|
4251
|
-
...readNonBlankDetailString("lastNotificationItemType") ? { lastNotificationItemType: readNonBlankDetailString("lastNotificationItemType") } : {},
|
|
4252
|
-
...readNonBlankDetailString("lastNotificationItemRole") ? { lastNotificationItemRole: readNonBlankDetailString("lastNotificationItemRole") } : {},
|
|
4253
|
-
...readNonBlankDetailString("lastAssistantTextPreview") ? { lastAssistantTextPreview: readNonBlankDetailString("lastAssistantTextPreview") } : {},
|
|
4254
|
-
...activeAppServerTurnRequests !== void 0 ? { activeAppServerTurnRequests } : {},
|
|
4255
|
-
...activeTurnItemCount !== void 0 ? { activeTurnItemCount } : {},
|
|
4256
|
-
...terminalTurnNotificationQueued !== void 0 ? { terminalTurnNotificationQueued } : {},
|
|
4257
|
-
...completionIdleWatchArmed !== void 0 ? { completionIdleWatchArmed } : {},
|
|
4258
|
-
...assistantCompletionIdleWatchArmed !== void 0 ? { assistantCompletionIdleWatchArmed } : {},
|
|
4259
|
-
...terminalIdleWatchArmed !== void 0 ? { terminalIdleWatchArmed } : {}
|
|
4260
|
-
};
|
|
4261
|
-
}
|
|
4262
3544
|
//#endregion
|
|
4263
3545
|
//#region extensions/codex/src/app-server/run-attempt-context.ts
|
|
4264
3546
|
async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
@@ -4292,9 +3574,17 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
|
4292
3574
|
sessionKey: contextSessionKey,
|
|
4293
3575
|
sessionId: params.sessionId,
|
|
4294
3576
|
workspaceDir: params.workspaceDir,
|
|
4295
|
-
messageProvider: params.messageProvider ?? void 0,
|
|
4296
3577
|
trigger: params.trigger,
|
|
4297
|
-
|
|
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,
|
|
4298
3588
|
...hookContextWindowFields
|
|
4299
3589
|
};
|
|
4300
3590
|
const hookRunner = getAgentHarnessHookRunner();
|
|
@@ -4510,7 +3800,7 @@ function createCodexModelCallDiagnosticEmitter(params) {
|
|
|
4510
3800
|
}
|
|
4511
3801
|
/** Classifies model-call failures into timeout/abort buckets for diagnostics. */
|
|
4512
3802
|
function classifyCodexModelCallFailureKind(params) {
|
|
4513
|
-
if (params.timedOut
|
|
3803
|
+
if (params.timedOut) return "timeout";
|
|
4514
3804
|
const errorMessage = params.error ? params.formatError(params.error).toLowerCase() : "";
|
|
4515
3805
|
if (errorMessage.includes("timed out") || errorMessage.includes("timeout")) return "timeout";
|
|
4516
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";
|
|
@@ -4518,38 +3808,17 @@ function classifyCodexModelCallFailureKind(params) {
|
|
|
4518
3808
|
}
|
|
4519
3809
|
//#endregion
|
|
4520
3810
|
//#region extensions/codex/src/app-server/attempt-results.ts
|
|
4521
|
-
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.";
|
|
4522
|
-
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.";
|
|
4523
|
-
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.";
|
|
4524
3811
|
/** Joins terminal assistant text blocks into the final attempt answer. */
|
|
4525
3812
|
function collectTerminalAssistantText(result) {
|
|
4526
3813
|
return result.assistantTexts.join("\n\n").trim();
|
|
4527
3814
|
}
|
|
4528
|
-
/**
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
*/
|
|
4532
|
-
function buildCodexAppServerPromptTimeoutOutcome(params) {
|
|
4533
|
-
if (!params.turnCompletionIdleTimedOut) return;
|
|
4534
|
-
if (params.turnWatchTimeoutKind === "terminal") {
|
|
4535
|
-
if (collectTerminalAssistantText(params.result)) return;
|
|
4536
|
-
const terminalReplayBlockedReason = resolveCodexAppServerReplayBlockedReason(params.result);
|
|
4537
|
-
return {
|
|
4538
|
-
message: CODEX_APP_SERVER_TERMINAL_IDLE_USER_MESSAGE,
|
|
4539
|
-
...terminalReplayBlockedReason ? {
|
|
4540
|
-
replayInvalid: true,
|
|
4541
|
-
livenessState: "abandoned"
|
|
4542
|
-
} : {}
|
|
4543
|
-
};
|
|
4544
|
-
}
|
|
4545
|
-
if (params.turnWatchTimeoutKind !== void 0 && params.turnWatchTimeoutKind !== "completion") return;
|
|
4546
|
-
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;
|
|
4547
3818
|
return {
|
|
4548
|
-
message:
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
livenessState: "abandoned"
|
|
4552
|
-
} : {}
|
|
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"
|
|
4553
3822
|
};
|
|
4554
3823
|
}
|
|
4555
3824
|
/** Explains why an incomplete app-server turn cannot be safely replayed. */
|
|
@@ -4671,52 +3940,44 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4671
3940
|
const { effectiveRuntimeProviderId, effectiveRuntimeModelId } = runtime;
|
|
4672
3941
|
const { params, terminalState, runAbortController, activeContextEngine, bindingStore, bindingIdentity, appServer, usesSupervisionConnection, sessionAgentId, contextSessionKey, effectiveCwd, agentDir, attemptStartedAt, startupAuthProfileId } = connection;
|
|
4673
3942
|
const { toolBridge, toolState } = attemptTools;
|
|
4674
|
-
const { state, completion,
|
|
3943
|
+
const { state, completion, deadlines } = turnRuntime;
|
|
4675
3944
|
const { emitLifecycleTerminal, buildLifecycleTerminalMeta } = lifecycle;
|
|
4676
3945
|
const { drainNotificationQueue } = notifications;
|
|
4677
3946
|
const { codexModelCallDiagnostics } = requestRuntime;
|
|
4678
3947
|
const { activeTurnId, activeProjector, streamState, freezeRunTerminalOutcome, notifyUserMessagePersisted } = activeTurn;
|
|
4679
3948
|
await completion;
|
|
4680
|
-
await state.abortCleanup;
|
|
4681
|
-
const drain = drainNotificationQueue();
|
|
4682
3949
|
const abortGraceElapsed = createDeferred();
|
|
3950
|
+
let settlementClosed = false;
|
|
4683
3951
|
let abortGraceTimer;
|
|
4684
|
-
const
|
|
3952
|
+
const beginAbortGrace = () => {
|
|
3953
|
+
if (settlementClosed) return;
|
|
4685
3954
|
abortGraceTimer = setTimeout(() => abortGraceElapsed.resolve(), TURN_FINALIZE_DRAIN_ABORT_GRACE_MS);
|
|
4686
3955
|
abortGraceTimer.unref?.();
|
|
3956
|
+
};
|
|
3957
|
+
const abortListener = addAbortListener(runAbortController.signal, () => {
|
|
3958
|
+
state.abortCleanup.then(beginAbortGrace, beginAbortGrace);
|
|
4687
3959
|
});
|
|
3960
|
+
const closeProjection = () => {
|
|
3961
|
+
state.projectionClosed = true;
|
|
3962
|
+
return activeProjector.closeProjection();
|
|
3963
|
+
};
|
|
3964
|
+
const settlement = drainNotificationQueue().then(closeProjection);
|
|
4688
3965
|
try {
|
|
4689
|
-
await Promise.race([
|
|
3966
|
+
await Promise.race([settlement, abortGraceElapsed.promise]);
|
|
3967
|
+
if (runAbortController.signal.aborted) await state.abortCleanup;
|
|
4690
3968
|
} finally {
|
|
3969
|
+
settlementClosed = true;
|
|
4691
3970
|
abortListener[Symbol.dispose]();
|
|
4692
3971
|
clearTimeout(abortGraceTimer);
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
const hasRecoverableCompletedAssistant = !turnWatches.isCompletionIdleWatchPinnedByTerminalError() && turnWatches.isAssistantCompletionIdleWatchArmed() && hasQuiescentCompletedAssistant;
|
|
4696
|
-
const recoveredTurnWatchTimeout = state.turnCompletionIdleTimedOut && !terminalState.explicitCancellationObserved && hasRecoverableCompletedAssistant && activeProjector.recoverCompletedTerminalAssistantAfterTurnWatchTimeout();
|
|
4697
|
-
if (recoveredTurnWatchTimeout) {
|
|
4698
|
-
embeddedAgentLog.warn("codex app-server recovered completed assistant output after missing turn completion", {
|
|
4699
|
-
threadId: resourceState.thread.threadId,
|
|
4700
|
-
turnId: activeTurnId,
|
|
4701
|
-
timeoutKind: state.turnWatchTimeoutKind,
|
|
4702
|
-
idleMs: state.turnWatchTimeoutIdleMs,
|
|
4703
|
-
timeoutMs: state.turnWatchTimeoutMs
|
|
4704
|
-
});
|
|
4705
|
-
trajectoryRecorder?.recordEvent("turn.watch_timeout_recovered", {
|
|
4706
|
-
threadId: resourceState.thread.threadId,
|
|
4707
|
-
turnId: activeTurnId,
|
|
4708
|
-
timeoutKind: state.turnWatchTimeoutKind,
|
|
4709
|
-
idleMs: state.turnWatchTimeoutIdleMs,
|
|
4710
|
-
timeoutMs: state.turnWatchTimeoutMs
|
|
4711
|
-
});
|
|
3972
|
+
deadlines.dispose();
|
|
3973
|
+
if (!state.projectionClosed) await resources.runCleanupStep("codex-transcript-checkpoint", closeProjection);
|
|
4712
3974
|
}
|
|
4713
3975
|
const result = activeProjector.buildResult(toolBridge.telemetry, { yieldDetected: toolState.yieldDetected });
|
|
4714
3976
|
const projectedTerminal = attemptTerminal.project(result.terminal);
|
|
4715
|
-
const effectiveTimedOut = state.
|
|
4716
|
-
const
|
|
4717
|
-
const
|
|
4718
|
-
|
|
4719
|
-
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);
|
|
4720
3981
|
const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError instanceof Error ? finalPromptError.message : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
|
|
4721
3982
|
if (isInvalidCodexImagePayloadError(finalPromptErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(bindingStore, bindingIdentity, {
|
|
4722
3983
|
phase: "turn_completed",
|
|
@@ -4759,33 +4020,23 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4759
4020
|
});
|
|
4760
4021
|
finalPromptError = resourceState.executionDisconnectError ?? finalPromptError;
|
|
4761
4022
|
const finalPromptErrorSource = effectiveTimedOut || clientClosedPromptErrorForFinal ? "prompt" : projectedTerminal.promptErrorSource;
|
|
4762
|
-
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;
|
|
4763
4024
|
const replayBlockedReason = codexAppServerFailureKind ? resolveCodexAppServerReplayBlockedReason(result) : void 0;
|
|
4764
|
-
const promptTimeoutOutcome = buildCodexAppServerPromptTimeoutOutcome(
|
|
4765
|
-
|
|
4766
|
-
turnCompletionIdleTimedOut: effectiveTurnCompletionIdleTimedOut,
|
|
4767
|
-
turnWatchTimeoutKind: state.turnWatchTimeoutKind
|
|
4768
|
-
});
|
|
4769
|
-
const failureDiagnostics = codexAppServerFailureKind === "client_closed_before_turn_completed" && state.clientClosedDiagnostic ? { transportError: state.clientClosedDiagnostic } : codexAppServerFailureKind === "turn_completion_idle_timeout" && state.turnWatchTimeoutKind === "completion" ? buildCodexAppServerTimeoutDiagnostics({
|
|
4770
|
-
idleMs: state.turnWatchTimeoutIdleMs,
|
|
4771
|
-
timeoutMs: state.turnWatchTimeoutMs,
|
|
4772
|
-
lastActivityReason: state.turnWatchTimeoutLastActivityReason,
|
|
4773
|
-
details: state.turnWatchTimeoutDetails
|
|
4774
|
-
}) : 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;
|
|
4775
4027
|
const codexAppServerFailure = codexAppServerFailureKind ? {
|
|
4776
4028
|
kind: codexAppServerFailureKind,
|
|
4777
|
-
...codexAppServerFailureKind === "turn_completion_idle_timeout" && state.turnWatchTimeoutKind ? { turnWatchTimeoutKind: state.turnWatchTimeoutKind } : {},
|
|
4778
4029
|
transport: appServer.start.transport,
|
|
4779
4030
|
threadId: resourceState.thread.threadId,
|
|
4780
4031
|
turnId: activeTurnId,
|
|
4781
|
-
replaySafe: replayBlockedReason === void 0,
|
|
4032
|
+
replaySafe: codexAppServerFailureKind === "client_closed_before_turn_completed" && replayBlockedReason === void 0,
|
|
4782
4033
|
...replayBlockedReason ? { replayBlockedReason } : {},
|
|
4783
4034
|
...failureDiagnostics ? { diagnostics: failureDiagnostics } : {}
|
|
4784
4035
|
} : void 0;
|
|
4785
4036
|
const finalAborted = isFinalAborted();
|
|
4786
4037
|
const completedTurnStatus = activeProjector.getCompletedTurnStatus();
|
|
4787
|
-
const locallyCompletedTurn = state.completed &&
|
|
4788
|
-
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);
|
|
4789
4040
|
if (toolBridge.telemetry.messagingToolSentTargets.some((target) => target.sourceReplyFinal === true)) result.agentHarnessResultClassification = void 0;
|
|
4790
4041
|
const attemptSucceeded = turnSucceeded && result.agentHarnessResultClassification === void 0;
|
|
4791
4042
|
terminalState.turnSucceeded = turnSucceeded;
|
|
@@ -4799,7 +4050,6 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4799
4050
|
const modelCallFailureKind = classifyCodexModelCallFailureKind({
|
|
4800
4051
|
error: finalPromptError,
|
|
4801
4052
|
timedOut: effectiveTimedOut,
|
|
4802
|
-
turnCompletionIdleTimedOut: effectiveTurnCompletionIdleTimedOut,
|
|
4803
4053
|
runAborted: finalAborted,
|
|
4804
4054
|
abortReason: terminalState.explicitCancellationReason ?? runAbortController.signal.reason,
|
|
4805
4055
|
clientClosedAbort: state.clientClosedAbort,
|
|
@@ -4952,9 +4202,6 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4952
4202
|
}
|
|
4953
4203
|
//#endregion
|
|
4954
4204
|
//#region extensions/codex/src/app-server/attempt-notification-state.ts
|
|
4955
|
-
/**
|
|
4956
|
-
* State machine for Codex app-server turn notifications and idle-watch updates.
|
|
4957
|
-
*/
|
|
4958
4205
|
/** Emits coarse execution phases exactly once from app-server notifications. */
|
|
4959
4206
|
function reportCodexExecutionNotification(params) {
|
|
4960
4207
|
const { notification } = params;
|
|
@@ -4978,82 +4225,7 @@ function reportCodexExecutionNotification(params) {
|
|
|
4978
4225
|
}
|
|
4979
4226
|
/** Returns true when a notification ends the current app-server turn. */
|
|
4980
4227
|
function isTerminalCodexTurnNotificationForTurn(params) {
|
|
4981
|
-
|
|
4982
|
-
return params.notification.method === "turn/completed";
|
|
4983
|
-
}
|
|
4984
|
-
/**
|
|
4985
|
-
* Applies one notification to active item tracking, idle watches, and terminal
|
|
4986
|
-
* turn state.
|
|
4987
|
-
*/
|
|
4988
|
-
function applyCodexTurnNotificationState(params) {
|
|
4989
|
-
const { notification, turnWatches } = params;
|
|
4990
|
-
const isCurrentTurnNotification = isCodexNotificationForTurn(notification.params, params.threadId, params.turnId);
|
|
4991
|
-
const isTurnCompletion = notification.method === "turn/completed" && isCurrentTurnNotification;
|
|
4992
|
-
let turnCrossedToolHandoff = params.turnCrossedToolHandoff;
|
|
4993
|
-
if (isCurrentTurnNotification) {
|
|
4994
|
-
updateActiveTurnItemIds(notification, params.activeTurnItemIds);
|
|
4995
|
-
updateActiveCompletionBlockerItemIds(notification, params.activeCompletionBlockerItemIds);
|
|
4996
|
-
turnWatches.touchActivity(`notification:${notification.method}`, {
|
|
4997
|
-
details: describeNotificationActivity(notification),
|
|
4998
|
-
attemptProgress: true
|
|
4999
|
-
});
|
|
5000
|
-
params.onReportExecutionNotification(notification);
|
|
5001
|
-
if (notification.method === "item/completed" && params.activeTurnItemIds.size === 0) params.onScheduleTerminalDynamicToolReleaseCheck();
|
|
5002
|
-
}
|
|
5003
|
-
const unblockedAssistantCompletionRelease = isCurrentTurnNotification && turnWatches.isAssistantCompletionIdleWatchArmed() && notification.method === "item/completed" && params.activeTurnItemIds.size === 0;
|
|
5004
|
-
const trackedDynamicToolCompletion = isPendingOpenClawDynamicToolCompletionNotification(notification, params.pendingOpenClawDynamicToolCompletionIds);
|
|
5005
|
-
const rawToolOutputCompletion = isRawToolOutputCompletionNotification(notification);
|
|
5006
|
-
if (isCurrentTurnNotification && (rawToolOutputCompletion || isNativeToolProgressNotification(notification))) turnCrossedToolHandoff = true;
|
|
5007
|
-
const assistantCompletionCanRelease = isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff);
|
|
5008
|
-
const postToolProgressNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && ((isRawAssistantProgressNotification(notification) || isRawReasoningCompletionNotification(notification)) && params.activeTurnItemIds.size === 0 || isReasoningProgressNotification(notification));
|
|
5009
|
-
const postToolPatchUpdateNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && isFileChangePatchUpdatedNotification(notification);
|
|
5010
|
-
const rawResponseItemCompletedWithNoActiveItems = isCurrentTurnNotification && notification.method === "rawResponseItem/completed" && params.activeTurnItemIds.size === 0 && params.activeAppServerTurnRequests === 0 && !assistantCompletionCanRelease && !postToolProgressNeedsTerminalGuard && !rawToolOutputCompletion;
|
|
5011
|
-
const shouldArmNoToolPostProgressReplyWatch = isCurrentTurnNotification && !turnCrossedToolHandoff && params.activeTurnItemIds.size === 0 && (isReasoningItemCompletionNotification(notification) || isAssistantCommentaryCompletionNotification(notification));
|
|
5012
|
-
const shouldArmNoToolPostRawProgressReplyWatch = !turnCrossedToolHandoff && rawResponseItemCompletedWithNoActiveItems && (isRawReasoningCompletionNotification(notification) || isRawAssistantProgressNotification(notification));
|
|
5013
|
-
const shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem = isCurrentTurnNotification && notification.method === "item/completed" && params.activeTurnItemIds.size === 0 && !trackedDynamicToolCompletion && !assistantCompletionCanRelease && !shouldArmNoToolPostProgressReplyWatch;
|
|
5014
|
-
const shouldUsePostToolContinuationWatch = turnCrossedToolHandoff && (postToolProgressNeedsTerminalGuard || postToolPatchUpdateNeedsTerminalGuard || rawToolOutputCompletion || trackedDynamicToolCompletion || shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem);
|
|
5015
|
-
const armPostToolContinuationWatch = () => {
|
|
5016
|
-
turnWatches.armCompletionIdleWatch({ timeoutMs: params.postToolRawAssistantCompletionIdleTimeoutMs });
|
|
5017
|
-
turnWatches.extendAttemptIdleWatch(params.postToolRawAssistantCompletionIdleTimeoutMs);
|
|
5018
|
-
};
|
|
5019
|
-
const armPostProgressReplyWatch = () => {
|
|
5020
|
-
turnWatches.armCompletionIdleWatch({ timeoutMs: CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS });
|
|
5021
|
-
turnWatches.extendAttemptIdleWatch(CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS);
|
|
5022
|
-
};
|
|
5023
|
-
if (isCurrentTurnNotification && notification.method === "error") {
|
|
5024
|
-
if (isRetryableErrorNotification(notification.params)) turnWatches.disarmCompletionIdleWatch();
|
|
5025
|
-
else turnWatches.armCompletionIdleWatch({ pinnedByTerminalError: true });
|
|
5026
|
-
turnWatches.disarmAssistantCompletionIdleWatch();
|
|
5027
|
-
} else if (isTurnCompletion) turnWatches.disarmAssistantCompletionIdleWatch();
|
|
5028
|
-
else if (isCurrentTurnNotification && assistantCompletionCanRelease) turnWatches.armAssistantCompletionIdleWatch(describeNotificationActivity(notification));
|
|
5029
|
-
else if (postToolProgressNeedsTerminalGuard || postToolPatchUpdateNeedsTerminalGuard) armPostToolContinuationWatch();
|
|
5030
|
-
else if (shouldArmNoToolPostProgressReplyWatch || shouldArmNoToolPostRawProgressReplyWatch) armPostProgressReplyWatch();
|
|
5031
|
-
else if (trackedDynamicToolCompletion) armPostToolContinuationWatch();
|
|
5032
|
-
else if (unblockedAssistantCompletionRelease) turnWatches.armAssistantCompletionIdleWatch(describeNotificationActivity(notification));
|
|
5033
|
-
else if (shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) {
|
|
5034
|
-
if (shouldUsePostToolContinuationWatch) armPostToolContinuationWatch();
|
|
5035
|
-
else turnWatches.armCompletionIdleWatch();
|
|
5036
|
-
} else if (rawResponseItemCompletedWithNoActiveItems) turnWatches.armCompletionIdleWatch();
|
|
5037
|
-
else if (isCurrentTurnNotification && rawToolOutputCompletion) armPostToolContinuationWatch();
|
|
5038
|
-
else if (isCurrentTurnNotification && shouldDisarmAssistantCompletionIdleWatch(notification)) turnWatches.disarmAssistantCompletionIdleWatch();
|
|
5039
|
-
if (turnWatches.isCompletionIdleWatchArmed() && !turnWatches.isCompletionIdleWatchPinnedByTerminalError() && notification.method !== "turn/completed" && isCurrentTurnNotification && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !postToolProgressNeedsTerminalGuard && !postToolPatchUpdateNeedsTerminalGuard && !rawResponseItemCompletedWithNoActiveItems && !shouldArmNoToolPostProgressReplyWatch && !shouldArmNoToolPostRawProgressReplyWatch && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) turnWatches.disarmCompletionIdleWatch();
|
|
5040
|
-
if (trackedDynamicToolCompletion) {
|
|
5041
|
-
const itemId = readNotificationItemId(notification);
|
|
5042
|
-
if (itemId) {
|
|
5043
|
-
params.pendingOpenClawDynamicToolCompletionIds.delete(itemId);
|
|
5044
|
-
params.onScheduleTerminalDynamicToolReleaseCheck();
|
|
5045
|
-
}
|
|
5046
|
-
}
|
|
5047
|
-
return {
|
|
5048
|
-
isCurrentTurnNotification,
|
|
5049
|
-
isTurnAbortMarker: isCurrentTurnNotification && isCodexTurnAbortMarkerNotification(notification, { currentPromptTexts: params.currentPromptTexts }),
|
|
5050
|
-
isTurnTerminal: isTerminalCodexTurnNotificationForTurn({
|
|
5051
|
-
notification,
|
|
5052
|
-
threadId: params.threadId,
|
|
5053
|
-
turnId: params.turnId
|
|
5054
|
-
}),
|
|
5055
|
-
turnCrossedToolHandoff
|
|
5056
|
-
};
|
|
4228
|
+
return params.notification.method === "turn/completed" && isCodexNotificationForTurn(params.notification.params, params.threadId, params.turnId) && readCodexTurnCompletedNotification(params.notification.params) !== void 0;
|
|
5057
4229
|
}
|
|
5058
4230
|
//#endregion
|
|
5059
4231
|
//#region extensions/codex/src/app-server/run-attempt-lifecycle-terminal.ts
|
|
@@ -5248,10 +4420,9 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
5248
4420
|
const { prompt, state: resourceState, projectorRef, registerNativeSubagentMonitor } = resources;
|
|
5249
4421
|
const { context, turnState } = prompt;
|
|
5250
4422
|
const { attemptTools, runtime } = context;
|
|
5251
|
-
const {
|
|
5252
|
-
const { appServer, runAbortController } = connection;
|
|
4423
|
+
const { appServer, runAbortController } = runtime.connection;
|
|
5253
4424
|
const { allocateCodexToolOutcomeOrdinal } = attemptTools;
|
|
5254
|
-
const { state, turnIdRef, userInputBridgeRef, steeringQueueRef,
|
|
4425
|
+
const { state, turnIdRef, userInputBridgeRef, steeringQueueRef, activeTurnItemIds, pendingOpenClawDynamicToolCompletionIds, completeTurn, noteProgress, deadlines } = turnRuntime;
|
|
5255
4426
|
const { scheduleTerminalDynamicToolReleaseCheck, reportExecutionNotification, maybeAnnounceFastModeAutoOff } = lifecycle;
|
|
5256
4427
|
const isTerminalTurnNotificationForTurn = (notification, notificationTurnId) => isTerminalCodexTurnNotificationForTurn({
|
|
5257
4428
|
notification,
|
|
@@ -5259,81 +4430,47 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
5259
4430
|
turnId: notificationTurnId
|
|
5260
4431
|
});
|
|
5261
4432
|
const handleNotification = async (notification) => {
|
|
4433
|
+
if (state.projectionClosed) return;
|
|
5262
4434
|
const projector = projectorRef.current;
|
|
5263
4435
|
const turnId = turnIdRef.current;
|
|
5264
|
-
const steeringQueue = steeringQueueRef.current;
|
|
5265
4436
|
userInputBridgeRef.current?.handleNotification(notification);
|
|
5266
4437
|
if (!projector || !turnId) {
|
|
5267
4438
|
if (notification.method === "error") state.latestStartupErrorNotification = notification;
|
|
5268
4439
|
return;
|
|
5269
4440
|
}
|
|
5270
|
-
|
|
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") {
|
|
5271
4444
|
completeTurn();
|
|
5272
4445
|
return;
|
|
5273
4446
|
}
|
|
5274
|
-
|
|
5275
|
-
notification,
|
|
5276
|
-
threadId: resourceState.thread.threadId,
|
|
5277
|
-
turnId,
|
|
5278
|
-
currentPromptTexts: [turnState.codexTurnPromptText],
|
|
5279
|
-
turnWatches,
|
|
5280
|
-
activeTurnItemIds,
|
|
5281
|
-
activeCompletionBlockerItemIds,
|
|
5282
|
-
activeAppServerTurnRequests: state.activeAppServerTurnRequests,
|
|
5283
|
-
pendingOpenClawDynamicToolCompletionIds,
|
|
5284
|
-
turnCrossedToolHandoff: state.turnCrossedToolHandoff,
|
|
5285
|
-
postToolRawAssistantCompletionIdleTimeoutMs,
|
|
5286
|
-
onScheduleTerminalDynamicToolReleaseCheck: scheduleTerminalDynamicToolReleaseCheck,
|
|
5287
|
-
onReportExecutionNotification: reportExecutionNotification
|
|
5288
|
-
});
|
|
5289
|
-
state.turnCrossedToolHandoff = notificationState.turnCrossedToolHandoff;
|
|
5290
|
-
if (notificationState.isCurrentTurnNotification && notification.method === "item/completed") {
|
|
5291
|
-
const item = readCodexNotificationItem(notification.params);
|
|
5292
|
-
if (item?.type === "userMessage" && typeof item.clientId === "string") await steeringQueue?.confirmConsumed(item.clientId);
|
|
5293
|
-
}
|
|
5294
|
-
if (notificationState.isTurnAbortMarker) state.sawCodexInterruptMarker = true;
|
|
5295
|
-
const hookNotification = readCodexFinalizationHookNotification(notification, resourceState.thread.threadId, turnId);
|
|
5296
|
-
if (hookNotification?.phase === "started") {
|
|
5297
|
-
if (activeFinalizationHookRunIds.size === 0) finalizationHookBatchStatuses.clear();
|
|
5298
|
-
activeFinalizationHookRunIds.add(hookNotification.runId);
|
|
5299
|
-
turnWatches.disarmAssistantCompletionIdleWatch();
|
|
5300
|
-
}
|
|
5301
|
-
if (notificationState.isTurnTerminal) state.terminalTurnNotificationQueued = true;
|
|
4447
|
+
state.activeLocalProjections += 1;
|
|
5302
4448
|
try {
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
if (
|
|
5308
|
-
|
|
5309
|
-
|
|
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;
|
|
5310
4463
|
}
|
|
5311
|
-
|
|
4464
|
+
await projector.handleNotification(notification);
|
|
4465
|
+
if (isCurrentTurn && activeTurnItemIds.size === 0 && isRawFunctionToolOutputCompletionNotification(notification)) await maybeAnnounceFastModeAutoOff();
|
|
5312
4466
|
} catch (error) {
|
|
5313
4467
|
embeddedAgentLog.debug("codex app-server projector notification threw", {
|
|
5314
4468
|
method: notification.method,
|
|
5315
4469
|
error
|
|
5316
4470
|
});
|
|
5317
4471
|
} finally {
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
activeFinalizationHookRunIds.delete(hookNotification.runId);
|
|
5321
|
-
finalizationHookBatchStatuses.set(hookNotification.runId, hookNotification.status);
|
|
5322
|
-
if (activeFinalizationHookRunIds.size === 0) {
|
|
5323
|
-
const statuses = new Set(finalizationHookBatchStatuses.values());
|
|
5324
|
-
if (statuses.has("blocked") && !statuses.has("stopped")) {
|
|
5325
|
-
const itemId = projector.getLatestTerminalAssistantCandidate()?.itemId;
|
|
5326
|
-
state.rejectedFinalizationHookAssistant = itemId ? { itemId } : {};
|
|
5327
|
-
turnWatches.disarmAssistantCompletionIdleWatch();
|
|
5328
|
-
} else state.rejectedFinalizationHookAssistant = void 0;
|
|
5329
|
-
}
|
|
5330
|
-
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({
|
|
5331
|
-
lastNotificationMethod: notification.method,
|
|
5332
|
-
hookRunId: hookNotification.runId,
|
|
5333
|
-
hookStatus: hookNotification.status
|
|
5334
|
-
});
|
|
5335
|
-
}
|
|
5336
|
-
if (notificationState.isTurnTerminal) {
|
|
4472
|
+
state.activeLocalProjections -= 1;
|
|
4473
|
+
if (isTerminal) {
|
|
5337
4474
|
if ((readCodexTurnCompletedNotification(notification.params)?.turn)?.status === "interrupted" && state.sawCodexInterruptMarker) projector.markAborted();
|
|
5338
4475
|
completeTurn();
|
|
5339
4476
|
}
|
|
@@ -5358,10 +4495,12 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
5358
4495
|
const noteNotificationReceived = (notification, scope, receivedAtMs) => {
|
|
5359
4496
|
const projector = projectorRef.current;
|
|
5360
4497
|
const turnId = turnIdRef.current;
|
|
5361
|
-
if (!projector || !turnId) return;
|
|
4498
|
+
if (!projector || !turnId || state.projectionClosed) return;
|
|
4499
|
+
projector.recordMcpToolCallReceipt(notification);
|
|
5362
4500
|
if (isTerminalTurnNotificationForTurn(notification, turnId)) {
|
|
5363
4501
|
state.terminalTurnNotificationQueued = true;
|
|
5364
4502
|
steeringQueueRef.current?.sealAdmission();
|
|
4503
|
+
deadlines.beginSettlement(receivedAtMs);
|
|
5365
4504
|
}
|
|
5366
4505
|
if (scope.turnId === turnId) {
|
|
5367
4506
|
const modelToolCallId = readRawResponseToolCallId(notification);
|
|
@@ -5369,11 +4508,6 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
5369
4508
|
const nativeItem = readCodexNotificationItem(notification.params);
|
|
5370
4509
|
if (nativeItem?.type === "webSearch") projector.recordNativeToolOutcome(nativeItem);
|
|
5371
4510
|
}
|
|
5372
|
-
if (readCodexFinalizationHookNotification(notification, resourceState.thread.threadId, turnId)?.phase === "started") {
|
|
5373
|
-
state.unsettledFinalizationHookCount += 1;
|
|
5374
|
-
turnWatches.disarmAssistantCompletionIdleWatch();
|
|
5375
|
-
}
|
|
5376
|
-
turnWatches.noteNotificationReceived(notification.method, { receivedAtMs });
|
|
5377
4511
|
};
|
|
5378
4512
|
const enqueueNotification = async (notification, scope) => {
|
|
5379
4513
|
embeddedAgentLog.trace("codex app-server raw notification received", {
|
|
@@ -5863,6 +4997,8 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5863
4997
|
sessionId: params.sessionId,
|
|
5864
4998
|
sessionKey: contextSessionKey,
|
|
5865
4999
|
config: params.config,
|
|
5000
|
+
autoApproveMcpTools: shouldAutoApproveCodexAppServerApprovals(appServer),
|
|
5001
|
+
projectedMcpServers: runtime.bundleMcpThreadConfig.configPatch?.mcp_servers,
|
|
5866
5002
|
runId: params.runId,
|
|
5867
5003
|
channelId: hookChannelId,
|
|
5868
5004
|
...requester ? { requester } : {},
|
|
@@ -6004,297 +5140,6 @@ function prewarmCodexAttemptClient(params) {
|
|
|
6004
5140
|
});
|
|
6005
5141
|
}
|
|
6006
5142
|
//#endregion
|
|
6007
|
-
//#region extensions/codex/src/app-server/scheduled-app-authority.ts
|
|
6008
|
-
const CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE = "codex.apps";
|
|
6009
|
-
const CODEX_APPS_MCP_SERVER = "codex_apps";
|
|
6010
|
-
const MCP_STATUS_PAGE_SIZE = 100;
|
|
6011
|
-
const MCP_STATUS_MAX_PAGES = 100;
|
|
6012
|
-
const CODEX_APP_AUTHORITY_CAPTURE_TIMEOUT_MS = 6e4;
|
|
6013
|
-
const CODEX_APP_AUTHORITY_CAPTURE_MIN_TIMEOUT_MS = 100;
|
|
6014
|
-
function resolveScheduledCodexAppCreatorCaptureDecision(params) {
|
|
6015
|
-
if (!params.appsMayBeVisible) return {
|
|
6016
|
-
required: false,
|
|
6017
|
-
supported: false
|
|
6018
|
-
};
|
|
6019
|
-
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;
|
|
6020
|
-
return {
|
|
6021
|
-
required: true,
|
|
6022
|
-
supported: !unavailableReason,
|
|
6023
|
-
...unavailableReason ? { unavailableReason } : {}
|
|
6024
|
-
};
|
|
6025
|
-
}
|
|
6026
|
-
function normalizeApprovalMode(value) {
|
|
6027
|
-
return value === "allow" || value === "deny" || value === "auto" || value === "ask" ? value : void 0;
|
|
6028
|
-
}
|
|
6029
|
-
function normalizeAppToolApprovalMode(value) {
|
|
6030
|
-
return value === "auto" || value === "prompt" || value === "writes" || value === "approve" ? value : void 0;
|
|
6031
|
-
}
|
|
6032
|
-
function defaultApprovalMode(entry) {
|
|
6033
|
-
return entry.destructiveApprovalMode ?? (entry.allowDestructiveActions ? "allow" : "deny");
|
|
6034
|
-
}
|
|
6035
|
-
function parseScheduledCodexAppAuthority(authority) {
|
|
6036
|
-
if (!authority || authority.runtimeId !== "codex") return;
|
|
6037
|
-
if (authority.version !== 1) throw new Error("Unsupported Codex scheduled authority version; reauthorize this automation.");
|
|
6038
|
-
if (authority.namespace !== CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE) throw new Error(`Unsupported Codex scheduled authority namespace ${authority.namespace}; reauthorize this automation.`);
|
|
6039
|
-
const payload = asOptionalRecord(authority.payload);
|
|
6040
|
-
const auth = asOptionalRecord(payload?.auth);
|
|
6041
|
-
const profileId = normalizeOptionalString(auth?.profileId);
|
|
6042
|
-
const accountId = normalizeOptionalString(auth?.accountId);
|
|
6043
|
-
if (payload?.version !== 1 || !profileId || !accountId || !Array.isArray(payload.apps)) throw new Error("Stored Codex app authority is invalid; reauthorize this automation.");
|
|
6044
|
-
const seen = /* @__PURE__ */ new Set();
|
|
6045
|
-
const apps = payload.apps.map((raw) => {
|
|
6046
|
-
const app = asOptionalRecord(raw);
|
|
6047
|
-
const id = normalizeOptionalString(app?.id);
|
|
6048
|
-
const destructiveApprovalMode = normalizeApprovalMode(app?.destructiveApprovalMode);
|
|
6049
|
-
const rawTools = asOptionalRecord(app?.tools);
|
|
6050
|
-
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.");
|
|
6051
|
-
seen.add(id);
|
|
6052
|
-
const tools = {};
|
|
6053
|
-
for (const [name, rawMode] of Object.entries(rawTools)) {
|
|
6054
|
-
const toolName = normalizeOptionalString(name);
|
|
6055
|
-
const mode = normalizeAppToolApprovalMode(rawMode);
|
|
6056
|
-
if (!toolName || !mode) throw new Error("Stored Codex app authority is invalid; reauthorize this automation.");
|
|
6057
|
-
tools[toolName] = mode;
|
|
6058
|
-
}
|
|
6059
|
-
return {
|
|
6060
|
-
id,
|
|
6061
|
-
allowDestructiveActions: app.allowDestructiveActions,
|
|
6062
|
-
allowOpenWorld: app.allowOpenWorld,
|
|
6063
|
-
destructiveApprovalMode,
|
|
6064
|
-
tools
|
|
6065
|
-
};
|
|
6066
|
-
});
|
|
6067
|
-
return {
|
|
6068
|
-
version: 1,
|
|
6069
|
-
auth: {
|
|
6070
|
-
profileId,
|
|
6071
|
-
accountId
|
|
6072
|
-
},
|
|
6073
|
-
apps
|
|
6074
|
-
};
|
|
6075
|
-
}
|
|
6076
|
-
async function readCodexScheduledAppToolNamesByApp(params) {
|
|
6077
|
-
const toolNamesByApp = /* @__PURE__ */ new Map();
|
|
6078
|
-
const seenCursors = /* @__PURE__ */ new Set();
|
|
6079
|
-
let cursor;
|
|
6080
|
-
for (let page = 0; page < MCP_STATUS_MAX_PAGES; page += 1) {
|
|
6081
|
-
const response = await params.request("mcpServerStatus/list", {
|
|
6082
|
-
...params.threadId ? { threadId: params.threadId } : {},
|
|
6083
|
-
detail: "toolsAndAuthOnly",
|
|
6084
|
-
limit: MCP_STATUS_PAGE_SIZE,
|
|
6085
|
-
...cursor ? { cursor } : {}
|
|
6086
|
-
});
|
|
6087
|
-
if (!isJsonObject(response) || !Array.isArray(response.data)) throw new Error("Codex mcpServerStatus/list returned invalid scheduled app inventory");
|
|
6088
|
-
for (const status of response.data) {
|
|
6089
|
-
if (!isJsonObject(status) || !isJsonObject(status.tools)) throw new Error("Codex scheduled app inventory contained an invalid server status");
|
|
6090
|
-
if (status.name !== CODEX_APPS_MCP_SERVER) continue;
|
|
6091
|
-
for (const [toolName, tool] of Object.entries(status.tools)) {
|
|
6092
|
-
const connectorId = readCodexMcpToolConnectorId(tool);
|
|
6093
|
-
if (connectorId) {
|
|
6094
|
-
const names = toolNamesByApp.get(connectorId) ?? /* @__PURE__ */ new Set();
|
|
6095
|
-
names.add(toolName);
|
|
6096
|
-
toolNamesByApp.set(connectorId, names);
|
|
6097
|
-
}
|
|
6098
|
-
}
|
|
6099
|
-
}
|
|
6100
|
-
if (response.nextCursor !== void 0 && response.nextCursor !== null && typeof response.nextCursor !== "string") throw new Error("Codex scheduled app inventory returned an invalid pagination cursor");
|
|
6101
|
-
cursor = response.nextCursor;
|
|
6102
|
-
if (!cursor) return toolNamesByApp;
|
|
6103
|
-
if (seenCursors.has(cursor)) throw new Error("Codex app connector inventory repeated its pagination cursor");
|
|
6104
|
-
seenCursors.add(cursor);
|
|
6105
|
-
}
|
|
6106
|
-
throw new Error("Codex app connector inventory exceeded its bounded page limit");
|
|
6107
|
-
}
|
|
6108
|
-
/** Reads the current account policy and connector-backed tool names under one caller deadline. */
|
|
6109
|
-
async function readCurrentCodexScheduledAppPolicy$1(params) {
|
|
6110
|
-
const [configResponse, toolNamesByApp] = await Promise.all([params.request("config/read", {
|
|
6111
|
-
includeLayers: false,
|
|
6112
|
-
...params.configCwd ? { cwd: params.configCwd } : {}
|
|
6113
|
-
}), readCodexScheduledAppToolNamesByApp(params)]);
|
|
6114
|
-
if (!isJsonObject(configResponse)) throw new Error("Codex config/read returned an invalid scheduled app policy response");
|
|
6115
|
-
return {
|
|
6116
|
-
config: isJsonObject(configResponse.config) ? configResponse.config : {},
|
|
6117
|
-
toolNamesByApp
|
|
6118
|
-
};
|
|
6119
|
-
}
|
|
6120
|
-
function readToolApprovalMode(config, appId, toolName, fallback = "auto") {
|
|
6121
|
-
const app = asOptionalRecord(asOptionalRecord(config.apps)?.[appId]);
|
|
6122
|
-
return normalizeAppToolApprovalMode(asOptionalRecord(asOptionalRecord(app?.tools)?.[toolName])?.approval_mode) ?? fallback;
|
|
6123
|
-
}
|
|
6124
|
-
/** Captures only apps callable on the exact active Codex client/thread. */
|
|
6125
|
-
async function captureScheduledCodexAppAuthority(params) {
|
|
6126
|
-
const requestedTimeoutMs = params.timeoutMs ?? CODEX_APP_AUTHORITY_CAPTURE_TIMEOUT_MS;
|
|
6127
|
-
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));
|
|
6128
|
-
const deadlineMs = Date.now() + timeoutMs;
|
|
6129
|
-
const boundedClient = { request: ((method, requestParams) => {
|
|
6130
|
-
const remainingTimeoutMs = deadlineMs - Date.now();
|
|
6131
|
-
if (remainingTimeoutMs <= 0) throw new CodexScheduledAppAuthorityCaptureTimeoutError();
|
|
6132
|
-
return params.client.request(method, requestParams, {
|
|
6133
|
-
timeoutMs: remainingTimeoutMs,
|
|
6134
|
-
signal: params.signal
|
|
6135
|
-
});
|
|
6136
|
-
}) };
|
|
6137
|
-
let installed;
|
|
6138
|
-
let currentPolicy;
|
|
6139
|
-
try {
|
|
6140
|
-
[installed, currentPolicy] = await withAbortableTimeout({
|
|
6141
|
-
promise: Promise.all([boundedClient.request("app/installed", {
|
|
6142
|
-
threadId: params.threadId,
|
|
6143
|
-
forceRefresh: false
|
|
6144
|
-
}), readCurrentCodexScheduledAppPolicy$1({
|
|
6145
|
-
request: (method, requestParams) => boundedClient.request(method, requestParams),
|
|
6146
|
-
threadId: params.threadId,
|
|
6147
|
-
configCwd: params.configCwd
|
|
6148
|
-
})]),
|
|
6149
|
-
timeoutMs,
|
|
6150
|
-
signal: params.signal,
|
|
6151
|
-
timeoutMessage: "Codex scheduled app authority capture deadline elapsed",
|
|
6152
|
-
createTimeoutError: () => new CodexScheduledAppAuthorityCaptureTimeoutError()
|
|
6153
|
-
});
|
|
6154
|
-
} catch (error) {
|
|
6155
|
-
if (params.signal?.aborted || !(error instanceof CodexScheduledAppAuthorityCaptureTimeoutError) && !isCodexAppServerRequestTimeoutError(error)) throw error;
|
|
6156
|
-
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 });
|
|
6157
|
-
}
|
|
6158
|
-
const callableIds = new Set(installed.apps.filter((app) => app.enabled && app.callable).map((app) => app.id));
|
|
6159
|
-
const apps = Object.entries(params.policyContext.apps).filter(([id]) => callableIds.has(id) && currentPolicy.toolNamesByApp.has(id)).map(([id, policy]) => ({
|
|
6160
|
-
id,
|
|
6161
|
-
allowDestructiveActions: policy.allowDestructiveActions,
|
|
6162
|
-
allowOpenWorld: policy.allowOpenWorld !== false,
|
|
6163
|
-
destructiveApprovalMode: defaultApprovalMode(policy),
|
|
6164
|
-
tools: Object.fromEntries([...currentPolicy.toolNamesByApp.get(id) ?? []].toSorted().map((toolName) => [toolName, readToolApprovalMode(currentPolicy.config, id, toolName, appApprovalCeiling(defaultApprovalMode(policy)))]))
|
|
6165
|
-
})).toSorted((left, right) => left.id.localeCompare(right.id));
|
|
6166
|
-
if (apps.length === 0) return;
|
|
6167
|
-
return {
|
|
6168
|
-
version: 1,
|
|
6169
|
-
runtimeId: "codex",
|
|
6170
|
-
namespace: CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE,
|
|
6171
|
-
payload: {
|
|
6172
|
-
version: 1,
|
|
6173
|
-
auth: {
|
|
6174
|
-
profileId: params.profileId,
|
|
6175
|
-
accountId: params.accountId
|
|
6176
|
-
},
|
|
6177
|
-
apps
|
|
6178
|
-
}
|
|
6179
|
-
};
|
|
6180
|
-
}
|
|
6181
|
-
var CodexScheduledAppAuthorityCaptureTimeoutError = class extends Error {
|
|
6182
|
-
constructor() {
|
|
6183
|
-
super("Codex scheduled app authority capture deadline elapsed");
|
|
6184
|
-
this.name = "CodexScheduledAppAuthorityCaptureTimeoutError";
|
|
6185
|
-
}
|
|
6186
|
-
};
|
|
6187
|
-
const APPROVAL_RANK = {
|
|
6188
|
-
deny: 0,
|
|
6189
|
-
ask: 1,
|
|
6190
|
-
auto: 2,
|
|
6191
|
-
allow: 3
|
|
6192
|
-
};
|
|
6193
|
-
function stricterApprovalMode(left, right) {
|
|
6194
|
-
return APPROVAL_RANK[left] <= APPROVAL_RANK[right] ? left : right;
|
|
6195
|
-
}
|
|
6196
|
-
function intersectToolApprovalMode(captured, current) {
|
|
6197
|
-
if (captured === current) return captured;
|
|
6198
|
-
if (captured === "prompt" || current === "prompt") return "prompt";
|
|
6199
|
-
if (captured === "approve") return current;
|
|
6200
|
-
if (current === "approve") return captured;
|
|
6201
|
-
return "prompt";
|
|
6202
|
-
}
|
|
6203
|
-
function appApprovalCeiling(mode) {
|
|
6204
|
-
if (mode === "allow") return "approve";
|
|
6205
|
-
return mode === "ask" ? "prompt" : "auto";
|
|
6206
|
-
}
|
|
6207
|
-
function stableStringify(value) {
|
|
6208
|
-
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
6209
|
-
if (value && typeof value === "object") return `{${Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`).join(",")}}`;
|
|
6210
|
-
return JSON.stringify(value);
|
|
6211
|
-
}
|
|
6212
|
-
/** Intersects a stored app-ID cap with current policy without admitting new apps. */
|
|
6213
|
-
function intersectCodexPluginThreadConfigWithScheduledAuthority(config, authority, currentPolicy = {
|
|
6214
|
-
config: {},
|
|
6215
|
-
toolNamesByApp: /* @__PURE__ */ new Map()
|
|
6216
|
-
}) {
|
|
6217
|
-
const scheduled = parseScheduledCodexAppAuthority(authority);
|
|
6218
|
-
if (!scheduled) return config;
|
|
6219
|
-
const omittedAppIds = scheduled.apps.map((app) => app.id).filter((id) => {
|
|
6220
|
-
const currentTools = currentPolicy.toolNamesByApp.get(id);
|
|
6221
|
-
return !Object.hasOwn(config.policyContext.apps, id) || !currentTools || currentTools.size === 0;
|
|
6222
|
-
}).toSorted();
|
|
6223
|
-
if (omittedAppIds.length > 0) {
|
|
6224
|
-
const visibleIds = omittedAppIds.slice(0, 10).join(", ");
|
|
6225
|
-
const remaining = omittedAppIds.length - Math.min(omittedAppIds.length, 10);
|
|
6226
|
-
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.`);
|
|
6227
|
-
}
|
|
6228
|
-
const capturedById = new Map(scheduled.apps.map((app) => [app.id, app]));
|
|
6229
|
-
const apps = {};
|
|
6230
|
-
for (const [id, current] of Object.entries(config.policyContext.apps)) {
|
|
6231
|
-
const captured = capturedById.get(id);
|
|
6232
|
-
if (!captured) continue;
|
|
6233
|
-
apps[id] = {
|
|
6234
|
-
...current,
|
|
6235
|
-
allowDestructiveActions: current.allowDestructiveActions && captured.allowDestructiveActions,
|
|
6236
|
-
allowOpenWorld: current.allowOpenWorld !== false && captured.allowOpenWorld,
|
|
6237
|
-
destructiveApprovalMode: stricterApprovalMode(defaultApprovalMode(current), captured.destructiveApprovalMode)
|
|
6238
|
-
};
|
|
6239
|
-
}
|
|
6240
|
-
const pluginAppIds = Object.fromEntries(Object.entries(config.policyContext.pluginAppIds).map(([key, ids]) => [key, ids.filter((id) => Object.hasOwn(apps, id))]).filter(([, ids]) => ids.length > 0));
|
|
6241
|
-
const policyContext = buildPluginAppPolicyContext(apps, pluginAppIds);
|
|
6242
|
-
const configPatch = buildCodexPluginAppsConfigPatchFromPolicyContext(policyContext);
|
|
6243
|
-
const appsPatch = asOptionalRecord(configPatch.apps);
|
|
6244
|
-
for (const [appId, captured] of capturedById) {
|
|
6245
|
-
const appPatch = asOptionalRecord(appsPatch?.[appId]);
|
|
6246
|
-
if (!appPatch || !Object.hasOwn(apps, appId)) continue;
|
|
6247
|
-
const currentApp = apps[appId];
|
|
6248
|
-
if (!currentApp) continue;
|
|
6249
|
-
const storedAppCeiling = appApprovalCeiling(captured.destructiveApprovalMode);
|
|
6250
|
-
const currentAppCeiling = appApprovalCeiling(defaultApprovalMode(currentApp));
|
|
6251
|
-
const toolNames = currentPolicy.toolNamesByApp.get(appId) ?? /* @__PURE__ */ new Set();
|
|
6252
|
-
appPatch.tools = Object.fromEntries([...toolNames].toSorted().map((toolName) => {
|
|
6253
|
-
return [toolName, { approval_mode: intersectToolApprovalMode(intersectToolApprovalMode(captured.tools[toolName] ?? storedAppCeiling, storedAppCeiling), intersectToolApprovalMode(readToolApprovalMode(currentPolicy.config, appId, toolName, currentAppCeiling), currentAppCeiling)) }];
|
|
6254
|
-
}));
|
|
6255
|
-
}
|
|
6256
|
-
const fingerprint = crypto.createHash("sha256").update(stableStringify({
|
|
6257
|
-
version: 1,
|
|
6258
|
-
namespace: CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE,
|
|
6259
|
-
authority: scheduled,
|
|
6260
|
-
inputFingerprint: config.inputFingerprint,
|
|
6261
|
-
policyContext,
|
|
6262
|
-
configPatch
|
|
6263
|
-
})).digest("hex");
|
|
6264
|
-
return {
|
|
6265
|
-
...config,
|
|
6266
|
-
fingerprint,
|
|
6267
|
-
configPatch,
|
|
6268
|
-
provisionalAppIds: Object.keys(apps).toSorted(),
|
|
6269
|
-
policyContext
|
|
6270
|
-
};
|
|
6271
|
-
}
|
|
6272
|
-
function readScheduledCodexAppAuthorityAuth(authority) {
|
|
6273
|
-
return parseScheduledCodexAppAuthority(authority)?.auth;
|
|
6274
|
-
}
|
|
6275
|
-
function assertScheduledCodexAppAuthorityRuntime(connection, params) {
|
|
6276
|
-
const scheduledAuth = readScheduledCodexAppAuthorityAuth(params.scheduledRuntimeAuthority);
|
|
6277
|
-
if (!scheduledAuth) return;
|
|
6278
|
-
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.");
|
|
6279
|
-
const prepared = connection.startupPreparedAuth;
|
|
6280
|
-
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.`);
|
|
6281
|
-
}
|
|
6282
|
-
function buildLegacyScheduledCodexAppRecoveryPrompt(params) {
|
|
6283
|
-
if (params.trigger !== "cron" || !params.scheduledRuntimeAuthorityRecoveryRequired || params.scheduledRuntimeAuthority) return;
|
|
6284
|
-
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.";
|
|
6285
|
-
}
|
|
6286
|
-
/** Makes stored-cap identity part of thread reuse admission, including cap removal. */
|
|
6287
|
-
function buildScheduledCodexAppAuthorityInputFingerprint(baseFingerprint, authority) {
|
|
6288
|
-
const scheduled = parseScheduledCodexAppAuthority(authority);
|
|
6289
|
-
if (!scheduled) return baseFingerprint;
|
|
6290
|
-
return crypto.createHash("sha256").update(stableStringify({
|
|
6291
|
-
version: 1,
|
|
6292
|
-
namespace: CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE,
|
|
6293
|
-
baseFingerprint,
|
|
6294
|
-
authority: scheduled
|
|
6295
|
-
})).digest("hex");
|
|
6296
|
-
}
|
|
6297
|
-
//#endregion
|
|
6298
5143
|
//#region extensions/codex/src/app-server/scheduled-configured-mcp-authority.ts
|
|
6299
5144
|
/** Limits fresh scheduled-authority capture to authenticated local durable operator turns. */
|
|
6300
5145
|
function canResolveScheduledConfiguredMcpCreatorAuthority(params) {
|
|
@@ -6380,6 +5225,7 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
6380
5225
|
const bundleManifestRegistry = resolveCodexAttemptBundleManifestRegistry(params.preparedModelRuntime);
|
|
6381
5226
|
const bundleMcpThreadConfig = await loadCodexBundleMcpThreadConfig({
|
|
6382
5227
|
workspaceDir: effectiveWorkspace,
|
|
5228
|
+
agentId: sessionAgentId,
|
|
6383
5229
|
cfg: params.config,
|
|
6384
5230
|
toolsEnabled: usesSupervisionConnection || supportsModelTools(params.model),
|
|
6385
5231
|
disableTools: params.disableTools,
|
|
@@ -6388,7 +5234,7 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
6388
5234
|
toolOverrides: codexMcpToolOverrides
|
|
6389
5235
|
});
|
|
6390
5236
|
const authenticatedScheduledMode = params.trigger === "cron" && params.scheduledToolPolicy !== void 0 && Array.isArray(params.toolsAllow);
|
|
6391
|
-
const
|
|
5237
|
+
const scheduledConfiguredMcpSurface = authenticatedScheduledMode && (bundleMcpThreadConfig.staticServerNames.length > 0 || mutable.startupBinding?.configuredMcpOwnershipVersion === 1);
|
|
6392
5238
|
const cronCreatorAuthorityCapability = params.cronCreatorAuthorityCapability;
|
|
6393
5239
|
const hasFreshCreatorAuthority = cronCreatorAuthorityCapability?.active === true && cronCreatorAuthorityCapability.runId === params.runId && !cronCreatorAuthorityCapability.signal.aborted;
|
|
6394
5240
|
const mayResolveScheduledConfiguredMcpCreatorAuthority = !authenticatedScheduledMode && canResolveScheduledConfiguredMcpCreatorAuthority({
|
|
@@ -6415,6 +5261,7 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
6415
5261
|
runtimeSessionKey: sandboxSessionKey,
|
|
6416
5262
|
sandboxExecServerEnabled
|
|
6417
5263
|
});
|
|
5264
|
+
const configuredMcpSurface = scheduledConfiguredMcpSurface ? "scheduled" : !nativeToolSurfaceEnabled && bundleMcpThreadConfig.staticServerNames.length > 0 ? "transient" : void 0;
|
|
6418
5265
|
preDynamicStartupStages.mark("native-tool-surface");
|
|
6419
5266
|
const nativeProviderWebSearchSupport = resolveCodexWebSearchPlan({
|
|
6420
5267
|
config: params.config,
|
|
@@ -6464,7 +5311,7 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
6464
5311
|
bundleMcpThreadConfig,
|
|
6465
5312
|
bundleManifestRegistry,
|
|
6466
5313
|
authenticatedScheduledMode,
|
|
6467
|
-
|
|
5314
|
+
configuredMcpSurface,
|
|
6468
5315
|
canResolveScheduledConfiguredMcpCreatorAuthority: mayResolveScheduledConfiguredMcpCreatorAuthority,
|
|
6469
5316
|
codexMcpToolOverrides,
|
|
6470
5317
|
sandboxExecServerEnabled,
|
|
@@ -6558,7 +5405,6 @@ function resolveCodexDynamicToolDirectNames(params, hostSystemAgentActive = fals
|
|
|
6558
5405
|
const names = [];
|
|
6559
5406
|
if (hostSystemAgentActive && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow)) names.push("openclaw");
|
|
6560
5407
|
if (params.sourceReplyDeliveryMode === "message_tool_only") names.push("message");
|
|
6561
|
-
names.push("progress_card");
|
|
6562
5408
|
return names;
|
|
6563
5409
|
}
|
|
6564
5410
|
//#endregion
|
|
@@ -6574,37 +5420,32 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6574
5420
|
const { runtime, attemptTools } = context;
|
|
6575
5421
|
const { connection } = runtime;
|
|
6576
5422
|
const { params, computerUseConfig, runAbortController, appServer, sessionAgentId } = connection;
|
|
5423
|
+
const autoApprove = shouldAutoApproveCodexAppServerApprovals(appServer);
|
|
6577
5424
|
const { compactionPlanState, toolBridge, toolOutcomeOrdinals, suppressedDynamicToolOutcomeOrdinals, allocateCodexToolOutcomeOrdinal } = attemptTools;
|
|
6578
|
-
const { state, turnIdRef, userInputBridgeRef, openClawDynamicToolExecutions, pendingOpenClawDynamicToolCompletionIds,
|
|
5425
|
+
const { state, turnIdRef, userInputBridgeRef, openClawDynamicToolExecutions, pendingOpenClawDynamicToolCompletionIds, noteProgress } = turnRuntime;
|
|
6579
5426
|
const { emitExecutionPhaseOnce, scheduleTurnReleaseAfterTerminalDynamicTool, scheduleTerminalDynamicToolReleaseCheck } = lifecycle;
|
|
6580
5427
|
const handleServerRequest = async (request, scope, requestSignal = new AbortController().signal) => {
|
|
6581
5428
|
const signal = AbortSignal.any([runAbortController.signal, requestSignal]);
|
|
6582
5429
|
const turnId = turnIdRef.current;
|
|
6583
5430
|
const projector = projectorRef.current;
|
|
6584
|
-
let armCompletionWatchOnResponse = false;
|
|
6585
5431
|
let requestCountsAsTurnActivity = false;
|
|
6586
|
-
|
|
6587
|
-
const markCurrentTurnRequestProgress = (options) => {
|
|
5432
|
+
const markCurrentTurnRequestProgress = () => {
|
|
6588
5433
|
state.activeAppServerTurnRequests += 1;
|
|
6589
|
-
requestKeepsAttemptWatchArmed = options?.hasIndependentTimeout !== true;
|
|
6590
|
-
if (requestKeepsAttemptWatchArmed) state.activeAppServerTurnRequestsWithoutTimeout += 1;
|
|
6591
|
-
turnWatches.clearCompletionIdleTimer();
|
|
6592
|
-
turnWatches.disarmAssistantCompletionIdleWatch();
|
|
6593
5434
|
requestCountsAsTurnActivity = true;
|
|
6594
|
-
|
|
5435
|
+
noteProgress(`request:${request.method}:start`);
|
|
6595
5436
|
};
|
|
6596
5437
|
try {
|
|
6597
5438
|
if (!turnId) return;
|
|
6598
5439
|
if (request.method === "mcpServer/elicitation/request") {
|
|
6599
|
-
if (!scope.turnId || scope.turnId === turnId)
|
|
6600
|
-
armCompletionWatchOnResponse = true;
|
|
6601
|
-
markCurrentTurnRequestProgress();
|
|
6602
|
-
}
|
|
5440
|
+
if (!scope.turnId || scope.turnId === turnId) markCurrentTurnRequestProgress();
|
|
6603
5441
|
const approvalResult = await routeCodexAppServerElicitationRequest({
|
|
6604
5442
|
requestParams: request.params,
|
|
6605
5443
|
paramsForRun: params,
|
|
6606
5444
|
threadId: resourceState.thread.threadId,
|
|
6607
5445
|
turnId,
|
|
5446
|
+
autoApproveMcpTools: autoApprove,
|
|
5447
|
+
projectedMcpServers: runtime.bundleMcpThreadConfig.configPatch?.mcp_servers,
|
|
5448
|
+
getActiveMcpToolCall: (serverName) => projector?.getActiveMcpToolCall(serverName),
|
|
6608
5449
|
pluginAppPolicyContext: resourceState.thread.pluginAppPolicyContext,
|
|
6609
5450
|
...computerUseConfig.enabled ? { computerUseMcpServerName: computerUseConfig.mcpServerName } : {},
|
|
6610
5451
|
signal
|
|
@@ -6616,10 +5457,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6616
5457
|
});
|
|
6617
5458
|
}
|
|
6618
5459
|
if (request.method === "item/tool/requestUserInput") {
|
|
6619
|
-
if (scope.turnId === turnId)
|
|
6620
|
-
armCompletionWatchOnResponse = true;
|
|
6621
|
-
markCurrentTurnRequestProgress();
|
|
6622
|
-
}
|
|
5460
|
+
if (scope.turnId === turnId) markCurrentTurnRequestProgress();
|
|
6623
5461
|
return await userInputBridgeRef.current?.handleRequest({
|
|
6624
5462
|
id: request.id,
|
|
6625
5463
|
params: request.params
|
|
@@ -6627,10 +5465,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6627
5465
|
}
|
|
6628
5466
|
if (request.method !== "item/tool/call") {
|
|
6629
5467
|
if (isCodexAppServerApprovalRequest(request.method)) {
|
|
6630
|
-
if (scope.turnId === turnId)
|
|
6631
|
-
armCompletionWatchOnResponse = true;
|
|
6632
|
-
markCurrentTurnRequestProgress();
|
|
6633
|
-
}
|
|
5468
|
+
if (scope.turnId === turnId) markCurrentTurnRequestProgress();
|
|
6634
5469
|
return await handleCodexAppServerApprovalRequest({
|
|
6635
5470
|
method: request.method,
|
|
6636
5471
|
requestParams: request.params,
|
|
@@ -6638,7 +5473,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6638
5473
|
threadId: resourceState.thread.threadId,
|
|
6639
5474
|
turnId,
|
|
6640
5475
|
nativeHookRelay: resourceState.nativeHookRelay,
|
|
6641
|
-
autoApprove
|
|
5476
|
+
autoApprove,
|
|
6642
5477
|
signal,
|
|
6643
5478
|
onNativeToolFailureDisposition: (itemId, disposition, approvalKind) => projector?.recordNativeToolApprovalFailure(itemId, disposition, approvalKind)
|
|
6644
5479
|
});
|
|
@@ -6649,15 +5484,11 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6649
5484
|
if (!call || call.threadId !== resourceState.thread.threadId || call.turnId !== turnId) return;
|
|
6650
5485
|
const replayedExecution = openClawDynamicToolExecutions.get(call);
|
|
6651
5486
|
if (replayedExecution) {
|
|
6652
|
-
|
|
6653
|
-
markCurrentTurnRequestProgress({ hasIndependentTimeout: true });
|
|
6654
|
-
state.turnCrossedToolHandoff = true;
|
|
5487
|
+
markCurrentTurnRequestProgress();
|
|
6655
5488
|
return toCodexDynamicToolProtocolResponse(await replayedExecution);
|
|
6656
5489
|
}
|
|
6657
5490
|
const toolCallOrdinal = allocateCodexToolOutcomeOrdinal?.(call.callId);
|
|
6658
|
-
|
|
6659
|
-
markCurrentTurnRequestProgress({ hasIndependentTimeout: true });
|
|
6660
|
-
state.turnCrossedToolHandoff = true;
|
|
5491
|
+
markCurrentTurnRequestProgress();
|
|
6661
5492
|
pendingOpenClawDynamicToolCompletionIds.add(call.callId);
|
|
6662
5493
|
trajectoryRecorder?.recordEvent("tool.call", {
|
|
6663
5494
|
threadId: call.threadId,
|
|
@@ -6834,17 +5665,10 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6834
5665
|
}
|
|
6835
5666
|
} finally {
|
|
6836
5667
|
if (requestCountsAsTurnActivity) {
|
|
6837
|
-
state.activeAppServerTurnRequests
|
|
6838
|
-
|
|
6839
|
-
const postToolContinuationTimeoutMs = request.method === "item/tool/call" && state.turnCrossedToolHandoff ? postToolRawAssistantCompletionIdleTimeoutMs : void 0;
|
|
6840
|
-
turnWatches.touchActivity(`request:${request.method}:response`, {
|
|
6841
|
-
arm: armCompletionWatchOnResponse,
|
|
6842
|
-
attemptProgress: true,
|
|
6843
|
-
...postToolContinuationTimeoutMs !== void 0 ? { attemptTimeoutMs: postToolContinuationTimeoutMs } : {}
|
|
6844
|
-
});
|
|
6845
|
-
if (armCompletionWatchOnResponse && postToolContinuationTimeoutMs !== void 0) turnWatches.armCompletionIdleWatch({ timeoutMs: postToolContinuationTimeoutMs });
|
|
5668
|
+
state.activeAppServerTurnRequests -= 1;
|
|
5669
|
+
noteProgress(`request:${request.method}:response`);
|
|
6846
5670
|
scheduleTerminalDynamicToolReleaseCheck();
|
|
6847
|
-
}
|
|
5671
|
+
}
|
|
6848
5672
|
}
|
|
6849
5673
|
};
|
|
6850
5674
|
return { handleServerRequest };
|
|
@@ -6853,7 +5677,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6853
5677
|
//#region extensions/codex/src/app-server/attempt-runtime-artifact.ts
|
|
6854
5678
|
async function verifyStartupArtifact(params) {
|
|
6855
5679
|
if (!params.request) return;
|
|
6856
|
-
const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-
|
|
5680
|
+
const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-C3jVimFn.js");
|
|
6857
5681
|
const runtimeArtifact = readCodexAppServerClientRuntimeArtifact(params.client);
|
|
6858
5682
|
const expected = params.request.expected;
|
|
6859
5683
|
const matchesExpected = !expected || runtimeArtifact?.id === expected.id && runtimeArtifact.fingerprint === expected.fingerprint;
|
|
@@ -7100,14 +5924,13 @@ async function startCodexAttemptThread(params) {
|
|
|
7100
5924
|
startupClientForAbandonedRequestCleanup = void 0;
|
|
7101
5925
|
},
|
|
7102
5926
|
operation: async () => {
|
|
7103
|
-
const threadConfig = mergeCodexThreadConfigs(params.
|
|
5927
|
+
const threadConfig = mergeCodexThreadConfigs(params.configuredMcpDynamicSurface ? void 0 : params.bundleMcpThreadConfig?.configPatch);
|
|
7104
5928
|
const { pluginThreadConfigRequired, pluginThreadConfigPluginConfig, resolvedPluginPolicy, enabledPluginConfigKeys } = resolveCodexPluginThreadConfigStartupPolicy({
|
|
7105
5929
|
pluginConfig: params.pluginConfig,
|
|
7106
5930
|
nativeToolSurfaceEnabled: params.nativeToolSurfaceEnabled,
|
|
7107
5931
|
scheduledRuntimeAuthority: params.buildAttemptParams().scheduledRuntimeAuthority
|
|
7108
5932
|
});
|
|
7109
|
-
|
|
7110
|
-
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) ? {
|
|
7111
5934
|
...params.appServer,
|
|
7112
5935
|
approvalPolicy: withMcpElicitationsApprovalPolicy(params.appServer.approvalPolicy)
|
|
7113
5936
|
} : params.appServer;
|
|
@@ -7299,9 +6122,9 @@ async function startCodexAttemptThread(params) {
|
|
|
7299
6122
|
nativeCodeModeEnabled: params.nativeToolSurfaceEnabled,
|
|
7300
6123
|
nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
|
|
7301
6124
|
nativeCodeModeOnlyEnabled: params.appServer.codeModeOnly,
|
|
7302
|
-
userMcpServersEnabled: params.
|
|
7303
|
-
mcpServersFingerprint: params.
|
|
7304
|
-
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,
|
|
7305
6128
|
configuredMcpOwnershipVersion: params.configuredMcpOwnershipVersion,
|
|
7306
6129
|
environmentSelection: startupEnvironmentSelection,
|
|
7307
6130
|
appServerRuntimeFingerprint,
|
|
@@ -7380,10 +6203,7 @@ async function startCodexAttemptThread(params) {
|
|
|
7380
6203
|
if (startupAbandoned || params.signal.aborted) {
|
|
7381
6204
|
if (startupClientForAbandonedRequestCleanup === startupClient) startupClientForAbandonedRequestCleanup = void 0;
|
|
7382
6205
|
await closeCodexStartupClientBestEffort(startupClient);
|
|
7383
|
-
} else if (!isCodexAppServerStartSelectionChangedError(startupAttemptError) && (shouldClearSharedClientAfterStartupRace(startupAttemptError) || shouldClearSharedClientAfterStartupFailure({
|
|
7384
|
-
error: startupAttemptError,
|
|
7385
|
-
spawnedBy: params.spawnedBy
|
|
7386
|
-
}))) {
|
|
6206
|
+
} else if (!isCodexAppServerStartSelectionChangedError(startupAttemptError) && (shouldClearSharedClientAfterStartupRace(startupAttemptError) || shouldClearSharedClientAfterStartupFailure(startupAttemptError, params.spawnedBy))) {
|
|
7387
6207
|
if (startupClientForAbandonedRequestCleanup === startupClient) startupClientForAbandonedRequestCleanup = void 0;
|
|
7388
6208
|
await closeCodexStartupClientBestEffort(startupClient);
|
|
7389
6209
|
}
|
|
@@ -7432,10 +6252,7 @@ async function startCodexAttemptThread(params) {
|
|
|
7432
6252
|
releaseSharedClientLease = void 0;
|
|
7433
6253
|
await closeCodexStartupClientBestEffort(startupClientForAbandonedRequestCleanup);
|
|
7434
6254
|
startupClientForAbandonedRequestCleanup = void 0;
|
|
7435
|
-
} else if (!isCodexAppServerStartSelectionChangedError(error) && (shouldClearSharedClientAfterStartupRace(error) || shouldClearSharedClientAfterStartupFailure({
|
|
7436
|
-
error,
|
|
7437
|
-
spawnedBy: params.spawnedBy
|
|
7438
|
-
}))) {
|
|
6255
|
+
} else if (!isCodexAppServerStartSelectionChangedError(error) && (shouldClearSharedClientAfterStartupRace(error) || shouldClearSharedClientAfterStartupFailure(error, params.spawnedBy))) {
|
|
7439
6256
|
releaseSharedClientLease?.();
|
|
7440
6257
|
releaseSharedClientLease = void 0;
|
|
7441
6258
|
await closeCodexStartupClientBestEffort(startupClientForAbandonedRequestCleanup);
|
|
@@ -7449,9 +6266,8 @@ async function startCodexAttemptThread(params) {
|
|
|
7449
6266
|
function shouldClearSharedClientAfterStartupRace(error) {
|
|
7450
6267
|
return isCodexAppServerStartupError(error) || isCodexAppServerRequestTimeoutError(error);
|
|
7451
6268
|
}
|
|
7452
|
-
function shouldClearSharedClientAfterStartupFailure(
|
|
7453
|
-
|
|
7454
|
-
return isCodexAppServerBrokenPipeError(params.error) || !params.spawnedBy;
|
|
6269
|
+
function shouldClearSharedClientAfterStartupFailure(error, spawnedBy) {
|
|
6270
|
+
return !isCodexAppServerOverloadError(error) && !(error instanceof AgentHarnessPreflightError && error.scope === void 0) && (isCodexAppServerBrokenPipeError(error) || !spawnedBy);
|
|
7455
6271
|
}
|
|
7456
6272
|
//#endregion
|
|
7457
6273
|
//#region extensions/codex/src/app-server/run-attempt-start.ts
|
|
@@ -7461,7 +6277,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
7461
6277
|
const { runtime, attemptTools, promptState } = context;
|
|
7462
6278
|
const { connection, runtimeParams, preparedAuthBinding, buildActiveRunAttemptParams, startupAuthAccountCacheKey, startupEnvApiKeyCacheKey, bundleMcpThreadConfig, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, effectiveRuntimeModelId, sandboxExecServerEnabled } = runtime;
|
|
7463
6279
|
const { toolBridge, toolState } = attemptTools;
|
|
7464
|
-
const developerInstructions = joinPresentSections(turnState.promptBuild.developerInstructions, attemptTools.
|
|
6280
|
+
const developerInstructions = joinPresentSections(turnState.promptBuild.developerInstructions, attemptTools.configuredMcp?.diagnosticNotice);
|
|
7465
6281
|
const { params, attemptClientFactory, bindingStore, appServer, pluginConfig, computerUseConfig, startupClientAuthProfileId, runtimeArtifactRequest, startupPreparedAuth, agentDir, sessionAgentId, effectiveWorkspace, effectiveCwd, sandbox, runAbortController, usesSupervisionConnection, resolveReviewerPolicyContext, resolveRuntimeOptionsForCurrentBinding, startupAuthProfileId, startupAuthRequirement, abortFromUpstream } = connection;
|
|
7466
6282
|
let pluginAppServer = withCodexAppServerFastModeServiceTier(appServer, runtimeParams);
|
|
7467
6283
|
const loopDetectionEnabled = (sessionAgentId && params.config ? resolveAgentConfig$1(params.config, sessionAgentId)?.tools?.loopDetection?.enabled : void 0) ?? params.config?.tools?.loopDetection?.enabled ?? false;
|
|
@@ -7501,6 +6317,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
7501
6317
|
buildFinalConfigPatch: buildNativeHookRelayFinalConfigPatch,
|
|
7502
6318
|
nativeHookRelayRequired: connection.options.nativeHookRelay?.enabled !== false && params.pluginHarnessToolPolicyRestricted !== true && connection.nativeHookRelayEvents.includes("pre_tool_use") && (hasBeforeToolCallPolicy() || appServer.loopDetectionPreToolUseRelay && Boolean(connection.sandboxSessionKey) && loopDetectionEnabled),
|
|
7503
6319
|
bundleMcpThreadConfig,
|
|
6320
|
+
configuredMcpDynamicSurface: attemptTools.configuredMcp !== void 0,
|
|
7504
6321
|
configuredMcpOwnershipVersion: attemptTools.configuredMcpOwnershipVersion,
|
|
7505
6322
|
nativeToolSurfaceEnabled,
|
|
7506
6323
|
nativeProviderWebSearchSupport,
|
|
@@ -7583,7 +6400,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
7583
6400
|
recordCodexTrajectoryContext(trajectoryRecorder, {
|
|
7584
6401
|
attempt: params,
|
|
7585
6402
|
cwd: effectiveCwd,
|
|
7586
|
-
developerInstructions: joinPresentSections(buildRenderedCodexDeveloperInstructions(), attemptTools.
|
|
6403
|
+
developerInstructions: joinPresentSections(buildRenderedCodexDeveloperInstructions(), attemptTools.configuredMcp?.diagnosticNotice),
|
|
7587
6404
|
prompt: turnState.codexTurnPromptText,
|
|
7588
6405
|
tools: toolBridge.availableSpecs
|
|
7589
6406
|
});
|
|
@@ -7597,7 +6414,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
7597
6414
|
await runCleanupStep("codex-start-failure-sandbox-release", releaseSandboxExecEnvironment);
|
|
7598
6415
|
await runCleanupStep("codex-start-failure-shared-client-release", releaseSharedClientLeaseAndRetireOneShotClient);
|
|
7599
6416
|
await runCleanupStep("codex-start-failure-abort-listener", () => params.abortSignal?.removeEventListener("abort", abortFromUpstream));
|
|
7600
|
-
throw state.executionDisconnectError ?? error;
|
|
6417
|
+
throw error instanceof CodexThreadPolicyHandoffError ? error : state.executionDisconnectError ?? error;
|
|
7601
6418
|
}
|
|
7602
6419
|
}
|
|
7603
6420
|
//#endregion
|
|
@@ -7606,7 +6423,7 @@ function isAuthorityResolutionOperationAbort(error, signal) {
|
|
|
7606
6423
|
return signal?.aborted === true && error === signal.reason;
|
|
7607
6424
|
}
|
|
7608
6425
|
async function prepareCodexAttemptTools(runtime) {
|
|
7609
|
-
const { connection, bundleMcpThreadConfig, bundleManifestRegistry, runtimeParams, effectiveRuntimeModelId, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, hookChannelId, codexMcpToolOverrides, authenticatedScheduledMode,
|
|
6426
|
+
const { connection, bundleMcpThreadConfig, bundleManifestRegistry, runtimeParams, effectiveRuntimeModelId, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, hookChannelId, codexMcpToolOverrides, authenticatedScheduledMode, configuredMcpSurface, canResolveScheduledConfiguredMcpCreatorAuthority } = runtime;
|
|
7610
6427
|
const { params, preDynamicStartupStages, mutable, startupAuthProfileId, resolvedWorkspace, effectiveWorkspace, effectiveCwd, sandboxSessionKey, contextSessionKey, sandbox, sessionPermissionPolicy, runAbortController, sessionAgentId, policyAgentId, pluginConfig, profilerEnabled, agentDir } = connection;
|
|
7611
6428
|
const preDynamicSummary = preDynamicStartupStages.snapshot();
|
|
7612
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)}`, {
|
|
@@ -7655,16 +6472,24 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7655
6472
|
const cronCreatorToolAllowlistCaptureRef = {};
|
|
7656
6473
|
const scheduledAppAuthoritySourceRef = {};
|
|
7657
6474
|
const preparedChatgptAuth = connection.startupPreparedAuth?.kind === "profile" && connection.startupPreparedAuth.snapshot?.loginParams.type === "chatgptAuthTokens" && connection.startupPreparedAuth.snapshot.chatgptAccountId ? {
|
|
6475
|
+
kind: "prepared-profile",
|
|
7658
6476
|
profileId: connection.startupPreparedAuth.profileId,
|
|
7659
6477
|
accountId: connection.startupPreparedAuth.snapshot.chatgptAccountId
|
|
7660
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;
|
|
7661
6484
|
const appPolicy = resolveCodexPluginsPolicy(pluginConfig);
|
|
6485
|
+
const codexAppsMayBeVisible = appPolicy.enabled && (appPolicy.allowAllPlugins || appPolicy.pluginPolicies.some((entry) => entry.enabled));
|
|
7662
6486
|
const appCreatorCapture = resolveScheduledCodexAppCreatorCaptureDecision({
|
|
7663
|
-
appsMayBeVisible:
|
|
6487
|
+
appsMayBeVisible: codexAppsMayBeVisible,
|
|
7664
6488
|
authenticatedScheduledMode,
|
|
7665
6489
|
usesSupervisionConnection: connection.usesSupervisionConnection,
|
|
7666
6490
|
homeScope: connection.appServer.start.homeScope,
|
|
7667
|
-
hasPreparedAccountIdentity: Boolean(preparedChatgptAuth)
|
|
6491
|
+
hasPreparedAccountIdentity: Boolean(preparedChatgptAuth),
|
|
6492
|
+
hasConfiguredAppServerIdentity: Boolean(configuredAppServerAuth)
|
|
7668
6493
|
});
|
|
7669
6494
|
const codexAppAuthorityUnavailableReason = appCreatorCapture.unavailableReason;
|
|
7670
6495
|
const canResolveScheduledCodexAppAuthority = appCreatorCapture.supported;
|
|
@@ -7675,6 +6500,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7675
6500
|
let resolveCreatorAuthorityImpl;
|
|
7676
6501
|
const runtimeYieldCompletionClaim = {};
|
|
7677
6502
|
const commonToolParams = {
|
|
6503
|
+
nodeExecAvailability: {},
|
|
7678
6504
|
params: dynamicToolParams,
|
|
7679
6505
|
resolvedWorkspace,
|
|
7680
6506
|
effectiveWorkspace,
|
|
@@ -7711,6 +6537,32 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7711
6537
|
return pending;
|
|
7712
6538
|
} } : {}
|
|
7713
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
|
+
}
|
|
7714
6566
|
const tools = await buildDynamicTools({
|
|
7715
6567
|
...commonToolParams,
|
|
7716
6568
|
registerRunCleanup: (cleanup) => runCleanups.push(cleanup),
|
|
@@ -7723,7 +6575,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7723
6575
|
toolState.webSearchAllowed = allowed;
|
|
7724
6576
|
}
|
|
7725
6577
|
});
|
|
7726
|
-
const registeredTools = await buildDynamicTools({
|
|
6578
|
+
const registeredTools = nativeSpecs ? [] : await buildDynamicTools({
|
|
7727
6579
|
...commonToolParams,
|
|
7728
6580
|
forceHeartbeatTool: true,
|
|
7729
6581
|
ignoreDisableMessageTool: true,
|
|
@@ -7781,9 +6633,10 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7781
6633
|
...params.memberRoleIds?.length ? { roleIds: [...params.memberRoleIds] } : {}
|
|
7782
6634
|
};
|
|
7783
6635
|
const hasRequester = Object.keys(requester).length > 0;
|
|
7784
|
-
const
|
|
6636
|
+
const configuredMcp = configuredMcpSurface ? await materializeStaticMcpToolsForHarnessRun({
|
|
7785
6637
|
sessionId: params.sessionId,
|
|
7786
6638
|
sessionKey: params.sessionKey,
|
|
6639
|
+
agentId: sessionAgentId,
|
|
7787
6640
|
workspaceDir: effectiveWorkspace,
|
|
7788
6641
|
agentDir: policyContext.agentDir,
|
|
7789
6642
|
cfg: params.config,
|
|
@@ -7792,6 +6645,29 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7792
6645
|
toolsAllow: params.toolsAllow,
|
|
7793
6646
|
toolOverrides: codexMcpToolOverrides,
|
|
7794
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
|
+
} } : {},
|
|
7795
6671
|
policyContext,
|
|
7796
6672
|
warn: (message) => embeddedAgentLog.warn(message)
|
|
7797
6673
|
}) : void 0;
|
|
@@ -7808,13 +6684,13 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7808
6684
|
requesterSenderId: params.senderId,
|
|
7809
6685
|
agentAccountId: params.agentAccountId,
|
|
7810
6686
|
messageChannel: params.messageChannel ?? params.messageProvider,
|
|
7811
|
-
reservedToolNames,
|
|
6687
|
+
reservedToolNames: [...reservedToolNames, ...configuredMcp?.tools.map((tool) => tool.name) ?? []],
|
|
7812
6688
|
toolsAllow: params.toolsAllow,
|
|
7813
6689
|
policyContext,
|
|
7814
6690
|
warn: (message) => embeddedAgentLog.warn(message)
|
|
7815
6691
|
});
|
|
7816
|
-
const scopedExecutable = filterCodexDynamicTools(
|
|
7817
|
-
const scopedAdvertised = filterCodexDynamicTools(
|
|
6692
|
+
const scopedExecutable = filterCodexDynamicTools([...configuredMcp?.tools ?? [], ...scopedMcpTools?.tools ?? []], pluginConfig);
|
|
6693
|
+
const scopedAdvertised = filterCodexDynamicTools([...configuredMcp?.tools ?? [], ...scopedMcpTools?.advertisedTools ?? []], pluginConfig);
|
|
7818
6694
|
const toolsWithScopedMcp = scopedExecutable.length > 0 ? [...tools, ...scopedExecutable] : tools;
|
|
7819
6695
|
const registeredWithScopedMcp = scopedAdvertised.length > 0 ? [...registeredTools, ...scopedAdvertised] : registeredTools;
|
|
7820
6696
|
const hookContext = {
|
|
@@ -7849,6 +6725,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7849
6725
|
toolBridge = createCodexDynamicToolBridge({
|
|
7850
6726
|
tools: toolsWithScopedMcp,
|
|
7851
6727
|
registeredTools: registeredWithScopedMcp,
|
|
6728
|
+
registeredSpecs: nativeSpecs,
|
|
7852
6729
|
signal: runAbortController.signal,
|
|
7853
6730
|
computerContextEpoch,
|
|
7854
6731
|
loading: resolveCodexDynamicToolsLoadingForRuntime(pluginConfig, effectiveRuntimeModelId, { connectionClass: connection.appServer.connectionClass }),
|
|
@@ -7867,9 +6744,9 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7867
6744
|
await captureFinalCodexCronCreatorToolAllowlist(authorityTools, captureRef, toolBridge.availableTools);
|
|
7868
6745
|
if (!captureRef.value) throw new Error("cron creator authority snapshot did not produce provenance");
|
|
7869
6746
|
const appSource = scheduledAppAuthoritySourceRef.current;
|
|
7870
|
-
const runtimeAuthority = canResolveScheduledCodexAppAuthority &&
|
|
6747
|
+
const runtimeAuthority = canResolveScheduledCodexAppAuthority && scheduledCodexAppAuth ? appSource ? await captureScheduledCodexAppAuthority({
|
|
7871
6748
|
...appSource,
|
|
7872
|
-
|
|
6749
|
+
auth: scheduledCodexAppAuth,
|
|
7873
6750
|
signal: options?.signal
|
|
7874
6751
|
}) : (() => {
|
|
7875
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.");
|
|
@@ -7885,8 +6762,9 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7885
6762
|
const authorityRuntimeId = `cron-authority:${params.runId}`;
|
|
7886
6763
|
let materialized;
|
|
7887
6764
|
try {
|
|
7888
|
-
materialized = await
|
|
6765
|
+
materialized = await materializeStaticMcpToolsForHarnessRun({
|
|
7889
6766
|
sessionId: authorityRuntimeId,
|
|
6767
|
+
agentId: sessionAgentId,
|
|
7890
6768
|
workspaceDir: effectiveWorkspace,
|
|
7891
6769
|
agentDir: policyContext.agentDir,
|
|
7892
6770
|
cfg: params.config,
|
|
@@ -7895,6 +6773,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7895
6773
|
toolsAllow: params.toolsAllow,
|
|
7896
6774
|
toolOverrides: codexMcpToolOverrides,
|
|
7897
6775
|
autoApproveCodexAppServerApprovals: shouldAutoApproveCodexAppServerApprovals(connection.appServer),
|
|
6776
|
+
projectedMcpServers: bundleMcpThreadConfig.configPatch?.mcp_servers,
|
|
7898
6777
|
policyContext,
|
|
7899
6778
|
warn: (message) => embeddedAgentLog.warn(message),
|
|
7900
6779
|
retireSessionRuntimeAfterDispose: true
|
|
@@ -7926,8 +6805,8 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7926
6805
|
tools: toolsWithScopedMcp,
|
|
7927
6806
|
registeredTools: registeredWithScopedMcp,
|
|
7928
6807
|
scopedMcpTools,
|
|
7929
|
-
|
|
7930
|
-
configuredMcpOwnershipVersion:
|
|
6808
|
+
configuredMcp,
|
|
6809
|
+
configuredMcpOwnershipVersion: configuredMcpSurface === "scheduled" ? 1 : void 0,
|
|
7931
6810
|
cronCreatorToolAllowlist,
|
|
7932
6811
|
cronCreatorToolAllowlistCaptureRef,
|
|
7933
6812
|
scheduledAppAuthoritySourceRef,
|
|
@@ -7945,7 +6824,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7945
6824
|
};
|
|
7946
6825
|
} catch (error) {
|
|
7947
6826
|
await scopedMcpTools?.dispose();
|
|
7948
|
-
await
|
|
6827
|
+
await configuredMcp?.dispose();
|
|
7949
6828
|
throw error;
|
|
7950
6829
|
}
|
|
7951
6830
|
}
|
|
@@ -7985,7 +6864,7 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
|
|
|
7985
6864
|
const { context, turnState, buildRenderedCodexDeveloperInstructions } = prompt;
|
|
7986
6865
|
const { runtime, attemptTools, hookContextWindowFields, workspaceBootstrapContext } = context;
|
|
7987
6866
|
const { connection, runtimeParams, effectiveRuntimeProviderId, effectiveRuntimeModelId } = runtime;
|
|
7988
|
-
const { tools } = attemptTools;
|
|
6867
|
+
const { tools, toolBridge } = attemptTools;
|
|
7989
6868
|
const { params, usesSupervisionConnection, codexModelCallId, codexModelCallTrace, codexModelContentCapture, appServer, runAbortController } = connection;
|
|
7990
6869
|
const { state } = turnRuntime;
|
|
7991
6870
|
const explicitSkillInputs = await resolveCodexExplicitSkillInputs({
|
|
@@ -8048,7 +6927,8 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
|
|
|
8048
6927
|
turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
|
|
8049
6928
|
skillsCollaborationInstructions: context.skillsCollaborationInstructions,
|
|
8050
6929
|
memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
|
|
8051
|
-
preserveNativeTurnSettings: usesSupervisionConnection
|
|
6930
|
+
preserveNativeTurnSettings: usesSupervisionConnection,
|
|
6931
|
+
sessionStatusAvailable: toolBridge.availableTools.some((tool) => tool.name === "session_status")
|
|
8052
6932
|
});
|
|
8053
6933
|
codexModelCallDiagnostics.setRequestPayloadBytes(utf8JsonByteLength(turnStartParams));
|
|
8054
6934
|
state.latestStartupErrorNotification = void 0;
|
|
@@ -8232,7 +7112,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
8232
7112
|
trajectoryRecorder?.recordEvent("session.ended", {
|
|
8233
7113
|
status: "error",
|
|
8234
7114
|
threadId: resourceState.thread.threadId,
|
|
8235
|
-
timedOut: state.
|
|
7115
|
+
timedOut: state.timeout !== void 0,
|
|
8236
7116
|
aborted: runAbortController.signal.aborted,
|
|
8237
7117
|
promptError: message
|
|
8238
7118
|
});
|
|
@@ -8253,8 +7133,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
8253
7133
|
});
|
|
8254
7134
|
const failureKind = classifyCodexModelCallFailureKind({
|
|
8255
7135
|
error: turnStartError,
|
|
8256
|
-
timedOut: state.
|
|
8257
|
-
turnCompletionIdleTimedOut: state.turnCompletionIdleTimedOut,
|
|
7136
|
+
timedOut: state.timeout !== void 0,
|
|
8258
7137
|
runAborted: runAbortController.signal.aborted,
|
|
8259
7138
|
abortReason: runAbortController.signal.reason,
|
|
8260
7139
|
clientClosedAbort: state.clientClosedAbort,
|
|
@@ -8275,11 +7154,10 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
8275
7154
|
ctx: hookContext,
|
|
8276
7155
|
hookRunner
|
|
8277
7156
|
});
|
|
8278
|
-
|
|
7157
|
+
if ((isIncognitoSessionKey(params.sessionKey) ? await bindingStore.mutate(bindingIdentity, {
|
|
8279
7158
|
kind: "clear",
|
|
8280
7159
|
threadId: resourceState.thread.threadId
|
|
8281
|
-
}) : true
|
|
8282
|
-
if (!state.timedOut && bindingReleased && !resourceState.startupClientUnsafe) {
|
|
7160
|
+
}) : true) && !resourceState.startupClientUnsafe) {
|
|
8283
7161
|
if (!await unsubscribeCodexThreadBestEffort(resourceState.client, {
|
|
8284
7162
|
threadId: resourceState.thread.threadId,
|
|
8285
7163
|
timeoutMs: 5e3
|
|
@@ -8352,279 +7230,56 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
8352
7230
|
return { turn };
|
|
8353
7231
|
}
|
|
8354
7232
|
//#endregion
|
|
8355
|
-
//#region extensions/codex/src/app-server/attempt-
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
let attemptIdleTimeoutOverrideMs;
|
|
8378
|
-
let attemptLastProgressAt = Date.now();
|
|
8379
|
-
let attemptLastProgressReason = "startup";
|
|
8380
|
-
let attemptLastProgressDetails;
|
|
8381
|
-
const turnCompletionIdleTimeoutMs = resolveTimerTimeoutMs(params.turnCompletionIdleTimeoutMs, 1);
|
|
8382
|
-
const turnAssistantCompletionIdleTimeoutMs = resolveTimerTimeoutMs(params.turnAssistantCompletionIdleTimeoutMs, 1);
|
|
8383
|
-
const turnAttemptIdleTimeoutMs = resolveTimerTimeoutMs(params.turnAttemptIdleTimeoutMs, 1);
|
|
8384
|
-
const turnTerminalIdleTimeoutMs = resolveTimerTimeoutMs(params.turnTerminalIdleTimeoutMs, 1);
|
|
8385
|
-
const interruptTimeoutMs = resolveTimerTimeoutMs(params.interruptTimeoutMs, 1);
|
|
8386
|
-
const resolveWatchTimeoutMs = (timeoutMs) => resolveTimerTimeoutMs(timeoutMs, 1);
|
|
8387
|
-
const clearTimer = (kind) => {
|
|
8388
|
-
const timer = timers[kind];
|
|
8389
|
-
if (timer) {
|
|
8390
|
-
clearTimeout(timer);
|
|
8391
|
-
delete timers[kind];
|
|
8392
|
-
}
|
|
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
|
|
7244
|
+
});
|
|
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?.();
|
|
8393
7255
|
};
|
|
8394
|
-
const
|
|
8395
|
-
|
|
8396
|
-
|
|
7256
|
+
const dispose = () => {
|
|
7257
|
+
deadline = { kind: "closed" };
|
|
7258
|
+
clearTimeout(timer);
|
|
7259
|
+
params.signal.removeEventListener("abort", dispose);
|
|
8397
7260
|
};
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
if (
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
scheduleWatch("completion", fireCompletionIdleTimeout, completionLastActivityAt, completionIdleTimeoutOverrideMs ?? turnCompletionIdleTimeoutMs, completionIdleWatchArmed && params.getActiveAppServerTurnRequests() === 0 && params.getActiveCompletionBlockerItemCount() === 0);
|
|
8408
|
-
}
|
|
8409
|
-
function scheduleAssistantCompletionIdleWatch() {
|
|
8410
|
-
scheduleWatch("assistant", fireAssistantCompletionIdleRelease, assistantCompletionLastActivityAt, turnAssistantCompletionIdleTimeoutMs, assistantCompletionIdleWatchArmed && params.getActiveFinalizationHookCount() === 0);
|
|
8411
|
-
}
|
|
8412
|
-
function shouldPauseAttemptIdleWatch() {
|
|
8413
|
-
if (params.getActiveAppServerTurnRequestsWithoutTimeout() > 0) return false;
|
|
8414
|
-
return params.getActiveCompletionBlockerItemCount() > 0 || params.getActiveAppServerTurnRequests() > 0;
|
|
8415
|
-
}
|
|
8416
|
-
function scheduleAttemptIdleWatch() {
|
|
8417
|
-
scheduleWatch("attempt", fireAttemptIdleTimeout, attemptLastProgressAt, attemptIdleTimeoutOverrideMs ?? turnAttemptIdleTimeoutMs, attemptIdleWatchArmed && !shouldPauseAttemptIdleWatch());
|
|
8418
|
-
}
|
|
8419
|
-
const terminalWorkIsActive = () => params.getActiveAppServerTurnRequests() > 0 || params.isTerminalTurnNotificationQueued() && params.getActiveFinalizationHookCount() > 0;
|
|
8420
|
-
const terminalIdleTimeoutMs = () => params.isTerminalTurnNotificationQueued() && !terminalWorkIsActive() ? Math.min(TURN_TERMINAL_SETTLEMENT_IDLE_TIMEOUT_MS, turnTerminalIdleTimeoutMs) : turnTerminalIdleTimeoutMs;
|
|
8421
|
-
function scheduleTerminalIdleWatch() {
|
|
8422
|
-
scheduleWatch("terminal", fireTerminalIdleTimeout, completionLastActivityAt, terminalIdleTimeoutMs(), terminalIdleWatchArmed && (params.isTerminalTurnNotificationQueued() || params.getActiveAppServerTurnRequests() === 0));
|
|
8423
|
-
}
|
|
8424
|
-
function scheduleProgressWatches() {
|
|
8425
|
-
scheduleAttemptIdleWatch();
|
|
8426
|
-
scheduleCompletionIdleWatch();
|
|
8427
|
-
scheduleTerminalIdleWatch();
|
|
8428
|
-
}
|
|
8429
|
-
function isCompletionIdleTimeoutDueBeforeAttempt(timeoutMs) {
|
|
8430
|
-
if (params.isCompleted() || params.isTerminalTurnNotificationQueued() || params.signal.aborted || !completionIdleWatchArmed || params.getActiveAppServerTurnRequests() > 0 || params.getActiveCompletionBlockerItemCount() > 0) return false;
|
|
8431
|
-
const completionTimeoutMs = completionIdleTimeoutOverrideMs ?? turnCompletionIdleTimeoutMs;
|
|
8432
|
-
if (completionTimeoutMs > timeoutMs) return false;
|
|
8433
|
-
return Math.max(0, Date.now() - completionLastActivityAt) >= completionTimeoutMs;
|
|
8434
|
-
}
|
|
8435
|
-
function recordAttemptProgress(reason, options) {
|
|
8436
|
-
attemptIdleTimeoutOverrideMs = options?.attemptTimeoutMs !== void 0 ? resolveWatchTimeoutMs(options.attemptTimeoutMs) : void 0;
|
|
8437
|
-
attemptLastProgressAt = completionLastActivityAt;
|
|
8438
|
-
attemptLastProgressReason = reason;
|
|
8439
|
-
attemptLastProgressDetails = options?.details;
|
|
8440
|
-
params.onAttemptProgress(reason, options?.details);
|
|
8441
|
-
scheduleAttemptIdleWatch();
|
|
8442
|
-
}
|
|
8443
|
-
function fireAssistantCompletionIdleRelease() {
|
|
8444
|
-
if (params.isCompleted() || params.signal.aborted || !assistantCompletionIdleWatchArmed) return;
|
|
8445
|
-
if (params.getActiveAppServerTurnRequests() > 0 || params.getActiveTurnItemCount() > 0 || params.getActiveFinalizationHookCount() > 0) {
|
|
8446
|
-
scheduleAssistantCompletionIdleWatch();
|
|
8447
|
-
return;
|
|
8448
|
-
}
|
|
8449
|
-
if (!params.canReleaseAssistantCompletionIdle()) {
|
|
8450
|
-
assistantCompletionIdleWatchArmed = false;
|
|
8451
|
-
assistantCompletionLastActivityDetails = void 0;
|
|
8452
|
-
clearTimer("assistant");
|
|
8453
|
-
return;
|
|
8454
|
-
}
|
|
8455
|
-
const idleMs = Math.max(0, Date.now() - assistantCompletionLastActivityAt);
|
|
8456
|
-
if (idleMs < turnAssistantCompletionIdleTimeoutMs) {
|
|
8457
|
-
scheduleAssistantCompletionIdleWatch();
|
|
8458
|
-
return;
|
|
8459
|
-
}
|
|
8460
|
-
assistantCompletionIdleWatchArmed = false;
|
|
8461
|
-
clearCompletionIdleTimer();
|
|
8462
|
-
clearTimer("terminal");
|
|
8463
|
-
const turnId = params.getTurnId();
|
|
8464
|
-
const fields = {
|
|
8465
|
-
threadId: params.threadId,
|
|
8466
|
-
turnId,
|
|
8467
|
-
idleMs,
|
|
8468
|
-
timeoutMs: turnAssistantCompletionIdleTimeoutMs,
|
|
8469
|
-
...assistantCompletionLastActivityDetails
|
|
8470
|
-
};
|
|
8471
|
-
params.onRecordEvent("turn.assistant_completion_idle_release", fields);
|
|
8472
|
-
embeddedAgentLog.warn("codex app-server turn released after completed assistant item without terminal event", fields);
|
|
8473
|
-
if (turnId) {
|
|
8474
|
-
params.onInterruptTurn({
|
|
8475
|
-
threadId: params.threadId,
|
|
8476
|
-
turnId,
|
|
8477
|
-
timeoutMs: interruptTimeoutMs
|
|
8478
|
-
}).finally(params.onCompleted);
|
|
8479
|
-
return;
|
|
8480
|
-
}
|
|
8481
|
-
params.onCompleted();
|
|
8482
|
-
}
|
|
8483
|
-
function reportTimeout(timeout) {
|
|
8484
|
-
params.onTimeout(timeout);
|
|
8485
|
-
const fields = {
|
|
8486
|
-
threadId: params.threadId,
|
|
8487
|
-
turnId: params.getTurnId(),
|
|
8488
|
-
idleMs: timeout.idleMs,
|
|
8489
|
-
timeoutMs: timeout.timeoutMs,
|
|
8490
|
-
lastActivityReason: timeout.lastActivityReason,
|
|
8491
|
-
...timeout.details
|
|
8492
|
-
};
|
|
8493
|
-
params.onRecordEvent(`turn.${timeout.kind}_idle_timeout`, fields);
|
|
8494
|
-
embeddedAgentLog.warn(`codex app-server turn idle timed out waiting for ${timeout.kind === "terminal" ? "terminal event" : timeout.kind}`, fields);
|
|
8495
|
-
params.onAbort(`turn_${timeout.kind}_idle_timeout`);
|
|
8496
|
-
}
|
|
8497
|
-
function fireAttemptIdleTimeout() {
|
|
8498
|
-
if (params.isCompleted() || params.signal.aborted || !attemptIdleWatchArmed || shouldPauseAttemptIdleWatch()) return;
|
|
8499
|
-
const idleMs = Math.max(0, Date.now() - attemptLastProgressAt);
|
|
8500
|
-
const timeoutMs = attemptIdleTimeoutOverrideMs ?? turnAttemptIdleTimeoutMs;
|
|
8501
|
-
if (idleMs < timeoutMs) {
|
|
8502
|
-
scheduleAttemptIdleWatch();
|
|
8503
|
-
return;
|
|
8504
|
-
}
|
|
8505
|
-
if (isCompletionIdleTimeoutDueBeforeAttempt(timeoutMs)) {
|
|
8506
|
-
fireCompletionIdleTimeout();
|
|
8507
|
-
return;
|
|
8508
|
-
}
|
|
8509
|
-
reportTimeout({
|
|
8510
|
-
kind: "progress",
|
|
8511
|
-
idleMs,
|
|
8512
|
-
timeoutMs,
|
|
8513
|
-
lastActivityReason: attemptLastProgressReason,
|
|
8514
|
-
details: attemptLastProgressDetails
|
|
8515
|
-
});
|
|
8516
|
-
}
|
|
8517
|
-
function fireCompletionIdleTimeout() {
|
|
8518
|
-
if (params.isCompleted() || params.isTerminalTurnNotificationQueued() || params.signal.aborted || !completionIdleWatchArmed || params.getActiveAppServerTurnRequests() > 0 || params.getActiveCompletionBlockerItemCount() > 0) return;
|
|
8519
|
-
const timeoutMs = completionIdleTimeoutOverrideMs ?? turnCompletionIdleTimeoutMs;
|
|
8520
|
-
const idleMs = Math.max(0, Date.now() - completionLastActivityAt);
|
|
8521
|
-
if (idleMs < timeoutMs) {
|
|
8522
|
-
scheduleCompletionIdleWatch();
|
|
8523
|
-
return;
|
|
8524
|
-
}
|
|
8525
|
-
const details = {
|
|
8526
|
-
...completionLastActivityDetails,
|
|
8527
|
-
activeAppServerTurnRequests: params.getActiveAppServerTurnRequests(),
|
|
8528
|
-
activeTurnItemCount: params.getActiveTurnItemCount(),
|
|
8529
|
-
terminalTurnNotificationQueued: params.isTerminalTurnNotificationQueued(),
|
|
8530
|
-
completionIdleWatchArmed,
|
|
8531
|
-
assistantCompletionIdleWatchArmed,
|
|
8532
|
-
terminalIdleWatchArmed
|
|
8533
|
-
};
|
|
8534
|
-
reportTimeout({
|
|
8535
|
-
kind: "completion",
|
|
8536
|
-
idleMs,
|
|
8537
|
-
timeoutMs,
|
|
8538
|
-
lastActivityReason: completionLastActivityReason,
|
|
8539
|
-
details
|
|
8540
|
-
});
|
|
8541
|
-
}
|
|
8542
|
-
function fireTerminalIdleTimeout() {
|
|
8543
|
-
if (params.isCompleted() || params.signal.aborted || !terminalIdleWatchArmed) return;
|
|
8544
|
-
if (!params.isTerminalTurnNotificationQueued() && params.getActiveAppServerTurnRequests() > 0) {
|
|
8545
|
-
scheduleTerminalIdleWatch();
|
|
8546
|
-
return;
|
|
8547
|
-
}
|
|
8548
|
-
const timeoutMs = terminalIdleTimeoutMs();
|
|
8549
|
-
const idleMs = Math.max(0, Date.now() - completionLastActivityAt);
|
|
8550
|
-
if (idleMs < timeoutMs) {
|
|
8551
|
-
scheduleTerminalIdleWatch();
|
|
8552
|
-
return;
|
|
8553
|
-
}
|
|
8554
|
-
reportTimeout({
|
|
8555
|
-
kind: "terminal",
|
|
8556
|
-
idleMs,
|
|
8557
|
-
timeoutMs,
|
|
8558
|
-
lastActivityReason: completionLastActivityReason,
|
|
8559
|
-
details: {
|
|
8560
|
-
...completionLastActivityDetails,
|
|
8561
|
-
terminalTurnNotificationQueued: params.isTerminalTurnNotificationQueued()
|
|
8562
|
-
}
|
|
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
|
|
8563
7270
|
});
|
|
8564
7271
|
}
|
|
8565
7272
|
return {
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
terminalIdleWatchArmed = true;
|
|
8575
|
-
scheduleTerminalIdleWatch();
|
|
8576
|
-
},
|
|
8577
|
-
armCompletionIdleWatch: (options) => {
|
|
8578
|
-
completionIdleWatchArmed = true;
|
|
8579
|
-
completionIdleWatchPinnedByTerminalError = options?.pinnedByTerminalError === true;
|
|
8580
|
-
completionIdleTimeoutOverrideMs = options?.timeoutMs !== void 0 ? resolveWatchTimeoutMs(options.timeoutMs) : void 0;
|
|
8581
|
-
scheduleCompletionIdleWatch();
|
|
8582
|
-
},
|
|
8583
|
-
disarmCompletionIdleWatch: () => {
|
|
8584
|
-
completionIdleWatchArmed = false;
|
|
8585
|
-
completionIdleWatchPinnedByTerminalError = false;
|
|
8586
|
-
completionIdleTimeoutOverrideMs = void 0;
|
|
8587
|
-
clearCompletionIdleTimer();
|
|
8588
|
-
},
|
|
8589
|
-
armAssistantCompletionIdleWatch: (details) => {
|
|
8590
|
-
assistantCompletionIdleWatchArmed = true;
|
|
8591
|
-
assistantCompletionLastActivityAt = Date.now();
|
|
8592
|
-
assistantCompletionLastActivityDetails = details;
|
|
8593
|
-
scheduleAssistantCompletionIdleWatch();
|
|
8594
|
-
},
|
|
8595
|
-
disarmAssistantCompletionIdleWatch: () => {
|
|
8596
|
-
assistantCompletionIdleWatchArmed = false;
|
|
8597
|
-
assistantCompletionLastActivityDetails = void 0;
|
|
8598
|
-
clearTimer("assistant");
|
|
8599
|
-
},
|
|
8600
|
-
touchActivity: (reason, options) => {
|
|
8601
|
-
completionLastActivityAt = Date.now();
|
|
8602
|
-
completionLastActivityReason = reason;
|
|
8603
|
-
completionLastActivityDetails = options?.details;
|
|
8604
|
-
completionIdleTimeoutOverrideMs = void 0;
|
|
8605
|
-
if (options?.attemptProgress) recordAttemptProgress(reason, options);
|
|
8606
|
-
params.onProgressDiagnostic(reason);
|
|
8607
|
-
if (options?.arm) {
|
|
8608
|
-
completionIdleWatchArmed = true;
|
|
8609
|
-
completionIdleWatchPinnedByTerminalError = false;
|
|
8610
|
-
}
|
|
8611
|
-
scheduleProgressWatches();
|
|
8612
|
-
},
|
|
8613
|
-
noteNotificationReceived: (method, options) => {
|
|
8614
|
-
const now = Date.now();
|
|
8615
|
-
completionLastActivityAt = Math.max(completionLastActivityAt, Math.min(now, options?.receivedAtMs ?? now));
|
|
8616
|
-
completionLastActivityReason = `notification:${method}`;
|
|
8617
|
-
if (options?.details !== void 0) completionLastActivityDetails = options.details;
|
|
8618
|
-
if (options?.attemptProgress) recordAttemptProgress(completionLastActivityReason, options);
|
|
8619
|
-
if (params.isTerminalTurnNotificationQueued()) scheduleTerminalIdleWatch();
|
|
8620
|
-
},
|
|
8621
|
-
extendAttemptIdleWatch: (timeoutMs) => {
|
|
8622
|
-
attemptIdleTimeoutOverrideMs = resolveWatchTimeoutMs(timeoutMs);
|
|
8623
|
-
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
|
+
});
|
|
8624
7281
|
},
|
|
8625
|
-
|
|
8626
|
-
clearCompletionIdleTimer,
|
|
8627
|
-
clearAllTimers
|
|
7282
|
+
dispose
|
|
8628
7283
|
};
|
|
8629
7284
|
}
|
|
8630
7285
|
//#endregion
|
|
@@ -8632,9 +7287,8 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
8632
7287
|
const CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS = 6e4;
|
|
8633
7288
|
function createCodexAttemptTurnState(resources) {
|
|
8634
7289
|
const { prompt, state: resourceState, projectorRef, trajectoryRecorder, startupTimeoutMs } = resources;
|
|
8635
|
-
const {
|
|
8636
|
-
const {
|
|
8637
|
-
const { params, options, appServer, runAbortController } = connection;
|
|
7290
|
+
const { connection } = prompt.context.runtime;
|
|
7291
|
+
const { params, options, runAbortController } = connection;
|
|
8638
7292
|
const state = {
|
|
8639
7293
|
latestStartupErrorNotification: void 0,
|
|
8640
7294
|
rateLimitsRevisionBeforeLastTurnStart: void 0,
|
|
@@ -8644,14 +7298,7 @@ function createCodexAttemptTurnState(resources) {
|
|
|
8644
7298
|
localCompletionRequested: false,
|
|
8645
7299
|
terminalTurnNotificationQueued: false,
|
|
8646
7300
|
sawCodexInterruptMarker: false,
|
|
8647
|
-
|
|
8648
|
-
turnCompletionIdleTimedOut: false,
|
|
8649
|
-
turnWatchTimeoutKind: void 0,
|
|
8650
|
-
turnWatchTimeoutIdleMs: void 0,
|
|
8651
|
-
turnWatchTimeoutMs: void 0,
|
|
8652
|
-
turnWatchTimeoutLastActivityReason: void 0,
|
|
8653
|
-
turnWatchTimeoutDetails: void 0,
|
|
8654
|
-
turnCompletionIdleTimeoutMessage: void 0,
|
|
7301
|
+
timeout: void 0,
|
|
8655
7302
|
clientClosedPromptError: void 0,
|
|
8656
7303
|
clientClosedDiagnostic: void 0,
|
|
8657
7304
|
clientClosedAbort: false,
|
|
@@ -8660,26 +7307,16 @@ function createCodexAttemptTurnState(resources) {
|
|
|
8660
7307
|
lifecycleTerminalEmitted: false,
|
|
8661
7308
|
nativeHookRelayLastRenewedAt: 0,
|
|
8662
7309
|
activeAppServerTurnRequests: 0,
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
rejectedFinalizationHookAssistant: void 0,
|
|
8666
|
-
turnCrossedToolHandoff: false,
|
|
7310
|
+
activeLocalProjections: 0,
|
|
7311
|
+
projectionClosed: false,
|
|
8667
7312
|
pendingTerminalDynamicToolRelease: void 0,
|
|
8668
7313
|
terminalDynamicToolReleaseCheckScheduled: false,
|
|
8669
7314
|
currentTurnHadNonTerminalDynamicToolResult: false
|
|
8670
7315
|
};
|
|
8671
7316
|
const { promise: completion, resolve: resolveCompletion } = createDeferred();
|
|
8672
|
-
const turnCompletionIdleTimeoutMs = resolveCodexTurnCompletionIdleTimeoutMs(options.turnCompletionIdleTimeoutMs ?? appServer.turnCompletionIdleTimeoutMs);
|
|
8673
|
-
const turnAssistantCompletionIdleTimeoutMs = resolveCodexTurnAssistantCompletionIdleTimeoutMs(options.turnAssistantCompletionIdleTimeoutMs ?? appServer.turnAssistantCompletionIdleTimeoutMs);
|
|
8674
|
-
const postToolRawAssistantCompletionIdleTimeoutMs = resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs(options.postToolRawAssistantCompletionIdleTimeoutMs ?? appServer.postToolRawAssistantCompletionIdleTimeoutMs, turnAssistantCompletionIdleTimeoutMs);
|
|
8675
|
-
const turnTerminalIdleTimeoutMs = resolveCodexTurnTerminalIdleTimeoutMs(options.turnTerminalIdleTimeoutMs, params.runTimeoutOverrideMs);
|
|
8676
|
-
const turnAttemptIdleTimeoutMs = Math.max(100, Math.floor(params.timeoutMs));
|
|
8677
7317
|
const pendingOpenClawDynamicToolCompletionIds = /* @__PURE__ */ new Set();
|
|
8678
7318
|
const openClawDynamicToolExecutions = createCodexDynamicToolExecutionRegistry();
|
|
8679
7319
|
const activeTurnItemIds = /* @__PURE__ */ new Set();
|
|
8680
|
-
const activeCompletionBlockerItemIds = /* @__PURE__ */ new Set();
|
|
8681
|
-
const activeFinalizationHookRunIds = /* @__PURE__ */ new Set();
|
|
8682
|
-
const finalizationHookBatchStatuses = /* @__PURE__ */ new Map();
|
|
8683
7320
|
const turnIdRef = {};
|
|
8684
7321
|
const userInputBridgeRef = {};
|
|
8685
7322
|
const steeringQueueRef = {};
|
|
@@ -8687,7 +7324,7 @@ function createCodexAttemptTurnState(resources) {
|
|
|
8687
7324
|
if (state.completed) return;
|
|
8688
7325
|
state.completed = true;
|
|
8689
7326
|
steeringQueueRef.current?.cancel();
|
|
8690
|
-
|
|
7327
|
+
deadlines.beginSettlement(Date.now());
|
|
8691
7328
|
resolveCompletion();
|
|
8692
7329
|
};
|
|
8693
7330
|
const interruptTurn = async (turnId, completionOptions) => {
|
|
@@ -8709,86 +7346,62 @@ function createCodexAttemptTurnState(resources) {
|
|
|
8709
7346
|
state.nativeHookRelayLastRenewedAt = now;
|
|
8710
7347
|
resourceState.nativeHookRelay.renew(resolveCodexNativeHookRelayTtlMs({
|
|
8711
7348
|
explicitTtlMs: void 0,
|
|
8712
|
-
attemptTimeoutMs:
|
|
7349
|
+
attemptTimeoutMs: params.timeoutMs,
|
|
8713
7350
|
startupTimeoutMs,
|
|
8714
7351
|
turnStartTimeoutMs: params.timeoutMs
|
|
8715
7352
|
}));
|
|
8716
7353
|
};
|
|
8717
|
-
const
|
|
8718
|
-
|
|
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,
|
|
8719
7374
|
signal: runAbortController.signal,
|
|
8720
|
-
|
|
8721
|
-
isCompleted: () => state.completed,
|
|
8722
|
-
isTerminalTurnNotificationQueued: () => state.terminalTurnNotificationQueued,
|
|
8723
|
-
getActiveAppServerTurnRequests: () => state.activeAppServerTurnRequests,
|
|
8724
|
-
getActiveAppServerTurnRequestsWithoutTimeout: () => state.activeAppServerTurnRequestsWithoutTimeout,
|
|
8725
|
-
getActiveTurnItemCount: () => activeTurnItemIds.size,
|
|
8726
|
-
getActiveCompletionBlockerItemCount: () => activeCompletionBlockerItemIds.size,
|
|
8727
|
-
getActiveFinalizationHookCount: () => state.unsettledFinalizationHookCount,
|
|
8728
|
-
canReleaseAssistantCompletionIdle: () => projectorRef.current?.hasLatestTerminalAssistantCandidateText() === true,
|
|
8729
|
-
turnCompletionIdleTimeoutMs,
|
|
8730
|
-
turnAssistantCompletionIdleTimeoutMs,
|
|
8731
|
-
turnAttemptIdleTimeoutMs,
|
|
8732
|
-
turnTerminalIdleTimeoutMs,
|
|
8733
|
-
interruptTimeoutMs: CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS,
|
|
8734
|
-
onInterruptTurn: ({ turnId, timeoutMs }) => interruptTurn(turnId, {
|
|
8735
|
-
locallyCompleted: true,
|
|
8736
|
-
timeoutMs
|
|
8737
|
-
}),
|
|
7375
|
+
onDeadlineChanged: params.onAttemptDeadlineChanged,
|
|
8738
7376
|
onTimeout: (timeout) => {
|
|
8739
|
-
state.
|
|
8740
|
-
state.turnCompletionIdleTimedOut = true;
|
|
8741
|
-
state.turnWatchTimeoutKind = timeout.kind;
|
|
8742
|
-
state.turnWatchTimeoutIdleMs = timeout.idleMs;
|
|
8743
|
-
state.turnWatchTimeoutMs = timeout.timeoutMs;
|
|
8744
|
-
state.turnWatchTimeoutLastActivityReason = timeout.lastActivityReason;
|
|
8745
|
-
state.turnWatchTimeoutDetails = timeout.details;
|
|
8746
|
-
state.turnCompletionIdleTimeoutMessage = "codex app-server turn idle timed out waiting for turn/completed";
|
|
7377
|
+
state.timeout = timeout;
|
|
8747
7378
|
projectorRef.current?.markTimedOut();
|
|
8748
|
-
|
|
8749
|
-
|
|
8750
|
-
|
|
8751
|
-
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
backend: "codex-app-server"
|
|
8759
|
-
});
|
|
8760
|
-
},
|
|
8761
|
-
onProgressDiagnostic: (reason) => {
|
|
8762
|
-
emitTrustedDiagnosticEvent({
|
|
8763
|
-
type: "run.progress",
|
|
8764
|
-
runId: params.runId,
|
|
8765
|
-
sessionId: params.sessionId,
|
|
8766
|
-
sessionKey: params.sessionKey,
|
|
8767
|
-
reason: `codex_app_server:${reason}`
|
|
8768
|
-
});
|
|
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);
|
|
8769
7389
|
}
|
|
8770
7390
|
});
|
|
8771
7391
|
return {
|
|
8772
7392
|
state,
|
|
8773
7393
|
completion,
|
|
8774
|
-
turnCompletionIdleTimeoutMs,
|
|
8775
|
-
turnAssistantCompletionIdleTimeoutMs,
|
|
8776
|
-
postToolRawAssistantCompletionIdleTimeoutMs,
|
|
8777
|
-
turnTerminalIdleTimeoutMs,
|
|
8778
|
-
turnAttemptIdleTimeoutMs,
|
|
8779
7394
|
pendingOpenClawDynamicToolCompletionIds,
|
|
8780
7395
|
openClawDynamicToolExecutions,
|
|
8781
7396
|
activeTurnItemIds,
|
|
8782
|
-
activeCompletionBlockerItemIds,
|
|
8783
|
-
activeFinalizationHookRunIds,
|
|
8784
|
-
finalizationHookBatchStatuses,
|
|
8785
7397
|
turnIdRef,
|
|
8786
7398
|
userInputBridgeRef,
|
|
8787
7399
|
steeringQueueRef,
|
|
8788
7400
|
completeTurn,
|
|
8789
7401
|
interruptTurn,
|
|
8790
7402
|
renewNativeHookRelayForTurnProgress,
|
|
8791
|
-
|
|
7403
|
+
noteProgress,
|
|
7404
|
+
deadlines
|
|
8792
7405
|
};
|
|
8793
7406
|
}
|
|
8794
7407
|
//#endregion
|
|
@@ -8804,21 +7417,26 @@ async function runCodexAppServerAttempt(params, options) {
|
|
|
8804
7417
|
attemptTools.runtimeYieldCompletionClaim.current = () => resources.state.nativeHookRelay?.hasClaimedDirectChild() ?? false;
|
|
8805
7418
|
await startCodexAttemptRuntime(resources);
|
|
8806
7419
|
const turnRuntime = createCodexAttemptTurnState(resources);
|
|
8807
|
-
const lifecycle = createCodexAttemptLifecycleController(resources, turnRuntime);
|
|
8808
|
-
const notifications = createCodexAttemptNotificationController(resources, turnRuntime, lifecycle);
|
|
8809
|
-
const { ensureCurrentThreadRoute } = await prepareCodexAttemptRoute(resources, turnRuntime, notifications, createCodexAttemptServerRequestController(resources, turnRuntime, lifecycle).handleServerRequest);
|
|
8810
|
-
const turnRequest = await prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurrentThreadRoute, notifications.waitForActiveNativeTurnCompletion);
|
|
8811
|
-
const turnStart = await startCodexAttemptTurn(resources, turnRuntime, notifications, turnRequest);
|
|
8812
|
-
if ("result" in turnStart) return turnStart.result;
|
|
8813
|
-
const activeTurn = await activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, turnStart.turn);
|
|
8814
|
-
let finalizedResult;
|
|
8815
7420
|
try {
|
|
8816
|
-
|
|
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;
|
|
8817
7437
|
} finally {
|
|
8818
|
-
|
|
7438
|
+
turnRuntime.deadlines.dispose();
|
|
8819
7439
|
}
|
|
8820
|
-
if (resources.state.executionDisconnectError && !connection.terminalState.explicitCancellationObserved) throw resources.state.executionDisconnectError;
|
|
8821
|
-
return finalizedResult;
|
|
8822
7440
|
}
|
|
8823
7441
|
//#endregion
|
|
8824
7442
|
export { runCodexAppServerAttempt };
|