@openclaw/codex 2026.8.1-beta.2 → 2026.9.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/api.js +147 -0
  2. package/dist/{attempt-client-cleanup-DMLXUfa8.js → attempt-client-cleanup-bfsmcQ6m.js} +21 -2
  3. package/dist/{binding-connection-I5Bo-AsX.js → binding-connection-BMvPX73o.js} +15 -3
  4. package/dist/{bounded-turn-qgZmzy_4.js → bounded-turn-B7iBUcuP.js} +22 -16
  5. package/dist/{capabilities-CybGI1oz.js → capabilities-BRMh0aIq.js} +1 -1
  6. package/dist/cli-metadata.js +1 -1
  7. package/dist/{command-formatters-B1AEz8ZA.js → command-formatters-DEsIufkt.js} +2 -2
  8. package/dist/{command-handlers-Db8pu_ds.js → command-handlers-D_-1_qRp.js} +65 -37
  9. package/dist/command-rpc-CCeCkf_v.js +90 -0
  10. package/dist/{compact-LspQaGfl.js → compact-BglNFZrQ.js} +35 -29
  11. package/dist/{session-binding-DPxIvMgE.js → config-giW8X0QA.js} +108 -914
  12. package/dist/context-compaction-activity-BOeJf7yo.js +58 -0
  13. package/dist/doctor-contract-api.js +23 -21
  14. package/dist/{dynamic-tools-BVdyWkUD.js → dynamic-tools-Dnlfa--w.js} +1345 -1424
  15. package/dist/{effective-mcp-catalog-DIIhAtOZ.js → effective-mcp-catalog-CTeGrnfO.js} +2 -2
  16. package/dist/elicitation-input-DMkeki8d.js +71 -0
  17. package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
  18. package/dist/{event-projector-usage-e5huIQWu.js → event-projector-usage-Bk1I90Bg.js} +18 -18
  19. package/dist/harness-Csz0F-DK.js +258 -0
  20. package/dist/harness.js +2 -226
  21. package/dist/index.js +262 -181
  22. package/dist/{isolated-completion-C58NbL40.js → isolated-completion-Cv6FqygM.js} +4 -4
  23. package/dist/managed-binary-DFYK4DWq.js +248 -0
  24. package/dist/media-understanding-provider.js +2 -2
  25. package/dist/model-catalog-i9rNBthX.js +48 -0
  26. package/dist/{models-BFlpn1Ex.js → models-TS3HBU-q.js} +4 -3
  27. package/dist/{native-subagent-monitor-DyTGmTUx.js → native-subagent-monitor-4Mfq2HDs.js} +354 -83
  28. package/dist/node-exec-server.runtime-BpWqJO1V.js +192 -0
  29. package/dist/{plugin-app-cache-key-C3H2CVp6.js → plugin-app-cache-key-C1CAdfcP.js} +19 -4
  30. package/dist/plugin-approval-roundtrip-bUm777tR.js +95 -0
  31. package/dist/{plugin-marketplace-discovery-CzrGJdCR.js → plugin-marketplace-discovery-B9DvaAG-.js} +59 -54
  32. package/dist/{plugin-metadata-cache-CNJPj4_b.js → plugin-metadata-cache-CTCT3w5L.js} +164 -134
  33. package/dist/{protocol-validators-B4F7L8Rf.js → protocol-validators-VeJxxJ0U.js} +80 -5
  34. package/dist/{rate-limits-DZXmOL8-.js → rate-limits-C5_D8Gmb.js} +1 -1
  35. package/dist/{request-BRl5_UfX.js → request-DXXGHko0.js} +2 -2
  36. package/dist/{run-attempt-P8BdxC1I.js → run-attempt-DYc0QCBF.js} +1276 -765
  37. package/dist/{runtime-artifact-BVSPdd6g.js → runtime-artifact-BvyT1uyd.js} +4 -7
  38. package/dist/{sandbox-guard-Cmwc9eIk.js → sandbox-guard-kuWTn9C5.js} +25 -19
  39. package/dist/session-binding-Bcynfd-_.js +874 -0
  40. package/dist/{session-catalog-xwNi_SDM.js → session-catalog-DaLKVtpH.js} +1534 -1288
  41. package/dist/session-catalog-home-id-BNwAJ9D7.js +18 -0
  42. package/dist/{session-cli-7hgXZDV7.js → session-cli-DMc4oS2w.js} +20 -7
  43. package/dist/session-permission-policy-BrNH1bjy.js +160 -0
  44. package/dist/{session-retirement-DoMMJFKm.js → session-retirement-CcNC3YSY.js} +3 -3
  45. package/dist/{session-upstream-marker-CrIFX06J.js → session-upstream-marker-BIkusb95.js} +1 -1
  46. package/dist/{settled-turn-finalizer-BRWBO4MO.js → settled-turn-finalizer-Dc3ApjU4.js} +24 -20
  47. package/dist/{shared-client-kIBbGjk4.js → shared-client-DKz23hHY.js} +1632 -372
  48. package/dist/{side-question-9HAL26l9.js → side-question-DjA_jsNe.js} +105 -54
  49. package/dist/{thread-lifecycle-Bu1BTDXr.js → thread-lifecycle-L7oEkTlq.js} +1147 -114
  50. package/dist/{thread-ownership-6kOQHlyC.js → thread-ownership-DZeuKH1j.js} +2 -2
  51. package/dist/{thread-resume-CPrJNQVM.js → thread-resume-BE9qNEW0.js} +3 -3
  52. package/dist/{transcript-mirror-B9gGgnJS.js → transcript-mirror-DsCMWBca.js} +137 -38
  53. package/dist/{transport-stdio-DIImwDVS.js → transport-stdio-DhoGy33Z.js} +2 -2
  54. package/dist/{upstream-prompt-provenance-ClRBije0.js → upstream-prompt-provenance-CFmsKwr9.js} +12 -14
  55. package/dist/{upstream-session-fork-CE-_LdnP.js → upstream-session-fork-DlaHxSLC.js} +12 -6
  56. package/dist/{usage-CHlV0e-o.js → usage-ROIaW3wo.js} +3 -3
  57. package/dist/{web-search-provider.runtime-DRw2Vl42.js → web-search-provider.runtime-ClaNPV7N.js} +3 -3
  58. package/openclaw.plugin.json +49 -2
  59. package/package.json +9 -8
  60. package/dist/app-server-policy-zcBDc1JU.js +0 -49
