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

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 (38) hide show
  1. package/dist/{app-server-policy-DUMF2Xyr.js → app-server-policy-BO3jYBkv.js} +1 -1
  2. package/dist/{attempt-notifications-Ecjyzufe.js → attempt-notifications-DdmnBMUp.js} +1 -1
  3. package/dist/{media-understanding-provider-IPNNQre6.js → bounded-turn-CaQL96kg.js} +43 -183
  4. package/dist/capabilities-CLICvTxf.js +36 -0
  5. package/dist/cli-metadata.js +1 -1
  6. package/dist/{command-formatters-NCTL7A2q.js → command-formatters-DgADqnHa.js} +3 -37
  7. package/dist/{command-handlers-DtFbZiba.js → command-handlers-l_lVPNlB.js} +12 -11
  8. package/dist/{compact-Kgy26gIM.js → compact-CC5KhBzX.js} +5 -4
  9. package/dist/{computer-use-C7x4ZaqR.js → computer-use-Ip1-QGa-.js} +4 -4
  10. package/dist/{conversation-control-B0s3aIjT.js → conversation-control-sNPsbTCP.js} +6 -5
  11. package/dist/doctor-contract-api.js +1 -1
  12. package/dist/{dynamic-tools-D_vSVmv9.js → dynamic-tools-CQI3UwqY.js} +105 -2670
  13. package/dist/event-projector-assistant-message-DTgnPPVF.js +101 -0
  14. package/dist/event-projector-usage-D6tE7_qD.js +69 -0
  15. package/dist/harness.js +25 -6
  16. package/dist/incognito-session-ET_ufDH-.js +2 -0
  17. package/dist/index.js +60 -26
  18. package/dist/media-understanding-provider.js +168 -1
  19. package/dist/{models-DD5zBdX5.js → models-BNeMlHgg.js} +2 -2
  20. package/dist/{notification-correlation-C8DVQ_Bq.js → notification-correlation-BGLixv5_.js} +3 -3
  21. package/dist/{plugin-app-cache-key-DJbhLYSK.js → plugin-app-cache-key-CvzvmBRz.js} +2 -2
  22. package/dist/{rate-limits-CqhWQ2R9.js → rate-limits-D0IJT-a6.js} +1 -1
  23. package/dist/{request-9yf9pZjf.js → request-BTccUTD3.js} +1 -1
  24. package/dist/{run-attempt-BIoO8ISr.js → run-attempt--858NXDl.js} +2653 -109
  25. package/dist/{session-binding-Bmt20HfB.js → session-binding-ZSMX1omP.js} +7 -2
  26. package/dist/{session-catalog-CA7R-hX2.js → session-catalog-DsKaezgR.js} +82 -80
  27. package/dist/{session-cli-Bxk3-Wqz.js → session-cli-CYJTfRLG.js} +1 -1
  28. package/dist/session-upstream-marker-D7XlI9us.js +82 -0
  29. package/dist/settled-turn-finalizer-DHltNgtF.js +303 -0
  30. package/dist/{shared-client-CSXLtCLE.js → shared-client-wmgNFNYp.js} +33 -13
  31. package/dist/{side-question-DtzquMOb.js → side-question-BfFZCsJ-.js} +21 -15
  32. package/dist/{thread-lifecycle-CQ_9mAa1.js → thread-lifecycle-cqrOlJkq.js} +120 -26
  33. package/dist/{transcript-mirror-D9rTxx2P.js → transcript-mirror-2p7kl6e4.js} +433 -145
  34. package/dist/upstream-session-fork-vPjwkT1i.js +320 -0
  35. package/dist/{usage-CuPpFgTc.js → usage-DM_I3mPT.js} +3 -3
  36. package/dist/{web-search-provider.runtime-_x5XTeqh.js → web-search-provider.runtime-Bx6HAc_k.js} +3 -3
  37. package/npm-shrinkwrap.json +38 -38
  38. package/package.json +7 -7
