@openclaw/codex 2026.7.2-beta.1 → 2026.7.2-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +1 -1
  2. package/dist/{app-server-policy-DVcxdse_.js → app-server-policy-DUMF2Xyr.js} +1 -1
  3. package/dist/{attempt-notifications-DEv9h7iC.js → attempt-notifications-Ecjyzufe.js} +3 -6
  4. package/dist/cli-metadata.js +1 -1
  5. package/dist/{command-formatters-D6ZlGNmb.js → command-formatters-NCTL7A2q.js} +38 -3
  6. package/dist/{command-handlers-Cpl9fUWv.js → command-handlers-DtFbZiba.js} +70 -15
  7. package/dist/{compact-FnJmiPNA.js → compact-Kgy26gIM.js} +4 -5
  8. package/dist/{computer-use-DVzr8OP1.js → computer-use-C7x4ZaqR.js} +4 -4
  9. package/dist/{conversation-control-DtQ-E7mr.js → conversation-control-B0s3aIjT.js} +5 -7
  10. package/dist/doctor-contract-api.js +1 -1
  11. package/dist/{dynamic-tools-BMLoaTeG.js → dynamic-tools-D_vSVmv9.js} +851 -434
  12. package/dist/harness.js +11 -6
  13. package/dist/index.js +52 -31
  14. package/dist/{media-understanding-provider-D580L0P8.js → media-understanding-provider-IPNNQre6.js} +11 -12
  15. package/dist/media-understanding-provider.js +1 -1
  16. package/dist/{models-DuKzZA6G.js → models-DD5zBdX5.js} +5 -9
  17. package/dist/{notification-correlation-DfaCm0mx.js → notification-correlation-C8DVQ_Bq.js} +3 -3
  18. package/dist/{plugin-app-cache-key-BKNjHMEs.js → plugin-app-cache-key-DJbhLYSK.js} +2 -2
  19. package/dist/{rate-limits-Dhp04Rqo.js → rate-limits-CqhWQ2R9.js} +9 -6
  20. package/dist/{request-DborTWgw.js → request-9yf9pZjf.js} +54 -8
  21. package/dist/{run-attempt-VPVJoYDP.js → run-attempt-BIoO8ISr.js} +637 -351
  22. package/dist/{config-c48K5HP9.js → session-binding-Bmt20HfB.js} +788 -3
  23. package/dist/{session-catalog-7H112Tr_.js → session-catalog-CA7R-hX2.js} +82 -45
  24. package/dist/{session-cli-B28RhCyp.js → session-cli-Bxk3-Wqz.js} +2 -2
  25. package/dist/{shared-client-D4mFI9al.js → shared-client-CSXLtCLE.js} +304 -81
  26. package/dist/{side-question-CgJBz52s.js → side-question-DtzquMOb.js} +15 -13
  27. package/dist/{thread-lifecycle-BgLXzjvV.js → thread-lifecycle-CQ_9mAa1.js} +1821 -1582
  28. package/dist/{protocol-validators-dZQ-UTOa.js → transcript-mirror-D9rTxx2P.js} +485 -2
  29. package/dist/usage-CuPpFgTc.js +25 -0
  30. package/dist/{web-search-provider.runtime-Bs-eTn5U.js → web-search-provider.runtime-_x5XTeqh.js} +3 -3
  31. package/npm-shrinkwrap.json +30 -30
  32. package/openclaw.plugin.json +21 -6
  33. package/package.json +6 -6
  34. package/dist/capabilities-42Dfn2TV.js +0 -33
  35. package/dist/prompt-overlay.js +0 -15
  36. package/dist/protocol-BMifTfdW.js +0 -15
  37. package/dist/provider-catalog.js +0 -118
  38. package/dist/provider-discovery.js +0 -34
  39. package/dist/provider.js +0 -307
  40. package/dist/session-binding-BMfX1OX-.js +0 -786
  41. package/dist/transcript-mirror-DhLwFIL4.js +0 -485