@@ -1,42 +1,48 @@
1
- import { C as isCodexRemoteExecPlacementSandbox, E as resolveCodexPluginsPolicy, M as isCodexAppServerApprovalPolicyAllowedByRequirements, N as resolveOpenClawExecPolicyForCodexAppServer, S as withMcpElicitationsApprovalPolicy, T as readCodexPluginConfig, c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, h as resolveCodexAppServerHomeScope, i as createCodexSessionGenerationSupersededError, j as resolveCodexModelBackedReviewerPolicyContext, l as resolveCodexRunSessionBindingAuthority, u as scopeCodexRunBindingStore, v as resolveCodexComputerUseConfig, w as isCodexSandboxExecServerEnabled, x as shouldAutoApproveCodexAppServerApprovals } from "./session-binding-DPxIvMgE.js";
2
- import { $ as resolveCodexAppServerAuthProfileId, A as isCodexAppServerApprovalRequest, C as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, D as resolveCodexTurnTerminalIdleTimeoutMs, E as resolveCodexTurnCompletionIdleTimeoutMs, G as protectCodexAppServerLiveThread, H as ensureCodexAppServerClientRuntime, I as isCodexAppServerRequestTimeoutError, M as isCodexAppServerConnectionClosedError, N as isCodexAppServerIndeterminateRequestCancellationError, O as withCodexStartupTimeout, P as isCodexAppServerIndeterminateTransportError, Q as resolveCodexAppServerAuthAccountCacheKey, R as resolveCodexAppServerClientInstanceId, T as resolveCodexTurnAssistantCompletionIdleTimeoutMs, X as readRecentCodexRateLimits, Y as readCodexRateLimitsRevision, Z as rememberCodexRateLimitsRead, a as getLeasedSharedCodexAppServerClient, b as CodexAppServerStartupError, ct as isJsonObject, et as resolveCodexAppServerAuthProfileIdForAgent, f as retainSharedCodexAppServerClientIfCurrent, g as withAbortableTimeout, j as isCodexAppServerBrokenPipeError, k as getCodexAppServerClientInstanceId, l as releaseLeasedSharedCodexAppServerClient, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, nt as resolveCodexAppServerPreparedApiKeyCacheKey, o as getSharedCodexAppServerClient, p as retireSharedCodexAppServerClientIfCurrent, q as retainCodexAppServerLiveThread, rt as resolveCodexAppServerPreparedAuthHandoff, s as isCodexAppServerStartSelectionChangedError, st as flattenCodexDynamicToolFunctions, t as clearSharedCodexAppServerClientIfCurrent, tt as resolveCodexAppServerFallbackApiKeyCacheKey, ut as resolveCodexAppServerHomeDir, w as resolveCodexStartupTimeoutMs, x as isCodexAppServerStartupError, y as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, z as CodexAppServerRpcError } from "./shared-client-kIBbGjk4.js";
3
- import { A as shouldSynthesizeToolProgressForItem, B as readNullableString, E as itemStatus, F as readItem, I as readItemString, N as readCodexErrorNotificationMessage, O as shouldClearTerminalPresentationForNativeItem, T as itemName, V as splitPlanText, a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, f as CODEX_APP_SERVER_NATIVE_TURN_WAIT_TIMEOUT_MS, g as readCodexNotificationThreadId, h as isCodexNotificationForTurn, j as extractRawAssistantText, l as retireCodexAppServerClientAfterTimedOutTurn, m as CodexProjectionDiagnostics, o as interruptCodexTurnAndWaitBestEffort, p as getCodexAppServerTurnRouter, r as CodexAppServerUnsafeSubscriptionError, t as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS, u as retireUnsafeCodexTurnClientBestEffort, z as readNonNegativeInteger } from "./attempt-client-cleanup-DMLXUfa8.js";
4
- import { C as readRawResponseToolCallId, E as updateActiveTurnItemIds, S as readNotificationItemId, T as updateActiveCompletionBlockerItemIds, _ as isReasoningItemCompletionNotification, a as codexExecutionToolName, b as isTerminalTurnStatus, c as isAssistantCompletionReleaseNotification, d as isNativeToolProgressNotification, f as isPendingOpenClawDynamicToolCompletionNotification, g as isRawToolOutputCompletionNotification, h as isRawReasoningCompletionNotification, l as isCodexTurnAbortMarkerNotification, m as isRawFunctionToolOutputCompletionNotification, o as describeNotificationActivity, p as isRawAssistantProgressNotification, r as projectCodexThreadUsageUpdate, s as isAssistantCommentaryCompletionNotification, t as CodexResponseCompletionProjection, u as isFileChangePatchUpdatedNotification, v as isReasoningProgressNotification, w as shouldDisarmAssistantCompletionIdleWatch, x as readCodexNotificationItem, y as isRetryableErrorNotification } from "./event-projector-usage-e5huIQWu.js";
5
- import { l as readCodexTurn, o as assertCodexTurnStartResponse, s as readCodexDynamicToolCallParams, u as readCodexTurnCompletedNotification } from "./protocol-validators-B4F7L8Rf.js";
6
- import { i as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-C3H2CVp6.js";
7
- import { A as resolveCodexDynamicToolsLoadingForRuntime, B as buildCodexPluginThreadConfigInputFingerprint, C as codexLegacyDynamicToolsFingerprint, D as isSystemAgentOnlyCodexDynamicToolAllowlist, F as projectContextEngineAssemblyForCodex, G as shouldBuildCodexPluginThreadConfig, I as resolveCodexContextEngineProjectionMaxChars, L as resolveCodexContextEngineProjectionReserveTokens, M as isContextEngineBindingCompatible, N as fitCodexProjectedContextForTurnStart, P as neutralizeCodexExplicitMentionSigils, R as buildCodexPluginAppsConfigPatchFromPolicyContext, S as codexDynamicToolsFingerprint, U as buildPluginAppPolicyContext, V as buildCodexPluginThreadConfigTimeoutFallback, W as mergeCodexThreadConfigs, Z as resolveRecoverableCodexPluginConfigKeys, _ as resolveCodexAppServerThreadModelSelection, a as isCodexAppServerProfilerEnabled, f as resolveCodexWebSearchPlan, i as startOrResumeThread, j as buildContextEngineBinding, n as buildTurnStartParams, p as buildDeveloperInstructions, r as buildCodexUserInput, t as buildTurnCollaborationMode, w as filterCodexDynamicTools, x as areCodexDynamicToolFingerprintsCompatible, z as buildCodexPluginThreadConfig } from "./thread-lifecycle-Bu1BTDXr.js";
1
+ import { C as resolveCodexModelBackedReviewerPolicyContext, D as readCodexRequirementsToml, d as withMcpElicitationsApprovalPolicy, f as isCodexPairedNodeRemoteExecPlacementSandbox, g as resolveCodexPluginsPolicy, h as readCodexPluginConfig, j as resolveOpenClawExecPolicyForCodexAppServer, m as isCodexSandboxExecServerEnabled, o as resolveCodexComputerUseConfig, p as isCodexRemoteExecPlacementSandbox, r as resolveCodexAppServerHomeScope, u as shouldAutoApproveCodexAppServerApprovals, x as canUseCodexModelBackedApprovalsReviewerForModel } from "./config-giW8X0QA.js";
2
+ import { A as resolveCodexTurnAssistantCompletionIdleTimeoutMs, E as isCodexAppServerStartupError, F as isCodexAppServerApprovalRequest, G as CodexAppServerRpcError, I as isCodexAppServerBrokenPipeError, K as createCodexElicitationResponse, L as isCodexAppServerConnectionClosedError, M as resolveCodexTurnTerminalIdleTimeoutMs, N as withCodexStartupTimeout, O as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, P as getCodexAppServerClientInstanceId, Q as protectCodexAppServerLiveThread, R as isCodexAppServerIndeterminateRequestCancellationError, T as CodexAppServerStartupError, U as resolveCodexAppServerClientInstanceId, V as isCodexAppServerRequestTimeoutError, Y as ensureCodexAppServerClientRuntime, _ as retireSharedCodexAppServerClientIfCurrent, _t as flattenCodexDynamicToolFunctions, a as createIsolatedCodexAppServerClient, at as readRecentCodexRateLimits, c as isCodexAppServerStartSelectionChangedError, ct as resolveCodexAppServerAuthAccountCacheKey, dt as resolveCodexAppServerFallbackApiKeyCacheKey, et as retainCodexAppServerLiveThread, ft as resolveCodexAppServerPreparedApiKeyCacheKey, g as retainSharedCodexAppServerClientIfCurrent, it as readCodexRateLimitsRevision, j as resolveCodexTurnCompletionIdleTimeoutMs, k as resolveCodexStartupTimeoutMs, lt as resolveCodexAppServerAuthProfileId, n as clearSharedCodexAppServerClientIfCurrent, nt as withAbortableTimeout, o as getLeasedSharedCodexAppServerClient, ot as rememberCodexRateLimitsRead, p as releaseLeasedSharedCodexAppServerClient, pt as resolveCodexAppServerPreparedAuthHandoff, r as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, s as getSharedCodexAppServerClient, u as readCodexAppServerClientDesktopGenerationFingerprint, ut as resolveCodexAppServerAuthProfileIdForAgent, vt as isJsonObject, w as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, xt as resolveCodexAppServerHomeDir, z as isCodexAppServerIndeterminateTransportError } from "./shared-client-DKz23hHY.js";
3
+ import { c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, i as createCodexSessionGenerationSupersededError, l as resolveCodexRunSessionBindingAuthority, u as scopeCodexRunBindingStore } from "./session-binding-Bcynfd-_.js";
4
+ import { A as shouldSynthesizeToolProgressForItem, B as readNullableString, E as itemStatus, F as readItem, I as readItemString, N as readCodexErrorNotificationMessage, O as shouldClearTerminalPresentationForNativeItem, T as itemName, V as splitPlanText, a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, f as CODEX_APP_SERVER_NATIVE_TURN_WAIT_TIMEOUT_MS, g as readCodexNotificationThreadId, h as isCodexNotificationForTurn, j as extractRawAssistantText, l as retireCodexAppServerClientAfterTimedOutTurn, m as CodexProjectionDiagnostics, o as interruptCodexTurnAndWaitBestEffort, p as getCodexAppServerTurnRouter, r as CodexAppServerUnsafeSubscriptionError, t as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS, u as retireUnsafeCodexTurnClientBestEffort, z as readNonNegativeInteger } from "./attempt-client-cleanup-bfsmcQ6m.js";
5
+ import { C as readRawResponseToolCallId, E as updateActiveTurnItemIds, S as readNotificationItemId, T as updateActiveCompletionBlockerItemIds, _ as isReasoningItemCompletionNotification, a as codexExecutionToolName, b as isTerminalTurnStatus, c as isAssistantCompletionReleaseNotification, d as isNativeToolProgressNotification, f as isPendingOpenClawDynamicToolCompletionNotification, g as isRawToolOutputCompletionNotification, h as isRawReasoningCompletionNotification, l as isCodexTurnAbortMarkerNotification, m as isRawFunctionToolOutputCompletionNotification, o as describeNotificationActivity, p as isRawAssistantProgressNotification, r as projectCodexThreadUsageUpdate, s as isAssistantCommentaryCompletionNotification, t as CodexResponseCompletionProjection, u as isFileChangePatchUpdatedNotification, v as isReasoningProgressNotification, w as shouldDisarmAssistantCompletionIdleWatch, x as readCodexNotificationItem, y as isRetryableErrorNotification } from "./event-projector-usage-Bk1I90Bg.js";
6
+ import { l as readCodexTurn, o as assertCodexTurnStartResponse, s as readCodexDynamicToolCallParams, u as readCodexTurnCompletedNotification } from "./protocol-validators-VeJxxJ0U.js";
7
+ import { n as buildCodexAppServerRuntimeFingerprint, o as defaultCodexAppInventoryCache, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-C1CAdfcP.js";
8
+ import { C as toCodexDynamicToolProgressResponse, Dt as resolveRecoverableCodexPluginConfigKeys, F as resolveCodexWebSearchPlan, I as buildDeveloperInstructions, J as areCodexDynamicToolFingerprintsCompatible, S as shouldReleaseTurnAfterTerminalDynamicTool, T as resolveCodexToolAbortTerminalReason, V as resolveCodexAppServerThreadModelSelection, X as codexLegacyDynamicToolsFingerprint, Y as codexDynamicToolsFingerprint, Z as filterCodexDynamicTools, _ as isDynamicToolTerminalDiagnosticEvent, _t as buildCodexPluginThreadConfigTimeoutFallback, a as isCodexAppServerProfilerEnabled, at as buildContextEngineBinding, b as resolveTerminalDynamicToolBatchAction, bt as mergeCodexThreadConfigs, c as buildCodexNativeHookRelayConfig, ct as fitCodexProjectedContextForTurnStart, d as emitCodexNativePreToolUseFailureDiagnostic, dt as resolveCodexContextEngineProjectionMaxChars, et as isMessageOnlyCodexSourceReply, f as resolveCodexNativeHookRelayEvents, ft as resolveCodexContextEngineProjectionReserveTokens, g as hasPendingDynamicToolTerminalDiagnostic, gt as buildCodexPluginThreadConfigInputFingerprint, h as handleDynamicToolCallWithTimeout, ht as buildCodexPluginThreadConfig, i as startOrResumeThread, it as resolveCodexDynamicToolsLoadingForRuntime, l as buildCodexNativeHookRelayDisabledConfig, lt as neutralizeCodexExplicitMentionSigils, m as scheduleCodexNativeHookRelayUnregister, mt as buildCodexPluginAppsConfigPatchFromPolicyContext, n as buildTurnStartParams, ot as isContextEngineBindingCompatible, p as resolveCodexNativeHookRelayTtlMs, pt as resolveCodexContinuityProjectionMaxChars, r as buildCodexUserInput, s as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, st as buildCodexContinuityCalibration, t as buildTurnCollaborationMode, tt as isSystemAgentOnlyCodexDynamicToolAllowlist, u as createCodexNativeHookRelay, ut as projectContextEngineAssemblyForCodex, v as isMatchingDynamicToolTerminalDiagnostic, w as toCodexDynamicToolProtocolResponse, x as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult, xt as shouldBuildCodexPluginThreadConfig, y as resolveDynamicToolCallTimeoutMs, yt as buildPluginAppPolicyContext } from "./thread-lifecycle-L7oEkTlq.js";
8
9
  import { t as isIncognitoSessionKey } from "./incognito-session-ET_ufDH-.js";
9
- import { i as readUpstreamUserText, n as attachUpstreamUserText, r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-ClRBije0.js";
10
- import { a as buildCodexUserPromptMessage, c as readCodexMirrorSourceFingerprint, i as mirrorPromptAtTurnStartBestEffort, l as serializeCodexMirrorSourceEvidence, n as createCodexAppServerUserMessagePersistenceNotifier, o as promptSnapshot, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-B9gGgnJS.js";
11
- import { t as CODEX_CONTROL_METHODS } from "./capabilities-CybGI1oz.js";
12
- import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-DZXmOL8-.js";
13
- import { r as formatCodexDisplayText } from "./command-formatters-B1AEz8ZA.js";
14
- import { n as resolveCodexAppServerForOpenClawToolPolicy, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-zcBDc1JU.js";
15
- import { n as resolveCodexBindingAppServerConnection } from "./binding-connection-I5Bo-AsX.js";
10
+ import { i as readUpstreamUserText, n as attachUpstreamUserText, r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-CFmsKwr9.js";
11
+ import { a as buildCodexUserPromptMessage, c as readCodexMirrorSourceFingerprint, i as mirrorPromptAtTurnStartBestEffort, l as serializeCodexMirrorSourceEvidence, n as createCodexAppServerUserMessagePersistenceNotifier, o as promptSnapshot, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-DsCMWBca.js";
12
+ import { t as CODEX_CONTROL_METHODS } from "./capabilities-BRMh0aIq.js";
13
+ import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-C5_D8Gmb.js";
14
+ import { r as formatCodexDisplayText } from "./command-formatters-DEsIufkt.js";
15
+ import { a as resolveCodexAppServerForModelProvider, i as resolveCodexSessionPermissionCwd, n as applyCodexSessionPermissionPolicy, r as resolveCodexEffectiveSessionPermissionPolicy } from "./session-permission-policy-BrNH1bjy.js";
16
+ import { n as resolveCodexBindingAppServerConnection } from "./binding-connection-BMvPX73o.js";
16
17
  import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-B4FfbcCg.js";
17
- import { t as resolveCodexLocalRuntimeAttribution } from "./local-runtime-attribution-B_2mnqhb.js";
18
- import { n as createAssistantMessage, r as createAssistantMirrorMessage, t as createAssistantCommentaryMessage } from "./event-projector-assistant-message-BwxV4d6N.js";
19
- import { a as CodexToolProgressProjection, c as isCodexCommandBearingToolCall, d as sanitizeCodexToolResponse, i as readCodexMirroredSessionHistoryMessages, l as resolveCodexToolProgressDetailMode, n as CodexEventProjection, o as shouldEmitTranscriptToolProgress, r as CodexToolTranscriptProjection, s as inferCodexDynamicToolMeta, t as codexNativeSubagentMonitorRuntime, u as sanitizeCodexToolArguments } from "./native-subagent-monitor-DyTGmTUx.js";
20
- import { A as buildCodexNativeHookRelayDisabledConfig, B as resolveDynamicToolCallTimeoutMs, C as shouldWarnCodexDynamicToolBuildStageSummary, E as CodexNativeToolLifecycleProjector, F as scheduleCodexNativeHookRelayUnregister, G as toCodexDynamicToolProtocolResponse, H as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult, I as handleDynamicToolCallWithTimeout, K as resolveCodexToolAbortTerminalReason, L as hasPendingDynamicToolTerminalDiagnostic, M as emitCodexNativePreToolUseFailureDiagnostic, N as resolveCodexNativeHookRelayEvents, O as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, P as resolveCodexNativeHookRelayTtlMs, R as isDynamicToolTerminalDiagnosticEvent, S as shouldRequireCodexSandboxExecServerEnvironment, T as readBoundedCodexRemoteWorkspaceFile, U as shouldReleaseTurnAfterTerminalDynamicTool, V as resolveTerminalDynamicToolBatchAction, W as toCodexDynamicToolProgressResponse, _ as resolveCodexAppServerHookChannelId, a as emitDynamicToolStartedDiagnostic, b as resolveCodexSandboxEnvironmentSelection, c as resolveCodexProviderWebSearchSupport, d as releaseCodexSandboxExecServerEnvironment, f as buildDynamicTools, g as resolveCodexAppServerExecutionCwd, h as formatCodexDynamicToolBuildStageSummary, i as emitDynamicToolErrorDiagnostic, j as createCodexNativeHookRelay, k as buildCodexNativeHookRelayConfig, m as disableCodexPluginThreadConfig, n as projectCodexExecutableDynamicTools, o as emitDynamicToolTerminalDiagnostic, p as createCodexDynamicToolBuildStageTracker, r as handleCodexAppServerElicitationRequest, s as handleCodexAppServerApprovalRequest, t as createCodexDynamicToolBridge, u as ensureCodexSandboxExecServerEnvironment, v as resolveCodexExternalSandboxPolicyForOpenClawSandbox, x as shouldEnableCodexAppServerNativeToolSurface, y as resolveCodexMessageToolProvider, z as isMatchingDynamicToolTerminalDiagnostic } from "./dynamic-tools-BVdyWkUD.js";
21
- import { a as runCodexComputerUseLiveTest, n as ensureCodexComputerUse, o as killStaleComputerUseMcpChildren, t as defaultCodexPluginMetadataCache } from "./plugin-metadata-cache-CNJPj4_b.js";
18
+ import { t as persistCodexContextCompactionActivity } from "./context-compaction-activity-BOeJf7yo.js";
19
+ import { i as createAssistantMirrorMessage, n as createAssistantCommentaryMessage, r as createAssistantMessage, t as createAssistantAsyncMessage } from "./event-projector-assistant-message-C5-Ds8mA.js";
20
+ import { a as readCodexMirroredSessionHistoryMessages, c as inferCodexDynamicToolMeta, d as sanitizeCodexToolArguments, f as sanitizeCodexToolResponse, i as CodexToolTranscriptProjection, l as isCodexCommandBearingToolCall, n as CodexEventProjection, o as CodexToolProgressProjection, r as emitCodexAgentEvent, s as shouldEmitTranscriptToolProgress, t as codexNativeSubagentMonitorRuntime, u as resolveCodexToolProgressDetailMode } from "./native-subagent-monitor-4Mfq2HDs.js";
21
+ import { C as shouldRequireCodexSandboxExecServerEnvironment, D as CodexNativeToolLifecycleProjector, E as readBoundedCodexRemoteWorkspaceFile, S as shouldEnableCodexAppServerNativeToolSurface, _ as resolveCodexAppServerHookChannelId, a as emitDynamicToolStartedDiagnostic, c as resolveCodexProviderWebSearchSupport, d as releaseCodexSandboxExecServerEnvironment, f as buildDynamicTools, g as resolveCodexAppServerExecutionCwd, h as formatCodexDynamicToolBuildStageSummary, i as emitDynamicToolErrorDiagnostic, m as disableCodexPluginThreadConfig, n as projectCodexExecutableDynamicTools, o as emitDynamicToolTerminalDiagnostic, p as createCodexDynamicToolBuildStageTracker, r as routeCodexAppServerElicitationRequest, s as handleCodexAppServerApprovalRequest, t as createCodexDynamicToolBridge, u as ensureCodexSandboxExecServerEnvironment, v as resolveCodexExternalSandboxPolicyForOpenClawSandbox, w as shouldWarnCodexDynamicToolBuildStageSummary, x as resolveCodexSandboxEnvironmentSelection, y as resolveCodexMessageToolProvider } from "./dynamic-tools-Dnlfa--w.js";
22
+ import { a as runCodexComputerUseLiveTest, n as ensureCodexComputerUse, t as defaultCodexPluginMetadataCache } from "./plugin-metadata-cache-CTCT3w5L.js";
22
23
  import { asBoolean, asFiniteNumber, asOptionalRecord, hasNonEmptyString, normalizeOptionalString, readNonBlankString, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
23
24
  import fs from "node:fs/promises";
24
25
  import path from "node:path";
25
26
  import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
26
27
  import { asDateTimestampMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
27
- import { AgentHarnessPreflightError, CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, agentHarnessAttemptTerminal, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildAgentHarnessUserInputAnswers, buildBootstrapContextForFiles, buildHarnessContextEngineRuntimeContext, buildWatchedSessionsHarnessContext, callGatewayTool, cancelPendingAgentQuestionForSession, claimPendingAgentQuestionAnswer, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, deliverAgentHarnessUserInputPrompt, embeddedAgentLog, emitAgentEvent, emptyAgentHarnessUserInputAnswers, formatErrorMessage, formatFastModeAutoProgressText, getAgentHarnessHookRunner, getBeforeToolCallPolicyDiagnosticState, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, prepareHarnessNativeMcpAppPreview, projectAgentHarnessTranscriptMessageForDisplay, resolveAgentDir, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessAfterCompactionHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessGatewayQuestion, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
28
+ import { AgentHarnessPreflightError, CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, agentHarnessAttemptTerminal, agentHarnessStructuredInput, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildBootstrapContextForFiles, buildEmbeddedForegroundPromptContext, buildHarnessContextEngineRuntimeContext, buildWatchedSessionsHarnessContext, callGatewayTool, cancelPendingAgentQuestionForSession, claimPendingAgentQuestionAnswer, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, embeddedAgentLog, emitAgentEvent, emptyAgentHarnessUserInputAnswers, formatErrorMessage, formatFastModeAutoProgressText, getAgentHarnessHookRunner, hasBeforeToolCallPolicy, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, prepareHarnessNativeMcpAppPreview, projectAgentHarnessTranscriptMessageForDisplay, resolveAgentDir, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessAfterCompactionHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
28
29
  import crypto, { createHash } from "node:crypto";
29
30
  import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
31
+ import { resolveAgentConfig as resolveAgentConfig$1 } from "openclaw/plugin-sdk/agent-scope-runtime";
30
32
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
31
33
  import { parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
32
- import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
34
+ import { truncateUtf16Safe, truncateUtf8Prefix } from "openclaw/plugin-sdk/text-utility-runtime";
35
+ import { isPathStrictlyInside, root } from "openclaw/plugin-sdk/file-access-runtime";
33
36
  import { captureFinalCodexCronCreatorToolAllowlist, materializeStaticMcpToolsForScheduledHarnessRun, resolveCodexMcpToolOverridesForAgent } from "openclaw/plugin-sdk/codex-mcp-projection";
34
37
  import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
38
+ import { Buffer as Buffer$1 } from "node:buffer";
39
+ import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
35
40
  import { prepareMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
41
+ import { isSilentReplyPayloadText } from "openclaw/plugin-sdk/reply-chunking";
36
42
  import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
37
43
  import { resolveGeneratedMediaMaxBytes } from "openclaw/plugin-sdk/media-generation-runtime";
38
44
  import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
39
- import { root } from "openclaw/plugin-sdk/file-access-runtime";
45
+ import { stripInvisibleUnicode } from "openclaw/plugin-sdk/web-content-extractor";
40
46
  import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
41
47
  //#region extensions/codex/src/app-server/attempt-steering.ts
42
48
  /**
@@ -173,10 +179,12 @@ function createCodexSteeringQueue(params) {
173
179
  acceptance: "open",
174
180
  text,
175
181
  images: options?.images,
182
+ isInboundUserMessage: options?.isInboundUserMessage,
176
183
  onQueueAccepted: options?.onQueueAccepted,
177
184
  resolve: resolveDelivery,
178
185
  reject: rejectDelivery,
179
- settled: false
186
+ settled: false,
187
+ userTurnTranscriptRecorder: options?.userTurnTranscriptRecorder
180
188
  };
181
189
  pendingMessages.add(item);
182
190
  return {
@@ -193,19 +201,6 @@ function createCodexSteeringQueue(params) {
193
201
  options?.onQueueAccepted?.(false);
194
202
  throw unavailableError;
195
203
  }
196
- const pendingUserInput = options?.isInboundUserMessage === true ? params.claimPendingUserInput() : void 0;
197
- if (pendingUserInput) {
198
- if (!options?.images?.length) {
199
- const answered = pendingUserInput.answer(text);
200
- options?.onQueueAccepted?.(answered);
201
- if (!answered) throw new Error("codex pending user input rejected the answer");
202
- return;
203
- }
204
- flushBatch().catch(() => void 0);
205
- const { item, delivery } = createPendingMessage(text, options);
206
- await Promise.all([enqueueSend([item]).finally(() => pendingUserInput.cancel()), delivery]);
207
- return;
208
- }
209
204
  const { item, delivery } = createPendingMessage(text, options);
210
205
  batchedMessages.push(item);
211
206
  clearBatchTimer();
@@ -221,8 +216,21 @@ function createCodexSteeringQueue(params) {
221
216
  const batch = dispatchedBatches.get(clientUserMessageId);
222
217
  if (!batch) return false;
223
218
  dispatchedBatches.delete(clientUserMessageId);
224
- for (const item of batch.items) resolveItem(item);
225
- return true;
219
+ for (const item of batch.items) reportItemAcceptance(item, true);
220
+ const resolveBatch = () => {
221
+ for (const item of batch.items) resolveItem(item);
222
+ return true;
223
+ };
224
+ const rejectBatch = (error) => {
225
+ for (const item of batch.items) rejectItem(item, error);
226
+ return true;
227
+ };
228
+ if (!params.beforeConfirmConsumed) return resolveBatch();
229
+ try {
230
+ return params.beforeConfirmConsumed(batch.items).then(resolveBatch, rejectBatch);
231
+ } catch (error) {
232
+ return rejectBatch(error);
233
+ }
226
234
  },
227
235
  sealAdmission: sealQueueAdmission,
228
236
  cancel: cancelQueue
@@ -244,6 +252,7 @@ var CodexAssistantProjection = class {
244
252
  this.assistantItemOrder = [];
245
253
  this.assistantTimestampByItem = /* @__PURE__ */ new Map();
246
254
  this.assistantPhaseByItem = /* @__PURE__ */ new Map();
255
+ this.assistantDeliveryByItem = /* @__PURE__ */ new Map();
247
256
  this.latestTerminalAssistantCandidateSuperseded = false;
248
257
  this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
249
258
  this.terminalAssistantCandidateEarlierActiveItemIds = /* @__PURE__ */ new Set();
@@ -253,6 +262,9 @@ var CodexAssistantProjection = class {
253
262
  this.rawPromotedAssistantItemIds = /* @__PURE__ */ new Set();
254
263
  this.assistantStarted = false;
255
264
  this.streamedPartialAssistantItemReplaceable = false;
265
+ this.persistableAssistantBarrier = 0;
266
+ this.persistedAssistantBoundary = false;
267
+ this.persistableAssistantBarrierItemIds = /* @__PURE__ */ new Set();
256
268
  }
257
269
  hasCompletedTerminalAssistantText(completedItemIds) {
258
270
  const latestCompletedItemId = this.latestCompletedTerminalAssistantItemId;
@@ -284,7 +296,8 @@ var CodexAssistantProjection = class {
284
296
  if (!delta) return;
285
297
  if (itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
286
298
  const isCommentary = this.isCommentaryAssistantItem(itemId);
287
- if (!isCommentary && itemId !== this.latestTerminalAssistantCandidateItemId) this.markTerminalAssistantCandidateSupersededBy();
299
+ const isAsync = this.isAsyncAssistantItem(itemId);
300
+ if (!isCommentary && !isAsync && itemId !== this.latestTerminalAssistantCandidateItemId) this.markTerminalAssistantCandidateSupersededBy();
288
301
  if (!this.assistantStarted) {
289
302
  this.assistantStarted = true;
290
303
  await this.params.onAssistantMessageStart?.();
@@ -292,6 +305,7 @@ var CodexAssistantProjection = class {
292
305
  this.rememberAssistantItem(itemId);
293
306
  const text = `${this.assistantTextByItem.get(itemId) ?? ""}${delta}`;
294
307
  this.assistantTextByItem.set(itemId, text);
308
+ if (isAsync) return;
295
309
  if (isCommentary) {
296
310
  this.emitCommentaryProgress({
297
311
  itemId,
@@ -322,23 +336,25 @@ var CodexAssistantProjection = class {
322
336
  if (knownFinalAnswer && !replaceable) await this.params.onPartialReply?.(streamPayload);
323
337
  }
324
338
  recordItemStarted(item, itemId) {
325
- if (item?.type === "agentMessage" && itemId && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
339
+ this.noteNativeWorkBarrier(item);
326
340
  this.rememberAssistantPhase(item);
341
+ if (item?.type === "agentMessage" && itemId && !this.isNonTerminalAssistantItem(itemId) && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
327
342
  if (item?.type === "agentMessage" && itemId) this.rememberAssistantItem(itemId);
328
- if (itemId && itemId !== this.latestTerminalAssistantCandidateItemId) {
343
+ if (itemId && !this.isNonTerminalAssistantItem(itemId) && itemId !== this.latestTerminalAssistantCandidateItemId) {
329
344
  this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
330
345
  if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
331
346
  }
332
347
  }
333
348
  recordItemCompleted(item, itemId, activeItemIds) {
334
- if (item?.type === "agentMessage" && itemId && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
335
- if (itemId) this.latestCompletedItemId = itemId;
349
+ this.noteNativeWorkBarrier(item);
336
350
  this.rememberAssistantPhase(item);
337
- if (item?.type === "agentMessage" && !this.isCommentaryAssistantItem(item.id)) {
351
+ if (item?.type === "agentMessage" && itemId && !this.isNonTerminalAssistantItem(itemId) && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
352
+ if (itemId && !this.isNonTerminalAssistantItem(itemId)) this.latestCompletedItemId = itemId;
353
+ if (item?.type === "agentMessage" && !this.isNonTerminalAssistantItem(item.id)) {
338
354
  this.latestCompletedTerminalAssistantItemId = item.id;
339
355
  this.markLatestTerminalAssistantCandidate(item.id, activeItemIds);
340
356
  this.pendingRawTerminalAssistantEchoItemId = item.id;
341
- } else if (itemId) {
357
+ } else if (itemId && !this.isNonTerminalAssistantItem(itemId)) {
342
358
  this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
343
359
  if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
344
360
  }
@@ -351,7 +367,8 @@ var CodexAssistantProjection = class {
351
367
  text: item.text
352
368
  });
353
369
  this.pendingRawCommentaryEchoes += 1;
354
- } else if (item.text && this.isFinalAnswerAssistantItem(item.id)) this.emitAnswerCandidate(item.id, "candidate");
370
+ } else if (item.text && !this.isAsyncAssistantItem(item.id) && this.isFinalAnswerAssistantItem(item.id)) this.emitAnswerCandidate(item.id, "candidate");
371
+ return this.createAsyncDelivery(item.id);
355
372
  }
356
373
  }
357
374
  recordSnapshotItem(item) {
@@ -359,6 +376,7 @@ var CodexAssistantProjection = class {
359
376
  if (item.type === "agentMessage" && typeof item.text === "string") {
360
377
  this.rememberAssistantItem(item.id);
361
378
  this.assistantTextByItem.set(item.id, item.text);
379
+ return this.createAsyncDelivery(item.id);
362
380
  }
363
381
  }
364
382
  handleRawResponseItemCompleted(item, activeItemIds) {
@@ -403,8 +421,15 @@ var CodexAssistantProjection = class {
403
421
  else this.markLatestTerminalAssistantCandidate(itemId, activeItemIds, { canReleaseAfterToolHandoff: isIdlessTerminalAssistantAfterCompletedWork });
404
422
  }
405
423
  collectAssistantTexts() {
406
- const finalText = this.resolveFinalAssistantTextItem()?.text;
407
- return finalText ? [finalText] : [];
424
+ const afterHandoff = this.collectPersistableAssistantTexts(this.persistableAssistantBarrier);
425
+ const audibleAfterHandoff = afterHandoff.filter((text) => !isSilentReplyPayloadText(text));
426
+ if (audibleAfterHandoff.length > 0) return audibleAfterHandoff;
427
+ if (afterHandoff.length > 0) return afterHandoff.slice(-1);
428
+ if (this.persistedAssistantBoundary) return [];
429
+ const recoveredAudible = this.collectPersistableAssistantTexts(0).filter((text) => !isSilentReplyPayloadText(text));
430
+ if (recoveredAudible.length > 0) return recoveredAudible.slice(-1);
431
+ const recovered = this.resolveFinalAssistantTextItem()?.text;
432
+ return recovered ? [recovered] : [];
408
433
  }
409
434
  collectCommentaryMessages() {
410
435
  return this.assistantItemOrder.flatMap((itemId) => {
@@ -418,6 +443,39 @@ var CodexAssistantProjection = class {
418
443
  }];
419
444
  });
420
445
  }
446
+ collectAsyncMessages() {
447
+ return this.assistantItemOrder.flatMap((itemId) => {
448
+ if (!this.isAsyncAssistantItem(itemId)) return [];
449
+ const text = this.assistantTextByItem.get(itemId)?.trim();
450
+ const timestamp = this.assistantTimestampByItem.get(itemId);
451
+ if (!text || timestamp === void 0) return [];
452
+ return [{
453
+ itemId,
454
+ message: createAssistantAsyncMessage(this.params, text, itemId, timestamp)
455
+ }];
456
+ });
457
+ }
458
+ createCompletedAssistantBoundaryMessage(completedItemIds, options) {
459
+ const itemId = this.latestCompletedTerminalAssistantItemId;
460
+ const text = itemId ? this.assistantTextByItem.get(itemId)?.trim() : void 0;
461
+ const itemIndex = itemId ? this.assistantItemOrder.indexOf(itemId) : -1;
462
+ if (!itemId || !completedItemIds.has(itemId) || itemIndex < this.persistableAssistantBarrier || !text || isSilentReplyPayloadText(text) || this.isToolProgressEchoText(itemId, text)) return;
463
+ const message = this.createAssistantMessage(text, options);
464
+ return {
465
+ itemId,
466
+ message: {
467
+ ...message,
468
+ timestamp: this.assistantTimestampByItem.get(itemId) ?? message.timestamp
469
+ }
470
+ };
471
+ }
472
+ markAssistantBoundaryPersisted(itemId) {
473
+ const index = this.assistantItemOrder.indexOf(itemId);
474
+ if (index >= 0) {
475
+ this.persistableAssistantBarrier = Math.max(this.persistableAssistantBarrier, index + 1);
476
+ this.persistedAssistantBoundary = true;
477
+ }
478
+ }
421
479
  finalizeAnswerCandidate(turn) {
422
480
  if (turn.status !== "completed") {
423
481
  this.supersedeVisibleAnswerCandidate();
@@ -427,7 +485,7 @@ var CodexAssistantProjection = class {
427
485
  const authoritativeIndex = turnItems.findLastIndex((item) => {
428
486
  if (item.type !== "agentMessage" || typeof item.text !== "string" || item.text.trim().length === 0) return false;
429
487
  const phase = readItemString(item, "phase");
430
- return phase === "final_answer" || phase === void 0;
488
+ return readItemString(item, "delivery") !== "async" && (phase === "final_answer" || phase === void 0);
431
489
  });
432
490
  const authoritative = authoritativeIndex >= 0 ? turnItems[authoritativeIndex] : void 0;
433
491
  if (turnItems.slice(authoritativeIndex + 1).some(shouldClearTerminalPresentationForNativeItem) || authoritative?.id === this.latestTerminalAssistantCandidateItemId && this.latestTerminalAssistantCandidateSuperseded) {
@@ -445,7 +503,7 @@ var CodexAssistantProjection = class {
445
503
  hasAssistantItemTextForSynthesis() {
446
504
  for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
447
505
  const itemId = this.assistantItemOrder[i];
448
- if (!itemId || this.assistantPhaseByItem.get(itemId) === "commentary") continue;
506
+ if (!itemId || this.isNonTerminalAssistantItem(itemId)) continue;
449
507
  const text = this.assistantTextByItem.get(itemId);
450
508
  if (text && text.length > 0) return true;
451
509
  }
@@ -454,7 +512,7 @@ var CodexAssistantProjection = class {
454
512
  createCurrentAttemptAssistantMessage(options) {
455
513
  for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
456
514
  const itemId = this.assistantItemOrder[i];
457
- if (!itemId || this.isCommentaryAssistantItem(itemId) || !this.assistantTextByItem.has(itemId)) continue;
515
+ if (!itemId || this.isNonTerminalAssistantItem(itemId) || !this.assistantTextByItem.has(itemId)) continue;
458
516
  const text = this.assistantTextByItem.get(itemId) ?? "";
459
517
  const normalizedText = text.trim();
460
518
  if (normalizedText && this.isToolProgressEchoText(itemId, normalizedText)) continue;
@@ -475,10 +533,18 @@ var CodexAssistantProjection = class {
475
533
  if (item?.type !== "agentMessage") return;
476
534
  const phase = readItemString(item, "phase");
477
535
  if (phase) this.assistantPhaseByItem.set(item.id, phase);
536
+ const delivery = readItemString(item, "delivery");
537
+ if (delivery) this.assistantDeliveryByItem.set(item.id, delivery);
478
538
  }
479
539
  isCommentaryAssistantItem(itemId) {
480
540
  return this.assistantPhaseByItem.get(itemId) === "commentary";
481
541
  }
542
+ isAsyncAssistantItem(itemId) {
543
+ return this.assistantDeliveryByItem.get(itemId) === "async";
544
+ }
545
+ isNonTerminalAssistantItem(itemId) {
546
+ return this.isCommentaryAssistantItem(itemId) || this.isAsyncAssistantItem(itemId);
547
+ }
482
548
  isFinalAnswerAssistantItem(itemId) {
483
549
  return this.assistantPhaseByItem.get(itemId) === "final_answer";
484
550
  }
@@ -486,7 +552,7 @@ var CodexAssistantProjection = class {
486
552
  return this.assistantPhaseByItem.get(itemId) === "final_answer";
487
553
  }
488
554
  emitCommentaryProgress(params) {
489
- const progressText = params.text.replace(/\s+/g, " ").trim();
555
+ const progressText = params.text.trim();
490
556
  if (!progressText || this.lastCommentaryProgressTextByItem.get(params.itemId) === progressText) return;
491
557
  this.lastCommentaryProgressTextByItem.set(params.itemId, progressText);
492
558
  this.emitAgentEvent({
@@ -553,22 +619,98 @@ var CodexAssistantProjection = class {
553
619
  const itemId = this.assistantItemOrder[i];
554
620
  if (!itemId) continue;
555
621
  const text = this.assistantTextByItem.get(itemId)?.trim();
556
- if (this.assistantPhaseByItem.get(itemId) === "commentary") continue;
622
+ if (this.isNonTerminalAssistantItem(itemId)) continue;
557
623
  if (text && !this.isToolProgressEchoText(itemId, text)) return {
558
624
  itemId,
559
625
  text
560
626
  };
561
627
  }
562
628
  }
629
+ collectPersistableAssistantTexts(minIndex) {
630
+ let texts = [];
631
+ let replaceable = false;
632
+ for (let index = minIndex; index < this.assistantItemOrder.length; index += 1) {
633
+ const itemId = this.assistantItemOrder[index];
634
+ if (!itemId || this.isNonTerminalAssistantItem(itemId)) continue;
635
+ const text = this.assistantTextByItem.get(itemId)?.trim();
636
+ if (!text || this.isToolProgressEchoText(itemId, text)) continue;
637
+ if (isSilentReplyPayloadText(text)) {
638
+ texts.push(text);
639
+ continue;
640
+ }
641
+ const isTerminalFinal = this.assistantPhaseByItem.get(itemId) === "final_answer";
642
+ if (!isTerminalFinal || replaceable) {
643
+ texts = [text];
644
+ replaceable = !isTerminalFinal;
645
+ continue;
646
+ }
647
+ texts.push(text);
648
+ }
649
+ return texts;
650
+ }
651
+ noteNativeWorkBarrier(item) {
652
+ if (!item || !shouldAdvancePersistableAssistantBarrier(item)) return;
653
+ if (item.id && this.persistableAssistantBarrierItemIds.has(item.id)) return;
654
+ if (item.id) this.persistableAssistantBarrierItemIds.add(item.id);
655
+ this.persistableAssistantBarrier = this.assistantItemOrder.length;
656
+ }
563
657
  rememberAssistantItem(itemId) {
564
658
  if (!itemId || this.assistantItemOrder.includes(itemId)) return;
565
659
  this.assistantItemOrder.push(itemId);
566
660
  this.assistantTimestampByItem.set(itemId, this.nextTranscriptTimestamp());
567
661
  }
662
+ createAsyncDelivery(itemId) {
663
+ if (!this.isAsyncAssistantItem(itemId)) return;
664
+ const text = this.assistantTextByItem.get(itemId);
665
+ const timestamp = this.assistantTimestampByItem.get(itemId);
666
+ if (!text?.trim() || timestamp === void 0) return;
667
+ return {
668
+ itemId,
669
+ message: createAssistantAsyncMessage(this.params, text, itemId, timestamp),
670
+ text
671
+ };
672
+ }
568
673
  isToolProgressEchoText(itemId, text) {
569
674
  return this.rawPromotedAssistantItemIds.has(itemId) && this.matchesToolProgressEcho(text);
570
675
  }
571
676
  };
677
+ function shouldAdvancePersistableAssistantBarrier(item) {
678
+ return shouldClearTerminalPresentationForNativeItem(item) || item.type === "dynamicToolCall" || item.type === "sleep";
679
+ }
680
+ //#endregion
681
+ //#region extensions/codex/src/app-server/event-projector-async-delivery.ts
682
+ /** Owns authorization, exactly-once settlement, and terminal retry for async user messages. */
683
+ var CodexAsyncDeliveryProjection = class {
684
+ constructor(params, threadId, turnId, options) {
685
+ this.params = params;
686
+ this.threadId = threadId;
687
+ this.turnId = turnId;
688
+ this.options = options;
689
+ this.settledItemIds = /* @__PURE__ */ new Set();
690
+ this.pendingDeliveries = /* @__PURE__ */ new Map();
691
+ }
692
+ allows(item, reportUnauthorized = false) {
693
+ if (item?.type !== "agentMessage" || item.delivery !== "async") return true;
694
+ const allowed = this.params.disableTools !== true && (this.options.asyncUserMessageAllowed ?? (this.params.toolsAllow === void 0 || this.params.toolsAllow.some((name) => name === "*" || name === "message")));
695
+ if (!allowed && reportUnauthorized) embeddedAgentLog.warn("blocked unauthorized codex async user message", {
696
+ itemId: item.id,
697
+ threadId: this.threadId,
698
+ turnId: this.turnId
699
+ });
700
+ return allowed;
701
+ }
702
+ pending() {
703
+ return [...this.pendingDeliveries.values()];
704
+ }
705
+ async deliver(delivery) {
706
+ if (this.settledItemIds.has(delivery.itemId)) return;
707
+ const settlement = await this.options.onAsyncDelivery?.(delivery);
708
+ if (settlement === "settled") {
709
+ this.settledItemIds.add(delivery.itemId);
710
+ this.pendingDeliveries.delete(delivery.itemId);
711
+ } else if (settlement === "retry") this.pendingDeliveries.set(delivery.itemId, delivery);
712
+ }
713
+ };
572
714
  //#endregion
573
715
  //#region extensions/codex/src/app-server/event-projector-media.ts
574
716
  const GENERATED_IMAGE_MEDIA_SUBDIR = "tool-image-generation";
@@ -739,9 +881,10 @@ function isBase64WhitespaceCode(code) {
739
881
  //#endregion
740
882
  //#region extensions/codex/src/app-server/event-projector-reasoning.ts
741
883
  var CodexReasoningProjection = class {
742
- constructor(params, emitAgentEvent) {
884
+ constructor(params, emitAgentEvent, onNativePlanUpdate) {
743
885
  this.params = params;
744
886
  this.emitAgentEvent = emitAgentEvent;
887
+ this.onNativePlanUpdate = onNativePlanUpdate;
745
888
  this.reasoningTextByGroup = /* @__PURE__ */ new Map();
746
889
  this.reasoningItemOrder = /* @__PURE__ */ new Map();
747
890
  this.planTextByItem = /* @__PURE__ */ new Map();
@@ -782,7 +925,7 @@ var CodexReasoningProjection = class {
782
925
  }))
783
926
  });
784
927
  }
785
- handleTurnPlanUpdated(params, source = "codex-app-server") {
928
+ async handleTurnPlanUpdated(params, source = "codex-app-server") {
786
929
  const explanation = readNullableString(params, "explanation");
787
930
  const plan = Array.isArray(params.plan) ? params.plan.flatMap((entry) => {
788
931
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [];
@@ -796,6 +939,10 @@ var CodexReasoningProjection = class {
796
939
  }) : void 0;
797
940
  const planText = [explanation, ...(plan ?? []).map(({ step, status }) => `- [${status}] ${step}`)].filter((part) => Boolean(part)).join("\n");
798
941
  if (planText) this.turnPlanText = planText;
942
+ if (source === "codex-app-server" && plan) await this.onNativePlanUpdate?.({
943
+ ...typeof explanation === "string" ? { markdown: explanation } : {},
944
+ steps: plan
945
+ });
799
946
  this.emitPlanUpdate({
800
947
  explanation,
801
948
  steps: plan
@@ -825,7 +972,7 @@ var CodexReasoningProjection = class {
825
972
  return this.turnPlanText ?? [...this.planTextByItem.values()].filter((text) => text.trim().length > 0).join("\n\n");
826
973
  }
827
974
  emitPlanUpdate(params, source = "codex-app-server") {
828
- if (!params.explanation && (!params.steps || params.steps.length === 0)) return;
975
+ if (!params.explanation && params.steps === void 0) return;
829
976
  this.emitAgentEvent({
830
977
  stream: "plan",
831
978
  data: {
@@ -833,7 +980,7 @@ var CodexReasoningProjection = class {
833
980
  title: "Plan updated",
834
981
  source,
835
982
  ...params.explanation ? { explanation: params.explanation } : {},
836
- ...params.steps && params.steps.length > 0 ? { steps: params.steps } : {}
983
+ ...params.steps ? { steps: params.steps } : {}
837
984
  }
838
985
  });
839
986
  }
@@ -858,9 +1005,9 @@ function reasoningMethodOrder(method) {
858
1005
  const attemptTerminal = agentHarnessAttemptTerminal;
859
1006
  //#endregion
860
1007
  //#region extensions/codex/src/app-server/event-projector-snapshot.ts
1008
+ const CODEX_META_KEY$1 = "__openclaw";
861
1009
  function readTurnTaintMetadata(message) {
862
- const metadata = message["__openclaw"];
863
- return metadata && typeof metadata === "object" && !Array.isArray(metadata) ? metadata : void 0;
1010
+ return asOptionalRecord(CODEX_META_KEY$1 in message ? message[CODEX_META_KEY$1] : void 0);
864
1011
  }
865
1012
  function applyStickyTurnTaint(messages) {
866
1013
  let tainted = false;
@@ -883,25 +1030,59 @@ function applyStickyTurnTaint(messages) {
883
1030
  function buildCodexMessagesSnapshot(params) {
884
1031
  const messages = promptSnapshot(params.runParams, params.turnId, params.upstreamUserText);
885
1032
  if (params.reasoningText) messages.push(attachCodexMirrorIdentity(params.createAssistantMirrorMessage("Codex reasoning", params.reasoningText), `${params.turnId}:reasoning`));
886
- if (params.planText) messages.push(attachCodexMirrorIdentity(params.createAssistantMirrorMessage("Codex plan", params.planText), `${params.turnId}:plan`));
887
- const visibleWorkMessages = [...params.runParams.config?.ui?.prefs?.chatPersistCommentary === false ? [] : params.commentaryMessages.map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:commentary:${itemId}`)), ...params.toolMessages].toSorted((left, right) => (asDateTimestampMs(left.timestamp) ?? 0) - (asDateTimestampMs(right.timestamp) ?? 0));
1033
+ const commentaryMessages = params.runParams.config?.ui?.prefs?.chatPersistCommentary === false ? [] : params.commentaryMessages.map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:commentary:${itemId}`));
1034
+ const asyncMessages = params.asyncMessages.map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:async:${itemId}`));
1035
+ const visibleWorkMessages = [
1036
+ ...commentaryMessages,
1037
+ ...asyncMessages,
1038
+ ...params.toolMessages
1039
+ ].toSorted((left, right) => (asDateTimestampMs(left.timestamp) ?? 0) - (asDateTimestampMs(right.timestamp) ?? 0));
888
1040
  messages.push(...visibleWorkMessages);
889
- if (params.lastAssistant) messages.push(attachCodexMirrorIdentity(params.lastAssistant, `${params.turnId}:assistant`));
1041
+ if (params.lastAssistant) messages.push(attachCodexMirrorIdentity(params.lastAssistant, params.lastAssistantIdentity ?? `${params.turnId}:assistant`));
890
1042
  return applyStickyTurnTaint(messages).map((message) => projectAgentHarnessTranscriptMessageForDisplay({
891
1043
  hidden: params.runParams.trigger === "memory",
892
1044
  message
893
1045
  }));
894
1046
  }
1047
+ function buildCodexSteeringMessagesSnapshot(params) {
1048
+ const asyncMessages = params.assistantProjection.collectAsyncMessages().filter(({ itemId }) => params.completedItemIds.has(itemId));
1049
+ const commentaryMessages = params.assistantProjection.collectCommentaryMessages().filter(({ itemId }) => params.completedItemIds.has(itemId));
1050
+ const assistantBoundary = params.assistantProjection.createCompletedAssistantBoundaryMessage(params.completedItemIds, {
1051
+ tokenUsage: void 0,
1052
+ aborted: false,
1053
+ promptError: void 0
1054
+ });
1055
+ return {
1056
+ messages: buildCodexMessagesSnapshot({
1057
+ runParams: params.runParams,
1058
+ turnId: params.turnId,
1059
+ upstreamUserText: params.upstreamUserText,
1060
+ reasoningText: void 0,
1061
+ asyncMessages,
1062
+ commentaryMessages,
1063
+ toolMessages: params.toolMessages,
1064
+ lastAssistant: assistantBoundary?.message,
1065
+ ...assistantBoundary ? { lastAssistantIdentity: `${params.turnId}:assistant:${assistantBoundary.itemId}` } : {},
1066
+ createAssistantMirrorMessage: (title, text) => params.assistantProjection.createAssistantMirrorMessage(title, text)
1067
+ }).filter((message) => message.role !== "user"),
1068
+ ...assistantBoundary ? { assistantBoundaryItemId: assistantBoundary.itemId } : {}
1069
+ };
1070
+ }
895
1071
  //#endregion
896
1072
  //#region extensions/codex/src/app-server/event-projector-result.ts
897
1073
  function buildCodexAttemptResult(input) {
898
1074
  input.nativeToolLifecycleProjection.finalizeActive();
899
1075
  const assistantTexts = input.assistantProjection.collectAssistantTexts();
1076
+ const asyncMessages = input.assistantProjection.collectAsyncMessages();
900
1077
  const commentaryMessages = input.assistantProjection.collectCommentaryMessages();
901
1078
  const reasoningText = input.reasoningProjection.reasoningText();
902
1079
  const planText = input.reasoningProjection.planText();
903
- const completedUsage = input.responseCompletions.usage ?? input.tokenUsage;
904
- const projectedUsage = input.aborted ? input.tokenUsage : completedUsage;
1080
+ const unavailableThreadUsage = input.tokenUsage ? {
1081
+ ...input.tokenUsage,
1082
+ contextUsage: { state: "unavailable" }
1083
+ } : void 0;
1084
+ const completedUsage = input.responseCompletions.usage ?? (input.responseCompletions.modelIterations > 0 ? unavailableThreadUsage : input.tokenUsage);
1085
+ const projectedUsage = input.aborted ? unavailableThreadUsage : completedUsage;
905
1086
  const hasAssistantItemText = input.assistantProjection.hasAssistantItemTextForSynthesis();
906
1087
  const legacyFailClosed = !input.completedTurn || input.completedTurn.status !== "completed" || hasAssistantItemText;
907
1088
  const hasDeliverableAssistantOnCompletedTurn = input.completedTurn?.status === "completed" && assistantTexts.some((text) => text.trim().length > 0);
@@ -927,7 +1108,7 @@ function buildCodexAttemptResult(input) {
927
1108
  turnId: input.turnId,
928
1109
  upstreamUserText: input.upstreamUserText,
929
1110
  reasoningText,
930
- planText,
1111
+ asyncMessages,
931
1112
  commentaryMessages,
932
1113
  toolMessages: input.toolTranscriptProjection.transcriptMessages,
933
1114
  lastAssistant,
@@ -976,6 +1157,7 @@ function buildCodexAttemptResult(input) {
976
1157
  acceptedSessionSpawns: input.toolTelemetry.acceptedSessionSpawns,
977
1158
  cloudCodeAssistFormatError: false,
978
1159
  contextTokens: input.contextTokens,
1160
+ contextTokensSource: input.contextTokensSource,
979
1161
  attemptUsage: projectedUsage,
980
1162
  ...input.completedCompactionCount > 0 ? { compactionCount: input.completedCompactionCount } : {},
981
1163
  replayMetadata: {
@@ -1147,7 +1329,9 @@ var CodexAppServerEventProjector = class {
1147
1329
  this.responseCompletions = new CodexResponseCompletionProjection();
1148
1330
  this.completedCompactionCount = 0;
1149
1331
  this.lastTranscriptTimestamp = 0;
1332
+ this.asyncDeliveryProjection = new CodexAsyncDeliveryProjection(params, threadId, turnId, options);
1150
1333
  this.contextTokens = options.initialContextTokens;
1334
+ this.contextTokensSource = options.initialContextTokens === void 0 ? void 0 : "resolved";
1151
1335
  this.diagnostics = new CodexProjectionDiagnostics(threadId, turnId);
1152
1336
  this.nativeToolLifecycleProjector = new CodexNativeToolLifecycleProjector(params, threadId, turnId, { runAbortSignal: options.runAbortSignal });
1153
1337
  this.generatedMediaProjection = new CodexGeneratedMediaProjection(params.config, {
@@ -1164,7 +1348,7 @@ var CodexAppServerEventProjector = class {
1164
1348
  });
1165
1349
  this.eventProjection = new CodexEventProjection(threadId, turnId, (event) => this.emitAgentEvent(event), this.toolProgressProjection, this.toolTranscriptProjection, options.onNativeToolResultRecorded);
1166
1350
  this.assistantProjection = new CodexAssistantProjection(params, (event) => this.emitAgentEvent(event), (text) => this.toolProgressProjection.matchesEcho(text), () => this.nextTranscriptTimestamp());
1167
- this.reasoningProjection = new CodexReasoningProjection(params, (event) => this.emitAgentEvent(event));
1351
+ this.reasoningProjection = new CodexReasoningProjection(params, (event) => this.emitAgentEvent(event), options.onNativePlanUpdate);
1168
1352
  }
1169
1353
  nextTranscriptTimestamp() {
1170
1354
  this.lastTranscriptTimestamp = Math.max(Date.now(), this.lastTranscriptTimestamp + 1);
@@ -1173,6 +1357,25 @@ var CodexAppServerEventProjector = class {
1173
1357
  getCompletedTurnStatus() {
1174
1358
  return this.completedTurn?.status;
1175
1359
  }
1360
+ buildSteeringTranscriptPrefix() {
1361
+ const snapshot = buildCodexSteeringMessagesSnapshot({
1362
+ runParams: this.params,
1363
+ turnId: this.turnId,
1364
+ upstreamUserText: this.options.upstreamUserText,
1365
+ completedItemIds: this.completedItemIds,
1366
+ assistantProjection: this.assistantProjection,
1367
+ toolMessages: this.toolTranscriptProjection.transcriptMessages
1368
+ });
1369
+ this.pendingSteeringAssistantBoundaryItemId = snapshot.assistantBoundaryItemId;
1370
+ return snapshot.messages;
1371
+ }
1372
+ markSteeringTranscriptPersisted() {
1373
+ const itemId = this.pendingSteeringAssistantBoundaryItemId;
1374
+ if (itemId) {
1375
+ this.assistantProjection.markAssistantBoundaryPersisted(itemId);
1376
+ this.pendingSteeringAssistantBoundaryItemId = void 0;
1377
+ }
1378
+ }
1176
1379
  hasCompletedTerminalAssistantText() {
1177
1380
  return this.assistantProjection.hasCompletedTerminalAssistantText(this.completedItemIds);
1178
1381
  }
@@ -1199,8 +1402,9 @@ var CodexAppServerEventProjector = class {
1199
1402
  const ordinal = this.params.allocateToolOutcomeOrdinal?.(item.id);
1200
1403
  if (ordinal !== void 0) this.nativeToolOutcomeOrdinals.set(item.id, ordinal);
1201
1404
  }
1202
- recordNativeToolApprovalFailure(toolCallId, disposition) {
1405
+ recordNativeToolApprovalFailure(toolCallId, disposition, approvalKind) {
1203
1406
  this.nativeToolLifecycleProjector.recordApprovalFailureDisposition(toolCallId, disposition);
1407
+ if (disposition === "timed_out" && approvalKind) this.toolProgressProjection.approvalTimeoutKinds.set(toolCallId, approvalKind);
1204
1408
  }
1205
1409
  recordNativeToolPreToolUseFailure(failure) {
1206
1410
  this.nativeToolLifecycleProjector.recordPreToolUseFailure(failure);
@@ -1210,9 +1414,11 @@ var CodexAppServerEventProjector = class {
1210
1414
  if (!params) return;
1211
1415
  if (notification.method === "hook/started" || notification.method === "hook/completed") {
1212
1416
  if (!this.isHookNotificationForCurrentThread(params)) return;
1213
- } else if (notification.method === "guardianWarning") {
1214
- if (readCodexNotificationThreadId(params) !== this.threadId) return;
1417
+ } else if (notification.method === "guardianWarning" || notification.method === "warning" || notification.method === "configWarning") {
1418
+ const warningThreadId = readCodexNotificationThreadId(params);
1419
+ if (notification.method === "guardianWarning" && warningThreadId !== this.threadId || warningThreadId && warningThreadId !== this.threadId) return;
1215
1420
  } else if (!isCodexNotificationForTurn(params, this.threadId, this.turnId)) return;
1421
+ if (notification.method !== "guardianWarning" && notification.method !== "item/autoApprovalReview/started" && notification.method !== "item/autoApprovalReview/completed") this.eventProjection.flushPendingGuardianWarning();
1216
1422
  this.nativeToolLifecycleProjector.handleNotification(notification);
1217
1423
  this.assistantProjection.handleNotification(notification.method, params);
1218
1424
  switch (notification.method) {
@@ -1227,7 +1433,7 @@ var CodexAppServerEventProjector = class {
1227
1433
  this.reasoningProjection.handlePlanDelta(params);
1228
1434
  break;
1229
1435
  case "turn/plan/updated":
1230
- this.reasoningProjection.handleTurnPlanUpdated(params);
1436
+ await this.reasoningProjection.handleTurnPlanUpdated(params);
1231
1437
  break;
1232
1438
  case "item/started":
1233
1439
  await this.handleItemStarted(params);
@@ -1242,18 +1448,28 @@ var CodexAppServerEventProjector = class {
1242
1448
  case "item/autoApprovalReview/completed":
1243
1449
  this.eventProjection.handleGuardianReview(notification.method, params);
1244
1450
  break;
1451
+ case "autoApprovalReview/strictReviewRequired":
1452
+ this.eventProjection.handleStrictReviewRequired(params);
1453
+ break;
1245
1454
  case "guardianWarning":
1246
1455
  this.eventProjection.handleGuardianWarning(params);
1247
1456
  break;
1457
+ case "warning":
1458
+ case "configWarning":
1459
+ this.eventProjection.handleWarning(params);
1460
+ break;
1248
1461
  case "hook/started":
1249
1462
  case "hook/completed":
1250
1463
  this.eventProjection.handleHook(notification.method, params);
1251
1464
  break;
1252
1465
  case "thread/tokenUsage/updated":
1253
1466
  projectCodexThreadUsageUpdate(params, this.tokenUsage, (usage) => this.tokenUsage = usage, (data) => {
1254
- this.contextTokens = data.modelContextWindow ?? this.contextTokens;
1467
+ if (data.modelContextWindow !== void 0) {
1468
+ this.contextTokens = data.modelContextWindow;
1469
+ this.contextTokensSource = this.params.authoredContextTokenCap === void 0 ? "runtime" : "runtime-configured";
1470
+ }
1255
1471
  this.emitAgentEvent({
1256
- stream: "codex_app_server.usage",
1472
+ stream: "usage",
1257
1473
  data
1258
1474
  });
1259
1475
  });
@@ -1267,13 +1483,19 @@ var CodexAppServerEventProjector = class {
1267
1483
  case "rawResponseItem/completed":
1268
1484
  await this.handleRawResponseItemCompleted(params);
1269
1485
  break;
1270
- case "error":
1486
+ case "model/rerouted":
1487
+ this.eventProjection.handleModelRerouted(params);
1488
+ break;
1489
+ case "error": {
1271
1490
  this.responseCompletions.clear();
1272
1491
  if (params.willRetry === true) break;
1273
- this.settledTurnFailureFinalizationAllowed = (isJsonObject(params.error) ? params.error.codexErrorInfo : void 0) === "serverOverloaded";
1492
+ const codexErrorInfo = isJsonObject(params.error) ? params.error.codexErrorInfo : void 0;
1493
+ const compactionFailure = codexErrorInfo === "other" && this.isCompacting();
1494
+ this.settledTurnFailureFinalizationAllowed = codexErrorInfo === "serverOverloaded" || compactionFailure;
1274
1495
  this.promptError = this.formatCodexErrorMessage(params) ?? "codex app-server error";
1275
- this.promptErrorSource = "prompt";
1496
+ this.promptErrorSource = compactionFailure ? "compaction" : "prompt";
1276
1497
  break;
1498
+ }
1277
1499
  case "thread/compacted":
1278
1500
  case "turn/started":
1279
1501
  case "turn/diff/updated":
@@ -1282,7 +1504,6 @@ var CodexAppServerEventProjector = class {
1282
1504
  case "item/fileChange/outputDelta":
1283
1505
  case "item/fileChange/patchUpdated":
1284
1506
  case "item/mcpToolCall/progress":
1285
- case "model/rerouted":
1286
1507
  case "model/verification":
1287
1508
  case "turn/moderationMetadata":
1288
1509
  case "model/safetyBuffering/updated": break;
@@ -1292,6 +1513,7 @@ var CodexAppServerEventProjector = class {
1292
1513
  }
1293
1514
  }
1294
1515
  buildResult(toolTelemetry, options) {
1516
+ this.eventProjection.flushPendingGuardianWarning();
1295
1517
  return buildCodexAttemptResult({
1296
1518
  runParams: this.params,
1297
1519
  turnId: this.turnId,
@@ -1307,6 +1529,7 @@ var CodexAppServerEventProjector = class {
1307
1529
  aborted: this.aborted,
1308
1530
  tokenUsage: this.tokenUsage,
1309
1531
  contextTokens: this.contextTokens,
1532
+ contextTokensSource: this.contextTokensSource,
1310
1533
  completedCompactionCount: this.completedCompactionCount,
1311
1534
  activeItemCount: this.activeItemIds.size,
1312
1535
  completedItemCount: this.completedItemIds.size,
@@ -1325,9 +1548,12 @@ var CodexAppServerEventProjector = class {
1325
1548
  recordDynamicToolCall(params) {
1326
1549
  this.toolTranscriptProjection.recordDynamicToolCall(params);
1327
1550
  }
1328
- /** Projects a successful OpenClaw update_plan call through the native plan stream. */
1329
- recordDynamicPlanUpdate(params) {
1330
- if (isJsonObject(params)) this.reasoningProjection.handleTurnPlanUpdated(params, "openclaw");
1551
+ /** Projects a successful OpenClaw progress_card call through the native plan stream. */
1552
+ async recordDynamicProgressCardUpdate(params) {
1553
+ if (isJsonObject(params)) {
1554
+ const projected = { plan: Array.isArray(params.plan) ? params.plan : [] };
1555
+ await this.reasoningProjection.handleTurnPlanUpdated(projected, "openclaw");
1556
+ }
1331
1557
  }
1332
1558
  recordDynamicToolResult(params) {
1333
1559
  this.toolProgressProjection.recordDynamicToolResult(params);
@@ -1409,13 +1635,15 @@ var CodexAppServerEventProjector = class {
1409
1635
  this.activeItemIds.delete(itemId);
1410
1636
  this.completedItemIds.add(itemId);
1411
1637
  }
1412
- this.assistantProjection.recordItemCompleted(item, itemId, this.activeItemIds);
1638
+ if (!this.asyncDeliveryProjection.allows(item, true)) return;
1639
+ const asyncMessage = this.assistantProjection.recordItemCompleted(item, itemId, this.activeItemIds);
1640
+ if (asyncMessage) await this.asyncDeliveryProjection.deliver(asyncMessage);
1413
1641
  this.reasoningProjection.recordItem(item);
1414
1642
  await this.generatedMediaProjection.recordNative(item);
1415
1643
  if (item?.type === "contextCompaction" && itemId) {
1416
1644
  this.activeCompactionItemIds.delete(itemId);
1417
1645
  this.completedCompactionCount += 1;
1418
- this.options.onContextCompacted?.();
1646
+ await this.options.onContextCompacted?.();
1419
1647
  await runAgentHarnessAfterCompactionHook({
1420
1648
  sessionFile: this.params.sessionFile,
1421
1649
  messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
@@ -1431,17 +1659,17 @@ var CodexAppServerEventProjector = class {
1431
1659
  channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
1432
1660
  }
1433
1661
  });
1434
- this.emitAgentEvent({
1435
- stream: "compaction",
1436
- data: {
1437
- phase: "end",
1438
- backend: "codex-app-server",
1439
- completed: true,
1440
- threadId: this.threadId,
1441
- turnId: this.turnId,
1442
- itemId
1443
- }
1662
+ await persistCodexContextCompactionActivity({
1663
+ sessionTarget: this.params.sessionTarget,
1664
+ config: this.params.config,
1665
+ cwd: this.params.workspaceDir,
1666
+ runId: this.params.runId,
1667
+ threadId: this.threadId,
1668
+ turnId: this.turnId,
1669
+ itemId,
1670
+ timestamp: this.nextTranscriptTimestamp()
1444
1671
  });
1672
+ this.eventProjection.emitCompactionEnd(itemId, true);
1445
1673
  }
1446
1674
  this.toolProgressProjection.recordToolMeta(item);
1447
1675
  this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
@@ -1470,7 +1698,8 @@ var CodexAppServerEventProjector = class {
1470
1698
  const turn = readCodexTurn(params.turn);
1471
1699
  if (!turn || turn.id !== this.turnId) return;
1472
1700
  this.completedTurn = turn;
1473
- this.settledTurnFailureFinalizationAllowed = turn.status === "failed" && turn.error?.codexErrorInfo === "serverOverloaded";
1701
+ const compactionFailure = turn.status === "failed" && (this.promptErrorSource === "compaction" || turn.error?.codexErrorInfo === "other" && this.isCompacting());
1702
+ this.settledTurnFailureFinalizationAllowed = turn.status === "failed" && (turn.error?.codexErrorInfo === "serverOverloaded" || compactionFailure);
1474
1703
  if (turn.status !== "completed") this.responseCompletions.clear();
1475
1704
  if (turn.status === "failed") {
1476
1705
  const usageLimitMessage = formatCodexUsageLimitErrorMessage({
@@ -1479,9 +1708,18 @@ var CodexAppServerEventProjector = class {
1479
1708
  rateLimits: this.options.readRecentRateLimits?.()
1480
1709
  });
1481
1710
  this.promptError = usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : turn.error?.message ?? "codex app-server turn failed";
1482
- this.promptErrorSource = "prompt";
1711
+ this.promptErrorSource = compactionFailure ? "compaction" : "prompt";
1712
+ }
1713
+ if (compactionFailure) {
1714
+ const failedCompactionItemIds = [...this.activeCompactionItemIds];
1715
+ for (const itemId of failedCompactionItemIds) {
1716
+ this.activeItemIds.delete(itemId);
1717
+ this.activeCompactionItemIds.delete(itemId);
1718
+ this.eventProjection.emitCompactionEnd(itemId, false);
1719
+ }
1483
1720
  }
1484
1721
  const turnItems = turn.items ?? [];
1722
+ const unsettledAsyncDeliveries = this.asyncDeliveryProjection.pending();
1485
1723
  for (let index = turnItems.length - 1; index >= 0; index -= 1) {
1486
1724
  const item = turnItems[index];
1487
1725
  if (!item || !this.isCurrentTurnSnapshotItem(item)) continue;
@@ -1492,8 +1730,10 @@ var CodexAppServerEventProjector = class {
1492
1730
  }
1493
1731
  }
1494
1732
  for (const item of turnItems) {
1733
+ if (!this.asyncDeliveryProjection.allows(item)) continue;
1495
1734
  this.diagnostics.warnUnknownItemStatus(item);
1496
- this.assistantProjection.recordSnapshotItem(item);
1735
+ const asyncMessage = this.assistantProjection.recordSnapshotItem(item);
1736
+ if (asyncMessage) await this.asyncDeliveryProjection.deliver(asyncMessage);
1497
1737
  this.reasoningProjection.recordItem(item);
1498
1738
  await this.generatedMediaProjection.recordNative(item);
1499
1739
  this.toolProgressProjection.recordToolMeta(item);
@@ -1505,6 +1745,8 @@ var CodexAppServerEventProjector = class {
1505
1745
  this.toolProgressProjection.emitToolResultSummary(item);
1506
1746
  this.toolProgressProjection.emitToolResultOutput(item);
1507
1747
  }
1748
+ this.toolProgressProjection.approvalTimeoutKinds.clear();
1749
+ for (const delivery of unsettledAsyncDeliveries) await this.asyncDeliveryProjection.deliver(delivery);
1508
1750
  this.assistantProjection.finalizeAnswerCandidate(turn);
1509
1751
  this.activeCompactionItemIds.clear();
1510
1752
  await this.reasoningProjection.maybeEndReasoning();
@@ -1566,24 +1808,7 @@ var CodexAppServerEventProjector = class {
1566
1808
  return usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : readCodexErrorNotificationMessage(params);
1567
1809
  }
1568
1810
  emitAgentEvent(event) {
1569
- try {
1570
- emitAgentEvent({
1571
- runId: this.params.runId,
1572
- stream: event.stream,
1573
- data: event.data,
1574
- ...this.params.sessionKey ? { sessionKey: this.params.sessionKey } : {}
1575
- });
1576
- } catch (error) {
1577
- embeddedAgentLog.debug("codex app-server global agent event emit failed", { error });
1578
- }
1579
- try {
1580
- const maybePromise = this.params.onAgentEvent?.(event);
1581
- Promise.resolve(maybePromise).catch((error) => {
1582
- embeddedAgentLog.debug("codex app-server agent event handler rejected", { error });
1583
- });
1584
- } catch (error) {
1585
- embeddedAgentLog.debug("codex app-server agent event handler threw", { error });
1586
- }
1811
+ emitCodexAgentEvent(this.params, event);
1587
1812
  }
1588
1813
  isHookNotificationForCurrentThread(params) {
1589
1814
  const threadId = readStringField(params, "threadId");
@@ -1592,11 +1817,28 @@ var CodexAppServerEventProjector = class {
1592
1817
  }
1593
1818
  };
1594
1819
  //#endregion
1820
+ //#region extensions/codex/src/app-server/mcp-tool-metadata.ts
1821
+ /** Hosted app ownership is authoritative only on metadata supplied by Codex. */
1822
+ function readCodexMcpToolConnectorId(tool) {
1823
+ const metadata = asOptionalRecord(asOptionalRecord(tool)?.["_meta"]);
1824
+ return normalizeOptionalString(metadata?.connector_id) ?? normalizeOptionalString(metadata?.connectorId);
1825
+ }
1826
+ /** Preserve MCP App visibility so model-only tools cannot become widget authority. */
1827
+ function readCodexMcpToolUiVisibility(tool) {
1828
+ const visibility = asOptionalRecord(asOptionalRecord(asOptionalRecord(tool)?.["_meta"])?.ui)?.visibility;
1829
+ if (!Array.isArray(visibility)) return;
1830
+ return [...new Set(visibility.filter((value) => value === "app" || value === "model"))].toSorted();
1831
+ }
1832
+ //#endregion
1595
1833
  //#region extensions/codex/src/app-server/native-mcp-app.ts
1834
+ const CODEX_APPS_MCP_SERVER$1 = "codex_apps";
1596
1835
  function readMcpAppResourceUri(item) {
1597
1836
  const uri = normalizeOptionalString(asOptionalRecord(item.appContext)?.resourceUri) ?? normalizeOptionalString(item.mcpAppResourceUri);
1598
1837
  return uri?.startsWith("ui://") ? uri : void 0;
1599
1838
  }
1839
+ function readMcpAppConnectorId(item) {
1840
+ return normalizeOptionalString(asOptionalRecord(item.appContext)?.connectorId);
1841
+ }
1600
1842
  function readMcpToolResult(item) {
1601
1843
  const result = asOptionalRecord(item.result);
1602
1844
  if (!result || !Array.isArray(result.content)) return;
@@ -1634,13 +1876,16 @@ function createNativeMcpRuntime(params) {
1634
1876
  launchSummary: "Codex native MCP connection",
1635
1877
  toolCount: Object.keys(status.tools).length
1636
1878
  }])),
1637
- tools: loaded.flatMap((status) => statusTools(status).map((tool) => ({
1638
- serverName: status.name,
1639
- safeServerName: status.name,
1640
- toolName: String(tool.name),
1641
- inputSchema: asOptionalRecord(tool.inputSchema) ?? { type: "object" },
1642
- fallbackDescription: normalizeOptionalString(tool.description) ?? String(tool.name)
1643
- })))
1879
+ tools: loaded.flatMap((status) => statusTools(status).map((tool) => {
1880
+ const uiVisibility = readCodexMcpToolUiVisibility(tool);
1881
+ return Object.assign({
1882
+ serverName: status.name,
1883
+ safeServerName: status.name,
1884
+ toolName: String(tool.name),
1885
+ inputSchema: asOptionalRecord(tool.inputSchema) ?? { type: "object" },
1886
+ fallbackDescription: normalizeOptionalString(tool.description) ?? String(tool.name)
1887
+ }, uiVisibility ? { uiVisibility } : {});
1888
+ }))
1644
1889
  };
1645
1890
  return catalog;
1646
1891
  };
@@ -1668,11 +1913,18 @@ function createNativeMcpRuntime(params) {
1668
1913
  const status = (await loadStatuses()).find((entry) => entry.name === serverName);
1669
1914
  return { tools: status ? statusTools(status) : [] };
1670
1915
  },
1671
- readResource: async (serverName, uri) => await params.client.request("mcpServer/resource/read", {
1672
- threadId: params.threadId,
1673
- server: serverName,
1674
- uri
1675
- }),
1916
+ readResource: async (serverName, uri) => {
1917
+ const isCodexAppsServer = serverName === CODEX_APPS_MCP_SERVER$1;
1918
+ const response = await params.client.request("mcpServer/resource/read", {
1919
+ threadId: params.threadId,
1920
+ ...isCodexAppsServer ? { originCallId: params.originCallId } : {},
1921
+ server: serverName,
1922
+ uri,
1923
+ ...params.connectorId ? { connectorId: params.connectorId } : {}
1924
+ });
1925
+ if (isCodexAppsServer && response.originCallId !== params.originCallId) throw new Error(`Codex MCP resource response originCallId mismatch: expected ${params.originCallId}, received ${response.originCallId}`);
1926
+ return response;
1927
+ },
1676
1928
  listResources: async (serverName) => {
1677
1929
  return { resources: (await loadStatuses()).find((entry) => entry.name === serverName)?.resources ?? [] };
1678
1930
  },
@@ -1685,15 +1937,25 @@ function createNativeMcpRuntime(params) {
1685
1937
  }
1686
1938
  function createCodexNativeMcpAppResultDetailsPreparer(params) {
1687
1939
  if (params.attempt.config?.mcp?.apps?.enabled !== true) return;
1688
- const runtime = createNativeMcpRuntime(params);
1689
1940
  return async (item) => {
1690
1941
  const serverName = normalizeOptionalString(item.server);
1691
1942
  const toolName = normalizeOptionalString(item.tool);
1692
1943
  const uiResourceUri = readMcpAppResourceUri(item);
1944
+ const connectorId = readMcpAppConnectorId(item);
1693
1945
  const toolResult = readMcpToolResult(item);
1694
1946
  if (!serverName || !toolName || !uiResourceUri || !toolResult) return;
1695
- const allowedAppToolNames = new Set((await runtime.getCatalog()).tools.filter((tool) => tool.serverName === serverName).map((tool) => tool.toolName));
1696
- if (allowedAppToolNames.size === 0) return;
1947
+ if (serverName === CODEX_APPS_MCP_SERVER$1 && !connectorId) return;
1948
+ const runtime = createNativeMcpRuntime({
1949
+ ...params,
1950
+ originCallId: item.id,
1951
+ ...connectorId ? { connectorId } : {}
1952
+ });
1953
+ const tools = (await runtime.listTools?.(serverName))?.tools ?? [];
1954
+ const allowedAppToolNames = new Set(tools.filter((tool) => {
1955
+ const uiVisibility = readCodexMcpToolUiVisibility(tool);
1956
+ return (uiVisibility === void 0 || uiVisibility.includes("app")) && (serverName !== CODEX_APPS_MCP_SERVER$1 || readCodexMcpToolConnectorId(tool) === connectorId);
1957
+ }).map((tool) => tool.name));
1958
+ if (!allowedAppToolNames.has(toolName)) return;
1697
1959
  return await prepareHarnessNativeMcpAppPreview({
1698
1960
  runtime,
1699
1961
  serverName,
@@ -1708,184 +1970,347 @@ function createCodexNativeMcpAppResultDetailsPreparer(params) {
1708
1970
  };
1709
1971
  }
1710
1972
  //#endregion
1973
+ //#region extensions/codex/src/app-server/plan-compaction-state.ts
1974
+ const RESTORED_PLAN_PREAMBLE = "OpenClaw restored the session progress card after context compaction. This is application state, not a new user request. Continue the current task and call progress_card whenever the status meaningfully changes.";
1975
+ const PROGRESS_CARD_MAX_STEPS = 50;
1976
+ const PROGRESS_CARD_MAX_STEP_UTF8_BYTES = 512;
1977
+ const PROGRESS_CARD_MAX_UTF8_BYTES = 8 * 1024;
1978
+ const RESTORED_PLAN_MAX_MARKDOWN_BYTES = 2 * 1024;
1979
+ const RESTORED_PLAN_MAX_PAYLOAD_BYTES = 32 * 1024;
1980
+ const RESTORED_PLAN_TRUNCATION_SUFFIX = "…";
1981
+ function canonicalizeNativeProgressCardInput(input) {
1982
+ const markdown = input.markdown === void 0 ? void 0 : truncateUtf8(stripInvisibleUnicode(input.markdown), PROGRESS_CARD_MAX_UTF8_BYTES);
1983
+ const plan = [];
1984
+ let hasInProgressStep = false;
1985
+ for (const step of input.steps.slice(0, PROGRESS_CARD_MAX_STEPS)) {
1986
+ const text = truncateUtf8(stripInvisibleUnicode(step.step), PROGRESS_CARD_MAX_STEP_UTF8_BYTES);
1987
+ if (!text.trim()) continue;
1988
+ let status = step.status;
1989
+ if (status === "in_progress") if (hasInProgressStep) status = "pending";
1990
+ else hasInProgressStep = true;
1991
+ plan.push({
1992
+ step: text,
1993
+ status
1994
+ });
1995
+ }
1996
+ return {
1997
+ ...markdown !== void 0 ? { markdown } : {},
1998
+ plan
1999
+ };
2000
+ }
2001
+ /** Retains the latest projected plan so Codex compaction cannot discard it. */
2002
+ var CodexCompactionPlanState = class {
2003
+ record(event) {
2004
+ if (event.stream !== "plan") return;
2005
+ const plan = readBoundedPlan(event.data.explanation, event.data.steps);
2006
+ this.latestPlan = plan;
2007
+ }
2008
+ /** Retains markdown that migration-only plan events intentionally omit. */
2009
+ recordProgressCardInput(value) {
2010
+ if (!isJsonObject(value)) return;
2011
+ this.latestPlan = readBoundedPlan(value.markdown, value.plan);
2012
+ }
2013
+ async restore(params) {
2014
+ if (!this.latestPlan) return;
2015
+ await params.client.request("thread/inject_items", {
2016
+ threadId: params.threadId,
2017
+ items: [{
2018
+ type: "message",
2019
+ role: "user",
2020
+ content: [{
2021
+ type: "input_text",
2022
+ text: `${RESTORED_PLAN_PREAMBLE}\n${serializePlan(this.latestPlan)}`
2023
+ }]
2024
+ }]
2025
+ }, {
2026
+ timeoutMs: params.timeoutMs,
2027
+ signal: params.signal
2028
+ });
2029
+ }
2030
+ };
2031
+ function readBoundedPlan(markdownValue, stepsValue) {
2032
+ const canonical = canonicalizeNativeProgressCardInput({
2033
+ ...typeof markdownValue === "string" ? { markdown: markdownValue } : {},
2034
+ steps: readPlanSteps(stepsValue)
2035
+ });
2036
+ const markdown = canonical.markdown === void 0 ? void 0 : truncateUtf8(canonical.markdown, RESTORED_PLAN_MAX_MARKDOWN_BYTES);
2037
+ const steps = [];
2038
+ for (const step of canonical.plan) {
2039
+ const candidate = {
2040
+ ...markdown?.trim() ? { markdown } : {},
2041
+ steps: [...steps, step]
2042
+ };
2043
+ if (Buffer$1.byteLength(serializePlan(candidate), "utf8") > RESTORED_PLAN_MAX_PAYLOAD_BYTES) break;
2044
+ steps.push(step);
2045
+ }
2046
+ return markdown?.trim() || steps.length > 0 ? {
2047
+ ...markdown?.trim() ? { markdown } : {},
2048
+ steps
2049
+ } : void 0;
2050
+ }
2051
+ function serializePlan(plan) {
2052
+ return JSON.stringify({
2053
+ markdown: plan.markdown,
2054
+ plan: plan.steps
2055
+ });
2056
+ }
2057
+ function truncateUtf8(value, maxBytes) {
2058
+ if (Buffer$1.byteLength(value, "utf8") <= maxBytes) return value;
2059
+ return `${truncateUtf8Prefix(value, maxBytes - Buffer$1.byteLength(RESTORED_PLAN_TRUNCATION_SUFFIX, "utf8"))}${RESTORED_PLAN_TRUNCATION_SUFFIX}`;
2060
+ }
2061
+ function readPlanSteps(value) {
2062
+ if (!Array.isArray(value)) return [];
2063
+ return value.flatMap((entry) => {
2064
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [];
2065
+ const { step, status } = entry;
2066
+ if (typeof step !== "string" || !isPlanStatus(status)) return [];
2067
+ return [{
2068
+ step,
2069
+ status
2070
+ }];
2071
+ });
2072
+ }
2073
+ function isPlanStatus(value) {
2074
+ return value === "pending" || value === "in_progress" || value === "completed";
2075
+ }
2076
+ //#endregion
1711
2077
  //#region extensions/codex/src/app-server/user-input-bridge.ts
1712
- /** Bridges Codex request_user_input calls to gateway questions and secret text prompts. */
2078
+ /** Owns per-turn Codex request_user_input and ordinary MCP elicitation lifecycles. */
1713
2079
  const DEFAULT_USER_INPUT_TIMEOUT_MS = 15 * 6e4;
1714
2080
  const NONBLOCKING_USER_INPUT_TIMEOUT_MS = 12e4;
1715
- /** Creates a per-turn bridge for pending Codex user-input requests. */
2081
+ const MAX_USER_INPUT_QUESTIONS = 3;
2082
+ const MAX_USER_INPUT_OPTIONS = 4;
2083
+ const MAX_USER_INPUT_ID = 256;
2084
+ const MAX_USER_INPUT_HEADER = 64;
2085
+ const MAX_USER_INPUT_TEXT = 4096;
2086
+ /** Creates the single per-turn owner for Codex operator input. */
1716
2087
  function createCodexUserInputBridge(params) {
1717
- let sensitiveInput;
1718
- let pendingGateway;
1719
2088
  const gatewayCall = params.gatewayCall ?? callGatewayTool;
1720
- const resolveSecret = (value) => {
1721
- const current = sensitiveInput;
1722
- if (!current) return;
1723
- sensitiveInput = void 0;
1724
- current.cleanup();
1725
- current.resolve(value);
1726
- };
1727
- const resolveSecretIfCurrent = (current, value) => {
1728
- if (sensitiveInput !== current) return false;
1729
- resolveSecret(value);
1730
- return true;
2089
+ const jobs = [];
2090
+ let activeCompletion;
2091
+ const inputSessionKey = params.paramsForRun.sessionKey ?? params.paramsForRun.sessionId;
2092
+ const pump = () => {
2093
+ const job = jobs[0];
2094
+ if (activeCompletion || !job) return;
2095
+ activeCompletion = job.run(job.abort.signal).catch((error) => {
2096
+ embeddedAgentLog.warn("failed to bridge codex operator input", { error });
2097
+ return job.abort.signal.aborted ? job.cancelValue : job.failureValue;
2098
+ }).then((value) => {
2099
+ job.resolve(job.abort.signal.aborted ? job.cancelValue : value ?? job.failureValue);
2100
+ }).finally(() => {
2101
+ if (jobs[0] === job) jobs.shift();
2102
+ activeCompletion = void 0;
2103
+ pump();
2104
+ });
1731
2105
  };
1732
- const cancelGateway = () => {
1733
- pendingGateway?.abort.abort(/* @__PURE__ */ new Error("Codex user input request cancelled"));
2106
+ const enqueue = (definition) => {
2107
+ if (params.signal?.aborted) return Promise.resolve(definition.cancelValue);
2108
+ return new Promise((resolve) => {
2109
+ jobs.push({
2110
+ ...definition,
2111
+ resolve
2112
+ });
2113
+ pump();
2114
+ });
1734
2115
  };
2116
+ const cancelJob = (job) => {
2117
+ const index = jobs.indexOf(job);
2118
+ if (index < 0) return;
2119
+ if (index === 0) {
2120
+ job.abort.abort(/* @__PURE__ */ new Error("Codex operator input request cancelled"));
2121
+ return;
2122
+ }
2123
+ jobs.splice(index, 1);
2124
+ job.resolve(job.cancelValue);
2125
+ };
2126
+ const cancelPending = async () => {
2127
+ const pendingCompletion = activeCompletion;
2128
+ const queuedJobs = jobs.splice(1);
2129
+ for (const job of queuedJobs) job.resolve(job.cancelValue);
2130
+ jobs[0]?.abort.abort(/* @__PURE__ */ new Error("Codex operator input request cancelled"));
2131
+ await pendingCompletion;
2132
+ };
2133
+ const execute = (input, timeoutMs, signal) => agentHarnessStructuredInput.run({
2134
+ input,
2135
+ sessionKey: inputSessionKey,
2136
+ agentId: params.paramsForRun.agentId,
2137
+ runId: params.paramsForRun.runId,
2138
+ timeoutMs,
2139
+ gatewayCall,
2140
+ delivery: params.paramsForRun,
2141
+ signal,
2142
+ promptOptions: {
2143
+ formatText: formatCodexDisplayText,
2144
+ unsupportedIntro: "Codex input request could not be shown:",
2145
+ urlIntro: "Codex needs confirmation:"
2146
+ }
2147
+ });
2148
+ params.signal?.addEventListener("abort", () => void cancelPending(), { once: true });
1735
2149
  return {
1736
2150
  async handleRequest(request) {
1737
2151
  const requestParams = readUserInputParams(request.params);
1738
- if (!requestParams) return;
1739
- if (requestParams.threadId !== params.threadId || requestParams.turnId !== params.turnId) return;
2152
+ if (!requestParams || requestParams.threadId !== params.threadId || requestParams.turnId !== params.turnId) return;
1740
2153
  if (requestParams.questions.length === 0) return emptyUserInputResponse();
1741
- resolveSecret(emptyUserInputResponse());
1742
- cancelGateway();
1743
- if (requestParams.questions.some((question) => question.isSecret)) return new Promise((resolve) => {
1744
- const abortListener = () => resolveSecret(emptyUserInputResponse());
1745
- const timeout = requestParams.isBlocking ? void 0 : setTimeout(() => resolveSecret(emptyUserInputResponse()), NONBLOCKING_USER_INPUT_TIMEOUT_MS);
1746
- timeout?.unref?.();
1747
- const cleanup = () => {
1748
- params.signal?.removeEventListener("abort", abortListener);
1749
- if (timeout) clearTimeout(timeout);
1750
- };
1751
- const current = {
1752
- requestId: request.id,
1753
- threadId: requestParams.threadId,
1754
- questions: requestParams.questions,
1755
- claimed: false,
1756
- resolve,
1757
- cleanup
1758
- };
1759
- sensitiveInput = current;
1760
- params.signal?.addEventListener("abort", abortListener, { once: true });
1761
- if (params.signal?.aborted) {
1762
- resolveSecret(emptyUserInputResponse());
1763
- return;
2154
+ const timeoutMs = requestParams.isBlocking ? params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS : NONBLOCKING_USER_INPUT_TIMEOUT_MS;
2155
+ const input = compileUserInputQuestions(requestParams.questions);
2156
+ const cancelValue = emptyUserInputResponse();
2157
+ return await enqueue({
2158
+ requestId: request.id,
2159
+ abort: new AbortController(),
2160
+ cancelValue,
2161
+ failureValue: cancelValue,
2162
+ run: async (signal) => {
2163
+ const result = await execute(input, timeoutMs, signal);
2164
+ return result.status === "answered" ? gatewayAnswersToCodexResponse(result.answers) : cancelValue;
1764
2165
  }
1765
- deliverAgentHarnessUserInputPrompt(params.paramsForRun, requestParams.questions, {
1766
- formatText: formatCodexDisplayText,
1767
- intro: "Codex needs input:"
1768
- }).catch((error) => {
1769
- embeddedAgentLog.warn("failed to deliver secret codex user input prompt", { error });
1770
- resolveSecretIfCurrent(current, emptyUserInputResponse());
1771
- });
1772
2166
  });
1773
- const abort = new AbortController();
1774
- const abortFromRun = () => abort.abort(params.signal?.reason);
1775
- params.signal?.addEventListener("abort", abortFromRun, { once: true });
1776
- if (params.signal?.aborted) abortFromRun();
1777
- pendingGateway = {
1778
- requestId: request.id,
1779
- threadId: requestParams.threadId,
1780
- abort
1781
- };
1782
- try {
1783
- const result = await runAgentHarnessGatewayQuestion({
1784
- questions: requestParams.questions,
1785
- sessionKey: params.paramsForRun.sessionKey ?? params.paramsForRun.sessionId,
1786
- agentId: params.paramsForRun.agentId,
1787
- runId: params.paramsForRun.runId,
1788
- timeoutMs: requestParams.isBlocking ? params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS : NONBLOCKING_USER_INPUT_TIMEOUT_MS,
1789
- gatewayCall,
1790
- delivery: params.paramsForRun,
1791
- promptOptions: {
1792
- formatText: formatCodexDisplayText,
1793
- intro: "Codex needs input:"
1794
- },
1795
- signal: abort.signal
2167
+ },
2168
+ async handleElicitationRequest(request) {
2169
+ if (readRawOwnString(request.params, "threadId") !== params.threadId) return;
2170
+ const requestSnapshot = agentHarnessStructuredInput.snapshot(request.params);
2171
+ if (requestSnapshot === void 0) {
2172
+ const cancelValue = createCodexElicitationResponse("cancel");
2173
+ return await enqueue({
2174
+ requestId: request.id,
2175
+ abort: new AbortController(),
2176
+ cancelValue,
2177
+ failureValue: declineElicitation("OpenClaw could not handle this elicitation."),
2178
+ run: async (signal) => {
2179
+ const result = await execute({
2180
+ kind: "unsupported",
2181
+ message: "OpenClaw declined a malformed or over-limit MCP elicitation request."
2182
+ }, params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS, signal);
2183
+ return result.status === "unsupported" ? declineElicitation(result.message) : cancelValue;
2184
+ }
1796
2185
  });
1797
- return result.status === "answered" ? gatewayAnswersToCodexResponse(result.answers.answers) : emptyUserInputResponse();
1798
- } catch (error) {
1799
- embeddedAgentLog.warn("failed to bridge codex user input through gateway", { error });
1800
- return emptyUserInputResponse();
1801
- } finally {
1802
- params.signal?.removeEventListener("abort", abortFromRun);
1803
- if (pendingGateway?.abort === abort) pendingGateway = void 0;
1804
2186
  }
1805
- },
1806
- claimPendingRequest() {
1807
- const current = sensitiveInput;
1808
- if (!current || current.claimed) return;
1809
- current.claimed = true;
1810
- return {
1811
- answer: (text) => resolveSecretIfCurrent(current, buildUserInputResponse(current.questions, text)),
1812
- cancel: () => resolveSecretIfCurrent(current, emptyUserInputResponse())
1813
- };
2187
+ const { compileCodexOrdinaryElicitation } = await import("./elicitation-input-DMkeki8d.js");
2188
+ const compiled = compileCodexOrdinaryElicitation({
2189
+ value: requestSnapshot,
2190
+ threadId: params.threadId,
2191
+ turnId: params.turnId
2192
+ });
2193
+ if (compiled.kind === "ignored") return;
2194
+ const cancelValue = createCodexElicitationResponse("cancel");
2195
+ const timeoutMs = params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS;
2196
+ return await enqueue({
2197
+ requestId: request.id,
2198
+ abort: new AbortController(),
2199
+ cancelValue,
2200
+ failureValue: declineElicitation("OpenClaw could not handle this elicitation."),
2201
+ run: async (signal) => {
2202
+ const result = await execute(compiled.input, timeoutMs, signal);
2203
+ if (result.status === "answered") return createCodexElicitationResponse("accept", compiled.input.kind === "ready" && compiled.input.plan.kind === "url" ? null : result.content);
2204
+ if (result.status === "declined") return declineElicitation(result.message);
2205
+ if (result.status === "unsupported") return declineElicitation(result.message);
2206
+ return cancelValue;
2207
+ }
2208
+ });
1814
2209
  },
1815
2210
  handleNotification(notification) {
1816
- if (notification.method !== "serverRequest/resolved") return;
1817
- const notificationParams = isJsonObject(notification.params) ? notification.params : void 0;
1818
- const requestId = notificationParams ? readRequestId(notificationParams) : void 0;
1819
- if (!notificationParams || requestId === void 0) return;
1820
- if (sensitiveInput && readStringField(notificationParams, "threadId") === sensitiveInput.threadId && String(requestId) === String(sensitiveInput.requestId)) resolveSecret(emptyUserInputResponse());
1821
- if (pendingGateway && readStringField(notificationParams, "threadId") === pendingGateway.threadId && String(requestId) === String(pendingGateway.requestId)) pendingGateway.abort.abort(/* @__PURE__ */ new Error("Codex server request resolved"));
2211
+ if (notification.method !== "serverRequest/resolved" || !isJsonObject(notification.params)) return;
2212
+ const requestId = readRequestId(notification.params);
2213
+ if (requestId === void 0 || readOwnString(notification.params, "threadId") !== params.threadId) return;
2214
+ const job = jobs.find((candidate) => typeof candidate.requestId === typeof requestId && candidate.requestId === requestId);
2215
+ if (job) cancelJob(job);
1822
2216
  },
1823
- cancelPending() {
1824
- resolveSecret(emptyUserInputResponse());
1825
- cancelGateway();
1826
- }
2217
+ cancelPending
1827
2218
  };
1828
2219
  }
2220
+ function compileUserInputQuestions(questions) {
2221
+ return agentHarnessStructuredInput.compileQuestions({
2222
+ questions,
2223
+ intro: "Codex needs input:"
2224
+ });
2225
+ }
1829
2226
  function readUserInputParams(value) {
1830
- if (!isJsonObject(value)) return;
1831
- const threadId = readStringField(value, "threadId");
1832
- const turnId = readStringField(value, "turnId");
1833
- const itemId = readStringField(value, "itemId");
1834
- const questionsRaw = value.questions;
1835
- if (!threadId || !turnId || !itemId || !Array.isArray(questionsRaw)) return;
2227
+ const snapshot = agentHarnessStructuredInput.snapshot(value);
2228
+ if (!agentHarnessStructuredInput.isRecord(snapshot)) return;
2229
+ const threadId = readBoundedUserInputText(snapshot, "threadId", MAX_USER_INPUT_ID);
2230
+ const turnId = readBoundedUserInputText(snapshot, "turnId", MAX_USER_INPUT_ID);
2231
+ const itemId = readBoundedUserInputText(snapshot, "itemId", MAX_USER_INPUT_ID);
2232
+ const questions = readArray(snapshot, "questions", MAX_USER_INPUT_QUESTIONS);
2233
+ if (!threadId || !turnId || !itemId || !questions) return;
2234
+ const parsed = [];
2235
+ for (const questionValue of questions) {
2236
+ const question = readQuestion(questionValue);
2237
+ if (!question) return;
2238
+ parsed.push(question);
2239
+ }
1836
2240
  return {
1837
2241
  threadId,
1838
2242
  turnId,
1839
- itemId,
1840
- questions: questionsRaw.map((rawQuestion) => {
1841
- const question = readQuestion(rawQuestion);
1842
- if (question && isJsonObject(rawQuestion) && rawQuestion.multiSelect === true) question.multiSelect = true;
1843
- return question;
1844
- }).filter((question) => Boolean(question)),
1845
- isBlocking: value.isBlocking !== false
2243
+ questions: parsed,
2244
+ isBlocking: readValue(snapshot, "isBlocking") !== false
1846
2245
  };
1847
2246
  }
1848
2247
  function readQuestion(value) {
1849
- if (!isJsonObject(value)) return;
1850
- const id = readStringField(value, "id");
1851
- const header = readStringField(value, "header");
1852
- const question = readStringField(value, "question");
2248
+ if (!agentHarnessStructuredInput.isRecord(value)) return;
2249
+ const id = readBoundedUserInputText(value, "id", MAX_USER_INPUT_ID);
2250
+ const header = readBoundedUserInputText(value, "header", MAX_USER_INPUT_HEADER);
2251
+ const question = readBoundedUserInputText(value, "question", MAX_USER_INPUT_TEXT);
1853
2252
  if (!id || !header || !question) return;
2253
+ const options = readOptions(readValue(value, "options"));
2254
+ if (options === void 0) return;
1854
2255
  return {
1855
2256
  id,
1856
2257
  header,
1857
2258
  question,
1858
- isOther: value.isOther === true,
1859
- isSecret: value.isSecret === true,
1860
- options: readOptions(value.options)
2259
+ isOther: readValue(value, "isOther") === true,
2260
+ isSecret: readValue(value, "isSecret") === true,
2261
+ ...readValue(value, "multiSelect") === true ? { multiSelect: true } : {},
2262
+ options
1861
2263
  };
1862
2264
  }
1863
2265
  function readOptions(value) {
1864
- if (!Array.isArray(value)) return null;
1865
- const options = value.map(readOption).filter((option) => Boolean(option));
1866
- return options.length > 0 ? options : null;
1867
- }
1868
- function readOption(value) {
1869
- if (!isJsonObject(value)) return;
1870
- const label = readStringField(value, "label");
1871
- const description = readStringField(value, "description") ?? "";
1872
- return label ? {
1873
- label,
1874
- description
1875
- } : void 0;
2266
+ if (value === void 0 || value === null) return null;
2267
+ if (!Array.isArray(value) || value.length > MAX_USER_INPUT_OPTIONS) return;
2268
+ const options = [];
2269
+ for (const entry of value) {
2270
+ if (!agentHarnessStructuredInput.isRecord(entry)) return;
2271
+ const label = readBoundedUserInputText(entry, "label", MAX_USER_INPUT_ID);
2272
+ const description = readBoundedUserInputText(entry, "description", MAX_USER_INPUT_TEXT, true);
2273
+ if (!label) return;
2274
+ options.push({
2275
+ label,
2276
+ ...description ? { description } : {}
2277
+ });
2278
+ }
2279
+ return options;
2280
+ }
2281
+ function readValue(record, key) {
2282
+ return Object.hasOwn(record, key) ? record[key] : void 0;
2283
+ }
2284
+ function readBoundedUserInputText(record, key, maximum, allowEmpty = false) {
2285
+ const value = readValue(record, key);
2286
+ return typeof value === "string" && value.length <= maximum && (allowEmpty || value.length > 0) ? value : void 0;
2287
+ }
2288
+ function readArray(record, key, maximum) {
2289
+ const value = readValue(record, key);
2290
+ return Array.isArray(value) && value.length <= maximum ? value : void 0;
2291
+ }
2292
+ function readOwnString(record, key) {
2293
+ const descriptor = Object.getOwnPropertyDescriptor(record, key);
2294
+ return descriptor && "value" in descriptor && typeof descriptor.value === "string" ? descriptor.value : void 0;
1876
2295
  }
1877
- function buildUserInputResponse(questions, inputText) {
1878
- return buildAgentHarnessUserInputAnswers(questions, inputText);
2296
+ function readRawOwnString(value, key) {
2297
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
2298
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
2299
+ return descriptor && "value" in descriptor && typeof descriptor.value === "string" ? descriptor.value : void 0;
2300
+ }
2301
+ function readRequestId(record) {
2302
+ const descriptor = Object.getOwnPropertyDescriptor(record, "requestId");
2303
+ const value = descriptor && "value" in descriptor ? descriptor.value : void 0;
2304
+ return typeof value === "string" || typeof value === "number" ? value : void 0;
1879
2305
  }
1880
2306
  function gatewayAnswersToCodexResponse(answers) {
1881
2307
  return { answers: Object.fromEntries(Object.entries(answers).map(([questionId, values]) => [questionId, { answers: values }])) };
1882
2308
  }
1883
2309
  function emptyUserInputResponse() {
1884
- return emptyAgentHarnessUserInputAnswers();
2310
+ return { ...emptyAgentHarnessUserInputAnswers() };
1885
2311
  }
1886
- function readRequestId(record) {
1887
- const value = record.requestId;
1888
- return typeof value === "string" || typeof value === "number" ? value : void 0;
2312
+ function declineElicitation(message) {
2313
+ return createCodexElicitationResponse("decline", null, message ? { message } : null);
1889
2314
  }
1890
2315
  //#endregion
1891
2316
  //#region extensions/codex/src/app-server/run-attempt-active-turn.ts
@@ -1894,12 +2319,14 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
1894
2319
  const { context, turnState } = prompt;
1895
2320
  const { runtime, attemptTools } = context;
1896
2321
  const { connection } = runtime;
1897
- const { params, runAbortController, terminalState, abortExplicitly, abortFromUpstream, bindingStore, bindingIdentity, sessionAgentId, sandboxSessionKey, effectiveCwd } = connection;
1898
- const { dynamicToolParams, computerContextEpoch, toolBridge } = attemptTools;
2322
+ const { params, runAbortController, terminalState, abortExplicitly, abortFromUpstream, bindingStore, bindingIdentity, sessionAgentId, sandboxSessionKey, contextSessionKey, effectiveCwd } = connection;
2323
+ const { dynamicToolParams, compactionPlanState, computerContextEpoch, toolBridge } = attemptTools;
1899
2324
  const { state, userInputBridgeRef, steeringQueueRef, turnWatches, completeTurn, interruptTurn } = turnRuntime;
1900
2325
  const { emitExecutionPhaseOnce, emitLifecycleStart, maybeAnnounceFastModeAutoOff } = lifecycle;
1901
2326
  const { enqueueNotification } = notifications;
1902
2327
  const activeTurnId = turn.turn.id;
2328
+ const progressCardTool = toolBridge.availableTools.find((tool) => tool.name === "progress_card");
2329
+ let nativePlanUpdateOrdinal = 0;
1903
2330
  const prepareNativeMcpAppResultDetails = createCodexNativeMcpAppResultDetailsPreparer({
1904
2331
  client: resourceState.client,
1905
2332
  threadId: resourceState.thread.threadId,
@@ -1934,6 +2361,16 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
1934
2361
  }, resourceState.thread.threadId, activeTurnId, {
1935
2362
  initialContextTokens: connection.mutable.startupContextTokens,
1936
2363
  nativePostToolUseRelayEnabled: resourceState.nativeHookRelay?.allowedEvents.includes("post_tool_use") === true && resourceState.nativeHookRelay.shouldRelayEvent("post_tool_use"),
2364
+ asyncUserMessageAllowed: params.disableTools !== true && (params.toolsAllow === void 0 || toolBridge.availableTools.some((tool) => tool.name === "message")),
2365
+ onAsyncDelivery: async (delivery) => {
2366
+ return await codexTranscriptMirrorRuntime.deliverAsyncMessageBestEffort({
2367
+ params: dynamicToolParams,
2368
+ cwd: effectiveCwd,
2369
+ threadId: resourceState.thread.threadId,
2370
+ turnId: activeTurnId,
2371
+ ...delivery
2372
+ });
2373
+ },
1937
2374
  readRecentRateLimits: () => readRecentCodexRateLimits(resourceState.client),
1938
2375
  runAbortSignal: runAbortController.signal,
1939
2376
  remoteWorkspaceRoot: connection.appServer.remoteWorkspaceRoot,
@@ -1948,12 +2385,39 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
1948
2385
  trajectoryRecorder,
1949
2386
  resolveDynamicToolResultContentSource: toolBridge.resultContentSourceForTool,
1950
2387
  onNativeToolResultRecorded: maybeAnnounceFastModeAutoOff,
2388
+ ...progressCardTool ? { onNativePlanUpdate: async (update) => {
2389
+ nativePlanUpdateOrdinal += 1;
2390
+ try {
2391
+ const input = canonicalizeNativeProgressCardInput(update);
2392
+ await progressCardTool.execute(`codex-native-plan:${activeTurnId}:${nativePlanUpdateOrdinal}`, input, runAbortController.signal);
2393
+ } catch (error) {
2394
+ embeddedAgentLog.warn("failed to persist native Codex plan to progress card", {
2395
+ runId: params.runId,
2396
+ threadId: resourceState.thread.threadId,
2397
+ error: formatErrorMessage(error)
2398
+ });
2399
+ }
2400
+ } } : {},
1951
2401
  ...prepareNativeMcpAppResultDetails ? { prepareNativeMcpAppResultDetails } : {},
1952
2402
  upstreamUserText: turnState.codexTurnPromptText,
1953
- onContextCompacted: () => {
2403
+ onContextCompacted: async () => {
1954
2404
  computerContextEpoch.value += 1;
1955
2405
  delete computerContextEpoch.frameToolCallId;
1956
2406
  delete computerContextEpoch.frameImageIdentity;
2407
+ try {
2408
+ await compactionPlanState.restore({
2409
+ client: resourceState.client,
2410
+ threadId: resourceState.thread.threadId,
2411
+ timeoutMs: connection.appServer.requestTimeoutMs,
2412
+ signal: runAbortController.signal
2413
+ });
2414
+ } catch (error) {
2415
+ embeddedAgentLog.warn("failed to restore Codex plan state after compaction", {
2416
+ runId: params.runId,
2417
+ threadId: resourceState.thread.threadId,
2418
+ error: formatErrorMessage(error)
2419
+ });
2420
+ }
1957
2421
  }
1958
2422
  });
1959
2423
  if (isTerminalTurnStatus(turn.turn.status)) state.terminalTurnNotificationQueued = true;
@@ -1964,6 +2428,18 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
1964
2428
  turnWatches.armAttemptIdleWatch();
1965
2429
  turnWatches.touchActivity("turn:start", { attemptProgress: true });
1966
2430
  for (const failure of pendingNativePreToolUseFailures.splice(0)) activeProjector.recordNativeToolPreToolUseFailure(failure);
2431
+ const notifyUserMessagePersisted = createCodexAppServerUserMessagePersistenceNotifier(params);
2432
+ const promptMirrorPromise = mirrorPromptAtTurnStartBestEffort({
2433
+ params,
2434
+ agentId: sessionAgentId,
2435
+ notifyUserMessagePersisted,
2436
+ sessionKey: sandboxSessionKey,
2437
+ cwd: effectiveCwd,
2438
+ threadId: resourceState.thread.threadId,
2439
+ turnId: activeTurnId,
2440
+ upstreamUserText: turnState.codexTurnPromptText
2441
+ });
2442
+ await promptMirrorPromise;
1967
2443
  if (resourceState.turnRoute) try {
1968
2444
  await resourceState.turnRoute.bindTurn(activeTurnId);
1969
2445
  } catch (error) {
@@ -1974,24 +2450,53 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
1974
2450
  throw error;
1975
2451
  }
1976
2452
  }
1977
- if (!state.completed && isTerminalTurnStatus(turn.turn.status)) await enqueueNotification({
1978
- method: "turn/completed",
1979
- params: {
2453
+ if (!state.completed && isTerminalTurnStatus(turn.turn.status)) {
2454
+ if (!isJsonObject(turn.turn)) throw new Error("Codex turn completion payload is not a JSON object");
2455
+ await enqueueNotification({
2456
+ method: "turn/completed",
2457
+ params: {
2458
+ threadId: resourceState.thread.threadId,
2459
+ turnId: activeTurnId,
2460
+ turn: turn.turn
2461
+ }
2462
+ }, {
1980
2463
  threadId: resourceState.thread.threadId,
1981
- turnId: activeTurnId,
1982
- turn: turn.turn
1983
- }
1984
- }, {
1985
- threadId: resourceState.thread.threadId,
1986
- turnId: activeTurnId
1987
- });
2464
+ turnId: activeTurnId
2465
+ });
2466
+ }
1988
2467
  const activeSteeringQueue = createCodexSteeringQueue({
1989
2468
  client: resourceState.client,
1990
2469
  threadId: resourceState.thread.threadId,
1991
2470
  turnId: activeTurnId,
1992
2471
  requestTimeoutMs: connection.appServer.requestTimeoutMs,
1993
- claimPendingUserInput: () => userInputBridgeRef.current?.claimPendingRequest(),
1994
- signal: runAbortController.signal
2472
+ signal: runAbortController.signal,
2473
+ beforeConfirmConsumed: async (items) => {
2474
+ const inboundItems = items.filter((item) => item.isInboundUserMessage === true);
2475
+ if (inboundItems.length === 0) return;
2476
+ await promptMirrorPromise;
2477
+ const messages = activeProjector.buildSteeringTranscriptPrefix();
2478
+ if (params.sessionTarget && messages.length > 0) {
2479
+ await codexTranscriptMirrorRuntime.mirror({
2480
+ agentId: sessionAgentId,
2481
+ sessionKey: contextSessionKey,
2482
+ sessionId: params.sessionId,
2483
+ storePath: params.sessionTarget.storePath,
2484
+ cwd: effectiveCwd,
2485
+ messages,
2486
+ idempotencyScope: `codex-app-server:${resourceState.thread.threadId}`,
2487
+ runId: params.runId,
2488
+ runMirrorIdentityPrefix: `${activeTurnId}:`,
2489
+ config: params.config
2490
+ });
2491
+ activeProjector.markSteeringTranscriptPersisted();
2492
+ }
2493
+ for (const item of inboundItems) {
2494
+ const recorder = item.userTurnTranscriptRecorder;
2495
+ if (!recorder) continue;
2496
+ await recorder.persistApproved();
2497
+ if (!recorder.hasPersisted()) throw new Error("Codex consumed steering before its user turn was persisted");
2498
+ }
2499
+ }
1995
2500
  });
1996
2501
  steeringQueueRef.current = activeSteeringQueue;
1997
2502
  const claimPendingUserInputAnswer = async (text, optionsLocal) => {
@@ -2058,17 +2563,6 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
2058
2563
  terminalState.terminalOutcomeFrozen = true;
2059
2564
  params.abortSignal?.removeEventListener("abort", abortFromUpstream);
2060
2565
  };
2061
- const notifyUserMessagePersisted = createCodexAppServerUserMessagePersistenceNotifier(params);
2062
- mirrorPromptAtTurnStartBestEffort({
2063
- params,
2064
- agentId: sessionAgentId,
2065
- notifyUserMessagePersisted,
2066
- sessionKey: sandboxSessionKey,
2067
- cwd: effectiveCwd,
2068
- threadId: resourceState.thread.threadId,
2069
- turnId: activeTurnId,
2070
- upstreamUserText: turnState.codexTurnPromptText
2071
- });
2072
2566
  const abortListener = () => {
2073
2567
  if (state.timedOut) {
2074
2568
  (async () => {
@@ -2295,10 +2789,7 @@ async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codex
2295
2789
  path.join(resolvedAgentDir, "agent", "codex-home", "sessions"),
2296
2790
  path.join(path.dirname(resolvedAgentDir), "codex-home", "sessions")
2297
2791
  ];
2298
- const rolloutRoot = rolloutPath ? roots.find((root) => {
2299
- const relativePath = path.relative(root, rolloutPath);
2300
- return relativePath !== "" && relativePath !== ".." && !relativePath.startsWith(`..${path.sep}`) && !path.isAbsolute(relativePath);
2301
- }) : void 0;
2792
+ const rolloutRoot = rolloutPath ? roots.find((root) => isPathStrictlyInside(root, rolloutPath)) : void 0;
2302
2793
  if (rolloutPath && rolloutRoot && path.isAbsolute(rolloutPath) && path.extname(rolloutPath) === ".jsonl" && path.basename(rolloutPath).includes(threadId)) try {
2303
2794
  const opened = await (await root(rolloutRoot, {
2304
2795
  hardlinks: "reject",
@@ -2555,14 +3046,6 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
2555
3046
  }
2556
3047
  //#endregion
2557
3048
  //#region extensions/codex/src/app-server/run-attempt-connection.ts
2558
- function applyStoredBindingPermissions(params) {
2559
- if (params.execPolicyTouched || params.binding?.connectionScope === "supervision") return params.appServer;
2560
- return {
2561
- ...params.appServer,
2562
- approvalPolicy: params.binding?.approvalPolicy ?? params.appServer.approvalPolicy,
2563
- sandbox: params.binding?.sandbox ?? params.appServer.sandbox
2564
- };
2565
- }
2566
3049
  async function prepareCodexAttemptConnection({ params, options }) {
2567
3050
  const attemptStartedAt = Date.now();
2568
3051
  const profilerEnabled = isCodexAppServerProfilerEnabled(params.config);
@@ -2575,16 +3058,15 @@ async function prepareCodexAttemptConnection({ params, options }) {
2575
3058
  resetAnnounced: false
2576
3059
  };
2577
3060
  const preDynamicStartupStages = createCodexDynamicToolBuildStageTracker({ enabled: profilerEnabled });
2578
- const attemptClientFactory = options.clientFactory ?? getLeasedSharedCodexAppServerClient;
2579
3061
  const runtimeArtifactRequest = params.captureRuntimeArtifact || params.expectedRuntimeArtifact ? params.expectedRuntimeArtifact ? { expected: params.expectedRuntimeArtifact } : {} : void 0;
2580
3062
  const pluginConfig = readCodexPluginConfig(options.pluginConfig);
3063
+ const requirementsToml = readCodexRequirementsToml({});
2581
3064
  const computerUseConfig = resolveCodexComputerUseConfig({ pluginConfig });
2582
3065
  const { sessionAgentId } = resolveSessionAgentIds({
2583
3066
  sessionKey: params.sessionKey,
2584
3067
  config: params.config,
2585
3068
  agentId: params.agentId
2586
3069
  });
2587
- const beforeToolCallPolicy = getBeforeToolCallPolicyDiagnosticState();
2588
3070
  preDynamicStartupStages.mark("config");
2589
3071
  const resolvedWorkspace = resolveUserPath(params.workspaceDir);
2590
3072
  await ensureCodexWorkspaceDirOnce(resolvedWorkspace);
@@ -2596,14 +3078,36 @@ async function prepareCodexAttemptConnection({ params, options }) {
2596
3078
  sessionKey: sandboxSessionKey,
2597
3079
  workspaceDir: resolvedWorkspace
2598
3080
  });
3081
+ const attemptClientFactory = options.clientFactory ?? (isCodexPairedNodeRemoteExecPlacementSandbox(sandbox) ? createIsolatedCodexAppServerClient : getLeasedSharedCodexAppServerClient);
2599
3082
  preDynamicStartupStages.mark("sandbox");
2600
3083
  const execPolicy = resolveOpenClawExecPolicyForCodexAppServer({
3084
+ permissionMode: params.permissionMode,
2601
3085
  execOverrides: params.execOverrides,
2602
- approvals: loadExecApprovals(),
3086
+ approvals: params.permissionMode === "full" ? void 0 : loadExecApprovals(),
2603
3087
  config: params.config,
2604
3088
  agentId: sessionAgentId
2605
3089
  });
2606
3090
  const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId);
3091
+ const preparedEnvironment = params.hostCapabilities.preparedEnvironment?.();
3092
+ const remoteExec = isCodexRemoteExecPlacementSandbox(sandbox);
3093
+ const preparedShellEnvironment = preparedEnvironment ? {
3094
+ ...preparedEnvironment.credentialScrubEnv,
3095
+ ...!remoteExec ? preparedEnvironment.localIdentityEnv : void 0
3096
+ } : void 0;
3097
+ const shellEnvironment = preparedShellEnvironment && Object.keys(preparedShellEnvironment).length > 0 ? preparedShellEnvironment : void 0;
3098
+ const disableLoginShell = remoteExec || preparedEnvironment?.managedLocalIdentity === true || preparedEnvironment !== void 0 && Object.keys(preparedEnvironment.credentialScrubEnv).length > 0;
3099
+ const withPreparedProcessEnv = (appServer) => {
3100
+ return shellEnvironment ? {
3101
+ ...appServer,
3102
+ start: {
3103
+ ...appServer.start,
3104
+ env: {
3105
+ ...appServer.start.env,
3106
+ ...shellEnvironment
3107
+ }
3108
+ }
3109
+ } : appServer;
3110
+ };
2607
3111
  let bindingIdentity = sessionBindingIdentity({
2608
3112
  sessionId: params.sessionId,
2609
3113
  sessionKey: params.sessionKey,
@@ -2650,21 +3154,20 @@ async function prepareCodexAttemptConnection({ params, options }) {
2650
3154
  const usesSupervisionConnection = startupBinding?.connectionScope === "supervision";
2651
3155
  if (usesSupervisionConnection) activeContextEngine = void 0;
2652
3156
  if (usesSupervisionConnection && pluginConfig.supervision?.enabled !== true) throw new Error("Codex supervision is disabled; refusing to open a native user-home supervised session");
2653
- const resolveRuntimeOptionsForBinding = (selection) => applyStoredBindingPermissions({
2654
- appServer: resolveCodexBindingAppServerConnection({
2655
- binding: startupBinding,
2656
- pluginConfig,
2657
- execPolicy,
2658
- modelProvider: selection.modelProvider,
2659
- model: selection.model,
2660
- config: params.config,
2661
- agentDir,
2662
- openClawSandboxActive: sandbox?.enabled === true
2663
- }).appServer,
2664
- binding: startupBinding,
2665
- execPolicyTouched: execPolicy.touched
2666
- });
3157
+ const resolveRuntimeOptionsForBinding = (binding, selection) => resolveCodexBindingAppServerConnection({
3158
+ binding,
3159
+ pluginConfig,
3160
+ execPolicy,
3161
+ modelProvider: selection.modelProvider,
3162
+ model: selection.model,
3163
+ config: params.config,
3164
+ agentDir,
3165
+ requirementsToml,
3166
+ openClawSandboxActive: sandbox?.enabled === true,
3167
+ sessionPermissionMode: params.permissionMode
3168
+ }).appServer;
2667
3169
  const initialStartupBindingHadInactiveThreadBootstrap = isInactiveThreadBootstrapBinding(startupBinding);
3170
+ const appServerHomeScope = resolveCodexAppServerHomeScope({ appServer: pluginConfig.appServer });
2668
3171
  const preparedAuthRoute = usesSupervisionConnection ? void 0 : params.runtimePlan?.auth.modelRoute;
2669
3172
  const startupAuthProfileCandidate = usesSupervisionConnection ? void 0 : preparedAuthRoute ? params.runtimePlan?.auth.forwardedAuthProfileId : params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId;
2670
3173
  const resolvedStartupAuthProfileId = usesSupervisionConnection ? void 0 : preparedAuthRoute ? startupAuthProfileCandidate : params.authProfileStore ? resolveCodexAppServerAuthProfileId({
@@ -2686,13 +3189,13 @@ async function prepareCodexAttemptConnection({ params, options }) {
2686
3189
  authProfileId: resolvedStartupAuthProfileId,
2687
3190
  authProfileStore: params.authProfileStore,
2688
3191
  agentDir,
2689
- homeScope: resolveCodexAppServerHomeScope({ appServer: pluginConfig.appServer }),
3192
+ homeScope: appServerHomeScope,
2690
3193
  requirePreparedAuth: isCodexRemoteExecPlacementSandbox(sandbox),
2691
3194
  config: params.config,
2692
3195
  subscriptionProfileRequiredError: "Prepared Codex subscription route requires a forwarded OpenAI OAuth or token profile.",
2693
3196
  subscriptionProfileUnusableError: "Prepared Codex subscription auth profile is unusable."
2694
3197
  });
2695
- const startupClientAuthProfileId = usesSupervisionConnection || startupPreparedAuth?.kind === "api-key" ? null : startupAuthProfileId;
3198
+ const startupClientAuthProfileId = usesSupervisionConnection || appServerHomeScope === "user" || startupPreparedAuth?.kind === "api-key" ? null : startupAuthProfileId;
2696
3199
  const resolveReviewerPolicyContext = (binding) => {
2697
3200
  const nativeModelOwned = binding?.preserveNativeModel === true;
2698
3201
  return resolveCodexModelBackedReviewerPolicyContext({
@@ -2705,41 +3208,67 @@ async function prepareCodexAttemptConnection({ params, options }) {
2705
3208
  };
2706
3209
  let reviewerPolicyContext = resolveReviewerPolicyContext(startupBinding);
2707
3210
  preDynamicStartupStages.mark("auth-profile");
2708
- let configuredAppServer = resolveRuntimeOptionsForBinding({
3211
+ let configuredAppServer = resolveRuntimeOptionsForBinding(startupBinding, {
2709
3212
  modelProvider: reviewerPolicyContext.modelProvider,
2710
3213
  model: reviewerPolicyContext.model
2711
3214
  });
2712
3215
  const effectiveWorkspace = sandbox?.enabled ? sandbox.workspaceAccess === "rw" ? resolvedWorkspace : sandbox.workspaceDir : resolvedWorkspace;
2713
3216
  const requestedCwd = params.cwd ? resolveUserPath(params.cwd) : void 0;
2714
3217
  if (sandbox?.enabled && requestedCwd && requestedCwd !== resolvedWorkspace) throw new Error("cwd override is not supported for sandboxed Codex app-server runs; omit cwd or use the agent workspace as cwd");
2715
- const effectiveCwd = sandbox?.enabled ? effectiveWorkspace : requestedCwd ?? effectiveWorkspace;
3218
+ const sessionPermissionCwd = resolveCodexSessionPermissionCwd({
3219
+ permissionMode: params.permissionMode,
3220
+ sessionRoot: params.sessionRoot,
3221
+ defaultRoot: effectiveWorkspace,
3222
+ requestedCwd,
3223
+ fallbackCwd: effectiveWorkspace
3224
+ });
3225
+ const effectiveCwd = sandbox?.enabled ? effectiveWorkspace : sessionPermissionCwd;
2716
3226
  if (effectiveWorkspace !== resolvedWorkspace) await ensureCodexWorkspaceDirOnce(effectiveWorkspace);
2717
3227
  preDynamicStartupStages.mark("effective-workspace");
2718
- const shouldPromoteApprovalPolicy = beforeToolCallPolicy.hasBeforeToolCallHook || beforeToolCallPolicy.trustedToolPolicies.length > 0;
2719
- const resolvePolicyAppServer = () => resolveCodexAppServerForOpenClawToolPolicy({
2720
- appServer: configuredAppServer,
3228
+ const applySessionPermissionPolicy = (appServer, selection) => applyCodexSessionPermissionPolicy({
3229
+ appServer,
3230
+ permissionMode: params.permissionMode,
3231
+ sessionRoot: params.sessionRoot,
3232
+ defaultRoot: effectiveWorkspace,
2721
3233
  pluginConfig,
2722
- env: process.env,
2723
- shouldPromote: shouldPromoteApprovalPolicy,
2724
- execPolicy,
2725
- canUseUntrustedApprovalPolicy: shouldPromoteApprovalPolicy && configuredAppServer.approvalPolicy === "never" && (configuredAppServer.start.transport !== "stdio" || isCodexAppServerApprovalPolicyAllowedByRequirements("untrusted"))
2726
- });
2727
- let policyAppServer = resolvePolicyAppServer();
2728
- let appServer = resolveCodexAppServerForModelProvider({
2729
- appServer: policyAppServer,
2730
- provider: reviewerPolicyContext.modelProvider,
2731
- model: reviewerPolicyContext.model,
2732
- config: params.config,
2733
- env: process.env,
2734
- agentDir
2735
- });
2736
- let approvalPolicyPromotedForOpenClawToolPolicy = configuredAppServer.approvalPolicy === "never" && appServer.approvalPolicy === "untrusted";
2737
- if (approvalPolicyPromotedForOpenClawToolPolicy) embeddedAgentLog.info("codex app-server approval policy promoted for OpenClaw tool policy", {
2738
- from: "never",
2739
- to: "untrusted",
2740
- beforeToolCallHook: beforeToolCallPolicy.hasBeforeToolCallHook,
2741
- trustedToolPolicies: beforeToolCallPolicy.trustedToolPolicies
3234
+ canUseAutoReview: canUseCodexModelBackedApprovalsReviewerForModel({
3235
+ modelProvider: selection.modelProvider,
3236
+ model: selection.model,
3237
+ config: params.config,
3238
+ env: {
3239
+ ...process.env,
3240
+ ...appServer.start.env,
3241
+ ...shellEnvironment
3242
+ },
3243
+ agentDir,
3244
+ homeScope: appServer.start.homeScope,
3245
+ codexArgs: appServer.start.args
3246
+ }),
3247
+ requirementsToml,
3248
+ policyLocked: startupBinding?.connectionScope === "supervision",
3249
+ execMode: execPolicy.mode
2742
3250
  });
3251
+ const resolveFinalAppServer = (configured, selection) => {
3252
+ const session = applySessionPermissionPolicy(configured, selection);
3253
+ const trusted = resolveCodexAppServerForModelProvider({
3254
+ appServer: session,
3255
+ provider: selection.modelProvider,
3256
+ model: selection.model,
3257
+ config: params.config,
3258
+ env: {
3259
+ ...process.env,
3260
+ ...session.start.env,
3261
+ ...shellEnvironment
3262
+ },
3263
+ agentDir
3264
+ });
3265
+ return {
3266
+ session,
3267
+ appServer: withPreparedProcessEnv(trusted)
3268
+ };
3269
+ };
3270
+ let resolvedAppServer = resolveFinalAppServer(configuredAppServer, reviewerPolicyContext);
3271
+ let appServer = resolvedAppServer.appServer;
2743
3272
  preDynamicStartupStages.mark("app-server-policy");
2744
3273
  preDynamicStartupStages.mark("native-hook-relay");
2745
3274
  const terminalState = {
@@ -2787,20 +3316,23 @@ async function prepareCodexAttemptConnection({ params, options }) {
2787
3316
  preDynamicStartupStages.mark("rotate-binding");
2788
3317
  if (startupBinding !== startupBindingBeforeRotation) {
2789
3318
  reviewerPolicyContext = resolveReviewerPolicyContext(startupBinding);
2790
- configuredAppServer = resolveRuntimeOptionsForBinding({
3319
+ configuredAppServer = resolveRuntimeOptionsForBinding(startupBinding, {
2791
3320
  modelProvider: reviewerPolicyContext.modelProvider,
2792
3321
  model: reviewerPolicyContext.model
2793
3322
  });
2794
- policyAppServer = resolvePolicyAppServer();
2795
- appServer = resolveCodexAppServerForModelProvider({
2796
- appServer: policyAppServer,
2797
- provider: reviewerPolicyContext.modelProvider,
2798
- model: reviewerPolicyContext.model,
2799
- config: params.config,
2800
- env: process.env,
2801
- agentDir
2802
- });
2803
- approvalPolicyPromotedForOpenClawToolPolicy = configuredAppServer.approvalPolicy === "never" && appServer.approvalPolicy === "untrusted";
3323
+ resolvedAppServer = resolveFinalAppServer(configuredAppServer, reviewerPolicyContext);
3324
+ appServer = resolvedAppServer.appServer;
3325
+ }
3326
+ const sessionPermissionPolicy = resolveCodexEffectiveSessionPermissionPolicy({
3327
+ appServer,
3328
+ permissionMode: params.permissionMode,
3329
+ sessionRoot: params.sessionRoot,
3330
+ defaultRoot: effectiveWorkspace
3331
+ });
3332
+ if (sessionPermissionPolicy) {
3333
+ params.permissionMode = sessionPermissionPolicy.mode;
3334
+ params.sessionRoot = sessionPermissionPolicy.root;
3335
+ (params.execOverrides ??= {}).mode = sessionPermissionPolicy.execMode;
2804
3336
  }
2805
3337
  const nativeHookRelayEvents = resolveCodexNativeHookRelayEvents({
2806
3338
  configuredEvents: options.nativeHookRelay?.events,
@@ -2809,22 +3341,10 @@ async function prepareCodexAttemptConnection({ params, options }) {
2809
3341
  const mutable = {
2810
3342
  startupBinding,
2811
3343
  startupContextTokens: startupBindingResolution.startupContextTokens,
2812
- pluginAppServer: appServer
3344
+ pluginAppServer: appServer,
3345
+ continuityCalibration: startupBindingBeforeRotation?.continuityCalibration
2813
3346
  };
2814
- const resolveRuntimeOptionsForCurrentBinding = (selection) => applyStoredBindingPermissions({
2815
- appServer: resolveCodexBindingAppServerConnection({
2816
- binding: mutable.startupBinding,
2817
- pluginConfig,
2818
- execPolicy,
2819
- modelProvider: selection.modelProvider,
2820
- model: selection.model,
2821
- config: params.config,
2822
- agentDir,
2823
- openClawSandboxActive: sandbox?.enabled === true
2824
- }).appServer,
2825
- binding: mutable.startupBinding,
2826
- execPolicyTouched: execPolicy.touched
2827
- });
3347
+ const resolveRuntimeOptionsForCurrentBinding = (selection) => resolveFinalAppServer(resolveRuntimeOptionsForBinding(mutable.startupBinding, selection), selection).appServer;
2828
3348
  return {
2829
3349
  params,
2830
3350
  options,
@@ -2846,6 +3366,8 @@ async function prepareCodexAttemptConnection({ params, options }) {
2846
3366
  contextSessionKey,
2847
3367
  sandbox,
2848
3368
  agentDir,
3369
+ shellEnvironment,
3370
+ disableLoginShell,
2849
3371
  bindingIdentity,
2850
3372
  bindingStore,
2851
3373
  activeContextEngine,
@@ -2858,7 +3380,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
2858
3380
  effectiveWorkspace,
2859
3381
  effectiveCwd,
2860
3382
  appServer,
2861
- approvalPolicyPromotedForOpenClawToolPolicy,
3383
+ sessionPermissionPolicy,
2862
3384
  nativeHookRelayEvents,
2863
3385
  runAbortController,
2864
3386
  terminalState,
@@ -2951,10 +3473,12 @@ function resolveContextEngineBootstrapProjectionDecision(params) {
2951
3473
  */
2952
3474
  async function buildCodexWorkspaceBootstrapContext(params) {
2953
3475
  try {
3476
+ const inheritsAgentWorkspace = (params.executionWorkspace ?? params.resolvedWorkspace) !== params.resolvedWorkspace;
3477
+ const promptWorkspace = inheritsAgentWorkspace ? params.resolvedWorkspace : params.effectiveWorkspace;
2954
3478
  const memoryToolsAvailable = params.memoryToolNames.length > 0 && canRouteCodexWorkspaceMemoryThroughTools({
2955
3479
  config: params.params.config,
2956
3480
  agentId: params.params.agentId ?? params.sessionAgentId,
2957
- workspaceDir: params.effectiveWorkspace
3481
+ workspaceDir: inheritsAgentWorkspace ? params.resolvedWorkspace : params.effectiveWorkspace
2958
3482
  });
2959
3483
  const bootstrapFiles = await resolveBootstrapFilesForRun({
2960
3484
  workspaceDir: params.resolvedWorkspace,
@@ -2974,7 +3498,7 @@ async function buildCodexWorkspaceBootstrapContext(params) {
2974
3498
  const memoryReferenceFiles = memoryToolRoutedBootstrapFiles.map((file) => remapCodexContextFilePath({
2975
3499
  file: toCodexEmbeddedContextFile(file),
2976
3500
  sourceWorkspaceDir: params.resolvedWorkspace,
2977
- targetWorkspaceDir: params.effectiveWorkspace
3501
+ targetWorkspaceDir: promptWorkspace
2978
3502
  }));
2979
3503
  const contextFiles = buildBootstrapContextForFiles(memoryToolsAvailable ? bootstrapFiles.filter((file) => !isCodexWorkspaceRootMemoryBootstrapFile({
2980
3504
  file,
@@ -2986,23 +3510,33 @@ async function buildCodexWorkspaceBootstrapContext(params) {
2986
3510
  }).map((file) => remapCodexContextFilePath({
2987
3511
  file,
2988
3512
  sourceWorkspaceDir: params.resolvedWorkspace,
2989
- targetWorkspaceDir: params.effectiveWorkspace
3513
+ targetWorkspaceDir: promptWorkspace
2990
3514
  }));
2991
3515
  const promptContextFiles = selectCodexWorkspacePromptContextFiles(contextFiles, {
2992
3516
  excludeMemory: memoryToolsAvailable,
2993
3517
  memoryWorkspaceDir: params.effectiveWorkspace
2994
3518
  });
2995
- const turnScopedDeveloperInstructionFiles = shouldInjectCodexOpenClawPromptContext(params.params) ? selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) : [];
3519
+ const injectOpenClawContext = shouldInjectCodexOpenClawPromptContext(params.params);
3520
+ const restrictedProjectDocNeedsOpenClawCarrier = params.params.pluginHarnessToolPolicyRestricted === true && !params.params.disableTools && !isMessageOnlyCodexSourceReply(params.params) && params.params.bootstrapContextMode !== "lightweight";
3521
+ const threadDeveloperInstructionFiles = injectOpenClawContext && !params.ringZeroActive && (inheritsAgentWorkspace || restrictedProjectDocNeedsOpenClawCarrier) ? selectCodexWorkspaceAgentProjectInstructionFiles(contextFiles, params.resolvedWorkspace) : [];
3522
+ const turnScopedDeveloperInstructionFiles = injectOpenClawContext ? selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) : [];
2996
3523
  return {
2997
3524
  bootstrapFiles,
2998
3525
  contextFiles,
3526
+ inheritsAgentWorkspace,
2999
3527
  promptContextFiles,
3528
+ threadDeveloperInstructionFiles,
3000
3529
  turnScopedDeveloperInstructionFiles,
3001
3530
  memoryReferenceFiles,
3002
3531
  memoryToolRoutedBootstrapFiles,
3003
3532
  memoryToolNames: [...params.memoryToolNames],
3004
3533
  memoryToolRouted: memoryToolsAvailable,
3005
3534
  promptContext: renderCodexWorkspaceBootstrapPromptContext(promptContextFiles),
3535
+ threadDeveloperInstructions: renderCodexWorkspaceDeveloperInstructions({
3536
+ files: threadDeveloperInstructionFiles,
3537
+ header: "## OpenClaw Agent Workspace Instructions",
3538
+ preamble: "OpenClaw loaded this bounded snapshot from the configured agent workspace."
3539
+ }),
3006
3540
  turnScopedDeveloperInstructions: renderCodexWorkspaceCollaborationDeveloperInstructions(turnScopedDeveloperInstructionFiles),
3007
3541
  memoryCollaborationInstructions: shouldInjectCodexOpenClawPromptContext(params.params) ? await renderCodexWorkspaceMemoryCollaborationInstructions({
3008
3542
  files: memoryReferenceFiles,
@@ -3018,7 +3552,8 @@ async function buildCodexWorkspaceBootstrapContext(params) {
3018
3552
  embeddedAgentLog.warn("failed to load codex workspace bootstrap instructions", { error });
3019
3553
  return {
3020
3554
  bootstrapFiles: [],
3021
- contextFiles: []
3555
+ contextFiles: [],
3556
+ inheritsAgentWorkspace: false
3022
3557
  };
3023
3558
  }
3024
3559
  }
@@ -3051,7 +3586,7 @@ function buildCodexSystemPromptReport(params) {
3051
3586
  injectedWorkspaceFiles: buildCodexBootstrapInjectionStats({
3052
3587
  bootstrapFiles: params.workspaceBootstrapContext.bootstrapFiles,
3053
3588
  injectedFiles: params.workspaceBootstrapContext.promptContextFiles ?? [],
3054
- developerInstructionFiles: params.workspaceBootstrapContext.turnScopedDeveloperInstructionFiles ?? [],
3589
+ developerInstructionFiles: [...params.workspaceBootstrapContext.threadDeveloperInstructionFiles ?? [], ...params.workspaceBootstrapContext.turnScopedDeveloperInstructionFiles ?? []],
3055
3590
  memoryToolRoutedBootstrapFiles: params.workspaceBootstrapContext.memoryToolRoutedBootstrapFiles ?? [],
3056
3591
  memoryToolRouted: params.workspaceBootstrapContext.memoryToolRouted === true
3057
3592
  }),
@@ -3132,12 +3667,17 @@ function buildCodexBootstrapInjectionStats(params) {
3132
3667
  const rawChars = file.missing ? 0 : (file.content ?? "").trimEnd().length;
3133
3668
  const memoryToolRoutedFile = baseName === CODEX_MEMORY_CONTEXT_BASENAME && params.memoryToolRouted === true && memoryToolRoutedPaths.has(normalizeCodexContextFilePath(pathValue));
3134
3669
  const injected = memoryToolRoutedFile ? void 0 : readCodexIndexedContextFileContent(injectedIndex, pathValue, fileName) ?? readCodexIndexedContextFileContent(developerInstructionIndex, pathValue, fileName);
3135
- let injectedChars = memoryToolRoutedFile ? 0 : injected?.length ?? 0;
3136
- let truncated = memoryToolRoutedFile ? false : !file.missing && injectedChars < rawChars;
3137
- if (injected === void 0 && CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName)) {
3138
- injectedChars = rawChars;
3139
- truncated = false;
3140
- }
3670
+ if (!file.missing && injected === void 0 && CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName)) return {
3671
+ name: displayName,
3672
+ path: pathValue,
3673
+ missing: false,
3674
+ rawChars,
3675
+ injectionStatus: "native_unverified",
3676
+ injectedChars: null,
3677
+ truncated: null
3678
+ };
3679
+ const injectedChars = memoryToolRoutedFile ? 0 : injected?.length ?? 0;
3680
+ const truncated = memoryToolRoutedFile ? false : !file.missing && injectedChars < rawChars;
3141
3681
  return {
3142
3682
  name: displayName,
3143
3683
  path: pathValue,
@@ -3272,7 +3812,7 @@ function renderCodexWorkspaceBootstrapPromptContext(contextFiles) {
3272
3812
  const files = contextFiles;
3273
3813
  if (files.length === 0) return;
3274
3814
  const lines = [
3275
- "OpenClaw loaded these user-editable workspace files for the current turn. Codex loads AGENTS.md natively. SOUL.md, IDENTITY.md, and USER.md are provided as turn-scoped collaboration instructions so native Codex subagents do not inherit them. Those files are not repeated here.",
3815
+ "OpenClaw loaded these user-editable workspace files for the current turn. Codex loads project-local AGENTS.md natively. When execution uses another folder, OpenClaw supplies the agent workspace AGENTS.md as thread-level developer instructions. SOUL.md, IDENTITY.md, and USER.md remain turn-scoped collaboration instructions. Those files are not repeated here.",
3276
3816
  "",
3277
3817
  "# Project Context",
3278
3818
  "",
@@ -3295,6 +3835,10 @@ function selectCodexWorkspacePromptContextFiles(contextFiles, options = {}) {
3295
3835
  function selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) {
3296
3836
  return selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES);
3297
3837
  }
3838
+ function selectCodexWorkspaceAgentProjectInstructionFiles(contextFiles, agentWorkspaceDir) {
3839
+ const agentProjectDocPath = path.join(path.resolve(agentWorkspaceDir), "AGENTS.md");
3840
+ return selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, CODEX_NATIVE_PROJECT_DOC_BASENAMES).filter((file) => path.resolve(file.path) === agentProjectDocPath);
3841
+ }
3298
3842
  function selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, basenames) {
3299
3843
  return contextFiles.filter((file) => {
3300
3844
  const baseName = getCodexContextFileBasename(file.path);
@@ -3428,34 +3972,131 @@ function remapCodexContextFilePath(params) {
3428
3972
  path: targetUsesPosixSeparators ? path.posix.join(params.targetWorkspaceDir, normalizedRelativePath) : path.win32.join(params.targetWorkspaceDir, normalizedRelativePath)
3429
3973
  };
3430
3974
  }
3431
- function compareCodexContextFiles(left, right) {
3432
- const leftPath = normalizeCodexContextFilePath(left.path);
3433
- const rightPath = normalizeCodexContextFilePath(right.path);
3434
- const leftBase = getCodexContextFileBasename(left.path);
3435
- const rightBase = getCodexContextFileBasename(right.path);
3436
- const leftOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(leftBase) ?? Number.MAX_SAFE_INTEGER;
3437
- const rightOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(rightBase) ?? Number.MAX_SAFE_INTEGER;
3438
- if (leftOrder !== rightOrder) return leftOrder - rightOrder;
3439
- if (leftBase !== rightBase) return leftBase.localeCompare(rightBase);
3440
- return leftPath.localeCompare(rightPath);
3975
+ function compareCodexContextFiles(left, right) {
3976
+ const leftPath = normalizeCodexContextFilePath(left.path);
3977
+ const rightPath = normalizeCodexContextFilePath(right.path);
3978
+ const leftBase = getCodexContextFileBasename(left.path);
3979
+ const rightBase = getCodexContextFileBasename(right.path);
3980
+ const leftOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(leftBase) ?? Number.MAX_SAFE_INTEGER;
3981
+ const rightOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(rightBase) ?? Number.MAX_SAFE_INTEGER;
3982
+ if (leftOrder !== rightOrder) return leftOrder - rightOrder;
3983
+ if (leftBase !== rightBase) return leftBase.localeCompare(rightBase);
3984
+ return leftPath.localeCompare(rightPath);
3985
+ }
3986
+ function compareCodexBootstrapFiles(left, right) {
3987
+ return compareCodexContextFiles(toCodexEmbeddedContextFile(left), toCodexEmbeddedContextFile(right));
3988
+ }
3989
+ function normalizeCodexContextFilePath(filePath) {
3990
+ return filePath.trim().replaceAll("\\", "/").toLowerCase();
3991
+ }
3992
+ function getCodexContextFileDisplayBasename(filePath) {
3993
+ return filePath.trim().replaceAll("\\", "/").split("/").pop()?.trim() ?? "";
3994
+ }
3995
+ function getCodexContextFileBasename(filePath) {
3996
+ return normalizeCodexContextFilePath(filePath).split("/").pop() ?? "";
3997
+ }
3998
+ function normalizeCodexDynamicToolName(name) {
3999
+ return name.trim().toLowerCase();
4000
+ }
4001
+ function isNonEmptyString$1(value) {
4002
+ return typeof value === "string" && value.length > 0;
4003
+ }
4004
+ //#endregion
4005
+ //#region extensions/codex/src/app-server/run-attempt-state.ts
4006
+ async function clearCodexBindingAfterInvalidImagePayload(bindingStore, identity, fields) {
4007
+ const currentBinding = await bindingStore.read(identity);
4008
+ const expectedThreadId = fields.threadId ?? currentBinding?.threadId;
4009
+ if (!expectedThreadId) return;
4010
+ if (currentBinding && currentBinding.threadId !== expectedThreadId) {
4011
+ embeddedAgentLog.warn("codex app-server image payload error detected for unbound thread; preserving thread binding", {
4012
+ ...fields,
4013
+ boundThreadId: currentBinding.threadId
4014
+ });
4015
+ return;
4016
+ }
4017
+ if (currentBinding?.connectionScope === "supervision") {
4018
+ embeddedAgentLog.warn("codex app-server image payload error detected for supervised thread; preserving native binding", fields);
4019
+ return;
4020
+ }
4021
+ embeddedAgentLog.warn("codex app-server image payload error detected; clearing thread binding", fields);
4022
+ await bindingStore.mutate(identity, {
4023
+ kind: "clear",
4024
+ threadId: expectedThreadId
4025
+ });
4026
+ }
4027
+ async function markCodexAppServerBindingCoveredThroughTurn(params) {
4028
+ await params.bindingStore.mutate(params.identity, {
4029
+ kind: "patch",
4030
+ threadId: params.threadId,
4031
+ patch: {
4032
+ historyCoveredThrough: (/* @__PURE__ */ new Date()).toISOString(),
4033
+ ...params.continuityCalibration ? { continuityCalibration: params.continuityCalibration } : {}
4034
+ }
4035
+ });
4036
+ }
4037
+ function isNonEmptyString(value) {
4038
+ return typeof value === "string" && value.length > 0;
3441
4039
  }
3442
- function compareCodexBootstrapFiles(left, right) {
3443
- return compareCodexContextFiles(toCodexEmbeddedContextFile(left), toCodexEmbeddedContextFile(right));
4040
+ function shouldUseFreshCodexThreadAfterContextEngineOverflow(params) {
4041
+ if (!params.contextEngineActive || params.thread.lifecycle.action !== "resumed") return false;
4042
+ const message = formatErrorMessage(params.error);
4043
+ return /ran out of room in the model'?s context window/iu.test(message) || /context window/iu.test(message) || /context length/iu.test(message) || /maximum context/iu.test(message) || /too many tokens/iu.test(message);
3444
4044
  }
3445
- function normalizeCodexContextFilePath(filePath) {
3446
- return filePath.trim().replaceAll("\\", "/").toLowerCase();
4045
+ function isCodexActiveCompactTurnError(error) {
4046
+ if (!(error instanceof CodexAppServerRpcError)) return false;
4047
+ const data = isJsonObject(error.data) ? error.data : void 0;
4048
+ const codexErrorInfo = isJsonObject(data?.codexErrorInfo) ? data.codexErrorInfo : void 0;
4049
+ return (isJsonObject(codexErrorInfo?.activeTurnNotSteerable) ? codexErrorInfo.activeTurnNotSteerable : void 0)?.turnKind === "compact";
3447
4050
  }
3448
- function getCodexContextFileDisplayBasename(filePath) {
3449
- return filePath.trim().replaceAll("\\", "/").split("/").pop()?.trim() ?? "";
4051
+ function readCodexFinalizationHookNotification(notification, threadId, turnId) {
4052
+ if (notification.method !== "hook/started" && notification.method !== "hook/completed") return;
4053
+ const params = isJsonObject(notification.params) ? notification.params : void 0;
4054
+ const run = params && isJsonObject(params.run) ? params.run : void 0;
4055
+ if (params?.threadId !== threadId || params.turnId !== turnId || run?.eventName !== "stop" && run?.eventName !== "subagentStop" || typeof run.id !== "string" || !run.id) return;
4056
+ if (notification.method === "hook/started") return {
4057
+ phase: "started",
4058
+ runId: run.id
4059
+ };
4060
+ return {
4061
+ phase: "completed",
4062
+ runId: run.id,
4063
+ status: typeof run.status === "string" ? run.status : void 0
4064
+ };
3450
4065
  }
3451
- function getCodexContextFileBasename(filePath) {
3452
- return normalizeCodexContextFilePath(filePath).split("/").pop() ?? "";
4066
+ function joinPresentSections(...sections) {
4067
+ return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
3453
4068
  }
3454
- function normalizeCodexDynamicToolName(name) {
3455
- return name.trim().toLowerCase();
4069
+ function prependCurrentInboundContext(prompt, context) {
4070
+ const text = context?.text.trim();
4071
+ return text ? [neutralizeCodexExplicitMentionSigils(text), prompt].filter(Boolean).join("\n\n") : prompt;
3456
4072
  }
3457
- function isNonEmptyString$1(value) {
3458
- return typeof value === "string" && value.length > 0;
4073
+ function buildCodexAppServerTimeoutDiagnostics(params) {
4074
+ const readNonBlankDetailString = (key) => {
4075
+ const value = params.details?.[key];
4076
+ return hasNonEmptyString(value) ? value : void 0;
4077
+ };
4078
+ const activeAppServerTurnRequests = asFiniteNumber(params.details?.activeAppServerTurnRequests);
4079
+ const activeTurnItemCount = asFiniteNumber(params.details?.activeTurnItemCount);
4080
+ const terminalTurnNotificationQueued = asBoolean(params.details?.terminalTurnNotificationQueued);
4081
+ const completionIdleWatchArmed = asBoolean(params.details?.completionIdleWatchArmed);
4082
+ const assistantCompletionIdleWatchArmed = asBoolean(params.details?.assistantCompletionIdleWatchArmed);
4083
+ const terminalIdleWatchArmed = asBoolean(params.details?.terminalIdleWatchArmed);
4084
+ return {
4085
+ ...params.idleMs !== void 0 ? { idleMs: params.idleMs } : {},
4086
+ ...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
4087
+ ...params.lastActivityReason ? { lastActivityReason: params.lastActivityReason } : {},
4088
+ ...readNonBlankDetailString("lastNotificationMethod") ? { lastNotificationMethod: readNonBlankDetailString("lastNotificationMethod") } : {},
4089
+ ...readNonBlankDetailString("lastNotificationItemId") ? { lastNotificationItemId: readNonBlankDetailString("lastNotificationItemId") } : {},
4090
+ ...readNonBlankDetailString("lastNotificationItemType") ? { lastNotificationItemType: readNonBlankDetailString("lastNotificationItemType") } : {},
4091
+ ...readNonBlankDetailString("lastNotificationItemRole") ? { lastNotificationItemRole: readNonBlankDetailString("lastNotificationItemRole") } : {},
4092
+ ...readNonBlankDetailString("lastAssistantTextPreview") ? { lastAssistantTextPreview: readNonBlankDetailString("lastAssistantTextPreview") } : {},
4093
+ ...activeAppServerTurnRequests !== void 0 ? { activeAppServerTurnRequests } : {},
4094
+ ...activeTurnItemCount !== void 0 ? { activeTurnItemCount } : {},
4095
+ ...terminalTurnNotificationQueued !== void 0 ? { terminalTurnNotificationQueued } : {},
4096
+ ...completionIdleWatchArmed !== void 0 ? { completionIdleWatchArmed } : {},
4097
+ ...assistantCompletionIdleWatchArmed !== void 0 ? { assistantCompletionIdleWatchArmed } : {},
4098
+ ...terminalIdleWatchArmed !== void 0 ? { terminalIdleWatchArmed } : {}
4099
+ };
3459
4100
  }
3460
4101
  //#endregion
3461
4102
  //#region extensions/codex/src/app-server/run-attempt-context.ts
@@ -3527,16 +4168,20 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
3527
4168
  });
3528
4169
  historyState.messages = await readFencedHistory() ?? historyState.messages;
3529
4170
  }
4171
+ const memoryToolNames = getCodexWorkspaceMemoryToolNames(toolBridge.availableSpecs);
3530
4172
  const workspaceBootstrapContext = await buildCodexWorkspaceBootstrapContext({
3531
4173
  params: runtimeParams,
3532
- resolvedWorkspace,
4174
+ resolvedWorkspace: runtimeParams.bootstrapWorkspaceDir ?? resolvedWorkspace,
4175
+ executionWorkspace: resolvedWorkspace,
3533
4176
  effectiveWorkspace,
3534
4177
  sessionKey: contextSessionKey,
3535
4178
  sessionAgentId,
3536
- memoryToolNames: getCodexWorkspaceMemoryToolNames(toolBridge.availableSpecs),
4179
+ memoryToolNames,
4180
+ ringZeroActive: isHostScopedAgentToolActive("openclaw") && isSystemAgentOnlyCodexDynamicToolAllowlist(runtimeParams.toolsAllow),
3537
4181
  sandboxed: sandbox?.enabled === true
3538
4182
  });
3539
- const baseDeveloperInstructions = buildDeveloperInstructions(runtimeParams, { dynamicTools: toolBridge.availableSpecs });
4183
+ const agentWorkspaceDeveloperInstructions = workspaceBootstrapContext.threadDeveloperInstructions ? connection.mutable.startupBinding?.agentWorkspaceDeveloperInstructions ?? workspaceBootstrapContext.threadDeveloperInstructions : void 0;
4184
+ const baseDeveloperInstructions = joinPresentSections(buildDeveloperInstructions(runtimeParams, { dynamicTools: toolBridge.availableSpecs }), agentWorkspaceDeveloperInstructions);
3540
4185
  return {
3541
4186
  runtime,
3542
4187
  attemptTools,
@@ -3547,6 +4192,7 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
3547
4192
  hookRunner,
3548
4193
  buildActiveContextEngineRuntimeContext,
3549
4194
  workspaceBootstrapContext,
4195
+ agentWorkspaceDeveloperInstructions,
3550
4196
  baseDeveloperInstructions,
3551
4197
  openClawPromptContext: buildCodexOpenClawPromptContext({
3552
4198
  params: runtimeParams,
@@ -3570,11 +4216,16 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
3570
4216
  contextEngineProjection: void 0,
3571
4217
  precomputedStaleBindingContinuityProjectionApplied: false,
3572
4218
  staleBindingContinuityForcedFreshStart: false,
4219
+ noEngineContinuityProjectionApplied: false,
3573
4220
  inactiveThreadBootstrapBindingForcedFreshStart: initialInactiveThreadBootstrapBindingForcedFreshStart
3574
4221
  },
3575
4222
  codexContextProjectionMaxChars: resolveCodexContextEngineProjectionMaxChars({
3576
4223
  contextTokenBudget: effectiveContextTokenBudget,
3577
4224
  reserveTokens: resolveCodexContextEngineProjectionReserveTokens()
4225
+ }),
4226
+ codexContinuityProjectionMaxChars: resolveCodexContinuityProjectionMaxChars({
4227
+ contextTokenBudget: effectiveContextTokenBudget,
4228
+ calibration: connection.mutable.continuityCalibration
3578
4229
  })
3579
4230
  };
3580
4231
  }
@@ -3785,105 +4436,6 @@ function isInvalidCodexImagePayloadError(message) {
3785
4436
  return /\b(?:invalid|malformed)\b[\s\S]{0,120}\b(?:image|image url|base64)\b/iu.test(normalizedMessage) || /\b(?:image|image url|base64)\b[\s\S]{0,120}\b(?:invalid|malformed)\b/iu.test(normalizedMessage);
3786
4437
  }
3787
4438
  //#endregion
3788
- //#region extensions/codex/src/app-server/run-attempt-state.ts
3789
- async function clearCodexBindingAfterInvalidImagePayload(bindingStore, identity, fields) {
3790
- const currentBinding = await bindingStore.read(identity);
3791
- const expectedThreadId = fields.threadId ?? currentBinding?.threadId;
3792
- if (!expectedThreadId) return;
3793
- if (currentBinding && currentBinding.threadId !== expectedThreadId) {
3794
- embeddedAgentLog.warn("codex app-server image payload error detected for unbound thread; preserving thread binding", {
3795
- ...fields,
3796
- boundThreadId: currentBinding.threadId
3797
- });
3798
- return;
3799
- }
3800
- if (currentBinding?.connectionScope === "supervision") {
3801
- embeddedAgentLog.warn("codex app-server image payload error detected for supervised thread; preserving native binding", fields);
3802
- return;
3803
- }
3804
- embeddedAgentLog.warn("codex app-server image payload error detected; clearing thread binding", fields);
3805
- await bindingStore.mutate(identity, {
3806
- kind: "clear",
3807
- threadId: expectedThreadId
3808
- });
3809
- }
3810
- async function markCodexAppServerBindingCoveredThroughTurn(params) {
3811
- await params.bindingStore.mutate(params.identity, {
3812
- kind: "patch",
3813
- threadId: params.threadId,
3814
- patch: { historyCoveredThrough: (/* @__PURE__ */ new Date()).toISOString() }
3815
- });
3816
- }
3817
- function isNonEmptyString(value) {
3818
- return typeof value === "string" && value.length > 0;
3819
- }
3820
- function shouldUseFreshCodexThreadAfterContextEngineOverflow(params) {
3821
- if (!params.contextEngineActive || params.thread.lifecycle.action !== "resumed") return false;
3822
- const message = formatErrorMessage(params.error);
3823
- return /ran out of room in the model'?s context window/iu.test(message) || /context window/iu.test(message) || /context length/iu.test(message) || /maximum context/iu.test(message) || /too many tokens/iu.test(message);
3824
- }
3825
- function isCodexActiveCompactTurnError(error) {
3826
- if (!(error instanceof CodexAppServerRpcError)) return false;
3827
- const data = isJsonObject(error.data) ? error.data : void 0;
3828
- const codexErrorInfo = isJsonObject(data?.codexErrorInfo) ? data.codexErrorInfo : void 0;
3829
- return (isJsonObject(codexErrorInfo?.activeTurnNotSteerable) ? codexErrorInfo.activeTurnNotSteerable : void 0)?.turnKind === "compact";
3830
- }
3831
- function readCodexFinalizationHookNotification(notification, threadId, turnId) {
3832
- if (notification.method !== "hook/started" && notification.method !== "hook/completed") return;
3833
- const params = isJsonObject(notification.params) ? notification.params : void 0;
3834
- const run = params && isJsonObject(params.run) ? params.run : void 0;
3835
- if (params?.threadId !== threadId || params.turnId !== turnId || run?.eventName !== "stop" && run?.eventName !== "subagentStop" || typeof run.id !== "string" || !run.id) return;
3836
- if (notification.method === "hook/started") return {
3837
- phase: "started",
3838
- runId: run.id
3839
- };
3840
- return {
3841
- phase: "completed",
3842
- runId: run.id,
3843
- status: typeof run.status === "string" ? run.status : void 0
3844
- };
3845
- }
3846
- function joinPresentSections(...sections) {
3847
- return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
3848
- }
3849
- function prependCurrentInboundContext(prompt, context) {
3850
- const text = context?.text.trim();
3851
- return text ? [neutralizeCodexExplicitMentionSigils(text), prompt].filter(Boolean).join("\n\n") : prompt;
3852
- }
3853
- function waitForCodexNotificationDispatchTurn() {
3854
- return new Promise((resolve) => {
3855
- setImmediate(resolve);
3856
- });
3857
- }
3858
- function buildCodexAppServerTimeoutDiagnostics(params) {
3859
- const readNonBlankDetailString = (key) => {
3860
- const value = params.details?.[key];
3861
- return hasNonEmptyString(value) ? value : void 0;
3862
- };
3863
- const activeAppServerTurnRequests = asFiniteNumber(params.details?.activeAppServerTurnRequests);
3864
- const activeTurnItemCount = asFiniteNumber(params.details?.activeTurnItemCount);
3865
- const terminalTurnNotificationQueued = asBoolean(params.details?.terminalTurnNotificationQueued);
3866
- const completionIdleWatchArmed = asBoolean(params.details?.completionIdleWatchArmed);
3867
- const assistantCompletionIdleWatchArmed = asBoolean(params.details?.assistantCompletionIdleWatchArmed);
3868
- const terminalIdleWatchArmed = asBoolean(params.details?.terminalIdleWatchArmed);
3869
- return {
3870
- ...params.idleMs !== void 0 ? { idleMs: params.idleMs } : {},
3871
- ...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
3872
- ...params.lastActivityReason ? { lastActivityReason: params.lastActivityReason } : {},
3873
- ...readNonBlankDetailString("lastNotificationMethod") ? { lastNotificationMethod: readNonBlankDetailString("lastNotificationMethod") } : {},
3874
- ...readNonBlankDetailString("lastNotificationItemId") ? { lastNotificationItemId: readNonBlankDetailString("lastNotificationItemId") } : {},
3875
- ...readNonBlankDetailString("lastNotificationItemType") ? { lastNotificationItemType: readNonBlankDetailString("lastNotificationItemType") } : {},
3876
- ...readNonBlankDetailString("lastNotificationItemRole") ? { lastNotificationItemRole: readNonBlankDetailString("lastNotificationItemRole") } : {},
3877
- ...readNonBlankDetailString("lastAssistantTextPreview") ? { lastAssistantTextPreview: readNonBlankDetailString("lastAssistantTextPreview") } : {},
3878
- ...activeAppServerTurnRequests !== void 0 ? { activeAppServerTurnRequests } : {},
3879
- ...activeTurnItemCount !== void 0 ? { activeTurnItemCount } : {},
3880
- ...terminalTurnNotificationQueued !== void 0 ? { terminalTurnNotificationQueued } : {},
3881
- ...completionIdleWatchArmed !== void 0 ? { completionIdleWatchArmed } : {},
3882
- ...assistantCompletionIdleWatchArmed !== void 0 ? { assistantCompletionIdleWatchArmed } : {},
3883
- ...terminalIdleWatchArmed !== void 0 ? { terminalIdleWatchArmed } : {}
3884
- };
3885
- }
3886
- //#endregion
3887
4439
  //#region extensions/codex/src/app-server/settled-turn-context.ts
3888
4440
  function collectUniqueMessageIdentities(messages) {
3889
4441
  const identities = /* @__PURE__ */ new Map();
@@ -3973,100 +4525,13 @@ async function captureCodexSettledTurnFinalizationContext(params) {
3973
4525
  }
3974
4526
  //#endregion
3975
4527
  //#region extensions/codex/src/app-server/trajectory.ts
3976
- const SENSITIVE_FIELD_RE = /(?:authorization|cookie|credential|key|password|passwd|secret|token)/iu;
3977
- const PRIVATE_PAYLOAD_FIELD_RE = /(?:image|screenshot|attachment|fileData|dataUri)/iu;
3978
- const AUTHORIZATION_VALUE_RE = /\b(Bearer|Basic)\s+[A-Za-z0-9+/._~=-]{8,}/giu;
3979
- const JWT_VALUE_RE = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/gu;
3980
- const COOKIE_PAIR_RE = /\b([A-Za-z][A-Za-z0-9_.-]{1,64})=([A-Za-z0-9+/._~%=-]{16,})(?=;|\s|$)/gu;
3981
- const TRAJECTORY_RUNTIME_EVENT_MAX_BYTES = 256 * 1024;
3982
- const TRAJECTORY_RUNTIME_OVERSIZE_PRESERVED_DATA_KEYS = ["usage", "promptCache"];
3983
- function boundedTrajectoryEvent(event) {
3984
- const line = JSON.stringify(event);
3985
- const bytes = Buffer.byteLength(line, "utf8");
3986
- if (bytes <= TRAJECTORY_RUNTIME_EVENT_MAX_BYTES) return event;
3987
- const originalData = event.data && typeof event.data === "object" && !Array.isArray(event.data) ? event.data : {};
3988
- const originalDataKeys = Object.keys(originalData);
3989
- const preservedDataKeys = /* @__PURE__ */ new Set();
3990
- const baseData = {
3991
- truncated: true,
3992
- originalBytes: bytes,
3993
- limitBytes: TRAJECTORY_RUNTIME_EVENT_MAX_BYTES,
3994
- reason: "trajectory-event-size-limit"
3995
- };
3996
- const buildTruncatedEvent = (includeDroppedFields) => {
3997
- const data = { ...baseData };
3998
- for (const key of TRAJECTORY_RUNTIME_OVERSIZE_PRESERVED_DATA_KEYS) if (preservedDataKeys.has(key)) data[key] = originalData[key];
3999
- if (includeDroppedFields) {
4000
- const droppedFields = originalDataKeys.filter((key) => !preservedDataKeys.has(key));
4001
- if (droppedFields.length > 0) data.droppedFields = droppedFields;
4002
- }
4003
- const truncatedEvent = {
4004
- ...event,
4005
- data
4006
- };
4007
- const truncated = JSON.stringify(truncatedEvent);
4008
- if (Buffer.byteLength(truncated, "utf8") <= TRAJECTORY_RUNTIME_EVENT_MAX_BYTES) return truncatedEvent;
4009
- };
4010
- let best = buildTruncatedEvent(true) ?? buildTruncatedEvent(false);
4011
- if (!best) return;
4012
- for (const key of TRAJECTORY_RUNTIME_OVERSIZE_PRESERVED_DATA_KEYS) {
4013
- if (!Object.hasOwn(originalData, key)) continue;
4014
- preservedDataKeys.add(key);
4015
- const next = buildTruncatedEvent(true) ?? buildTruncatedEvent(false);
4016
- if (next) {
4017
- best = next;
4018
- continue;
4019
- }
4020
- preservedDataKeys.delete(key);
4021
- }
4022
- return best;
4023
- }
4024
- function createCodexHostTrajectorySink(params) {
4025
- return {
4026
- write: (event) => {
4027
- params.recorder.recordEvent(event.type, event.data);
4028
- },
4029
- flush: async () => {
4030
- await params.recorder.flush();
4031
- }
4032
- };
4033
- }
4034
- /** Creates a trajectory recorder when trajectory capture is enabled for the environment. */
4528
+ /** Creates a trajectory recorder when the host exposes its capture capability. */
4035
4529
  function createCodexTrajectoryRecorder(params) {
4036
- if (!parseTrajectoryEnabled(params.env ?? process.env)) return null;
4037
- if (!params.trajectoryRecorder) {
4038
- params.warn?.("codex trajectory capture requires the SQLite host recorder", {
4039
- sessionId: params.attempt.sessionId,
4040
- reason: "sqlite-recorder-unavailable"
4041
- });
4042
- return null;
4043
- }
4044
- const sink = createCodexHostTrajectorySink({ recorder: params.trajectoryRecorder });
4045
- let seq = 0;
4046
- const attribution = resolveCodexLocalRuntimeAttribution(params.attempt);
4530
+ if (!params.trajectory) return null;
4531
+ const trajectory = params.trajectory;
4047
4532
  return {
4048
- recordEvent: (type, data) => {
4049
- const event = boundedTrajectoryEvent({
4050
- traceSchema: "openclaw-trajectory",
4051
- schemaVersion: 1,
4052
- traceId: params.attempt.sessionId,
4053
- source: "runtime",
4054
- type,
4055
- ts: (/* @__PURE__ */ new Date()).toISOString(),
4056
- seq: seq += 1,
4057
- sourceSeq: seq,
4058
- sessionId: params.attempt.sessionId,
4059
- sessionKey: params.attempt.sessionKey,
4060
- runId: params.attempt.runId,
4061
- workspaceDir: params.cwd,
4062
- provider: attribution.provider,
4063
- modelId: params.attempt.modelId,
4064
- modelApi: attribution.api,
4065
- data: data ? sanitizeValue(data) : void 0
4066
- });
4067
- if (event) sink.write(event);
4068
- },
4069
- flush: sink.flush
4533
+ recordEvent: trajectory.recordEvent,
4534
+ flush: trajectory.flush
4070
4535
  };
4071
4536
  }
4072
4537
  /** Records compiled prompt/tool context at the start of a Codex runtime attempt. */
@@ -4095,12 +4560,6 @@ function recordCodexTrajectoryCompletion(recorder, params) {
4095
4560
  messagesSnapshot: params.result.messagesSnapshot
4096
4561
  });
4097
4562
  }
4098
- function parseTrajectoryEnabled(env) {
4099
- const value = env.OPENCLAW_TRAJECTORY?.trim().toLowerCase();
4100
- if (value === "1" || value === "true" || value === "yes" || value === "on") return true;
4101
- if (value === "0" || value === "false" || value === "no" || value === "off") return false;
4102
- return true;
4103
- }
4104
4563
  function toTrajectoryToolDefinitions(tools) {
4105
4564
  if (!tools || tools.length === 0) return;
4106
4565
  return flattenCodexDynamicToolFunctions(tools).flatMap((tool) => {
@@ -4109,31 +4568,10 @@ function toTrajectoryToolDefinitions(tools) {
4109
4568
  return [{
4110
4569
  name,
4111
4570
  description: tool.description,
4112
- parameters: sanitizeValue(tool.inputSchema)
4571
+ parameters: tool.inputSchema
4113
4572
  }];
4114
4573
  }).toSorted((left, right) => left.name.localeCompare(right.name));
4115
4574
  }
4116
- function sanitizeValue(value, depth = 0, key = "") {
4117
- if (value == null || typeof value === "boolean" || typeof value === "number") return value;
4118
- if (typeof value === "string") {
4119
- if (SENSITIVE_FIELD_RE.test(key)) return "<redacted>";
4120
- if (value.startsWith("data:") && value.length > 256) return `<redacted data-uri ${value.slice(0, value.indexOf(",")).length} chars>`;
4121
- if (PRIVATE_PAYLOAD_FIELD_RE.test(key) && value.length > 256) return "<redacted payload>";
4122
- const redacted = redactSensitiveString(value);
4123
- return redacted.length > 2e4 ? `${truncateUtf16Safe(redacted, 2e4)}…` : redacted;
4124
- }
4125
- if (depth >= 6) return "<truncated>";
4126
- if (Array.isArray(value)) return value.slice(0, 100).map((entry) => sanitizeValue(entry, depth + 1, key));
4127
- if (typeof value === "object") {
4128
- const next = {};
4129
- for (const [keyLocal, child] of Object.entries(value).slice(0, 100)) next[keyLocal] = sanitizeValue(child, depth + 1, keyLocal);
4130
- return next;
4131
- }
4132
- return JSON.stringify(value);
4133
- }
4134
- function redactSensitiveString(value) {
4135
- return value.replace(AUTHORIZATION_VALUE_RE, "$1 <redacted>").replace(JWT_VALUE_RE, "<redacted-jwt>").replace(COOKIE_PAIR_RE, "$1=<redacted>");
4136
- }
4137
4575
  /** Converts arbitrary prompt errors into trajectory-safe text. */
4138
4576
  function normalizeCodexTrajectoryError(value) {
4139
4577
  if (!value) return null;
@@ -4154,7 +4592,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
4154
4592
  const { hookContextWindowFields, hookRunner } = context;
4155
4593
  const { connection, preparedAuthBinding } = runtime;
4156
4594
  const { effectiveRuntimeProviderId, effectiveRuntimeModelId } = runtime;
4157
- const { params, terminalState, runAbortController, activeContextEngine, bindingStore, bindingIdentity, appServer, usesSupervisionConnection, sessionAgentId, contextSessionKey, effectiveCwd, attemptStartedAt, startupAuthProfileId } = connection;
4595
+ const { params, terminalState, runAbortController, activeContextEngine, bindingStore, bindingIdentity, appServer, usesSupervisionConnection, sessionAgentId, contextSessionKey, effectiveCwd, agentDir, attemptStartedAt, startupAuthProfileId } = connection;
4158
4596
  const { toolBridge, toolState } = attemptTools;
4159
4597
  const { state, completion, pendingOpenClawDynamicToolCompletionIds, activeTurnItemIds, activeCompletionBlockerItemIds, activeFinalizationHookRunIds, turnWatches } = turnRuntime;
4160
4598
  const { emitLifecycleTerminal, buildLifecycleTerminalMeta } = lifecycle;
@@ -4186,9 +4624,9 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
4186
4624
  const projectedTerminal = attemptTerminal.project(result.terminal);
4187
4625
  const effectiveTimedOut = state.timedOut && !recoveredTurnWatchTimeout;
4188
4626
  const effectiveTurnCompletionIdleTimedOut = state.turnCompletionIdleTimedOut && !recoveredTurnWatchTimeout;
4189
- const isFinalAborted = () => projectedTerminal.aborted || terminalState.explicitCancellationObserved || runAbortController.signal.aborted && !state.clientClosedAbort && !recoveredTurnWatchTimeout;
4627
+ const isFinalAborted = () => terminalState.explicitCancellationObserved || !resourceState.executionDisconnectError && (projectedTerminal.aborted || runAbortController.signal.aborted && !state.clientClosedAbort && !recoveredTurnWatchTimeout);
4190
4628
  const clientClosedPromptErrorForFinal = state.clientClosedPromptError && hasRecoverableCompletedAssistant ? void 0 : state.clientClosedPromptError;
4191
- let finalPromptError = clientClosedPromptErrorForFinal ?? (effectiveTurnCompletionIdleTimedOut ? state.turnCompletionIdleTimeoutMessage : effectiveTimedOut ? "codex app-server attempt timed out" : projectedTerminal.promptError);
4629
+ let finalPromptError = resourceState.executionDisconnectError ?? clientClosedPromptErrorForFinal ?? (effectiveTurnCompletionIdleTimedOut ? state.turnCompletionIdleTimeoutMessage : effectiveTimedOut ? "codex app-server attempt timed out" : projectedTerminal.promptError);
4192
4630
  const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError instanceof Error ? finalPromptError.message : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
4193
4631
  if (isInvalidCodexImagePayloadError(finalPromptErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(bindingStore, bindingIdentity, {
4194
4632
  phase: "turn_completed",
@@ -4229,6 +4667,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
4229
4667
  authProfileId: startupAuthProfileId,
4230
4668
  rateLimits: readRecentCodexRateLimits(resourceState.client)
4231
4669
  });
4670
+ finalPromptError = resourceState.executionDisconnectError ?? finalPromptError;
4232
4671
  const finalPromptErrorSource = effectiveTimedOut || clientClosedPromptErrorForFinal ? "prompt" : projectedTerminal.promptErrorSource;
4233
4672
  const codexAppServerFailureKind = clientClosedPromptErrorForFinal ? "client_closed_before_turn_completed" : effectiveTurnCompletionIdleTimedOut ? "turn_completion_idle_timeout" : void 0;
4234
4673
  const replayBlockedReason = codexAppServerFailureKind ? resolveCodexAppServerReplayBlockedReason(result) : void 0;
@@ -4332,20 +4771,11 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
4332
4771
  modelIterations: result.modelIterations ?? 0,
4333
4772
  skillWorkshopAvailable: flattenCodexDynamicToolFunctions(attemptTools.toolBridge.availableSpecs).some((tool) => tool.name === "skill_workshop"),
4334
4773
  compacted: (result.compactionCount ?? 0) > 0,
4335
- messageChannel: params.messageChannel,
4336
- messageProvider: params.messageProvider,
4337
- chatType: params.chatType,
4338
- agentAccountId: params.agentAccountId,
4339
- groupId: params.groupId,
4340
- groupChannel: params.groupChannel,
4341
- groupSpace: params.groupSpace,
4342
- memberRoleIds: params.memberRoleIds,
4343
- spawnedBy: params.spawnedBy,
4344
4774
  senderId: params.senderId ?? void 0,
4345
- senderName: params.senderName,
4346
- senderUsername: params.senderUsername,
4347
- senderE164: params.senderE164,
4348
- senderIsOwner: params.senderIsOwner
4775
+ foregroundPromptContext: buildEmbeddedForegroundPromptContext({
4776
+ ...params,
4777
+ agentId: sessionAgentId
4778
+ }, agentDir)
4349
4779
  },
4350
4780
  hookRunner
4351
4781
  });
@@ -4354,7 +4784,11 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
4354
4784
  await markCodexAppServerBindingCoveredThroughTurn({
4355
4785
  bindingStore,
4356
4786
  identity: bindingIdentity,
4357
- threadId: resourceState.thread.threadId
4787
+ threadId: resourceState.thread.threadId,
4788
+ continuityCalibration: context.promptState.noEngineContinuityProjectionApplied ? buildCodexContinuityCalibration({
4789
+ promptChars: prompt.turnState.codexTurnPromptText.length,
4790
+ inputTokens: (result.attemptUsage?.input ?? 0) + (result.attemptUsage?.cacheRead ?? 0) + (result.attemptUsage?.cacheWrite ?? 0)
4791
+ }) : void 0
4358
4792
  });
4359
4793
  } catch (error) {
4360
4794
  if (resourceState.thread.connectionScope === "supervision") throw error;
@@ -4407,6 +4841,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
4407
4841
  });
4408
4842
  const finalizedResult = {
4409
4843
  ...result,
4844
+ ...toolState.yieldAcknowledgment ? { yieldAcknowledgment: toolState.yieldAcknowledgment } : {},
4410
4845
  terminal: attemptTerminal.normalize({
4411
4846
  timedOut: effectiveTimedOut,
4412
4847
  aborted: finalAborted,
@@ -4420,6 +4855,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
4420
4855
  ...terminalAnchor ? { contextEngineTerminalAnchor: terminalAnchor } : {},
4421
4856
  ...settledTurnFinalizationContext ? { settledTurnFinalizationContext } : {},
4422
4857
  ...resourceState.runtimeArtifact ? { runtimeArtifact: resourceState.runtimeArtifact } : {},
4858
+ ...resourceState.runtimeContinuationStarted ? { runtimeContinuationStarted: true } : {},
4423
4859
  ...!finalAborted && !effectiveTimedOut && !finalPromptError && preparedAuthBinding ? { authBindingFingerprint: preparedAuthBinding.fingerprint } : {},
4424
4860
  systemPromptReport
4425
4861
  };
@@ -4764,7 +5200,7 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
4764
5200
  state.turnCrossedToolHandoff = notificationState.turnCrossedToolHandoff;
4765
5201
  if (notificationState.isCurrentTurnNotification && notification.method === "item/completed") {
4766
5202
  const item = readCodexNotificationItem(notification.params);
4767
- if (item?.type === "userMessage" && typeof item.clientId === "string") steeringQueue?.confirmConsumed(item.clientId);
5203
+ if (item?.type === "userMessage" && typeof item.clientId === "string") await steeringQueue?.confirmConsumed(item.clientId);
4768
5204
  }
4769
5205
  if (notificationState.isTurnAbortMarker) state.sawCodexInterruptMarker = true;
4770
5206
  const hookNotification = readCodexFinalizationHookNotification(notification, resourceState.thread.threadId, turnId);
@@ -4775,7 +5211,6 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
4775
5211
  }
4776
5212
  if (notificationState.isTurnTerminal) state.terminalTurnNotificationQueued = true;
4777
5213
  try {
4778
- await waitForCodexNotificationDispatchTurn();
4779
5214
  await projector.handleNotification(notification);
4780
5215
  const canRelease = isAssistantCompletionReleaseNotification(notification, state.turnCrossedToolHandoff) || notificationState.isCurrentTurnNotification && state.turnCrossedToolHandoff && notification.method === "rawResponseItem/completed" && projector.canReleaseLatestTerminalAssistantAfterToolHandoff();
4781
5216
  if (notificationState.isCurrentTurnNotification && canRelease) {
@@ -4871,11 +5306,12 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
4871
5306
  }
4872
5307
  //#endregion
4873
5308
  //#region extensions/codex/src/app-server/run-attempt-prompt.ts
5309
+ const CODEX_META_KEY = "__openclaw";
4874
5310
  function isRestrictivePromptToolsAllow(toolsAllow) {
4875
5311
  return toolsAllow !== void 0 && !toolsAllow.some((name) => name.trim() === "*");
4876
5312
  }
4877
5313
  async function prepareCodexAttemptPrompt(context) {
4878
- const { runtime, attemptTools, historyState, hookContext, workspaceBootstrapContext, buildActiveContextEngineRuntimeContext, baseDeveloperInstructions, openClawPromptContext, skillsCollaborationInstructions, promptState, codexContextProjectionMaxChars } = context;
5314
+ const { runtime, attemptTools, historyState, hookContext, workspaceBootstrapContext, buildActiveContextEngineRuntimeContext, baseDeveloperInstructions, openClawPromptContext, skillsCollaborationInstructions, promptState, codexContextProjectionMaxChars, codexContinuityProjectionMaxChars } = context;
4879
5315
  const { connection, buildActiveRunAttemptParams, effectiveContextTokenBudget, effectiveRuntimeModelId, effectiveRuntimeProviderId } = runtime;
4880
5316
  const { params, activeContextEngine, usesSupervisionConnection, mutable, isInactiveThreadBootstrapBinding, bindingStore, bindingIdentity, agentDir, appServer, contextSessionKey, effectiveWorkspace, sandbox } = connection;
4881
5317
  const { toolBridge } = attemptTools;
@@ -4884,11 +5320,12 @@ async function prepareCodexAttemptPrompt(context) {
4884
5320
  assembledMessages: historyState.messages,
4885
5321
  originalHistoryMessages: historyState.messages,
4886
5322
  prompt: params.prompt,
4887
- maxRenderedContextChars: codexContextProjectionMaxChars
5323
+ maxRenderedContextChars: codexContinuityProjectionMaxChars
4888
5324
  });
4889
5325
  promptState.promptText = projection.promptText;
4890
5326
  promptState.promptContextRange = projection.promptContextRange;
4891
5327
  promptState.prePromptMessageCount = projection.prePromptMessageCount;
5328
+ promptState.noEngineContinuityProjectionApplied = true;
4892
5329
  };
4893
5330
  const applyActiveContextEngineProjection = async (decisionStartupBinding) => {
4894
5331
  if (!activeContextEngine) return;
@@ -4962,15 +5399,21 @@ async function prepareCodexAttemptPrompt(context) {
4962
5399
  }
4963
5400
  const codexModelInputHistoryMessages = [];
4964
5401
  const buildPromptFromCurrentInputs = async () => {
4965
- const result = await resolveAgentHarnessBeforePromptBuildResult({
5402
+ return await resolveAgentHarnessBeforePromptBuildResult({
4966
5403
  prompt: prependCurrentInboundContext(promptState.promptText, params.currentInboundContext),
4967
- developerInstructions: promptState.developerInstructions,
5404
+ developerInstructions: { build: ({ toolsAllow }) => {
5405
+ if (isRestrictivePromptToolsAllow(toolsAllow)) throw new Error("Codex app-server cannot enforce before_prompt_build toolsAllow; use the embedded or Copilot runtime for turn-scoped tool policy.");
5406
+ return promptState.developerInstructions;
5407
+ } },
4968
5408
  messages: structuredClone(historyState.messages),
4969
5409
  ctx: hookContext,
4970
- bootstrapContextRunKind: params.bootstrapContextRunKind
5410
+ bootstrapContextRunKind: params.bootstrapContextRunKind,
5411
+ toolAuthority: {
5412
+ fingerprint: params.toolAuthorityFingerprint,
5413
+ activeToolNames: () => flattenCodexDynamicToolFunctions(toolBridge.availableSpecs).map((tool) => tool.name).filter(isNonEmptyString),
5414
+ assertActive: params.hostCapabilities.assertActive
5415
+ }
4971
5416
  });
4972
- if (isRestrictivePromptToolsAllow(result.toolsAllow)) throw new Error("Codex app-server cannot enforce before_prompt_build toolsAllow; use the embedded or Copilot runtime for turn-scoped tool policy.");
4973
- return result;
4974
5417
  };
4975
5418
  const resolveShiftedPromptInputRange = (prompt, promptInputRange, turnPromptText) => {
4976
5419
  if (!promptInputRange || promptInputRange.start < 0 || promptInputRange.end < promptInputRange.start || promptInputRange.end > prompt.length || !turnPromptText.endsWith(prompt)) return;
@@ -5040,12 +5483,11 @@ async function prepareCodexAttemptPrompt(context) {
5040
5483
  const cutoff = Date.parse(binding.historyCoveredThrough ?? "");
5041
5484
  return historyState.messages.filter((message) => {
5042
5485
  if (message.role !== "user" && message.role !== "assistant") return false;
5043
- const record = message;
5044
- const meta = record["__openclaw"];
5486
+ const meta = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
5045
5487
  const mirrorIdentity = meta && typeof meta === "object" && !Array.isArray(meta) ? meta.mirrorIdentity : void 0;
5046
5488
  const mirrorOrigin = meta && typeof meta === "object" && !Array.isArray(meta) ? meta.mirrorOrigin : void 0;
5047
5489
  const timestamp = typeof message.timestamp === "number" ? message.timestamp : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
5048
- return !(typeof record.idempotencyKey === "string" && record.idempotencyKey.startsWith("codex-app-server:")) && mirrorOrigin !== "codex-app-server" && !(typeof mirrorIdentity === "string" && mirrorIdentity.startsWith("codex-app-server:")) && Number.isFinite(timestamp) && timestamp > (Number.isFinite(cutoff) ? cutoff : 0);
5490
+ return !("idempotencyKey" in message && typeof message.idempotencyKey === "string" && message.idempotencyKey.startsWith("codex-app-server:")) && mirrorOrigin !== "codex-app-server" && !(typeof mirrorIdentity === "string" && mirrorIdentity.startsWith("codex-app-server:")) && Number.isFinite(timestamp) && timestamp > (Number.isFinite(cutoff) ? cutoff : 0);
5049
5491
  });
5050
5492
  };
5051
5493
  const applyResumeStaleBindingContinuityProjection = (binding) => {
@@ -5055,11 +5497,12 @@ async function prepareCodexAttemptPrompt(context) {
5055
5497
  assembledMessages: newerVisibleMessages,
5056
5498
  originalHistoryMessages: historyState.messages,
5057
5499
  prompt: params.prompt,
5058
- maxRenderedContextChars: codexContextProjectionMaxChars
5500
+ maxRenderedContextChars: codexContinuityProjectionMaxChars
5059
5501
  });
5060
5502
  promptState.promptText = projection.promptText;
5061
5503
  promptState.promptContextRange = projection.promptContextRange;
5062
5504
  promptState.prePromptMessageCount = projection.prePromptMessageCount;
5505
+ promptState.noEngineContinuityProjectionApplied = true;
5063
5506
  return true;
5064
5507
  };
5065
5508
  const precomputeNoContextEngineStaleBindingProjection = () => {
@@ -5171,15 +5614,13 @@ function prepareCodexAttemptResources(prompt) {
5171
5614
  const { connection, hookChannelId } = runtime;
5172
5615
  const { appServer, params, effectiveCwd, sessionAgentId, sandboxSessionKey, runAbortController, sandbox, options, nativeHookRelayEvents } = connection;
5173
5616
  const { toolBridge } = attemptTools;
5174
- const hostTrajectoryRecorder = params.trajectoryRecorder;
5175
5617
  const trajectoryRecorder = createCodexTrajectoryRecorder({
5176
5618
  attempt: params,
5177
5619
  cwd: effectiveCwd,
5178
5620
  developerInstructions: buildRenderedCodexDeveloperInstructions(),
5179
5621
  prompt: turnState.codexTurnPromptText,
5180
- trajectoryRecorder: hostTrajectoryRecorder,
5181
- tools: toolBridge.availableSpecs,
5182
- warn: (message, fields) => embeddedAgentLog.warn(message, fields)
5622
+ trajectory: params.hostCapabilities.trajectory,
5623
+ tools: toolBridge.availableSpecs
5183
5624
  });
5184
5625
  const state = {
5185
5626
  client: void 0,
@@ -5192,12 +5633,14 @@ function prepareCodexAttemptResources(prompt) {
5192
5633
  trajectoryEndRecorded: false,
5193
5634
  nativeHookRelay: void 0,
5194
5635
  nativeSubagentMonitor: void 0,
5636
+ runtimeContinuationStarted: false,
5195
5637
  nativePreToolUseFailureFallbackActive: false,
5196
5638
  nativePreToolUseFailureFallbackTerminalReason: void 0,
5197
5639
  releaseSharedClientLease: void 0,
5198
5640
  startupClientUnsafe: false,
5199
5641
  sharedCodexClientRetiredForOneShotCleanup: false,
5200
- sandboxExecEnvironmentAcquired: false,
5642
+ sandboxExecEnvironment: void 0,
5643
+ executionDisconnectError: void 0,
5201
5644
  codexEnvironmentSelection: void 0,
5202
5645
  codexExecutionCwd: effectiveCwd,
5203
5646
  codexSandboxPolicy: void 0,
@@ -5236,7 +5679,7 @@ function prepareCodexAttemptResources(prompt) {
5236
5679
  if (params.cleanupBundleMcpOnRunEnd !== true || state.sharedCodexClientRetiredForOneShotCleanup) return;
5237
5680
  state.sharedCodexClientRetiredForOneShotCleanup = true;
5238
5681
  const retired = clearSharedCodexAppServerClientIfCurrentAndUnclaimed(state.client);
5239
- embeddedAgentLog.info("codex app-server one-shot cleanup checked shared client retirement", {
5682
+ embeddedAgentLog.debug("codex app-server one-shot cleanup checked shared client retirement", {
5240
5683
  runId: params.runId,
5241
5684
  sessionId: params.sessionId,
5242
5685
  sessionKey: params.sessionKey,
@@ -5250,16 +5693,27 @@ function prepareCodexAttemptResources(prompt) {
5250
5693
  forceKillDelayMs: 250
5251
5694
  });
5252
5695
  };
5696
+ const releaseSandboxExecEnvironment = async () => {
5697
+ if (state.sandboxExecEnvironment) {
5698
+ const environment = state.sandboxExecEnvironment;
5699
+ state.sandboxExecEnvironment = void 0;
5700
+ await releaseCodexSandboxExecServerEnvironment(sandbox, environment);
5701
+ }
5702
+ };
5253
5703
  const releaseSharedClientLeaseAndRetireOneShotClient = async () => {
5704
+ if (connection.attemptClientFactory === createIsolatedCodexAppServerClient) {
5705
+ await releaseSandboxExecEnvironment();
5706
+ const ownedClient = state.releaseSharedClientLease ? state.client : void 0;
5707
+ releaseSharedClientLeaseOnce();
5708
+ await ownedClient?.closeAndWait({
5709
+ exitTimeoutMs: 2e3,
5710
+ forceKillDelayMs: 250
5711
+ });
5712
+ return;
5713
+ }
5254
5714
  releaseSharedClientLeaseOnce();
5255
5715
  await retireSharedCodexClientForOneShotCleanup();
5256
5716
  };
5257
- const releaseSandboxExecEnvironment = async () => {
5258
- if (state.sandboxExecEnvironmentAcquired) {
5259
- state.sandboxExecEnvironmentAcquired = false;
5260
- await releaseCodexSandboxExecServerEnvironment(sandbox);
5261
- }
5262
- };
5263
5717
  const runCleanupStep = (step, operation) => runAgentCleanupStep({
5264
5718
  runId: params.runId,
5265
5719
  sessionId: params.sessionId,
@@ -5284,7 +5738,10 @@ function prepareCodexAttemptResources(prompt) {
5284
5738
  retainClient: () => retainSharedCodexAppServerClientIfCurrent(state.client),
5285
5739
  retainParentThread: (protectedThreadId) => protectCodexAppServerLiveThread(state.client, protectedThreadId),
5286
5740
  claimDirectChild: (childThreadId) => state.nativeHookRelay?.claimDirectChild(childThreadId),
5287
- rejectPendingDirectChild: (childThreadId, reason) => state.nativeHookRelay?.rejectPendingDirectChild(childThreadId, reason)
5741
+ rejectPendingDirectChild: (childThreadId, reason) => state.nativeHookRelay?.rejectPendingDirectChild(childThreadId, reason),
5742
+ ...params.sessionKey && params.agentHarnessTaskRuntimeScope ? { onDirectChildAccepted: () => {
5743
+ state.runtimeContinuationStarted = true;
5744
+ } } : {}
5288
5745
  });
5289
5746
  };
5290
5747
  const releaseCurrentRoute = () => {
@@ -5347,8 +5804,7 @@ function prepareCodexAttemptResources(prompt) {
5347
5804
  configPatch: state.nativeHookRelay ? buildCodexNativeHookRelayConfig({
5348
5805
  relay: state.nativeHookRelay,
5349
5806
  events: nativeHookRelayEvents,
5350
- hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec,
5351
- loopDetectionPreToolUseRelay: appServer.loopDetectionPreToolUseRelay
5807
+ hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec
5352
5808
  }) : options.nativeHookRelay?.enabled === false ? buildCodexNativeHookRelayDisabledConfig() : void 0,
5353
5809
  nativeHookRelayGeneration: state.nativeHookRelay?.generation
5354
5810
  };
@@ -5480,10 +5936,6 @@ function resolveScheduledCodexAppCreatorCaptureDecision(params) {
5480
5936
  ...unavailableReason ? { unavailableReason } : {}
5481
5937
  };
5482
5938
  }
5483
- function readConnectorId(tool) {
5484
- const meta = asOptionalRecord(asOptionalRecord(tool)?.["_meta"]);
5485
- return normalizeOptionalString(meta?.connector_id) ?? normalizeOptionalString(meta?.connectorId);
5486
- }
5487
5939
  function normalizeApprovalMode(value) {
5488
5940
  return value === "allow" || value === "deny" || value === "auto" || value === "ask" ? value : void 0;
5489
5941
  }
@@ -5550,7 +6002,7 @@ async function readCodexScheduledAppToolNamesByApp(params) {
5550
6002
  if (!isJsonObject(status) || !isJsonObject(status.tools)) throw new Error("Codex scheduled app inventory contained an invalid server status");
5551
6003
  if (status.name !== CODEX_APPS_MCP_SERVER) continue;
5552
6004
  for (const [toolName, tool] of Object.entries(status.tools)) {
5553
- const connectorId = readConnectorId(tool);
6005
+ const connectorId = readCodexMcpToolConnectorId(tool);
5554
6006
  if (connectorId) {
5555
6007
  const names = toolNamesByApp.get(connectorId) ?? /* @__PURE__ */ new Set();
5556
6008
  names.add(toolName);
@@ -5783,8 +6235,8 @@ async function prepareCodexAttemptRuntime(connection) {
5783
6235
  const effectiveContextWindowInfo = usesSupervisionConnection ? void 0 : params.contextWindowInfo;
5784
6236
  const effectiveContextTokenBudget = usesSupervisionConnection ? void 0 : params.contextTokenBudget;
5785
6237
  const effectiveRuntimeProviderId = usesSupervisionConnection ? mutable.startupBinding?.modelProvider ?? "codex" : params.provider;
5786
- const effectiveRuntimeModelId = usesSupervisionConnection ? mutable.startupBinding?.model ?? "codex-native" : params.modelId;
5787
- const { authProfileId: _outerAuthProfileId, contextWindowInfo: _outerContextWindowInfo, contextTokenBudget: _outerContextTokenBudget, model: _outerModel, modelId: _outerModelId, provider: _outerProvider, runtimePlan: _outerRuntimePlan, requestedModelId: _outerRequestedModelId, fallbackReason: _outerFallbackReason, degradedReason: _outerDegradedReason, thinkLevel: _outerThinkLevel, fastMode: _outerFastMode, ...paramsWithoutOuterNativeOwnership } = params;
6238
+ const effectiveRuntimeModelId = usesSupervisionConnection ? mutable.startupBinding?.model ?? "codex-native" : connection.options.runtimeModelId ?? params.modelId;
6239
+ const { authProfileId: _outerAuthProfileId, authoredContextTokenCap: _outerAuthoredContextTokenCap, contextWindowInfo: _outerContextWindowInfo, contextTokenBudget: _outerContextTokenBudget, model: _outerModel, modelId: _outerModelId, provider: _outerProvider, runtimePlan: _outerRuntimePlan, requestedModelId: _outerRequestedModelId, fallbackReason: _outerFallbackReason, degradedReason: _outerDegradedReason, thinkLevel: _outerThinkLevel, fastMode: _outerFastMode, ...paramsWithoutOuterNativeOwnership } = params;
5788
6240
  const supervisedRuntimeModel = {
5789
6241
  id: effectiveRuntimeModelId,
5790
6242
  name: effectiveRuntimeModelId,
@@ -6017,18 +6469,23 @@ function resolveCodexDynamicToolDirectNames(params, hostSystemAgentActive = fals
6017
6469
  const names = [];
6018
6470
  if (hostSystemAgentActive && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow)) names.push("openclaw");
6019
6471
  if (params.sourceReplyDeliveryMode === "message_tool_only") names.push("message");
6020
- if (params.pluginHarnessToolPolicyRestricted === true) names.push("update_plan");
6472
+ names.push("progress_card");
6021
6473
  return names;
6022
6474
  }
6023
6475
  //#endregion
6024
6476
  //#region extensions/codex/src/app-server/run-attempt-server-requests.ts
6477
+ const DYNAMIC_TOOL_TERMINAL_DIAGNOSTIC_TYPES = [
6478
+ "tool.execution.completed",
6479
+ "tool.execution.error",
6480
+ "tool.execution.blocked"
6481
+ ];
6025
6482
  function createCodexAttemptServerRequestController(resources, turnRuntime, lifecycle) {
6026
6483
  const { prompt, state: resourceState, projectorRef, trajectoryRecorder } = resources;
6027
6484
  const { context } = prompt;
6028
6485
  const { runtime, attemptTools } = context;
6029
6486
  const { connection } = runtime;
6030
- const { params, computerUseConfig, runAbortController, appServer, approvalPolicyPromotedForOpenClawToolPolicy, sessionAgentId } = connection;
6031
- const { toolBridge, toolOutcomeOrdinals, suppressedDynamicToolOutcomeOrdinals, allocateCodexToolOutcomeOrdinal } = attemptTools;
6487
+ const { params, computerUseConfig, runAbortController, appServer, sessionAgentId } = connection;
6488
+ const { compactionPlanState, toolBridge, toolOutcomeOrdinals, suppressedDynamicToolOutcomeOrdinals, allocateCodexToolOutcomeOrdinal } = attemptTools;
6032
6489
  const { state, turnIdRef, userInputBridgeRef, openClawDynamicToolExecutions, pendingOpenClawDynamicToolCompletionIds, postToolRawAssistantCompletionIdleTimeoutMs, turnWatches } = turnRuntime;
6033
6490
  const { emitExecutionPhaseOnce, scheduleTurnReleaseAfterTerminalDynamicTool, scheduleTerminalDynamicToolReleaseCheck } = lifecycle;
6034
6491
  const handleServerRequest = async (request, scope, requestSignal = new AbortController().signal) => {
@@ -6054,7 +6511,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
6054
6511
  armCompletionWatchOnResponse = true;
6055
6512
  markCurrentTurnRequestProgress();
6056
6513
  }
6057
- return await handleCodexAppServerElicitationRequest({
6514
+ const approvalResult = await routeCodexAppServerElicitationRequest({
6058
6515
  requestParams: request.params,
6059
6516
  paramsForRun: params,
6060
6517
  threadId: resourceState.thread.threadId,
@@ -6063,6 +6520,11 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
6063
6520
  ...computerUseConfig.enabled ? { computerUseMcpServerName: computerUseConfig.mcpServerName } : {},
6064
6521
  signal
6065
6522
  });
6523
+ if (approvalResult.kind === "handled") return approvalResult.response;
6524
+ return await userInputBridgeRef.current?.handleElicitationRequest({
6525
+ id: request.id,
6526
+ params: request.params
6527
+ });
6066
6528
  }
6067
6529
  if (request.method === "item/tool/requestUserInput") {
6068
6530
  if (scope.turnId === turnId) {
@@ -6088,9 +6550,8 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
6088
6550
  turnId,
6089
6551
  nativeHookRelay: resourceState.nativeHookRelay,
6090
6552
  autoApprove: shouldAutoApproveCodexAppServerApprovals(appServer),
6091
- autoApproveOpenClawToolPolicy: approvalPolicyPromotedForOpenClawToolPolicy,
6092
6553
  signal,
6093
- onNativeToolFailureDisposition: (itemId, disposition) => projector?.recordNativeToolApprovalFailure(itemId, disposition)
6554
+ onNativeToolFailureDisposition: (itemId, disposition, approvalKind) => projector?.recordNativeToolApprovalFailure(itemId, disposition, approvalKind)
6094
6555
  });
6095
6556
  }
6096
6557
  return;
@@ -6126,13 +6587,6 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
6126
6587
  tool: call.tool,
6127
6588
  toolCallId: call.callId
6128
6589
  });
6129
- emitDynamicToolStartedDiagnostic({
6130
- call,
6131
- agentId: sessionAgentId,
6132
- runId: params.runId,
6133
- sessionId: params.sessionId,
6134
- sessionKey: params.sessionKey
6135
- });
6136
6590
  const toolMeta = inferCodexDynamicToolMeta(call, resolveCodexToolProgressDetailMode(params.toolProgressDetail));
6137
6591
  const toolArgs = sanitizeCodexToolArguments(call.arguments);
6138
6592
  const commandBearing = isCodexCommandBearingToolCall(call.tool, toolArgs);
@@ -6162,30 +6616,39 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
6162
6616
  sessionId: params.sessionId,
6163
6617
  sessionKey: params.sessionKey
6164
6618
  })) terminalDiagnosticObserved = true;
6165
- });
6619
+ }, { include: DYNAMIC_TOOL_TERMINAL_DIAGNOSTIC_TYPES });
6166
6620
  try {
6167
- const { execution } = openClawDynamicToolExecutions.claim(call, () => handleDynamicToolCallWithTimeout({
6168
- call,
6169
- toolBridge,
6170
- signal,
6171
- timeoutMs: dynamicToolTimeoutMs,
6172
- toolMeta,
6173
- toolCallOrdinal,
6174
- onAgentToolResult: params.onAgentToolResult,
6175
- observeToolTerminal: params.observeToolTerminal,
6176
- onFallbackSelected: () => {
6177
- if (toolCallOrdinal !== void 0) suppressedDynamicToolOutcomeOrdinals.add(toolCallOrdinal);
6178
- },
6179
- onTimeout: () => {
6180
- trajectoryRecorder?.recordEvent("tool.timeout", {
6181
- threadId: call.threadId,
6182
- turnId: call.turnId,
6183
- toolCallId: call.callId,
6184
- name: call.tool,
6185
- timeoutMs: dynamicToolTimeoutMs
6186
- });
6187
- }
6188
- }));
6621
+ const { execution } = openClawDynamicToolExecutions.claim(call, () => {
6622
+ emitDynamicToolStartedDiagnostic({
6623
+ call,
6624
+ agentId: sessionAgentId,
6625
+ runId: params.runId,
6626
+ sessionId: params.sessionId,
6627
+ sessionKey: params.sessionKey
6628
+ });
6629
+ return handleDynamicToolCallWithTimeout({
6630
+ call,
6631
+ toolBridge,
6632
+ signal,
6633
+ timeoutMs: dynamicToolTimeoutMs,
6634
+ toolMeta,
6635
+ toolCallOrdinal,
6636
+ onAgentToolResult: params.onAgentToolResult,
6637
+ observeToolTerminal: params.observeToolTerminal,
6638
+ onFallbackSelected: () => {
6639
+ if (toolCallOrdinal !== void 0) suppressedDynamicToolOutcomeOrdinals.add(toolCallOrdinal);
6640
+ },
6641
+ onTimeout: () => {
6642
+ trajectoryRecorder?.recordEvent("tool.timeout", {
6643
+ threadId: call.threadId,
6644
+ turnId: call.turnId,
6645
+ toolCallId: call.callId,
6646
+ name: call.tool,
6647
+ timeoutMs: dynamicToolTimeoutMs
6648
+ });
6649
+ }
6650
+ });
6651
+ });
6189
6652
  const response = await execution;
6190
6653
  const protocolResponse = toCodexDynamicToolProtocolResponse(response);
6191
6654
  if (!protocolResponse.success && toolCallOrdinal !== void 0) {
@@ -6209,7 +6672,11 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
6209
6672
  contentItems: protocolResponse.contentItems
6210
6673
  });
6211
6674
  recordCodexDynamicToolResult(projector, call, response, protocolResponse);
6212
- if (protocolResponse.success && call.tool === "update_plan") projector?.recordDynamicPlanUpdate(response.executedArguments ?? call.arguments);
6675
+ if (protocolResponse.success && call.tool === "progress_card") {
6676
+ const progressCardInput = response.executedArguments ?? call.arguments;
6677
+ await projector?.recordDynamicProgressCardUpdate(progressCardInput);
6678
+ compactionPlanState.recordProgressCardInput(progressCardInput);
6679
+ }
6213
6680
  if (shouldEmitDynamicToolProgress) {
6214
6681
  const progressResponse = toCodexDynamicToolProgressResponse(response, protocolResponse);
6215
6682
  emitCodexAppServerEvent(params, {
@@ -6289,6 +6756,20 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
6289
6756
  return { handleServerRequest };
6290
6757
  }
6291
6758
  //#endregion
6759
+ //#region extensions/codex/src/app-server/attempt-runtime-artifact.ts
6760
+ async function verifyStartupArtifact(params) {
6761
+ if (!params.request) return;
6762
+ const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-BvyT1uyd.js");
6763
+ const runtimeArtifact = readCodexAppServerClientRuntimeArtifact(params.client);
6764
+ const expected = params.request.expected;
6765
+ const matchesExpected = !expected || runtimeArtifact?.id === expected.id && runtimeArtifact.fingerprint === expected.fingerprint;
6766
+ if (!runtimeArtifact || !matchesExpected || !await validateCodexAppServerRuntimeArtifact(runtimeArtifact, params.signal)) {
6767
+ retireSharedCodexAppServerClientIfCurrent(params.client);
6768
+ throw new Error(expected ? "Codex app-server runtime artifact does not match verified inference" : "Codex app-server runtime artifact is unavailable or stale");
6769
+ }
6770
+ return runtimeArtifact;
6771
+ }
6772
+ //#endregion
6292
6773
  //#region extensions/codex/src/app-server/computer-use-health.ts
6293
6774
  const COMPUTER_USE_HEALTH_MONITOR_STATE = Symbol.for("openclaw.codexComputerUseHealthMonitorState");
6294
6775
  function getComputerUseHealthMonitorState() {
@@ -6308,19 +6789,17 @@ function startCodexComputerUseHealthMonitor(params) {
6308
6789
  }
6309
6790
  const fingerprint = buildComputerUseHealthMonitorFingerprint(params.config);
6310
6791
  const intervalMs = params.config.healthCheckIntervalMinutes * 6e4;
6311
- if (existing?.fingerprint === fingerprint && existing.repairComputerUseMcpChildren === params.repairComputerUseMcpChildren) return {
6792
+ if (existing?.fingerprint === fingerprint) return {
6312
6793
  started: false,
6313
6794
  intervalMs,
6314
6795
  reason: "already_started"
6315
6796
  };
6316
6797
  if (existing) clearComputerUseHealthMonitor(params.client, existing);
6317
- const repairComputerUseMcpChildren = params.repairComputerUseMcpChildren ?? (() => killStaleComputerUseMcpChildren({ ancestorPid: params.client.getTransportPid() }));
6318
6798
  const monitor = {
6319
6799
  fingerprint,
6320
6800
  intervalMs,
6321
- repairComputerUseMcpChildren: params.repairComputerUseMcpChildren,
6322
6801
  timer: setInterval(() => {
6323
- runCodexComputerUseHealthProbe(params.client, params.config, monitor, { repairComputerUseMcpChildren });
6802
+ runCodexComputerUseHealthProbe(params.client, params.config, monitor);
6324
6803
  }, intervalMs),
6325
6804
  disposeCloseHandler: () => void 0,
6326
6805
  running: false
@@ -6345,13 +6824,12 @@ function buildComputerUseHealthMonitorFingerprint(config) {
6345
6824
  toolCallTimeoutMs: config.toolCallTimeoutMs
6346
6825
  });
6347
6826
  }
6348
- async function runCodexComputerUseHealthProbe(client, config, monitor, options) {
6827
+ async function runCodexComputerUseHealthProbe(client, config, monitor) {
6349
6828
  if (monitor.running) return;
6350
6829
  monitor.running = true;
6351
6830
  try {
6352
6831
  const { liveTest, repair } = await runCodexComputerUseLiveTest({
6353
6832
  config,
6354
- repairComputerUseMcpChildren: options.repairComputerUseMcpChildren,
6355
6833
  request: async (method, requestParams, requestOptions) => await client.request(method, requestParams, { timeoutMs: requestOptions?.timeoutMs ?? config.liveTestTimeoutMs })
6356
6834
  });
6357
6835
  if (!liveTest.ok) {
@@ -6364,10 +6842,7 @@ async function runCodexComputerUseHealthProbe(client, config, monitor, options)
6364
6842
  });
6365
6843
  return;
6366
6844
  }
6367
- if (repair?.killedPids.length) embeddedAgentLog.info("codex computer-use periodic health repaired stale children", {
6368
- mcpServerName: config.mcpServerName,
6369
- killedPids: repair.killedPids
6370
- });
6845
+ if (repair?.attempted && repair.warnings.length === 0) embeddedAgentLog.info("codex computer-use periodic health reloaded MCP servers", { mcpServerName: config.mcpServerName });
6371
6846
  } catch (error) {
6372
6847
  embeddedAgentLog.warn("codex computer-use periodic health probe crashed", {
6373
6848
  mcpServerName: config.mcpServerName,
@@ -6462,6 +6937,7 @@ function createCodexPluginThreadConfigStartupProvider(params) {
6462
6937
  build: async (buildOptions) => {
6463
6938
  const config = await buildCodexPluginThreadConfigWithinDeadline({
6464
6939
  ...buildParams,
6940
+ threadId: buildOptions?.threadId,
6465
6941
  appCache: appCache ?? defaultCodexAppInventoryCache,
6466
6942
  metadataCache,
6467
6943
  failClosedOnTimeout: Boolean(params.scheduledRuntimeAuthority),
@@ -6494,7 +6970,7 @@ function isCodexPluginThreadConfigTimeoutError(error) {
6494
6970
  * Startup orchestration for Codex app-server attempts, including shared-client
6495
6971
  * leasing, plugin thread config, sandbox environment, and thread lifecycle binding.
6496
6972
  */
6497
- const CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS = 3;
6973
+ const CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS = 3;
6498
6974
  const CODEX_APP_SERVER_CONTEXT_RESTART_SELECTION_CHANGED = "CODEX_APP_SERVER_CONTEXT_RESTART_SELECTION_CHANGED";
6499
6975
  /** True when a pre-write context restart must replay on the newly selected owner. */
6500
6976
  function isCodexContextRestartSelectionChangedError(error) {
@@ -6575,24 +7051,19 @@ async function startCodexAttemptThread(params) {
6575
7051
  startupClientLease = () => {
6576
7052
  if (startupClientLeaseReleased) return;
6577
7053
  startupClientLeaseReleased = true;
6578
- releaseLeasedSharedCodexAppServerClient(activeStartupClient);
7054
+ if (params.attemptClientFactory === createIsolatedCodexAppServerClient) activeStartupClient.close();
7055
+ else releaseLeasedSharedCodexAppServerClient(activeStartupClient);
6579
7056
  };
6580
7057
  releaseSharedClientLease = startupClientLease;
6581
7058
  attemptedClient = activeStartupClient;
6582
7059
  startupClientForAbandonedRequestCleanup = activeStartupClient;
6583
7060
  if (startupAbandoned) throw new CodexAppServerStartupError("timed_out");
6584
7061
  if (startupAbandonController.signal.aborted) throw new CodexAppServerStartupError("aborted");
6585
- let runtimeArtifact;
6586
- if (params.runtimeArtifactRequest) {
6587
- const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-BVSPdd6g.js");
6588
- runtimeArtifact = readCodexAppServerClientRuntimeArtifact(activeStartupClient);
6589
- const expected = params.runtimeArtifactRequest.expected;
6590
- const matchesExpected = !expected || Boolean(runtimeArtifact && runtimeArtifact.id === expected.id && runtimeArtifact.fingerprint === expected.fingerprint);
6591
- if (!runtimeArtifact || !matchesExpected || !await validateCodexAppServerRuntimeArtifact(runtimeArtifact, startupAbandonController.signal)) {
6592
- retireSharedCodexAppServerClientIfCurrent(activeStartupClient);
6593
- throw new Error(expected ? "Codex app-server runtime artifact does not match verified inference" : "Codex app-server runtime artifact is unavailable or stale");
6594
- }
6595
- }
7062
+ const runtimeArtifact = await verifyStartupArtifact({
7063
+ client: activeStartupClient,
7064
+ request: params.runtimeArtifactRequest,
7065
+ signal: startupAbandonController.signal
7066
+ });
6596
7067
  ensureCodexAppServerClientRuntime(activeStartupClient, {
6597
7068
  agentDir: params.agentDir,
6598
7069
  authProfileId: startupRuntimeAuthProfileId,
@@ -6611,7 +7082,7 @@ async function startCodexAttemptThread(params) {
6611
7082
  signal: startupAbandonController.signal
6612
7083
  });
6613
7084
  } catch (error) {
6614
- if (startupAbandonController.signal.aborted) throw error;
7085
+ if (startupAbandonController.signal.aborted || isCodexAppServerStartSelectionChangedError(error)) throw error;
6615
7086
  throw new AgentHarnessPreflightError(`Codex Computer Use readiness failed: ${formatErrorMessage(error)}`, {
6616
7087
  cause: error,
6617
7088
  scope: "harness"
@@ -6625,7 +7096,8 @@ async function startCodexAttemptThread(params) {
6625
7096
  accountId: params.startupAuthAccountCacheKey,
6626
7097
  envApiKeyFingerprint: params.startupEnvApiKeyCacheKey,
6627
7098
  appServerVersion: activeStartupClient.getServerVersion(),
6628
- runtimeIdentity: startupRuntimeIdentity
7099
+ runtimeIdentity: startupRuntimeIdentity,
7100
+ desktopGenerationFingerprint: readCodexAppServerClientDesktopGenerationFingerprint(activeStartupClient)
6629
7101
  });
6630
7102
  const appServerRuntimeFingerprint = buildCodexAppServerRuntimeFingerprint({
6631
7103
  appServer: params.appServer,
@@ -6652,7 +7124,7 @@ async function startCodexAttemptThread(params) {
6652
7124
  const releaseStartupSandboxEnvironment = async () => {
6653
7125
  if (startupSandboxEnvironmentAcquired) {
6654
7126
  startupSandboxEnvironmentAcquired = false;
6655
- await releaseCodexSandboxExecServerEnvironment(params.sandbox);
7127
+ await releaseCodexSandboxExecServerEnvironment(params.sandbox, startupSandboxEnvironment);
6656
7128
  }
6657
7129
  };
6658
7130
  releaseStartupResourcesOnTimeout = releaseStartupSandboxEnvironment;
@@ -6665,9 +7137,11 @@ async function startCodexAttemptThread(params) {
6665
7137
  startupSandboxEnvironment = sandboxEnvironmentRequired ? await ensureCodexSandboxExecServerEnvironment({
6666
7138
  client: activeStartupClient,
6667
7139
  sandbox: params.sandbox ?? null,
7140
+ runtime: params.runtime,
6668
7141
  appServerStartOptions: params.appServer.start,
6669
7142
  timeoutMs: params.appServer.requestTimeoutMs,
6670
- signal: startupAbandonController.signal
7143
+ signal: AbortSignal.any([params.signal, startupAbandonController.signal]),
7144
+ onExecutionDisconnect: params.onExecutionDisconnect
6671
7145
  }) : void 0;
6672
7146
  startupSandboxEnvironmentAcquired = Boolean(startupSandboxEnvironment);
6673
7147
  if (startupAbandonController.signal.aborted) {
@@ -6711,17 +7185,23 @@ async function startCodexAttemptThread(params) {
6711
7185
  reserveResumeThread,
6712
7186
  bindingStore: params.bindingStore,
6713
7187
  params: params.buildAttemptParams(),
7188
+ runtimeModelId: params.runtimeModelId,
6714
7189
  agentId: params.sessionAgentId,
7190
+ agentDir: params.agentDir,
6715
7191
  cwd: startupExecutionCwd,
6716
7192
  dynamicTools: params.dynamicTools,
6717
7193
  persistentWebSearchAllowed: params.persistentWebSearchAllowed,
6718
7194
  webSearchAllowed: params.webSearchAllowed,
6719
7195
  appServer: pluginAppServer,
6720
7196
  developerInstructions: params.developerInstructions,
7197
+ agentWorkspaceDeveloperInstructions: params.agentWorkspaceDeveloperInstructions,
6721
7198
  config: threadConfig,
7199
+ shellEnvironment: params.shellEnvironment,
7200
+ disableLoginShell: params.disableLoginShell,
6722
7201
  finalConfigPatch: params.finalConfigPatch,
6723
7202
  buildFinalConfigPatch: params.buildFinalConfigPatch,
6724
7203
  nativeHookRelayGeneration: params.nativeHookRelayGeneration,
7204
+ nativeHookRelayRequired: params.nativeHookRelayRequired,
6725
7205
  nativeCodeModeEnabled: params.nativeToolSurfaceEnabled,
6726
7206
  nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
6727
7207
  nativeCodeModeOnlyEnabled: params.appServer.codeModeOnly,
@@ -6816,30 +7296,31 @@ async function startCodexAttemptThread(params) {
6816
7296
  }
6817
7297
  }
6818
7298
  };
6819
- for (let attempt = 1; attempt <= CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS; attempt += 1) try {
7299
+ for (let attempt = 1; attempt <= CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS; attempt += 1) try {
6820
7300
  return await startupAttempt();
6821
7301
  } catch (error) {
6822
7302
  const selectionChanged = isCodexAppServerStartSelectionChangedError(error);
6823
7303
  if (startupAbandoned || params.signal.aborted || !selectionChanged && !isCodexAppServerConnectionClosedError(error)) throw error;
6824
- const failedClient = attemptedClient;
6825
- const refreshedSharedClient = selectionChanged ? retireSharedCodexAppServerClientIfCurrent(failedClient) : clearSharedCodexAppServerClientIfCurrent(failedClient);
6826
- if (startupClientForAbandonedRequestCleanup === failedClient) startupClientForAbandonedRequestCleanup = void 0;
6827
- if (attempt >= CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS) {
7304
+ const refreshedSharedClient = selectionChanged ? retireSharedCodexAppServerClientIfCurrent(attemptedClient) : clearSharedCodexAppServerClientIfCurrent(attemptedClient);
7305
+ if (startupClientForAbandonedRequestCleanup === attemptedClient) startupClientForAbandonedRequestCleanup = void 0;
7306
+ if (attempt >= CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS) {
6828
7307
  embeddedAgentLog.warn(selectionChanged ? "codex app-server executable selection kept changing during startup; retries exhausted" : "codex app-server connection closed during startup; retries exhausted", {
6829
7308
  attempt,
6830
- maxAttempts: CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS,
7309
+ maxAttempts: CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS,
6831
7310
  refreshedSharedClient,
6832
7311
  error: formatErrorMessage(error)
6833
7312
  });
6834
7313
  throw error;
6835
7314
  }
7315
+ const retryDelayMs = selectionChanged ? 0 : 1e3 * 2 ** (attempt - 1);
6836
7316
  embeddedAgentLog.warn(selectionChanged ? "codex app-server executable selection changed during startup; restarting app-server and retrying" : "codex app-server connection closed during startup; restarting app-server and retrying", {
6837
7317
  attempt,
6838
7318
  nextAttempt: attempt + 1,
6839
- maxAttempts: CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS,
7319
+ maxAttempts: CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS,
6840
7320
  refreshedSharedClient,
6841
7321
  error: formatErrorMessage(error)
6842
7322
  });
7323
+ await sleepWithAbort(retryDelayMs, startupAbandonController.signal);
6843
7324
  }
6844
7325
  throw new Error("codex app-server startup retry loop exited unexpectedly");
6845
7326
  }
@@ -6886,11 +7367,12 @@ async function startCodexAttemptRuntime(resources) {
6886
7367
  const { prompt, state, trajectoryRecorder, activateNativePreToolUseFailureFallback, releaseSandboxExecEnvironment, releaseSharedClientLeaseAndRetireOneShotClient, releaseCurrentRoute, runCleanupStep, startupTimeoutMs, buildNativeHookRelayFinalConfigPatch } = resources;
6887
7368
  const { context, turnState, buildRenderedCodexDeveloperInstructions, rebuildCodexTurnPromptTextFromCurrentProjection, applyNoContextEngineContinuityProjection } = prompt;
6888
7369
  const { runtime, attemptTools, promptState } = context;
6889
- const { connection, runtimeParams, preparedAuthBinding, buildActiveRunAttemptParams, startupAuthAccountCacheKey, startupEnvApiKeyCacheKey, bundleMcpThreadConfig, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, sandboxExecServerEnabled } = runtime;
7370
+ const { connection, runtimeParams, preparedAuthBinding, buildActiveRunAttemptParams, startupAuthAccountCacheKey, startupEnvApiKeyCacheKey, bundleMcpThreadConfig, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, effectiveRuntimeModelId, sandboxExecServerEnabled } = runtime;
6890
7371
  const { toolBridge, toolState } = attemptTools;
6891
7372
  const developerInstructions = joinPresentSections(turnState.promptBuild.developerInstructions, attemptTools.scheduledConfiguredMcp?.diagnosticNotice);
6892
7373
  const { params, attemptClientFactory, bindingStore, appServer, pluginConfig, computerUseConfig, startupClientAuthProfileId, runtimeArtifactRequest, startupPreparedAuth, agentDir, sessionAgentId, effectiveWorkspace, effectiveCwd, sandbox, runAbortController, usesSupervisionConnection, resolveReviewerPolicyContext, resolveRuntimeOptionsForCurrentBinding, startupAuthProfileId, startupAuthRequirement, abortFromUpstream } = connection;
6893
7374
  let pluginAppServer = withCodexAppServerFastModeServiceTier(appServer, runtimeParams);
7375
+ const loopDetectionEnabled = (sessionAgentId && params.config ? resolveAgentConfig$1(params.config, sessionAgentId)?.tools?.loopDetection?.enabled : void 0) ?? params.config?.tools?.loopDetection?.enabled ?? false;
6894
7376
  try {
6895
7377
  emitCodexAppServerEvent(params, {
6896
7378
  stream: "codex_app_server.lifecycle",
@@ -6899,6 +7381,7 @@ async function startCodexAttemptRuntime(resources) {
6899
7381
  const startupResult = await startCodexAttemptThread({
6900
7382
  attemptClientFactory,
6901
7383
  bindingStore,
7384
+ runtime: connection.options.runtime,
6902
7385
  appServer: pluginAppServer,
6903
7386
  pluginConfig,
6904
7387
  computerUseConfig,
@@ -6911,7 +7394,10 @@ async function startCodexAttemptRuntime(resources) {
6911
7394
  startupEnvApiKeyCacheKey,
6912
7395
  agentDir,
6913
7396
  config: params.config,
7397
+ shellEnvironment: connection.shellEnvironment,
7398
+ disableLoginShell: connection.disableLoginShell,
6914
7399
  buildAttemptParams: buildActiveRunAttemptParams,
7400
+ ...effectiveRuntimeModelId !== runtimeParams.modelId ? { runtimeModelId: effectiveRuntimeModelId } : {},
6915
7401
  sessionAgentId,
6916
7402
  effectiveWorkspace,
6917
7403
  effectiveCwd,
@@ -6919,7 +7405,9 @@ async function startCodexAttemptRuntime(resources) {
6919
7405
  persistentWebSearchAllowed: toolState.persistentWebSearchAllowed,
6920
7406
  webSearchAllowed: toolState.webSearchAllowed,
6921
7407
  developerInstructions,
7408
+ agentWorkspaceDeveloperInstructions: context.agentWorkspaceDeveloperInstructions,
6922
7409
  buildFinalConfigPatch: buildNativeHookRelayFinalConfigPatch,
7410
+ nativeHookRelayRequired: connection.options.nativeHookRelay?.enabled !== false && params.pluginHarnessToolPolicyRestricted !== true && connection.nativeHookRelayEvents.includes("pre_tool_use") && (hasBeforeToolCallPolicy() || appServer.loopDetectionPreToolUseRelay && Boolean(connection.sandboxSessionKey) && loopDetectionEnabled),
6923
7411
  bundleMcpThreadConfig,
6924
7412
  configuredMcpOwnershipVersion: attemptTools.configuredMcpOwnershipVersion,
6925
7413
  nativeToolSurfaceEnabled,
@@ -6930,6 +7418,11 @@ async function startCodexAttemptRuntime(resources) {
6930
7418
  startupTimeoutMs,
6931
7419
  signal: runAbortController.signal,
6932
7420
  onStartupTimeout: () => runAbortController.abort("codex_startup_timeout"),
7421
+ onExecutionDisconnect: (error) => {
7422
+ state.executionDisconnectError = error;
7423
+ embeddedAgentLog.warn(error.message);
7424
+ runAbortController.abort("client_closed");
7425
+ },
6933
7426
  spawnedBy: params.spawnedBy
6934
7427
  });
6935
7428
  state.client = startupResult.client;
@@ -6937,7 +7430,7 @@ async function startCodexAttemptRuntime(resources) {
6937
7430
  state.runtimeArtifact = startupResult.runtimeArtifact;
6938
7431
  state.turnRouter = startupResult.turnRouter;
6939
7432
  state.turnRoute = startupResult.turnRoute;
6940
- state.sandboxExecEnvironmentAcquired = Boolean(startupResult.sandboxEnvironment);
7433
+ state.sandboxExecEnvironment = startupResult.sandboxEnvironment;
6941
7434
  state.releaseSharedClientLease = startupResult.releaseSharedClientLease;
6942
7435
  state.restartContextEngineCodexThread = startupResult.restartContextEngineCodexThread;
6943
7436
  pluginAppServer = startupResult.pluginAppServer;
@@ -7011,7 +7504,7 @@ async function startCodexAttemptRuntime(resources) {
7011
7504
  await runCleanupStep("codex-start-failure-sandbox-release", releaseSandboxExecEnvironment);
7012
7505
  await runCleanupStep("codex-start-failure-shared-client-release", releaseSharedClientLeaseAndRetireOneShotClient);
7013
7506
  await runCleanupStep("codex-start-failure-abort-listener", () => params.abortSignal?.removeEventListener("abort", abortFromUpstream));
7014
- throw error;
7507
+ throw state.executionDisconnectError ?? error;
7015
7508
  }
7016
7509
  }
7017
7510
  //#endregion
@@ -7021,7 +7514,7 @@ function isAuthorityResolutionOperationAbort(error, signal) {
7021
7514
  }
7022
7515
  async function prepareCodexAttemptTools(runtime) {
7023
7516
  const { connection, bundleMcpThreadConfig, bundleManifestRegistry, runtimeParams, effectiveRuntimeModelId, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, hookChannelId, codexMcpToolOverrides, authenticatedScheduledMode, ownsScheduledConfiguredMcpSurface, canResolveScheduledConfiguredMcpCreatorAuthority } = runtime;
7024
- const { params, preDynamicStartupStages, mutable, startupAuthProfileId, resolvedWorkspace, effectiveWorkspace, effectiveCwd, sandboxSessionKey, sandbox, runAbortController, sessionAgentId, pluginConfig, profilerEnabled, agentDir } = connection;
7517
+ const { params, preDynamicStartupStages, mutable, startupAuthProfileId, resolvedWorkspace, effectiveWorkspace, effectiveCwd, sandboxSessionKey, sandbox, sessionPermissionPolicy, runAbortController, sessionAgentId, pluginConfig, profilerEnabled, agentDir } = connection;
7025
7518
  const preDynamicSummary = preDynamicStartupStages.snapshot();
7026
7519
  if (shouldWarnCodexDynamicToolBuildStageSummary(preDynamicSummary)) embeddedAgentLog.warn(`codex app-server pre-dynamic startup timings runId=${params.runId} sessionId=${params.sessionId} totalMs=${preDynamicSummary.totalMs} stages=${formatCodexDynamicToolBuildStageSummary(preDynamicSummary)}`, {
7027
7520
  runId: params.runId,
@@ -7035,6 +7528,7 @@ async function prepareCodexAttemptTools(runtime) {
7035
7528
  });
7036
7529
  const toolState = {
7037
7530
  yieldDetected: false,
7531
+ yieldAcknowledgment: void 0,
7038
7532
  persistentWebSearchAllowed: void 0,
7039
7533
  webSearchAllowed: false
7040
7534
  };
@@ -7052,11 +7546,16 @@ async function prepareCodexAttemptTools(runtime) {
7052
7546
  if (toolCallId) toolOutcomeOrdinals.set(toolCallId, ordinal);
7053
7547
  return ordinal;
7054
7548
  } : void 0;
7055
- const dynamicToolParams = allocateCodexToolOutcomeOrdinal || onCodexToolOutcome ? {
7549
+ const compactionPlanState = new CodexCompactionPlanState();
7550
+ const dynamicToolParams = {
7056
7551
  ...runtimeParams,
7552
+ onAgentEvent: (event) => {
7553
+ compactionPlanState.record(event);
7554
+ return runtimeParams.onAgentEvent?.(event);
7555
+ },
7057
7556
  ...allocateCodexToolOutcomeOrdinal ? { allocateToolOutcomeOrdinal: allocateCodexToolOutcomeOrdinal } : {},
7058
7557
  ...onCodexToolOutcome ? { onToolOutcome: onCodexToolOutcome } : {}
7059
- } : runtimeParams;
7558
+ };
7060
7559
  const computerContextEpoch = { value: 0 };
7061
7560
  const cronCreatorToolAllowlist = [];
7062
7561
  const cronCreatorToolAllowlistCaptureRef = {};
@@ -7080,6 +7579,7 @@ async function prepareCodexAttemptTools(runtime) {
7080
7579
  let toolBridge;
7081
7580
  let creatorAuthorityPromise;
7082
7581
  let resolveCreatorAuthorityImpl;
7582
+ const runtimeYieldCompletionClaim = {};
7083
7583
  const commonToolParams = {
7084
7584
  params: dynamicToolParams,
7085
7585
  resolvedWorkspace,
@@ -7087,6 +7587,7 @@ async function prepareCodexAttemptTools(runtime) {
7087
7587
  effectiveCwd,
7088
7588
  sandboxSessionKey,
7089
7589
  sandbox,
7590
+ sessionPermissionPolicy,
7090
7591
  nativeToolSurfaceEnabled,
7091
7592
  nativeProviderWebSearchSupport,
7092
7593
  runAbortController,
@@ -7094,9 +7595,11 @@ async function prepareCodexAttemptTools(runtime) {
7094
7595
  pluginConfig,
7095
7596
  profilerEnabled,
7096
7597
  ...params.cronCreatorAuthorityUnavailableReason === "queued-local-operator" && bundleMcpThreadConfig.staticServerNames.length > 0 ? { cronCreatorAuthorityUnavailableReason: "queued-local-operator-configured-mcp" } : {},
7097
- onYieldDetected: () => {
7598
+ onYieldDetected: (acknowledgment) => {
7098
7599
  toolState.yieldDetected = true;
7600
+ toolState.yieldAcknowledgment = acknowledgment;
7099
7601
  },
7602
+ claimYieldCompletion: () => runtimeYieldCompletionClaim.current?.() ?? false,
7100
7603
  onCodexAppServerEvent: (event) => {
7101
7604
  emitCodexAppServerEvent(params, event);
7102
7605
  },
@@ -7333,13 +7836,15 @@ async function prepareCodexAttemptTools(runtime) {
7333
7836
  cronCreatorToolAllowlistCaptureRef,
7334
7837
  scheduledAppAuthoritySourceRef,
7335
7838
  dynamicToolParams,
7839
+ compactionPlanState,
7336
7840
  computerContextEpoch,
7337
7841
  toolBridge,
7338
7842
  toolState,
7339
7843
  toolOutcomeOrdinals,
7340
7844
  suppressedDynamicToolOutcomeOrdinals,
7341
7845
  onCodexToolOutcome,
7342
- allocateCodexToolOutcomeOrdinal
7846
+ allocateCodexToolOutcomeOrdinal,
7847
+ runtimeYieldCompletionClaim
7343
7848
  };
7344
7849
  } catch (error) {
7345
7850
  await scopedMcpTools?.dispose();
@@ -7457,7 +7962,7 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
7457
7962
  data: {
7458
7963
  phase: "turn_starting",
7459
7964
  threadId: resourceState.thread.threadId,
7460
- model: turnStartParams.model,
7965
+ model: params.modelId,
7461
7966
  effort: turnStartParams.effort,
7462
7967
  collaborationEffort: turnStartParams.collaborationMode?.settings.reasoning_effort,
7463
7968
  serviceTier: turnStartParams.serviceTier
@@ -8179,11 +8684,14 @@ function createCodexAttemptTurnState(resources) {
8179
8684
  //#endregion
8180
8685
  //#region extensions/codex/src/app-server/run-attempt.ts
8181
8686
  async function runCodexAppServerAttempt(params, options) {
8182
- const runtime = await prepareCodexAttemptRuntime(await prepareCodexAttemptConnection({
8687
+ const connection = await prepareCodexAttemptConnection({
8183
8688
  params,
8184
8689
  options
8185
- }));
8186
- const resources = prepareCodexAttemptResources(await prepareCodexAttemptPrompt(await prepareCodexAttemptContext(runtime, await prepareCodexAttemptTools(runtime))));
8690
+ });
8691
+ const runtime = await prepareCodexAttemptRuntime(connection);
8692
+ const attemptTools = await prepareCodexAttemptTools(runtime);
8693
+ const resources = prepareCodexAttemptResources(await prepareCodexAttemptPrompt(await prepareCodexAttemptContext(runtime, attemptTools)));
8694
+ attemptTools.runtimeYieldCompletionClaim.current = () => resources.state.nativeHookRelay?.hasClaimedDirectChild() ?? false;
8187
8695
  await startCodexAttemptRuntime(resources);
8188
8696
  const turnRuntime = createCodexAttemptTurnState(resources);
8189
8697
  const lifecycle = createCodexAttemptLifecycleController(resources, turnRuntime);
@@ -8193,11 +8701,14 @@ async function runCodexAppServerAttempt(params, options) {
8193
8701
  const turnStart = await startCodexAttemptTurn(resources, turnRuntime, notifications, turnRequest);
8194
8702
  if ("result" in turnStart) return turnStart.result;
8195
8703
  const activeTurn = await activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, turnStart.turn);
8704
+ let finalizedResult;
8196
8705
  try {
8197
- return await finalizeCodexAttempt(resources, turnRuntime, lifecycle, notifications, turnRequest, activeTurn);
8706
+ finalizedResult = await finalizeCodexAttempt(resources, turnRuntime, lifecycle, notifications, turnRequest, activeTurn);
8198
8707
  } finally {
8199
8708
  await cleanupCodexAttempt(resources, turnRuntime, lifecycle, turnRequest, activeTurn);
8200
8709
  }
8710
+ if (resources.state.executionDisconnectError && !connection.terminalState.explicitCancellationObserved) throw resources.state.executionDisconnectError;
8711
+ return finalizedResult;
8201
8712
  }
8202
8713
  //#endregion
8203
8714
  export { runCodexAppServerAttempt };