@@ -1,32 +1,43 @@
1
- import { A as isCodexAppServerStartupError, B as isCodexAppServerApprovalRequest, C as resolveCodexAppServerFallbackApiKeyCacheKey, D as resolveCodexAppServerHomeDir, F as resolveCodexTurnCompletionIdleTimeoutMs, H as isCodexAppServerConnectionClosedError, I as resolveCodexTurnTerminalIdleTimeoutMs, K as isCodexAppServerRequestTimeoutError, L as withCodexStartupTimeout, M as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, N as resolveCodexStartupTimeoutMs, O as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, P as resolveCodexTurnAssistantCompletionIdleTimeoutMs, R as CodexAppServerRpcError, S as resolveCodexAppServerAuthProfileIdForAgent, T as resolveCodexAppServerPreparedAuthHandoff, V as isCodexAppServerBrokenPipeError, X as flattenCodexDynamicToolFunctions, Z as isJsonObject, _ as readCodexRateLimitsRevision, a as getLeasedSharedCodexAppServerClient, b as resolveCodexAppServerAuthAccountCacheKey, c as releaseLeasedSharedCodexAppServerClient, d as retireSharedCodexAppServerClientIfCurrent, g as ensureCodexAppServerClientRuntime, k as CodexAppServerStartupError, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as isCodexAppServerStartSelectionChangedError, t as clearSharedCodexAppServerClientIfCurrent, u as retainSharedCodexAppServerClientIfCurrent, v as readRecentCodexRateLimits, w as resolveCodexAppServerPreparedApiKeyCacheKey, x as resolveCodexAppServerAuthProfileId } from "./shared-client-CSXLtCLE.js";
2
- import { S as updateActiveTurnItemIds, _ as readCodexNotificationItem, a as isCodexTurnAbortMarkerNotification, b as shouldDisarmAssistantCompletionIdleWatch, c as isPendingOpenClawDynamicToolCompletionNotification, d as isRawReasoningCompletionNotification, f as isRawToolOutputCompletionNotification, g as isTerminalTurnStatus, h as isRetryableErrorNotification, i as isAssistantCompletionReleaseNotification, l as isRawAssistantProgressNotification, m as isReasoningProgressNotification, n as describeNotificationActivity, o as isFileChangePatchUpdatedNotification, p as isReasoningItemCompletionNotification, r as isAssistantCommentaryCompletionNotification, s as isNativeToolProgressNotification, t as codexExecutionToolName, u as isRawFunctionToolOutputCompletionNotification, v as readNotificationItemId, x as updateActiveCompletionBlockerItemIds, y as readRawResponseToolCallId } from "./attempt-notifications-Ecjyzufe.js";
3
- import { C as resolveCodexComputerUseConfig, D as resolveOpenClawExecPolicyForCodexAppServer, O as shouldAutoApproveCodexAppServerApprovals, T as resolveCodexPluginsPolicy, c as sessionBindingIdentity, g as isCodexAppServerApprovalPolicyAllowedByRequirements, k as withMcpElicitationsApprovalPolicy, s as reclaimCurrentCodexSessionGeneration, v as isCodexSandboxExecServerEnabled, w as resolveCodexModelBackedReviewerPolicyContext, y as readCodexPluginConfig } from "./session-binding-Bmt20HfB.js";
4
- import { _ as readCodexTurnCompletedNotification, f as assertCodexTurnStartResponse, i as mirrorPromptAtTurnStartBestEffort, n as createCodexAppServerUserMessagePersistenceNotifier, o as buildCodexUserPromptMessage, p as readCodexDynamicToolCallParams, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-D9rTxx2P.js";
5
- import { i as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-DJbhLYSK.js";
6
- import { A as CodexAppServerUnsafeSubscriptionError, B as fitCodexProjectedContextForTurnStart, D as resolveCodexDynamicToolsLoadingForRuntime, F as areCodexDynamicToolFingerprintsCompatible, G as buildCodexPluginThreadConfig, H as resolveCodexContextEngineProjectionMaxChars, I as codexDynamicToolsFingerprint, J as mergeCodexThreadConfigs, K as buildCodexPluginThreadConfigInputFingerprint, L as codexLegacyDynamicToolsFingerprint, M as interruptCodexTurnBestEffort, N as retireCodexAppServerClientAfterTimedOutTurn, O as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS, P as unsubscribeCodexThreadBestEffort, Q as resolveRecoverableCodexPluginConfigKeys, R as buildContextEngineBinding, U as resolveCodexContextEngineProjectionReserveTokens, V as projectContextEngineAssemblyForCodex, Y as shouldBuildCodexPluginThreadConfig, b as isCodexAppServerProfilerEnabled, d as resolveCodexWebSearchPlan, f as buildDeveloperInstructions, g as resolveCodexAppServerThreadModelSelection, j as closeCodexStartupClientBestEffort, k as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, n as buildTurnStartParams, q as buildCodexPluginThreadConfigTimeoutFallback, r as buildCodexUserInput, s as startOrResumeThread, t as buildTurnCollaborationMode, w as isSystemAgentOnlyCodexDynamicToolAllowlist, x as filterCodexDynamicTools, z as isContextEngineBindingCompatible } from "./thread-lifecycle-CQ_9mAa1.js";
7
- import { r as formatCodexDisplayText } from "./command-formatters-NCTL7A2q.js";
8
- import { n as resolveCodexAppServerForOpenClawToolPolicy, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-DUMF2Xyr.js";
9
- import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId, t as isCodexNotificationForTurn } from "./notification-correlation-C8DVQ_Bq.js";
1
+ import { A as isCodexAppServerStartupError, B as isCodexAppServerApprovalRequest, C as resolveCodexAppServerFallbackApiKeyCacheKey, D as resolveCodexAppServerHomeDir, F as resolveCodexTurnCompletionIdleTimeoutMs, H as isCodexAppServerConnectionClosedError, I as resolveCodexTurnTerminalIdleTimeoutMs, K as isCodexAppServerRequestTimeoutError, L as withCodexStartupTimeout, M as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, N as resolveCodexStartupTimeoutMs, O as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, P as resolveCodexTurnAssistantCompletionIdleTimeoutMs, Q as isJsonObject, R as CodexAppServerRpcError, S as resolveCodexAppServerAuthProfileIdForAgent, T as resolveCodexAppServerPreparedAuthHandoff, V as isCodexAppServerBrokenPipeError, Z as flattenCodexDynamicToolFunctions, _ as readCodexRateLimitsRevision, a as getLeasedSharedCodexAppServerClient, b as resolveCodexAppServerAuthAccountCacheKey, c as releaseLeasedSharedCodexAppServerClient, d as retireSharedCodexAppServerClientIfCurrent, g as ensureCodexAppServerClientRuntime, k as CodexAppServerStartupError, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as isCodexAppServerStartSelectionChangedError, t as clearSharedCodexAppServerClientIfCurrent, u as retainSharedCodexAppServerClientIfCurrent, v as readRecentCodexRateLimits, w as resolveCodexAppServerPreparedApiKeyCacheKey, x as resolveCodexAppServerAuthProfileId, y as rememberCodexRateLimitsRead } from "./shared-client-wmgNFNYp.js";
2
+ import { S as updateActiveTurnItemIds, _ as readCodexNotificationItem, a as isCodexTurnAbortMarkerNotification, b as shouldDisarmAssistantCompletionIdleWatch, c as isPendingOpenClawDynamicToolCompletionNotification, d as isRawReasoningCompletionNotification, f as isRawToolOutputCompletionNotification, g as isTerminalTurnStatus, h as isRetryableErrorNotification, i as isAssistantCompletionReleaseNotification, l as isRawAssistantProgressNotification, m as isReasoningProgressNotification, n as describeNotificationActivity, o as isFileChangePatchUpdatedNotification, p as isReasoningItemCompletionNotification, r as isAssistantCommentaryCompletionNotification, s as isNativeToolProgressNotification, t as codexExecutionToolName, u as isRawFunctionToolOutputCompletionNotification, v as readNotificationItemId, x as updateActiveCompletionBlockerItemIds, y as readRawResponseToolCallId } from "./attempt-notifications-DdmnBMUp.js";
3
+ import { A as withMcpElicitationsApprovalPolicy, E as resolveCodexPluginsPolicy, O as resolveOpenClawExecPolicyForCodexAppServer, T as resolveCodexModelBackedReviewerPolicyContext, _ as isCodexAppServerApprovalPolicyAllowedByRequirements, b as readCodexPluginConfig, c as reclaimCurrentCodexSessionGeneration, i as createCodexSessionGenerationSupersededError, k as shouldAutoApproveCodexAppServerApprovals, l as sessionBindingIdentity, w as resolveCodexComputerUseConfig, y as isCodexSandboxExecServerEnabled } from "./session-binding-ZSMX1omP.js";
4
+ import { $ as shouldBuildCodexPluginThreadConfig, B as codexDynamicToolsFingerprint, F as closeCodexStartupClientBestEffort, G as projectContextEngineAssemblyForCodex, H as buildContextEngineBinding, I as interruptCodexTurnBestEffort, K as resolveCodexContextEngineProjectionMaxChars, L as retireCodexAppServerClientAfterTimedOutTurn, M as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS, N as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, O as isSystemAgentOnlyCodexDynamicToolAllowlist, P as CodexAppServerUnsafeSubscriptionError, Q as mergeCodexThreadConfigs, R as unsubscribeCodexThreadBestEffort, T as filterCodexDynamicTools, U as isContextEngineBindingCompatible, V as codexLegacyDynamicToolsFingerprint, W as fitCodexProjectedContextForTurnStart, X as buildCodexPluginThreadConfigInputFingerprint, Y as buildCodexPluginThreadConfig, Z as buildCodexPluginThreadConfigTimeoutFallback, a as sanitizeCodexHistoryImagePayloads, at as readCodexErrorNotificationMessage, b as resolveCodexAppServerThreadModelSelection, ct as readItemString, dt as readNonNegativeInteger, ft as readNullableString$1, g as buildDeveloperInstructions, h as resolveCodexWebSearchPlan, ht as splitPlanText, it as normalizeNonEmptyString, j as resolveCodexDynamicToolsLoadingForRuntime, lt as readNonEmptyString$1, mt as readString$5, n as buildTurnStartParams, nt as resolveRecoverableCodexPluginConfigKeys, ot as readHookOutputEntries, pt as readNumber, q as resolveCodexContextEngineProjectionReserveTokens, r as buildCodexUserInput, rt as extractRawAssistantText, s as startOrResumeThread, st as readItem, t as buildTurnCollaborationMode, ut as readNonEmptyStringArray, w as isCodexAppServerProfilerEnabled, z as areCodexDynamicToolFingerprintsCompatible } from "./thread-lifecycle-cqrOlJkq.js";
5
+ import { n as projectCodexThreadUsageUpdate, t as normalizeCodexResponseTokenUsage } from "./event-projector-usage-D6tE7_qD.js";
6
+ import { C as readCodexTurnCompletedNotification, S as readCodexTurn, d as attachCodexMirrorIdentity, f as readMirrorIdentity, i as mirrorPromptAtTurnStartBestEffort, n as createCodexAppServerUserMessagePersistenceNotifier, o as buildCodexUserPromptMessage, s as promptSnapshot, t as codexTranscriptMirrorRuntime, u as serializeCodexMirrorSourceEvidence, v as assertCodexTurnStartResponse, y as readCodexDynamicToolCallParams } from "./transcript-mirror-2p7kl6e4.js";
7
+ import { i as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-CvzvmBRz.js";
8
+ import { t as isIncognitoSessionKey } from "./incognito-session-ET_ufDH-.js";
9
+ import { t as CODEX_CONTROL_METHODS } from "./capabilities-CLICvTxf.js";
10
+ import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-D0IJT-a6.js";
11
+ import { r as formatCodexDisplayText } from "./command-formatters-DgADqnHa.js";
12
+ import { n as resolveCodexAppServerForOpenClawToolPolicy, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-BO3jYBkv.js";
13
+ import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId, t as isCodexNotificationForTurn } from "./notification-correlation-BGLixv5_.js";
10
14
  import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-C1czuHPA.js";
11
- import { $ as resolveCodexToolProgressDetailMode, B as hasPendingDynamicToolTerminalDiagnostic, C as CodexAppServerEventProjector, D as markCodexAuthProfileBlockedFromRateLimits, E as isCodexUsageLimitPromptError, F as emitCodexNativePreToolUseFailureDiagnostic, G as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult, H as isMatchingDynamicToolTerminalDiagnostic, I as resolveCodexNativeHookRelayEvents, J as toCodexDynamicToolProtocolResponse, K as shouldReleaseTurnAfterTerminalDynamicTool, L as resolveCodexNativeHookRelayTtlMs, M as buildCodexNativeHookRelayConfig, N as buildCodexNativeHookRelayDisabledConfig, O as refreshCodexUsageLimitPromptError, P as createCodexNativeHookRelay, Q as inferCodexDynamicToolMeta, R as scheduleCodexNativeHookRelayUnregister, T as formatCodexTurnStartUsageLimitError, U as resolveDynamicToolCallTimeoutMs, V as isDynamicToolTerminalDiagnosticEvent, W as resolveTerminalDynamicToolBatchAction, X as readCodexMirroredSessionHistoryMessages, Y as resolveCodexToolAbortTerminalReason, Z as shouldEmitTranscriptToolProgress, _ as resolveCodexMessageToolProvider, a as emitDynamicToolStartedDiagnostic, b as shouldRequireCodexSandboxExecServerEnvironment, d as createCodexDynamicToolBuildStageTracker, et as sanitizeCodexToolArguments, f as disableCodexPluginThreadConfig, g as resolveCodexExternalSandboxPolicyForOpenClawSandbox, h as resolveCodexAppServerHookChannelId, i as emitDynamicToolErrorDiagnostic, j as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, l as settleCodexSourceReplyFinality, m as resolveCodexAppServerExecutionCwd, n as handleCodexAppServerApprovalRequest, nt as redactCodexEventKind, o as emitDynamicToolTerminalDiagnostic, p as formatCodexDynamicToolBuildStageSummary, q as toCodexDynamicToolProgressResponse, r as handleCodexAppServerElicitationRequest, rt as resolveCodexLocalRuntimeAttribution, s as resolveCodexProviderWebSearchSupport, t as createCodexDynamicToolBridge, tt as sanitizeCodexToolResponse, u as buildDynamicTools, v as resolveCodexSandboxEnvironmentSelection, w as createCodexUsageLimitPromptError, x as shouldWarnCodexDynamicToolBuildStageSummary, y as shouldEnableCodexAppServerNativeToolSurface, z as handleDynamicToolCallWithTimeout } from "./dynamic-tools-D_vSVmv9.js";
12
- import { a as runCodexComputerUseLiveTest, r as killStaleComputerUseMcpChildren, t as ensureCodexComputerUse } from "./computer-use-C7x4ZaqR.js";
15
+ import { i as resolveCodexLocalRuntimeAttribution, n as createAssistantMessage, r as createAssistantMirrorMessage, t as createAssistantCommentaryMessage } from "./event-projector-assistant-message-DTgnPPVF.js";
16
+ import { $ as shouldSynthesizeToolProgressForItem, A as resolveCodexNativeHookRelayEvents, B as shouldReleaseTurnAfterTerminalDynamicTool, C as CodexNativeToolLifecycleProjector, D as buildCodexNativeHookRelayDisabledConfig, E as buildCodexNativeHookRelayConfig, F as isDynamicToolTerminalDiagnosticEvent, G as isNonSuccessItemStatus, H as toCodexDynamicToolProtocolResponse, I as isMatchingDynamicToolTerminalDiagnostic, J as itemName, K as isSideEffectingNativeToolItem, L as resolveDynamicToolCallTimeoutMs, M as scheduleCodexNativeHookRelayUnregister, N as handleDynamicToolCallWithTimeout, O as createCodexNativeHookRelay, P as hasPendingDynamicToolTerminalDiagnostic, Q as shouldRecordNativeToolTranscript, R as resolveTerminalDynamicToolBatchAction, T as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, U as resolveCodexToolAbortTerminalReason, V as toCodexDynamicToolProgressResponse, W as isMutatingNativeToolItem, X as itemTitle, Y as itemStatus, Z as shouldClearTerminalPresentationForNativeItem, _ as resolveCodexMessageToolProvider, a as emitDynamicToolStartedDiagnostic, b as shouldRequireCodexSandboxExecServerEnvironment, d as createCodexDynamicToolBuildStageTracker, et as unknownItemStatus, f as disableCodexPluginThreadConfig, g as resolveCodexExternalSandboxPolicyForOpenClawSandbox, h as resolveCodexAppServerHookChannelId, i as emitDynamicToolErrorDiagnostic, j as resolveCodexNativeHookRelayTtlMs, k as emitCodexNativePreToolUseFailureDiagnostic, l as settleCodexSourceReplyFinality, m as resolveCodexAppServerExecutionCwd, n as handleCodexAppServerApprovalRequest, o as emitDynamicToolTerminalDiagnostic, p as formatCodexDynamicToolBuildStageSummary, q as itemKind, r as handleCodexAppServerElicitationRequest, s as resolveCodexProviderWebSearchSupport, t as createCodexDynamicToolBridge, u as buildDynamicTools, v as resolveCodexSandboxEnvironmentSelection, x as shouldWarnCodexDynamicToolBuildStageSummary, y as shouldEnableCodexAppServerNativeToolSurface, z as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult } from "./dynamic-tools-CQI3UwqY.js";
17
+ import { a as runCodexComputerUseLiveTest, r as killStaleComputerUseMcpChildren, t as ensureCodexComputerUse } from "./computer-use-Ip1-QGa-.js";
13
18
  import fs from "node:fs/promises";
14
19
  import path, { posix } from "node:path";
15
- import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
20
+ import { asDateTimestampMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
16
21
  import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
17
22
  import { createHash, randomUUID } from "node:crypto";
18
- import { resolveAgentDir, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
23
+ import { markAuthProfileBlockedUntil, resolveAgentDir, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
19
24
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
20
25
  import { asFiniteNumber, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
21
- import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildAgentHarnessUserInputAnswers, buildBootstrapContextForFiles, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, callGatewayTool, cancelPendingAgentQuestionForSession, claimPendingAgentQuestionAnswer, clearActiveEmbeddedRun, deliverAgentHarnessUserInputPrompt, embeddedAgentLog, emitAgentEvent, emptyAgentHarnessUserInputAnswers, finalizeHarnessContextEngineTurn, formatErrorMessage, formatFastModeAutoProgressText, getAgentHarnessHookRunner, getBeforeToolCallPolicyDiagnosticState, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, resolveAgentDir as resolveAgentDir$1, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds as resolveSessionAgentIds$1, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessGatewayQuestion, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
26
+ import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, TOOL_PROGRESS_OUTPUT_MAX_CHARS, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildAgentHarnessUserInputAnswers, buildBootstrapContextForFiles, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, callGatewayTool, cancelPendingAgentQuestionForSession, claimPendingAgentQuestionAnswer, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, deliverAgentHarnessUserInputPrompt, embeddedAgentLog, emitAgentEvent, emptyAgentHarnessUserInputAnswers, finalizeHarnessContextEngineTurn, formatErrorMessage, formatFastModeAutoProgressText, formatToolAggregate, formatToolProgressOutput, getAgentHarnessHookRunner, getBeforeToolCallPolicyDiagnosticState, inferToolMetaFromArgs, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, projectAgentHarnessTranscriptMessageForDisplay, resolveAgentDir as resolveAgentDir$1, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds as resolveSessionAgentIds$1, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessGatewayQuestion, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
22
27
  import { spawn } from "node:child_process";
23
28
  import { once } from "node:events";
24
29
  import { isIP } from "node:net";
25
30
  import { WebSocketServer } from "ws";
26
- import { parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
31
+ import { listSessionEntries, parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
27
32
  import { fileURLToPath } from "node:url";
33
+ import { redactSensitiveFieldValue, redactSensitiveText, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
28
34
  import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
35
+ import { readSessionTranscriptEvents } from "openclaw/plugin-sdk/session-transcript-runtime";
29
36
  import { prepareMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
37
+ import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
38
+ import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "openclaw/plugin-sdk/agent-sessions";
39
+ import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
40
+ import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
30
41
  import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
31
42
  import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
32
43
  import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
@@ -190,6 +201,2430 @@ function normalizeCodexSteerDebounceMs(value) {
190
201
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : CODEX_STEER_ALL_DEBOUNCE_MS;
191
202
  }
192
203
  //#endregion
204
+ //#region extensions/codex/src/app-server/event-projector-assistant.ts
205
+ var CodexAssistantProjection = class {
206
+ constructor(params, emitAgentEvent, matchesToolProgressEcho, nextTranscriptTimestamp) {
207
+ this.params = params;
208
+ this.emitAgentEvent = emitAgentEvent;
209
+ this.matchesToolProgressEcho = matchesToolProgressEcho;
210
+ this.nextTranscriptTimestamp = nextTranscriptTimestamp;
211
+ this.assistantTextByItem = /* @__PURE__ */ new Map();
212
+ this.assistantItemOrder = [];
213
+ this.assistantTimestampByItem = /* @__PURE__ */ new Map();
214
+ this.assistantPhaseByItem = /* @__PURE__ */ new Map();
215
+ this.latestTerminalAssistantCandidateSuperseded = false;
216
+ this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
217
+ this.terminalAssistantCandidateEarlierActiveItemIds = /* @__PURE__ */ new Set();
218
+ this.lastCommentaryProgressTextByItem = /* @__PURE__ */ new Map();
219
+ this.lastAnswerCandidateEventByItem = /* @__PURE__ */ new Map();
220
+ this.pendingRawCommentaryEchoes = 0;
221
+ this.rawPromotedAssistantItemIds = /* @__PURE__ */ new Set();
222
+ this.assistantStarted = false;
223
+ this.streamedPartialAssistantItemReplaceable = false;
224
+ }
225
+ hasCompletedTerminalAssistantText(completedItemIds) {
226
+ const latestCompletedItemId = this.latestCompletedTerminalAssistantItemId;
227
+ if (!latestCompletedItemId) return false;
228
+ const finalItem = this.resolveFinalAssistantTextItem();
229
+ return this.latestCompletedItemId === latestCompletedItemId && finalItem?.itemId === latestCompletedItemId && completedItemIds.has(latestCompletedItemId);
230
+ }
231
+ getLatestTerminalAssistantCandidate() {
232
+ const itemId = this.latestTerminalAssistantCandidateItemId;
233
+ if (!itemId) return;
234
+ const text = this.assistantTextByItem.get(itemId)?.trim();
235
+ return {
236
+ itemId,
237
+ hasText: Boolean(text && !this.isToolProgressEchoText(itemId, text))
238
+ };
239
+ }
240
+ hasLatestTerminalAssistantCandidateText() {
241
+ return !this.latestTerminalAssistantCandidateSuperseded && this.getLatestTerminalAssistantCandidate()?.hasText === true;
242
+ }
243
+ canReleaseLatestTerminalAssistantAfterToolHandoff() {
244
+ return this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff && this.hasLatestTerminalAssistantCandidateText();
245
+ }
246
+ async handleAssistantDelta(params) {
247
+ const itemId = readString$5(params, "itemId") ?? "assistant";
248
+ const delta = readString$5(params, "delta") ?? "";
249
+ if (!delta) return;
250
+ if (itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
251
+ const isCommentary = this.isCommentaryAssistantItem(itemId);
252
+ if (!isCommentary && itemId !== this.latestTerminalAssistantCandidateItemId) this.markTerminalAssistantCandidateSupersededBy();
253
+ if (!this.assistantStarted) {
254
+ this.assistantStarted = true;
255
+ await this.params.onAssistantMessageStart?.();
256
+ }
257
+ this.rememberAssistantItem(itemId);
258
+ const text = `${this.assistantTextByItem.get(itemId) ?? ""}${delta}`;
259
+ this.assistantTextByItem.set(itemId, text);
260
+ if (isCommentary) {
261
+ this.emitCommentaryProgress({
262
+ itemId,
263
+ text
264
+ });
265
+ return;
266
+ }
267
+ if (this.isFinalAnswerAssistantItem(itemId)) this.emitAnswerCandidate(itemId, "candidate");
268
+ const knownFinalAnswer = this.shouldStreamAssistantPartial(itemId);
269
+ const replace = this.streamedPartialAssistantItemId !== void 0 && this.streamedPartialAssistantItemId !== itemId;
270
+ if (replace && (!knownFinalAnswer || this.streamedPartialAssistantItemReplaceable)) this.streamedPartialAssistantItemReplaceable = true;
271
+ else if (this.streamedPartialAssistantItemId === void 0) this.streamedPartialAssistantItemReplaceable = !knownFinalAnswer;
272
+ this.streamedPartialAssistantItemId = itemId;
273
+ const replaceable = this.streamedPartialAssistantItemReplaceable;
274
+ const replacement = replace && replaceable;
275
+ const streamPayload = {
276
+ text,
277
+ delta: replacement ? "" : delta,
278
+ ...replacement ? { replace: true } : {}
279
+ };
280
+ this.emitAgentEvent({
281
+ stream: "assistant",
282
+ data: {
283
+ ...streamPayload,
284
+ ...replaceable ? { replaceable: true } : {}
285
+ }
286
+ });
287
+ if (knownFinalAnswer && !replaceable) await this.params.onPartialReply?.(streamPayload);
288
+ }
289
+ recordItemStarted(item, itemId) {
290
+ if (item?.type === "agentMessage" && itemId && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
291
+ this.rememberAssistantPhase(item);
292
+ if (item?.type === "agentMessage" && itemId) this.rememberAssistantItem(itemId);
293
+ if (itemId && itemId !== this.latestTerminalAssistantCandidateItemId) {
294
+ this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
295
+ if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
296
+ }
297
+ }
298
+ recordItemCompleted(item, itemId, activeItemIds) {
299
+ if (item?.type === "agentMessage" && itemId && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
300
+ if (itemId) this.latestCompletedItemId = itemId;
301
+ this.rememberAssistantPhase(item);
302
+ if (item?.type === "agentMessage" && !this.isCommentaryAssistantItem(item.id)) {
303
+ this.latestCompletedTerminalAssistantItemId = item.id;
304
+ this.markLatestTerminalAssistantCandidate(item.id, activeItemIds);
305
+ this.pendingRawTerminalAssistantEchoItemId = item.id;
306
+ } else if (itemId) {
307
+ this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
308
+ if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
309
+ }
310
+ if (item?.type === "agentMessage" && typeof item.text === "string") {
311
+ this.rememberAssistantItem(item.id);
312
+ this.assistantTextByItem.set(item.id, item.text);
313
+ if (item.text && this.isCommentaryAssistantItem(item.id)) {
314
+ this.emitCommentaryProgress({
315
+ itemId: item.id,
316
+ text: item.text
317
+ });
318
+ this.pendingRawCommentaryEchoes += 1;
319
+ } else if (item.text && this.isFinalAnswerAssistantItem(item.id)) this.emitAnswerCandidate(item.id, "candidate");
320
+ }
321
+ }
322
+ recordSnapshotItem(item) {
323
+ this.rememberAssistantPhase(item);
324
+ if (item.type === "agentMessage" && typeof item.text === "string") {
325
+ this.rememberAssistantItem(item.id);
326
+ this.assistantTextByItem.set(item.id, item.text);
327
+ }
328
+ }
329
+ handleRawResponseItemCompleted(item, activeItemIds) {
330
+ const role = readString$5(item, "role");
331
+ const phase = readString$5(item, "phase");
332
+ const rawItemId = readString$5(item, "id");
333
+ const candidateWasSupersededBeforeRaw = this.latestTerminalAssistantCandidateSuperseded;
334
+ const pendingTerminalAssistantEchoItemId = this.pendingRawTerminalAssistantEchoItemId;
335
+ const isPendingTerminalAssistantEcho = role === "assistant" && phase !== "commentary" && pendingTerminalAssistantEchoItemId !== void 0 && (rawItemId === void 0 || rawItemId === pendingTerminalAssistantEchoItemId);
336
+ if (pendingTerminalAssistantEchoItemId !== void 0 && !isPendingTerminalAssistantEcho) this.pendingRawTerminalAssistantEchoItemId = void 0;
337
+ if (!isPendingTerminalAssistantEcho) {
338
+ this.latestCompletedItemId = void 0;
339
+ this.markTerminalAssistantCandidateSupersededBy(rawItemId);
340
+ }
341
+ if (role !== "assistant") return;
342
+ if (phase === "commentary" && this.pendingRawCommentaryEchoes > 0) {
343
+ this.pendingRawCommentaryEchoes -= 1;
344
+ return;
345
+ }
346
+ const text = extractRawAssistantText(item);
347
+ if (isPendingTerminalAssistantEcho) {
348
+ const typedItemId = pendingTerminalAssistantEchoItemId;
349
+ this.pendingRawTerminalAssistantEchoItemId = void 0;
350
+ if (this.assistantTextByItem.get(typedItemId)?.trim() || !text) return;
351
+ this.rememberAssistantItem(typedItemId);
352
+ this.assistantTextByItem.set(typedItemId, text);
353
+ return;
354
+ }
355
+ if (!text) return;
356
+ const itemId = rawItemId ?? `raw-assistant-${this.assistantItemOrder.length + 1}`;
357
+ const isIdlessTerminalAssistantAfterCompletedWork = candidateWasSupersededBeforeRaw && rawItemId === void 0 && pendingTerminalAssistantEchoItemId === void 0 && activeItemIds.size === 0;
358
+ if (phase !== "commentary" && candidateWasSupersededBeforeRaw && itemId !== this.streamedPartialAssistantItemId && !isIdlessTerminalAssistantAfterCompletedWork) return;
359
+ if (phase) this.assistantPhaseByItem.set(itemId, phase);
360
+ this.rememberAssistantItem(itemId);
361
+ this.assistantTextByItem.set(itemId, text);
362
+ this.rawPromotedAssistantItemIds.add(itemId);
363
+ if (phase === "commentary") this.emitCommentaryProgress({
364
+ itemId,
365
+ text
366
+ });
367
+ else this.markLatestTerminalAssistantCandidate(itemId, activeItemIds, { canReleaseAfterToolHandoff: isIdlessTerminalAssistantAfterCompletedWork });
368
+ }
369
+ collectAssistantTexts() {
370
+ const finalText = this.resolveFinalAssistantTextItem()?.text;
371
+ return finalText ? [finalText] : [];
372
+ }
373
+ collectCommentaryMessages() {
374
+ return this.assistantItemOrder.flatMap((itemId) => {
375
+ if (!this.isCommentaryAssistantItem(itemId)) return [];
376
+ const text = this.assistantTextByItem.get(itemId)?.trim();
377
+ const timestamp = this.assistantTimestampByItem.get(itemId);
378
+ if (!text || timestamp === void 0) return [];
379
+ return [{
380
+ itemId,
381
+ message: createAssistantCommentaryMessage(this.params, text, itemId, timestamp)
382
+ }];
383
+ });
384
+ }
385
+ finalizeAnswerCandidate(turn) {
386
+ if (turn.status !== "completed") {
387
+ this.supersedeVisibleAnswerCandidate();
388
+ return;
389
+ }
390
+ const turnItems = turn.items ?? [];
391
+ const authoritativeIndex = turnItems.findLastIndex((item) => item.type === "agentMessage" && readItemString(item, "phase") === "final_answer" && typeof item.text === "string" && item.text.trim().length > 0);
392
+ const authoritative = authoritativeIndex >= 0 ? turnItems[authoritativeIndex] : void 0;
393
+ if (turnItems.slice(authoritativeIndex + 1).some(shouldClearTerminalPresentationForNativeItem) || authoritative?.id === this.latestTerminalAssistantCandidateItemId && this.latestTerminalAssistantCandidateSuperseded) {
394
+ this.supersedeVisibleAnswerCandidate();
395
+ return;
396
+ }
397
+ const itemId = authoritative?.id ?? this.visibleAnswerCandidateItemId;
398
+ if (!itemId) return;
399
+ if (itemId !== this.visibleAnswerCandidateItemId) {
400
+ this.supersedeVisibleAnswerCandidate();
401
+ this.visibleAnswerCandidateItemId = itemId;
402
+ }
403
+ this.emitAnswerCandidate(itemId, "selected");
404
+ }
405
+ hasAssistantItemTextForSynthesis() {
406
+ for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
407
+ const itemId = this.assistantItemOrder[i];
408
+ if (!itemId || this.assistantPhaseByItem.get(itemId) === "commentary") continue;
409
+ const text = this.assistantTextByItem.get(itemId);
410
+ if (text && text.length > 0) return true;
411
+ }
412
+ return false;
413
+ }
414
+ createCurrentAttemptAssistantMessage(options) {
415
+ for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
416
+ const itemId = this.assistantItemOrder[i];
417
+ if (!itemId || this.isCommentaryAssistantItem(itemId) || !this.assistantTextByItem.has(itemId)) continue;
418
+ const text = this.assistantTextByItem.get(itemId) ?? "";
419
+ const normalizedText = text.trim();
420
+ if (normalizedText && this.isToolProgressEchoText(itemId, normalizedText)) continue;
421
+ return this.createAssistantMessage(text, options);
422
+ }
423
+ }
424
+ createAssistantMessage(text, options) {
425
+ return createAssistantMessage(this.params, text, options);
426
+ }
427
+ createAssistantMirrorMessage(title, text) {
428
+ return createAssistantMirrorMessage(this.params, title, text);
429
+ }
430
+ rememberAssistantPhase(item) {
431
+ if (item?.type !== "agentMessage") return;
432
+ const phase = readItemString(item, "phase");
433
+ if (phase) this.assistantPhaseByItem.set(item.id, phase);
434
+ }
435
+ isCommentaryAssistantItem(itemId) {
436
+ return this.assistantPhaseByItem.get(itemId) === "commentary";
437
+ }
438
+ isFinalAnswerAssistantItem(itemId) {
439
+ return this.assistantPhaseByItem.get(itemId) === "final_answer";
440
+ }
441
+ shouldStreamAssistantPartial(itemId) {
442
+ return this.assistantPhaseByItem.get(itemId) === "final_answer";
443
+ }
444
+ emitCommentaryProgress(params) {
445
+ const progressText = params.text.replace(/\s+/g, " ").trim();
446
+ if (!progressText || this.lastCommentaryProgressTextByItem.get(params.itemId) === progressText) return;
447
+ this.lastCommentaryProgressTextByItem.set(params.itemId, progressText);
448
+ this.emitAgentEvent({
449
+ stream: "item",
450
+ data: {
451
+ itemId: params.itemId,
452
+ kind: "preamble",
453
+ title: "Preamble",
454
+ phase: "update",
455
+ progressText,
456
+ source: "codex-app-server"
457
+ }
458
+ });
459
+ }
460
+ emitAnswerCandidate(itemId, status) {
461
+ const text = this.assistantTextByItem.get(itemId)?.trim();
462
+ if (!text) return;
463
+ if (status === "candidate" && this.visibleAnswerCandidateItemId !== itemId) {
464
+ this.supersedeVisibleAnswerCandidate();
465
+ this.visibleAnswerCandidateItemId = itemId;
466
+ }
467
+ const signature = `${status}\0${text}`;
468
+ if (this.lastAnswerCandidateEventByItem.get(itemId) === signature) return;
469
+ this.lastAnswerCandidateEventByItem.set(itemId, signature);
470
+ this.emitAgentEvent({
471
+ stream: "item",
472
+ data: {
473
+ itemId,
474
+ kind: "answer_candidate",
475
+ title: "Answer candidate",
476
+ phase: "update",
477
+ status,
478
+ progressText: text,
479
+ source: "codex-app-server",
480
+ hideFromChannelProgress: true
481
+ }
482
+ });
483
+ }
484
+ supersedeVisibleAnswerCandidate() {
485
+ const itemId = this.visibleAnswerCandidateItemId;
486
+ if (!itemId) return;
487
+ this.emitAnswerCandidate(itemId, "superseded");
488
+ this.visibleAnswerCandidateItemId = void 0;
489
+ }
490
+ markLatestTerminalAssistantCandidate(itemId, activeItemIds, options) {
491
+ this.latestTerminalAssistantCandidateItemId = itemId;
492
+ this.latestTerminalAssistantCandidateSuperseded = false;
493
+ this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = options?.canReleaseAfterToolHandoff === true;
494
+ this.terminalAssistantCandidateEarlierActiveItemIds = new Set(activeItemIds);
495
+ }
496
+ markTerminalAssistantCandidateSupersededBy(itemId, options) {
497
+ if (!this.latestTerminalAssistantCandidateItemId) return;
498
+ if (itemId && this.terminalAssistantCandidateEarlierActiveItemIds.has(itemId)) {
499
+ if (!options?.preserveEarlierActiveItem) this.terminalAssistantCandidateEarlierActiveItemIds.delete(itemId);
500
+ return;
501
+ }
502
+ this.latestTerminalAssistantCandidateSuperseded = true;
503
+ this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
504
+ this.terminalAssistantCandidateEarlierActiveItemIds.clear();
505
+ this.supersedeVisibleAnswerCandidate();
506
+ }
507
+ resolveFinalAssistantTextItem() {
508
+ for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
509
+ const itemId = this.assistantItemOrder[i];
510
+ if (!itemId) continue;
511
+ const text = this.assistantTextByItem.get(itemId)?.trim();
512
+ if (this.assistantPhaseByItem.get(itemId) === "commentary") continue;
513
+ if (text && !this.isToolProgressEchoText(itemId, text)) return {
514
+ itemId,
515
+ text
516
+ };
517
+ }
518
+ }
519
+ rememberAssistantItem(itemId) {
520
+ if (!itemId || this.assistantItemOrder.includes(itemId)) return;
521
+ this.assistantItemOrder.push(itemId);
522
+ this.assistantTimestampByItem.set(itemId, this.nextTranscriptTimestamp());
523
+ }
524
+ isToolProgressEchoText(itemId, text) {
525
+ return this.rawPromotedAssistantItemIds.has(itemId) && this.matchesToolProgressEcho(text);
526
+ }
527
+ };
528
+ //#endregion
529
+ //#region extensions/codex/src/app-server/event-projector-diagnostics.ts
530
+ function redactCodexEventKind(method) {
531
+ return redactSensitiveText(sanitizeTerminalText(method));
532
+ }
533
+ var CodexProjectionDiagnostics = class {
534
+ constructor(threadId, turnId) {
535
+ this.threadId = threadId;
536
+ this.turnId = turnId;
537
+ this.warningKeys = /* @__PURE__ */ new Set();
538
+ }
539
+ warnUnknownItemStatus(item) {
540
+ if (!item) return;
541
+ const status = unknownItemStatus(item);
542
+ if (!status) return;
543
+ const safeStatus = redactCodexEventKind(status);
544
+ const safeItemType = redactCodexEventKind(item.type);
545
+ this.warnOnce(JSON.stringify([
546
+ "status",
547
+ item.type,
548
+ status
549
+ ]), "codex app-server item reported unknown status; continuing projection", {
550
+ itemId: item.id,
551
+ itemType: safeItemType,
552
+ status: safeStatus
553
+ });
554
+ }
555
+ warnUnknownEvent(notification, params) {
556
+ const notificationThreadId = readCodexNotificationThreadId(params);
557
+ const notificationTurnId = readCodexNotificationTurnId(params);
558
+ const eventKind = redactCodexEventKind(notification.method);
559
+ this.warnOnce(JSON.stringify(["method", notification.method]), `codex app-server projector received unknown event kind; continuing: ${eventKind}`, {
560
+ eventKind,
561
+ activeThreadId: this.threadId,
562
+ activeTurnId: this.turnId,
563
+ threadId: notificationThreadId,
564
+ turnId: notificationTurnId,
565
+ matchesActiveThread: notificationThreadId === this.threadId,
566
+ matchesActiveTurn: notificationTurnId === this.turnId
567
+ });
568
+ }
569
+ warnOnce(key, message, context) {
570
+ if (this.warningKeys.has(key)) return;
571
+ this.warningKeys.add(key);
572
+ embeddedAgentLog.warn(message, context);
573
+ }
574
+ };
575
+ //#endregion
576
+ //#region extensions/codex/src/app-server/event-projector-tool-output.ts
577
+ const TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS = 1e4;
578
+ const TOOL_OUTPUT_TRUNCATION_NOTICE_PREFIX = "...(OpenClaw truncated Codex native tool output";
579
+ var ToolOutputAccumulator = class {
580
+ constructor() {
581
+ this.prefixByItem = /* @__PURE__ */ new Map();
582
+ this.originalLengthByItem = /* @__PURE__ */ new Map();
583
+ this.normalizedLengthByItem = /* @__PURE__ */ new Map();
584
+ this.trimStateByItem = /* @__PURE__ */ new Map();
585
+ this.truncatedItemIds = /* @__PURE__ */ new Set();
586
+ this.textByItem = /* @__PURE__ */ new Map();
587
+ }
588
+ append(itemId, delta) {
589
+ const originalLength = (this.originalLengthByItem.get(itemId) ?? this.textByItem.get(itemId)?.length ?? 0) + delta.length;
590
+ this.originalLengthByItem.set(itemId, originalLength);
591
+ const normalizedLength = updateToolOutputTrimState(this.trimStateByItem, itemId, delta);
592
+ this.normalizedLengthByItem.set(itemId, normalizedLength);
593
+ if (this.truncatedItemIds.has(itemId)) {
594
+ const next = appendBoundedToolTranscriptText(this.prefixByItem.get(itemId) ?? this.textByItem.get(itemId) ?? "", "", originalLength);
595
+ this.prefixByItem.set(itemId, next.rawPrefix);
596
+ this.textByItem.set(itemId, next.text);
597
+ return {
598
+ text: next.text,
599
+ originalLength,
600
+ normalizedLength,
601
+ rawPrefix: next.rawPrefix
602
+ };
603
+ }
604
+ const next = appendBoundedToolTranscriptText(this.prefixByItem.get(itemId) ?? this.textByItem.get(itemId) ?? "", delta, originalLength);
605
+ this.prefixByItem.set(itemId, next.rawPrefix);
606
+ this.textByItem.set(itemId, next.text);
607
+ if (originalLength > 1e4) this.truncatedItemIds.add(itemId);
608
+ return {
609
+ text: next.text,
610
+ originalLength,
611
+ normalizedLength,
612
+ rawPrefix: next.rawPrefix
613
+ };
614
+ }
615
+ };
616
+ function updateToolOutputTrimState(trimStateByItem, itemId, delta) {
617
+ const state = trimStateByItem.get(itemId) ?? {
618
+ totalLength: 0,
619
+ leadingWhitespaceLength: 0,
620
+ trailingWhitespaceLength: 0,
621
+ sawNonWhitespace: false
622
+ };
623
+ state.totalLength += delta.length;
624
+ const firstNonWhitespace = delta.search(/\S/u);
625
+ if (firstNonWhitespace === -1) {
626
+ if (!state.sawNonWhitespace) state.leadingWhitespaceLength += delta.length;
627
+ state.trailingWhitespaceLength += delta.length;
628
+ trimStateByItem.set(itemId, state);
629
+ return state.sawNonWhitespace ? state.totalLength - state.leadingWhitespaceLength - state.trailingWhitespaceLength : 0;
630
+ }
631
+ if (!state.sawNonWhitespace) {
632
+ state.leadingWhitespaceLength += firstNonWhitespace;
633
+ state.sawNonWhitespace = true;
634
+ }
635
+ state.trailingWhitespaceLength = delta.match(/\s*$/u)?.[0].length ?? 0;
636
+ trimStateByItem.set(itemId, state);
637
+ return state.totalLength - state.leadingWhitespaceLength - state.trailingWhitespaceLength;
638
+ }
639
+ function toolOutputRawEchoSignature(text) {
640
+ const trimmed = text.trim();
641
+ if (!trimmed) return;
642
+ return {
643
+ rawLength: trimmed.length,
644
+ rawPrefix: trimmed.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)
645
+ };
646
+ }
647
+ function normalizeToolTranscriptArguments(value) {
648
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
649
+ return value;
650
+ }
651
+ function collectDynamicToolContentText(contentItems) {
652
+ if (!Array.isArray(contentItems)) return "";
653
+ return contentItems.flatMap((entry) => {
654
+ if (!isJsonObject(entry)) return [];
655
+ const text = readString$5(entry, "text");
656
+ return text ? [text] : [];
657
+ }).join("\n");
658
+ }
659
+ function appendBoundedToolTranscriptText(currentPrefix, delta, originalLength) {
660
+ if (originalLength <= 1e4) {
661
+ const rawPrefix = currentPrefix + delta;
662
+ return {
663
+ text: rawPrefix,
664
+ rawPrefix
665
+ };
666
+ }
667
+ const notice = toolTranscriptTruncationNotice(originalLength);
668
+ if (notice.length >= 1e4) return {
669
+ text: notice.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS),
670
+ rawPrefix: ""
671
+ };
672
+ const textBudget = TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS - notice.length;
673
+ const remaining = Math.max(0, textBudget - currentPrefix.length);
674
+ const rawPrefix = truncateUtf16Safe(remaining > 0 ? `${currentPrefix}${truncateUtf16Safe(delta, remaining)}` : currentPrefix, textBudget);
675
+ return {
676
+ text: `${rawPrefix}${notice}`,
677
+ rawPrefix
678
+ };
679
+ }
680
+ function toolTranscriptTruncationNotice(originalLength) {
681
+ return `\n${`${TOOL_OUTPUT_TRUNCATION_NOTICE_PREFIX}: original ${originalLength} chars, showing ${TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS}; rerun with narrower args.)`}`;
682
+ }
683
+ function truncateToolTranscriptText(text, originalLength = text.length) {
684
+ if (originalLength <= 1e4 && text.length <= 1e4) return text;
685
+ const notice = toolTranscriptTruncationNotice(originalLength);
686
+ if (notice.length >= 1e4) return notice.slice(1, 10001);
687
+ return `${truncateUtf16Safe(text, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS - notice.length)}${notice}`;
688
+ }
689
+ function formatToolSummary(toolName, meta) {
690
+ const trimmedMeta = meta?.trim();
691
+ return formatToolAggregate(toolName, trimmedMeta ? [trimmedMeta] : void 0, { markdown: true });
692
+ }
693
+ function formatToolOutput(toolName, meta, output) {
694
+ const formattedOutput = formatToolProgressOutput(output);
695
+ if (!formattedOutput) return formatToolSummary(toolName, meta);
696
+ const fence = markdownFenceForText(formattedOutput);
697
+ return `${formatToolSummary(toolName, meta)}\n${fence}txt\n${formattedOutput}\n${fence}`;
698
+ }
699
+ function markdownFenceForText(text) {
700
+ return "`".repeat(Math.max(3, longestBacktickRun(text) + 1));
701
+ }
702
+ function longestBacktickRun(value) {
703
+ let longest = 0;
704
+ let current = 0;
705
+ for (const char of value) {
706
+ if (char === "`") {
707
+ current += 1;
708
+ longest = Math.max(longest, current);
709
+ continue;
710
+ }
711
+ current = 0;
712
+ }
713
+ return longest;
714
+ }
715
+ //#endregion
716
+ //#region extensions/codex/src/app-server/tool-progress-normalization.ts
717
+ /**
718
+ * Normalizes and sanitizes Codex dynamic-tool progress payloads before they are
719
+ * emitted into OpenClaw events or logs.
720
+ */
721
+ /** Maps OpenClaw tool-progress config to the mode used by Codex progress metadata. */
722
+ function resolveCodexToolProgressDetailMode(value) {
723
+ return value === "raw" ? "raw" : "explain";
724
+ }
725
+ /** Recursively redacts sensitive strings and handles circular values in event payloads. */
726
+ function sanitizeCodexAgentEventValue(value, seen = /* @__PURE__ */ new WeakSet()) {
727
+ if (typeof value === "string") return redactToolPayloadText(value);
728
+ if (Array.isArray(value)) {
729
+ if (seen.has(value)) return "[Circular]";
730
+ seen.add(value);
731
+ return value.map((entry) => sanitizeCodexAgentEventValue(entry, seen));
732
+ }
733
+ if (value && typeof value === "object") {
734
+ if (seen.has(value)) return "[Circular]";
735
+ seen.add(value);
736
+ const out = {};
737
+ for (const [key, child] of Object.entries(value)) out[key] = typeof child === "string" ? redactSensitiveFieldValue(key, child) : sanitizeCodexAgentEventValue(child, seen);
738
+ return out;
739
+ }
740
+ return value;
741
+ }
742
+ /** Sanitizes a record-shaped Codex agent event payload. */
743
+ function sanitizeCodexAgentEventRecord(value) {
744
+ return sanitizeCodexAgentEventValue(value);
745
+ }
746
+ /** Sanitizes dynamic-tool arguments before diagnostic/event emission. */
747
+ function sanitizeCodexToolArguments(value) {
748
+ if (!isJsonObject(value)) return;
749
+ return sanitizeCodexAgentEventRecord(value);
750
+ }
751
+ /** Sanitizes a Codex dynamic-tool response before diagnostic/event emission. */
752
+ function sanitizeCodexToolResponse(response) {
753
+ return sanitizeCodexAgentEventRecord(response);
754
+ }
755
+ /** Infers compact human-readable tool metadata from Codex dynamic-tool arguments. */
756
+ function inferCodexDynamicToolMeta(call, detailMode) {
757
+ return inferToolMetaFromArgs(call.tool, call.arguments, { detailMode });
758
+ }
759
+ //#endregion
760
+ //#region extensions/codex/src/app-server/event-projector-tool-items.ts
761
+ function nativeToolActionFingerprint(item) {
762
+ if (item.type === "commandExecution" && typeof item.command === "string") return JSON.stringify({
763
+ type: item.type,
764
+ command: item.command,
765
+ cwd: typeof item.cwd === "string" ? item.cwd : ""
766
+ });
767
+ if (item.type === "fileChange") return JSON.stringify({
768
+ type: item.type,
769
+ changes: itemFileChanges(item)
770
+ });
771
+ }
772
+ function isNativePostToolUseRelayItem(item) {
773
+ switch (item.type) {
774
+ case "commandExecution":
775
+ case "fileChange":
776
+ case "mcpToolCall": return true;
777
+ default: return false;
778
+ }
779
+ }
780
+ function shouldSuppressChannelProgressForItem(item) {
781
+ if (shouldSynthesizeToolProgressForItem(item)) return true;
782
+ return item.type === "dynamicToolCall";
783
+ }
784
+ function itemToolArgs(item) {
785
+ if (item.type === "commandExecution") return sanitizeCodexAgentEventRecord({
786
+ command: item.command,
787
+ ...typeof item.cwd === "string" ? { cwd: item.cwd } : {}
788
+ });
789
+ if (item.type === "fileChange") return sanitizeCodexAgentEventRecord({ changes: itemFileChangesForTranscript(item) });
790
+ if (item.type === "webSearch") return webSearchToolArgs(item);
791
+ if (item.type === "dynamicToolCall" || item.type === "mcpToolCall") return sanitizeCodexToolArguments(item.arguments);
792
+ }
793
+ function webSearchToolArgs(item) {
794
+ const action = isJsonObject(item.action) ? item.action : void 0;
795
+ const actionType = action ? readNonEmptyString$1(action, "type") : void 0;
796
+ const queries = action && actionType === "search" ? readNonEmptyStringArray(action, "queries") : [];
797
+ const query = normalizeNonEmptyString(item.query) ?? (action && actionType === "search" ? readNonEmptyString$1(action, "query") : void 0) ?? queries[0];
798
+ const url = action ? readNonEmptyString$1(action, "url") : void 0;
799
+ const pattern = action ? readNonEmptyString$1(action, "pattern") : void 0;
800
+ const args = {};
801
+ if (query) args.query = query;
802
+ if (queries.length > 0) args.queries = queries;
803
+ if (actionType && actionType !== "search") args.action = actionType;
804
+ if (url) args.url = url;
805
+ if (pattern) args.pattern = pattern;
806
+ if (!query && !url && !pattern) args.queryUnavailable = true;
807
+ return sanitizeCodexAgentEventRecord(args);
808
+ }
809
+ function itemToolResult(item) {
810
+ if (item.type === "commandExecution") return { result: sanitizeCodexAgentEventRecord({
811
+ status: item.status,
812
+ exitCode: item.exitCode,
813
+ durationMs: item.durationMs
814
+ }) };
815
+ if (item.type === "fileChange") return { result: sanitizeCodexAgentEventRecord({
816
+ status: item.status,
817
+ changes: itemFileChanges(item)
818
+ }) };
819
+ if (item.type === "mcpToolCall") return { result: sanitizeCodexAgentEventRecord({
820
+ status: item.status,
821
+ durationMs: item.durationMs,
822
+ ...item.error ? { error: item.error } : {},
823
+ ...item.result ? { result: item.result } : {}
824
+ }) };
825
+ if (item.type === "webSearch") return { result: webSearchToolResult(item) };
826
+ return {};
827
+ }
828
+ function webSearchToolResult(item) {
829
+ return sanitizeCodexAgentEventRecord({
830
+ status: itemStatus(item),
831
+ ...typeof item.durationMs === "number" ? { durationMs: item.durationMs } : {},
832
+ ...webSearchToolArgs(item)
833
+ });
834
+ }
835
+ function itemFileChangeRecords(item) {
836
+ const changes = item.changes;
837
+ return Array.isArray(changes) ? changes.filter(isJsonObject) : [];
838
+ }
839
+ function itemFileChanges(item) {
840
+ return itemFileChangeRecords(item).flatMap((change) => {
841
+ const path = normalizeNonEmptyString(change.path);
842
+ if (!path || change.kind === void 0) return [];
843
+ return [{
844
+ path,
845
+ kind: change.kind
846
+ }];
847
+ });
848
+ }
849
+ function fileChangeKindType(kind) {
850
+ if (typeof kind === "string") return kind;
851
+ return isJsonObject(kind) ? normalizeNonEmptyString(kind.type) : void 0;
852
+ }
853
+ function countFileContentLines(content) {
854
+ if (!content) return 0;
855
+ const lines = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
856
+ if (lines.length > 1 && lines.at(-1) === "") lines.pop();
857
+ return lines.length;
858
+ }
859
+ function fileChangeDiffStat(diff, kind) {
860
+ const kindType = fileChangeKindType(kind);
861
+ if (kindType === "add") return {
862
+ added: countFileContentLines(diff),
863
+ removed: 0
864
+ };
865
+ if (kindType === "delete") return {
866
+ added: 0,
867
+ removed: countFileContentLines(diff)
868
+ };
869
+ let added = 0;
870
+ let removed = 0;
871
+ let inHunk = false;
872
+ for (const line of diff.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n")) {
873
+ if (line.startsWith("@@")) {
874
+ inHunk = true;
875
+ continue;
876
+ }
877
+ if (!inHunk) continue;
878
+ if (line.startsWith("+")) added += 1;
879
+ else if (line.startsWith("-")) removed += 1;
880
+ }
881
+ return {
882
+ added,
883
+ removed
884
+ };
885
+ }
886
+ function truncateFileChangeDiffAtLineBoundary(diff, maxChars) {
887
+ if (diff.length <= maxChars) return { diff };
888
+ if (maxChars <= 0) return { diffTruncated: true };
889
+ const boundary = diff.lastIndexOf("\n", maxChars - 1);
890
+ return boundary >= 0 ? {
891
+ diff: diff.slice(0, boundary + 1),
892
+ diffTruncated: true
893
+ } : { diffTruncated: true };
894
+ }
895
+ function itemFileChangesForTranscript(item) {
896
+ let remainingDiffChars = 1e4;
897
+ return itemFileChangeRecords(item).flatMap((change) => {
898
+ const path = normalizeNonEmptyString(change.path);
899
+ if (!path || change.kind === void 0) return [];
900
+ const result = {
901
+ path,
902
+ kind: change.kind
903
+ };
904
+ if (typeof change.diff !== "string") return [result];
905
+ result.stat = fileChangeDiffStat(change.diff, change.kind);
906
+ const bounded = truncateFileChangeDiffAtLineBoundary(change.diff, remainingDiffChars);
907
+ if (bounded.diff !== void 0) {
908
+ result.diff = bounded.diff;
909
+ remainingDiffChars -= bounded.diff.length;
910
+ }
911
+ if (bounded.diffTruncated) result.diffTruncated = true;
912
+ return [result];
913
+ });
914
+ }
915
+ function itemToolError(item, status, outputTextByItem) {
916
+ if (status === "blocked") return "codex native tool blocked";
917
+ if (status !== "failed") return;
918
+ return itemOutputText(item, outputTextByItem) ?? "codex native tool failed";
919
+ }
920
+ function itemMeta(item, detailMode = "explain") {
921
+ if (item.type === "commandExecution" && typeof item.command === "string") return inferToolMetaFromArgs("exec", {
922
+ command: item.command,
923
+ cwd: typeof item.cwd === "string" ? item.cwd : void 0
924
+ }, { detailMode });
925
+ if (item.type === "webSearch") return inferToolMetaFromArgs("web_search", webSearchToolArgs(item), { detailMode });
926
+ const toolName = itemName(item);
927
+ if ((item.type === "dynamicToolCall" || item.type === "mcpToolCall") && toolName) return inferToolMetaFromArgs(toolName, item.arguments, { detailMode });
928
+ }
929
+ function itemOutputText(item, outputTextByItem) {
930
+ if (item.type === "commandExecution") {
931
+ const output = item.aggregatedOutput?.trim() || outputTextByItem?.get(item.id)?.trim();
932
+ return output ? truncateToolTranscriptText(output) : void 0;
933
+ }
934
+ if (item.type === "dynamicToolCall") {
935
+ const output = collectDynamicToolContentText(item.contentItems).trim();
936
+ return output ? truncateToolTranscriptText(output) : void 0;
937
+ }
938
+ if (item.type === "mcpToolCall") {
939
+ const output = item.error ? stringifyJsonValue(item.error) : item.result ? stringifyJsonValue(item.result) : void 0;
940
+ return output ? truncateToolTranscriptText(output) : void 0;
941
+ }
942
+ }
943
+ function itemTranscriptResultText(item, outputTextByItem) {
944
+ const output = itemOutputText(item, outputTextByItem);
945
+ if (output) return output;
946
+ const result = itemToolResult(item).result;
947
+ const resultText = result ? stringifyJsonValue(result) : void 0;
948
+ return resultText ? truncateToolTranscriptText(resultText) : itemStatus(item);
949
+ }
950
+ function stringifyJsonValue(value) {
951
+ try {
952
+ return JSON.stringify(value, null, 2);
953
+ } catch {
954
+ return;
955
+ }
956
+ }
957
+ //#endregion
958
+ //#region extensions/codex/src/app-server/event-projector-tool-progress.ts
959
+ const TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES = /* @__PURE__ */ new Set([
960
+ "message",
961
+ "messages",
962
+ "reply",
963
+ "send",
964
+ "reaction",
965
+ "react",
966
+ "typing"
967
+ ]);
968
+ function shouldEmitTranscriptToolProgress(toolName, _args) {
969
+ const normalized = typeof toolName === "string" ? toolName.trim().toLowerCase() : "";
970
+ return Boolean(normalized && !TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES.has(normalized));
971
+ }
972
+ var CodexToolProgressProjection = class {
973
+ constructor(params) {
974
+ this.params = params;
975
+ this.echoesByItem = /* @__PURE__ */ new Map();
976
+ this.resultSummaryItemIds = /* @__PURE__ */ new Set();
977
+ this.resultOutputItemIds = /* @__PURE__ */ new Set();
978
+ this.resultOutputStreamedItemIds = /* @__PURE__ */ new Set();
979
+ this.transcriptProgressSuppressedIds = /* @__PURE__ */ new Set();
980
+ this.transcriptArgumentsById = /* @__PURE__ */ new Map();
981
+ this.resultOutputDeltaState = /* @__PURE__ */ new Map();
982
+ this.output = new ToolOutputAccumulator();
983
+ this.metas = /* @__PURE__ */ new Map();
984
+ this.sideEffectingNativeIds = /* @__PURE__ */ new Set();
985
+ this.sideEffectingDynamicIds = /* @__PURE__ */ new Set();
986
+ this.transcriptProgressCallIds = /* @__PURE__ */ new Set();
987
+ }
988
+ get outputTextByItem() {
989
+ return this.output.textByItem;
990
+ }
991
+ get toolMetas() {
992
+ return [...this.metas.values()];
993
+ }
994
+ getToolMeta(itemId) {
995
+ return this.metas.get(itemId);
996
+ }
997
+ get lastToolError() {
998
+ return this.lastNativeToolError;
999
+ }
1000
+ get hasPotentialSideEffects() {
1001
+ return this.sideEffectingNativeIds.size > 0 || this.sideEffectingDynamicIds.size > 0;
1002
+ }
1003
+ setLastToolError(error) {
1004
+ if (!error) {
1005
+ this.lastNativeToolError = void 0;
1006
+ return;
1007
+ }
1008
+ const terminalResolution = this.params.observeToolTerminal?.({
1009
+ toolName: error.toolName,
1010
+ ...error.meta ? { meta: error.meta } : {},
1011
+ outcome: "failure",
1012
+ failure: {
1013
+ ...error.errorCode ? { errorCode: error.errorCode } : {},
1014
+ ...error.error ? { error: error.error } : {},
1015
+ ...error.validationErrorSummary ? { validationErrorSummary: error.validationErrorSummary } : {},
1016
+ ...error.timedOut ? { timedOut: true } : {},
1017
+ ...error.middlewareError ? { middlewareError: true } : {}
1018
+ },
1019
+ nativeMutation: {
1020
+ mutatingAction: error.mutatingAction === true,
1021
+ replaySafe: error.mutatingAction !== true,
1022
+ ...error.actionFingerprint ? { actionFingerprint: error.actionFingerprint } : {},
1023
+ ...error.fileTarget ? { fileTarget: error.fileTarget } : {}
1024
+ }
1025
+ });
1026
+ this.lastNativeToolError = terminalResolution?.lastToolError ?? (this.lastNativeToolError?.mutatingAction && error.mutatingAction !== true ? this.lastNativeToolError : error);
1027
+ }
1028
+ recordDynamicToolResult(params) {
1029
+ const resultText = collectDynamicToolContentText(params.contentItems);
1030
+ const existing = this.metas.get(params.callId);
1031
+ this.metas.set(params.callId, {
1032
+ toolName: existing?.toolName ?? params.tool,
1033
+ ...existing?.meta ? { meta: existing.meta } : {},
1034
+ ...params.asyncStarted === true ? { asyncStarted: true } : {},
1035
+ ...!params.success ? { isError: true } : {}
1036
+ });
1037
+ if (params.terminalResolution) this.lastNativeToolError = params.terminalResolution.lastToolError;
1038
+ else if (!params.success) this.lastNativeToolError = {
1039
+ toolName: params.tool,
1040
+ error: resultText || (params.terminalType === "blocked" ? "codex dynamic tool blocked" : "codex dynamic tool failed")
1041
+ };
1042
+ else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
1043
+ if (params.sideEffectEvidence === true) this.sideEffectingDynamicIds.add(params.callId);
1044
+ }
1045
+ handleOutputDelta(params, toolName) {
1046
+ const itemId = readString$5(params, "itemId");
1047
+ const delta = readString$5(params, "delta");
1048
+ if (!itemId || !delta) return;
1049
+ const storedOutput = this.output.append(itemId, delta);
1050
+ this.rememberEcho(itemId, {
1051
+ displayText: storedOutput.text,
1052
+ rawLength: storedOutput.normalizedLength,
1053
+ rawPrefix: storedOutput.rawPrefix,
1054
+ streamedDisplay: true
1055
+ });
1056
+ if (!this.shouldEmitToolOutput()) return;
1057
+ if (this.transcriptProgressSuppressedIds.has(itemId) || !shouldEmitTranscriptToolProgress(toolName, this.transcriptArgumentsById.get(itemId))) return;
1058
+ const state = this.resultOutputDeltaState.get(itemId) ?? {
1059
+ chars: 0,
1060
+ messages: 0,
1061
+ truncated: false
1062
+ };
1063
+ if (state.truncated) return;
1064
+ const remainingChars = Math.max(0, TOOL_PROGRESS_OUTPUT_MAX_CHARS - state.chars);
1065
+ const remainingMessages = Math.max(0, 20 - state.messages);
1066
+ if (remainingChars === 0 || remainingMessages === 0) {
1067
+ state.truncated = true;
1068
+ this.resultOutputDeltaState.set(itemId, state);
1069
+ this.emitToolResultMessage({
1070
+ itemId,
1071
+ text: formatToolOutput(toolName, void 0, "(output truncated)")
1072
+ });
1073
+ return;
1074
+ }
1075
+ const chunk = delta.length > remainingChars ? truncateUtf16Safe(delta, remainingChars) : delta;
1076
+ state.chars += chunk.length;
1077
+ state.messages += 1;
1078
+ const reachedLimit = delta.length > remainingChars || state.chars >= TOOL_PROGRESS_OUTPUT_MAX_CHARS || state.messages >= 20;
1079
+ if (reachedLimit) state.truncated = true;
1080
+ this.resultOutputDeltaState.set(itemId, state);
1081
+ this.resultOutputStreamedItemIds.add(itemId);
1082
+ this.emitToolResultMessage({
1083
+ itemId,
1084
+ text: formatToolOutput(toolName, void 0, reachedLimit ? `${chunk}\n...(truncated)...` : chunk)
1085
+ });
1086
+ }
1087
+ recordNativeToolError(params) {
1088
+ const executionStarted = params.status !== "blocked";
1089
+ const mutatingAction = executionStarted && isMutatingNativeToolItem(params.item);
1090
+ const actionFingerprint = mutatingAction ? nativeToolActionFingerprint(params.item) : void 0;
1091
+ const isFailure = isNonSuccessItemStatus(params.status);
1092
+ const error = isFailure ? itemToolError(params.item, params.status, this.output.textByItem) : void 0;
1093
+ const terminalResolution = this.params.observeToolTerminal?.({
1094
+ toolCallId: params.item.id,
1095
+ toolName: params.name,
1096
+ arguments: itemToolArgs(params.item),
1097
+ ...params.meta ? { meta: params.meta } : {},
1098
+ executionStarted,
1099
+ outcome: isFailure ? "failure" : "success",
1100
+ ...isFailure ? { failure: error ? { error } : {} } : {},
1101
+ nativeMutation: {
1102
+ mutatingAction,
1103
+ replaySafe: !mutatingAction,
1104
+ ...actionFingerprint ? { actionFingerprint } : {}
1105
+ }
1106
+ });
1107
+ if (terminalResolution) {
1108
+ this.lastNativeToolError = terminalResolution.lastToolError;
1109
+ return;
1110
+ }
1111
+ if (isFailure) this.lastNativeToolError = {
1112
+ toolName: params.name,
1113
+ ...params.meta ? { meta: params.meta } : {},
1114
+ ...error ? { error } : {},
1115
+ ...mutatingAction ? { mutatingAction: true } : {},
1116
+ ...actionFingerprint ? { actionFingerprint } : {}
1117
+ };
1118
+ else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
1119
+ }
1120
+ emitToolResultSummary(item) {
1121
+ if (!item || !this.params.onToolResult || !this.shouldEmitToolResult()) return;
1122
+ if (this.resultSummaryItemIds.has(item.id)) return;
1123
+ const toolName = itemName(item);
1124
+ if (!toolName || !shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
1125
+ this.resultSummaryItemIds.add(item.id);
1126
+ this.emitToolResultMessage({
1127
+ itemId: item.id,
1128
+ text: formatToolSummary(toolName, itemMeta(item, this.toolProgressDetailMode()))
1129
+ });
1130
+ }
1131
+ emitToolResultOutput(item) {
1132
+ if (!item || !this.params.onToolResult || !this.shouldEmitToolOutput()) return;
1133
+ if (this.resultOutputItemIds.has(item.id) || this.resultOutputStreamedItemIds.has(item.id)) return;
1134
+ const toolName = itemName(item);
1135
+ const output = itemOutputText(item, this.output.textByItem);
1136
+ if (!toolName || !output || !shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
1137
+ this.emitToolResultMessage({
1138
+ itemId: item.id,
1139
+ text: formatToolOutput(toolName, itemMeta(item, this.toolProgressDetailMode()), output),
1140
+ finalOutput: true,
1141
+ isError: isNonSuccessItemStatus(itemStatus(item))
1142
+ });
1143
+ }
1144
+ recordToolMeta(item) {
1145
+ if (!item) return;
1146
+ if (isSideEffectingNativeToolItem(item)) this.sideEffectingNativeIds.add(item.id);
1147
+ else this.sideEffectingNativeIds.delete(item.id);
1148
+ const toolName = itemName(item);
1149
+ if (!toolName) return;
1150
+ const meta = itemMeta(item, this.toolProgressDetailMode());
1151
+ const status = itemStatus(item);
1152
+ const existing = this.metas.get(item.id);
1153
+ this.metas.set(item.id, {
1154
+ toolName,
1155
+ ...meta ? { meta } : {},
1156
+ ...existing?.asyncStarted ? { asyncStarted: true } : {},
1157
+ ...status !== "running" && isNonSuccessItemStatus(status) ? { isError: true } : {}
1158
+ });
1159
+ }
1160
+ recordTranscriptCall(params) {
1161
+ this.transcriptArgumentsById.set(params.id, params.arguments);
1162
+ if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) this.transcriptProgressSuppressedIds.add(params.id);
1163
+ else this.transcriptProgressSuppressedIds.delete(params.id);
1164
+ this.emitTranscriptToolCallProgress(params);
1165
+ }
1166
+ recordTranscriptResult(params) {
1167
+ this.emitTranscriptToolResultProgress(params);
1168
+ }
1169
+ matchesEcho(text) {
1170
+ for (const state of this.echoesByItem.values()) {
1171
+ if (state.streamedDisplayText === text || state.displayTexts.includes(text)) return true;
1172
+ if (state.streamedRawSignature && text.length === state.streamedRawSignature.length && text.startsWith(state.streamedRawSignature.prefix)) return true;
1173
+ for (const signature of state.rawSignatures) if (text.length === signature.length && text.startsWith(signature.prefix)) return true;
1174
+ }
1175
+ return false;
1176
+ }
1177
+ rememberCommandAggregateOutputEcho(item) {
1178
+ if (item?.type !== "commandExecution" || typeof item.aggregatedOutput !== "string") return;
1179
+ const signature = toolOutputRawEchoSignature(item.aggregatedOutput);
1180
+ if (signature) this.rememberEcho(item.id, signature);
1181
+ }
1182
+ toolProgressDetailMode() {
1183
+ return resolveCodexToolProgressDetailMode(this.params.toolProgressDetail);
1184
+ }
1185
+ emitToolResultMessage(params) {
1186
+ const rawText = params.text.trim();
1187
+ const text = truncateToolTranscriptText(rawText);
1188
+ if (!text) return;
1189
+ this.rememberEcho(params.itemId, {
1190
+ displayText: text,
1191
+ rawText
1192
+ });
1193
+ if (params.finalOutput) this.resultOutputItemIds.add(params.itemId);
1194
+ try {
1195
+ Promise.resolve(this.params.onToolResult?.({
1196
+ text,
1197
+ ...params.isError === true ? { isError: true } : {}
1198
+ })).catch(() => {});
1199
+ } catch {}
1200
+ }
1201
+ shouldEmitToolResult() {
1202
+ return typeof this.params.shouldEmitToolResult === "function" ? this.params.shouldEmitToolResult() : this.params.verboseLevel === "on" || this.params.verboseLevel === "full";
1203
+ }
1204
+ shouldEmitToolOutput() {
1205
+ return typeof this.params.shouldEmitToolOutput === "function" ? this.params.shouldEmitToolOutput() : this.params.verboseLevel === "full";
1206
+ }
1207
+ emitTranscriptToolCallProgress(params) {
1208
+ if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) return;
1209
+ this.transcriptProgressCallIds.add(params.id);
1210
+ const args = normalizeToolTranscriptArguments(params.arguments);
1211
+ const meta = inferToolMetaFromArgs(params.name, args, { detailMode: this.toolProgressDetailMode() });
1212
+ if (!this.params.onToolResult || !this.shouldEmitToolResult() || this.resultSummaryItemIds.has(params.id) || this.resultOutputStreamedItemIds.has(params.id)) return;
1213
+ this.resultSummaryItemIds.add(params.id);
1214
+ this.emitToolResultMessage({
1215
+ itemId: params.id,
1216
+ text: formatToolSummary(params.name, meta)
1217
+ });
1218
+ }
1219
+ emitTranscriptToolResultProgress(params) {
1220
+ if (this.transcriptProgressSuppressedIds.has(params.id) || !shouldEmitTranscriptToolProgress(params.name, this.transcriptArgumentsById.get(params.id))) return;
1221
+ if (!this.transcriptProgressCallIds.has(params.id)) this.emitTranscriptToolCallProgress({
1222
+ id: params.id,
1223
+ name: params.name,
1224
+ arguments: {}
1225
+ });
1226
+ if (!this.params.onToolResult || !this.shouldEmitToolOutput() || this.resultOutputItemIds.has(params.id) || this.resultOutputStreamedItemIds.has(params.id)) return;
1227
+ const text = params.text?.trim();
1228
+ if (text) this.emitToolResultMessage({
1229
+ itemId: params.id,
1230
+ text: formatToolOutput(params.name, void 0, text),
1231
+ finalOutput: true,
1232
+ isError: params.isError
1233
+ });
1234
+ }
1235
+ rememberEcho(itemId, signature) {
1236
+ if (!itemId) return;
1237
+ const existing = this.echoesByItem.get(itemId) ?? {
1238
+ displayTexts: [],
1239
+ rawSignatures: []
1240
+ };
1241
+ const displayText = signature.displayText?.trim();
1242
+ if (displayText) {
1243
+ if (signature.streamedDisplay) existing.streamedDisplayText = displayText;
1244
+ else if (!existing.displayTexts.includes(displayText)) {
1245
+ if (existing.displayTexts.length >= 24) existing.displayTexts.shift();
1246
+ existing.displayTexts.push(displayText);
1247
+ }
1248
+ }
1249
+ const rawText = signature.rawText?.trim();
1250
+ const rawLength = signature.rawLength ?? rawText?.length;
1251
+ const rawPrefix = signature.rawPrefix?.trim() ?? rawText;
1252
+ if (rawLength !== void 0 && rawPrefix && rawPrefix.length >= 1024) {
1253
+ const next = {
1254
+ length: rawLength,
1255
+ prefix: rawPrefix.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)
1256
+ };
1257
+ if (signature.streamedDisplay) existing.streamedRawSignature = next;
1258
+ else {
1259
+ const matchIndex = existing.rawSignatures.findIndex((entry) => entry.prefix === next.prefix);
1260
+ if (matchIndex >= 0) existing.rawSignatures[matchIndex] = next;
1261
+ else {
1262
+ if (existing.rawSignatures.length >= 24) existing.rawSignatures.shift();
1263
+ existing.rawSignatures.push(next);
1264
+ }
1265
+ }
1266
+ }
1267
+ this.echoesByItem.set(itemId, existing);
1268
+ }
1269
+ };
1270
+ //#endregion
1271
+ //#region extensions/codex/src/app-server/session-history.ts
1272
+ /**
1273
+ * Reads OpenClaw session history for Codex transcript mirroring and sanitizes
1274
+ * image payloads before replaying messages into the app-server projector.
1275
+ */
1276
+ function isMissingFileError(error) {
1277
+ return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
1278
+ }
1279
+ /** Returns sanitized session-context messages for a Codex mirrored session file. */
1280
+ async function readCodexMirroredSessionHistoryMessages(target) {
1281
+ try {
1282
+ const entries = await readCodexMirroredSessionEntries(target);
1283
+ if (entries.length === 0) return [];
1284
+ const firstEntry = entries[0];
1285
+ if (firstEntry?.type !== "session") return [];
1286
+ if (typeof firstEntry.id !== "string") return;
1287
+ migrateSessionEntries(entries);
1288
+ return sanitizeCodexHistoryImagePayloads(buildSessionContext(entries.filter((entry) => {
1289
+ return entry !== null && typeof entry === "object" && !Array.isArray(entry) && entry.type !== "session";
1290
+ })).messages, "codex mirrored history");
1291
+ } catch (error) {
1292
+ if (isMissingFileError(error)) return [];
1293
+ return;
1294
+ }
1295
+ }
1296
+ async function readCodexMirroredSessionEntries(target) {
1297
+ const sqliteMarker = parseSqliteSessionFileMarker(target.sessionFile);
1298
+ if (sqliteMarker) {
1299
+ if (sqliteMarker.sessionId !== target.sessionId || target.agentId !== void 0 && sqliteMarker.agentId !== target.agentId) return [];
1300
+ const sessionKey = resolveSqliteMarkerSessionKey(target, sqliteMarker);
1301
+ if (!sessionKey) return [];
1302
+ return await readSessionTranscriptEvents({
1303
+ agentId: sqliteMarker.agentId,
1304
+ sessionId: sqliteMarker.sessionId,
1305
+ sessionKey,
1306
+ storePath: sqliteMarker.storePath
1307
+ });
1308
+ }
1309
+ return parseSessionEntries(await fs.readFile(target.sessionFile, "utf-8"));
1310
+ }
1311
+ function resolveSqliteMarkerSessionKey(target, marker) {
1312
+ const explicitSessionKey = target.sessionKey?.trim();
1313
+ if (explicitSessionKey) return explicitSessionKey;
1314
+ const entries = listSessionEntries({
1315
+ agentId: marker.agentId,
1316
+ readOnly: true,
1317
+ storePath: marker.storePath
1318
+ });
1319
+ return (entries.find(({ entry }) => {
1320
+ return entry.sessionId === marker.sessionId && entry.sessionFile === target.sessionFile;
1321
+ }) ?? entries.find(({ entry }) => {
1322
+ return entry.sessionId === marker.sessionId;
1323
+ }))?.sessionKey;
1324
+ }
1325
+ //#endregion
1326
+ //#region extensions/codex/src/app-server/event-projector-tool-transcript.ts
1327
+ const ZERO_USAGE = {
1328
+ input: 0,
1329
+ output: 0,
1330
+ cacheRead: 0,
1331
+ cacheWrite: 0,
1332
+ totalTokens: 0,
1333
+ cost: {
1334
+ input: 0,
1335
+ output: 0,
1336
+ cacheRead: 0,
1337
+ cacheWrite: 0,
1338
+ total: 0
1339
+ }
1340
+ };
1341
+ const MISSING_TOOL_RESULT_ERROR = "OpenClaw recorded a native Codex tool.call without a matching tool.result before the turn completed.";
1342
+ var CodexToolTranscriptProjection = class {
1343
+ constructor(params, threadId, turnId, progress, nextTranscriptTimestamp, options = {}) {
1344
+ this.params = params;
1345
+ this.threadId = threadId;
1346
+ this.turnId = turnId;
1347
+ this.progress = progress;
1348
+ this.nextTranscriptTimestamp = nextTranscriptTimestamp;
1349
+ this.options = options;
1350
+ this.messages = [];
1351
+ this.callIds = /* @__PURE__ */ new Set();
1352
+ this.resultIds = /* @__PURE__ */ new Set();
1353
+ this.namesById = /* @__PURE__ */ new Map();
1354
+ this.trajectoryCallIds = /* @__PURE__ */ new Set();
1355
+ this.trajectoryResultIds = /* @__PURE__ */ new Set();
1356
+ this.trajectoryNamesById = /* @__PURE__ */ new Map();
1357
+ this.trajectoryItemsById = /* @__PURE__ */ new Map();
1358
+ this.afterToolCallObservedItemIds = /* @__PURE__ */ new Set();
1359
+ }
1360
+ get transcriptMessages() {
1361
+ return this.messages;
1362
+ }
1363
+ recordDynamicToolCall(params) {
1364
+ this.recordToolCall({
1365
+ id: params.callId,
1366
+ name: params.tool,
1367
+ arguments: sanitizeCodexToolArguments(params.arguments)
1368
+ });
1369
+ }
1370
+ recordDynamicToolResult(params) {
1371
+ this.recordToolResult({
1372
+ id: params.callId,
1373
+ name: params.tool,
1374
+ text: collectDynamicToolContentText(params.contentItems),
1375
+ isError: !params.success
1376
+ });
1377
+ }
1378
+ recordNativeToolCall(item) {
1379
+ if (!item || !shouldRecordNativeToolTranscript(item)) return;
1380
+ const name = itemName(item);
1381
+ if (name) this.recordToolCall({
1382
+ id: item.id,
1383
+ name,
1384
+ arguments: itemToolArgs(item)
1385
+ });
1386
+ }
1387
+ recordNativeToolResult(item) {
1388
+ if (!item || !shouldRecordNativeToolTranscript(item)) return;
1389
+ const name = itemName(item);
1390
+ if (name) this.recordToolResult({
1391
+ id: item.id,
1392
+ name,
1393
+ text: itemTranscriptResultText(item, this.progress.outputTextByItem),
1394
+ isError: isNonSuccessItemStatus(itemStatus(item))
1395
+ });
1396
+ }
1397
+ recordTrajectoryEvent(params) {
1398
+ if (params.phase === "start") {
1399
+ this.trajectoryCallIds.add(params.item.id);
1400
+ this.trajectoryNamesById.set(params.item.id, params.name);
1401
+ this.trajectoryItemsById.set(params.item.id, params.item);
1402
+ this.options.trajectoryRecorder?.recordEvent("tool.call", {
1403
+ threadId: this.threadId,
1404
+ turnId: this.turnId,
1405
+ itemId: params.item.id,
1406
+ toolCallId: params.item.id,
1407
+ name: params.name,
1408
+ arguments: params.args
1409
+ });
1410
+ return;
1411
+ }
1412
+ this.trajectoryResultIds.add(params.item.id);
1413
+ const toolResult = itemToolResult(params.item).result;
1414
+ const output = itemOutputText(params.item, this.progress.outputTextByItem);
1415
+ this.options.trajectoryRecorder?.recordEvent("tool.result", {
1416
+ threadId: this.threadId,
1417
+ turnId: this.turnId,
1418
+ itemId: params.item.id,
1419
+ toolCallId: params.item.id,
1420
+ name: params.name,
1421
+ status: params.status,
1422
+ isError: isNonSuccessItemStatus(params.status),
1423
+ ...toolResult ? { result: toolResult } : {},
1424
+ ...output ? { output } : {}
1425
+ });
1426
+ }
1427
+ emitAfterToolCallObservation(item) {
1428
+ if (!this.shouldEmitAfterToolCallObservation(item)) return;
1429
+ const name = itemName(item);
1430
+ const status = itemStatus(item);
1431
+ if (!name || status === "running") return;
1432
+ this.afterToolCallObservedItemIds.add(item.id);
1433
+ const result = itemToolResult(item).result;
1434
+ const error = itemToolError(item, status, this.progress.outputTextByItem);
1435
+ const startedAt = resolveStartedAtFromDurationMs(item.durationMs);
1436
+ const hookParams = {
1437
+ toolName: name,
1438
+ toolCallId: item.id,
1439
+ runId: this.params.runId,
1440
+ agentId: this.params.agentId,
1441
+ sessionId: this.params.sessionId,
1442
+ sessionKey: this.params.sessionKey,
1443
+ startArgs: itemToolArgs(item) ?? {},
1444
+ ...result !== void 0 ? { result } : {},
1445
+ ...error ? { error } : {},
1446
+ ...startedAt !== void 0 ? { startedAt } : {}
1447
+ };
1448
+ setImmediate(() => {
1449
+ runAgentHarnessAfterToolCallHook(hookParams);
1450
+ });
1451
+ }
1452
+ synthesizeMissingToolResults(params) {
1453
+ if (!params.synthesize) return;
1454
+ const missingTranscriptIds = [...this.callIds].filter((id) => !this.resultIds.has(id));
1455
+ const missingTrajectoryIds = [...this.trajectoryCallIds].filter((id) => !this.trajectoryResultIds.has(id));
1456
+ if (missingTranscriptIds.length === 0 && missingTrajectoryIds.length === 0) return;
1457
+ for (const id of missingTranscriptIds) {
1458
+ const name = this.namesById.get(id) ?? this.trajectoryNamesById.get(id);
1459
+ if (name) this.recordToolResult({
1460
+ id,
1461
+ name,
1462
+ text: formatMissingToolResultError({
1463
+ id,
1464
+ name
1465
+ }),
1466
+ isError: true
1467
+ });
1468
+ }
1469
+ for (const id of missingTrajectoryIds) {
1470
+ const name = this.trajectoryNamesById.get(id) ?? this.namesById.get(id);
1471
+ if (!name) continue;
1472
+ this.trajectoryResultIds.add(id);
1473
+ const text = formatMissingToolResultError({
1474
+ id,
1475
+ name
1476
+ });
1477
+ this.options.trajectoryRecorder?.recordEvent("tool.result", {
1478
+ threadId: this.threadId,
1479
+ turnId: this.turnId,
1480
+ itemId: id,
1481
+ toolCallId: id,
1482
+ name,
1483
+ status: "failed",
1484
+ isError: true,
1485
+ result: {
1486
+ status: "failed",
1487
+ reason: "missing_tool_result"
1488
+ },
1489
+ output: text
1490
+ });
1491
+ }
1492
+ if (!params.recordPromptError) {
1493
+ this.recordMissingToolError(missingTranscriptIds, missingTrajectoryIds);
1494
+ return;
1495
+ }
1496
+ const missingCount = (/* @__PURE__ */ new Set([...missingTranscriptIds, ...missingTrajectoryIds])).size;
1497
+ return missingCount === 1 ? MISSING_TOOL_RESULT_ERROR : `${MISSING_TOOL_RESULT_ERROR} missingToolResultCount=${missingCount}`;
1498
+ }
1499
+ async readMirroredSessionMessages() {
1500
+ return await readCodexMirroredSessionHistoryMessages({
1501
+ agentId: this.params.agentId,
1502
+ sessionFile: this.params.sessionFile,
1503
+ sessionId: this.params.sessionId,
1504
+ sessionKey: this.params.sessionKey
1505
+ }) ?? [];
1506
+ }
1507
+ recordToolCall(params) {
1508
+ if (!params.id || !params.name || this.callIds.has(params.id)) return;
1509
+ this.callIds.add(params.id);
1510
+ this.namesById.set(params.id, params.name);
1511
+ this.progress.recordTranscriptCall(params);
1512
+ this.messages.push(attachCodexMirrorIdentity(this.createToolCallMessage(params), `${this.turnId}:tool:${params.id}:call`));
1513
+ }
1514
+ recordToolResult(params) {
1515
+ if (!params.id || !params.name || this.resultIds.has(params.id)) return;
1516
+ this.resultIds.add(params.id);
1517
+ this.progress.recordTranscriptResult(params);
1518
+ this.messages.push(attachCodexMirrorIdentity(this.createToolResultMessage(params), `${this.turnId}:tool:${params.id}:result`));
1519
+ }
1520
+ recordMissingToolError(missingTranscriptIds, missingTrajectoryIds) {
1521
+ const firstMissingId = missingTranscriptIds.find((id) => Boolean(this.namesById.get(id))) ?? missingTrajectoryIds.find((id) => Boolean(this.trajectoryNamesById.get(id) ?? this.namesById.get(id)));
1522
+ if (!firstMissingId) return;
1523
+ const name = this.namesById.get(firstMissingId) ?? this.trajectoryNamesById.get(firstMissingId);
1524
+ if (!name) return;
1525
+ const item = this.trajectoryItemsById.get(firstMissingId);
1526
+ const meta = item ? itemMeta(item, this.progress.toolProgressDetailMode()) : this.progress.getToolMeta(firstMissingId)?.meta;
1527
+ const actionFingerprint = item ? nativeToolActionFingerprint(item) : void 0;
1528
+ this.progress.setLastToolError({
1529
+ toolName: name,
1530
+ ...meta ? { meta } : {},
1531
+ error: formatMissingToolResultError({
1532
+ id: firstMissingId,
1533
+ name
1534
+ }),
1535
+ ...item && isMutatingNativeToolItem(item) ? { mutatingAction: true } : {},
1536
+ ...actionFingerprint ? { actionFingerprint } : {}
1537
+ });
1538
+ }
1539
+ shouldEmitAfterToolCallObservation(item) {
1540
+ if (!shouldSynthesizeToolProgressForItem(item) || this.afterToolCallObservedItemIds.has(item.id)) return false;
1541
+ return !(this.options.nativePostToolUseRelayEnabled && isNativePostToolUseRelayItem(item));
1542
+ }
1543
+ createToolCallMessage(params) {
1544
+ const args = normalizeToolTranscriptArguments(params.arguments);
1545
+ const attribution = resolveCodexLocalRuntimeAttribution(this.params);
1546
+ return {
1547
+ role: "assistant",
1548
+ content: [{
1549
+ type: "toolCall",
1550
+ id: params.id,
1551
+ name: params.name,
1552
+ arguments: args,
1553
+ input: args
1554
+ }],
1555
+ api: attribution.api ?? "openai-chatgpt-responses",
1556
+ provider: attribution.provider,
1557
+ model: this.params.modelId,
1558
+ usage: ZERO_USAGE,
1559
+ stopReason: "toolUse",
1560
+ timestamp: this.nextTranscriptTimestamp()
1561
+ };
1562
+ }
1563
+ createToolResultMessage(params) {
1564
+ const text = truncateToolTranscriptText(params.text?.trim() || toolResultStatusText(params));
1565
+ return {
1566
+ role: "toolResult",
1567
+ toolCallId: params.id,
1568
+ toolName: params.name,
1569
+ isError: params.isError,
1570
+ content: [{
1571
+ type: "toolResult",
1572
+ id: params.id,
1573
+ name: params.name,
1574
+ toolName: params.name,
1575
+ toolCallId: params.id,
1576
+ toolUseId: params.id,
1577
+ tool_use_id: params.id,
1578
+ content: text,
1579
+ text
1580
+ }],
1581
+ timestamp: this.nextTranscriptTimestamp()
1582
+ };
1583
+ }
1584
+ };
1585
+ function formatMissingToolResultError(params) {
1586
+ return `${MISSING_TOOL_RESULT_ERROR} toolCallId=${params.id}; toolName=${params.name}`;
1587
+ }
1588
+ function toolResultStatusText(params) {
1589
+ return params.isError ? `${params.name} failed` : `${params.name} completed`;
1590
+ }
1591
+ function resolveStartedAtFromDurationMs(durationMs) {
1592
+ if (typeof durationMs !== "number" || !Number.isFinite(durationMs)) return;
1593
+ return asDateTimestampMs(Date.now() - Math.max(0, durationMs));
1594
+ }
1595
+ //#endregion
1596
+ //#region extensions/codex/src/app-server/event-projector-events.ts
1597
+ var CodexEventProjection = class {
1598
+ constructor(threadId, turnId, emitAgentEvent, toolProgress, toolTranscript, onNativeToolResultRecorded) {
1599
+ this.threadId = threadId;
1600
+ this.turnId = turnId;
1601
+ this.emitAgentEvent = emitAgentEvent;
1602
+ this.toolProgress = toolProgress;
1603
+ this.toolTranscript = toolTranscript;
1604
+ this.onNativeToolResultRecorded = onNativeToolResultRecorded;
1605
+ this.reviewCount = 0;
1606
+ }
1607
+ get guardianReviewCount() {
1608
+ return this.reviewCount;
1609
+ }
1610
+ handleGuardianReview(method, params) {
1611
+ this.reviewCount += 1;
1612
+ const review = isJsonObject(params.review) ? params.review : void 0;
1613
+ const action = isJsonObject(params.action) ? params.action : void 0;
1614
+ this.emitAgentEvent({
1615
+ stream: "codex_app_server.guardian",
1616
+ data: {
1617
+ method,
1618
+ phase: method.endsWith("/started") ? "started" : "completed",
1619
+ reviewId: readString$5(params, "reviewId"),
1620
+ targetItemId: readNullableString$1(params, "targetItemId"),
1621
+ decisionSource: readString$5(params, "decisionSource"),
1622
+ status: review ? readString$5(review, "status") : void 0,
1623
+ riskLevel: review ? readString$5(review, "riskLevel") : void 0,
1624
+ userAuthorization: review ? readString$5(review, "userAuthorization") : void 0,
1625
+ rationale: review ? readNullableString$1(review, "rationale") : void 0,
1626
+ actionType: action ? readString$5(action, "type") : void 0
1627
+ }
1628
+ });
1629
+ }
1630
+ handleGuardianWarning(params) {
1631
+ this.emitAgentEvent({
1632
+ stream: "codex_app_server.guardian",
1633
+ data: {
1634
+ phase: "warning",
1635
+ message: readString$5(params, "message")
1636
+ }
1637
+ });
1638
+ }
1639
+ handleHook(method, params) {
1640
+ const run = isJsonObject(params.run) ? params.run : void 0;
1641
+ if (!run) return;
1642
+ const durationMs = readNumber(run, "durationMs");
1643
+ const entries = readHookOutputEntries(run.entries);
1644
+ const hookTurnId = readNullableString$1(params, "turnId");
1645
+ this.emitAgentEvent({
1646
+ stream: "codex_app_server.hook",
1647
+ data: {
1648
+ phase: method === "hook/started" ? "started" : "completed",
1649
+ threadId: this.threadId,
1650
+ turnId: hookTurnId === void 0 ? this.turnId : hookTurnId,
1651
+ hookRunId: readString$5(run, "id"),
1652
+ eventName: readString$5(run, "eventName"),
1653
+ handlerType: readString$5(run, "handlerType"),
1654
+ executionMode: readString$5(run, "executionMode"),
1655
+ scope: readString$5(run, "scope"),
1656
+ source: readString$5(run, "source"),
1657
+ sourcePath: readString$5(run, "sourcePath"),
1658
+ status: readString$5(run, "status"),
1659
+ statusMessage: readNullableString$1(run, "statusMessage"),
1660
+ ...durationMs !== void 0 ? { durationMs } : {},
1661
+ ...entries.length > 0 ? { entries } : {}
1662
+ }
1663
+ });
1664
+ }
1665
+ emitStandardItemEvent(params) {
1666
+ const { item } = params;
1667
+ if (!item) return;
1668
+ const kind = itemKind(item);
1669
+ if (!kind) return;
1670
+ const meta = itemMeta(item, this.toolProgress.toolProgressDetailMode());
1671
+ const suppressChannelProgress = shouldSuppressChannelProgressForItem(item);
1672
+ this.emitAgentEvent({
1673
+ stream: "item",
1674
+ data: {
1675
+ itemId: item.id,
1676
+ phase: params.phase,
1677
+ kind,
1678
+ title: itemTitle(item),
1679
+ status: params.phase === "start" ? "running" : itemStatus(item),
1680
+ ...itemName(item) ? { name: itemName(item) } : {},
1681
+ ...meta ? { meta } : {},
1682
+ ...suppressChannelProgress ? { suppressChannelProgress: true } : {}
1683
+ }
1684
+ });
1685
+ }
1686
+ async emitNormalizedToolItemEvent(params) {
1687
+ const { item } = params;
1688
+ if (!item || !shouldSynthesizeToolProgressForItem(item)) return;
1689
+ const name = itemName(item);
1690
+ if (!name) return;
1691
+ const status = params.phase === "result" ? itemStatus(item) : "running";
1692
+ const args = itemToolArgs(item);
1693
+ const meta = itemMeta(item, this.toolProgress.toolProgressDetailMode());
1694
+ this.toolTranscript.recordTrajectoryEvent({
1695
+ phase: params.phase,
1696
+ item,
1697
+ name,
1698
+ args,
1699
+ status
1700
+ });
1701
+ if (params.phase === "result") this.toolProgress.recordNativeToolError({
1702
+ item,
1703
+ name,
1704
+ meta,
1705
+ status
1706
+ });
1707
+ if (!shouldEmitTranscriptToolProgress(name, args)) {
1708
+ if (params.phase === "result") {
1709
+ this.toolTranscript.emitAfterToolCallObservation(item);
1710
+ await this.onNativeToolResultRecorded?.();
1711
+ }
1712
+ return;
1713
+ }
1714
+ this.emitAgentEvent({
1715
+ stream: "tool",
1716
+ data: {
1717
+ phase: params.phase,
1718
+ name,
1719
+ itemId: item.id,
1720
+ toolCallId: item.id,
1721
+ ...meta ? { meta } : {},
1722
+ ...params.phase === "start" && args ? { args } : {},
1723
+ ...params.phase === "result" ? {
1724
+ status,
1725
+ isError: isNonSuccessItemStatus(status),
1726
+ ...itemToolResult(item)
1727
+ } : {}
1728
+ }
1729
+ });
1730
+ if (params.phase === "result") {
1731
+ this.toolTranscript.emitAfterToolCallObservation(item);
1732
+ await this.onNativeToolResultRecorded?.();
1733
+ }
1734
+ }
1735
+ };
1736
+ //#endregion
1737
+ //#region extensions/codex/src/app-server/event-projector-media.ts
1738
+ const GENERATED_IMAGE_MEDIA_SUBDIR = "tool-image-generation";
1739
+ const BYTES_PER_MB = 1024 * 1024;
1740
+ const DEFAULT_GENERATED_IMAGE_MAX_BYTES = 6 * BYTES_PER_MB;
1741
+ var CodexGeneratedMediaProjection = class {
1742
+ constructor(config) {
1743
+ this.config = config;
1744
+ this.itemIds = /* @__PURE__ */ new Set();
1745
+ this.urlsByItemId = /* @__PURE__ */ new Map();
1746
+ }
1747
+ hasGeneratedMedia() {
1748
+ return this.itemIds.size > 0;
1749
+ }
1750
+ recordNative(item) {
1751
+ if (item?.type !== "imageGeneration") return;
1752
+ const savedPath = readItemString(item, "savedPath")?.trim();
1753
+ if (savedPath) this.recordUrl({
1754
+ itemId: item.id,
1755
+ mediaUrl: savedPath
1756
+ });
1757
+ }
1758
+ async recordRaw(item) {
1759
+ if (readString$5(item, "type") !== "image_generation_call") return;
1760
+ const result = readString$5(item, "result");
1761
+ if (!result) return;
1762
+ const itemId = readString$5(item, "id") ?? `raw-image-${this.itemIds.size}`;
1763
+ this.itemIds.add(itemId);
1764
+ const maxBytes = resolveGeneratedImageMaxBytes(this.config);
1765
+ const estimatedDecodedBytes = estimateBase64DecodedBytes(result);
1766
+ if (estimatedDecodedBytes !== void 0 && estimatedDecodedBytes > maxBytes) {
1767
+ embeddedAgentLog.warn("codex app-server raw image generation result exceeds media limit", {
1768
+ itemId,
1769
+ estimatedDecodedBytes,
1770
+ maxBytes
1771
+ });
1772
+ return;
1773
+ }
1774
+ const asset = generatedImageAssetFromBase64({
1775
+ base64: result,
1776
+ index: this.itemIds.size,
1777
+ revisedPrompt: readString$5(item, "revised_prompt") ?? readString$5(item, "revisedPrompt"),
1778
+ fileNamePrefix: "codex-image-generation",
1779
+ sniffMimeType: true
1780
+ });
1781
+ if (!asset) return;
1782
+ try {
1783
+ const saved = await saveMediaBuffer(asset.buffer, asset.mimeType, GENERATED_IMAGE_MEDIA_SUBDIR, maxBytes, asset.fileName);
1784
+ this.recordUrl({
1785
+ itemId,
1786
+ mediaUrl: saved.path,
1787
+ replaceExisting: true
1788
+ });
1789
+ } catch (error) {
1790
+ embeddedAgentLog.warn("codex app-server raw image generation result save failed", {
1791
+ itemId,
1792
+ error
1793
+ });
1794
+ }
1795
+ }
1796
+ buildToolMediaUrls(params) {
1797
+ const mediaUrls = new Set(params.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []);
1798
+ if ((params.messagingToolSentMediaUrls?.length ?? 0) === 0) for (const mediaUrl of this.urlsByItemId.values()) mediaUrls.add(mediaUrl);
1799
+ return mediaUrls.size > 0 ? [...mediaUrls] : params.toolMediaUrls;
1800
+ }
1801
+ buildHostOwnedMediaUrls(params) {
1802
+ if ((params.messagingToolSentMediaUrls?.length ?? 0) > 0) return;
1803
+ const mediaUrls = [...this.urlsByItemId.values()];
1804
+ return mediaUrls.length > 0 ? mediaUrls : void 0;
1805
+ }
1806
+ recordUrl(params) {
1807
+ if (this.urlsByItemId.has(params.itemId) && params.replaceExisting !== true) {
1808
+ this.itemIds.add(params.itemId);
1809
+ return;
1810
+ }
1811
+ this.urlsByItemId.set(params.itemId, params.mediaUrl);
1812
+ this.itemIds.add(params.itemId);
1813
+ }
1814
+ };
1815
+ function estimateBase64DecodedBytes(base64) {
1816
+ let nonWhitespaceLength = 0;
1817
+ let previousCode = -1;
1818
+ let lastCode = -1;
1819
+ for (let i = 0; i < base64.length; i += 1) {
1820
+ const code = base64.charCodeAt(i);
1821
+ if (isBase64WhitespaceCode(code)) continue;
1822
+ nonWhitespaceLength += 1;
1823
+ previousCode = lastCode;
1824
+ lastCode = code;
1825
+ }
1826
+ if (nonWhitespaceLength === 0) return;
1827
+ const equalsCode = "=".charCodeAt(0);
1828
+ const padding = lastCode === equalsCode ? previousCode === equalsCode ? 2 : 1 : 0;
1829
+ return Math.max(0, Math.floor(nonWhitespaceLength * 3 / 4) - padding);
1830
+ }
1831
+ function isBase64WhitespaceCode(code) {
1832
+ return code === 32 || code === 9 || code === 10 || code === 13;
1833
+ }
1834
+ function resolveGeneratedImageMaxBytes(config) {
1835
+ const configured = config?.agents?.defaults?.mediaMaxMb;
1836
+ if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) return Math.floor(configured * BYTES_PER_MB);
1837
+ return DEFAULT_GENERATED_IMAGE_MAX_BYTES;
1838
+ }
1839
+ //#endregion
1840
+ //#region extensions/codex/src/app-server/event-projector-reasoning.ts
1841
+ var CodexReasoningProjection = class {
1842
+ constructor(params, emitAgentEvent) {
1843
+ this.params = params;
1844
+ this.emitAgentEvent = emitAgentEvent;
1845
+ this.reasoningTextByGroup = /* @__PURE__ */ new Map();
1846
+ this.reasoningItemOrder = /* @__PURE__ */ new Map();
1847
+ this.planTextByItem = /* @__PURE__ */ new Map();
1848
+ this.reasoningStarted = false;
1849
+ this.reasoningEnded = false;
1850
+ }
1851
+ async handleReasoningDelta(method, params) {
1852
+ const itemId = readString$5(params, "itemId") ?? "reasoning";
1853
+ const delta = readString$5(params, "delta") ?? "";
1854
+ if (!delta) return;
1855
+ this.reasoningStarted = true;
1856
+ if (!this.reasoningItemOrder.has(itemId)) this.reasoningItemOrder.set(itemId, this.reasoningItemOrder.size);
1857
+ const groupIndex = method === "item/reasoning/textDelta" ? readNonNegativeInteger(params, "contentIndex") ?? 0 : readNonNegativeInteger(params, "summaryIndex") ?? 0;
1858
+ const groupKey = `${method}\0${itemId}\0${groupIndex}`;
1859
+ const current = this.reasoningTextByGroup.get(groupKey);
1860
+ this.reasoningTextByGroup.set(groupKey, {
1861
+ itemId,
1862
+ method,
1863
+ index: groupIndex,
1864
+ text: `${current?.text ?? ""}${delta}`
1865
+ });
1866
+ await this.params.onReasoningStream?.({
1867
+ text: this.reasoningText(),
1868
+ isReasoningSnapshot: true
1869
+ });
1870
+ }
1871
+ handlePlanDelta(params) {
1872
+ const itemId = readString$5(params, "itemId") ?? "plan";
1873
+ const delta = readString$5(params, "delta") ?? "";
1874
+ if (!delta) return;
1875
+ const text = `${this.planTextByItem.get(itemId) ?? ""}${delta}`;
1876
+ this.planTextByItem.set(itemId, text);
1877
+ this.emitPlanUpdate({
1878
+ explanation: void 0,
1879
+ steps: splitPlanText(text).map((step) => ({
1880
+ step,
1881
+ status: "pending"
1882
+ }))
1883
+ });
1884
+ }
1885
+ handleTurnPlanUpdated(params) {
1886
+ const explanation = readNullableString$1(params, "explanation");
1887
+ const plan = Array.isArray(params.plan) ? params.plan.flatMap((entry) => {
1888
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [];
1889
+ const record = entry;
1890
+ const step = readString$5(record, "step");
1891
+ if (!step) return [];
1892
+ return [{
1893
+ step,
1894
+ status: normalizePlanStepStatus(readString$5(record, "status"))
1895
+ }];
1896
+ }) : void 0;
1897
+ const planText = [explanation, ...(plan ?? []).map(({ step, status }) => `- [${status}] ${step}`)].filter((part) => Boolean(part)).join("\n");
1898
+ if (planText) this.turnPlanText = planText;
1899
+ this.emitPlanUpdate({
1900
+ explanation,
1901
+ steps: plan
1902
+ });
1903
+ }
1904
+ recordItem(item) {
1905
+ if (item?.type === "plan" && typeof item.text === "string" && item.text) {
1906
+ this.planTextByItem.set(item.id, item.text);
1907
+ this.emitPlanUpdate({
1908
+ explanation: void 0,
1909
+ steps: splitPlanText(item.text).map((step) => ({
1910
+ step,
1911
+ status: "pending"
1912
+ }))
1913
+ });
1914
+ }
1915
+ }
1916
+ async maybeEndReasoning() {
1917
+ if (!this.reasoningStarted || this.reasoningEnded) return;
1918
+ this.reasoningEnded = true;
1919
+ await this.params.onReasoningEnd?.();
1920
+ }
1921
+ reasoningText() {
1922
+ return collectReasoningTextValues(this.reasoningTextByGroup, this.reasoningItemOrder).join("\n\n");
1923
+ }
1924
+ planText() {
1925
+ return this.turnPlanText ?? [...this.planTextByItem.values()].filter((text) => text.trim().length > 0).join("\n\n");
1926
+ }
1927
+ emitPlanUpdate(params) {
1928
+ if (!params.explanation && (!params.steps || params.steps.length === 0)) return;
1929
+ this.emitAgentEvent({
1930
+ stream: "plan",
1931
+ data: {
1932
+ phase: "update",
1933
+ title: "Plan updated",
1934
+ source: "codex-app-server",
1935
+ ...params.explanation ? { explanation: params.explanation } : {},
1936
+ ...params.steps && params.steps.length > 0 ? { steps: params.steps } : {}
1937
+ }
1938
+ });
1939
+ }
1940
+ };
1941
+ function normalizePlanStepStatus(status) {
1942
+ if (status === "inProgress" || status === "in_progress") return "in_progress";
1943
+ return status === "completed" ? "completed" : "pending";
1944
+ }
1945
+ function collectReasoningTextValues(groups, itemOrder) {
1946
+ return [...groups.values()].toSorted((left, right) => {
1947
+ const itemDelta = (itemOrder.get(left.itemId) ?? Number.MAX_SAFE_INTEGER) - (itemOrder.get(right.itemId) ?? Number.MAX_SAFE_INTEGER);
1948
+ if (itemDelta !== 0) return itemDelta;
1949
+ const methodDelta = reasoningMethodOrder(left.method) - reasoningMethodOrder(right.method);
1950
+ return methodDelta !== 0 ? methodDelta : left.index - right.index;
1951
+ }).map((group) => group.text).filter((text) => text.trim().length > 0);
1952
+ }
1953
+ function reasoningMethodOrder(method) {
1954
+ return method === "item/reasoning/summaryTextDelta" ? 0 : 1;
1955
+ }
1956
+ //#endregion
1957
+ //#region extensions/codex/src/app-server/event-projector-snapshot.ts
1958
+ function buildCodexMessagesSnapshot(params) {
1959
+ const messages = promptSnapshot(params.runParams, params.turnId, params.upstreamUserText);
1960
+ if (params.reasoningText) messages.push(attachCodexMirrorIdentity(params.createAssistantMirrorMessage("Codex reasoning", params.reasoningText), `${params.turnId}:reasoning`));
1961
+ if (params.planText) messages.push(attachCodexMirrorIdentity(params.createAssistantMirrorMessage("Codex plan", params.planText), `${params.turnId}:plan`));
1962
+ 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));
1963
+ messages.push(...visibleWorkMessages);
1964
+ if (params.lastAssistant) messages.push(attachCodexMirrorIdentity(params.lastAssistant, `${params.turnId}:assistant`));
1965
+ return messages.map((message) => projectAgentHarnessTranscriptMessageForDisplay({
1966
+ hidden: params.runParams.trigger === "memory",
1967
+ message
1968
+ }));
1969
+ }
1970
+ //#endregion
1971
+ //#region extensions/codex/src/app-server/usage-limit-error.ts
1972
+ /**
1973
+ * Enriches Codex usage-limit failures with current rate-limit information and
1974
+ * marks blocked auth profiles when Codex exposes a reset time.
1975
+ */
1976
+ const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
1977
+ function createCodexUsageLimitPromptError(message) {
1978
+ return Object.assign(new Error(message), { status: 429 });
1979
+ }
1980
+ function isCodexUsageLimitPromptError(error) {
1981
+ return error instanceof Error && "status" in error && error.status === 429;
1982
+ }
1983
+ /** Marks a Codex auth profile blocked until the reset time advertised by rate limits. */
1984
+ async function markCodexAuthProfileBlockedFromRateLimits(params) {
1985
+ const authProfileId = params.authProfileId?.trim();
1986
+ if (!authProfileId || !params.params.authProfileStore) return;
1987
+ const blockedUntil = resolveCodexUsageLimitResetAtMs(params.rateLimits);
1988
+ if (!blockedUntil) return;
1989
+ try {
1990
+ await markAuthProfileBlockedUntil({
1991
+ store: params.params.authProfileStore,
1992
+ profileId: authProfileId,
1993
+ blockedUntil,
1994
+ source: "codex_rate_limits",
1995
+ agentDir: params.params.agentDir,
1996
+ runId: params.params.runId,
1997
+ modelId: params.params.modelId
1998
+ });
1999
+ } catch (error) {
2000
+ embeddedAgentLog.debug("failed to mark Codex auth profile blocked from app-server limits", {
2001
+ authProfileId,
2002
+ error: formatErrorMessage(error)
2003
+ });
2004
+ }
2005
+ }
2006
+ /** Formats a turn-start usage-limit error, refreshing rate limits when needed. */
2007
+ async function formatCodexTurnStartUsageLimitError(params) {
2008
+ return refreshCodexUsageLimitError({
2009
+ client: params.client,
2010
+ source: readCodexTurnStartUsageLimitErrorSource(params.client, params.error, params.errorNotification, params.rateLimitsRevisionBeforeTurnStart),
2011
+ timeoutMs: params.timeoutMs,
2012
+ signal: params.signal
2013
+ });
2014
+ }
2015
+ /** Refreshes a generic prompt usage-limit message into a reset-aware message. */
2016
+ async function refreshCodexUsageLimitPromptError(params) {
2017
+ if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(params.message)) return;
2018
+ return refreshCodexUsageLimitError({
2019
+ client: params.client,
2020
+ source: {
2021
+ message: params.message,
2022
+ codexErrorInfo: "usageLimitExceeded",
2023
+ rateLimits: readRecentCodexRateLimits(params.client)
2024
+ },
2025
+ timeoutMs: params.timeoutMs,
2026
+ signal: params.signal
2027
+ });
2028
+ }
2029
+ async function refreshCodexUsageLimitError(params) {
2030
+ const initialMessage = formatCodexUsageLimitErrorMessage(params.source);
2031
+ if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(initialMessage)) return initialMessage ? {
2032
+ message: initialMessage,
2033
+ ...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
2034
+ } : void 0;
2035
+ const rateLimits = await readCodexRateLimitsFromAppServerForUsageLimitError({
2036
+ client: params.client,
2037
+ timeoutMs: params.timeoutMs,
2038
+ signal: params.signal
2039
+ });
2040
+ if (!rateLimits) return initialMessage ? {
2041
+ message: initialMessage,
2042
+ ...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
2043
+ } : void 0;
2044
+ const message = formatCodexUsageLimitErrorMessage({
2045
+ message: params.source.message,
2046
+ codexErrorInfo: params.source.codexErrorInfo,
2047
+ rateLimits,
2048
+ rateLimitsAuthoritative: true
2049
+ }) ?? initialMessage;
2050
+ return message ? {
2051
+ message,
2052
+ rateLimitsForProfile: rateLimits
2053
+ } : void 0;
2054
+ }
2055
+ async function readCodexRateLimitsFromAppServerForUsageLimitError(params) {
2056
+ if (params.signal?.aborted) return;
2057
+ try {
2058
+ const rateLimits = await params.client.request(CODEX_CONTROL_METHODS.rateLimits, void 0, {
2059
+ timeoutMs: resolveCodexUsageLimitRateLimitRefreshTimeoutMs(params.timeoutMs),
2060
+ signal: params.signal
2061
+ });
2062
+ rememberCodexRateLimitsRead(params.client, rateLimits);
2063
+ return rateLimits;
2064
+ } catch (error) {
2065
+ embeddedAgentLog.debug("codex app-server rate-limit refresh failed after usage-limit error", { error: formatErrorMessage(error) });
2066
+ return;
2067
+ }
2068
+ }
2069
+ function resolveCodexUsageLimitRateLimitRefreshTimeoutMs(timeoutMs) {
2070
+ if (timeoutMs === void 0 || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS;
2071
+ return Math.max(100, Math.min(timeoutMs, CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS));
2072
+ }
2073
+ function readCodexTurnStartUsageLimitErrorSource(client, error, errorNotification, rateLimitsRevisionBeforeTurnStart) {
2074
+ const notificationError = readCodexErrorNotification(errorNotification);
2075
+ const errorPayload = readCodexErrorPayload(error);
2076
+ const rateLimits = errorPayload.rateLimits ?? readRecentCodexRateLimits(client);
2077
+ const cacheUpdatedDuringTurnStart = rateLimitsRevisionBeforeTurnStart !== void 0 && readCodexRateLimitsRevision(client) > rateLimitsRevisionBeforeTurnStart;
2078
+ return {
2079
+ message: notificationError?.message ?? errorPayload.message ?? formatErrorMessage(error),
2080
+ codexErrorInfo: notificationError?.codexErrorInfo ?? errorPayload.codexErrorInfo,
2081
+ rateLimits,
2082
+ rateLimitsTrustedForProfile: errorPayload.rateLimits !== void 0 || cacheUpdatedDuringTurnStart
2083
+ };
2084
+ }
2085
+ function readCodexErrorNotification(notification) {
2086
+ if (notification?.method !== "error" || !isJsonObject(notification.params)) return;
2087
+ const error = notification.params.error;
2088
+ return isJsonObject(error) ? {
2089
+ message: readString$4(error, "message"),
2090
+ codexErrorInfo: error.codexErrorInfo
2091
+ } : void 0;
2092
+ }
2093
+ function readCodexErrorPayload(error) {
2094
+ const message = error instanceof Error ? error.message : void 0;
2095
+ if (!error || typeof error !== "object" || !("data" in error)) return { message };
2096
+ const data = error.data;
2097
+ if (!isJsonObject(data)) return { message };
2098
+ const nestedError = isJsonObject(data.error) ? data.error : data;
2099
+ const rateLimits = nestedError.rateLimits ?? data.rateLimits;
2100
+ return {
2101
+ message: readString$4(nestedError, "message") ?? message,
2102
+ codexErrorInfo: nestedError.codexErrorInfo,
2103
+ rateLimits
2104
+ };
2105
+ }
2106
+ function readString$4(record, key) {
2107
+ const value = record[key];
2108
+ return typeof value === "string" ? value : void 0;
2109
+ }
2110
+ //#endregion
2111
+ //#region extensions/codex/src/app-server/event-projector.ts
2112
+ var CodexAppServerEventProjector = class {
2113
+ constructor(params, threadId, turnId, options = {}) {
2114
+ this.params = params;
2115
+ this.threadId = threadId;
2116
+ this.turnId = turnId;
2117
+ this.options = options;
2118
+ this.activeItemIds = /* @__PURE__ */ new Set();
2119
+ this.completedItemIds = /* @__PURE__ */ new Set();
2120
+ this.activeCompactionItemIds = /* @__PURE__ */ new Set();
2121
+ this.terminalPresentationClearedItemIds = /* @__PURE__ */ new Set();
2122
+ this.nativeToolOutcomeOrdinals = /* @__PURE__ */ new Map();
2123
+ this.promptErrorSource = null;
2124
+ this.synthesizedMissingToolResultError = null;
2125
+ this.aborted = false;
2126
+ this.completedCompactionCount = 0;
2127
+ this.lastTranscriptTimestamp = 0;
2128
+ this.diagnostics = new CodexProjectionDiagnostics(threadId, turnId);
2129
+ this.nativeToolLifecycleProjector = new CodexNativeToolLifecycleProjector(params, threadId, turnId, { runAbortSignal: options.runAbortSignal });
2130
+ this.generatedMediaProjection = new CodexGeneratedMediaProjection(params.config);
2131
+ this.toolProgressProjection = new CodexToolProgressProjection(params);
2132
+ this.toolTranscriptProjection = new CodexToolTranscriptProjection(params, threadId, turnId, this.toolProgressProjection, () => this.nextTranscriptTimestamp(), {
2133
+ nativePostToolUseRelayEnabled: options.nativePostToolUseRelayEnabled,
2134
+ trajectoryRecorder: options.trajectoryRecorder
2135
+ });
2136
+ this.eventProjection = new CodexEventProjection(threadId, turnId, (event) => this.emitAgentEvent(event), this.toolProgressProjection, this.toolTranscriptProjection, options.onNativeToolResultRecorded);
2137
+ this.assistantProjection = new CodexAssistantProjection(params, (event) => this.emitAgentEvent(event), (text) => this.toolProgressProjection.matchesEcho(text), () => this.nextTranscriptTimestamp());
2138
+ this.reasoningProjection = new CodexReasoningProjection(params, (event) => this.emitAgentEvent(event));
2139
+ }
2140
+ nextTranscriptTimestamp() {
2141
+ this.lastTranscriptTimestamp = Math.max(Date.now(), this.lastTranscriptTimestamp + 1);
2142
+ return this.lastTranscriptTimestamp;
2143
+ }
2144
+ getCompletedTurnStatus() {
2145
+ return this.completedTurn?.status;
2146
+ }
2147
+ hasCompletedTerminalAssistantText() {
2148
+ return this.assistantProjection.hasCompletedTerminalAssistantText(this.completedItemIds);
2149
+ }
2150
+ getLatestTerminalAssistantCandidate() {
2151
+ return this.assistantProjection.getLatestTerminalAssistantCandidate();
2152
+ }
2153
+ hasLatestTerminalAssistantCandidateText() {
2154
+ return this.assistantProjection.hasLatestTerminalAssistantCandidateText();
2155
+ }
2156
+ canReleaseLatestTerminalAssistantAfterToolHandoff() {
2157
+ return this.assistantProjection.canReleaseLatestTerminalAssistantAfterToolHandoff();
2158
+ }
2159
+ /** Restores a completed final item after only the enclosing turn timeout fired. */
2160
+ recoverCompletedTerminalAssistantAfterTurnWatchTimeout() {
2161
+ if (!this.aborted || this.promptError !== "codex app-server attempt timed out" || !this.hasCompletedTerminalAssistantText()) return false;
2162
+ this.aborted = false;
2163
+ this.promptError = void 0;
2164
+ this.promptErrorSource = null;
2165
+ return true;
2166
+ }
2167
+ /** Resolves the shared model-order position for a native tool item. */
2168
+ recordNativeToolOutcome(item) {
2169
+ if (!item || this.nativeToolOutcomeOrdinals.has(item.id) || !shouldClearTerminalPresentationForNativeItem(item)) return;
2170
+ const ordinal = this.params.allocateToolOutcomeOrdinal?.(item.id);
2171
+ if (ordinal !== void 0) this.nativeToolOutcomeOrdinals.set(item.id, ordinal);
2172
+ }
2173
+ recordNativeToolApprovalFailure(toolCallId, disposition) {
2174
+ this.nativeToolLifecycleProjector.recordApprovalFailureDisposition(toolCallId, disposition);
2175
+ }
2176
+ recordNativeToolPreToolUseFailure(failure) {
2177
+ this.nativeToolLifecycleProjector.recordPreToolUseFailure(failure);
2178
+ }
2179
+ async handleNotification(notification) {
2180
+ const params = isJsonObject(notification.params) ? notification.params : void 0;
2181
+ if (!params) return;
2182
+ if (isHookNotificationMethod(notification.method)) {
2183
+ if (!this.isHookNotificationForCurrentThread(params)) return;
2184
+ } else if (notification.method === "guardianWarning") {
2185
+ if (readCodexNotificationThreadId(params) !== this.threadId) return;
2186
+ } else if (!this.isNotificationForTurn(params)) return;
2187
+ this.nativeToolLifecycleProjector.handleNotification(notification);
2188
+ switch (notification.method) {
2189
+ case "item/agentMessage/delta":
2190
+ await this.assistantProjection.handleAssistantDelta(params);
2191
+ break;
2192
+ case "item/reasoning/summaryTextDelta":
2193
+ case "item/reasoning/textDelta":
2194
+ await this.reasoningProjection.handleReasoningDelta(notification.method, params);
2195
+ break;
2196
+ case "item/plan/delta":
2197
+ this.reasoningProjection.handlePlanDelta(params);
2198
+ break;
2199
+ case "turn/plan/updated":
2200
+ this.reasoningProjection.handleTurnPlanUpdated(params);
2201
+ break;
2202
+ case "item/started":
2203
+ await this.handleItemStarted(params);
2204
+ break;
2205
+ case "item/completed":
2206
+ await this.handleItemCompleted(params);
2207
+ break;
2208
+ case "item/commandExecution/outputDelta":
2209
+ this.toolProgressProjection.handleOutputDelta(params, "bash");
2210
+ break;
2211
+ case "item/autoApprovalReview/started":
2212
+ case "item/autoApprovalReview/completed":
2213
+ this.eventProjection.handleGuardianReview(notification.method, params);
2214
+ break;
2215
+ case "guardianWarning":
2216
+ this.eventProjection.handleGuardianWarning(params);
2217
+ break;
2218
+ case "hook/started":
2219
+ case "hook/completed":
2220
+ this.eventProjection.handleHook(notification.method, params);
2221
+ break;
2222
+ case "thread/tokenUsage/updated":
2223
+ projectCodexThreadUsageUpdate(params, this.tokenUsage, (usage) => this.tokenUsage = usage, (data) => this.emitAgentEvent({
2224
+ stream: "codex_app_server.usage",
2225
+ data
2226
+ }));
2227
+ break;
2228
+ case "turn/completed":
2229
+ await this.handleTurnCompleted(params);
2230
+ break;
2231
+ case "rawResponse/completed":
2232
+ this.handleRawResponseCompleted(params);
2233
+ break;
2234
+ case "rawResponseItem/completed":
2235
+ await this.handleRawResponseItemCompleted(params);
2236
+ break;
2237
+ case "error":
2238
+ this.responseUsage = void 0;
2239
+ if (params.willRetry === true) break;
2240
+ this.promptError = this.formatCodexErrorMessage(params) ?? "codex app-server error";
2241
+ this.promptErrorSource = "prompt";
2242
+ break;
2243
+ case "thread/compacted":
2244
+ case "turn/started":
2245
+ case "turn/diff/updated":
2246
+ case "item/reasoning/summaryPartAdded":
2247
+ case "item/commandExecution/terminalInteraction":
2248
+ case "item/fileChange/outputDelta":
2249
+ case "item/fileChange/patchUpdated":
2250
+ case "item/mcpToolCall/progress":
2251
+ case "model/rerouted":
2252
+ case "model/verification":
2253
+ case "turn/moderationMetadata":
2254
+ case "model/safetyBuffering/updated": break;
2255
+ default:
2256
+ this.diagnostics.warnUnknownEvent(notification, params);
2257
+ break;
2258
+ }
2259
+ }
2260
+ buildResult(toolTelemetry, options) {
2261
+ this.nativeToolLifecycleProjector.finalizeActive();
2262
+ const assistantTexts = this.assistantProjection.collectAssistantTexts();
2263
+ const commentaryMessages = this.assistantProjection.collectCommentaryMessages();
2264
+ const reasoningText = this.reasoningProjection.reasoningText();
2265
+ const planText = this.reasoningProjection.planText();
2266
+ const projectedUsage = this.aborted ? this.tokenUsage : this.responseUsage ?? this.tokenUsage;
2267
+ const hasAssistantItemText = this.assistantProjection.hasAssistantItemTextForSynthesis();
2268
+ const legacyFailClosed = !this.completedTurn || this.completedTurn.status !== "completed" || hasAssistantItemText;
2269
+ const hasDeliverableAssistantOnCompletedTurn = this.completedTurn?.status === "completed" && assistantTexts.some((text) => text.trim().length > 0);
2270
+ const synthesizedMissingToolResultError = this.toolTranscriptProjection.synthesizeMissingToolResults({
2271
+ synthesize: legacyFailClosed,
2272
+ recordPromptError: legacyFailClosed && !hasDeliverableAssistantOnCompletedTurn && !this.aborted
2273
+ });
2274
+ if (synthesizedMissingToolResultError) {
2275
+ this.synthesizedMissingToolResultError = synthesizedMissingToolResultError;
2276
+ this.promptErrorSource = this.promptErrorSource ?? "prompt";
2277
+ }
2278
+ const assistantMessageOptions = {
2279
+ tokenUsage: projectedUsage,
2280
+ aborted: this.aborted,
2281
+ promptError: this.promptError
2282
+ };
2283
+ const lastAssistant = assistantTexts.length ? this.assistantProjection.createAssistantMessage(assistantTexts.join("\n\n"), assistantMessageOptions) : void 0;
2284
+ const currentAttemptAssistant = this.assistantProjection.createCurrentAttemptAssistantMessage(assistantMessageOptions);
2285
+ const messagesSnapshot = buildCodexMessagesSnapshot({
2286
+ runParams: this.params,
2287
+ turnId: this.turnId,
2288
+ upstreamUserText: this.options.upstreamUserText,
2289
+ reasoningText,
2290
+ planText,
2291
+ commentaryMessages,
2292
+ toolMessages: this.toolTranscriptProjection.transcriptMessages,
2293
+ lastAssistant,
2294
+ createAssistantMirrorMessage: (title, text) => this.assistantProjection.createAssistantMirrorMessage(title, text)
2295
+ });
2296
+ const turnFailed = this.completedTurn?.status === "failed";
2297
+ const promptError = this.promptError ?? this.synthesizedMissingToolResultError ?? (turnFailed ? this.completedTurn?.error?.message ?? "codex app-server turn failed" : null);
2298
+ const agentHarnessResultClassification = classifyAgentHarnessTerminalOutcome({
2299
+ assistantTexts,
2300
+ reasoningText,
2301
+ planText,
2302
+ promptError,
2303
+ turnCompleted: Boolean(this.completedTurn)
2304
+ });
2305
+ const toolMetas = this.toolProgressProjection.toolMetas;
2306
+ const hadPotentialSideEffects = toolTelemetry.didSendViaMessagingTool || (toolTelemetry.successfulCronAdds ?? 0) > 0 || this.generatedMediaProjection.hasGeneratedMedia() || this.toolProgressProjection.hasPotentialSideEffects;
2307
+ return {
2308
+ aborted: this.aborted,
2309
+ externalAbort: false,
2310
+ timedOut: false,
2311
+ idleTimedOut: false,
2312
+ timedOutDuringCompaction: false,
2313
+ timedOutDuringToolExecution: false,
2314
+ promptError,
2315
+ promptErrorSource: promptError ? this.promptErrorSource || "prompt" : null,
2316
+ sessionIdUsed: this.params.sessionId,
2317
+ ...agentHarnessResultClassification ? { agentHarnessResultClassification } : {},
2318
+ bootstrapPromptWarningSignaturesSeen: this.params.bootstrapPromptWarningSignaturesSeen,
2319
+ bootstrapPromptWarningSignature: this.params.bootstrapPromptWarningSignature,
2320
+ messagesSnapshot,
2321
+ assistantTexts,
2322
+ toolMetas,
2323
+ lastAssistant,
2324
+ currentAttemptAssistant,
2325
+ ...this.toolProgressProjection.lastToolError ? { lastToolError: this.toolProgressProjection.lastToolError } : {},
2326
+ didSendViaMessagingTool: toolTelemetry.didSendViaMessagingTool,
2327
+ didDeliverSourceReplyViaMessageTool: toolTelemetry.didDeliverSourceReplyViaMessageTool === true,
2328
+ messagingToolSentTexts: toolTelemetry.messagingToolSentTexts,
2329
+ messagingToolSentMediaUrls: toolTelemetry.messagingToolSentMediaUrls,
2330
+ messagingToolSentTargets: toolTelemetry.messagingToolSentTargets,
2331
+ messagingToolSourceReplyPayloads: toolTelemetry.messagingToolSourceReplyPayloads ?? [],
2332
+ heartbeatToolResponse: toolTelemetry.heartbeatToolResponse,
2333
+ toolMediaUrls: this.generatedMediaProjection.buildToolMediaUrls(toolTelemetry),
2334
+ hostOwnedToolMediaUrls: this.generatedMediaProjection.buildHostOwnedMediaUrls(toolTelemetry),
2335
+ toolAudioAsVoice: toolTelemetry.toolAudioAsVoice,
2336
+ successfulCronAdds: toolTelemetry.successfulCronAdds,
2337
+ cloudCodeAssistFormatError: false,
2338
+ attemptUsage: projectedUsage,
2339
+ ...this.completedCompactionCount > 0 ? { compactionCount: this.completedCompactionCount } : {},
2340
+ replayMetadata: {
2341
+ hadPotentialSideEffects,
2342
+ replaySafe: !hadPotentialSideEffects
2343
+ },
2344
+ itemLifecycle: {
2345
+ startedCount: this.activeItemIds.size + this.completedItemIds.size,
2346
+ completedCount: this.completedItemIds.size,
2347
+ activeCount: this.activeItemIds.size
2348
+ },
2349
+ yieldDetected: options?.yieldDetected || false,
2350
+ didSendDeterministicApprovalPrompt: this.eventProjection.guardianReviewCount > 0 ? false : void 0
2351
+ };
2352
+ }
2353
+ recordDynamicToolCall(params) {
2354
+ this.toolTranscriptProjection.recordDynamicToolCall(params);
2355
+ }
2356
+ recordDynamicToolResult(params) {
2357
+ this.toolProgressProjection.recordDynamicToolResult(params);
2358
+ this.toolTranscriptProjection.recordDynamicToolResult(params);
2359
+ }
2360
+ markTimedOut() {
2361
+ this.aborted = true;
2362
+ this.promptError = "codex app-server attempt timed out";
2363
+ this.promptErrorSource = "prompt";
2364
+ }
2365
+ markAborted() {
2366
+ this.aborted = true;
2367
+ this.responseUsage = void 0;
2368
+ }
2369
+ isCompacting() {
2370
+ return this.activeCompactionItemIds.size > 0;
2371
+ }
2372
+ async handleItemStarted(params) {
2373
+ const item = readItem(params.item);
2374
+ const itemId = item?.id ?? readString$5(params, "itemId");
2375
+ this.assistantProjection.recordItemStarted(item, itemId);
2376
+ if (itemId) this.activeItemIds.add(itemId);
2377
+ this.recordNativeToolOutcome(item);
2378
+ if (item?.type === "contextCompaction" && itemId) {
2379
+ this.activeCompactionItemIds.add(itemId);
2380
+ await runAgentHarnessBeforeCompactionHook({
2381
+ sessionFile: this.params.sessionFile,
2382
+ messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
2383
+ ctx: {
2384
+ runId: this.params.runId,
2385
+ agentId: this.params.agentId,
2386
+ sessionKey: this.params.sessionKey,
2387
+ sessionId: this.params.sessionId,
2388
+ workspaceDir: this.params.workspaceDir,
2389
+ messageProvider: this.params.messageProvider ?? void 0,
2390
+ trigger: this.params.trigger,
2391
+ channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
2392
+ }
2393
+ });
2394
+ this.emitAgentEvent({
2395
+ stream: "compaction",
2396
+ data: {
2397
+ phase: "start",
2398
+ backend: "codex-app-server",
2399
+ threadId: this.threadId,
2400
+ turnId: this.turnId,
2401
+ itemId
2402
+ }
2403
+ });
2404
+ }
2405
+ this.toolProgressProjection.recordToolMeta(item);
2406
+ this.eventProjection.emitStandardItemEvent({
2407
+ phase: "start",
2408
+ item
2409
+ });
2410
+ await this.eventProjection.emitNormalizedToolItemEvent({
2411
+ phase: "start",
2412
+ item
2413
+ });
2414
+ this.toolTranscriptProjection.recordNativeToolCall(item);
2415
+ this.toolProgressProjection.emitToolResultSummary(item);
2416
+ this.emitAgentEvent({
2417
+ stream: "codex_app_server.item",
2418
+ data: {
2419
+ phase: "started",
2420
+ itemId,
2421
+ type: item?.type
2422
+ }
2423
+ });
2424
+ }
2425
+ async handleItemCompleted(params) {
2426
+ const item = readItem(params.item);
2427
+ this.diagnostics.warnUnknownItemStatus(item);
2428
+ this.recordNativeToolOutcome(item);
2429
+ this.clearTerminalPresentationForNativeItem(item);
2430
+ const itemId = item?.id ?? readString$5(params, "itemId");
2431
+ if (itemId) {
2432
+ this.activeItemIds.delete(itemId);
2433
+ this.completedItemIds.add(itemId);
2434
+ }
2435
+ this.assistantProjection.recordItemCompleted(item, itemId, this.activeItemIds);
2436
+ this.reasoningProjection.recordItem(item);
2437
+ this.generatedMediaProjection.recordNative(item);
2438
+ if (item?.type === "contextCompaction" && itemId) {
2439
+ this.activeCompactionItemIds.delete(itemId);
2440
+ this.completedCompactionCount += 1;
2441
+ this.options.onContextCompacted?.();
2442
+ await runAgentHarnessAfterCompactionHook({
2443
+ sessionFile: this.params.sessionFile,
2444
+ messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
2445
+ compactedCount: -1,
2446
+ ctx: {
2447
+ runId: this.params.runId,
2448
+ agentId: this.params.agentId,
2449
+ sessionKey: this.params.sessionKey,
2450
+ sessionId: this.params.sessionId,
2451
+ workspaceDir: this.params.workspaceDir,
2452
+ messageProvider: this.params.messageProvider ?? void 0,
2453
+ trigger: this.params.trigger,
2454
+ channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
2455
+ }
2456
+ });
2457
+ this.emitAgentEvent({
2458
+ stream: "compaction",
2459
+ data: {
2460
+ phase: "end",
2461
+ backend: "codex-app-server",
2462
+ completed: true,
2463
+ threadId: this.threadId,
2464
+ turnId: this.turnId,
2465
+ itemId
2466
+ }
2467
+ });
2468
+ }
2469
+ this.toolProgressProjection.recordToolMeta(item);
2470
+ this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
2471
+ this.eventProjection.emitStandardItemEvent({
2472
+ phase: "end",
2473
+ item
2474
+ });
2475
+ await this.eventProjection.emitNormalizedToolItemEvent({
2476
+ phase: "result",
2477
+ item
2478
+ });
2479
+ this.toolTranscriptProjection.recordNativeToolCall(item);
2480
+ this.toolTranscriptProjection.recordNativeToolResult(item);
2481
+ this.toolProgressProjection.emitToolResultSummary(item);
2482
+ this.toolProgressProjection.emitToolResultOutput(item);
2483
+ this.emitAgentEvent({
2484
+ stream: "codex_app_server.item",
2485
+ data: {
2486
+ phase: "completed",
2487
+ itemId,
2488
+ type: item?.type
2489
+ }
2490
+ });
2491
+ }
2492
+ handleRawResponseCompleted(params) {
2493
+ const usage = isJsonObject(params.usage) ? params.usage : void 0;
2494
+ this.responseUsage = usage ? normalizeCodexResponseTokenUsage(usage) : void 0;
2495
+ }
2496
+ async handleTurnCompleted(params) {
2497
+ const turn = readCodexTurn(params.turn);
2498
+ if (!turn || turn.id !== this.turnId) return;
2499
+ this.completedTurn = turn;
2500
+ if (turn.status !== "completed") this.responseUsage = void 0;
2501
+ if (turn.status === "failed") {
2502
+ const usageLimitMessage = formatCodexUsageLimitErrorMessage({
2503
+ message: turn.error?.message,
2504
+ codexErrorInfo: turn.error?.codexErrorInfo,
2505
+ rateLimits: this.options.readRecentRateLimits?.()
2506
+ });
2507
+ this.promptError = usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : turn.error?.message ?? "codex app-server turn failed";
2508
+ this.promptErrorSource = "prompt";
2509
+ }
2510
+ const turnItems = turn.items ?? [];
2511
+ for (let index = turnItems.length - 1; index >= 0; index -= 1) {
2512
+ const item = turnItems[index];
2513
+ if (!item || !this.isCurrentTurnSnapshotItem(item)) continue;
2514
+ if (item?.type === "dynamicToolCall") break;
2515
+ if (shouldClearTerminalPresentationForNativeItem(item)) {
2516
+ this.clearTerminalPresentationForNativeItem(item);
2517
+ break;
2518
+ }
2519
+ }
2520
+ for (const item of turnItems) {
2521
+ this.diagnostics.warnUnknownItemStatus(item);
2522
+ this.assistantProjection.recordSnapshotItem(item);
2523
+ this.reasoningProjection.recordItem(item);
2524
+ this.generatedMediaProjection.recordNative(item);
2525
+ this.toolProgressProjection.recordToolMeta(item);
2526
+ this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
2527
+ await this.emitSnapshotOnlyNativeToolProgress(item);
2528
+ this.toolTranscriptProjection.recordNativeToolCall(item);
2529
+ this.toolTranscriptProjection.recordNativeToolResult(item);
2530
+ this.toolTranscriptProjection.emitAfterToolCallObservation(item);
2531
+ this.toolProgressProjection.emitToolResultSummary(item);
2532
+ this.toolProgressProjection.emitToolResultOutput(item);
2533
+ }
2534
+ this.assistantProjection.finalizeAnswerCandidate(turn);
2535
+ this.activeCompactionItemIds.clear();
2536
+ await this.reasoningProjection.maybeEndReasoning();
2537
+ }
2538
+ async emitSnapshotOnlyNativeToolProgress(item) {
2539
+ if (!shouldSynthesizeToolProgressForItem(item) || !this.isCurrentTurnSnapshotItem(item) || this.completedItemIds.has(item.id) || itemStatus(item) === "running") return;
2540
+ if (!this.activeItemIds.has(item.id)) {
2541
+ this.eventProjection.emitStandardItemEvent({
2542
+ phase: "start",
2543
+ item
2544
+ });
2545
+ await this.eventProjection.emitNormalizedToolItemEvent({
2546
+ phase: "start",
2547
+ item
2548
+ });
2549
+ }
2550
+ this.activeItemIds.delete(item.id);
2551
+ this.eventProjection.emitStandardItemEvent({
2552
+ phase: "end",
2553
+ item
2554
+ });
2555
+ await this.eventProjection.emitNormalizedToolItemEvent({
2556
+ phase: "result",
2557
+ item
2558
+ });
2559
+ this.completedItemIds.add(item.id);
2560
+ }
2561
+ isCurrentTurnSnapshotItem(item) {
2562
+ const itemTurnId = readItemString(item, "turnId");
2563
+ return itemTurnId === void 0 || itemTurnId === this.turnId;
2564
+ }
2565
+ async handleRawResponseItemCompleted(params) {
2566
+ const item = isJsonObject(params.item) ? params.item : void 0;
2567
+ if (!item) return;
2568
+ this.assistantProjection.handleRawResponseItemCompleted(item, this.activeItemIds);
2569
+ await this.generatedMediaProjection.recordRaw(item);
2570
+ }
2571
+ clearTerminalPresentationForNativeItem(item) {
2572
+ if (!item || this.terminalPresentationClearedItemIds.has(item.id) || !shouldClearTerminalPresentationForNativeItem(item)) return;
2573
+ const toolCallOrdinal = this.nativeToolOutcomeOrdinals.get(item.id);
2574
+ this.terminalPresentationClearedItemIds.add(item.id);
2575
+ this.params.onToolOutcome?.({
2576
+ toolName: itemName(item) ?? item.type,
2577
+ argsHash: "",
2578
+ resultHash: "",
2579
+ ...toolCallOrdinal !== void 0 ? { toolCallOrdinal } : {},
2580
+ terminalPresentation: void 0,
2581
+ presentationOnly: true
2582
+ });
2583
+ }
2584
+ formatCodexErrorMessage(params) {
2585
+ const error = isJsonObject(params.error) ? params.error : void 0;
2586
+ const usageLimitMessage = formatCodexUsageLimitErrorMessage({
2587
+ message: error ? readString$5(error, "message") : void 0,
2588
+ codexErrorInfo: error?.codexErrorInfo,
2589
+ rateLimits: this.options.readRecentRateLimits?.()
2590
+ });
2591
+ return usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : readCodexErrorNotificationMessage(params);
2592
+ }
2593
+ emitAgentEvent(event) {
2594
+ try {
2595
+ emitAgentEvent({
2596
+ runId: this.params.runId,
2597
+ stream: event.stream,
2598
+ data: event.data,
2599
+ ...this.params.sessionKey ? { sessionKey: this.params.sessionKey } : {}
2600
+ });
2601
+ } catch (error) {
2602
+ embeddedAgentLog.debug("codex app-server global agent event emit failed", { error });
2603
+ }
2604
+ try {
2605
+ const maybePromise = this.params.onAgentEvent?.(event);
2606
+ Promise.resolve(maybePromise).catch((error) => {
2607
+ embeddedAgentLog.debug("codex app-server agent event handler rejected", { error });
2608
+ });
2609
+ } catch (error) {
2610
+ embeddedAgentLog.debug("codex app-server agent event handler threw", { error });
2611
+ }
2612
+ }
2613
+ isNotificationForTurn(params) {
2614
+ const threadId = readCodexNotificationThreadId(params);
2615
+ const turnId = readCodexNotificationTurnId(params);
2616
+ return threadId === this.threadId && turnId === this.turnId;
2617
+ }
2618
+ isHookNotificationForCurrentThread(params) {
2619
+ const threadId = readString$5(params, "threadId");
2620
+ const turnId = params.turnId;
2621
+ return threadId === this.threadId && (turnId === this.turnId || turnId === null);
2622
+ }
2623
+ };
2624
+ function isHookNotificationMethod(method) {
2625
+ return method === "hook/started" || method === "hook/completed";
2626
+ }
2627
+ //#endregion
193
2628
  //#region extensions/codex/src/app-server/user-input-bridge.ts
194
2629
  /** Bridges Codex request_user_input calls to gateway questions and secret text prompts. */
195
2630
  const DEFAULT_USER_INPUT_TIMEOUT_MS = 15 * 6e4;
@@ -267,7 +2702,7 @@ function createCodexUserInputBridge(params) {
267
2702
  },
268
2703
  signal: abort.signal
269
2704
  });
270
- return result.status === "answered" ? result.answers : emptyUserInputResponse();
2705
+ return result.status === "answered" ? gatewayAnswersToCodexResponse(result.answers.answers) : emptyUserInputResponse();
271
2706
  } catch (error) {
272
2707
  embeddedAgentLog.warn("failed to bridge codex user input through gateway", { error });
273
2708
  return emptyUserInputResponse();
@@ -350,6 +2785,9 @@ function readOption(value) {
350
2785
  function buildUserInputResponse(questions, inputText) {
351
2786
  return buildAgentHarnessUserInputAnswers(questions, inputText);
352
2787
  }
2788
+ function gatewayAnswersToCodexResponse(answers) {
2789
+ return { answers: Object.fromEntries(Object.entries(answers).map(([questionId, values]) => [questionId, { answers: values }])) };
2790
+ }
353
2791
  function emptyUserInputResponse() {
354
2792
  return emptyAgentHarnessUserInputAnswers();
355
2793
  }
@@ -474,6 +2912,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
474
2912
  isStopped: () => state.completed || state.timedOut || runAbortController.signal.aborted,
475
2913
  isAbortable: () => !terminalState.terminalOutcomeFrozen || terminalState.sharedAbortAllowedAfterTerminalOutcome,
476
2914
  isCompacting: () => projectorRef.current?.isCompacting() ?? false,
2915
+ supportsTranscriptCommitWait: true,
477
2916
  supportsQueueMessageImages: true,
478
2917
  sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
479
2918
  cancel: () => abortExplicitly("cancelled"),
@@ -536,7 +2975,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
536
2975
  async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRuntime, activeTurn) {
537
2976
  const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, releaseSharedClientLeaseAndRetireOneShotClient, releaseSandboxExecEnvironment } = resources;
538
2977
  const { connection } = prompt.context.runtime;
539
- const { params, options, runAbortController } = connection;
2978
+ const { params, options, runAbortController, terminalState, bindingStore, bindingIdentity } = connection;
540
2979
  const { state, steeringQueueRef, userInputBridgeRef, turnWatches } = turnRuntime;
541
2980
  const { maybeEmitFastModeAutoResetBestEffort, emitLifecycleTerminal, buildLifecycleTerminalMeta } = lifecycle;
542
2981
  const { codexModelCallDiagnostics } = requestRuntime;
@@ -566,10 +3005,17 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
566
3005
  cleanup: async () => trajectoryRecorder?.flush()
567
3006
  });