@@ -1,212 +1,328 @@
1
- import { i as isJsonObject, r as flattenCodexDynamicToolFunctions } from "./protocol-BMifTfdW.js";
2
- import { S as updateActiveTurnItemIds, _ as readCodexNotificationItem, a as isCodexTurnAbortMarkerNotification, b as shouldDisarmAssistantCompletionIdleWatch, c as isPendingOpenClawDynamicToolCompletionNotification, d as isRawReasoningCompletionNotification, f as isRawToolOutputCompletionNotification, g as isTerminalTurnStatus, h as isRetryableErrorNotification, i as isAssistantCompletionReleaseNotification, l as isRawAssistantProgressNotification, m as isReasoningProgressNotification, n as describeNotificationActivity, o as isFileChangePatchUpdatedNotification, p as isReasoningItemCompletionNotification, r as isAssistantCommentaryCompletionNotification, s as isNativeToolProgressNotification, t as codexExecutionToolName, u as isRawFunctionToolOutputCompletionNotification, v as readNotificationItemId, x as updateActiveCompletionBlockerItemIds, y as readRawResponseToolCallId } from "./attempt-notifications-DEv9h7iC.js";
3
- import { _ as resolveCodexPluginsPolicy, b as shouldAutoApproveCodexAppServerApprovals, d as readCodexPluginConfig, g as resolveCodexModelBackedReviewerPolicyContext, h as resolveCodexComputerUseConfig, l as isCodexSandboxExecServerEnabled, s as isCodexAppServerApprovalPolicyAllowedByRequirements, x as withMcpElicitationsApprovalPolicy, y as resolveOpenClawExecPolicyForCodexAppServer } from "./config-c48K5HP9.js";
4
- import { a as readCodexDynamicToolCallParams, i as assertCodexTurnStartResponse } from "./protocol-validators-dZQ-UTOa.js";
5
- import { i as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-BKNjHMEs.js";
6
- import { A as isCodexAppServerApprovalRequest, C as resolveCodexAppServerFallbackApiKeyCacheKey, D as resolveCodexAppServerHomeDir, O as CodexAppServerRpcError, S as resolveCodexAppServerAuthProfileIdForAgent, T as resolveCodexAppServerPreparedAuthHandoff, _ as readCodexRateLimitsRevision, a as getLeasedSharedCodexAppServerClient, b as resolveCodexAppServerAuthAccountCacheKey, c as releaseLeasedSharedCodexAppServerClient, d as retireSharedCodexAppServerClientIfCurrent, g as ensureCodexAppServerClientRuntime, j as isCodexAppServerConnectionClosedError, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as isCodexAppServerStartSelectionChangedError, t as clearSharedCodexAppServerClientIfCurrent, u as retainSharedCodexAppServerClientIfCurrent, v as readRecentCodexRateLimits, w as resolveCodexAppServerPreparedApiKeyCacheKey, x as resolveCodexAppServerAuthProfileId, y as rememberCodexRateLimitsRead } from "./shared-client-D4mFI9al.js";
7
- import { A as fitCodexProjectedContextForTurnStart, B as unsubscribeCodexThreadBestEffort, E as isSystemAgentOnlyCodexDynamicToolAllowlist, F as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, G as shouldBuildCodexPluginThreadConfig, H as buildCodexPluginThreadConfig, I as CodexAppServerUnsafeSubscriptionError, L as closeCodexStartupClientBestEffort, M as resolveCodexContextEngineProjectionMaxChars, N as resolveCodexContextEngineProjectionReserveTokens, P as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS, R as interruptCodexTurnBestEffort, U as buildCodexPluginThreadConfigInputFingerprint, W as mergeCodexThreadConfigs, a as buildDeveloperInstructions, b as isCodexAppServerProfilerEnabled, c as codexDynamicToolsFingerprint, g as startOrResumeThread, i as buildContextEngineBinding, j as projectContextEngineAssemblyForCodex, k as resolveCodexDynamicToolsLoadingForRuntime, l as codexLegacyDynamicToolsFingerprint, n as areCodexDynamicToolFingerprintsCompatible, o as buildTurnCollaborationMode, p as resolveCodexAppServerThreadModelSelection, s as buildTurnStartParams, u as isContextEngineBindingCompatible, v as resolveCodexWebSearchPlan, w as filterCodexDynamicTools, z as retireCodexAppServerClientAfterTimedOutTurn } from "./thread-lifecycle-BgLXzjvV.js";
8
- import { c as sessionBindingIdentity, s as reclaimCurrentCodexSessionGeneration } from "./session-binding-BMfX1OX-.js";
9
- import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-Dhp04Rqo.js";
10
- import { i as mirrorPromptAtTurnStartBestEffort, n as createCodexAppServerUserMessagePersistenceNotifier, o as buildCodexUserPromptMessage, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-DhLwFIL4.js";
11
- import { t as CODEX_CONTROL_METHODS } from "./capabilities-42Dfn2TV.js";
12
- import { r as formatCodexDisplayText } from "./command-formatters-D6ZlGNmb.js";
13
- import { n as resolveCodexAppServerForOpenClawToolPolicy, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-DVcxdse_.js";
14
- import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId, t as isCodexNotificationForTurn } from "./notification-correlation-DfaCm0mx.js";
1
+ import { A as isCodexAppServerStartupError, B as isCodexAppServerApprovalRequest, C as resolveCodexAppServerFallbackApiKeyCacheKey, D as resolveCodexAppServerHomeDir, F as resolveCodexTurnCompletionIdleTimeoutMs, H as isCodexAppServerConnectionClosedError, I as resolveCodexTurnTerminalIdleTimeoutMs, K as isCodexAppServerRequestTimeoutError, L as withCodexStartupTimeout, M as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, N as resolveCodexStartupTimeoutMs, O as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, P as resolveCodexTurnAssistantCompletionIdleTimeoutMs, R as CodexAppServerRpcError, S as resolveCodexAppServerAuthProfileIdForAgent, T as resolveCodexAppServerPreparedAuthHandoff, V as isCodexAppServerBrokenPipeError, X as flattenCodexDynamicToolFunctions, Z as isJsonObject, _ as readCodexRateLimitsRevision, a as getLeasedSharedCodexAppServerClient, b as resolveCodexAppServerAuthAccountCacheKey, c as releaseLeasedSharedCodexAppServerClient, d as retireSharedCodexAppServerClientIfCurrent, g as ensureCodexAppServerClientRuntime, k as CodexAppServerStartupError, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as isCodexAppServerStartSelectionChangedError, t as clearSharedCodexAppServerClientIfCurrent, u as retainSharedCodexAppServerClientIfCurrent, v as readRecentCodexRateLimits, w as resolveCodexAppServerPreparedApiKeyCacheKey, x as resolveCodexAppServerAuthProfileId } from "./shared-client-CSXLtCLE.js";
2
+ import { S as updateActiveTurnItemIds, _ as readCodexNotificationItem, a as isCodexTurnAbortMarkerNotification, b as shouldDisarmAssistantCompletionIdleWatch, c as isPendingOpenClawDynamicToolCompletionNotification, d as isRawReasoningCompletionNotification, f as isRawToolOutputCompletionNotification, g as isTerminalTurnStatus, h as isRetryableErrorNotification, i as isAssistantCompletionReleaseNotification, l as isRawAssistantProgressNotification, m as isReasoningProgressNotification, n as describeNotificationActivity, o as isFileChangePatchUpdatedNotification, p as isReasoningItemCompletionNotification, r as isAssistantCommentaryCompletionNotification, s as isNativeToolProgressNotification, t as codexExecutionToolName, u as isRawFunctionToolOutputCompletionNotification, v as readNotificationItemId, x as updateActiveCompletionBlockerItemIds, y as readRawResponseToolCallId } from "./attempt-notifications-Ecjyzufe.js";
3
+ import { C as resolveCodexComputerUseConfig, D as resolveOpenClawExecPolicyForCodexAppServer, O as shouldAutoApproveCodexAppServerApprovals, T as resolveCodexPluginsPolicy, c as sessionBindingIdentity, g as isCodexAppServerApprovalPolicyAllowedByRequirements, k as withMcpElicitationsApprovalPolicy, s as reclaimCurrentCodexSessionGeneration, v as isCodexSandboxExecServerEnabled, w as resolveCodexModelBackedReviewerPolicyContext, y as readCodexPluginConfig } from "./session-binding-Bmt20HfB.js";
4
+ import { _ as readCodexTurnCompletedNotification, f as assertCodexTurnStartResponse, i as mirrorPromptAtTurnStartBestEffort, n as createCodexAppServerUserMessagePersistenceNotifier, o as buildCodexUserPromptMessage, p as readCodexDynamicToolCallParams, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-D9rTxx2P.js";
5
+ import { i as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-DJbhLYSK.js";
6
+ import { A as CodexAppServerUnsafeSubscriptionError, B as fitCodexProjectedContextForTurnStart, D as resolveCodexDynamicToolsLoadingForRuntime, F as areCodexDynamicToolFingerprintsCompatible, G as buildCodexPluginThreadConfig, H as resolveCodexContextEngineProjectionMaxChars, I as codexDynamicToolsFingerprint, J as mergeCodexThreadConfigs, K as buildCodexPluginThreadConfigInputFingerprint, L as codexLegacyDynamicToolsFingerprint, M as interruptCodexTurnBestEffort, N as retireCodexAppServerClientAfterTimedOutTurn, O as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS, P as unsubscribeCodexThreadBestEffort, Q as resolveRecoverableCodexPluginConfigKeys, R as buildContextEngineBinding, U as resolveCodexContextEngineProjectionReserveTokens, V as projectContextEngineAssemblyForCodex, Y as shouldBuildCodexPluginThreadConfig, b as isCodexAppServerProfilerEnabled, d as resolveCodexWebSearchPlan, f as buildDeveloperInstructions, g as resolveCodexAppServerThreadModelSelection, j as closeCodexStartupClientBestEffort, k as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, n as buildTurnStartParams, q as buildCodexPluginThreadConfigTimeoutFallback, r as buildCodexUserInput, s as startOrResumeThread, t as buildTurnCollaborationMode, w as isSystemAgentOnlyCodexDynamicToolAllowlist, x as filterCodexDynamicTools, z as isContextEngineBindingCompatible } from "./thread-lifecycle-CQ_9mAa1.js";
7
+ import { r as formatCodexDisplayText } from "./command-formatters-NCTL7A2q.js";
8
+ import { n as resolveCodexAppServerForOpenClawToolPolicy, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-DUMF2Xyr.js";
9
+ import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId, t as isCodexNotificationForTurn } from "./notification-correlation-C8DVQ_Bq.js";
15
10
  import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-C1czuHPA.js";
16
- import { $ as inferCodexDynamicToolMeta, B as handleDynamicToolCallWithTimeout, C as resolveCodexMessageToolProvider, D as shouldWarnCodexDynamicToolBuildStageSummary, E as shouldRequireCodexSandboxExecServerEnvironment, F as createCodexNativeHookRelay, G as resolveTerminalDynamicToolBatchAction, H as isDynamicToolTerminalDiagnosticEvent, I as emitCodexNativePreToolUseFailureDiagnostic, J as toCodexDynamicToolProgressResponse, K as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult, L as resolveCodexNativeHookRelayEvents, M as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, N as buildCodexNativeHookRelayConfig, P as buildCodexNativeHookRelayDisabledConfig, Q as shouldEmitTranscriptToolProgress, R as resolveCodexNativeHookRelayTtlMs, S as resolveCodexExternalSandboxPolicyForOpenClawSandbox, T as shouldEnableCodexAppServerNativeToolSurface, U as isMatchingDynamicToolTerminalDiagnostic, V as hasPendingDynamicToolTerminalDiagnostic, W as resolveDynamicToolCallTimeoutMs, X as resolveCodexToolAbortTerminalReason, Y as toCodexDynamicToolProtocolResponse, Z as readCodexMirroredSessionHistoryMessages, _ as createCodexDynamicToolBuildStageTracker, a as emitDynamicToolStartedDiagnostic, b as resolveCodexAppServerExecutionCwd, d as resolveCodexStartupTimeoutMs, et as resolveCodexToolProgressDetailMode, f as resolveCodexTurnAssistantCompletionIdleTimeoutMs, g as buildDynamicTools, h as withCodexStartupTimeout, i as emitDynamicToolErrorDiagnostic, k as CodexAppServerEventProjector, l as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, m as resolveCodexTurnTerminalIdleTimeoutMs, n as handleCodexAppServerApprovalRequest, nt as sanitizeCodexToolResponse, o as emitDynamicToolTerminalDiagnostic, p as resolveCodexTurnCompletionIdleTimeoutMs, q as shouldReleaseTurnAfterTerminalDynamicTool, r as handleCodexAppServerElicitationRequest, rt as resolveCodexLocalRuntimeAttribution, s as resolveCodexProviderWebSearchSupport, t as createCodexDynamicToolBridge, tt as sanitizeCodexToolArguments, u as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, v as disableCodexPluginThreadConfig, w as resolveCodexSandboxEnvironmentSelection, x as resolveCodexAppServerHookChannelId, y as formatCodexDynamicToolBuildStageSummary, z as scheduleCodexNativeHookRelayUnregister } from "./dynamic-tools-BMLoaTeG.js";
17
- import { a as runCodexComputerUseLiveTest, r as killStaleComputerUseMcpChildren, t as ensureCodexComputerUse } from "./computer-use-DVzr8OP1.js";
11
+ import { $ as resolveCodexToolProgressDetailMode, B as hasPendingDynamicToolTerminalDiagnostic, C as CodexAppServerEventProjector, D as markCodexAuthProfileBlockedFromRateLimits, E as isCodexUsageLimitPromptError, F as emitCodexNativePreToolUseFailureDiagnostic, G as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult, H as isMatchingDynamicToolTerminalDiagnostic, I as resolveCodexNativeHookRelayEvents, J as toCodexDynamicToolProtocolResponse, K as shouldReleaseTurnAfterTerminalDynamicTool, L as resolveCodexNativeHookRelayTtlMs, M as buildCodexNativeHookRelayConfig, N as buildCodexNativeHookRelayDisabledConfig, O as refreshCodexUsageLimitPromptError, P as createCodexNativeHookRelay, Q as inferCodexDynamicToolMeta, R as scheduleCodexNativeHookRelayUnregister, T as formatCodexTurnStartUsageLimitError, U as resolveDynamicToolCallTimeoutMs, V as isDynamicToolTerminalDiagnosticEvent, W as resolveTerminalDynamicToolBatchAction, X as readCodexMirroredSessionHistoryMessages, Y as resolveCodexToolAbortTerminalReason, Z as shouldEmitTranscriptToolProgress, _ as resolveCodexMessageToolProvider, a as emitDynamicToolStartedDiagnostic, b as shouldRequireCodexSandboxExecServerEnvironment, d as createCodexDynamicToolBuildStageTracker, et as sanitizeCodexToolArguments, f as disableCodexPluginThreadConfig, g as resolveCodexExternalSandboxPolicyForOpenClawSandbox, h as resolveCodexAppServerHookChannelId, i as emitDynamicToolErrorDiagnostic, j as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, l as settleCodexSourceReplyFinality, m as resolveCodexAppServerExecutionCwd, n as handleCodexAppServerApprovalRequest, nt as redactCodexEventKind, o as emitDynamicToolTerminalDiagnostic, p as formatCodexDynamicToolBuildStageSummary, q as toCodexDynamicToolProgressResponse, r as handleCodexAppServerElicitationRequest, rt as resolveCodexLocalRuntimeAttribution, s as resolveCodexProviderWebSearchSupport, t as createCodexDynamicToolBridge, tt as sanitizeCodexToolResponse, u as buildDynamicTools, v as resolveCodexSandboxEnvironmentSelection, w as createCodexUsageLimitPromptError, x as shouldWarnCodexDynamicToolBuildStageSummary, y as shouldEnableCodexAppServerNativeToolSurface, z as handleDynamicToolCallWithTimeout } from "./dynamic-tools-D_vSVmv9.js";
12
+ import { a as runCodexComputerUseLiveTest, r as killStaleComputerUseMcpChildren, t as ensureCodexComputerUse } from "./computer-use-C7x4ZaqR.js";
18
13
  import fs from "node:fs/promises";
19
14
  import path, { posix } from "node:path";
20
15
  import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
21
- import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
16
+ import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
22
17
  import { createHash, randomUUID } from "node:crypto";
23
- import { markAuthProfileBlockedUntil, resolveAgentDir, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
18
+ import { resolveAgentDir, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
24
19
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
25
20
  import { asFiniteNumber, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
26
- import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildAgentHarnessUserInputAnswers, buildBootstrapContextForFiles, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, clearActiveEmbeddedRun, deliverAgentHarnessUserInputPrompt, embeddedAgentLog, emitAgentEvent, emptyAgentHarnessUserInputAnswers, finalizeHarnessContextEngineTurn, formatErrorMessage, formatFastModeAutoProgressText, getAgentHarnessHookRunner, getBeforeToolCallPolicyDiagnosticState, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, resolveAgentDir as resolveAgentDir$1, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds as resolveSessionAgentIds$1, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
21
+ import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildAgentHarnessUserInputAnswers, buildBootstrapContextForFiles, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, callGatewayTool, cancelPendingAgentQuestionForSession, claimPendingAgentQuestionAnswer, clearActiveEmbeddedRun, deliverAgentHarnessUserInputPrompt, embeddedAgentLog, emitAgentEvent, emptyAgentHarnessUserInputAnswers, finalizeHarnessContextEngineTurn, formatErrorMessage, formatFastModeAutoProgressText, getAgentHarnessHookRunner, getBeforeToolCallPolicyDiagnosticState, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, resolveAgentDir as resolveAgentDir$1, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds as resolveSessionAgentIds$1, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessGatewayQuestion, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
27
22
  import { spawn } from "node:child_process";
28
23
  import { once } from "node:events";
29
24
  import { isIP } from "node:net";
30
25
  import { WebSocketServer } from "ws";
31
26
  import { parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
32
- import { buildMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
27
+ import { fileURLToPath } from "node:url";
33
28
  import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
29
+ import { prepareMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
34
30
  import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
35
31
  import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
36
32
  import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
37
33
  //#region extensions/codex/src/app-server/attempt-steering.ts
38
34
  /**
39
- * Debounced steering queue for forwarding user text to an active Codex
35
+ * Debounced steering queue for forwarding user messages to an active Codex
40
36
  * app-server turn.
41
37
  */
42
38
  const CODEX_STEER_ALL_DEBOUNCE_MS = 500;
43
39
  /**
44
- * Creates a queue that batches steer text while still serializing app-server
45
- * `turn/steer` requests.
40
+ * Creates a queue that batches steer messages while still serializing
41
+ * app-server `turn/steer` requests.
46
42
  */
47
43
  function createCodexSteeringQueue(params) {
48
- let batchedTexts = [];
44
+ let batchedMessages = [];
45
+ const dispatchedBatches = /* @__PURE__ */ new Map();
46
+ const pendingMessages = /* @__PURE__ */ new Set();
49
47
  let batchTimer;
48
+ let batchSequence = 0;
50
49
  let sendChain = Promise.resolve();
50
+ let closedError;
51
51
  const clearBatchTimer = () => {
52
52
  if (batchTimer) {
53
53
  clearTimeout(batchTimer);
54
54
  batchTimer = void 0;
55
55
  }
56
56
  };
57
- const sendTexts = async (texts) => {
58
- if (texts.length === 0) return;
59
- if (params.signal.aborted) throw new Error("codex app-server steering queue aborted");
60
- await params.client.request("turn/steer", {
61
- threadId: params.threadId,
62
- expectedTurnId: params.turnId,
63
- input: texts.map(toCodexTextInput)
64
- });
57
+ const resolveItem = (item) => {
58
+ if (item.settled) return;
59
+ item.settled = true;
60
+ pendingMessages.delete(item);
61
+ item.resolve();
62
+ };
63
+ const rejectItem = (item, error) => {
64
+ if (item.settled) return;
65
+ item.settled = true;
66
+ pendingMessages.delete(item);
67
+ item.reject(error);
68
+ };
69
+ const closeQueue = (error) => {
70
+ if (closedError) return;
71
+ closedError = error;
72
+ params.signal.removeEventListener("abort", abortQueue);
73
+ clearBatchTimer();
74
+ batchedMessages = [];
75
+ dispatchedBatches.clear();
76
+ for (const item of pendingMessages) rejectItem(item, error);
77
+ };
78
+ const abortQueue = () => {
79
+ closeQueue(/* @__PURE__ */ new Error("codex app-server steering queue aborted"));
80
+ };
81
+ const cancelQueue = () => {
82
+ closeQueue(/* @__PURE__ */ new Error("codex app-server steering queue cancelled"));
83
+ };
84
+ const sendBatch = async (items) => {
85
+ const liveItems = items.filter((item) => !item.settled);
86
+ if (liveItems.length === 0) return;
87
+ const unavailableError = closedError ?? (params.signal.aborted ? /* @__PURE__ */ new Error("codex app-server steering queue aborted") : void 0);
88
+ if (unavailableError) {
89
+ for (const item of liveItems) rejectItem(item, unavailableError);
90
+ throw unavailableError;
91
+ }
92
+ const clientUserMessageId = `openclaw:${params.turnId}:steer:${++batchSequence}`;
93
+ const batch = { items: liveItems };
94
+ dispatchedBatches.set(clientUserMessageId, batch);
95
+ try {
96
+ await params.client.request("turn/steer", {
97
+ threadId: params.threadId,
98
+ expectedTurnId: params.turnId,
99
+ input: liveItems.flatMap((item) => buildCodexUserInput(item.text, item.images)),
100
+ clientUserMessageId
101
+ });
102
+ } catch (error) {
103
+ dispatchedBatches.delete(clientUserMessageId);
104
+ for (const item of liveItems) rejectItem(item, error);
105
+ throw error;
106
+ }
65
107
  };
66
- const enqueueSend = (texts) => {
67
- const send = sendChain.then(() => sendTexts(texts));
68
- sendChain = send.catch((error) => {
108
+ const enqueueSend = (items) => {
109
+ const send = sendChain.then(() => sendBatch(items));
110
+ sendChain = send;
111
+ send.catch((error) => {
112
+ for (const item of items) rejectItem(item, error);
69
113
  embeddedAgentLog.debug("codex app-server queued steer failed", { error });
70
114
  });
71
115
  return send;
72
116
  };
73
117
  const flushBatch = () => {
74
118
  clearBatchTimer();
75
- const items = batchedTexts;
76
- batchedTexts = [];
77
- const send = enqueueSend(items.map((item) => item.text));
78
- send.then(() => {
79
- for (const item of items) item.resolve();
80
- }, (error) => {
81
- for (const item of items) item.reject(error);
82
- });
119
+ const items = batchedMessages;
120
+ batchedMessages = [];
121
+ if (items.length === 0) return sendChain;
122
+ const send = enqueueSend(items);
123
+ send.catch(() => void 0);
83
124
  return send;
84
125
  };
126
+ const createPendingMessage = (text, images) => {
127
+ let resolveDelivery;
128
+ let rejectDelivery;
129
+ const delivery = new Promise((resolve, reject) => {
130
+ resolveDelivery = resolve;
131
+ rejectDelivery = reject;
132
+ });
133
+ const item = {
134
+ text,
135
+ images,
136
+ resolve: resolveDelivery,
137
+ reject: rejectDelivery,
138
+ settled: false
139
+ };
140
+ pendingMessages.add(item);
141
+ return {
142
+ item,
143
+ delivery
144
+ };
145
+ };
146
+ params.signal.addEventListener("abort", abortQueue, { once: true });
147
+ if (params.signal.aborted) abortQueue();
85
148
  return {
86
149
  async queue(text, options) {
87
- if (params.answerPendingUserInput(text)) return;
88
- return await new Promise((resolve, reject) => {
89
- batchedTexts.push({
90
- text,
91
- resolve,
92
- reject
93
- });
94
- clearBatchTimer();
95
- const debounceMs = normalizeCodexSteerDebounceMs(options?.debounceMs);
96
- if (debounceMs === 0) {
97
- flushBatch().catch(() => void 0);
150
+ const pendingUserInput = params.claimPendingUserInput();
151
+ if (pendingUserInput) {
152
+ if (!options?.images?.length) {
153
+ pendingUserInput.answer(text);
98
154
  return;
99
155
  }
100
- batchTimer = setTimeout(() => {
101
- batchTimer = void 0;
102
- flushBatch().catch(() => void 0);
103
- }, debounceMs);
104
- });
156
+ flushBatch().catch(() => void 0);
157
+ const { item, delivery } = createPendingMessage(text, options.images);
158
+ await Promise.all([enqueueSend([item]).finally(() => pendingUserInput.cancel()), delivery]);
159
+ return;
160
+ }
161
+ if (closedError) throw closedError;
162
+ if (params.signal.aborted) throw new Error("codex app-server steering queue aborted");
163
+ const { item, delivery } = createPendingMessage(text, options?.images);
164
+ batchedMessages.push(item);
165
+ clearBatchTimer();
166
+ const debounceMs = normalizeCodexSteerDebounceMs(options?.debounceMs);
167
+ if (debounceMs === 0) flushBatch();
168
+ else batchTimer = setTimeout(() => {
169
+ batchTimer = void 0;
170
+ flushBatch();
171
+ }, debounceMs);
172
+ return await delivery;
105
173
  },
106
174
  async flushPending() {
175
+ if (closedError) return;
107
176
  await flushBatch().catch(() => void 0);
108
177
  },
109
- cancel() {
110
- clearBatchTimer();
111
- const items = batchedTexts;
112
- batchedTexts = [];
113
- for (const item of items) item.reject(/* @__PURE__ */ new Error("codex app-server steering queue cancelled"));
114
- }
178
+ confirmConsumed(clientUserMessageId) {
179
+ const batch = dispatchedBatches.get(clientUserMessageId);
180
+ if (!batch) return false;
181
+ dispatchedBatches.delete(clientUserMessageId);
182
+ for (const item of batch.items) resolveItem(item);
183
+ return true;
184
+ },
185
+ cancel: cancelQueue
115
186
  };
116
187
  }
117
188
  /** Normalizes steer debounce milliseconds, preserving explicit zero. */
118
189
  function normalizeCodexSteerDebounceMs(value) {
119
190
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : CODEX_STEER_ALL_DEBOUNCE_MS;
120
191
  }
121
- /** Converts plain text into the Codex app-server user-input shape. */
122
- function toCodexTextInput(text) {
123
- return {
124
- type: "text",
125
- text,
126
- text_elements: []
127
- };
128
- }
129
192
  //#endregion
130
193
  //#region extensions/codex/src/app-server/user-input-bridge.ts
131
- /**
132
- * Bridges Codex item/tool user-input requests to OpenClaw messaging prompts and
133
- * turns replies into app-server answer payloads.
134
- */
194
+ /** Bridges Codex request_user_input calls to gateway questions and secret text prompts. */
195
+ const DEFAULT_USER_INPUT_TIMEOUT_MS = 15 * 6e4;
135
196
  /** Creates a per-turn bridge for pending Codex user-input requests. */
136
197
  function createCodexUserInputBridge(params) {
137
- let pending;
138
- const resolvePending = (value) => {
139
- const current = pending;
198
+ let sensitiveInput;
199
+ let pendingGateway;
200
+ const gatewayCall = params.gatewayCall ?? callGatewayTool;
201
+ const resolveSecret = (value) => {
202
+ const current = sensitiveInput;
140
203
  if (!current) return;
141
- pending = void 0;
204
+ sensitiveInput = void 0;
142
205
  current.cleanup();
143
206
  current.resolve(value);
144
207
  };
208
+ const resolveSecretIfCurrent = (current, value) => {
209
+ if (sensitiveInput !== current) return false;
210
+ resolveSecret(value);
211
+ return true;
212
+ };
213
+ const cancelGateway = () => {
214
+ pendingGateway?.abort.abort(/* @__PURE__ */ new Error("Codex user input request cancelled"));
215
+ };
145
216
  return {
146
217
  async handleRequest(request) {
147
218
  const requestParams = readUserInputParams(request.params);
148
219
  if (!requestParams) return;
149
220
  if (requestParams.threadId !== params.threadId || requestParams.turnId !== params.turnId) return;
150
221
  if (requestParams.questions.length === 0) return emptyUserInputResponse();
151
- resolvePending(emptyUserInputResponse());
152
- return new Promise((resolve) => {
153
- const abortListener = () => resolvePending(emptyUserInputResponse());
222
+ resolveSecret(emptyUserInputResponse());
223
+ cancelGateway();
224
+ if (requestParams.questions.some((question) => question.isSecret)) return new Promise((resolve) => {
225
+ const abortListener = () => resolveSecret(emptyUserInputResponse());
154
226
  const cleanup = () => params.signal?.removeEventListener("abort", abortListener);
155
- pending = {
227
+ sensitiveInput = {
156
228
  requestId: request.id,
157
229
  threadId: requestParams.threadId,
158
- turnId: requestParams.turnId,
159
- itemId: requestParams.itemId,
160
230
  questions: requestParams.questions,
231
+ claimed: false,
161
232
  resolve,
162
233
  cleanup
163
234
  };
164
235
  params.signal?.addEventListener("abort", abortListener, { once: true });
165
236
  if (params.signal?.aborted) {
166
- resolvePending(emptyUserInputResponse());
237
+ resolveSecret(emptyUserInputResponse());
167
238
  return;
168
239
  }
169
- deliverUserInputPrompt(params.paramsForRun, requestParams.questions).catch((error) => {
170
- embeddedAgentLog.warn("failed to deliver codex user input prompt", { error });
240
+ deliverAgentHarnessUserInputPrompt(params.paramsForRun, requestParams.questions, {
241
+ formatText: formatCodexDisplayText,
242
+ intro: "Codex needs input:"
243
+ }).catch((error) => {
244
+ embeddedAgentLog.warn("failed to deliver secret codex user input prompt", { error });
171
245
  });
172
246
  });
247
+ const abort = new AbortController();
248
+ const abortFromRun = () => abort.abort(params.signal?.reason);
249
+ params.signal?.addEventListener("abort", abortFromRun, { once: true });
250
+ if (params.signal?.aborted) abortFromRun();
251
+ pendingGateway = {
252
+ requestId: request.id,
253
+ threadId: requestParams.threadId,
254
+ abort
255
+ };
256
+ try {
257
+ const result = await runAgentHarnessGatewayQuestion({
258
+ questions: requestParams.questions,
259
+ sessionKey: params.paramsForRun.sessionKey ?? params.paramsForRun.sessionId,
260
+ agentId: params.paramsForRun.agentId,
261
+ timeoutMs: requestParams.autoResolutionMs ?? params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS,
262
+ gatewayCall,
263
+ delivery: params.paramsForRun,
264
+ promptOptions: {
265
+ formatText: formatCodexDisplayText,
266
+ intro: "Codex needs input:"
267
+ },
268
+ signal: abort.signal
269
+ });
270
+ return result.status === "answered" ? result.answers : emptyUserInputResponse();
271
+ } catch (error) {
272
+ embeddedAgentLog.warn("failed to bridge codex user input through gateway", { error });
273
+ return emptyUserInputResponse();
274
+ } finally {
275
+ params.signal?.removeEventListener("abort", abortFromRun);
276
+ if (pendingGateway?.abort === abort) pendingGateway = void 0;
277
+ }
173
278
  },
174
- handleQueuedMessage(text) {
175
- const current = pending;
176
- if (!current) return false;
177
- resolvePending(buildUserInputResponse(current.questions, text));
178
- return true;
279
+ claimPendingRequest() {
280
+ const current = sensitiveInput;
281
+ if (!current || current.claimed) return;
282
+ current.claimed = true;
283
+ return {
284
+ answer: (text) => resolveSecretIfCurrent(current, buildUserInputResponse(current.questions, text)),
285
+ cancel: () => resolveSecretIfCurrent(current, emptyUserInputResponse())
286
+ };
179
287
  },
180
288
  handleNotification(notification) {
181
- if (notification.method !== "serverRequest/resolved" || !pending) return;
289
+ if (notification.method !== "serverRequest/resolved") return;
182
290
  const notificationParams = isJsonObject(notification.params) ? notification.params : void 0;
183
291
  const requestId = notificationParams ? readRequestId(notificationParams) : void 0;
184
- if (notificationParams && readString$4(notificationParams, "threadId") === pending.threadId && requestId !== void 0 && String(requestId) === String(pending.requestId)) resolvePending(emptyUserInputResponse());
292
+ if (!notificationParams || requestId === void 0) return;
293
+ if (sensitiveInput && readString$3(notificationParams, "threadId") === sensitiveInput.threadId && String(requestId) === String(sensitiveInput.requestId)) resolveSecret(emptyUserInputResponse());
294
+ if (pendingGateway && readString$3(notificationParams, "threadId") === pendingGateway.threadId && String(requestId) === String(pendingGateway.requestId)) pendingGateway.abort.abort(/* @__PURE__ */ new Error("Codex server request resolved"));
185
295
  },
186
296
  cancelPending() {
187
- resolvePending(emptyUserInputResponse());
297
+ resolveSecret(emptyUserInputResponse());
298
+ cancelGateway();
188
299
  }
189
300
  };
190
301
  }
191
302
  function readUserInputParams(value) {
192
303
  if (!isJsonObject(value)) return;
193
- const threadId = readString$4(value, "threadId");
194
- const turnId = readString$4(value, "turnId");
195
- const itemId = readString$4(value, "itemId");
304
+ const threadId = readString$3(value, "threadId");
305
+ const turnId = readString$3(value, "turnId");
306
+ const itemId = readString$3(value, "itemId");
196
307
  const questionsRaw = value.questions;
197
308
  if (!threadId || !turnId || !itemId || !Array.isArray(questionsRaw)) return;
198
309
  return {
199
310
  threadId,
200
311
  turnId,
201
312
  itemId,
202
- questions: questionsRaw.map(readQuestion).filter((question) => Boolean(question))
313
+ questions: questionsRaw.map((rawQuestion) => {
314
+ const question = readQuestion(rawQuestion);
315
+ if (question && isJsonObject(rawQuestion) && rawQuestion.multiSelect === true) question.multiSelect = true;
316
+ return question;
317
+ }).filter((question) => Boolean(question)),
318
+ autoResolutionMs: typeof value.autoResolutionMs === "number" && value.autoResolutionMs > 0 ? value.autoResolutionMs : void 0
203
319
  };
204
320
  }
205
321
  function readQuestion(value) {
206
322
  if (!isJsonObject(value)) return;
207
- const id = readString$4(value, "id");
208
- const header = readString$4(value, "header");
209
- const question = readString$4(value, "question");
323
+ const id = readString$3(value, "id");
324
+ const header = readString$3(value, "header");
325
+ const question = readString$3(value, "question");
210
326
  if (!id || !header || !question) return;
211
327
  return {
212
328
  id,
@@ -224,26 +340,20 @@ function readOptions(value) {
224
340
  }
225
341
  function readOption(value) {
226
342
  if (!isJsonObject(value)) return;
227
- const label = readString$4(value, "label");
228
- const description = readString$4(value, "description") ?? "";
343
+ const label = readString$3(value, "label");
344
+ const description = readString$3(value, "description") ?? "";
229
345
  return label ? {
230
346
  label,
231
347
  description
232
348
  } : void 0;
233
349
  }
234
- async function deliverUserInputPrompt(params, questions) {
235
- await deliverAgentHarnessUserInputPrompt(params, questions, {
236
- formatText: formatCodexDisplayText,
237
- intro: "Codex needs input:"
238
- });
239
- }
240
350
  function buildUserInputResponse(questions, inputText) {
241
351
  return buildAgentHarnessUserInputAnswers(questions, inputText);
242
352
  }
243
353
  function emptyUserInputResponse() {
244
354
  return emptyAgentHarnessUserInputAnswers();
245
355
  }
246
- function readString$4(record, key) {
356
+ function readString$3(record, key) {
247
357
  const value = record[key];
248
358
  return typeof value === "string" ? value : void 0;
249
359
  }
@@ -336,18 +446,35 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
336
446
  client: resourceState.client,
337
447
  threadId: resourceState.thread.threadId,
338
448
  turnId: activeTurnId,
339
- answerPendingUserInput: (text) => userInputBridgeRef.current?.handleQueuedMessage(text) ?? false,
449
+ claimPendingUserInput: () => userInputBridgeRef.current?.claimPendingRequest(),
340
450
  signal: runAbortController.signal
341
451
  });
342
452
  steeringQueueRef.current = activeSteeringQueue;
343
453
  const handle = {
344
454
  kind: "embedded",
345
455
  runId: params.runId,
346
- queueMessage: async (text, optionsLocal) => activeSteeringQueue.queue(text, optionsLocal),
456
+ queueMessage: async (text, optionsLocal) => {
457
+ const isInboundUserMessage = optionsLocal?.isInboundUserMessage === true;
458
+ if (isInboundUserMessage && !optionsLocal?.images?.length) {
459
+ if (await claimPendingAgentQuestionAnswer({
460
+ sessionKey: params.sessionKey ?? params.sessionId,
461
+ text
462
+ })) return;
463
+ } else if (isInboundUserMessage) try {
464
+ await cancelPendingAgentQuestionForSession({
465
+ sessionKey: params.sessionKey ?? params.sessionId,
466
+ resolvedBy: "image-reply"
467
+ });
468
+ } catch (error) {
469
+ embeddedAgentLog.warn("failed to cancel codex gateway question before image steering", { error });
470
+ }
471
+ await activeSteeringQueue.queue(text, optionsLocal);
472
+ },
347
473
  isStreaming: () => !state.completed && !runAbortController.signal.aborted,
348
474
  isStopped: () => state.completed || state.timedOut || runAbortController.signal.aborted,
349
475
  isAbortable: () => !terminalState.terminalOutcomeFrozen || terminalState.sharedAbortAllowedAfterTerminalOutcome,
350
476
  isCompacting: () => projectorRef.current?.isCompacting() ?? false,
477
+ supportsQueueMessageImages: true,
351
478
  sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
352
479
  cancel: () => abortExplicitly("cancelled"),
353
480
  abort: () => abortExplicitly("aborted")
@@ -1058,6 +1185,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
1058
1185
  isInactiveThreadBootstrapBinding,
1059
1186
  usesSupervisionConnection,
1060
1187
  startupAuthProfileId,
1188
+ startupAuthRequirement: preparedAuthRoute?.authRequirement,
1061
1189
  startupPreparedAuth,
1062
1190
  startupClientAuthProfileId,
1063
1191
  effectiveWorkspace,
@@ -1215,13 +1343,14 @@ async function buildCodexWorkspaceBootstrapContext(params) {
1215
1343
  promptContext: renderCodexWorkspaceBootstrapPromptContext(promptContextFiles),
1216
1344
  developerInstructions: renderCodexWorkspaceThreadDeveloperInstructions(developerInstructionFiles),
1217
1345
  turnScopedDeveloperInstructions: renderCodexWorkspaceCollaborationDeveloperInstructions(turnScopedDeveloperInstructionFiles),
1218
- memoryCollaborationInstructions: shouldInjectCodexOpenClawPromptContext(params.params) ? renderCodexWorkspaceMemoryCollaborationInstructions({
1346
+ memoryCollaborationInstructions: shouldInjectCodexOpenClawPromptContext(params.params) ? await renderCodexWorkspaceMemoryCollaborationInstructions({
1219
1347
  files: memoryReferenceFiles,
1220
1348
  toolNames: params.memoryToolNames,
1221
1349
  memoryToolRouted: memoryToolsAvailable,
1222
1350
  citationsMode: params.params.config?.memory?.citations,
1223
1351
  agentId: params.params.agentId ?? params.sessionAgentId,
1224
- agentSessionKey: params.sessionKey
1352
+ agentSessionKey: params.sessionKey,
1353
+ sandboxed: params.sandboxed
1225
1354
  }) : void 0,
1226
1355
  heartbeatCollaborationInstructions: renderCodexWorkspaceHeartbeatReference(heartbeatReferenceFiles)
1227
1356
  };
@@ -1576,24 +1705,26 @@ function renderCodexWorkspaceMemoryReference(params) {
1576
1705
  for (const file of params.files) lines.push(`- ${file.path}`);
1577
1706
  return lines.join("\n").trim();
1578
1707
  }
1579
- function renderCodexWorkspaceMemoryCollaborationInstructions(params) {
1580
- const sections = [params.memoryToolRouted ? renderCodexMemoryRecallInstructions({
1708
+ async function renderCodexWorkspaceMemoryCollaborationInstructions(params) {
1709
+ const sections = [params.memoryToolRouted ? await renderCodexMemoryRecallInstructions({
1581
1710
  toolNames: params.toolNames,
1582
1711
  citationsMode: params.citationsMode,
1583
1712
  agentId: params.agentId,
1584
- agentSessionKey: params.agentSessionKey
1713
+ agentSessionKey: params.agentSessionKey,
1714
+ sandboxed: params.sandboxed
1585
1715
  }) : void 0, renderCodexWorkspaceMemoryReference({
1586
1716
  files: params.files,
1587
1717
  toolNames: params.toolNames
1588
1718
  })].filter(isNonEmptyString$1);
1589
1719
  return sections.length > 0 ? sections.join("\n\n") : void 0;
1590
1720
  }
1591
- function renderCodexMemoryRecallInstructions(params) {
1592
- const memoryPrompt = buildMemorySystemPromptAddition({
1721
+ async function renderCodexMemoryRecallInstructions(params) {
1722
+ const memoryPrompt = await prepareMemorySystemPromptAddition({
1593
1723
  availableTools: new Set(params.toolNames),
1594
1724
  citationsMode: params.citationsMode,
1595
1725
  agentId: params.agentId,
1596
- agentSessionKey: params.agentSessionKey
1726
+ agentSessionKey: params.agentSessionKey,
1727
+ sandboxed: params.sandboxed
1597
1728
  });
1598
1729
  if (!memoryPrompt) return;
1599
1730
  return [memoryPrompt, renderCodexMemoryToolSearchBridge(params.toolNames)].filter(isNonEmptyString$1).join("\n").trim();
@@ -1790,7 +1921,7 @@ function buildCodexAppServerTimeoutDiagnostics(params) {
1790
1921
  //#region extensions/codex/src/app-server/run-attempt-context.ts
1791
1922
  async function prepareCodexAttemptContext(runtime, attemptTools) {
1792
1923
  const { connection, runtimeParams, activeSessionId, activeSessionFile, buildActiveRunAttemptParams, effectiveContextWindowInfo, effectiveContextTokenBudget, effectiveRuntimeProviderId, effectiveRuntimeModelId, hookChannelId } = runtime;
1793
- const { params, sessionAgentId, contextSessionKey, activeContextEngine, initialStartupBindingHadInactiveThreadBootstrap, sandboxSessionKey, effectiveWorkspace, effectiveCwd, agentDir, usesSupervisionConnection, resolvedWorkspace, initialInactiveThreadBootstrapBindingForcedFreshStart } = connection;
1924
+ const { params, sessionAgentId, contextSessionKey, activeContextEngine, initialStartupBindingHadInactiveThreadBootstrap, sandboxSessionKey, effectiveWorkspace, effectiveCwd, agentDir, usesSupervisionConnection, resolvedWorkspace, initialInactiveThreadBootstrapBindingForcedFreshStart, sandbox } = connection;
1794
1925
  const { toolBridge } = attemptTools;
1795
1926
  const activeTranscriptTarget = {
1796
1927
  agentId: sessionAgentId,
@@ -1854,7 +1985,8 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
1854
1985
  effectiveWorkspace,
1855
1986
  sessionKey: contextSessionKey,
1856
1987
  sessionAgentId,
1857
- memoryToolNames: getCodexWorkspaceMemoryToolNames(toolBridge.availableSpecs)
1988
+ memoryToolNames: getCodexWorkspaceMemoryToolNames(toolBridge.availableSpecs),
1989
+ sandboxed: sandbox?.enabled === true
1858
1990
  });
1859
1991
  const baseDeveloperInstructions = joinPresentSections(buildDeveloperInstructions(runtimeParams, { dynamicTools: toolBridge.availableSpecs }), workspaceBootstrapContext.developerInstructions);
1860
1992
  return {
@@ -2070,7 +2202,7 @@ function buildCodexTurnStartFailureResult(params) {
2070
2202
  idleTimedOut: false,
2071
2203
  timedOutDuringCompaction: false,
2072
2204
  timedOutDuringToolExecution: false,
2073
- promptError: params.message,
2205
+ promptError: params.promptError ?? params.message,
2074
2206
  promptErrorSource: "prompt",
2075
2207
  sessionIdUsed: params.params.sessionId,
2076
2208
  messagesSnapshot: params.messagesSnapshot,
@@ -2284,139 +2416,6 @@ function normalizeCodexTrajectoryError(value) {
2284
2416
  }
2285
2417
  }
2286
2418
  //#endregion
2287
- //#region extensions/codex/src/app-server/usage-limit-error.ts
2288
- /**
2289
- * Enriches Codex usage-limit failures with current rate-limit information and
2290
- * marks blocked auth profiles when Codex exposes a reset time.
2291
- */
2292
- const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
2293
- /** Marks a Codex auth profile blocked until the reset time advertised by rate limits. */
2294
- async function markCodexAuthProfileBlockedFromRateLimits(params) {
2295
- const authProfileId = params.authProfileId?.trim();
2296
- if (!authProfileId || !params.params.authProfileStore) return;
2297
- const blockedUntil = resolveCodexUsageLimitResetAtMs(params.rateLimits);
2298
- if (!blockedUntil) return;
2299
- try {
2300
- await markAuthProfileBlockedUntil({
2301
- store: params.params.authProfileStore,
2302
- profileId: authProfileId,
2303
- blockedUntil,
2304
- source: "codex_rate_limits",
2305
- agentDir: params.params.agentDir,
2306
- runId: params.params.runId,
2307
- modelId: params.params.modelId
2308
- });
2309
- } catch (error) {
2310
- embeddedAgentLog.debug("failed to mark Codex auth profile blocked from app-server limits", {
2311
- authProfileId,
2312
- error: formatErrorMessage(error)
2313
- });
2314
- }
2315
- }
2316
- /** Formats a turn-start usage-limit error, refreshing rate limits when needed. */
2317
- async function formatCodexTurnStartUsageLimitError(params) {
2318
- return refreshCodexUsageLimitError({
2319
- client: params.client,
2320
- source: readCodexTurnStartUsageLimitErrorSource(params.client, params.error, params.errorNotification, params.rateLimitsRevisionBeforeTurnStart),
2321
- timeoutMs: params.timeoutMs,
2322
- signal: params.signal
2323
- });
2324
- }
2325
- /** Refreshes a generic prompt usage-limit message into a reset-aware message. */
2326
- async function refreshCodexUsageLimitPromptError(params) {
2327
- if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(params.message)) return;
2328
- return (await refreshCodexUsageLimitError({
2329
- client: params.client,
2330
- source: {
2331
- message: params.message,
2332
- codexErrorInfo: "usageLimitExceeded",
2333
- rateLimits: readRecentCodexRateLimits(params.client)
2334
- },
2335
- timeoutMs: params.timeoutMs,
2336
- signal: params.signal
2337
- }))?.message;
2338
- }
2339
- async function refreshCodexUsageLimitError(params) {
2340
- const initialMessage = formatCodexUsageLimitErrorMessage(params.source);
2341
- if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(initialMessage)) return initialMessage ? {
2342
- message: initialMessage,
2343
- ...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
2344
- } : void 0;
2345
- const rateLimits = await readCodexRateLimitsFromAppServerForUsageLimitError({
2346
- client: params.client,
2347
- timeoutMs: params.timeoutMs,
2348
- signal: params.signal
2349
- });
2350
- if (!rateLimits) return initialMessage ? {
2351
- message: initialMessage,
2352
- ...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
2353
- } : void 0;
2354
- const message = formatCodexUsageLimitErrorMessage({
2355
- message: params.source.message,
2356
- codexErrorInfo: params.source.codexErrorInfo,
2357
- rateLimits
2358
- }) ?? initialMessage;
2359
- return message ? {
2360
- message,
2361
- rateLimitsForProfile: rateLimits
2362
- } : void 0;
2363
- }
2364
- async function readCodexRateLimitsFromAppServerForUsageLimitError(params) {
2365
- if (params.signal?.aborted) return;
2366
- try {
2367
- const rateLimits = await params.client.request(CODEX_CONTROL_METHODS.rateLimits, void 0, {
2368
- timeoutMs: resolveCodexUsageLimitRateLimitRefreshTimeoutMs(params.timeoutMs),
2369
- signal: params.signal
2370
- });
2371
- rememberCodexRateLimitsRead(params.client, rateLimits);
2372
- return rateLimits;
2373
- } catch (error) {
2374
- embeddedAgentLog.debug("codex app-server rate-limit refresh failed after usage-limit error", { error: formatErrorMessage(error) });
2375
- return;
2376
- }
2377
- }
2378
- function resolveCodexUsageLimitRateLimitRefreshTimeoutMs(timeoutMs) {
2379
- if (timeoutMs === void 0 || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS;
2380
- return Math.max(100, Math.min(timeoutMs, CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS));
2381
- }
2382
- function readCodexTurnStartUsageLimitErrorSource(client, error, errorNotification, rateLimitsRevisionBeforeTurnStart) {
2383
- const notificationError = readCodexErrorNotification(errorNotification);
2384
- const errorPayload = readCodexErrorPayload(error);
2385
- const rateLimits = errorPayload.rateLimits ?? readRecentCodexRateLimits(client);
2386
- const cacheUpdatedDuringTurnStart = rateLimitsRevisionBeforeTurnStart !== void 0 && readCodexRateLimitsRevision(client) > rateLimitsRevisionBeforeTurnStart;
2387
- return {
2388
- message: notificationError?.message ?? errorPayload.message ?? formatErrorMessage(error),
2389
- codexErrorInfo: notificationError?.codexErrorInfo ?? errorPayload.codexErrorInfo,
2390
- rateLimits,
2391
- rateLimitsTrustedForProfile: errorPayload.rateLimits !== void 0 || cacheUpdatedDuringTurnStart
2392
- };
2393
- }
2394
- function readCodexErrorNotification(notification) {
2395
- if (notification?.method !== "error" || !isJsonObject(notification.params)) return;
2396
- const error = notification.params.error;
2397
- return isJsonObject(error) ? {
2398
- message: readString$3(error, "message"),
2399
- codexErrorInfo: error.codexErrorInfo
2400
- } : void 0;
2401
- }
2402
- function readCodexErrorPayload(error) {
2403
- const message = error instanceof Error ? error.message : void 0;
2404
- if (!error || typeof error !== "object" || !("data" in error)) return { message };
2405
- const data = error.data;
2406
- if (!isJsonObject(data)) return { message };
2407
- const nestedError = isJsonObject(data.error) ? data.error : data;
2408
- const rateLimits = nestedError.rateLimits ?? data.rateLimits;
2409
- return {
2410
- message: readString$3(nestedError, "message") ?? message,
2411
- codexErrorInfo: nestedError.codexErrorInfo,
2412
- rateLimits
2413
- };
2414
- }
2415
- function readString$3(record, key) {
2416
- const value = record[key];
2417
- return typeof value === "string" ? value : void 0;
2418
- }
2419
- //#endregion
2420
2419
  //#region extensions/codex/src/app-server/run-attempt-finalize.ts
2421
2420
  async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notifications, requestRuntime, activeTurn) {
2422
2421
  const { prompt, state: resourceState, trajectoryRecorder, markTrajectoryEndRecorded } = resources;
@@ -2425,7 +2424,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2425
2424
  const { hookContextWindowFields, hookRunner, promptState } = context;
2426
2425
  const { connection, preparedAuthBinding, activeSessionId, activeSessionFile } = runtime;
2427
2426
  const { buildActiveRunAttemptParams, effectiveContextTokenBudget, effectiveRuntimeProviderId, effectiveRuntimeModelId } = runtime;
2428
- const { params, terminalState, runAbortController, activeContextEngine, bindingStore, bindingIdentity, appServer, usesSupervisionConnection, sessionAgentId, contextSessionKey, effectiveCwd, effectiveWorkspace, agentDir, attemptStartedAt } = connection;
2427
+ const { params, terminalState, runAbortController, activeContextEngine, bindingStore, bindingIdentity, appServer, usesSupervisionConnection, sessionAgentId, contextSessionKey, effectiveCwd, effectiveWorkspace, agentDir, attemptStartedAt, startupAuthProfileId } = connection;
2429
2428
  const { toolBridge, toolState } = attemptTools;
2430
2429
  const { state, completion, pendingOpenClawDynamicToolCompletionIds, activeTurnItemIds, activeCompletionBlockerItemIds, activeFinalizationHookRunIds, turnWatches } = turnRuntime;
2431
2430
  const { emitLifecycleTerminal, buildLifecycleTerminalMeta } = lifecycle;
@@ -2459,7 +2458,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2459
2458
  const isFinalAborted = () => result.aborted || terminalState.explicitCancellationObserved || runAbortController.signal.aborted && !state.clientClosedAbort && !recoveredTurnWatchTimeout;
2460
2459
  const clientClosedPromptErrorForFinal = state.clientClosedPromptError && hasRecoverableCompletedAssistant ? void 0 : state.clientClosedPromptError;
2461
2460
  let finalPromptError = clientClosedPromptErrorForFinal ?? (effectiveTurnCompletionIdleTimedOut ? state.turnCompletionIdleTimeoutMessage : effectiveTimedOut ? "codex app-server attempt timed out" : result.promptError);
2462
- const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
2461
+ const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError instanceof Error ? finalPromptError.message : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
2463
2462
  if (isInvalidCodexImagePayloadError(finalPromptErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(bindingStore, bindingIdentity, {
2464
2463
  phase: "turn_completed",
2465
2464
  threadId: resourceState.thread.threadId,
@@ -2487,7 +2486,18 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2487
2486
  timeoutMs: appServer.requestTimeoutMs,
2488
2487
  signal: runAbortController.signal
2489
2488
  });
2490
- if (refreshedUsageLimitPromptError) finalPromptError = refreshedUsageLimitPromptError;
2489
+ if (refreshedUsageLimitPromptError) {
2490
+ await markCodexAuthProfileBlockedFromRateLimits({
2491
+ params,
2492
+ authProfileId: startupAuthProfileId,
2493
+ rateLimits: refreshedUsageLimitPromptError.rateLimitsForProfile
2494
+ });
2495
+ finalPromptError = createCodexUsageLimitPromptError(refreshedUsageLimitPromptError.message);
2496
+ } else if (isCodexUsageLimitPromptError(finalPromptError) && state.rateLimitsRevisionBeforeLastTurnStart !== void 0 && readCodexRateLimitsRevision(resourceState.client) > state.rateLimitsRevisionBeforeLastTurnStart) await markCodexAuthProfileBlockedFromRateLimits({
2497
+ params,
2498
+ authProfileId: startupAuthProfileId,
2499
+ rateLimits: readRecentCodexRateLimits(resourceState.client)
2500
+ });
2491
2501
  const finalPromptErrorSource = effectiveTimedOut || clientClosedPromptErrorForFinal ? "prompt" : result.promptErrorSource;
2492
2502
  const codexAppServerFailureKind = clientClosedPromptErrorForFinal ? "client_closed_before_turn_completed" : effectiveTurnCompletionIdleTimedOut ? "turn_completion_idle_timeout" : void 0;
2493
2503
  const replayBlockedReason = codexAppServerFailureKind ? resolveCodexAppServerReplayBlockedReason(result) : void 0;
@@ -2515,7 +2525,9 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2515
2525
  const finalAborted = isFinalAborted();
2516
2526
  const completedTurnStatus = activeProjector.getCompletedTurnStatus();
2517
2527
  const completedWithoutTerminalNotification = state.completed && !state.terminalTurnNotificationQueued && !state.timedOut && clientClosedPromptErrorForFinal === void 0;
2518
- const attemptSucceeded = !finalAborted && !effectiveTimedOut && (finalPromptError === null || finalPromptError === void 0) && result.agentHarnessResultClassification === void 0 && (completedTurnStatus === "completed" || recoveredTurnWatchTimeout || completedWithoutTerminalNotification);
2528
+ const turnSucceeded = !finalAborted && !effectiveTimedOut && (finalPromptError === null || finalPromptError === void 0) && (completedTurnStatus === "completed" || recoveredTurnWatchTimeout || completedWithoutTerminalNotification);
2529
+ if (settleCodexSourceReplyFinality(toolBridge.telemetry, turnSucceeded)) result.agentHarnessResultClassification = void 0;
2530
+ const attemptSucceeded = turnSucceeded && result.agentHarnessResultClassification === void 0;
2519
2531
  terminalState.sharedAbortAllowedAfterTerminalOutcome = shouldKeepCodexSharedAbortOpen({
2520
2532
  trigger: params.trigger,
2521
2533
  result,
@@ -2662,7 +2674,8 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2662
2674
  phase: "end",
2663
2675
  ...buildLifecycleTerminalMeta({
2664
2676
  aborted: finalAborted,
2665
- timedOut: effectiveTimedOut
2677
+ timedOut: effectiveTimedOut,
2678
+ yielded: toolState.yieldDetected
2666
2679
  })
2667
2680
  });
2668
2681
  return {
@@ -2708,7 +2721,7 @@ function reportCodexExecutionNotification(params) {
2708
2721
  /** Returns true when a notification ends the current app-server turn. */
2709
2722
  function isTerminalCodexTurnNotificationForTurn(params) {
2710
2723
  if (!isCodexNotificationForTurn(params.notification.params, params.threadId, params.turnId)) return false;
2711
- return params.notification.method === "turn/completed" || isCodexTurnAbortMarkerNotification(params.notification, { currentPromptTexts: params.currentPromptTexts });
2724
+ return params.notification.method === "turn/completed";
2712
2725
  }
2713
2726
  /**
2714
2727
  * Applies one notification to active item tracking, idle watches, and terminal
@@ -2778,13 +2791,33 @@ function applyCodexTurnNotificationState(params) {
2778
2791
  isTurnTerminal: isTerminalCodexTurnNotificationForTurn({
2779
2792
  notification,
2780
2793
  threadId: params.threadId,
2781
- turnId: params.turnId,
2782
- currentPromptTexts: params.currentPromptTexts
2794
+ turnId: params.turnId
2783
2795
  }),
2784
2796
  turnCrossedToolHandoff
2785
2797
  };
2786
2798
  }
2787
2799
  //#endregion
2800
+ //#region extensions/codex/src/app-server/run-attempt-lifecycle-terminal.ts
2801
+ function buildCodexLifecycleTerminalMeta(input) {
2802
+ if (input.timedOut || input.abortStopReason === "timeout") return {
2803
+ aborted: true,
2804
+ status: "timed_out",
2805
+ stopReason: "timeout",
2806
+ timeoutPhase: "provider",
2807
+ providerStarted: true
2808
+ };
2809
+ if (input.yielded && !input.aborted) return {
2810
+ yielded: true,
2811
+ livenessState: "paused",
2812
+ stopReason: "end_turn"
2813
+ };
2814
+ return input.aborted ? {
2815
+ aborted: true,
2816
+ status: "cancelled",
2817
+ stopReason: "stop"
2818
+ } : void 0;
2819
+ }
2820
+ //#endregion
2788
2821
  //#region extensions/codex/src/app-server/run-attempt-lifecycle-controller.ts
2789
2822
  function createCodexAttemptLifecycleController(resources, turnRuntime) {
2790
2823
  const { prompt, state: resourceState, trajectoryRecorder } = resources;
@@ -2816,6 +2849,7 @@ function createCodexAttemptLifecycleController(resources, turnRuntime) {
2816
2849
  tool: value.call.tool,
2817
2850
  durationMs: value.durationMs
2818
2851
  });
2852
+ turnRuntime.steeringQueueRef.current?.cancel();
2819
2853
  interruptCodexTurnBestEffort(resourceState.client, {
2820
2854
  threadId: value.call.threadId,
2821
2855
  turnId: value.call.turnId,
@@ -2832,6 +2866,7 @@ function createCodexAttemptLifecycleController(resources, turnRuntime) {
2832
2866
  state.terminalDynamicToolReleaseCheckScheduled = true;
2833
2867
  setImmediate(() => {
2834
2868
  state.terminalDynamicToolReleaseCheckScheduled = false;
2869
+ if (state.pendingTerminalDynamicToolRelease?.response.success === true && !state.currentTurnHadNonTerminalDynamicToolResult && state.activeAppServerTurnRequests === 0 && pendingOpenClawDynamicToolCompletionIds.size === 0) turnRuntime.steeringQueueRef.current?.cancel();
2835
2870
  const action = resolveTerminalDynamicToolBatchAction({
2836
2871
  activeAppServerTurnRequests: state.activeAppServerTurnRequests,
2837
2872
  activeTurnItemIdsCount: activeTurnItemIds.size,
@@ -2868,25 +2903,17 @@ function createCodexAttemptLifecycleController(resources, turnRuntime) {
2868
2903
  startedAt: attemptStartedAt,
2869
2904
  endedAt: Date.now(),
2870
2905
  ...data,
2871
- ...params.deferTerminalLifecycle ?? params.deferTerminalLifecycleEnd ? { phase: "finishing" } : {}
2906
+ ...params.deferTerminalLifecycle ? { phase: "finishing" } : {}
2872
2907
  }
2873
2908
  });
2874
2909
  state.lifecycleTerminalEmitted = true;
2875
2910
  };
2876
2911
  const buildLifecycleTerminalMeta = (input) => {
2877
2912
  const abortFields = input.aborted ? resolveAgentRunAbortLifecycleFields(runAbortController.signal) : void 0;
2878
- if (input.timedOut || abortFields?.stopReason === "timeout") return {
2879
- aborted: true,
2880
- status: "timed_out",
2881
- stopReason: "timeout",
2882
- timeoutPhase: "provider",
2883
- providerStarted: true
2884
- };
2885
- return input.aborted ? {
2886
- aborted: true,
2887
- status: "cancelled",
2888
- stopReason: "stop"
2889
- } : void 0;
2913
+ return buildCodexLifecycleTerminalMeta({
2914
+ ...input,
2915
+ abortStopReason: abortFields?.stopReason
2916
+ });
2890
2917
  };
2891
2918
  const executionPhaseKeys = /* @__PURE__ */ new Set();
2892
2919
  const emitExecutionPhaseOnce = (key, info) => {
@@ -2999,7 +3026,8 @@ var ClientTurnRouter = class {
2999
3026
  gate: "open",
3000
3027
  pending: [],
3001
3028
  notificationTail: Promise.resolve(),
3002
- nativeTurnCompleted: false
3029
+ nativeTurnCompleted: false,
3030
+ ignoredTurnNotificationKeys: /* @__PURE__ */ new Set()
3003
3031
  };
3004
3032
  this.routes.set(threadId, route);
3005
3033
  if (options.onNotification || options.onRequest) this.activateNow(route, options);
@@ -3082,6 +3110,7 @@ var ClientTurnRouter = class {
3082
3110
  this.assertRoute(route);
3083
3111
  if (route.gate !== "open") throw new Error(`codex app-server thread route cannot arm from ${route.gate}`);
3084
3112
  route.gate = "armed";
3113
+ route.ignoredTurnNotificationKeys.clear();
3085
3114
  route.nativeTurnCompleted = false;
3086
3115
  route.binding = deferred();
3087
3116
  }
@@ -3131,7 +3160,10 @@ var ClientTurnRouter = class {
3131
3160
  }
3132
3161
  const handler = route.handlers.onNotification;
3133
3162
  if (!handler) return;
3134
- if (route.gate === "bound" && scope.turnId && scope.turnId !== route.turnId) return;
3163
+ if (route.gate === "bound" && scope.turnId && scope.turnId !== route.turnId) {
3164
+ this.warnDroppedStaleTurnNotification(route, notification, routeScope);
3165
+ return;
3166
+ }
3135
3167
  if (route.gate === "armed") {
3136
3168
  this.bufferNotification(route, notification, routeScope, receivedAtMs);
3137
3169
  return;
@@ -3174,11 +3206,31 @@ var ClientTurnRouter = class {
3174
3206
  flushNotifications(route) {
3175
3207
  const handler = route.handlers?.onNotification;
3176
3208
  if (!handler) return;
3177
- for (const pending of route.pending.splice(0)) if (!pending.scope.turnId || route.gate !== "bound" || pending.scope.turnId === route.turnId) {
3209
+ for (const pending of route.pending.splice(0)) {
3210
+ if (route.gate === "bound" && pending.scope.turnId && pending.scope.turnId !== route.turnId) {
3211
+ this.warnDroppedStaleTurnNotification(route, pending.notification, pending.scope);
3212
+ continue;
3213
+ }
3178
3214
  route.handlers?.onNotificationReceived?.(pending.notification, pending.scope, pending.receivedAtMs);
3179
3215
  this.enqueueNotification(route, handler, pending.notification, pending.scope);
3180
3216
  }
3181
3217
  }
3218
+ warnDroppedStaleTurnNotification(route, notification, scope) {
3219
+ if (notification.method === "turn/completed" || !scope.turnId || !route.turnId) return;
3220
+ const eventKind = redactCodexEventKind(notification.method);
3221
+ const key = JSON.stringify([notification.method, scope.turnId]);
3222
+ if (route.ignoredTurnNotificationKeys.has(key)) return;
3223
+ route.ignoredTurnNotificationKeys.add(key);
3224
+ embeddedAgentLog.warn("codex app-server notification ignored for inactive turn", {
3225
+ eventKind,
3226
+ activeThreadId: route.threadId,
3227
+ activeTurnId: route.turnId,
3228
+ threadId: scope.threadId,
3229
+ turnId: scope.turnId,
3230
+ matchesActiveThread: true,
3231
+ matchesActiveTurn: false
3232
+ });
3233
+ }
3182
3234
  bufferNotification(route, notification, scope, receivedAtMs) {
3183
3235
  if (route.pending.length < DEFAULT_PREBIND_NOTIFICATION_LIMIT) {
3184
3236
  route.pending.push({
@@ -3307,8 +3359,7 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
3307
3359
  const isTerminalTurnNotificationForTurn = (notification, notificationTurnId) => isTerminalCodexTurnNotificationForTurn({
3308
3360
  notification,
3309
3361
  threadId: resourceState.thread.threadId,
3310
- turnId: notificationTurnId,
3311
- currentPromptTexts: [turnState.codexTurnPromptText]
3362
+ turnId: notificationTurnId
3312
3363
  });
3313
3364
  const handleNotification = async (notification) => {
3314
3365
  const projector = projectorRef.current;
@@ -3335,6 +3386,11 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
3335
3386
  onReportExecutionNotification: reportExecutionNotification
3336
3387
  });
3337
3388
  state.turnCrossedToolHandoff = notificationState.turnCrossedToolHandoff;
3389
+ if (notificationState.isCurrentTurnNotification && notification.method === "item/completed") {
3390
+ const item = readCodexNotificationItem(notification.params);
3391
+ if (item?.type === "userMessage" && typeof item.clientId === "string") steeringQueue?.confirmConsumed(item.clientId);
3392
+ }
3393
+ if (notificationState.isTurnAbortMarker) state.sawCodexInterruptMarker = true;
3338
3394
  const hookNotification = readCodexFinalizationHookNotification(notification, resourceState.thread.threadId, turnId);
3339
3395
  if (hookNotification?.phase === "started") {
3340
3396
  if (activeFinalizationHookRunIds.size === 0) finalizationHookBatchStatuses.clear();
@@ -3378,7 +3434,7 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
3378
3434
  });
3379
3435
  }
3380
3436
  if (notificationState.isTurnTerminal) {
3381
- if (notificationState.isTurnAbortMarker) projector.markAborted();
3437
+ if ((readCodexTurnCompletedNotification(notification.params)?.turn)?.status === "interrupted" && state.sawCodexInterruptMarker) projector.markAborted();
3382
3438
  if (!state.timedOut && !runAbortController.signal.aborted) await steeringQueue?.flushPending();
3383
3439
  state.completed = true;
3384
3440
  turnWatches.clearCompletionIdleTimer();
@@ -3436,7 +3492,7 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
3436
3492
  async function prepareCodexAttemptPrompt(context) {
3437
3493
  const { runtime, attemptTools, historyState, hookContext, workspaceBootstrapContext, baseDeveloperInstructions, openClawPromptContext, skillsCollaborationInstructions, promptState, codexContextProjectionMaxChars } = context;
3438
3494
  const { connection, buildActiveRunAttemptParams, effectiveContextTokenBudget, effectiveRuntimeModelId, effectiveRuntimeProviderId } = runtime;
3439
- const { params, activeContextEngine, usesSupervisionConnection, mutable, isInactiveThreadBootstrapBinding, bindingStore, bindingIdentity, agentDir, appServer, contextSessionKey, effectiveWorkspace } = connection;
3495
+ const { params, activeContextEngine, usesSupervisionConnection, mutable, isInactiveThreadBootstrapBinding, bindingStore, bindingIdentity, agentDir, appServer, contextSessionKey, effectiveWorkspace, sandbox } = connection;
3440
3496
  const { toolBridge } = attemptTools;
3441
3497
  const applyFreshThreadContinuityProjection = () => {
3442
3498
  const projection = projectContextEngineAssemblyForCodex({
@@ -3459,6 +3515,7 @@ async function prepareCodexAttemptPrompt(context) {
3459
3515
  tokenBudget: effectiveContextTokenBudget,
3460
3516
  availableTools: new Set(flattenCodexDynamicToolFunctions(toolBridge.availableSpecs).map((tool) => tool.name).filter(isNonEmptyString)),
3461
3517
  citationsMode: params.config?.memory?.citations,
3518
+ sandboxed: sandbox?.enabled === true,
3462
3519
  modelId: effectiveRuntimeModelId,
3463
3520
  contextEngineHostSupport: CODEX_APP_SERVER_CONTEXT_ENGINE_HOST,
3464
3521
  providerId: effectiveRuntimeProviderId,
@@ -3520,7 +3577,7 @@ async function prepareCodexAttemptPrompt(context) {
3520
3577
  const buildPromptFromCurrentInputs = () => resolveAgentHarnessBeforePromptBuildResult({
3521
3578
  prompt: prependCurrentInboundContext(promptState.promptText, params.currentInboundContext),
3522
3579
  developerInstructions: promptState.developerInstructions,
3523
- messages: codexModelInputHistoryMessages,
3580
+ messages: structuredClone(historyState.messages),
3524
3581
  ctx: hookContext,
3525
3582
  bootstrapContextRunKind: params.bootstrapContextRunKind,
3526
3583
  ..."beforeAgentStartResult" in params ? { beforeAgentStartResult: params.beforeAgentStartResult } : {}
@@ -5265,6 +5322,30 @@ function sendError(socket, id, code, message) {
5265
5322
  }));
5266
5323
  }
5267
5324
  //#endregion
5325
+ //#region extensions/codex/src/app-server/sandbox-exec-server/path-uri.ts
5326
+ /** Converts Codex PathUri protocol values into sandbox-backend path strings. */
5327
+ const WINDOWS_DRIVE_PATH_RE = /^\/[A-Za-z]:(?:\/|$)/u;
5328
+ /** Resolves one Codex exec-server PathUri into a POSIX sandbox path. */
5329
+ function resolveExecServerPath(rawPath, label) {
5330
+ let pathUrl;
5331
+ try {
5332
+ pathUrl = new URL(rawPath);
5333
+ } catch (error) {
5334
+ throw new Error(`${label} must be a valid file URI: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
5335
+ }
5336
+ if (pathUrl.protocol !== "file:") throw new Error(`${label} URI must use the file scheme, received ${pathUrl.protocol.slice(0, -1)}.`);
5337
+ if (pathUrl.search || pathUrl.hash) throw new Error(`${label} file URI must not include a query or fragment.`);
5338
+ let resolved;
5339
+ try {
5340
+ resolved = fileURLToPath(pathUrl, { windows: false });
5341
+ } catch (error) {
5342
+ throw new Error(`${label} file URI is not valid for the sandbox: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
5343
+ }
5344
+ if (WINDOWS_DRIVE_PATH_RE.test(resolved)) throw new Error(`${label} Windows file URI is not supported by the sandbox.`);
5345
+ if (resolved.includes("\0")) throw new Error(`${label} file URI must not contain a null byte.`);
5346
+ return resolved;
5347
+ }
5348
+ //#endregion
5268
5349
  //#region extensions/codex/src/app-server/sandbox-exec-server/fs-policy.ts
5269
5350
  /**
5270
5351
  * Resolves Codex filesystem sandbox policy payloads into OpenClaw path/glob
@@ -5304,7 +5385,7 @@ function resolveFsSandboxPolicy(execServer, record) {
5304
5385
  }
5305
5386
  function readFsSandboxCwd(execServer, sandbox) {
5306
5387
  if (sandbox.cwd === void 0 || sandbox.cwd === null) return normalizeSandboxAbsolutePath(execServer.sandbox.containerWorkdir, "sandbox cwd");
5307
- return normalizeSandboxAbsolutePath(requireString(sandbox.cwd, "sandbox cwd"), "sandbox cwd");
5388
+ return normalizeSandboxAbsolutePath(resolveExecServerPath(requireString(sandbox.cwd, "sandbox cwd"), "sandbox cwd"), "sandbox cwd");
5308
5389
  }
5309
5390
  function resolveFsSandboxEntry(entry, cwd) {
5310
5391
  const access = readFsAccessMode(entry.access);
@@ -5312,7 +5393,7 @@ function resolveFsSandboxEntry(entry, cwd) {
5312
5393
  const pathType = requireString(pathSpec.type, "fs sandbox entry path type");
5313
5394
  if (pathType === "path") return {
5314
5395
  kind: "path",
5315
- path: normalizeSandboxAbsolutePath(requireString(pathSpec.path, "fs sandbox path"), "fs sandbox path"),
5396
+ path: normalizeSandboxAbsolutePath(resolveExecServerPath(requireString(pathSpec.path, "fs sandbox path"), "fs sandbox path"), "fs sandbox path"),
5316
5397
  access
5317
5398
  };
5318
5399
  if (pathType === "special") {
@@ -5506,7 +5587,7 @@ const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES = 512 * 1024 * 1024;
5506
5587
  /** Reads a sandbox file as base64 after read-policy and size checks. */
5507
5588
  async function readFile(execServer, params) {
5508
5589
  const record = requireObject(params, "fs/readFile params");
5509
- const filePath = requireString(record.path, "path");
5590
+ const filePath = resolveExecServerPath(requireString(record.path, "path"), "read path");
5510
5591
  assertFsSandboxAccess(execServer, record, [{
5511
5592
  path: filePath,
5512
5593
  access: "read"
@@ -5520,7 +5601,7 @@ async function readFile(execServer, params) {
5520
5601
  /** Writes base64 data to an existing sandbox directory after write-policy checks. */
5521
5602
  async function writeFile(execServer, params) {
5522
5603
  const record = requireObject(params, "fs/writeFile params");
5523
- const filePath = requireString(record.path, "path");
5604
+ const filePath = resolveExecServerPath(requireString(record.path, "path"), "write path");
5524
5605
  assertFsSandboxAccess(execServer, record, [{
5525
5606
  path: filePath,
5526
5607
  access: "write"
@@ -5536,7 +5617,7 @@ async function writeFile(execServer, params) {
5536
5617
  /** Creates a sandbox directory, respecting recursive and parent-directory semantics. */
5537
5618
  async function createDirectory(execServer, params) {
5538
5619
  const record = requireObject(params, "fs/createDirectory params");
5539
- const filePath = requireString(record.path, "path");
5620
+ const filePath = resolveExecServerPath(requireString(record.path, "path"), "create-directory path");
5540
5621
  assertFsSandboxAccess(execServer, record, [{
5541
5622
  path: filePath,
5542
5623
  access: "write"
@@ -5551,7 +5632,7 @@ async function createDirectory(execServer, params) {
5551
5632
  /** Returns normalized metadata for a sandbox path. */
5552
5633
  async function getMetadata(execServer, params) {
5553
5634
  const record = requireObject(params, "fs/getMetadata params");
5554
- const filePath = requireString(record.path, "path");
5635
+ const filePath = resolveExecServerPath(requireString(record.path, "path"), "metadata path");
5555
5636
  assertFsSandboxAccess(execServer, record, [{
5556
5637
  path: filePath,
5557
5638
  access: "read"
@@ -5563,7 +5644,7 @@ async function getMetadata(execServer, params) {
5563
5644
  /** Lists sandbox directory entries visible under the resolved filesystem policy. */
5564
5645
  async function readDirectory(execServer, params) {
5565
5646
  const record = requireObject(params, "fs/readDirectory params");
5566
- return { entries: await listDirectoryEntries(execServer, requireString(record.path, "path"), resolveFsSandboxPolicy(execServer, record)) };
5647
+ return { entries: await listDirectoryEntries(execServer, resolveExecServerPath(requireString(record.path, "path"), "read-directory path"), resolveFsSandboxPolicy(execServer, record)) };
5567
5648
  }
5568
5649
  async function listDirectoryEntries(execServer, filePath, fsSandboxPolicy) {
5569
5650
  assertResolvedFsSandboxAccess(fsSandboxPolicy, [{
@@ -5595,7 +5676,7 @@ async function listDirectoryEntries(execServer, filePath, fsSandboxPolicy) {
5595
5676
  /** Removes a sandbox path after rejecting writes outside policy or under read-only descendants. */
5596
5677
  async function removePath(execServer, params) {
5597
5678
  const record = requireObject(params, "fs/remove params");
5598
- const filePath = requireString(record.path, "path");
5679
+ const filePath = resolveExecServerPath(requireString(record.path, "path"), "remove path");
5599
5680
  const fsSandboxPolicy = resolveFsSandboxPolicy(execServer, record);
5600
5681
  assertResolvedFsSandboxAccess(fsSandboxPolicy, [{
5601
5682
  path: filePath,
@@ -5611,8 +5692,8 @@ async function removePath(execServer, params) {
5611
5692
  /** Copies sandbox files or recursive directories while enforcing source and destination policy. */
5612
5693
  async function copyPath(execServer, params) {
5613
5694
  const record = requireObject(params, "fs/copy params");
5614
- const sourcePath = requireString(record.sourcePath ?? record.source, "sourcePath");
5615
- const destinationPath = requireString(record.destinationPath ?? record.destination, "destinationPath");
5695
+ const sourcePath = resolveExecServerPath(requireString(record.sourcePath ?? record.source, "sourcePath"), "copy source path");
5696
+ const destinationPath = resolveExecServerPath(requireString(record.destinationPath ?? record.destination, "destinationPath"), "copy destination path");
5616
5697
  const fsSandboxPolicy = resolveFsSandboxPolicy(execServer, record);
5617
5698
  assertResolvedFsSandboxAccess(fsSandboxPolicy, [{
5618
5699
  path: sourcePath,
@@ -5812,8 +5893,9 @@ function readStreamingSandboxHttpResponse(params) {
5812
5893
  }
5813
5894
  reject(new Error(message));
5814
5895
  };
5896
+ params.child.stdout.setEncoding("utf8");
5815
5897
  params.child.stdout.on("data", (chunk) => {
5816
- stdoutBuffer += chunk.toString("utf8");
5898
+ stdoutBuffer += chunk;
5817
5899
  let newline = stdoutBuffer.indexOf("\n");
5818
5900
  while (newline >= 0) {
5819
5901
  const line = stdoutBuffer.slice(0, newline).trim();
@@ -5849,8 +5931,9 @@ function readStreamingSandboxHttpResponse(params) {
5849
5931
  fail(`sandbox http/request produced an unterminated stdout line longer than ${SANDBOX_HTTP_STREAM_LINE_MAX_CHARS} characters`, null);
5850
5932
  }
5851
5933
  });
5934
+ params.child.stderr.setEncoding("utf8");
5852
5935
  params.child.stderr.on("data", (chunk) => {
5853
- stderr = `${stderr}${chunk.toString("utf8")}`.slice(-4096);
5936
+ stderr = sliceUtf16Safe(`${stderr}${chunk}`, -4096);
5854
5937
  });
5855
5938
  params.child.once("error", (error) => {
5856
5939
  childFailure ??= error.message;
@@ -6101,7 +6184,7 @@ async function startProcess(execServer, processes, socket, params) {
6101
6184
  const processId = requireString(record.processId, "processId");
6102
6185
  if (processes.has(processId)) throw new Error(`process already exists: ${processId}`);
6103
6186
  const argv = requireStringArray(record.argv, "argv");
6104
- const cwd = requireString(record.cwd, "cwd");
6187
+ const cwd = resolveExecServerPath(requireString(record.cwd, "cwd"), "process cwd");
6105
6188
  rejectUnsupportedArg0(record.arg0);
6106
6189
  const env = readProcessEnv(record);
6107
6190
  const managed = {
@@ -6591,7 +6674,7 @@ function prepareCodexAttemptResources(prompt) {
6591
6674
  const { context, turnState, buildRenderedCodexDeveloperInstructions } = prompt;
6592
6675
  const { runtime, attemptTools } = context;
6593
6676
  const { connection, hookChannelId } = runtime;
6594
- const { params, effectiveCwd, sessionAgentId, sandboxSessionKey, runAbortController, sandbox, options, nativeHookRelayEvents } = connection;
6677
+ const { appServer, params, effectiveCwd, sessionAgentId, sandboxSessionKey, runAbortController, sandbox, options, nativeHookRelayEvents } = connection;
6595
6678
  const { toolBridge } = attemptTools;
6596
6679
  const hostTrajectoryRecorder = params.trajectoryRecorder;
6597
6680
  const trajectoryRecorder = createCodexTrajectoryRecorder({
@@ -6657,16 +6740,17 @@ function prepareCodexAttemptResources(prompt) {
6657
6740
  const retireSharedCodexClientForOneShotCleanup = async () => {
6658
6741
  if (params.cleanupBundleMcpOnRunEnd !== true || state.sharedCodexClientRetiredForOneShotCleanup) return;
6659
6742
  state.sharedCodexClientRetiredForOneShotCleanup = true;
6660
- const retired = retireSharedCodexAppServerClientIfCurrent(state.client);
6661
- embeddedAgentLog.info("codex app-server one-shot cleanup retired shared client", {
6743
+ const retired = clearSharedCodexAppServerClientIfCurrentAndUnclaimed(state.client);
6744
+ embeddedAgentLog.info("codex app-server one-shot cleanup checked shared client retirement", {
6662
6745
  runId: params.runId,
6663
6746
  sessionId: params.sessionId,
6664
6747
  sessionKey: params.sessionKey,
6665
- activeLeases: retired?.activeLeases ?? null,
6666
- closed: retired?.closed ?? false,
6667
- matchedSharedClient: Boolean(retired)
6748
+ activeLeases: retired.activeLeases,
6749
+ pendingAcquires: retired.pendingAcquires,
6750
+ closed: retired.closed,
6751
+ matchedSharedClient: retired.found
6668
6752
  });
6669
- if (retired?.closed) await state.client.closeAndWait({
6753
+ if (retired.closed) await state.client.closeAndWait({
6670
6754
  exitTimeoutMs: 2e3,
6671
6755
  forceKillDelayMs: 250
6672
6756
  });
@@ -6724,6 +6808,7 @@ function prepareCodexAttemptResources(prompt) {
6724
6808
  attemptTimeoutMs: params.timeoutMs,
6725
6809
  startupTimeoutMs,
6726
6810
  turnStartTimeoutMs: params.timeoutMs,
6811
+ loopDetectionPreToolUseRelay: appServer.loopDetectionPreToolUseRelay,
6727
6812
  signal: runAbortController.signal,
6728
6813
  onPreToolUseFailure: (failure) => {
6729
6814
  const projector = projectorRef.current;
@@ -6736,7 +6821,8 @@ function prepareCodexAttemptResources(prompt) {
6736
6821
  configPatch: state.nativeHookRelay ? buildCodexNativeHookRelayConfig({
6737
6822
  relay: state.nativeHookRelay,
6738
6823
  events: nativeHookRelayEvents,
6739
- hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec
6824
+ hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec,
6825
+ loopDetectionPreToolUseRelay: appServer.loopDetectionPreToolUseRelay
6740
6826
  }) : options.nativeHookRelay?.enabled === false ? buildCodexNativeHookRelayDisabledConfig() : void 0,
6741
6827
  nativeHookRelayGeneration: state.nativeHookRelay?.generation
6742
6828
  };
@@ -6955,6 +7041,21 @@ async function prepareCodexAttemptRuntime(connection) {
6955
7041
  };
6956
7042
  }
6957
7043
  //#endregion
7044
+ //#region extensions/codex/src/app-server/dynamic-tool-result-projection.ts
7045
+ /** Project one OpenClaw dynamic-tool response with its executed mutation identity. */
7046
+ function recordCodexDynamicToolResult(projector, call, response, protocolResponse) {
7047
+ projector?.recordDynamicToolResult({
7048
+ callId: call.callId,
7049
+ tool: call.tool,
7050
+ asyncStarted: response.asyncStarted === true,
7051
+ terminalResolution: response.terminalResolution,
7052
+ success: protocolResponse.success,
7053
+ terminalType: response.diagnosticTerminalType ?? (protocolResponse.success ? "completed" : "error"),
7054
+ sideEffectEvidence: response.sideEffectEvidence === true || response.terminalResolution?.sideEffectEvidence === true,
7055
+ contentItems: protocolResponse.contentItems
7056
+ });
7057
+ }
7058
+ //#endregion
6958
7059
  //#region extensions/codex/src/app-server/run-attempt-tools.ts
6959
7060
  function toTranscriptToolResult(response) {
6960
7061
  const sanitized = sanitizeCodexToolResponse(response);
@@ -7180,8 +7281,10 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
7180
7281
  toolBridge,
7181
7282
  signal: runAbortController.signal,
7182
7283
  timeoutMs: dynamicToolTimeoutMs,
7284
+ toolMeta,
7183
7285
  toolCallOrdinal,
7184
7286
  onAgentToolResult: params.onAgentToolResult,
7287
+ observeToolTerminal: params.observeToolTerminal,
7185
7288
  onFallbackSelected: () => {
7186
7289
  if (toolCallOrdinal !== void 0) suppressedDynamicToolOutcomeOrdinals.add(toolCallOrdinal);
7187
7290
  },
@@ -7217,15 +7320,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
7217
7320
  success: protocolResponse.success,
7218
7321
  contentItems: protocolResponse.contentItems
7219
7322
  });
7220
- projector?.recordDynamicToolResult({
7221
- callId: call.callId,
7222
- tool: call.tool,
7223
- asyncStarted: response.asyncStarted === true,
7224
- success: protocolResponse.success,
7225
- terminalType: response.diagnosticTerminalType ?? (protocolResponse.success ? "completed" : "error"),
7226
- sideEffectEvidence: response.sideEffectEvidence === true,
7227
- contentItems: protocolResponse.contentItems
7228
- });
7323
+ recordCodexDynamicToolResult(projector, call, response, protocolResponse);
7229
7324
  if (shouldEmitDynamicToolProgress) {
7230
7325
  const progressResponse = toCodexDynamicToolProgressResponse(response, protocolResponse);
7231
7326
  emitCodexAppServerEvent(params, {
@@ -7255,7 +7350,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
7255
7350
  durationMs: toolDurationMs
7256
7351
  });
7257
7352
  pendingOpenClawDynamicToolCompletionIds.delete(call.callId);
7258
- if (response.terminate === true) scheduleTurnReleaseAfterTerminalDynamicTool({
7353
+ if (response.terminate === true && response.success) scheduleTurnReleaseAfterTerminalDynamicTool({
7259
7354
  call,
7260
7355
  response,
7261
7356
  durationMs: toolDurationMs
@@ -7397,11 +7492,200 @@ function clearComputerUseHealthMonitor(client, monitor) {
7397
7492
  getComputerUseHealthMonitorState().monitors.delete(client);
7398
7493
  }
7399
7494
  //#endregion
7495
+ //#region extensions/codex/src/app-server/plugin-metadata-cache.ts
7496
+ const CODEX_PLUGIN_METADATA_CACHE_TTL_MS = 3600 * 1e3;
7497
+ /** Process-local plugin metadata cache with coalesced loads per query. */
7498
+ var CodexPluginMetadataCache = class {
7499
+ constructor(nowMs = Date.now) {
7500
+ this.nowMs = nowMs;
7501
+ this.entries = /* @__PURE__ */ new Map();
7502
+ this.inFlight = /* @__PURE__ */ new Map();
7503
+ this.generations = /* @__PURE__ */ new Map();
7504
+ this.clearGeneration = 0;
7505
+ }
7506
+ /** Returns a fresh cached snapshot without issuing a request. */
7507
+ read(appCacheKey, queryKind) {
7508
+ const entryKey = buildMetadataCacheEntryKey(appCacheKey, queryKind);
7509
+ const entry = this.entries.get(entryKey);
7510
+ if (!entry) return;
7511
+ if (entry.expiresAtMs <= this.nowMs()) {
7512
+ this.entries.delete(entryKey);
7513
+ return;
7514
+ }
7515
+ return entry.snapshot;
7516
+ }
7517
+ /** Returns a fresh cached snapshot or coalesces one plugin/list request. */
7518
+ async load(params) {
7519
+ const entryKey = buildMetadataCacheEntryKey(params.appCacheKey, params.queryKind);
7520
+ const cached = this.read(params.appCacheKey, params.queryKind);
7521
+ if (cached) return cached;
7522
+ const pending = this.inFlight.get(entryKey);
7523
+ if (pending) try {
7524
+ return await pending.promise;
7525
+ } catch {
7526
+ if (this.inFlight.get(entryKey) === pending) this.inFlight.delete(entryKey);
7527
+ return await this.load(params);
7528
+ }
7529
+ const generation = this.generations.get(params.appCacheKey) ?? 0;
7530
+ const clearGeneration = this.clearGeneration;
7531
+ const promise = (async () => {
7532
+ const response = await params.request("plugin/list", params.requestParams);
7533
+ const snapshot = {
7534
+ appCacheKey: params.appCacheKey,
7535
+ queryKind: params.queryKind,
7536
+ response
7537
+ };
7538
+ if (generation === (this.generations.get(params.appCacheKey) ?? 0) && clearGeneration === this.clearGeneration && !hasMarketplaceLoadErrors(response) && (params.cacheable?.(response) ?? true)) this.entries.set(entryKey, {
7539
+ snapshot,
7540
+ expiresAtMs: this.nowMs() + CODEX_PLUGIN_METADATA_CACHE_TTL_MS
7541
+ });
7542
+ return snapshot;
7543
+ })();
7544
+ this.inFlight.set(entryKey, {
7545
+ appCacheKey: params.appCacheKey,
7546
+ promise
7547
+ });
7548
+ try {
7549
+ return await promise;
7550
+ } finally {
7551
+ if (this.inFlight.get(entryKey)?.promise === promise) this.inFlight.delete(entryKey);
7552
+ }
7553
+ }
7554
+ /** Invalidates all plugin metadata queries for one app-server runtime. */
7555
+ invalidate(appCacheKey) {
7556
+ this.generations.set(appCacheKey, (this.generations.get(appCacheKey) ?? 0) + 1);
7557
+ for (const [entryKey, entry] of this.entries) if (entry.snapshot.appCacheKey === appCacheKey) this.entries.delete(entryKey);
7558
+ for (const [entryKey, pending] of this.inFlight) if (pending.appCacheKey === appCacheKey) this.inFlight.delete(entryKey);
7559
+ }
7560
+ /** Clears snapshots and prevents late in-flight loads from repopulating them. */
7561
+ clear() {
7562
+ this.clearGeneration += 1;
7563
+ this.generations.clear();
7564
+ this.entries.clear();
7565
+ this.inFlight.clear();
7566
+ }
7567
+ };
7568
+ /** Shared plugin metadata cache used by Codex app-server runtime paths. */
7569
+ const defaultCodexPluginMetadataCache = new CodexPluginMetadataCache();
7570
+ function hasMarketplaceLoadErrors(response) {
7571
+ return (response.marketplaceLoadErrors?.length ?? 0) > 0;
7572
+ }
7573
+ function buildMetadataCacheEntryKey(appCacheKey, queryKind) {
7574
+ return JSON.stringify([appCacheKey, queryKind]);
7575
+ }
7576
+ //#endregion
7577
+ //#region extensions/codex/src/app-server/plugin-thread-config-deadline.ts
7578
+ /** Enforces one bounded startup budget across Codex plugin config discovery. */
7579
+ const CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS = 5e3;
7580
+ const CODEX_PLUGIN_THREAD_CONFIG_TIMEOUT_DIVISOR = 4;
7581
+ const CODEX_PLUGIN_THREAD_CONFIG_MIN_TIMEOUT_MS = 100;
7582
+ var CodexPluginThreadConfigDeadlineError = class extends Error {
7583
+ constructor() {
7584
+ super("Codex plugin thread config deadline elapsed");
7585
+ this.name = "CodexPluginThreadConfigDeadlineError";
7586
+ }
7587
+ };
7588
+ /** Resolves the plugin policy state reused throughout app-server startup. */
7589
+ function resolveCodexPluginThreadConfigStartupPolicy(params) {
7590
+ const pluginThreadConfigRequired = !params.nativeToolSurfaceEnabled || shouldBuildCodexPluginThreadConfig(params.pluginConfig);
7591
+ const pluginThreadConfigPluginConfig = params.nativeToolSurfaceEnabled ? params.pluginConfig : disableCodexPluginThreadConfig(params.pluginConfig);
7592
+ const resolvedPluginPolicy = pluginThreadConfigRequired ? resolveCodexPluginsPolicy(pluginThreadConfigPluginConfig) : void 0;
7593
+ return {
7594
+ pluginThreadConfigRequired,
7595
+ pluginThreadConfigPluginConfig,
7596
+ resolvedPluginPolicy,
7597
+ enabledPluginConfigKeys: resolvedPluginPolicy ? resolvedPluginPolicy.pluginPolicies.filter((plugin) => plugin.enabled).map((plugin) => plugin.configKey).toSorted() : void 0
7598
+ };
7599
+ }
7600
+ /** Builds plugin config without allowing sequential RPC timeouts to consume the turn. */
7601
+ async function buildCodexPluginThreadConfigWithinDeadline(params) {
7602
+ const { requestTimeoutMs, signal, request, ...buildParams } = params;
7603
+ const timeoutMs = resolveCodexPluginThreadConfigTimeoutMs(requestTimeoutMs);
7604
+ const deadlineMs = Date.now() + timeoutMs;
7605
+ try {
7606
+ return await waitForCodexPluginThreadConfigBuild({
7607
+ signal,
7608
+ timeoutMs,
7609
+ build: () => buildCodexPluginThreadConfig({
7610
+ ...buildParams,
7611
+ request: (method, requestParams) => {
7612
+ const remainingTimeoutMs = deadlineMs - Date.now();
7613
+ if (remainingTimeoutMs <= 0) throw new CodexPluginThreadConfigDeadlineError();
7614
+ return request(method, requestParams, {
7615
+ timeoutMs: remainingTimeoutMs,
7616
+ signal
7617
+ });
7618
+ }
7619
+ })
7620
+ });
7621
+ } catch (error) {
7622
+ if (signal.aborted || !isCodexPluginThreadConfigTimeoutError(error)) throw error;
7623
+ return buildCodexPluginThreadConfigTimeoutFallback({
7624
+ pluginConfig: buildParams.pluginConfig,
7625
+ appCacheKey: buildParams.appCacheKey,
7626
+ message: `Codex plugin discovery exceeded its ${timeoutMs} ms startup budget; plugin apps were disabled for this turn.`
7627
+ });
7628
+ }
7629
+ }
7630
+ function waitForCodexPluginThreadConfigBuild(params) {
7631
+ if (params.signal.aborted) return Promise.reject(resolveAbortReason(params.signal));
7632
+ return new Promise((resolve, reject) => {
7633
+ let settled = false;
7634
+ const finish = () => {
7635
+ if (settled) return false;
7636
+ settled = true;
7637
+ clearTimeout(timer);
7638
+ params.signal.removeEventListener("abort", onAbort);
7639
+ return true;
7640
+ };
7641
+ const resolveOnce = (config) => {
7642
+ if (finish()) resolve(config);
7643
+ };
7644
+ const rejectOnce = (error) => {
7645
+ if (finish()) reject(error instanceof Error ? error : new Error(String(error)));
7646
+ };
7647
+ const onAbort = () => rejectOnce(resolveAbortReason(params.signal));
7648
+ const timer = setTimeout(() => rejectOnce(new CodexPluginThreadConfigDeadlineError()), params.timeoutMs);
7649
+ params.signal.addEventListener("abort", onAbort, { once: true });
7650
+ params.build().then(resolveOnce, rejectOnce);
7651
+ });
7652
+ }
7653
+ function resolveAbortReason(signal) {
7654
+ return signal.reason instanceof Error ? signal.reason : /* @__PURE__ */ new Error("Codex plugin thread config aborted");
7655
+ }
7656
+ /** Creates the recovery metadata and bounded builder used by thread startup. */
7657
+ function createCodexPluginThreadConfigStartupProvider(params) {
7658
+ const { client, policy, inputFingerprint, enabledPluginConfigKeys, appCache, metadataCache: configuredMetadataCache, ...buildParams } = params;
7659
+ const metadataCache = configuredMetadataCache ?? defaultCodexPluginMetadataCache;
7660
+ return {
7661
+ enabled: true,
7662
+ inputFingerprint,
7663
+ enabledPluginConfigKeys,
7664
+ accountAppRecoveryEnabled: policy?.allowAllPlugins,
7665
+ recoverablePluginConfigKeys: policy ? resolveRecoverableCodexPluginConfigKeys({
7666
+ policy,
7667
+ metadataCache,
7668
+ appCacheKey: params.appCacheKey
7669
+ }) : void 0,
7670
+ build: () => buildCodexPluginThreadConfigWithinDeadline({
7671
+ ...buildParams,
7672
+ appCache: appCache ?? defaultCodexAppInventoryCache,
7673
+ metadataCache,
7674
+ request: (method, requestParams, options) => client.request(method, requestParams, options)
7675
+ })
7676
+ };
7677
+ }
7678
+ function resolveCodexPluginThreadConfigTimeoutMs(requestTimeoutMs) {
7679
+ return Math.min(CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS, Math.max(CODEX_PLUGIN_THREAD_CONFIG_MIN_TIMEOUT_MS, Math.floor((Number.isFinite(requestTimeoutMs) && requestTimeoutMs > 0 ? requestTimeoutMs : CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS * CODEX_PLUGIN_THREAD_CONFIG_TIMEOUT_DIVISOR) / CODEX_PLUGIN_THREAD_CONFIG_TIMEOUT_DIVISOR)));
7680
+ }
7681
+ function isCodexPluginThreadConfigTimeoutError(error) {
7682
+ return error instanceof CodexPluginThreadConfigDeadlineError || error instanceof Error && "code" in error && error.code === "CODEX_APP_SERVER_LOCAL_REQUEST_CANCELLED" && error.message.endsWith(" timed out");
7683
+ }
7684
+ //#endregion
7400
7685
  //#region extensions/codex/src/app-server/attempt-startup.ts
7401
7686
  /**
7402
7687
  * Startup orchestration for Codex app-server attempts, including shared-client
7403
- * leasing, plugin thread config, sandbox execution environment, and thread
7404
- * lifecycle binding.
7688
+ * leasing, plugin thread config, sandbox environment, and thread lifecycle binding.
7405
7689
  */
7406
7690
  const CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS = 3;
7407
7691
  const CODEX_APP_SERVER_CONTEXT_RESTART_SELECTION_CHANGED = "CODEX_APP_SERVER_CONTEXT_RESTART_SELECTION_CHANGED";
@@ -7440,13 +7724,12 @@ async function startCodexAttemptThread(params) {
7440
7724
  },
7441
7725
  operation: async () => {
7442
7726
  const threadConfig = mergeCodexThreadConfigs(params.bundleMcpThreadConfig?.configPatch);
7443
- const pluginThreadConfigRequired = !params.nativeToolSurfaceEnabled || shouldBuildCodexPluginThreadConfig(params.pluginConfig);
7444
- const pluginThreadConfigPluginConfig = params.nativeToolSurfaceEnabled ? params.pluginConfig : disableCodexPluginThreadConfig(params.pluginConfig);
7445
- const resolvedPluginPolicy = pluginThreadConfigRequired ? resolveCodexPluginsPolicy(pluginThreadConfigPluginConfig) : void 0;
7727
+ const { pluginThreadConfigRequired, pluginThreadConfigPluginConfig, resolvedPluginPolicy, enabledPluginConfigKeys } = resolveCodexPluginThreadConfigStartupPolicy({
7728
+ pluginConfig: params.pluginConfig,
7729
+ nativeToolSurfaceEnabled: params.nativeToolSurfaceEnabled
7730
+ });
7446
7731
  const computerUseMcpElicitationDelegationRequired = params.computerUseConfig.enabled;
7447
- const mcpElicitationDelegationRequired = resolvedPluginPolicy?.enabled === true || computerUseMcpElicitationDelegationRequired;
7448
- const enabledPluginConfigKeys = resolvedPluginPolicy ? resolvedPluginPolicy.pluginPolicies.filter((plugin) => plugin.enabled).map((plugin) => plugin.configKey).toSorted() : void 0;
7449
- pluginAppServer = mcpElicitationDelegationRequired ? {
7732
+ pluginAppServer = resolvedPluginPolicy?.enabled === true || computerUseMcpElicitationDelegationRequired ? {
7450
7733
  ...params.appServer,
7451
7734
  approvalPolicy: withMcpElicitationsApprovalPolicy(params.appServer.approvalPolicy)
7452
7735
  } : params.appServer;
@@ -7461,6 +7744,7 @@ async function startCodexAttemptThread(params) {
7461
7744
  startupClient = await params.attemptClientFactory({
7462
7745
  startOptions: params.appServer.start,
7463
7746
  ...params.startupPreparedAuth ? { preparedAuth: params.startupPreparedAuth } : { authProfileId: params.startupAuthProfileId },
7747
+ authRequirement: params.startupAuthRequirement,
7464
7748
  authProfileStore: attemptParams.authProfileStore,
7465
7749
  authBindingFingerprint: params.startupAuthBindingFingerprint,
7466
7750
  ...params.runtimeArtifactRequest ? {
@@ -7486,8 +7770,8 @@ async function startCodexAttemptThread(params) {
7486
7770
  releaseSharedClientLease = startupClientLease;
7487
7771
  attemptedClient = activeStartupClient;
7488
7772
  startupClientForAbandonedRequestCleanup = activeStartupClient;
7489
- if (startupAbandoned) throw new Error("codex app-server startup timed out");
7490
- if (startupAbandonController.signal.aborted) throw new Error("codex app-server startup aborted");
7773
+ if (startupAbandoned) throw new CodexAppServerStartupError("timed_out");
7774
+ if (startupAbandonController.signal.aborted) throw new CodexAppServerStartupError("aborted");
7491
7775
  let runtimeArtifact;
7492
7776
  if (params.runtimeArtifactRequest) {
7493
7777
  const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-C2ITXdhM.js");
@@ -7568,7 +7852,7 @@ async function startCodexAttemptThread(params) {
7568
7852
  startupSandboxEnvironmentAcquired = Boolean(startupSandboxEnvironment);
7569
7853
  if (startupAbandonController.signal.aborted) {
7570
7854
  await releaseStartupSandboxEnvironment();
7571
- throw new Error("codex app-server startup aborted");
7855
+ throw new CodexAppServerStartupError("aborted");
7572
7856
  }
7573
7857
  if (params.sandbox?.enabled && params.nativeToolSurfaceEnabled && params.sandboxExecServerEnabled && !startupSandboxEnvironment) throw new Error("Codex app-server did not register an OpenClaw sandbox exec-server environment.");
7574
7858
  } catch (error) {
@@ -7631,21 +7915,17 @@ async function startCodexAttemptThread(params) {
7631
7915
  appServerRuntimeFingerprint,
7632
7916
  contextEngineProjection: params.contextEngineProjection,
7633
7917
  signal,
7634
- pluginThreadConfig: pluginThreadConfigRequired ? {
7635
- enabled: true,
7918
+ pluginThreadConfig: pluginThreadConfigRequired ? createCodexPluginThreadConfigStartupProvider({
7636
7919
  inputFingerprint: pluginThreadConfigInputFingerprint,
7637
7920
  enabledPluginConfigKeys,
7638
- build: () => buildCodexPluginThreadConfig({
7639
- pluginConfig: pluginThreadConfigPluginConfig,
7640
- request: (method, requestParams) => activeStartupClient.request(method, requestParams, {
7641
- timeoutMs: params.appServer.requestTimeoutMs,
7642
- signal
7643
- }),
7644
- configCwd: startupExecutionCwd,
7645
- appCache: defaultCodexAppInventoryCache,
7646
- appCacheKey: pluginAppCacheKey
7647
- })
7648
- } : void 0
7921
+ policy: resolvedPluginPolicy,
7922
+ requestTimeoutMs: params.appServer.requestTimeoutMs,
7923
+ signal,
7924
+ pluginConfig: pluginThreadConfigPluginConfig,
7925
+ client: activeStartupClient,
7926
+ configCwd: startupExecutionCwd,
7927
+ appCacheKey: pluginAppCacheKey
7928
+ }) : void 0
7649
7929
  });
7650
7930
  try {
7651
7931
  const startupThread = await startOrResumeThread(buildThreadLifecycleParams(startupAbandonController.signal, reserveStartupThread));
@@ -7658,7 +7938,7 @@ async function startCodexAttemptThread(params) {
7658
7938
  })) throw new CodexAppServerUnsafeSubscriptionError("Codex startup subscription cleanup failed", { cause: error });
7659
7939
  throw error;
7660
7940
  }
7661
- if (startupAbandonController.signal.aborted) throw new Error("codex app-server startup aborted");
7941
+ if (startupAbandonController.signal.aborted) throw new CodexAppServerStartupError("aborted");
7662
7942
  const startupRoute = startupReservation;
7663
7943
  if (!startupRoute) throw new Error("codex app-server startup did not reserve its thread route");
7664
7944
  startupSandboxEnvironmentAcquired = false;
@@ -7773,14 +8053,14 @@ async function startCodexAttemptThread(params) {
7773
8053
  }
7774
8054
  }
7775
8055
  function shouldClearSharedClientAfterStartupAbandon(error) {
7776
- return error instanceof Error && (error.message === "codex app-server startup timed out" || error.message === "codex app-server startup aborted");
8056
+ return isCodexAppServerStartupError(error);
7777
8057
  }
7778
8058
  function shouldClearSharedClientAfterStartupRace(error) {
7779
- return error instanceof Error && (shouldClearSharedClientAfterStartupAbandon(error) || error.message.endsWith(" timed out"));
8059
+ return shouldClearSharedClientAfterStartupAbandon(error) || isCodexAppServerRequestTimeoutError(error);
7780
8060
  }
7781
8061
  function shouldClearSharedClientAfterStartupFailure(params) {
7782
8062
  if (!(params.error instanceof Error)) return !params.spawnedBy;
7783
- if (params.error.message.includes("write EPIPE")) return true;
8063
+ if (isCodexAppServerBrokenPipeError(params.error)) return true;
7784
8064
  return !params.spawnedBy;
7785
8065
  }
7786
8066
  //#endregion
@@ -7791,7 +8071,7 @@ async function startCodexAttemptRuntime(resources) {
7791
8071
  const { runtime, attemptTools, promptState } = context;
7792
8072
  const { connection, runtimeParams, preparedAuthBinding, buildActiveRunAttemptParams, startupAuthAccountCacheKey, startupEnvApiKeyCacheKey, bundleMcpThreadConfig, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, sandboxExecServerEnabled } = runtime;
7793
8073
  const { toolBridge, toolState } = attemptTools;
7794
- const { params, attemptClientFactory, bindingStore, appServer, pluginConfig, computerUseConfig, startupClientAuthProfileId, runtimeArtifactRequest, startupPreparedAuth, agentDir, sessionAgentId, effectiveWorkspace, effectiveCwd, sandbox, runAbortController, usesSupervisionConnection, resolveReviewerPolicyContext, resolveRuntimeOptionsForCurrentBinding, startupAuthProfileId, abortFromUpstream } = connection;
8074
+ const { params, attemptClientFactory, bindingStore, appServer, pluginConfig, computerUseConfig, startupClientAuthProfileId, runtimeArtifactRequest, startupPreparedAuth, agentDir, sessionAgentId, effectiveWorkspace, effectiveCwd, sandbox, runAbortController, usesSupervisionConnection, resolveReviewerPolicyContext, resolveRuntimeOptionsForCurrentBinding, startupAuthProfileId, startupAuthRequirement, abortFromUpstream } = connection;
7795
8075
  let pluginAppServer = withCodexAppServerFastModeServiceTier(appServer, runtimeParams);
7796
8076
  try {
7797
8077
  emitCodexAppServerEvent(params, {
@@ -7805,6 +8085,7 @@ async function startCodexAttemptRuntime(resources) {
7805
8085
  pluginConfig,
7806
8086
  computerUseConfig,
7807
8087
  startupAuthProfileId: startupClientAuthProfileId,
8088
+ startupAuthRequirement,
7808
8089
  startupAuthBindingFingerprint: preparedAuthBinding?.fingerprint,
7809
8090
  ...runtimeArtifactRequest ? { runtimeArtifactRequest } : {},
7810
8091
  startupPreparedAuth,
@@ -7873,7 +8154,9 @@ async function startCodexAttemptRuntime(resources) {
7873
8154
  stream: "codex_app_server.lifecycle",
7874
8155
  data: {
7875
8156
  phase: "thread_ready",
7876
- threadId: state.thread.threadId
8157
+ threadId: state.thread.threadId,
8158
+ action: state.thread.lifecycle.action,
8159
+ clientId: state.client.getInstanceId()
7877
8160
  }
7878
8161
  });
7879
8162
  } catch (error) {
@@ -8097,6 +8380,7 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
8097
8380
  model: usesSupervisionConnection ? resourceState.thread.model ?? effectiveRuntimeModelId : params.modelId,
8098
8381
  api: usesSupervisionConnection ? runtimeParams.model.api : params.model.api,
8099
8382
  transport: appServer.start.transport,
8383
+ observationUnit: "turn",
8100
8384
  ...hookContextWindowFields,
8101
8385
  trace: codexModelCallTrace
8102
8386
  },
@@ -8385,6 +8669,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
8385
8669
  return { result: buildCodexTurnStartFailureResult({
8386
8670
  params,
8387
8671
  message: usageLimitError.message,
8672
+ promptError: createCodexUsageLimitPromptError(usageLimitError.message),
8388
8673
  messagesSnapshot,
8389
8674
  systemPromptReport
8390
8675
  }) };
@@ -8771,6 +9056,7 @@ function createCodexAttemptTurnState(resources) {
8771
9056
  rateLimitsRevisionBeforeLastTurnStart: void 0,
8772
9057
  completed: false,
8773
9058
  terminalTurnNotificationQueued: false,
9059
+ sawCodexInterruptMarker: false,
8774
9060
  timedOut: false,
8775
9061
  turnCompletionIdleTimedOut: false,
8776
9062
  turnWatchTimeoutKind: void 0,
@@ -8798,7 +9084,7 @@ function createCodexAttemptTurnState(resources) {
8798
9084
  state.resolveCompletion = resolve;
8799
9085
  });
8800
9086
  const turnCompletionIdleTimeoutMs = resolveCodexTurnCompletionIdleTimeoutMs(options.turnCompletionIdleTimeoutMs ?? appServer.turnCompletionIdleTimeoutMs);
8801
- const turnAssistantCompletionIdleTimeoutMs = resolveCodexTurnAssistantCompletionIdleTimeoutMs(options.turnAssistantCompletionIdleTimeoutMs);
9087
+ const turnAssistantCompletionIdleTimeoutMs = resolveCodexTurnAssistantCompletionIdleTimeoutMs(options.turnAssistantCompletionIdleTimeoutMs ?? appServer.turnAssistantCompletionIdleTimeoutMs);
8802
9088
  const postToolRawAssistantCompletionIdleTimeoutMs = resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs(options.postToolRawAssistantCompletionIdleTimeoutMs ?? appServer.postToolRawAssistantCompletionIdleTimeoutMs, turnAssistantCompletionIdleTimeoutMs);
8803
9089
  const turnTerminalIdleTimeoutMs = resolveCodexTurnTerminalIdleTimeoutMs(options.turnTerminalIdleTimeoutMs, params.runTimeoutOverrideMs);
8804
9090
  const turnAttemptIdleTimeoutMs = Math.max(100, Math.floor(params.timeoutMs));