568
3007
  if (!state.timedOut && !runAbortController.signal.aborted) await steeringQueueRef.current?.flushPending();
569
- if (!state.timedOut) await unsubscribeCodexThreadBestEffort(resourceState.client, {
570
- threadId: resourceState.thread.threadId,
571
- timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
572
- });
3008
+ const retainLiveIncognitoThread = terminalState.turnSucceeded && isIncognitoSessionKey(params.sessionKey);
3009
+ const bindingReleased = isIncognitoSessionKey(params.sessionKey) && !retainLiveIncognitoThread ? await bindingStore.mutate(bindingIdentity, {
3010
+ kind: "clear",
3011
+ threadId: resourceState.thread.threadId
3012
+ }) : true;
3013
+ if (!state.timedOut && !retainLiveIncognitoThread) {
3014
+ if (bindingReleased) await unsubscribeCodexThreadBestEffort(resourceState.client, {
3015
+ threadId: resourceState.thread.threadId,
3016
+ timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
3017
+ });
3018
+ }
573
3019
  userInputBridgeRef.current?.cancelPending();
574
3020
  turnWatches.clearAllTimers();
575
3021
  releaseCurrentRoute();
@@ -830,19 +3276,11 @@ function readCodexAppServerRolloutTokenSnapshotLine(line) {
830
3276
  return;
831
3277
  }
832
3278
  }
833
- function toNonNegativeInt(value) {
834
- if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return;
835
- return Math.floor(value);
836
- }
837
3279
  function readCompactionConfig(config) {
838
3280
  return isJsonObject(config?.agents?.defaults?.compaction) ? config.agents.defaults.compaction : void 0;
839
3281
  }
840
- function resolveCodexAppServerNativeThreadReserveTokens(config) {
841
- const compaction = readCompactionConfig(config);
842
- const reserveTokens = toNonNegativeInt(compaction?.reserveTokens);
843
- const reserveTokensFloor = toNonNegativeInt(compaction?.reserveTokensFloor);
844
- if (reserveTokens !== void 0) return Math.max(reserveTokens, reserveTokensFloor ?? CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS);
845
- return reserveTokensFloor ?? CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS;
3282
+ function resolveCodexAppServerNativeThreadReserveTokens(_config) {
3283
+ return CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS;
846
3284
  }
847
3285
  function resolveCodexAppServerNativeThreadTokenFuse(params) {
848
3286
  const projectedTurnTokens = typeof params.projectedTurnTokens === "number" && Number.isFinite(params.projectedTurnTokens) && params.projectedTurnTokens > 0 ? Math.floor(params.projectedTurnTokens) : 0;
@@ -938,6 +3376,14 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
938
3376
  }
939
3377
  //#endregion
940
3378
  //#region extensions/codex/src/app-server/run-attempt-connection.ts
3379
+ function applyStoredBindingPermissions(params) {
3380
+ if (params.execPolicyTouched || params.binding?.connectionScope === "supervision") return params.appServer;
3381
+ return {
3382
+ ...params.appServer,
3383
+ approvalPolicy: params.binding?.approvalPolicy ?? params.appServer.approvalPolicy,
3384
+ sandbox: params.binding?.sandbox ?? params.appServer.sandbox
3385
+ };
3386
+ }
941
3387
  async function prepareCodexAttemptConnection({ params, options }) {
942
3388
  const attemptStartedAt = Date.now();
943
3389
  const profilerEnabled = isCodexAppServerProfilerEnabled(params.config);
@@ -995,23 +3441,27 @@ async function prepareCodexAttemptConnection({ params, options }) {
995
3441
  bindingStore,
996
3442
  identity: bindingIdentity,
997
3443
  config: params.config
998
- })) throw new Error(`Codex session generation is no longer current: ${bindingIdentity.sessionId}`);
3444
+ })) throw createCodexSessionGenerationSupersededError(bindingIdentity.sessionId);
999
3445
  startupBinding = await bindingStore.read(bindingIdentity);
1000
3446
  }
1001
3447
  preDynamicStartupStages.mark("read-binding");
1002
3448
  const usesSupervisionConnection = startupBinding?.connectionScope === "supervision";
1003
3449
  if (usesSupervisionConnection) activeContextEngine = void 0;
1004
3450
  if (usesSupervisionConnection && pluginConfig.supervision?.enabled !== true) throw new Error("Codex supervision is disabled; refusing to open a native user-home supervised session");
1005
- const resolveRuntimeOptionsForBinding = (selection) => resolveCodexBindingAppServerConnection({
3451
+ const resolveRuntimeOptionsForBinding = (selection) => applyStoredBindingPermissions({
3452
+ appServer: resolveCodexBindingAppServerConnection({
3453
+ binding: startupBinding,
3454
+ pluginConfig,
3455
+ execPolicy,
3456
+ modelProvider: selection.modelProvider,
3457
+ model: selection.model,
3458
+ config: params.config,
3459
+ agentDir,
3460
+ openClawSandboxActive: sandbox?.enabled === true
3461
+ }).appServer,
1006
3462
  binding: startupBinding,
1007
- pluginConfig,
1008
- execPolicy,
1009
- modelProvider: selection.modelProvider,
1010
- model: selection.model,
1011
- config: params.config,
1012
- agentDir,
1013
- openClawSandboxActive: sandbox?.enabled === true
1014
- }).appServer;
3463
+ execPolicyTouched: execPolicy.touched
3464
+ });
1015
3465
  const initialStartupBindingHadInactiveThreadBootstrap = isInactiveThreadBootstrapBinding(startupBinding);
1016
3466
  const preparedAuthRoute = usesSupervisionConnection ? void 0 : params.runtimePlan?.auth.modelRoute;
1017
3467
  const startupAuthProfileCandidate = usesSupervisionConnection ? void 0 : preparedAuthRoute ? params.runtimePlan?.auth.forwardedAuthProfileId : params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId;
@@ -1087,6 +3537,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
1087
3537
  preDynamicStartupStages.mark("app-server-policy");
1088
3538
  preDynamicStartupStages.mark("native-hook-relay");
1089
3539
  const terminalState = {
3540
+ turnSucceeded: false,
1090
3541
  explicitCancellationObserved: false,
1091
3542
  explicitCancellationReason: void 0,
1092
3543
  terminalOutcomeFrozen: false,
@@ -1148,16 +3599,20 @@ async function prepareCodexAttemptConnection({ params, options }) {
1148
3599
  startupBinding,
1149
3600
  pluginAppServer: appServer
1150
3601
  };
1151
- const resolveRuntimeOptionsForCurrentBinding = (selection) => resolveCodexBindingAppServerConnection({
3602
+ const resolveRuntimeOptionsForCurrentBinding = (selection) => applyStoredBindingPermissions({
3603
+ appServer: resolveCodexBindingAppServerConnection({
3604
+ binding: mutable.startupBinding,
3605
+ pluginConfig,
3606
+ execPolicy,
3607
+ modelProvider: selection.modelProvider,
3608
+ model: selection.model,
3609
+ config: params.config,
3610
+ agentDir,
3611
+ openClawSandboxActive: sandbox?.enabled === true
3612
+ }).appServer,
1152
3613
  binding: mutable.startupBinding,
1153
- pluginConfig,
1154
- execPolicy,
1155
- modelProvider: selection.modelProvider,
1156
- model: selection.model,
1157
- config: params.config,
1158
- agentDir,
1159
- openClawSandboxActive: sandbox?.enabled === true
1160
- }).appServer;
3614
+ execPolicyTouched: execPolicy.touched
3615
+ });
1161
3616
  return {
1162
3617
  params,
1163
3618
  options,
@@ -1217,7 +3672,6 @@ const CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = /* @__PURE__ */
1217
3672
  "user.md"
1218
3673
  ]);
1219
3674
  const CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = /* @__PURE__ */ new Set([...CODEX_INHERITED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES, ...CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES]);
1220
- const CODEX_HEARTBEAT_CONTEXT_BASENAME = "heartbeat.md";
1221
3675
  const CODEX_MEMORY_CONTEXT_BASENAME = "memory.md";
1222
3676
  const CODEX_MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set(["memory_search", "memory_get"]);
1223
3677
  const CODEX_BOOTSTRAP_CONTEXT_ORDER = /* @__PURE__ */ new Map([
@@ -1226,8 +3680,7 @@ const CODEX_BOOTSTRAP_CONTEXT_ORDER = /* @__PURE__ */ new Map([
1226
3680
  ["user.md", 30],
1227
3681
  ["tools.md", 40],
1228
3682
  ["bootstrap.md", 50],
1229
- ["memory.md", 60],
1230
- ["heartbeat.md", 70]
3683
+ ["memory.md", 60]
1231
3684
  ]);
1232
3685
  /** Reads mirrored Codex session history for harness hooks. */
1233
3686
  async function readMirroredSessionHistoryMessages(params) {
@@ -1328,14 +3781,12 @@ async function buildCodexWorkspaceBootstrapContext(params) {
1328
3781
  });
1329
3782
  const developerInstructionFiles = shouldInjectCodexOpenClawPromptContext(params.params) ? selectCodexWorkspaceInheritedDeveloperInstructionFiles(contextFiles) : [];
1330
3783
  const turnScopedDeveloperInstructionFiles = shouldInjectCodexOpenClawPromptContext(params.params) ? selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) : [];
1331
- const heartbeatReferenceFiles = selectCodexWorkspaceHeartbeatReferenceFiles(contextFiles);
1332
3784
  return {
1333
3785
  bootstrapFiles,
1334
3786
  contextFiles,
1335
3787
  promptContextFiles,
1336
3788
  developerInstructionFiles,
1337
3789
  turnScopedDeveloperInstructionFiles,
1338
- heartbeatReferenceFiles,
1339
3790
  memoryReferenceFiles,
1340
3791
  memoryToolRoutedBootstrapFiles,
1341
3792
  memoryToolNames: [...params.memoryToolNames],
@@ -1351,8 +3802,7 @@ async function buildCodexWorkspaceBootstrapContext(params) {
1351
3802
  agentId: params.params.agentId ?? params.sessionAgentId,
1352
3803
  agentSessionKey: params.sessionKey,
1353
3804
  sandboxed: params.sandboxed
1354
- }) : void 0,
1355
- heartbeatCollaborationInstructions: renderCodexWorkspaceHeartbeatReference(heartbeatReferenceFiles)
3805
+ }) : void 0
1356
3806
  };
1357
3807
  } catch (error) {
1358
3808
  embeddedAgentLog.warn("failed to load codex workspace bootstrap instructions", { error });
@@ -1474,14 +3924,9 @@ function buildCodexBootstrapInjectionStats(params) {
1474
3924
  const injected = memoryToolRoutedFile ? void 0 : readCodexIndexedContextFileContent(injectedIndex, pathValue, fileName) ?? readCodexIndexedContextFileContent(developerInstructionIndex, pathValue, fileName);
1475
3925
  let injectedChars = memoryToolRoutedFile ? 0 : injected?.length ?? 0;
1476
3926
  let truncated = memoryToolRoutedFile ? false : !file.missing && injectedChars < rawChars;
1477
- if (injected === void 0) {
1478
- if (CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName)) {
1479
- injectedChars = rawChars;
1480
- truncated = false;
1481
- } else if (baseName === CODEX_HEARTBEAT_CONTEXT_BASENAME) {
1482
- injectedChars = 0;
1483
- truncated = false;
1484
- }
3927
+ if (injected === void 0 && CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName)) {
3928
+ injectedChars = rawChars;
3929
+ truncated = false;
1485
3930
  }
1486
3931
  return {
1487
3932
  name: displayName,
@@ -1605,7 +4050,7 @@ function renderCodexWorkspaceBootstrapPromptContext(contextFiles) {
1605
4050
  const files = contextFiles;
1606
4051
  if (files.length === 0) return;
1607
4052
  const lines = [
1608
- "OpenClaw loaded these user-editable workspace files for the current turn. Codex loads AGENTS.md natively. TOOLS.md is provided as inherited Codex developer instructions. SOUL.md, IDENTITY.md, and USER.md are provided as turn-scoped collaboration instructions so native Codex subagents do not inherit them. HEARTBEAT.md is handled by heartbeat collaboration-mode guidance. Those files are not repeated here.",
4053
+ "OpenClaw loaded these user-editable workspace files for the current turn. Codex loads AGENTS.md natively. TOOLS.md is provided as inherited Codex developer instructions. 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.",
1609
4054
  "",
1610
4055
  "# Project Context",
1611
4056
  "",
@@ -1619,7 +4064,7 @@ function selectCodexWorkspacePromptContextFiles(contextFiles, options = {}) {
1619
4064
  const excludeMemory = options.excludeMemory ?? true;
1620
4065
  return contextFiles.filter((file) => {
1621
4066
  const baseName = getCodexContextFileBasename(file.path);
1622
- return baseName && !CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName) && !CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES.has(baseName) && baseName !== CODEX_HEARTBEAT_CONTEXT_BASENAME && (!excludeMemory || !isCodexWorkspaceRootMemoryContextFile({
4067
+ return baseName && !CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName) && !CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES.has(baseName) && (!excludeMemory || !isCodexWorkspaceRootMemoryContextFile({
1623
4068
  file,
1624
4069
  workspaceDir: options.memoryWorkspaceDir
1625
4070
  })) && !isMissingCodexBootstrapContextFile(file);
@@ -1666,22 +4111,6 @@ function renderCodexWorkspaceDeveloperInstructions(params) {
1666
4111
  if (wrapperTag) lines.push(`</${wrapperTag}>`);
1667
4112
  return lines.join("\n").trim();
1668
4113
  }
1669
- function selectCodexWorkspaceHeartbeatReferenceFiles(contextFiles) {
1670
- return contextFiles.filter((file) => {
1671
- return getCodexContextFileBasename(file.path) === CODEX_HEARTBEAT_CONTEXT_BASENAME && !isMissingCodexBootstrapContextFile(file) && file.content.trim().length > 0;
1672
- }).toSorted(compareCodexContextFiles);
1673
- }
1674
- function renderCodexWorkspaceHeartbeatReference(files) {
1675
- if (files.length === 0) return;
1676
- const lines = [
1677
- "## OpenClaw Heartbeat Workspace",
1678
- "",
1679
- "HEARTBEAT.md exists in the active agent workspace. Read it before proceeding with this heartbeat, then decide what action is appropriate.",
1680
- ""
1681
- ];
1682
- for (const file of files) lines.push(`- ${file.path}`);
1683
- return lines.join("\n").trim();
1684
- }
1685
4114
  function selectCodexWorkspaceMemoryReferenceFiles(params) {
1686
4115
  return params.bootstrapFiles.filter((file) => {
1687
4116
  return isCodexWorkspaceRootMemoryBootstrapFile({
@@ -2020,7 +4449,7 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
2020
4449
  },
2021
4450
  codexContextProjectionMaxChars: resolveCodexContextEngineProjectionMaxChars({
2022
4451
  contextTokenBudget: effectiveContextTokenBudget,
2023
- reserveTokens: resolveCodexContextEngineProjectionReserveTokens({ config: params.config })
4452
+ reserveTokens: resolveCodexContextEngineProjectionReserveTokens()
2024
4453
  })
2025
4454
  };
2026
4455
  }
@@ -2235,6 +4664,67 @@ function isInvalidCodexImagePayloadError(message) {
2235
4664
  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);
2236
4665
  }
2237
4666
  //#endregion
4667
+ //#region extensions/codex/src/app-server/settled-turn-context.ts
4668
+ function collectUniqueMessageIdentities(messages) {
4669
+ const identities = /* @__PURE__ */ new Map();
4670
+ for (const [index, message] of messages.entries()) {
4671
+ const identity = readMirrorIdentity(message);
4672
+ if (!identity) continue;
4673
+ if (identities.has(identity)) return;
4674
+ identities.set(identity, index);
4675
+ }
4676
+ return identities;
4677
+ }
4678
+ /** Freezes one complete active transcript branch through the settled tool-result boundary. */
4679
+ function buildCodexSettledTurnFinalizationContext(params) {
4680
+ const boundaryMessage = params.settledMessages.findLast((message) => message.role === "toolResult");
4681
+ const boundaryIdentity = boundaryMessage ? readMirrorIdentity(boundaryMessage) : void 0;
4682
+ if (!boundaryMessage || !boundaryIdentity || !boundaryIdentity.startsWith(`${params.turnId}:tool:`)) return;
4683
+ const settledBoundaryIndex = params.settledMessages.indexOf(boundaryMessage);
4684
+ const requiredIdentities = params.settledMessages.slice(0, settledBoundaryIndex + 1).map(readMirrorIdentity);
4685
+ if (requiredIdentities.length === 0 || requiredIdentities.some((identity) => !identity) || new Set(requiredIdentities).size !== requiredIdentities.length || !requiredIdentities.includes(`${params.turnId}:prompt`)) return;
4686
+ const historyIdentities = collectUniqueMessageIdentities(params.historyMessages);
4687
+ const mirroredIdentities = collectUniqueMessageIdentities(params.mirroredMessages);
4688
+ if (!historyIdentities || !mirroredIdentities) return;
4689
+ const mirroredBoundaryIndex = mirroredIdentities.get(boundaryIdentity);
4690
+ if (mirroredBoundaryIndex === void 0) return;
4691
+ const mirroredThroughBoundary = params.mirroredMessages.slice(0, mirroredBoundaryIndex + 1);
4692
+ if (mirroredThroughBoundary.length !== requiredIdentities.length || mirroredThroughBoundary.some((message, index) => readMirrorIdentity(message) !== requiredIdentities[index])) return;
4693
+ const historyBoundaryIndex = historyIdentities.get(boundaryIdentity);
4694
+ if (historyBoundaryIndex === void 0) return;
4695
+ let previousHistoryIndex = -1;
4696
+ for (const mirroredMessage of mirroredThroughBoundary) {
4697
+ const identity = readMirrorIdentity(mirroredMessage);
4698
+ const historyIndex = identity ? historyIdentities.get(identity) : void 0;
4699
+ const historyMessage = historyIndex === void 0 ? void 0 : params.historyMessages[historyIndex];
4700
+ if (historyIndex === void 0 || historyIndex <= previousHistoryIndex || historyIndex > historyBoundaryIndex || !historyMessage || serializeCodexMirrorSourceEvidence(historyMessage) !== serializeCodexMirrorSourceEvidence(mirroredMessage)) return;
4701
+ previousHistoryIndex = historyIndex;
4702
+ }
4703
+ return {
4704
+ source: "openclaw-transcript",
4705
+ messages: Object.freeze(structuredClone(params.historyMessages.slice(0, historyBoundaryIndex + 1)))
4706
+ };
4707
+ }
4708
+ /** Reads and freezes the current active transcript branch after mirroring has settled. */
4709
+ async function captureCodexSettledTurnFinalizationContext(params) {
4710
+ try {
4711
+ const historyMessages = await readCodexMirroredSessionHistoryMessages(params);
4712
+ if (!historyMessages) return;
4713
+ return buildCodexSettledTurnFinalizationContext({
4714
+ historyMessages,
4715
+ mirroredMessages: params.mirroredMessages,
4716
+ settledMessages: params.settledMessages,
4717
+ turnId: params.turnId
4718
+ });
4719
+ } catch (error) {
4720
+ embeddedAgentLog.warn("codex settled-turn finalization context capture failed", {
4721
+ error: formatErrorMessage(error),
4722
+ turnId: params.turnId
4723
+ });
4724
+ return;
4725
+ }
4726
+ }
4727
+ //#endregion
2238
4728
  //#region extensions/codex/src/app-server/trajectory.ts
2239
4729
  const SENSITIVE_FIELD_RE = /(?:authorization|cookie|credential|key|password|passwd|secret|token)/iu;
2240
4730
  const PRIVATE_PAYLOAD_FIELD_RE = /(?:image|screenshot|attachment|fileData|dataUri)/iu;
@@ -2528,6 +5018,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2528
5018
  const turnSucceeded = !finalAborted && !effectiveTimedOut && (finalPromptError === null || finalPromptError === void 0) && (completedTurnStatus === "completed" || recoveredTurnWatchTimeout || completedWithoutTerminalNotification);
2529
5019
  if (settleCodexSourceReplyFinality(toolBridge.telemetry, turnSucceeded)) result.agentHarnessResultClassification = void 0;
2530
5020
  const attemptSucceeded = turnSucceeded && result.agentHarnessResultClassification === void 0;
5021
+ terminalState.turnSucceeded = turnSucceeded;
2531
5022
  terminalState.sharedAbortAllowedAfterTerminalOutcome = shouldKeepCodexSharedAbortOpen({
2532
5023
  trigger: params.trigger,
2533
5024
  result,
@@ -2547,7 +5038,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2547
5038
  if (modelCallFailureKind) codexModelCallDiagnostics.emitError(finalPromptError ?? "codex app-server attempt interrupted", { failureKind: modelCallFailureKind });
2548
5039
  else if (finalPromptError) codexModelCallDiagnostics.emitError(finalPromptError);
2549
5040
  else codexModelCallDiagnostics.emitCompleted(result);
2550
- const assistantTranscriptOwned = await codexTranscriptMirrorRuntime.mirrorBestEffort({
5041
+ const mirrorOutcome = await codexTranscriptMirrorRuntime.mirrorBestEffort({
2551
5042
  params,
2552
5043
  agentId: sessionAgentId,
2553
5044
  notifyUserMessagePersisted,
@@ -2557,6 +5048,18 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2557
5048
  threadId: resourceState.thread.threadId,
2558
5049
  turnId: activeTurnId
2559
5050
  });
5051
+ const { assistantTranscriptOwned, assistantTranscriptIdempotencyKey } = mirrorOutcome;
5052
+ const shouldCaptureSettledTurnFinalizationContext = turnSucceeded && result.assistantTexts.every((text) => !text.trim()) && result.messagesSnapshot.some((message) => message.role === "toolResult");
5053
+ const settledTurnFinalizationContext = shouldCaptureSettledTurnFinalizationContext ? await captureCodexSettledTurnFinalizationContext({
5054
+ ...activeTranscriptTarget,
5055
+ mirroredMessages: mirrorOutcome.mirroredMessages,
5056
+ settledMessages: result.messagesSnapshot,
5057
+ turnId: activeTurnId
5058
+ }) : void 0;
5059
+ if (shouldCaptureSettledTurnFinalizationContext && !settledTurnFinalizationContext) embeddedAgentLog.warn("codex settled-turn finalization context is unavailable", {
5060
+ threadId: resourceState.thread.threadId,
5061
+ turnId: activeTurnId
5062
+ });
2560
5063
  if (activeContextEngine) {
2561
5064
  const contextEnginePluginId = resolveContextEngineOwnerPluginId(activeContextEngine);
2562
5065
  const isHeartbeat = params.bootstrapContextRunKind === "heartbeat" || params.bootstrapContextRunKind === "commitment-only";
@@ -2687,6 +5190,8 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2687
5190
  ...codexAppServerFailure ? { codexAppServerFailure } : {},
2688
5191
  ...promptTimeoutOutcome ? { promptTimeoutOutcome } : {},
2689
5192
  ...assistantTranscriptOwned ? { assistantTranscriptOwned: true } : {},
5193
+ ...assistantTranscriptIdempotencyKey ? { assistantTranscriptIdempotencyKey } : {},
5194
+ ...settledTurnFinalizationContext ? { settledTurnFinalizationContext } : {},
2690
5195
  ...resourceState.runtimeArtifact ? { runtimeArtifact: resourceState.runtimeArtifact } : {},
2691
5196
  ...!finalAborted && !effectiveTimedOut && !finalPromptError && preparedAuthBinding ? { authBindingFingerprint: preparedAuthBinding.fingerprint } : {},
2692
5197
  systemPromptReport
@@ -3011,7 +5516,7 @@ var ClientTurnRouter = class {
3011
5516
  this.nativeTurnCompletionWatchers = /* @__PURE__ */ new Map();
3012
5517
  this.disposed = false;
3013
5518
  client.addNotificationHandler((notification) => this.routeNotification(notification));
3014
- client.addRequestHandler((request) => this.routeRequest(request));
5519
+ client.addRequestHandler((request, signal) => this.routeRequest(request, signal));
3015
5520
  client.addCloseHandler(() => this.dispose());
3016
5521
  }
3017
5522
  reserveThread(options) {
@@ -3172,34 +5677,35 @@ var ClientTurnRouter = class {
3172
5677
  this.enqueueNotification(route, handler, notification, routeScope);
3173
5678
  return route.notificationTail;
3174
5679
  }
3175
- async routeRequest(request) {
3176
- if (this.disposed) return;
5680
+ async routeRequest(request, signal = new AbortController().signal) {
5681
+ if (this.disposed || signal.aborted) return;
3177
5682
  const scope = readScope(request.params);
3178
5683
  if (!scope.threadId) return;
3179
5684
  const route = this.routes.get(scope.threadId);
3180
5685
  if (!route || route.released) return;
3181
- if (!route.handlers) await route.activated.promise;
3182
- if (route.released || !route.handlers) return;
5686
+ if (!route.handlers && !await waitForPromiseOrAbort(route.activated.promise, signal)) return;
5687
+ if (signal.aborted || route.released || !route.handlers) return;
3183
5688
  const handler = route.handlers.onRequest;
3184
5689
  if (!handler) return;
3185
5690
  while (route.gate === "armed") {
3186
- await route.binding?.promise;
3187
- if (route.released) return;
5691
+ const binding = route.binding?.promise;
5692
+ if (!binding || !await waitForPromiseOrAbort(binding, signal)) return;
5693
+ if (signal.aborted || route.released) return;
3188
5694
  }
3189
5695
  if (route.gate === "bound") {
3190
5696
  if (scope.turnId && scope.turnId !== route.turnId) return;
3191
5697
  if (route.released) return;
3192
5698
  }
3193
- await this.waitForNotifications(route);
3194
- if (route.released) return;
5699
+ if (!await waitForPromiseOrAbort(this.waitForNotifications(route), signal)) return;
5700
+ if (signal.aborted || route.released) return;
3195
5701
  try {
3196
5702
  const result = await handler(request, {
3197
5703
  threadId: scope.threadId,
3198
5704
  ...scope.turnId ? { turnId: scope.turnId } : {}
3199
- });
3200
- return route.released ? void 0 : result;
5705
+ }, signal);
5706
+ return signal.aborted || route.released ? void 0 : result;
3201
5707
  } catch (error) {
3202
- if (route.released) return;
5708
+ if (signal.aborted || route.released) return;
3203
5709
  throw error;
3204
5710
  }
3205
5711
  }
@@ -3319,6 +5825,20 @@ function isCodexTerminalTurnNotification(notification) {
3319
5825
  if (notification.method === "turn/completed") return true;
3320
5826
  return notification.method === "error" && isJsonObject(notification.params) && notification.params.willRetry === false;
3321
5827
  }
5828
+ async function waitForPromiseOrAbort(promise, signal) {
5829
+ if (signal.aborted) return false;
5830
+ let removeAbort;
5831
+ try {
5832
+ return await Promise.race([promise.then(() => true), new Promise((resolve) => {
5833
+ const onAbort = () => resolve(false);
5834
+ signal.addEventListener("abort", onAbort, { once: true });
5835
+ removeAbort = () => signal.removeEventListener("abort", onAbort);
5836
+ if (signal.aborted) onAbort();
5837
+ })]);
5838
+ } finally {
5839
+ removeAbort?.();
5840
+ }
5841
+ }
3322
5842
  function deferred() {
3323
5843
  let resolve;
3324
5844
  return {
@@ -3579,8 +6099,7 @@ async function prepareCodexAttemptPrompt(context) {
3579
6099
  developerInstructions: promptState.developerInstructions,
3580
6100
  messages: structuredClone(historyState.messages),
3581
6101
  ctx: hookContext,
3582
- bootstrapContextRunKind: params.bootstrapContextRunKind,
3583
- ..."beforeAgentStartResult" in params ? { beforeAgentStartResult: params.beforeAgentStartResult } : {}
6102
+ bootstrapContextRunKind: params.bootstrapContextRunKind
3584
6103
  });
3585
6104
  const resolveShiftedPromptInputRange = (prompt, promptInputRange, turnPromptText) => {
3586
6105
  if (!promptInputRange || promptInputRange.start < 0 || promptInputRange.end < promptInputRange.start || promptInputRange.end > prompt.length || !turnPromptText.endsWith(prompt)) return;
@@ -3631,8 +6150,7 @@ async function prepareCodexAttemptPrompt(context) {
3631
6150
  const buildRenderedCodexDeveloperInstructions = () => joinPresentSections(turnState.promptBuild.developerInstructions, buildTurnCollaborationMode(params, {
3632
6151
  turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
3633
6152
  skillsCollaborationInstructions,
3634
- memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
3635
- heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
6153
+ memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions
3636
6154
  }).settings.developer_instructions ?? void 0);
3637
6155
  const rebuildCodexPromptBuildFromCurrentProjection = async () => {
3638
6156
  turnState.promptBuild = await buildPromptFromCurrentInputs();
@@ -5595,7 +8113,7 @@ async function readFile(execServer, params) {
5595
8113
  const fsBridge = requireFsBridge(execServer);
5596
8114
  const stat = await fsBridge.stat({ filePath });
5597
8115
  if (!stat) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, "file not found");
5598
- if (stat.type === "file" && stat.size > CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES) throw new Error(`file is too large to read through Codex sandbox exec-server: ${stat.size} bytes`);
8116
+ assertSandboxFileReadWithinLimit(stat);
5599
8117
  return { dataBase64: (await fsBridge.readFile({ filePath })).toString("base64") };
5600
8118
  }
5601
8119
  /** Writes base64 data to an existing sandbox directory after write-policy checks. */
@@ -5736,6 +8254,15 @@ async function copySandboxPath(execServer, params) {
5736
8254
  }
5737
8255
  return;
5738
8256
  }
8257
+ if (sourceStat.type === "file" && fsBridge.copyFile) {
8258
+ await fsBridge.copyFile({
8259
+ sourcePath: params.sourcePath,
8260
+ destinationPath: params.destinationPath,
8261
+ mkdir: true
8262
+ });
8263
+ return;
8264
+ }
8265
+ assertSandboxFileReadWithinLimit(sourceStat);
5739
8266
  const data = await fsBridge.readFile({ filePath: params.sourcePath });
5740
8267
  await fsBridge.writeFile({
5741
8268
  filePath: params.destinationPath,
@@ -5743,6 +8270,9 @@ async function copySandboxPath(execServer, params) {
5743
8270
  mkdir: true
5744
8271
  });
5745
8272
  }
8273
+ function assertSandboxFileReadWithinLimit(stat) {
8274
+ if (stat.type === "file" && stat.size > CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES) throw new Error(`file is too large to read through Codex sandbox exec-server: ${stat.size} bytes`);
8275
+ }
5746
8276
  function metadataResponse(stat) {
5747
8277
  return {
5748
8278
  isDirectory: stat?.type === "directory",
@@ -6792,6 +9322,15 @@ function prepareCodexAttemptResources(prompt) {
6792
9322
  timeoutMs: params.timeoutMs,
6793
9323
  timeoutFloorMs: options.startupTimeoutFloorMs
6794
9324
  });
9325
+ const requesterChannel = params.messageChannel ?? params.messageProvider;
9326
+ const requester = {
9327
+ ...requesterChannel ? { channel: requesterChannel } : {},
9328
+ ...params.agentAccountId ? { accountId: params.agentAccountId } : {},
9329
+ ...params.senderId ? { senderId: params.senderId } : {},
9330
+ ...params.senderIsOwner !== void 0 ? { senderIsOwner: params.senderIsOwner } : {},
9331
+ ...params.memberRoleIds?.length ? { roleIds: [...params.memberRoleIds] } : {}
9332
+ };
9333
+ const hasRequester = Object.keys(requester).length > 0;
6795
9334
  const buildNativeHookRelayFinalConfigPatch = (decision) => {
6796
9335
  state.nativeHookRelay?.unregister();
6797
9336
  state.nativeHookRelay = createCodexNativeHookRelay({
@@ -6805,6 +9344,7 @@ function prepareCodexAttemptResources(prompt) {
6805
9344
  config: params.config,
6806
9345
  runId: params.runId,
6807
9346
  channelId: hookChannelId,
9347
+ ...hasRequester ? { requester } : {},
6808
9348
  attemptTimeoutMs: params.timeoutMs,
6809
9349
  startupTimeoutMs,
6810
9350
  turnStartTimeoutMs: params.timeoutMs,
@@ -7150,7 +9690,8 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
7150
9690
  const { toolBridge, toolOutcomeOrdinals, suppressedDynamicToolOutcomeOrdinals, allocateCodexToolOutcomeOrdinal } = attemptTools;
7151
9691
  const { state, turnIdRef, userInputBridgeRef, openClawDynamicToolExecutions, pendingOpenClawDynamicToolCompletionIds, postToolRawAssistantCompletionIdleTimeoutMs, turnWatches } = turnRuntime;
7152
9692
  const { emitExecutionPhaseOnce, scheduleTurnReleaseAfterTerminalDynamicTool, scheduleTerminalDynamicToolReleaseCheck } = lifecycle;
7153
- const handleServerRequest = async (request, scope) => {
9693
+ const handleServerRequest = async (request, scope, requestSignal = new AbortController().signal) => {
9694
+ const signal = AbortSignal.any([runAbortController.signal, requestSignal]);
7154
9695
  const turnId = turnIdRef.current;
7155
9696
  const projector = projectorRef.current;
7156
9697
  let armCompletionWatchOnResponse = false;
@@ -7176,7 +9717,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
7176
9717
  turnId,
7177
9718
  pluginAppPolicyContext: resourceState.thread.pluginAppPolicyContext,
7178
9719
  ...computerUseConfig.enabled ? { computerUseMcpServerName: computerUseConfig.mcpServerName } : {},
7179
- signal: runAbortController.signal
9720
+ signal
7180
9721
  });
7181
9722
  }
7182
9723
  if (request.method === "item/tool/requestUserInput") {
@@ -7203,7 +9744,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
7203
9744
  turnId,
7204
9745
  nativeHookRelay: resourceState.nativeHookRelay,
7205
9746
  autoApprove: shouldAutoApproveCodexAppServerApprovals(appServer),
7206
- signal: runAbortController.signal,
9747
+ signal,
7207
9748
  onNativeToolFailureDisposition: (itemId, disposition) => projector?.recordNativeToolApprovalFailure(itemId, disposition)
7208
9749
  });
7209
9750
  }
@@ -7279,7 +9820,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
7279
9820
  const { execution } = openClawDynamicToolExecutions.claim(call, () => handleDynamicToolCallWithTimeout({
7280
9821
  call,
7281
9822
  toolBridge,
7282
- signal: runAbortController.signal,
9823
+ signal,
7283
9824
  timeoutMs: dynamicToolTimeoutMs,
7284
9825
  toolMeta,
7285
9826
  toolCallOrdinal,
@@ -7576,7 +10117,7 @@ function buildMetadataCacheEntryKey(appCacheKey, queryKind) {
7576
10117
  //#endregion
7577
10118
  //#region extensions/codex/src/app-server/plugin-thread-config-deadline.ts
7578
10119
  /** Enforces one bounded startup budget across Codex plugin config discovery. */
7579
- const CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS = 5e3;
10120
+ const CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS = 6e4;
7580
10121
  const CODEX_PLUGIN_THREAD_CONFIG_TIMEOUT_DIVISOR = 4;
7581
10122
  const CODEX_PLUGIN_THREAD_CONFIG_MIN_TIMEOUT_MS = 100;
7582
10123
  var CodexPluginThreadConfigDeadlineError = class extends Error {
@@ -8418,7 +10959,6 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
8418
10959
  turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
8419
10960
  skillsCollaborationInstructions: context.skillsCollaborationInstructions,
8420
10961
  memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
8421
- heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions,
8422
10962
  preserveNativeTurnSettings: usesSupervisionConnection
8423
10963
  });
8424
10964
  codexModelCallDiagnostics.setRequestPayloadBytes(utf8JsonByteLength(turnStartParams));
@@ -8643,7 +11183,11 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
8643
11183
  ctx: hookContext,
8644
11184
  hookRunner
8645
11185
  });
8646
- if (!state.timedOut) await unsubscribeCodexThreadBestEffort(resourceState.client, {
11186
+ const bindingReleased = isIncognitoSessionKey(params.sessionKey) ? await bindingStore.mutate(bindingIdentity, {
11187
+ kind: "clear",
11188
+ threadId: resourceState.thread.threadId
11189
+ }) : true;
11190
+ if (!state.timedOut && bindingReleased) await unsubscribeCodexThreadBestEffort(resourceState.client, {
8647
11191
  threadId: resourceState.thread.threadId,
8648
11192
  timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
8649
11193
  });