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

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 (43) hide show
  1. package/dist/{app-server-policy-DUMF2Xyr.js → app-server-policy-BmDgseo_.js} +1 -1
  2. package/dist/attempt-client-cleanup-Ia52yRWc.js +127 -0
  3. package/dist/{attempt-notifications-Ecjyzufe.js → attempt-notifications-CMR2_fmR.js} +1 -1
  4. package/dist/{media-understanding-provider-IPNNQre6.js → bounded-turn-FEbUXoYT.js} +71 -188
  5. package/dist/capabilities-BHRSI6Cn.js +36 -0
  6. package/dist/cli-metadata.js +1 -1
  7. package/dist/{command-formatters-NCTL7A2q.js → command-formatters-ico4ZFnk.js} +3 -37
  8. package/dist/{command-handlers-DtFbZiba.js → command-handlers-CRmnwI2N.js} +1233 -1221
  9. package/dist/{compact-Kgy26gIM.js → compact-dEN49UH6.js} +8 -7
  10. package/dist/{computer-use-C7x4ZaqR.js → computer-use-BjGylO-E.js} +16 -6
  11. package/dist/{conversation-control-B0s3aIjT.js → conversation-control-DE7d9DOj.js} +6 -5
  12. package/dist/doctor-contract-api.js +24 -86
  13. package/dist/{dynamic-tools-D_vSVmv9.js → dynamic-tools-LIt9ojep.js} +135 -2696
  14. package/dist/event-projector-assistant-message-DTgnPPVF.js +101 -0
  15. package/dist/event-projector-usage-tvgb1NCX.js +69 -0
  16. package/dist/harness.js +31 -11
  17. package/dist/incognito-session-ET_ufDH-.js +2 -0
  18. package/dist/index.js +250 -275
  19. package/dist/media-understanding-provider.js +173 -1
  20. package/dist/{models-DD5zBdX5.js → models-BA01NEez.js} +2 -2
  21. package/dist/{notification-correlation-C8DVQ_Bq.js → notification-correlation-Bj_Ak_jI.js} +3 -3
  22. package/dist/{plugin-app-cache-key-DJbhLYSK.js → plugin-app-cache-key-DSXX-rXO.js} +5 -5
  23. package/dist/{transcript-mirror-D9rTxx2P.js → protocol-validators-Dm4eXZmt.js} +335 -595
  24. package/dist/{rate-limits-CqhWQ2R9.js → rate-limits-S_PXs0ul.js} +1 -1
  25. package/dist/realtime-voice-api-BPcA1uN9.js +494 -0
  26. package/dist/realtime-voice-api.js +2 -0
  27. package/dist/{request-9yf9pZjf.js → request-CXpPennK.js} +1 -1
  28. package/dist/{run-attempt-BIoO8ISr.js → run-attempt-C5GTPJOE.js} +3111 -387
  29. package/dist/{session-binding-Bmt20HfB.js → session-binding-DlVQ-Pxs.js} +957 -890
  30. package/dist/{session-catalog-CA7R-hX2.js → session-catalog-CP2oCcEb.js} +98 -87
  31. package/dist/{session-cli-Bxk3-Wqz.js → session-cli-CqZ0Fp2a.js} +2 -2
  32. package/dist/session-upstream-marker-QE-m5QFG.js +82 -0
  33. package/dist/settled-turn-finalizer-CA_2QXIE.js +303 -0
  34. package/dist/{shared-client-CSXLtCLE.js → shared-client-BVKE40c-.js} +1870 -1694
  35. package/dist/{side-question-DtzquMOb.js → side-question-CO12sHxo.js} +24 -16
  36. package/dist/{thread-lifecycle-CQ_9mAa1.js → thread-lifecycle-DRg_FdzC.js} +127 -153
  37. package/dist/transcript-mirror-uKA-A4tB.js +550 -0
  38. package/dist/upstream-session-fork-_Vrz4WJr.js +320 -0
  39. package/dist/{usage-CuPpFgTc.js → usage-UpVbdX5G.js} +3 -3
  40. package/dist/{web-search-provider.runtime-_x5XTeqh.js → web-search-provider.runtime-CaQMYDbp.js} +3 -3
  41. package/package.json +7 -8
  42. package/npm-shrinkwrap.json +0 -202
  43. package/dist/{auth-binding-C1czuHPA.js → auth-binding-B4FfbcCg.js} +1 -1
@@ -1,32 +1,46 @@
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";
10
- 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";
1
+ import { $ as withCodexStartupTimeout, A as rememberCodexRateLimitsRead, B as flattenCodexDynamicToolFunctions, D as ensureCodexAppServerClientRuntime, F as resolveCodexAppServerPreparedApiKeyCacheKey, G as CodexAppServerStartupError, I as resolveCodexAppServerPreparedAuthHandoff, J as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, K as isCodexAppServerStartupError, M as resolveCodexAppServerAuthProfileId, N as resolveCodexAppServerAuthProfileIdForAgent, O as readCodexRateLimitsRevision, P as resolveCodexAppServerFallbackApiKeyCacheKey, Q as resolveCodexTurnTerminalIdleTimeoutMs, T as isCodexAppServerRequestTimeoutError, U as resolveCodexAppServerHomeDir, V as isJsonObject, W as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, X as resolveCodexTurnAssistantCompletionIdleTimeoutMs, Y as resolveCodexStartupTimeoutMs, Z as resolveCodexTurnCompletionIdleTimeoutMs, _ as CodexAppServerRpcError, a as getLeasedSharedCodexAppServerClient, b as isCodexAppServerBrokenPipeError, d as retainSharedCodexAppServerClientIfCurrent, f as retireSharedCodexAppServerClientIfCurrent, j as resolveCodexAppServerAuthAccountCacheKey, k as readRecentCodexRateLimits, l as releaseLeasedSharedCodexAppServerClient, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as getSharedCodexAppServerClient, s as isCodexAppServerStartSelectionChangedError, t as clearSharedCodexAppServerClientIfCurrent, v as getCodexAppServerClientInstanceId, x as isCodexAppServerConnectionClosedError, y as isCodexAppServerApprovalRequest } from "./shared-client-BVKE40c-.js";
2
+ import { C as isCodexAppServerApprovalPolicyAllowedByRequirements, D as resolveOpenClawExecPolicyForCodexAppServer, E as resolveCodexPluginsPolicy, S as resolveCodexModelBackedReviewerPolicyContext, T as readCodexPluginConfig, c as reclaimCurrentCodexSessionGeneration, h as resolveCodexComputerUseConfig, i as createCodexSessionGenerationSupersededError, l as sessionBindingIdentity, v as shouldAutoApproveCodexAppServerApprovals, w as isCodexSandboxExecServerEnabled, y as withMcpElicitationsApprovalPolicy } from "./session-binding-DlVQ-Pxs.js";
3
+ import { a as closeCodexStartupClientBestEffort, l as retireCodexAppServerClientAfterTimedOutTurn, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError, s as interruptCodexTurnBestEffort, t as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS, u as unsubscribeCodexThreadBestEffort } from "./attempt-client-cleanup-Ia52yRWc.js";
4
+ 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-CMR2_fmR.js";
5
+ import { $ as readHookOutputEntries, B as resolveCodexContextEngineProjectionReserveTokens, F as buildContextEngineBinding, G as mergeCodexThreadConfigs, H as buildCodexPluginThreadConfig, I as isContextEngineBindingCompatible, K as shouldBuildCodexPluginThreadConfig, L as fitCodexProjectedContextForTurnStart, M as areCodexDynamicToolFingerprintsCompatible, N as codexDynamicToolsFingerprint, O as isSystemAgentOnlyCodexDynamicToolAllowlist, P as codexLegacyDynamicToolsFingerprint, Q as readCodexErrorNotificationMessage, R as projectContextEngineAssemblyForCodex, T as filterCodexDynamicTools, U as buildCodexPluginThreadConfigInputFingerprint, W as buildCodexPluginThreadConfigTimeoutFallback, X as extractRawAssistantText, Y as resolveRecoverableCodexPluginConfigKeys, Z as normalizeNonEmptyString, a as sanitizeCodexHistoryImagePayloads, at as readNullableString$1, b as resolveCodexAppServerThreadModelSelection, ct as splitPlanText, et as readItem, g as buildDeveloperInstructions, h as resolveCodexWebSearchPlan, it as readNonNegativeInteger, j as resolveCodexDynamicToolsLoadingForRuntime, n as buildTurnStartParams, nt as readNonEmptyString$1, ot as readNumber, r as buildCodexUserInput, rt as readNonEmptyStringArray, s as startOrResumeThread, st as readString$6, t as buildTurnCollaborationMode, tt as readItemString, w as isCodexAppServerProfilerEnabled, z as resolveCodexContextEngineProjectionMaxChars } from "./thread-lifecycle-DRg_FdzC.js";
6
+ import { n as projectCodexThreadUsageUpdate, t as normalizeCodexResponseTokenUsage } from "./event-projector-usage-tvgb1NCX.js";
7
+ import { a as assertCodexTurnStartResponse, l as readCodexTurn, o as readCodexDynamicToolCallParams, u as readCodexTurnCompletedNotification } from "./protocol-validators-Dm4eXZmt.js";
8
+ import { i as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-DSXX-rXO.js";
9
+ import { t as isIncognitoSessionKey } from "./incognito-session-ET_ufDH-.js";
10
+ import { d as attachCodexMirrorIdentity, f as readMirrorIdentity, i as mirrorPromptAtTurnStartBestEffort, n as createCodexAppServerUserMessagePersistenceNotifier, o as buildCodexUserPromptMessage, s as promptSnapshot, t as codexTranscriptMirrorRuntime, u as serializeCodexMirrorSourceEvidence } from "./transcript-mirror-uKA-A4tB.js";
11
+ import { t as CODEX_CONTROL_METHODS } from "./capabilities-BHRSI6Cn.js";
12
+ import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-S_PXs0ul.js";
13
+ import { r as formatCodexDisplayText } from "./command-formatters-ico4ZFnk.js";
14
+ import { n as resolveCodexAppServerForOpenClawToolPolicy, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-BmDgseo_.js";
15
+ import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId, t as isCodexNotificationForTurn } from "./notification-correlation-Bj_Ak_jI.js";
16
+ import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-B4FfbcCg.js";
17
+ import { i as resolveCodexLocalRuntimeAttribution, n as createAssistantMessage, r as createAssistantMirrorMessage, t as createAssistantCommentaryMessage } from "./event-projector-assistant-message-DTgnPPVF.js";
18
+ 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-LIt9ojep.js";
19
+ import { a as runCodexComputerUseLiveTest, r as killStaleComputerUseMcpChildren, t as ensureCodexComputerUse } from "./computer-use-BjGylO-E.js";
13
20
  import fs from "node:fs/promises";
14
21
  import path, { posix } from "node:path";
15
- import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
16
- import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
22
+ import { asDateTimestampMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
23
+ import { AgentHarnessPreflightError, CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, TOOL_PROGRESS_OUTPUT_MAX_CHARS, agentHarnessAttemptTerminal, 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, prepareHarnessNativeMcpAppPreview, projectAgentHarnessTranscriptMessageForDisplay, resolveAgentDir, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessGatewayQuestion, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
17
24
  import { createHash, randomUUID } from "node:crypto";
18
- import { resolveAgentDir, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
25
+ import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
19
26
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
20
27
  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";
28
+ import { listSessionEntries, parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
22
29
  import { spawn } from "node:child_process";
30
+ import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
23
31
  import { once } from "node:events";
24
32
  import { isIP } from "node:net";
25
33
  import { WebSocketServer } from "ws";
26
- import { parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
27
34
  import { fileURLToPath } from "node:url";
35
+ import { redactSensitiveFieldValue, redactSensitiveText, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
28
36
  import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
37
+ import { readSessionTranscriptEvents } from "openclaw/plugin-sdk/session-transcript-runtime";
29
38
  import { prepareMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
39
+ import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
40
+ import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "openclaw/plugin-sdk/agent-sessions";
41
+ import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
42
+ import { resolveGeneratedMediaMaxBytes } from "openclaw/plugin-sdk/media-generation-runtime";
43
+ import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
30
44
  import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
31
45
  import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
32
46
  import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
@@ -89,106 +103,2677 @@ function createCodexSteeringQueue(params) {
89
103
  for (const item of liveItems) rejectItem(item, unavailableError);
90
104
  throw unavailableError;
91
105
  }
92
- const clientUserMessageId = `openclaw:${params.turnId}:steer:${++batchSequence}`;
93
- const batch = { items: liveItems };
94
- dispatchedBatches.set(clientUserMessageId, batch);
106
+ const clientUserMessageId = `openclaw:${params.turnId}:steer:${++batchSequence}`;
107
+ const batch = { items: liveItems };
108
+ dispatchedBatches.set(clientUserMessageId, batch);
109
+ try {
110
+ await params.client.request("turn/steer", {
111
+ threadId: params.threadId,
112
+ expectedTurnId: params.turnId,
113
+ input: liveItems.flatMap((item) => buildCodexUserInput(item.text, item.images)),
114
+ clientUserMessageId
115
+ });
116
+ } catch (error) {
117
+ dispatchedBatches.delete(clientUserMessageId);
118
+ for (const item of liveItems) rejectItem(item, error);
119
+ throw error;
120
+ }
121
+ };
122
+ const enqueueSend = (items) => {
123
+ const send = sendChain.then(() => sendBatch(items));
124
+ sendChain = send;
125
+ send.catch((error) => {
126
+ for (const item of items) rejectItem(item, error);
127
+ embeddedAgentLog.debug("codex app-server queued steer failed", { error });
128
+ });
129
+ return send;
130
+ };
131
+ const flushBatch = () => {
132
+ clearBatchTimer();
133
+ const items = batchedMessages;
134
+ batchedMessages = [];
135
+ if (items.length === 0) return sendChain;
136
+ const send = enqueueSend(items);
137
+ send.catch(() => void 0);
138
+ return send;
139
+ };
140
+ const createPendingMessage = (text, images) => {
141
+ let resolveDelivery;
142
+ let rejectDelivery;
143
+ const delivery = new Promise((resolve, reject) => {
144
+ resolveDelivery = resolve;
145
+ rejectDelivery = reject;
146
+ });
147
+ const item = {
148
+ text,
149
+ images,
150
+ resolve: resolveDelivery,
151
+ reject: rejectDelivery,
152
+ settled: false
153
+ };
154
+ pendingMessages.add(item);
155
+ return {
156
+ item,
157
+ delivery
158
+ };
159
+ };
160
+ params.signal.addEventListener("abort", abortQueue, { once: true });
161
+ if (params.signal.aborted) abortQueue();
162
+ return {
163
+ async queue(text, options) {
164
+ const pendingUserInput = params.claimPendingUserInput();
165
+ if (pendingUserInput) {
166
+ if (!options?.images?.length) {
167
+ pendingUserInput.answer(text);
168
+ return;
169
+ }
170
+ flushBatch().catch(() => void 0);
171
+ const { item, delivery } = createPendingMessage(text, options.images);
172
+ await Promise.all([enqueueSend([item]).finally(() => pendingUserInput.cancel()), delivery]);
173
+ return;
174
+ }
175
+ if (closedError) throw closedError;
176
+ if (params.signal.aborted) throw new Error("codex app-server steering queue aborted");
177
+ const { item, delivery } = createPendingMessage(text, options?.images);
178
+ batchedMessages.push(item);
179
+ clearBatchTimer();
180
+ const debounceMs = normalizeCodexSteerDebounceMs(options?.debounceMs);
181
+ if (debounceMs === 0) flushBatch();
182
+ else batchTimer = setTimeout(() => {
183
+ batchTimer = void 0;
184
+ flushBatch();
185
+ }, debounceMs);
186
+ return await delivery;
187
+ },
188
+ async flushPending() {
189
+ if (closedError) return;
190
+ await flushBatch().catch(() => void 0);
191
+ },
192
+ confirmConsumed(clientUserMessageId) {
193
+ const batch = dispatchedBatches.get(clientUserMessageId);
194
+ if (!batch) return false;
195
+ dispatchedBatches.delete(clientUserMessageId);
196
+ for (const item of batch.items) resolveItem(item);
197
+ return true;
198
+ },
199
+ cancel: cancelQueue
200
+ };
201
+ }
202
+ /** Normalizes steer debounce milliseconds, preserving explicit zero. */
203
+ function normalizeCodexSteerDebounceMs(value) {
204
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : CODEX_STEER_ALL_DEBOUNCE_MS;
205
+ }
206
+ //#endregion
207
+ //#region extensions/codex/src/app-server/attempt-terminal.ts
208
+ const attemptTerminal = agentHarnessAttemptTerminal;
209
+ //#endregion
210
+ //#region extensions/codex/src/app-server/event-projector-assistant.ts
211
+ var CodexAssistantProjection = class {
212
+ constructor(params, emitAgentEvent, matchesToolProgressEcho, nextTranscriptTimestamp) {
213
+ this.params = params;
214
+ this.emitAgentEvent = emitAgentEvent;
215
+ this.matchesToolProgressEcho = matchesToolProgressEcho;
216
+ this.nextTranscriptTimestamp = nextTranscriptTimestamp;
217
+ this.assistantTextByItem = /* @__PURE__ */ new Map();
218
+ this.assistantItemOrder = [];
219
+ this.assistantTimestampByItem = /* @__PURE__ */ new Map();
220
+ this.assistantPhaseByItem = /* @__PURE__ */ new Map();
221
+ this.latestTerminalAssistantCandidateSuperseded = false;
222
+ this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
223
+ this.terminalAssistantCandidateEarlierActiveItemIds = /* @__PURE__ */ new Set();
224
+ this.lastCommentaryProgressTextByItem = /* @__PURE__ */ new Map();
225
+ this.lastAnswerCandidateEventByItem = /* @__PURE__ */ new Map();
226
+ this.pendingRawCommentaryEchoes = 0;
227
+ this.rawPromotedAssistantItemIds = /* @__PURE__ */ new Set();
228
+ this.assistantStarted = false;
229
+ this.streamedPartialAssistantItemReplaceable = false;
230
+ }
231
+ hasCompletedTerminalAssistantText(completedItemIds) {
232
+ const latestCompletedItemId = this.latestCompletedTerminalAssistantItemId;
233
+ if (!latestCompletedItemId) return false;
234
+ const finalItem = this.resolveFinalAssistantTextItem();
235
+ return this.latestCompletedItemId === latestCompletedItemId && finalItem?.itemId === latestCompletedItemId && completedItemIds.has(latestCompletedItemId);
236
+ }
237
+ getLatestTerminalAssistantCandidate() {
238
+ const itemId = this.latestTerminalAssistantCandidateItemId;
239
+ if (!itemId) return;
240
+ const text = this.assistantTextByItem.get(itemId)?.trim();
241
+ return {
242
+ itemId,
243
+ hasText: Boolean(text && !this.isToolProgressEchoText(itemId, text))
244
+ };
245
+ }
246
+ hasLatestTerminalAssistantCandidateText() {
247
+ return !this.latestTerminalAssistantCandidateSuperseded && this.getLatestTerminalAssistantCandidate()?.hasText === true;
248
+ }
249
+ canReleaseLatestTerminalAssistantAfterToolHandoff() {
250
+ return this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff && this.hasLatestTerminalAssistantCandidateText();
251
+ }
252
+ async handleAssistantDelta(params) {
253
+ const itemId = readString$6(params, "itemId") ?? "assistant";
254
+ const delta = readString$6(params, "delta") ?? "";
255
+ if (!delta) return;
256
+ if (itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
257
+ const isCommentary = this.isCommentaryAssistantItem(itemId);
258
+ if (!isCommentary && itemId !== this.latestTerminalAssistantCandidateItemId) this.markTerminalAssistantCandidateSupersededBy();
259
+ if (!this.assistantStarted) {
260
+ this.assistantStarted = true;
261
+ await this.params.onAssistantMessageStart?.();
262
+ }
263
+ this.rememberAssistantItem(itemId);
264
+ const text = `${this.assistantTextByItem.get(itemId) ?? ""}${delta}`;
265
+ this.assistantTextByItem.set(itemId, text);
266
+ if (isCommentary) {
267
+ this.emitCommentaryProgress({
268
+ itemId,
269
+ text
270
+ });
271
+ return;
272
+ }
273
+ if (this.isFinalAnswerAssistantItem(itemId)) this.emitAnswerCandidate(itemId, "candidate");
274
+ const knownFinalAnswer = this.shouldStreamAssistantPartial(itemId);
275
+ const replace = this.streamedPartialAssistantItemId !== void 0 && this.streamedPartialAssistantItemId !== itemId;
276
+ if (replace && (!knownFinalAnswer || this.streamedPartialAssistantItemReplaceable)) this.streamedPartialAssistantItemReplaceable = true;
277
+ else if (this.streamedPartialAssistantItemId === void 0) this.streamedPartialAssistantItemReplaceable = !knownFinalAnswer;
278
+ this.streamedPartialAssistantItemId = itemId;
279
+ const replaceable = this.streamedPartialAssistantItemReplaceable;
280
+ const replacement = replace && replaceable;
281
+ const streamPayload = {
282
+ text,
283
+ delta: replacement ? "" : delta,
284
+ ...replacement ? { replace: true } : {}
285
+ };
286
+ this.emitAgentEvent({
287
+ stream: "assistant",
288
+ data: {
289
+ ...streamPayload,
290
+ ...replaceable ? { replaceable: true } : {}
291
+ }
292
+ });
293
+ if (knownFinalAnswer && !replaceable) await this.params.onPartialReply?.(streamPayload);
294
+ }
295
+ recordItemStarted(item, itemId) {
296
+ if (item?.type === "agentMessage" && itemId && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
297
+ this.rememberAssistantPhase(item);
298
+ if (item?.type === "agentMessage" && itemId) this.rememberAssistantItem(itemId);
299
+ if (itemId && itemId !== this.latestTerminalAssistantCandidateItemId) {
300
+ this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
301
+ if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
302
+ }
303
+ }
304
+ recordItemCompleted(item, itemId, activeItemIds) {
305
+ if (item?.type === "agentMessage" && itemId && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
306
+ if (itemId) this.latestCompletedItemId = itemId;
307
+ this.rememberAssistantPhase(item);
308
+ if (item?.type === "agentMessage" && !this.isCommentaryAssistantItem(item.id)) {
309
+ this.latestCompletedTerminalAssistantItemId = item.id;
310
+ this.markLatestTerminalAssistantCandidate(item.id, activeItemIds);
311
+ this.pendingRawTerminalAssistantEchoItemId = item.id;
312
+ } else if (itemId) {
313
+ this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
314
+ if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
315
+ }
316
+ if (item?.type === "agentMessage" && typeof item.text === "string") {
317
+ this.rememberAssistantItem(item.id);
318
+ this.assistantTextByItem.set(item.id, item.text);
319
+ if (item.text && this.isCommentaryAssistantItem(item.id)) {
320
+ this.emitCommentaryProgress({
321
+ itemId: item.id,
322
+ text: item.text
323
+ });
324
+ this.pendingRawCommentaryEchoes += 1;
325
+ } else if (item.text && this.isFinalAnswerAssistantItem(item.id)) this.emitAnswerCandidate(item.id, "candidate");
326
+ }
327
+ }
328
+ recordSnapshotItem(item) {
329
+ this.rememberAssistantPhase(item);
330
+ if (item.type === "agentMessage" && typeof item.text === "string") {
331
+ this.rememberAssistantItem(item.id);
332
+ this.assistantTextByItem.set(item.id, item.text);
333
+ }
334
+ }
335
+ handleRawResponseItemCompleted(item, activeItemIds) {
336
+ const role = readString$6(item, "role");
337
+ const phase = readString$6(item, "phase");
338
+ const rawItemId = readString$6(item, "id");
339
+ const candidateWasSupersededBeforeRaw = this.latestTerminalAssistantCandidateSuperseded;
340
+ const pendingTerminalAssistantEchoItemId = this.pendingRawTerminalAssistantEchoItemId;
341
+ const isPendingTerminalAssistantEcho = role === "assistant" && phase !== "commentary" && pendingTerminalAssistantEchoItemId !== void 0 && (rawItemId === void 0 || rawItemId === pendingTerminalAssistantEchoItemId);
342
+ if (pendingTerminalAssistantEchoItemId !== void 0 && !isPendingTerminalAssistantEcho) this.pendingRawTerminalAssistantEchoItemId = void 0;
343
+ if (!isPendingTerminalAssistantEcho) {
344
+ this.latestCompletedItemId = void 0;
345
+ this.markTerminalAssistantCandidateSupersededBy(rawItemId);
346
+ }
347
+ if (role !== "assistant") return;
348
+ if (phase === "commentary" && this.pendingRawCommentaryEchoes > 0) {
349
+ this.pendingRawCommentaryEchoes -= 1;
350
+ return;
351
+ }
352
+ const text = extractRawAssistantText(item);
353
+ if (isPendingTerminalAssistantEcho) {
354
+ const typedItemId = pendingTerminalAssistantEchoItemId;
355
+ this.pendingRawTerminalAssistantEchoItemId = void 0;
356
+ if (this.assistantTextByItem.get(typedItemId)?.trim() || !text) return;
357
+ this.rememberAssistantItem(typedItemId);
358
+ this.assistantTextByItem.set(typedItemId, text);
359
+ return;
360
+ }
361
+ if (!text) return;
362
+ const itemId = rawItemId ?? `raw-assistant-${this.assistantItemOrder.length + 1}`;
363
+ const isIdlessTerminalAssistantAfterCompletedWork = candidateWasSupersededBeforeRaw && rawItemId === void 0 && pendingTerminalAssistantEchoItemId === void 0 && activeItemIds.size === 0;
364
+ if (phase !== "commentary" && candidateWasSupersededBeforeRaw && itemId !== this.streamedPartialAssistantItemId && !isIdlessTerminalAssistantAfterCompletedWork) return;
365
+ if (phase) this.assistantPhaseByItem.set(itemId, phase);
366
+ this.rememberAssistantItem(itemId);
367
+ this.assistantTextByItem.set(itemId, text);
368
+ this.rawPromotedAssistantItemIds.add(itemId);
369
+ if (phase === "commentary") this.emitCommentaryProgress({
370
+ itemId,
371
+ text
372
+ });
373
+ else this.markLatestTerminalAssistantCandidate(itemId, activeItemIds, { canReleaseAfterToolHandoff: isIdlessTerminalAssistantAfterCompletedWork });
374
+ }
375
+ collectAssistantTexts() {
376
+ const finalText = this.resolveFinalAssistantTextItem()?.text;
377
+ return finalText ? [finalText] : [];
378
+ }
379
+ collectCommentaryMessages() {
380
+ return this.assistantItemOrder.flatMap((itemId) => {
381
+ if (!this.isCommentaryAssistantItem(itemId)) return [];
382
+ const text = this.assistantTextByItem.get(itemId)?.trim();
383
+ const timestamp = this.assistantTimestampByItem.get(itemId);
384
+ if (!text || timestamp === void 0) return [];
385
+ return [{
386
+ itemId,
387
+ message: createAssistantCommentaryMessage(this.params, text, itemId, timestamp)
388
+ }];
389
+ });
390
+ }
391
+ finalizeAnswerCandidate(turn) {
392
+ if (turn.status !== "completed") {
393
+ this.supersedeVisibleAnswerCandidate();
394
+ return;
395
+ }
396
+ const turnItems = turn.items ?? [];
397
+ const authoritativeIndex = turnItems.findLastIndex((item) => item.type === "agentMessage" && readItemString(item, "phase") === "final_answer" && typeof item.text === "string" && item.text.trim().length > 0);
398
+ const authoritative = authoritativeIndex >= 0 ? turnItems[authoritativeIndex] : void 0;
399
+ if (turnItems.slice(authoritativeIndex + 1).some(shouldClearTerminalPresentationForNativeItem) || authoritative?.id === this.latestTerminalAssistantCandidateItemId && this.latestTerminalAssistantCandidateSuperseded) {
400
+ this.supersedeVisibleAnswerCandidate();
401
+ return;
402
+ }
403
+ const itemId = authoritative?.id ?? this.visibleAnswerCandidateItemId;
404
+ if (!itemId) return;
405
+ if (itemId !== this.visibleAnswerCandidateItemId) {
406
+ this.supersedeVisibleAnswerCandidate();
407
+ this.visibleAnswerCandidateItemId = itemId;
408
+ }
409
+ this.emitAnswerCandidate(itemId, "selected");
410
+ }
411
+ hasAssistantItemTextForSynthesis() {
412
+ for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
413
+ const itemId = this.assistantItemOrder[i];
414
+ if (!itemId || this.assistantPhaseByItem.get(itemId) === "commentary") continue;
415
+ const text = this.assistantTextByItem.get(itemId);
416
+ if (text && text.length > 0) return true;
417
+ }
418
+ return false;
419
+ }
420
+ createCurrentAttemptAssistantMessage(options) {
421
+ for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
422
+ const itemId = this.assistantItemOrder[i];
423
+ if (!itemId || this.isCommentaryAssistantItem(itemId) || !this.assistantTextByItem.has(itemId)) continue;
424
+ const text = this.assistantTextByItem.get(itemId) ?? "";
425
+ const normalizedText = text.trim();
426
+ if (normalizedText && this.isToolProgressEchoText(itemId, normalizedText)) continue;
427
+ return this.createAssistantMessage(text, options);
428
+ }
429
+ }
430
+ createAssistantMessage(text, options) {
431
+ return createAssistantMessage(this.params, text, options);
432
+ }
433
+ createAssistantMirrorMessage(title, text) {
434
+ return createAssistantMirrorMessage(this.params, title, text);
435
+ }
436
+ rememberAssistantPhase(item) {
437
+ if (item?.type !== "agentMessage") return;
438
+ const phase = readItemString(item, "phase");
439
+ if (phase) this.assistantPhaseByItem.set(item.id, phase);
440
+ }
441
+ isCommentaryAssistantItem(itemId) {
442
+ return this.assistantPhaseByItem.get(itemId) === "commentary";
443
+ }
444
+ isFinalAnswerAssistantItem(itemId) {
445
+ return this.assistantPhaseByItem.get(itemId) === "final_answer";
446
+ }
447
+ shouldStreamAssistantPartial(itemId) {
448
+ return this.assistantPhaseByItem.get(itemId) === "final_answer";
449
+ }
450
+ emitCommentaryProgress(params) {
451
+ const progressText = params.text.replace(/\s+/g, " ").trim();
452
+ if (!progressText || this.lastCommentaryProgressTextByItem.get(params.itemId) === progressText) return;
453
+ this.lastCommentaryProgressTextByItem.set(params.itemId, progressText);
454
+ this.emitAgentEvent({
455
+ stream: "item",
456
+ data: {
457
+ itemId: params.itemId,
458
+ kind: "preamble",
459
+ title: "Preamble",
460
+ phase: "update",
461
+ progressText,
462
+ source: "codex-app-server"
463
+ }
464
+ });
465
+ }
466
+ emitAnswerCandidate(itemId, status) {
467
+ const text = this.assistantTextByItem.get(itemId)?.trim();
468
+ if (!text) return;
469
+ if (status === "candidate" && this.visibleAnswerCandidateItemId !== itemId) {
470
+ this.supersedeVisibleAnswerCandidate();
471
+ this.visibleAnswerCandidateItemId = itemId;
472
+ }
473
+ const signature = `${status}\0${text}`;
474
+ if (this.lastAnswerCandidateEventByItem.get(itemId) === signature) return;
475
+ this.lastAnswerCandidateEventByItem.set(itemId, signature);
476
+ this.emitAgentEvent({
477
+ stream: "item",
478
+ data: {
479
+ itemId,
480
+ kind: "answer_candidate",
481
+ title: "Answer candidate",
482
+ phase: "update",
483
+ status,
484
+ progressText: text,
485
+ source: "codex-app-server",
486
+ hideFromChannelProgress: true
487
+ }
488
+ });
489
+ }
490
+ supersedeVisibleAnswerCandidate() {
491
+ const itemId = this.visibleAnswerCandidateItemId;
492
+ if (!itemId) return;
493
+ this.emitAnswerCandidate(itemId, "superseded");
494
+ this.visibleAnswerCandidateItemId = void 0;
495
+ }
496
+ markLatestTerminalAssistantCandidate(itemId, activeItemIds, options) {
497
+ this.latestTerminalAssistantCandidateItemId = itemId;
498
+ this.latestTerminalAssistantCandidateSuperseded = false;
499
+ this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = options?.canReleaseAfterToolHandoff === true;
500
+ this.terminalAssistantCandidateEarlierActiveItemIds = new Set(activeItemIds);
501
+ }
502
+ markTerminalAssistantCandidateSupersededBy(itemId, options) {
503
+ if (!this.latestTerminalAssistantCandidateItemId) return;
504
+ if (itemId && this.terminalAssistantCandidateEarlierActiveItemIds.has(itemId)) {
505
+ if (!options?.preserveEarlierActiveItem) this.terminalAssistantCandidateEarlierActiveItemIds.delete(itemId);
506
+ return;
507
+ }
508
+ this.latestTerminalAssistantCandidateSuperseded = true;
509
+ this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
510
+ this.terminalAssistantCandidateEarlierActiveItemIds.clear();
511
+ this.supersedeVisibleAnswerCandidate();
512
+ }
513
+ resolveFinalAssistantTextItem() {
514
+ for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
515
+ const itemId = this.assistantItemOrder[i];
516
+ if (!itemId) continue;
517
+ const text = this.assistantTextByItem.get(itemId)?.trim();
518
+ if (this.assistantPhaseByItem.get(itemId) === "commentary") continue;
519
+ if (text && !this.isToolProgressEchoText(itemId, text)) return {
520
+ itemId,
521
+ text
522
+ };
523
+ }
524
+ }
525
+ rememberAssistantItem(itemId) {
526
+ if (!itemId || this.assistantItemOrder.includes(itemId)) return;
527
+ this.assistantItemOrder.push(itemId);
528
+ this.assistantTimestampByItem.set(itemId, this.nextTranscriptTimestamp());
529
+ }
530
+ isToolProgressEchoText(itemId, text) {
531
+ return this.rawPromotedAssistantItemIds.has(itemId) && this.matchesToolProgressEcho(text);
532
+ }
533
+ };
534
+ //#endregion
535
+ //#region extensions/codex/src/app-server/event-projector-diagnostics.ts
536
+ function redactCodexEventKind(method) {
537
+ return redactSensitiveText(sanitizeTerminalText(method));
538
+ }
539
+ var CodexProjectionDiagnostics = class {
540
+ constructor(threadId, turnId) {
541
+ this.threadId = threadId;
542
+ this.turnId = turnId;
543
+ this.warningKeys = /* @__PURE__ */ new Set();
544
+ }
545
+ warnUnknownItemStatus(item) {
546
+ if (!item) return;
547
+ const status = unknownItemStatus(item);
548
+ if (!status) return;
549
+ const safeStatus = redactCodexEventKind(status);
550
+ const safeItemType = redactCodexEventKind(item.type);
551
+ this.warnOnce(JSON.stringify([
552
+ "status",
553
+ item.type,
554
+ status
555
+ ]), "codex app-server item reported unknown status; continuing projection", {
556
+ itemId: item.id,
557
+ itemType: safeItemType,
558
+ status: safeStatus
559
+ });
560
+ }
561
+ warnUnknownEvent(notification, params) {
562
+ const notificationThreadId = readCodexNotificationThreadId(params);
563
+ const notificationTurnId = readCodexNotificationTurnId(params);
564
+ const eventKind = redactCodexEventKind(notification.method);
565
+ this.warnOnce(JSON.stringify(["method", notification.method]), `codex app-server projector received unknown event kind; continuing: ${eventKind}`, {
566
+ eventKind,
567
+ activeThreadId: this.threadId,
568
+ activeTurnId: this.turnId,
569
+ threadId: notificationThreadId,
570
+ turnId: notificationTurnId,
571
+ matchesActiveThread: notificationThreadId === this.threadId,
572
+ matchesActiveTurn: notificationTurnId === this.turnId
573
+ });
574
+ }
575
+ warnOnce(key, message, context) {
576
+ if (this.warningKeys.has(key)) return;
577
+ this.warningKeys.add(key);
578
+ embeddedAgentLog.warn(message, context);
579
+ }
580
+ };
581
+ //#endregion
582
+ //#region extensions/codex/src/app-server/event-projector-tool-output.ts
583
+ const TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS = 1e4;
584
+ const TOOL_OUTPUT_TRUNCATION_NOTICE_PREFIX = "...(OpenClaw truncated Codex native tool output";
585
+ var ToolOutputAccumulator = class {
586
+ constructor() {
587
+ this.prefixByItem = /* @__PURE__ */ new Map();
588
+ this.originalLengthByItem = /* @__PURE__ */ new Map();
589
+ this.normalizedLengthByItem = /* @__PURE__ */ new Map();
590
+ this.trimStateByItem = /* @__PURE__ */ new Map();
591
+ this.truncatedItemIds = /* @__PURE__ */ new Set();
592
+ this.textByItem = /* @__PURE__ */ new Map();
593
+ }
594
+ append(itemId, delta) {
595
+ const originalLength = (this.originalLengthByItem.get(itemId) ?? this.textByItem.get(itemId)?.length ?? 0) + delta.length;
596
+ this.originalLengthByItem.set(itemId, originalLength);
597
+ const normalizedLength = updateToolOutputTrimState(this.trimStateByItem, itemId, delta);
598
+ this.normalizedLengthByItem.set(itemId, normalizedLength);
599
+ if (this.truncatedItemIds.has(itemId)) {
600
+ const next = appendBoundedToolTranscriptText(this.prefixByItem.get(itemId) ?? this.textByItem.get(itemId) ?? "", "", originalLength);
601
+ this.prefixByItem.set(itemId, next.rawPrefix);
602
+ this.textByItem.set(itemId, next.text);
603
+ return {
604
+ text: next.text,
605
+ originalLength,
606
+ normalizedLength,
607
+ rawPrefix: next.rawPrefix
608
+ };
609
+ }
610
+ const next = appendBoundedToolTranscriptText(this.prefixByItem.get(itemId) ?? this.textByItem.get(itemId) ?? "", delta, originalLength);
611
+ this.prefixByItem.set(itemId, next.rawPrefix);
612
+ this.textByItem.set(itemId, next.text);
613
+ if (originalLength > 1e4) this.truncatedItemIds.add(itemId);
614
+ return {
615
+ text: next.text,
616
+ originalLength,
617
+ normalizedLength,
618
+ rawPrefix: next.rawPrefix
619
+ };
620
+ }
621
+ };
622
+ function updateToolOutputTrimState(trimStateByItem, itemId, delta) {
623
+ const state = trimStateByItem.get(itemId) ?? {
624
+ totalLength: 0,
625
+ leadingWhitespaceLength: 0,
626
+ trailingWhitespaceLength: 0,
627
+ sawNonWhitespace: false
628
+ };
629
+ state.totalLength += delta.length;
630
+ const firstNonWhitespace = delta.search(/\S/u);
631
+ if (firstNonWhitespace === -1) {
632
+ if (!state.sawNonWhitespace) state.leadingWhitespaceLength += delta.length;
633
+ state.trailingWhitespaceLength += delta.length;
634
+ trimStateByItem.set(itemId, state);
635
+ return state.sawNonWhitespace ? state.totalLength - state.leadingWhitespaceLength - state.trailingWhitespaceLength : 0;
636
+ }
637
+ if (!state.sawNonWhitespace) {
638
+ state.leadingWhitespaceLength += firstNonWhitespace;
639
+ state.sawNonWhitespace = true;
640
+ }
641
+ state.trailingWhitespaceLength = delta.match(/\s*$/u)?.[0].length ?? 0;
642
+ trimStateByItem.set(itemId, state);
643
+ return state.totalLength - state.leadingWhitespaceLength - state.trailingWhitespaceLength;
644
+ }
645
+ function toolOutputRawEchoSignature(text) {
646
+ const trimmed = text.trim();
647
+ if (!trimmed) return;
648
+ return {
649
+ rawLength: trimmed.length,
650
+ rawPrefix: trimmed.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)
651
+ };
652
+ }
653
+ function normalizeToolTranscriptArguments(value) {
654
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
655
+ return value;
656
+ }
657
+ function collectDynamicToolContentText(contentItems) {
658
+ if (!Array.isArray(contentItems)) return "";
659
+ return contentItems.flatMap((entry) => {
660
+ if (!isJsonObject(entry)) return [];
661
+ const text = readString$6(entry, "text");
662
+ return text ? [text] : [];
663
+ }).join("\n");
664
+ }
665
+ function appendBoundedToolTranscriptText(currentPrefix, delta, originalLength) {
666
+ if (originalLength <= 1e4) {
667
+ const rawPrefix = currentPrefix + delta;
668
+ return {
669
+ text: rawPrefix,
670
+ rawPrefix
671
+ };
672
+ }
673
+ const notice = toolTranscriptTruncationNotice(originalLength);
674
+ if (notice.length >= 1e4) return {
675
+ text: notice.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS),
676
+ rawPrefix: ""
677
+ };
678
+ const textBudget = TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS - notice.length;
679
+ const remaining = Math.max(0, textBudget - currentPrefix.length);
680
+ const rawPrefix = truncateUtf16Safe(remaining > 0 ? `${currentPrefix}${truncateUtf16Safe(delta, remaining)}` : currentPrefix, textBudget);
681
+ return {
682
+ text: `${rawPrefix}${notice}`,
683
+ rawPrefix
684
+ };
685
+ }
686
+ function toolTranscriptTruncationNotice(originalLength) {
687
+ return `\n${`${TOOL_OUTPUT_TRUNCATION_NOTICE_PREFIX}: original ${originalLength} chars, showing ${TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS}; rerun with narrower args.)`}`;
688
+ }
689
+ function truncateToolTranscriptText(text, originalLength = text.length) {
690
+ if (originalLength <= 1e4 && text.length <= 1e4) return text;
691
+ const notice = toolTranscriptTruncationNotice(originalLength);
692
+ if (notice.length >= 1e4) return notice.slice(1, 10001);
693
+ return `${truncateUtf16Safe(text, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS - notice.length)}${notice}`;
694
+ }
695
+ function formatToolSummary(toolName, meta) {
696
+ const trimmedMeta = meta?.trim();
697
+ return formatToolAggregate(toolName, trimmedMeta ? [trimmedMeta] : void 0, { markdown: true });
698
+ }
699
+ function formatToolOutput(toolName, meta, output) {
700
+ const formattedOutput = formatToolProgressOutput(output);
701
+ if (!formattedOutput) return formatToolSummary(toolName, meta);
702
+ const fence = markdownFenceForText(formattedOutput);
703
+ return `${formatToolSummary(toolName, meta)}\n${fence}txt\n${formattedOutput}\n${fence}`;
704
+ }
705
+ function markdownFenceForText(text) {
706
+ return "`".repeat(Math.max(3, longestBacktickRun(text) + 1));
707
+ }
708
+ function longestBacktickRun(value) {
709
+ let longest = 0;
710
+ let current = 0;
711
+ for (const char of value) {
712
+ if (char === "`") {
713
+ current += 1;
714
+ longest = Math.max(longest, current);
715
+ continue;
716
+ }
717
+ current = 0;
718
+ }
719
+ return longest;
720
+ }
721
+ //#endregion
722
+ //#region extensions/codex/src/app-server/tool-progress-normalization.ts
723
+ /**
724
+ * Normalizes and sanitizes Codex dynamic-tool progress payloads before they are
725
+ * emitted into OpenClaw events or logs.
726
+ */
727
+ /** Maps OpenClaw tool-progress config to the mode used by Codex progress metadata. */
728
+ function resolveCodexToolProgressDetailMode(value) {
729
+ return value === "raw" ? "raw" : "explain";
730
+ }
731
+ /** Recursively redacts sensitive strings and handles circular values in event payloads. */
732
+ function sanitizeCodexAgentEventValue(value, seen = /* @__PURE__ */ new WeakSet()) {
733
+ if (typeof value === "string") return redactToolPayloadText(value);
734
+ if (Array.isArray(value)) {
735
+ if (seen.has(value)) return "[Circular]";
736
+ seen.add(value);
737
+ return value.map((entry) => sanitizeCodexAgentEventValue(entry, seen));
738
+ }
739
+ if (value && typeof value === "object") {
740
+ if (seen.has(value)) return "[Circular]";
741
+ seen.add(value);
742
+ const out = {};
743
+ for (const [key, child] of Object.entries(value)) out[key] = typeof child === "string" ? redactSensitiveFieldValue(key, child) : sanitizeCodexAgentEventValue(child, seen);
744
+ return out;
745
+ }
746
+ return value;
747
+ }
748
+ /** Sanitizes a record-shaped Codex agent event payload. */
749
+ function sanitizeCodexAgentEventRecord(value) {
750
+ return sanitizeCodexAgentEventValue(value);
751
+ }
752
+ /** Sanitizes dynamic-tool arguments before diagnostic/event emission. */
753
+ function sanitizeCodexToolArguments(value) {
754
+ if (!isJsonObject(value)) return;
755
+ return sanitizeCodexAgentEventRecord(value);
756
+ }
757
+ /** Sanitizes a Codex dynamic-tool response before diagnostic/event emission. */
758
+ function sanitizeCodexToolResponse(response) {
759
+ return sanitizeCodexAgentEventRecord(response);
760
+ }
761
+ /** Infers compact human-readable tool metadata from Codex dynamic-tool arguments. */
762
+ function inferCodexDynamicToolMeta(call, detailMode) {
763
+ return inferToolMetaFromArgs(call.tool, call.arguments, { detailMode });
764
+ }
765
+ //#endregion
766
+ //#region extensions/codex/src/app-server/event-projector-tool-items.ts
767
+ function nativeToolActionFingerprint(item) {
768
+ if (item.type === "commandExecution" && typeof item.command === "string") return JSON.stringify({
769
+ type: item.type,
770
+ command: item.command,
771
+ cwd: typeof item.cwd === "string" ? item.cwd : ""
772
+ });
773
+ if (item.type === "fileChange") return JSON.stringify({
774
+ type: item.type,
775
+ changes: itemFileChanges(item)
776
+ });
777
+ }
778
+ function isNativePostToolUseRelayItem(item) {
779
+ switch (item.type) {
780
+ case "commandExecution":
781
+ case "fileChange":
782
+ case "mcpToolCall": return true;
783
+ default: return false;
784
+ }
785
+ }
786
+ function shouldSuppressChannelProgressForItem(item) {
787
+ if (shouldSynthesizeToolProgressForItem(item)) return true;
788
+ return item.type === "dynamicToolCall";
789
+ }
790
+ function itemToolArgs(item) {
791
+ if (item.type === "commandExecution") return sanitizeCodexAgentEventRecord({
792
+ command: item.command,
793
+ ...typeof item.cwd === "string" ? { cwd: item.cwd } : {}
794
+ });
795
+ if (item.type === "fileChange") return sanitizeCodexAgentEventRecord({ changes: itemFileChangesForTranscript(item) });
796
+ if (item.type === "webSearch") return webSearchToolArgs(item);
797
+ if (item.type === "dynamicToolCall" || item.type === "mcpToolCall") return sanitizeCodexToolArguments(item.arguments);
798
+ }
799
+ function webSearchToolArgs(item) {
800
+ const action = isJsonObject(item.action) ? item.action : void 0;
801
+ const actionType = action ? readNonEmptyString$1(action, "type") : void 0;
802
+ const queries = action && actionType === "search" ? readNonEmptyStringArray(action, "queries") : [];
803
+ const query = normalizeNonEmptyString(item.query) ?? (action && actionType === "search" ? readNonEmptyString$1(action, "query") : void 0) ?? queries[0];
804
+ const url = action ? readNonEmptyString$1(action, "url") : void 0;
805
+ const pattern = action ? readNonEmptyString$1(action, "pattern") : void 0;
806
+ const args = {};
807
+ if (query) args.query = query;
808
+ if (queries.length > 0) args.queries = queries;
809
+ if (actionType && actionType !== "search") args.action = actionType;
810
+ if (url) args.url = url;
811
+ if (pattern) args.pattern = pattern;
812
+ if (!query && !url && !pattern) args.queryUnavailable = true;
813
+ return sanitizeCodexAgentEventRecord(args);
814
+ }
815
+ function itemToolResult(item) {
816
+ if (item.type === "commandExecution") return { result: sanitizeCodexAgentEventRecord({
817
+ status: item.status,
818
+ exitCode: item.exitCode,
819
+ durationMs: item.durationMs
820
+ }) };
821
+ if (item.type === "fileChange") return { result: sanitizeCodexAgentEventRecord({
822
+ status: item.status,
823
+ changes: itemFileChanges(item)
824
+ }) };
825
+ if (item.type === "mcpToolCall") return { result: sanitizeCodexAgentEventRecord({
826
+ status: item.status,
827
+ durationMs: item.durationMs,
828
+ ...item.error ? { error: item.error } : {},
829
+ ...item.result ? { result: item.result } : {}
830
+ }) };
831
+ if (item.type === "webSearch") return { result: webSearchToolResult(item) };
832
+ return {};
833
+ }
834
+ function webSearchToolResult(item) {
835
+ return sanitizeCodexAgentEventRecord({
836
+ status: itemStatus(item),
837
+ ...typeof item.durationMs === "number" ? { durationMs: item.durationMs } : {},
838
+ ...webSearchToolArgs(item)
839
+ });
840
+ }
841
+ function itemFileChangeRecords(item) {
842
+ const changes = item.changes;
843
+ return Array.isArray(changes) ? changes.filter(isJsonObject) : [];
844
+ }
845
+ function itemFileChanges(item) {
846
+ return itemFileChangeRecords(item).flatMap((change) => {
847
+ const path = normalizeNonEmptyString(change.path);
848
+ if (!path || change.kind === void 0) return [];
849
+ return [{
850
+ path,
851
+ kind: change.kind
852
+ }];
853
+ });
854
+ }
855
+ function fileChangeKindType(kind) {
856
+ if (typeof kind === "string") return kind;
857
+ return isJsonObject(kind) ? normalizeNonEmptyString(kind.type) : void 0;
858
+ }
859
+ function countFileContentLines(content) {
860
+ if (!content) return 0;
861
+ const lines = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
862
+ if (lines.length > 1 && lines.at(-1) === "") lines.pop();
863
+ return lines.length;
864
+ }
865
+ function fileChangeDiffStat(diff, kind) {
866
+ const kindType = fileChangeKindType(kind);
867
+ if (kindType === "add") return {
868
+ added: countFileContentLines(diff),
869
+ removed: 0
870
+ };
871
+ if (kindType === "delete") return {
872
+ added: 0,
873
+ removed: countFileContentLines(diff)
874
+ };
875
+ let added = 0;
876
+ let removed = 0;
877
+ let inHunk = false;
878
+ for (const line of diff.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n")) {
879
+ if (line.startsWith("@@")) {
880
+ inHunk = true;
881
+ continue;
882
+ }
883
+ if (!inHunk) continue;
884
+ if (line.startsWith("+")) added += 1;
885
+ else if (line.startsWith("-")) removed += 1;
886
+ }
887
+ return {
888
+ added,
889
+ removed
890
+ };
891
+ }
892
+ function truncateFileChangeDiffAtLineBoundary(diff, maxChars) {
893
+ if (diff.length <= maxChars) return { diff };
894
+ if (maxChars <= 0) return { diffTruncated: true };
895
+ const boundary = diff.lastIndexOf("\n", maxChars - 1);
896
+ return boundary >= 0 ? {
897
+ diff: diff.slice(0, boundary + 1),
898
+ diffTruncated: true
899
+ } : { diffTruncated: true };
900
+ }
901
+ function itemFileChangesForTranscript(item) {
902
+ let remainingDiffChars = 1e4;
903
+ return itemFileChangeRecords(item).flatMap((change) => {
904
+ const path = normalizeNonEmptyString(change.path);
905
+ if (!path || change.kind === void 0) return [];
906
+ const result = {
907
+ path,
908
+ kind: change.kind
909
+ };
910
+ if (typeof change.diff !== "string") return [result];
911
+ result.stat = fileChangeDiffStat(change.diff, change.kind);
912
+ const bounded = truncateFileChangeDiffAtLineBoundary(change.diff, remainingDiffChars);
913
+ if (bounded.diff !== void 0) {
914
+ result.diff = bounded.diff;
915
+ remainingDiffChars -= bounded.diff.length;
916
+ }
917
+ if (bounded.diffTruncated) result.diffTruncated = true;
918
+ return [result];
919
+ });
920
+ }
921
+ function itemToolError(item, status, outputTextByItem) {
922
+ if (status === "blocked") return "codex native tool blocked";
923
+ if (status !== "failed") return;
924
+ return itemOutputText(item, outputTextByItem) ?? "codex native tool failed";
925
+ }
926
+ function itemMeta(item, detailMode = "explain") {
927
+ if (item.type === "commandExecution" && typeof item.command === "string") return inferToolMetaFromArgs("exec", {
928
+ command: item.command,
929
+ cwd: typeof item.cwd === "string" ? item.cwd : void 0
930
+ }, { detailMode });
931
+ if (item.type === "webSearch") return inferToolMetaFromArgs("web_search", webSearchToolArgs(item), { detailMode });
932
+ const toolName = itemName(item);
933
+ if ((item.type === "dynamicToolCall" || item.type === "mcpToolCall") && toolName) return inferToolMetaFromArgs(toolName, item.arguments, { detailMode });
934
+ }
935
+ function itemOutputText(item, outputTextByItem) {
936
+ if (item.type === "commandExecution") {
937
+ const output = item.aggregatedOutput?.trim() || outputTextByItem?.get(item.id)?.trim();
938
+ return output ? truncateToolTranscriptText(output) : void 0;
939
+ }
940
+ if (item.type === "dynamicToolCall") {
941
+ const output = collectDynamicToolContentText(item.contentItems).trim();
942
+ return output ? truncateToolTranscriptText(output) : void 0;
943
+ }
944
+ if (item.type === "mcpToolCall") {
945
+ const output = item.error ? stringifyJsonValue(item.error) : item.result ? stringifyJsonValue(item.result) : void 0;
946
+ return output ? truncateToolTranscriptText(output) : void 0;
947
+ }
948
+ }
949
+ function itemTranscriptResultText(item, outputTextByItem) {
950
+ const output = itemOutputText(item, outputTextByItem);
951
+ if (output) return output;
952
+ const result = itemToolResult(item).result;
953
+ const resultText = result ? stringifyJsonValue(result) : void 0;
954
+ return resultText ? truncateToolTranscriptText(resultText) : itemStatus(item);
955
+ }
956
+ function stringifyJsonValue(value) {
957
+ try {
958
+ return JSON.stringify(value, null, 2);
959
+ } catch {
960
+ return;
961
+ }
962
+ }
963
+ //#endregion
964
+ //#region extensions/codex/src/app-server/event-projector-tool-progress.ts
965
+ const TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES = /* @__PURE__ */ new Set([
966
+ "message",
967
+ "messages",
968
+ "reply",
969
+ "send",
970
+ "reaction",
971
+ "react",
972
+ "typing"
973
+ ]);
974
+ function shouldEmitTranscriptToolProgress(toolName, _args) {
975
+ const normalized = typeof toolName === "string" ? toolName.trim().toLowerCase() : "";
976
+ return Boolean(normalized && !TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES.has(normalized));
977
+ }
978
+ var CodexToolProgressProjection = class {
979
+ constructor(params) {
980
+ this.params = params;
981
+ this.echoesByItem = /* @__PURE__ */ new Map();
982
+ this.resultSummaryItemIds = /* @__PURE__ */ new Set();
983
+ this.resultOutputItemIds = /* @__PURE__ */ new Set();
984
+ this.resultOutputStreamedItemIds = /* @__PURE__ */ new Set();
985
+ this.transcriptProgressSuppressedIds = /* @__PURE__ */ new Set();
986
+ this.transcriptArgumentsById = /* @__PURE__ */ new Map();
987
+ this.resultOutputDeltaState = /* @__PURE__ */ new Map();
988
+ this.output = new ToolOutputAccumulator();
989
+ this.metas = /* @__PURE__ */ new Map();
990
+ this.sideEffectingNativeIds = /* @__PURE__ */ new Set();
991
+ this.sideEffectingDynamicIds = /* @__PURE__ */ new Set();
992
+ this.transcriptProgressCallIds = /* @__PURE__ */ new Set();
993
+ }
994
+ get outputTextByItem() {
995
+ return this.output.textByItem;
996
+ }
997
+ get toolMetas() {
998
+ return [...this.metas.values()];
999
+ }
1000
+ getToolMeta(itemId) {
1001
+ return this.metas.get(itemId);
1002
+ }
1003
+ get lastToolError() {
1004
+ return this.lastNativeToolError;
1005
+ }
1006
+ get hasPotentialSideEffects() {
1007
+ return this.sideEffectingNativeIds.size > 0 || this.sideEffectingDynamicIds.size > 0;
1008
+ }
1009
+ setLastToolError(error) {
1010
+ if (!error) {
1011
+ this.lastNativeToolError = void 0;
1012
+ return;
1013
+ }
1014
+ const terminalResolution = this.params.observeToolTerminal?.({
1015
+ toolName: error.toolName,
1016
+ ...error.meta ? { meta: error.meta } : {},
1017
+ outcome: "failure",
1018
+ failure: {
1019
+ ...error.errorCode ? { errorCode: error.errorCode } : {},
1020
+ ...error.error ? { error: error.error } : {},
1021
+ ...error.validationErrorSummary ? { validationErrorSummary: error.validationErrorSummary } : {},
1022
+ ...error.timedOut ? { timedOut: true } : {},
1023
+ ...error.middlewareError ? { middlewareError: true } : {}
1024
+ },
1025
+ nativeMutation: {
1026
+ mutatingAction: error.mutatingAction === true,
1027
+ replaySafe: error.mutatingAction !== true,
1028
+ ...error.actionFingerprint ? { actionFingerprint: error.actionFingerprint } : {},
1029
+ ...error.fileTarget ? { fileTarget: error.fileTarget } : {}
1030
+ }
1031
+ });
1032
+ this.lastNativeToolError = terminalResolution?.lastToolError ?? (this.lastNativeToolError?.mutatingAction && error.mutatingAction !== true ? this.lastNativeToolError : error);
1033
+ }
1034
+ recordDynamicToolResult(params) {
1035
+ const resultText = collectDynamicToolContentText(params.contentItems);
1036
+ const existing = this.metas.get(params.callId);
1037
+ this.metas.set(params.callId, {
1038
+ toolName: existing?.toolName ?? params.tool,
1039
+ ...existing?.meta ? { meta: existing.meta } : {},
1040
+ ...params.asyncStarted === true ? { asyncStarted: true } : {},
1041
+ ...!params.success ? { isError: true } : {}
1042
+ });
1043
+ if (params.terminalResolution) this.lastNativeToolError = params.terminalResolution.lastToolError;
1044
+ else if (!params.success) this.lastNativeToolError = {
1045
+ toolName: params.tool,
1046
+ error: resultText || (params.terminalType === "blocked" ? "codex dynamic tool blocked" : "codex dynamic tool failed")
1047
+ };
1048
+ else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
1049
+ if (params.sideEffectEvidence === true) this.sideEffectingDynamicIds.add(params.callId);
1050
+ }
1051
+ handleOutputDelta(params, toolName) {
1052
+ const itemId = readString$6(params, "itemId");
1053
+ const delta = readString$6(params, "delta");
1054
+ if (!itemId || !delta) return;
1055
+ const storedOutput = this.output.append(itemId, delta);
1056
+ this.rememberEcho(itemId, {
1057
+ displayText: storedOutput.text,
1058
+ rawLength: storedOutput.normalizedLength,
1059
+ rawPrefix: storedOutput.rawPrefix,
1060
+ streamedDisplay: true
1061
+ });
1062
+ if (!this.shouldEmitToolOutput()) return;
1063
+ if (this.transcriptProgressSuppressedIds.has(itemId) || !shouldEmitTranscriptToolProgress(toolName, this.transcriptArgumentsById.get(itemId))) return;
1064
+ const state = this.resultOutputDeltaState.get(itemId) ?? {
1065
+ chars: 0,
1066
+ messages: 0,
1067
+ truncated: false
1068
+ };
1069
+ if (state.truncated) return;
1070
+ const remainingChars = Math.max(0, TOOL_PROGRESS_OUTPUT_MAX_CHARS - state.chars);
1071
+ const remainingMessages = Math.max(0, 20 - state.messages);
1072
+ if (remainingChars === 0 || remainingMessages === 0) {
1073
+ state.truncated = true;
1074
+ this.resultOutputDeltaState.set(itemId, state);
1075
+ this.emitToolResultMessage({
1076
+ itemId,
1077
+ text: formatToolOutput(toolName, void 0, "(output truncated)")
1078
+ });
1079
+ return;
1080
+ }
1081
+ const chunk = delta.length > remainingChars ? truncateUtf16Safe(delta, remainingChars) : delta;
1082
+ state.chars += chunk.length;
1083
+ state.messages += 1;
1084
+ const reachedLimit = delta.length > remainingChars || state.chars >= TOOL_PROGRESS_OUTPUT_MAX_CHARS || state.messages >= 20;
1085
+ if (reachedLimit) state.truncated = true;
1086
+ this.resultOutputDeltaState.set(itemId, state);
1087
+ this.resultOutputStreamedItemIds.add(itemId);
1088
+ this.emitToolResultMessage({
1089
+ itemId,
1090
+ text: formatToolOutput(toolName, void 0, reachedLimit ? `${chunk}\n...(truncated)...` : chunk)
1091
+ });
1092
+ }
1093
+ recordNativeToolError(params) {
1094
+ const executionStarted = params.status !== "blocked";
1095
+ const mutatingAction = executionStarted && isMutatingNativeToolItem(params.item);
1096
+ const actionFingerprint = mutatingAction ? nativeToolActionFingerprint(params.item) : void 0;
1097
+ const isFailure = isNonSuccessItemStatus(params.status);
1098
+ const error = isFailure ? itemToolError(params.item, params.status, this.output.textByItem) : void 0;
1099
+ const terminalResolution = this.params.observeToolTerminal?.({
1100
+ toolCallId: params.item.id,
1101
+ toolName: params.name,
1102
+ arguments: itemToolArgs(params.item),
1103
+ ...params.meta ? { meta: params.meta } : {},
1104
+ executionStarted,
1105
+ outcome: isFailure ? "failure" : "success",
1106
+ ...isFailure ? { failure: error ? { error } : {} } : {},
1107
+ nativeMutation: {
1108
+ mutatingAction,
1109
+ replaySafe: !mutatingAction,
1110
+ ...actionFingerprint ? { actionFingerprint } : {}
1111
+ }
1112
+ });
1113
+ if (terminalResolution) {
1114
+ this.lastNativeToolError = terminalResolution.lastToolError;
1115
+ return;
1116
+ }
1117
+ if (isFailure) this.lastNativeToolError = {
1118
+ toolName: params.name,
1119
+ ...params.meta ? { meta: params.meta } : {},
1120
+ ...error ? { error } : {},
1121
+ ...mutatingAction ? { mutatingAction: true } : {},
1122
+ ...actionFingerprint ? { actionFingerprint } : {}
1123
+ };
1124
+ else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
1125
+ }
1126
+ emitToolResultSummary(item) {
1127
+ if (!item || !this.params.onToolResult || !this.shouldEmitToolResult()) return;
1128
+ if (this.resultSummaryItemIds.has(item.id)) return;
1129
+ const toolName = itemName(item);
1130
+ if (!toolName || !shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
1131
+ this.resultSummaryItemIds.add(item.id);
1132
+ this.emitToolResultMessage({
1133
+ itemId: item.id,
1134
+ text: formatToolSummary(toolName, itemMeta(item, this.toolProgressDetailMode()))
1135
+ });
1136
+ }
1137
+ emitToolResultOutput(item) {
1138
+ if (!item || !this.params.onToolResult || !this.shouldEmitToolOutput()) return;
1139
+ if (this.resultOutputItemIds.has(item.id) || this.resultOutputStreamedItemIds.has(item.id)) return;
1140
+ const toolName = itemName(item);
1141
+ const output = itemOutputText(item, this.output.textByItem);
1142
+ if (!toolName || !output || !shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
1143
+ this.emitToolResultMessage({
1144
+ itemId: item.id,
1145
+ text: formatToolOutput(toolName, itemMeta(item, this.toolProgressDetailMode()), output),
1146
+ finalOutput: true,
1147
+ isError: isNonSuccessItemStatus(itemStatus(item))
1148
+ });
1149
+ }
1150
+ recordToolMeta(item) {
1151
+ if (!item) return;
1152
+ if (isSideEffectingNativeToolItem(item)) this.sideEffectingNativeIds.add(item.id);
1153
+ else this.sideEffectingNativeIds.delete(item.id);
1154
+ const toolName = itemName(item);
1155
+ if (!toolName) return;
1156
+ const meta = itemMeta(item, this.toolProgressDetailMode());
1157
+ const status = itemStatus(item);
1158
+ const existing = this.metas.get(item.id);
1159
+ this.metas.set(item.id, {
1160
+ toolName,
1161
+ ...meta ? { meta } : {},
1162
+ ...existing?.asyncStarted ? { asyncStarted: true } : {},
1163
+ ...status !== "running" && isNonSuccessItemStatus(status) ? { isError: true } : {}
1164
+ });
1165
+ }
1166
+ recordTranscriptCall(params) {
1167
+ this.transcriptArgumentsById.set(params.id, params.arguments);
1168
+ if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) this.transcriptProgressSuppressedIds.add(params.id);
1169
+ else this.transcriptProgressSuppressedIds.delete(params.id);
1170
+ this.emitTranscriptToolCallProgress(params);
1171
+ }
1172
+ recordTranscriptResult(params) {
1173
+ this.emitTranscriptToolResultProgress(params);
1174
+ }
1175
+ matchesEcho(text) {
1176
+ for (const state of this.echoesByItem.values()) {
1177
+ if (state.streamedDisplayText === text || state.displayTexts.includes(text)) return true;
1178
+ if (state.streamedRawSignature && text.length === state.streamedRawSignature.length && text.startsWith(state.streamedRawSignature.prefix)) return true;
1179
+ for (const signature of state.rawSignatures) if (text.length === signature.length && text.startsWith(signature.prefix)) return true;
1180
+ }
1181
+ return false;
1182
+ }
1183
+ rememberCommandAggregateOutputEcho(item) {
1184
+ if (item?.type !== "commandExecution" || typeof item.aggregatedOutput !== "string") return;
1185
+ const signature = toolOutputRawEchoSignature(item.aggregatedOutput);
1186
+ if (signature) this.rememberEcho(item.id, signature);
1187
+ }
1188
+ toolProgressDetailMode() {
1189
+ return resolveCodexToolProgressDetailMode(this.params.toolProgressDetail);
1190
+ }
1191
+ emitToolResultMessage(params) {
1192
+ const rawText = params.text.trim();
1193
+ const text = truncateToolTranscriptText(rawText);
1194
+ if (!text) return;
1195
+ this.rememberEcho(params.itemId, {
1196
+ displayText: text,
1197
+ rawText
1198
+ });
1199
+ if (params.finalOutput) this.resultOutputItemIds.add(params.itemId);
1200
+ try {
1201
+ Promise.resolve(this.params.onToolResult?.({
1202
+ text,
1203
+ ...params.isError === true ? { isError: true } : {}
1204
+ })).catch(() => {});
1205
+ } catch {}
1206
+ }
1207
+ shouldEmitToolResult() {
1208
+ return typeof this.params.shouldEmitToolResult === "function" ? this.params.shouldEmitToolResult() : this.params.verboseLevel === "on" || this.params.verboseLevel === "full";
1209
+ }
1210
+ shouldEmitToolOutput() {
1211
+ return typeof this.params.shouldEmitToolOutput === "function" ? this.params.shouldEmitToolOutput() : this.params.verboseLevel === "full";
1212
+ }
1213
+ emitTranscriptToolCallProgress(params) {
1214
+ if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) return;
1215
+ this.transcriptProgressCallIds.add(params.id);
1216
+ const args = normalizeToolTranscriptArguments(params.arguments);
1217
+ const meta = inferToolMetaFromArgs(params.name, args, { detailMode: this.toolProgressDetailMode() });
1218
+ if (!this.params.onToolResult || !this.shouldEmitToolResult() || this.resultSummaryItemIds.has(params.id) || this.resultOutputStreamedItemIds.has(params.id)) return;
1219
+ this.resultSummaryItemIds.add(params.id);
1220
+ this.emitToolResultMessage({
1221
+ itemId: params.id,
1222
+ text: formatToolSummary(params.name, meta)
1223
+ });
1224
+ }
1225
+ emitTranscriptToolResultProgress(params) {
1226
+ if (this.transcriptProgressSuppressedIds.has(params.id) || !shouldEmitTranscriptToolProgress(params.name, this.transcriptArgumentsById.get(params.id))) return;
1227
+ if (!this.transcriptProgressCallIds.has(params.id)) this.emitTranscriptToolCallProgress({
1228
+ id: params.id,
1229
+ name: params.name,
1230
+ arguments: {}
1231
+ });
1232
+ if (!this.params.onToolResult || !this.shouldEmitToolOutput() || this.resultOutputItemIds.has(params.id) || this.resultOutputStreamedItemIds.has(params.id)) return;
1233
+ const text = params.text?.trim();
1234
+ if (text) this.emitToolResultMessage({
1235
+ itemId: params.id,
1236
+ text: formatToolOutput(params.name, void 0, text),
1237
+ finalOutput: true,
1238
+ isError: params.isError
1239
+ });
1240
+ }
1241
+ rememberEcho(itemId, signature) {
1242
+ if (!itemId) return;
1243
+ const existing = this.echoesByItem.get(itemId) ?? {
1244
+ displayTexts: [],
1245
+ rawSignatures: []
1246
+ };
1247
+ const displayText = signature.displayText?.trim();
1248
+ if (displayText) {
1249
+ if (signature.streamedDisplay) existing.streamedDisplayText = displayText;
1250
+ else if (!existing.displayTexts.includes(displayText)) {
1251
+ if (existing.displayTexts.length >= 24) existing.displayTexts.shift();
1252
+ existing.displayTexts.push(displayText);
1253
+ }
1254
+ }
1255
+ const rawText = signature.rawText?.trim();
1256
+ const rawLength = signature.rawLength ?? rawText?.length;
1257
+ const rawPrefix = signature.rawPrefix?.trim() ?? rawText;
1258
+ if (rawLength !== void 0 && rawPrefix && rawPrefix.length >= 1024) {
1259
+ const next = {
1260
+ length: rawLength,
1261
+ prefix: rawPrefix.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)
1262
+ };
1263
+ if (signature.streamedDisplay) existing.streamedRawSignature = next;
1264
+ else {
1265
+ const matchIndex = existing.rawSignatures.findIndex((entry) => entry.prefix === next.prefix);
1266
+ if (matchIndex >= 0) existing.rawSignatures[matchIndex] = next;
1267
+ else {
1268
+ if (existing.rawSignatures.length >= 24) existing.rawSignatures.shift();
1269
+ existing.rawSignatures.push(next);
1270
+ }
1271
+ }
1272
+ }
1273
+ this.echoesByItem.set(itemId, existing);
1274
+ }
1275
+ };
1276
+ //#endregion
1277
+ //#region extensions/codex/src/app-server/session-history.ts
1278
+ /**
1279
+ * Reads OpenClaw session history for Codex transcript mirroring and sanitizes
1280
+ * image payloads before replaying messages into the app-server projector.
1281
+ */
1282
+ function isMissingFileError(error) {
1283
+ return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
1284
+ }
1285
+ function selectPreferredSessionKey(matches, sessionId) {
1286
+ const structural = matches.filter(({ sessionKey }) => sessionKey === sessionId || sessionKey.endsWith(`:${sessionId}`));
1287
+ const candidates = structural.length > 0 ? structural : matches;
1288
+ if (candidates.length === 1) return candidates[0]?.sessionKey;
1289
+ const sorted = candidates.toSorted((left, right) => (right.entry.updatedAt ?? 0) - (left.entry.updatedAt ?? 0));
1290
+ return (sorted[0]?.entry.updatedAt ?? 0) > (sorted[1]?.entry.updatedAt ?? 0) ? sorted[0]?.sessionKey : void 0;
1291
+ }
1292
+ /** Returns sanitized session-context messages for a Codex mirrored session file. */
1293
+ async function readCodexMirroredSessionHistoryMessages(target) {
1294
+ try {
1295
+ const entries = await readCodexMirroredSessionEntries(target);
1296
+ if (entries.length === 0) return [];
1297
+ const firstEntry = entries[0];
1298
+ if (firstEntry?.type !== "session") return [];
1299
+ if (typeof firstEntry.id !== "string") return;
1300
+ migrateSessionEntries(entries);
1301
+ return sanitizeCodexHistoryImagePayloads(buildSessionContext(entries.filter((entry) => {
1302
+ return entry !== null && typeof entry === "object" && !Array.isArray(entry) && entry.type !== "session";
1303
+ })).messages, "codex mirrored history");
1304
+ } catch (error) {
1305
+ if (isMissingFileError(error)) return [];
1306
+ return;
1307
+ }
1308
+ }
1309
+ async function readCodexMirroredSessionEntries(target) {
1310
+ const sqliteMarker = parseSqliteSessionFileMarker(target.sessionFile);
1311
+ if (sqliteMarker) {
1312
+ if (sqliteMarker.sessionId !== target.sessionId || target.agentId !== void 0 && sqliteMarker.agentId !== target.agentId) return [];
1313
+ const sessionKey = resolveSqliteMarkerSessionKey(target, sqliteMarker);
1314
+ if (!sessionKey) return [];
1315
+ return await readSessionTranscriptEvents({
1316
+ agentId: sqliteMarker.agentId,
1317
+ sessionId: sqliteMarker.sessionId,
1318
+ sessionKey,
1319
+ storePath: sqliteMarker.storePath
1320
+ });
1321
+ }
1322
+ return parseSessionEntries(await fs.readFile(target.sessionFile, "utf-8"));
1323
+ }
1324
+ function resolveSqliteMarkerSessionKey(target, marker) {
1325
+ const explicitSessionKey = target.sessionKey?.trim();
1326
+ const entries = listSessionEntries({
1327
+ agentId: marker.agentId,
1328
+ readOnly: true,
1329
+ storePath: marker.storePath
1330
+ });
1331
+ if (explicitSessionKey) {
1332
+ const explicitEntry = entries.find(({ sessionKey }) => sessionKey === explicitSessionKey);
1333
+ if (explicitEntry) return explicitEntry.entry.sessionId === marker.sessionId ? explicitSessionKey : void 0;
1334
+ }
1335
+ return selectPreferredSessionKey(entries.filter(({ entry }) => entry.sessionId === marker.sessionId), marker.sessionId);
1336
+ }
1337
+ //#endregion
1338
+ //#region extensions/codex/src/app-server/event-projector-tool-transcript.ts
1339
+ const ZERO_USAGE = {
1340
+ input: 0,
1341
+ output: 0,
1342
+ cacheRead: 0,
1343
+ cacheWrite: 0,
1344
+ totalTokens: 0,
1345
+ cost: {
1346
+ input: 0,
1347
+ output: 0,
1348
+ cacheRead: 0,
1349
+ cacheWrite: 0,
1350
+ total: 0
1351
+ }
1352
+ };
1353
+ const MISSING_TOOL_RESULT_ERROR = "OpenClaw recorded a native Codex tool.call without a matching tool.result before the turn completed.";
1354
+ var CodexToolTranscriptProjection = class {
1355
+ constructor(params, threadId, turnId, progress, nextTranscriptTimestamp, options = {}) {
1356
+ this.params = params;
1357
+ this.threadId = threadId;
1358
+ this.turnId = turnId;
1359
+ this.progress = progress;
1360
+ this.nextTranscriptTimestamp = nextTranscriptTimestamp;
1361
+ this.options = options;
1362
+ this.messages = [];
1363
+ this.callIds = /* @__PURE__ */ new Set();
1364
+ this.resultIds = /* @__PURE__ */ new Set();
1365
+ this.namesById = /* @__PURE__ */ new Map();
1366
+ this.trajectoryCallIds = /* @__PURE__ */ new Set();
1367
+ this.trajectoryResultIds = /* @__PURE__ */ new Set();
1368
+ this.trajectoryNamesById = /* @__PURE__ */ new Map();
1369
+ this.trajectoryItemsById = /* @__PURE__ */ new Map();
1370
+ this.afterToolCallObservedItemIds = /* @__PURE__ */ new Set();
1371
+ this.nativeMcpAppResultDetails = /* @__PURE__ */ new Map();
1372
+ this.nativeMcpAppResultDetailsAttempted = /* @__PURE__ */ new Set();
1373
+ }
1374
+ get transcriptMessages() {
1375
+ return this.messages;
1376
+ }
1377
+ recordDynamicToolCall(params) {
1378
+ this.recordToolCall({
1379
+ id: params.callId,
1380
+ name: params.tool,
1381
+ arguments: sanitizeCodexToolArguments(params.arguments)
1382
+ });
1383
+ }
1384
+ recordDynamicToolResult(params) {
1385
+ this.recordToolResult({
1386
+ id: params.callId,
1387
+ name: params.tool,
1388
+ text: collectDynamicToolContentText(params.contentItems),
1389
+ isError: !params.success,
1390
+ details: params.details
1391
+ });
1392
+ }
1393
+ recordNativeToolCall(item) {
1394
+ if (!item || !shouldRecordNativeToolTranscript(item)) return;
1395
+ const name = itemName(item);
1396
+ if (name) this.recordToolCall({
1397
+ id: item.id,
1398
+ name,
1399
+ arguments: itemToolArgs(item)
1400
+ });
1401
+ }
1402
+ recordNativeToolResult(item, details) {
1403
+ if (!item || !shouldRecordNativeToolTranscript(item)) return;
1404
+ const name = itemName(item);
1405
+ if (name) this.recordToolResult({
1406
+ id: item.id,
1407
+ name,
1408
+ text: itemTranscriptResultText(item, this.progress.outputTextByItem),
1409
+ isError: isNonSuccessItemStatus(itemStatus(item)),
1410
+ details
1411
+ });
1412
+ }
1413
+ async recordNativeToolResultWithDetails(item) {
1414
+ this.recordNativeToolResult(item, await this.prepareNativeMcpAppResultDetails(item));
1415
+ }
1416
+ async prepareNativeMcpAppResultDetails(item) {
1417
+ if (!item || item.type !== "mcpToolCall" || itemStatus(item) === "running") return;
1418
+ if (this.nativeMcpAppResultDetails.has(item.id)) return this.nativeMcpAppResultDetails.get(item.id);
1419
+ if (this.nativeMcpAppResultDetailsAttempted.has(item.id) || !this.options.prepareNativeMcpAppResultDetails) return;
1420
+ this.nativeMcpAppResultDetailsAttempted.add(item.id);
1421
+ try {
1422
+ const details = await this.options.prepareNativeMcpAppResultDetails(item);
1423
+ if (details !== void 0) this.nativeMcpAppResultDetails.set(item.id, details);
1424
+ return details;
1425
+ } catch (error) {
1426
+ embeddedAgentLog.debug("codex native MCP App preview preparation failed", {
1427
+ itemId: item.id,
1428
+ error
1429
+ });
1430
+ return;
1431
+ }
1432
+ }
1433
+ recordTrajectoryEvent(params) {
1434
+ if (params.phase === "start") {
1435
+ this.trajectoryCallIds.add(params.item.id);
1436
+ this.trajectoryNamesById.set(params.item.id, params.name);
1437
+ this.trajectoryItemsById.set(params.item.id, params.item);
1438
+ this.options.trajectoryRecorder?.recordEvent("tool.call", {
1439
+ threadId: this.threadId,
1440
+ turnId: this.turnId,
1441
+ itemId: params.item.id,
1442
+ toolCallId: params.item.id,
1443
+ name: params.name,
1444
+ arguments: params.args
1445
+ });
1446
+ return;
1447
+ }
1448
+ this.trajectoryResultIds.add(params.item.id);
1449
+ const toolResult = itemToolResult(params.item).result;
1450
+ const output = itemOutputText(params.item, this.progress.outputTextByItem);
1451
+ this.options.trajectoryRecorder?.recordEvent("tool.result", {
1452
+ threadId: this.threadId,
1453
+ turnId: this.turnId,
1454
+ itemId: params.item.id,
1455
+ toolCallId: params.item.id,
1456
+ name: params.name,
1457
+ status: params.status,
1458
+ isError: isNonSuccessItemStatus(params.status),
1459
+ ...toolResult ? { result: toolResult } : {},
1460
+ ...output ? { output } : {}
1461
+ });
1462
+ }
1463
+ emitAfterToolCallObservation(item) {
1464
+ if (!this.shouldEmitAfterToolCallObservation(item)) return;
1465
+ const name = itemName(item);
1466
+ const status = itemStatus(item);
1467
+ if (!name || status === "running") return;
1468
+ this.afterToolCallObservedItemIds.add(item.id);
1469
+ const result = itemToolResult(item).result;
1470
+ const error = itemToolError(item, status, this.progress.outputTextByItem);
1471
+ const startedAt = resolveStartedAtFromDurationMs(item.durationMs);
1472
+ const hookParams = {
1473
+ toolName: name,
1474
+ toolCallId: item.id,
1475
+ runId: this.params.runId,
1476
+ agentId: this.params.agentId,
1477
+ sessionId: this.params.sessionId,
1478
+ sessionKey: this.params.sessionKey,
1479
+ startArgs: itemToolArgs(item) ?? {},
1480
+ ...result !== void 0 ? { result } : {},
1481
+ ...error ? { error } : {},
1482
+ ...startedAt !== void 0 ? { startedAt } : {}
1483
+ };
1484
+ setImmediate(() => {
1485
+ runAgentHarnessAfterToolCallHook(hookParams);
1486
+ });
1487
+ }
1488
+ synthesizeMissingToolResults(params) {
1489
+ if (!params.synthesize) return;
1490
+ const missingTranscriptIds = [...this.callIds].filter((id) => !this.resultIds.has(id));
1491
+ const missingTrajectoryIds = [...this.trajectoryCallIds].filter((id) => !this.trajectoryResultIds.has(id));
1492
+ if (missingTranscriptIds.length === 0 && missingTrajectoryIds.length === 0) return;
1493
+ for (const id of missingTranscriptIds) {
1494
+ const name = this.namesById.get(id) ?? this.trajectoryNamesById.get(id);
1495
+ if (name) this.recordToolResult({
1496
+ id,
1497
+ name,
1498
+ text: formatMissingToolResultError({
1499
+ id,
1500
+ name
1501
+ }),
1502
+ isError: true
1503
+ });
1504
+ }
1505
+ for (const id of missingTrajectoryIds) {
1506
+ const name = this.trajectoryNamesById.get(id) ?? this.namesById.get(id);
1507
+ if (!name) continue;
1508
+ this.trajectoryResultIds.add(id);
1509
+ const text = formatMissingToolResultError({
1510
+ id,
1511
+ name
1512
+ });
1513
+ this.options.trajectoryRecorder?.recordEvent("tool.result", {
1514
+ threadId: this.threadId,
1515
+ turnId: this.turnId,
1516
+ itemId: id,
1517
+ toolCallId: id,
1518
+ name,
1519
+ status: "failed",
1520
+ isError: true,
1521
+ result: {
1522
+ status: "failed",
1523
+ reason: "missing_tool_result"
1524
+ },
1525
+ output: text
1526
+ });
1527
+ }
1528
+ if (!params.recordPromptError) {
1529
+ this.recordMissingToolError(missingTranscriptIds, missingTrajectoryIds);
1530
+ return;
1531
+ }
1532
+ const missingCount = (/* @__PURE__ */ new Set([...missingTranscriptIds, ...missingTrajectoryIds])).size;
1533
+ return missingCount === 1 ? MISSING_TOOL_RESULT_ERROR : `${MISSING_TOOL_RESULT_ERROR} missingToolResultCount=${missingCount}`;
1534
+ }
1535
+ async readMirroredSessionMessages() {
1536
+ return await readCodexMirroredSessionHistoryMessages({
1537
+ agentId: this.params.agentId,
1538
+ sessionFile: this.params.sessionFile,
1539
+ sessionId: this.params.sessionId,
1540
+ sessionKey: this.params.sessionKey
1541
+ }) ?? [];
1542
+ }
1543
+ recordToolCall(params) {
1544
+ if (!params.id || !params.name || this.callIds.has(params.id)) return;
1545
+ this.callIds.add(params.id);
1546
+ this.namesById.set(params.id, params.name);
1547
+ this.progress.recordTranscriptCall(params);
1548
+ this.messages.push(attachCodexMirrorIdentity(this.createToolCallMessage(params), `${this.turnId}:tool:${params.id}:call`));
1549
+ }
1550
+ recordToolResult(params) {
1551
+ if (!params.id || !params.name || this.resultIds.has(params.id)) return;
1552
+ this.resultIds.add(params.id);
1553
+ this.progress.recordTranscriptResult(params);
1554
+ this.messages.push(attachCodexMirrorIdentity(this.createToolResultMessage(params), `${this.turnId}:tool:${params.id}:result`));
1555
+ }
1556
+ recordMissingToolError(missingTranscriptIds, missingTrajectoryIds) {
1557
+ const firstMissingId = missingTranscriptIds.find((id) => Boolean(this.namesById.get(id))) ?? missingTrajectoryIds.find((id) => Boolean(this.trajectoryNamesById.get(id) ?? this.namesById.get(id)));
1558
+ if (!firstMissingId) return;
1559
+ const name = this.namesById.get(firstMissingId) ?? this.trajectoryNamesById.get(firstMissingId);
1560
+ if (!name) return;
1561
+ const item = this.trajectoryItemsById.get(firstMissingId);
1562
+ const meta = item ? itemMeta(item, this.progress.toolProgressDetailMode()) : this.progress.getToolMeta(firstMissingId)?.meta;
1563
+ const actionFingerprint = item ? nativeToolActionFingerprint(item) : void 0;
1564
+ this.progress.setLastToolError({
1565
+ toolName: name,
1566
+ ...meta ? { meta } : {},
1567
+ error: formatMissingToolResultError({
1568
+ id: firstMissingId,
1569
+ name
1570
+ }),
1571
+ ...item && isMutatingNativeToolItem(item) ? { mutatingAction: true } : {},
1572
+ ...actionFingerprint ? { actionFingerprint } : {}
1573
+ });
1574
+ }
1575
+ shouldEmitAfterToolCallObservation(item) {
1576
+ if (!shouldSynthesizeToolProgressForItem(item) || this.afterToolCallObservedItemIds.has(item.id)) return false;
1577
+ return !(this.options.nativePostToolUseRelayEnabled && isNativePostToolUseRelayItem(item));
1578
+ }
1579
+ createToolCallMessage(params) {
1580
+ const args = normalizeToolTranscriptArguments(params.arguments);
1581
+ const attribution = resolveCodexLocalRuntimeAttribution(this.params);
1582
+ return {
1583
+ role: "assistant",
1584
+ content: [{
1585
+ type: "toolCall",
1586
+ id: params.id,
1587
+ name: params.name,
1588
+ arguments: args,
1589
+ input: args
1590
+ }],
1591
+ api: attribution.api ?? "openai-chatgpt-responses",
1592
+ provider: attribution.provider,
1593
+ model: this.params.modelId,
1594
+ usage: ZERO_USAGE,
1595
+ stopReason: "toolUse",
1596
+ timestamp: this.nextTranscriptTimestamp()
1597
+ };
1598
+ }
1599
+ createToolResultMessage(params) {
1600
+ const text = truncateToolTranscriptText(params.text?.trim() || toolResultStatusText(params));
1601
+ return {
1602
+ role: "toolResult",
1603
+ toolCallId: params.id,
1604
+ toolName: params.name,
1605
+ isError: params.isError,
1606
+ content: [{
1607
+ type: "toolResult",
1608
+ id: params.id,
1609
+ name: params.name,
1610
+ toolName: params.name,
1611
+ toolCallId: params.id,
1612
+ toolUseId: params.id,
1613
+ tool_use_id: params.id,
1614
+ content: text,
1615
+ text
1616
+ }],
1617
+ ...params.details !== void 0 ? { details: params.details } : {},
1618
+ timestamp: this.nextTranscriptTimestamp()
1619
+ };
1620
+ }
1621
+ };
1622
+ function formatMissingToolResultError(params) {
1623
+ return `${MISSING_TOOL_RESULT_ERROR} toolCallId=${params.id}; toolName=${params.name}`;
1624
+ }
1625
+ function toolResultStatusText(params) {
1626
+ return params.isError ? `${params.name} failed` : `${params.name} completed`;
1627
+ }
1628
+ function resolveStartedAtFromDurationMs(durationMs) {
1629
+ if (typeof durationMs !== "number" || !Number.isFinite(durationMs)) return;
1630
+ return asDateTimestampMs(Date.now() - Math.max(0, durationMs));
1631
+ }
1632
+ //#endregion
1633
+ //#region extensions/codex/src/app-server/event-projector-events.ts
1634
+ var CodexEventProjection = class {
1635
+ constructor(threadId, turnId, emitAgentEvent, toolProgress, toolTranscript, onNativeToolResultRecorded) {
1636
+ this.threadId = threadId;
1637
+ this.turnId = turnId;
1638
+ this.emitAgentEvent = emitAgentEvent;
1639
+ this.toolProgress = toolProgress;
1640
+ this.toolTranscript = toolTranscript;
1641
+ this.onNativeToolResultRecorded = onNativeToolResultRecorded;
1642
+ this.reviewCount = 0;
1643
+ }
1644
+ get guardianReviewCount() {
1645
+ return this.reviewCount;
1646
+ }
1647
+ handleGuardianReview(method, params) {
1648
+ this.reviewCount += 1;
1649
+ const review = isJsonObject(params.review) ? params.review : void 0;
1650
+ const action = isJsonObject(params.action) ? params.action : void 0;
1651
+ this.emitAgentEvent({
1652
+ stream: "codex_app_server.guardian",
1653
+ data: {
1654
+ method,
1655
+ phase: method.endsWith("/started") ? "started" : "completed",
1656
+ reviewId: readString$6(params, "reviewId"),
1657
+ targetItemId: readNullableString$1(params, "targetItemId"),
1658
+ decisionSource: readString$6(params, "decisionSource"),
1659
+ status: review ? readString$6(review, "status") : void 0,
1660
+ riskLevel: review ? readString$6(review, "riskLevel") : void 0,
1661
+ userAuthorization: review ? readString$6(review, "userAuthorization") : void 0,
1662
+ rationale: review ? readNullableString$1(review, "rationale") : void 0,
1663
+ actionType: action ? readString$6(action, "type") : void 0
1664
+ }
1665
+ });
1666
+ }
1667
+ handleGuardianWarning(params) {
1668
+ this.emitAgentEvent({
1669
+ stream: "codex_app_server.guardian",
1670
+ data: {
1671
+ phase: "warning",
1672
+ message: readString$6(params, "message")
1673
+ }
1674
+ });
1675
+ }
1676
+ handleHook(method, params) {
1677
+ const run = isJsonObject(params.run) ? params.run : void 0;
1678
+ if (!run) return;
1679
+ const durationMs = readNumber(run, "durationMs");
1680
+ const entries = readHookOutputEntries(run.entries);
1681
+ const hookTurnId = readNullableString$1(params, "turnId");
1682
+ this.emitAgentEvent({
1683
+ stream: "codex_app_server.hook",
1684
+ data: {
1685
+ phase: method === "hook/started" ? "started" : "completed",
1686
+ threadId: this.threadId,
1687
+ turnId: hookTurnId === void 0 ? this.turnId : hookTurnId,
1688
+ hookRunId: readString$6(run, "id"),
1689
+ eventName: readString$6(run, "eventName"),
1690
+ handlerType: readString$6(run, "handlerType"),
1691
+ executionMode: readString$6(run, "executionMode"),
1692
+ scope: readString$6(run, "scope"),
1693
+ source: readString$6(run, "source"),
1694
+ sourcePath: readString$6(run, "sourcePath"),
1695
+ status: readString$6(run, "status"),
1696
+ statusMessage: readNullableString$1(run, "statusMessage"),
1697
+ ...durationMs !== void 0 ? { durationMs } : {},
1698
+ ...entries.length > 0 ? { entries } : {}
1699
+ }
1700
+ });
1701
+ }
1702
+ emitStandardItemEvent(params) {
1703
+ const { item } = params;
1704
+ if (!item) return;
1705
+ const kind = itemKind(item);
1706
+ if (!kind) return;
1707
+ const meta = itemMeta(item, this.toolProgress.toolProgressDetailMode());
1708
+ const suppressChannelProgress = shouldSuppressChannelProgressForItem(item);
1709
+ this.emitAgentEvent({
1710
+ stream: "item",
1711
+ data: {
1712
+ itemId: item.id,
1713
+ phase: params.phase,
1714
+ kind,
1715
+ title: itemTitle(item),
1716
+ status: params.phase === "start" ? "running" : itemStatus(item),
1717
+ ...itemName(item) ? { name: itemName(item) } : {},
1718
+ ...meta ? { meta } : {},
1719
+ ...suppressChannelProgress ? { suppressChannelProgress: true } : {}
1720
+ }
1721
+ });
1722
+ }
1723
+ async emitNormalizedToolItemEvent(params) {
1724
+ const { item } = params;
1725
+ if (!item || !shouldSynthesizeToolProgressForItem(item)) return;
1726
+ const name = itemName(item);
1727
+ if (!name) return;
1728
+ const status = params.phase === "result" ? itemStatus(item) : "running";
1729
+ const args = itemToolArgs(item);
1730
+ const meta = itemMeta(item, this.toolProgress.toolProgressDetailMode());
1731
+ this.toolTranscript.recordTrajectoryEvent({
1732
+ phase: params.phase,
1733
+ item,
1734
+ name,
1735
+ args,
1736
+ status
1737
+ });
1738
+ if (params.phase === "result") this.toolProgress.recordNativeToolError({
1739
+ item,
1740
+ name,
1741
+ meta,
1742
+ status
1743
+ });
1744
+ if (!shouldEmitTranscriptToolProgress(name, args)) {
1745
+ if (params.phase === "result") {
1746
+ this.toolTranscript.emitAfterToolCallObservation(item);
1747
+ await this.onNativeToolResultRecorded?.();
1748
+ }
1749
+ return;
1750
+ }
1751
+ this.emitAgentEvent({
1752
+ stream: "tool",
1753
+ data: {
1754
+ phase: params.phase,
1755
+ name,
1756
+ itemId: item.id,
1757
+ toolCallId: item.id,
1758
+ ...meta ? { meta } : {},
1759
+ ...params.phase === "start" && args ? { args } : {},
1760
+ ...params.phase === "result" ? {
1761
+ status,
1762
+ isError: isNonSuccessItemStatus(status),
1763
+ ...itemToolResult(item)
1764
+ } : {}
1765
+ }
1766
+ });
1767
+ if (params.phase === "result") {
1768
+ this.toolTranscript.emitAfterToolCallObservation(item);
1769
+ await this.onNativeToolResultRecorded?.();
1770
+ }
1771
+ }
1772
+ };
1773
+ //#endregion
1774
+ //#region extensions/codex/src/app-server/event-projector-media.ts
1775
+ const GENERATED_IMAGE_MEDIA_SUBDIR = "tool-image-generation";
1776
+ var CodexGeneratedMediaProjection = class {
1777
+ constructor(config) {
1778
+ this.config = config;
1779
+ this.itemIds = /* @__PURE__ */ new Set();
1780
+ this.urlsByItemId = /* @__PURE__ */ new Map();
1781
+ }
1782
+ hasGeneratedMedia() {
1783
+ return this.itemIds.size > 0;
1784
+ }
1785
+ recordNative(item) {
1786
+ if (item?.type !== "imageGeneration") return;
1787
+ const savedPath = readItemString(item, "savedPath")?.trim();
1788
+ if (savedPath) this.recordUrl({
1789
+ itemId: item.id,
1790
+ mediaUrl: savedPath
1791
+ });
1792
+ }
1793
+ async recordRaw(item) {
1794
+ if (readString$6(item, "type") !== "image_generation_call") return;
1795
+ const result = readString$6(item, "result");
1796
+ if (!result) return;
1797
+ const itemId = readString$6(item, "id") ?? `raw-image-${this.itemIds.size}`;
1798
+ this.itemIds.add(itemId);
1799
+ const maxBytes = resolveGeneratedMediaMaxBytes(this.config, "image");
1800
+ const estimatedDecodedBytes = estimateBase64DecodedBytes(result);
1801
+ if (estimatedDecodedBytes !== void 0 && estimatedDecodedBytes > maxBytes) {
1802
+ embeddedAgentLog.warn("codex app-server raw image generation result exceeds media limit", {
1803
+ itemId,
1804
+ estimatedDecodedBytes,
1805
+ maxBytes
1806
+ });
1807
+ return;
1808
+ }
1809
+ const asset = generatedImageAssetFromBase64({
1810
+ base64: result,
1811
+ index: this.itemIds.size,
1812
+ revisedPrompt: readString$6(item, "revised_prompt") ?? readString$6(item, "revisedPrompt"),
1813
+ fileNamePrefix: "codex-image-generation",
1814
+ sniffMimeType: true
1815
+ });
1816
+ if (!asset) return;
1817
+ try {
1818
+ const saved = await saveMediaBuffer(asset.buffer, asset.mimeType, GENERATED_IMAGE_MEDIA_SUBDIR, maxBytes, asset.fileName);
1819
+ this.recordUrl({
1820
+ itemId,
1821
+ mediaUrl: saved.path,
1822
+ replaceExisting: true
1823
+ });
1824
+ } catch (error) {
1825
+ embeddedAgentLog.warn("codex app-server raw image generation result save failed", {
1826
+ itemId,
1827
+ error
1828
+ });
1829
+ }
1830
+ }
1831
+ buildToolMediaUrls(params) {
1832
+ const mediaUrls = new Set(params.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []);
1833
+ if ((params.messagingToolSentMediaUrls?.length ?? 0) === 0) for (const mediaUrl of this.urlsByItemId.values()) mediaUrls.add(mediaUrl);
1834
+ return mediaUrls.size > 0 ? [...mediaUrls] : params.toolMediaUrls;
1835
+ }
1836
+ buildHostOwnedMediaUrls(params) {
1837
+ if ((params.messagingToolSentMediaUrls?.length ?? 0) > 0) return;
1838
+ const mediaUrls = [...this.urlsByItemId.values()];
1839
+ return mediaUrls.length > 0 ? mediaUrls : void 0;
1840
+ }
1841
+ recordUrl(params) {
1842
+ if (this.urlsByItemId.has(params.itemId) && params.replaceExisting !== true) {
1843
+ this.itemIds.add(params.itemId);
1844
+ return;
1845
+ }
1846
+ this.urlsByItemId.set(params.itemId, params.mediaUrl);
1847
+ this.itemIds.add(params.itemId);
1848
+ }
1849
+ };
1850
+ function estimateBase64DecodedBytes(base64) {
1851
+ let nonWhitespaceLength = 0;
1852
+ let previousCode = -1;
1853
+ let lastCode = -1;
1854
+ for (let i = 0; i < base64.length; i += 1) {
1855
+ const code = base64.charCodeAt(i);
1856
+ if (isBase64WhitespaceCode(code)) continue;
1857
+ nonWhitespaceLength += 1;
1858
+ previousCode = lastCode;
1859
+ lastCode = code;
1860
+ }
1861
+ if (nonWhitespaceLength === 0) return;
1862
+ const equalsCode = "=".charCodeAt(0);
1863
+ const padding = lastCode === equalsCode ? previousCode === equalsCode ? 2 : 1 : 0;
1864
+ return Math.max(0, Math.floor(nonWhitespaceLength * 3 / 4) - padding);
1865
+ }
1866
+ function isBase64WhitespaceCode(code) {
1867
+ return code === 32 || code === 9 || code === 10 || code === 13;
1868
+ }
1869
+ //#endregion
1870
+ //#region extensions/codex/src/app-server/event-projector-reasoning.ts
1871
+ var CodexReasoningProjection = class {
1872
+ constructor(params, emitAgentEvent) {
1873
+ this.params = params;
1874
+ this.emitAgentEvent = emitAgentEvent;
1875
+ this.reasoningTextByGroup = /* @__PURE__ */ new Map();
1876
+ this.reasoningItemOrder = /* @__PURE__ */ new Map();
1877
+ this.planTextByItem = /* @__PURE__ */ new Map();
1878
+ this.reasoningStarted = false;
1879
+ this.reasoningEnded = false;
1880
+ }
1881
+ async handleReasoningDelta(method, params) {
1882
+ const itemId = readString$6(params, "itemId") ?? "reasoning";
1883
+ const delta = readString$6(params, "delta") ?? "";
1884
+ if (!delta) return;
1885
+ this.reasoningStarted = true;
1886
+ if (!this.reasoningItemOrder.has(itemId)) this.reasoningItemOrder.set(itemId, this.reasoningItemOrder.size);
1887
+ const groupIndex = method === "item/reasoning/textDelta" ? readNonNegativeInteger(params, "contentIndex") ?? 0 : readNonNegativeInteger(params, "summaryIndex") ?? 0;
1888
+ const groupKey = `${method}\0${itemId}\0${groupIndex}`;
1889
+ const current = this.reasoningTextByGroup.get(groupKey);
1890
+ this.reasoningTextByGroup.set(groupKey, {
1891
+ itemId,
1892
+ method,
1893
+ index: groupIndex,
1894
+ text: `${current?.text ?? ""}${delta}`
1895
+ });
1896
+ await this.params.onReasoningStream?.({
1897
+ text: this.reasoningText(),
1898
+ isReasoningSnapshot: true
1899
+ });
1900
+ }
1901
+ handlePlanDelta(params) {
1902
+ const itemId = readString$6(params, "itemId") ?? "plan";
1903
+ const delta = readString$6(params, "delta") ?? "";
1904
+ if (!delta) return;
1905
+ const text = `${this.planTextByItem.get(itemId) ?? ""}${delta}`;
1906
+ this.planTextByItem.set(itemId, text);
1907
+ this.emitPlanUpdate({
1908
+ explanation: void 0,
1909
+ steps: splitPlanText(text).map((step) => ({
1910
+ step,
1911
+ status: "pending"
1912
+ }))
1913
+ });
1914
+ }
1915
+ handleTurnPlanUpdated(params) {
1916
+ const explanation = readNullableString$1(params, "explanation");
1917
+ const plan = Array.isArray(params.plan) ? params.plan.flatMap((entry) => {
1918
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [];
1919
+ const record = entry;
1920
+ const step = readString$6(record, "step");
1921
+ if (!step) return [];
1922
+ return [{
1923
+ step,
1924
+ status: normalizePlanStepStatus(readString$6(record, "status"))
1925
+ }];
1926
+ }) : void 0;
1927
+ const planText = [explanation, ...(plan ?? []).map(({ step, status }) => `- [${status}] ${step}`)].filter((part) => Boolean(part)).join("\n");
1928
+ if (planText) this.turnPlanText = planText;
1929
+ this.emitPlanUpdate({
1930
+ explanation,
1931
+ steps: plan
1932
+ });
1933
+ }
1934
+ recordItem(item) {
1935
+ if (item?.type === "plan" && typeof item.text === "string" && item.text) {
1936
+ this.planTextByItem.set(item.id, item.text);
1937
+ this.emitPlanUpdate({
1938
+ explanation: void 0,
1939
+ steps: splitPlanText(item.text).map((step) => ({
1940
+ step,
1941
+ status: "pending"
1942
+ }))
1943
+ });
1944
+ }
1945
+ }
1946
+ async maybeEndReasoning() {
1947
+ if (!this.reasoningStarted || this.reasoningEnded) return;
1948
+ this.reasoningEnded = true;
1949
+ await this.params.onReasoningEnd?.();
1950
+ }
1951
+ reasoningText() {
1952
+ return collectReasoningTextValues(this.reasoningTextByGroup, this.reasoningItemOrder).join("\n\n");
1953
+ }
1954
+ planText() {
1955
+ return this.turnPlanText ?? [...this.planTextByItem.values()].filter((text) => text.trim().length > 0).join("\n\n");
1956
+ }
1957
+ emitPlanUpdate(params) {
1958
+ if (!params.explanation && (!params.steps || params.steps.length === 0)) return;
1959
+ this.emitAgentEvent({
1960
+ stream: "plan",
1961
+ data: {
1962
+ phase: "update",
1963
+ title: "Plan updated",
1964
+ source: "codex-app-server",
1965
+ ...params.explanation ? { explanation: params.explanation } : {},
1966
+ ...params.steps && params.steps.length > 0 ? { steps: params.steps } : {}
1967
+ }
1968
+ });
1969
+ }
1970
+ };
1971
+ function normalizePlanStepStatus(status) {
1972
+ if (status === "inProgress" || status === "in_progress") return "in_progress";
1973
+ return status === "completed" ? "completed" : "pending";
1974
+ }
1975
+ function collectReasoningTextValues(groups, itemOrder) {
1976
+ return [...groups.values()].toSorted((left, right) => {
1977
+ const itemDelta = (itemOrder.get(left.itemId) ?? Number.MAX_SAFE_INTEGER) - (itemOrder.get(right.itemId) ?? Number.MAX_SAFE_INTEGER);
1978
+ if (itemDelta !== 0) return itemDelta;
1979
+ const methodDelta = reasoningMethodOrder(left.method) - reasoningMethodOrder(right.method);
1980
+ return methodDelta !== 0 ? methodDelta : left.index - right.index;
1981
+ }).map((group) => group.text).filter((text) => text.trim().length > 0);
1982
+ }
1983
+ function reasoningMethodOrder(method) {
1984
+ return method === "item/reasoning/summaryTextDelta" ? 0 : 1;
1985
+ }
1986
+ //#endregion
1987
+ //#region extensions/codex/src/app-server/event-projector-snapshot.ts
1988
+ function buildCodexMessagesSnapshot(params) {
1989
+ const messages = promptSnapshot(params.runParams, params.turnId, params.upstreamUserText);
1990
+ if (params.reasoningText) messages.push(attachCodexMirrorIdentity(params.createAssistantMirrorMessage("Codex reasoning", params.reasoningText), `${params.turnId}:reasoning`));
1991
+ if (params.planText) messages.push(attachCodexMirrorIdentity(params.createAssistantMirrorMessage("Codex plan", params.planText), `${params.turnId}:plan`));
1992
+ 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));
1993
+ messages.push(...visibleWorkMessages);
1994
+ if (params.lastAssistant) messages.push(attachCodexMirrorIdentity(params.lastAssistant, `${params.turnId}:assistant`));
1995
+ return messages.map((message) => projectAgentHarnessTranscriptMessageForDisplay({
1996
+ hidden: params.runParams.trigger === "memory",
1997
+ message
1998
+ }));
1999
+ }
2000
+ //#endregion
2001
+ //#region extensions/codex/src/app-server/usage-limit-error.ts
2002
+ /**
2003
+ * Enriches Codex usage-limit failures with current rate-limit information and
2004
+ * marks blocked auth profiles when Codex exposes a reset time.
2005
+ */
2006
+ const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
2007
+ function createCodexUsageLimitPromptError(message) {
2008
+ return Object.assign(new Error(message), { status: 429 });
2009
+ }
2010
+ function isCodexUsageLimitPromptError(error) {
2011
+ return error instanceof Error && "status" in error && error.status === 429;
2012
+ }
2013
+ /** Marks a Codex auth profile blocked until the reset time advertised by rate limits. */
2014
+ async function markCodexAuthProfileBlockedFromRateLimits(params) {
2015
+ const authProfileId = params.authProfileId?.trim();
2016
+ if (!authProfileId || !params.params.authProfileStore) return;
2017
+ const blockedUntil = resolveCodexUsageLimitResetAtMs(params.rateLimits);
2018
+ if (!blockedUntil) return;
2019
+ try {
2020
+ await markAuthProfileBlockedUntil({
2021
+ store: params.params.authProfileStore,
2022
+ profileId: authProfileId,
2023
+ blockedUntil,
2024
+ source: "codex_rate_limits",
2025
+ agentDir: params.params.agentDir,
2026
+ runId: params.params.runId,
2027
+ modelId: params.params.modelId
2028
+ });
2029
+ } catch (error) {
2030
+ embeddedAgentLog.debug("failed to mark Codex auth profile blocked from app-server limits", {
2031
+ authProfileId,
2032
+ error: formatErrorMessage(error)
2033
+ });
2034
+ }
2035
+ }
2036
+ /** Formats a turn-start usage-limit error, refreshing rate limits when needed. */
2037
+ async function formatCodexTurnStartUsageLimitError(params) {
2038
+ return refreshCodexUsageLimitError({
2039
+ client: params.client,
2040
+ source: readCodexTurnStartUsageLimitErrorSource(params.client, params.error, params.errorNotification, params.rateLimitsRevisionBeforeTurnStart),
2041
+ timeoutMs: params.timeoutMs,
2042
+ signal: params.signal
2043
+ });
2044
+ }
2045
+ /** Refreshes a generic prompt usage-limit message into a reset-aware message. */
2046
+ async function refreshCodexUsageLimitPromptError(params) {
2047
+ if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(params.message)) return;
2048
+ return refreshCodexUsageLimitError({
2049
+ client: params.client,
2050
+ source: {
2051
+ message: params.message,
2052
+ codexErrorInfo: "usageLimitExceeded",
2053
+ rateLimits: readRecentCodexRateLimits(params.client)
2054
+ },
2055
+ timeoutMs: params.timeoutMs,
2056
+ signal: params.signal
2057
+ });
2058
+ }
2059
+ async function refreshCodexUsageLimitError(params) {
2060
+ const initialMessage = formatCodexUsageLimitErrorMessage(params.source);
2061
+ if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(initialMessage)) return initialMessage ? {
2062
+ message: initialMessage,
2063
+ ...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
2064
+ } : void 0;
2065
+ const rateLimits = await readCodexRateLimitsFromAppServerForUsageLimitError({
2066
+ client: params.client,
2067
+ timeoutMs: params.timeoutMs,
2068
+ signal: params.signal
2069
+ });
2070
+ if (!rateLimits) return initialMessage ? {
2071
+ message: initialMessage,
2072
+ ...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
2073
+ } : void 0;
2074
+ const message = formatCodexUsageLimitErrorMessage({
2075
+ message: params.source.message,
2076
+ codexErrorInfo: params.source.codexErrorInfo,
2077
+ rateLimits,
2078
+ rateLimitsAuthoritative: true
2079
+ }) ?? initialMessage;
2080
+ return message ? {
2081
+ message,
2082
+ rateLimitsForProfile: rateLimits
2083
+ } : void 0;
2084
+ }
2085
+ async function readCodexRateLimitsFromAppServerForUsageLimitError(params) {
2086
+ if (params.signal?.aborted) return;
2087
+ try {
2088
+ const rateLimits = await params.client.request(CODEX_CONTROL_METHODS.rateLimits, void 0, {
2089
+ timeoutMs: resolveCodexUsageLimitRateLimitRefreshTimeoutMs(params.timeoutMs),
2090
+ signal: params.signal
2091
+ });
2092
+ rememberCodexRateLimitsRead(params.client, rateLimits);
2093
+ return rateLimits;
2094
+ } catch (error) {
2095
+ embeddedAgentLog.debug("codex app-server rate-limit refresh failed after usage-limit error", { error: formatErrorMessage(error) });
2096
+ return;
2097
+ }
2098
+ }
2099
+ function resolveCodexUsageLimitRateLimitRefreshTimeoutMs(timeoutMs) {
2100
+ if (timeoutMs === void 0 || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS;
2101
+ return Math.max(100, Math.min(timeoutMs, CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS));
2102
+ }
2103
+ function readCodexTurnStartUsageLimitErrorSource(client, error, errorNotification, rateLimitsRevisionBeforeTurnStart) {
2104
+ const notificationError = readCodexErrorNotification(errorNotification);
2105
+ const errorPayload = readCodexErrorPayload(error);
2106
+ const rateLimits = errorPayload.rateLimits ?? readRecentCodexRateLimits(client);
2107
+ const cacheUpdatedDuringTurnStart = rateLimitsRevisionBeforeTurnStart !== void 0 && readCodexRateLimitsRevision(client) > rateLimitsRevisionBeforeTurnStart;
2108
+ return {
2109
+ message: notificationError?.message ?? errorPayload.message ?? formatErrorMessage(error),
2110
+ codexErrorInfo: notificationError?.codexErrorInfo ?? errorPayload.codexErrorInfo,
2111
+ rateLimits,
2112
+ rateLimitsTrustedForProfile: errorPayload.rateLimits !== void 0 || cacheUpdatedDuringTurnStart
2113
+ };
2114
+ }
2115
+ function readCodexErrorNotification(notification) {
2116
+ if (notification?.method !== "error" || !isJsonObject(notification.params)) return;
2117
+ const error = notification.params.error;
2118
+ return isJsonObject(error) ? {
2119
+ message: readString$5(error, "message"),
2120
+ codexErrorInfo: error.codexErrorInfo
2121
+ } : void 0;
2122
+ }
2123
+ function readCodexErrorPayload(error) {
2124
+ const message = error instanceof Error ? error.message : void 0;
2125
+ if (!error || typeof error !== "object" || !("data" in error)) return { message };
2126
+ const data = error.data;
2127
+ if (!isJsonObject(data)) return { message };
2128
+ const nestedError = isJsonObject(data.error) ? data.error : data;
2129
+ const rateLimits = nestedError.rateLimits ?? data.rateLimits;
2130
+ return {
2131
+ message: readString$5(nestedError, "message") ?? message,
2132
+ codexErrorInfo: nestedError.codexErrorInfo,
2133
+ rateLimits
2134
+ };
2135
+ }
2136
+ function readString$5(record, key) {
2137
+ const value = record[key];
2138
+ return typeof value === "string" ? value : void 0;
2139
+ }
2140
+ //#endregion
2141
+ //#region extensions/codex/src/app-server/event-projector.ts
2142
+ var CodexAppServerEventProjector = class {
2143
+ constructor(params, threadId, turnId, options = {}) {
2144
+ this.params = params;
2145
+ this.threadId = threadId;
2146
+ this.turnId = turnId;
2147
+ this.options = options;
2148
+ this.activeItemIds = /* @__PURE__ */ new Set();
2149
+ this.completedItemIds = /* @__PURE__ */ new Set();
2150
+ this.activeCompactionItemIds = /* @__PURE__ */ new Set();
2151
+ this.terminalPresentationClearedItemIds = /* @__PURE__ */ new Set();
2152
+ this.nativeToolOutcomeOrdinals = /* @__PURE__ */ new Map();
2153
+ this.promptErrorSource = null;
2154
+ this.synthesizedMissingToolResultError = null;
2155
+ this.aborted = false;
2156
+ this.completedCompactionCount = 0;
2157
+ this.lastTranscriptTimestamp = 0;
2158
+ this.diagnostics = new CodexProjectionDiagnostics(threadId, turnId);
2159
+ this.nativeToolLifecycleProjector = new CodexNativeToolLifecycleProjector(params, threadId, turnId, { runAbortSignal: options.runAbortSignal });
2160
+ this.generatedMediaProjection = new CodexGeneratedMediaProjection(params.config);
2161
+ this.toolProgressProjection = new CodexToolProgressProjection(params);
2162
+ this.toolTranscriptProjection = new CodexToolTranscriptProjection(params, threadId, turnId, this.toolProgressProjection, () => this.nextTranscriptTimestamp(), {
2163
+ nativePostToolUseRelayEnabled: options.nativePostToolUseRelayEnabled,
2164
+ prepareNativeMcpAppResultDetails: options.prepareNativeMcpAppResultDetails,
2165
+ trajectoryRecorder: options.trajectoryRecorder
2166
+ });
2167
+ this.eventProjection = new CodexEventProjection(threadId, turnId, (event) => this.emitAgentEvent(event), this.toolProgressProjection, this.toolTranscriptProjection, options.onNativeToolResultRecorded);
2168
+ this.assistantProjection = new CodexAssistantProjection(params, (event) => this.emitAgentEvent(event), (text) => this.toolProgressProjection.matchesEcho(text), () => this.nextTranscriptTimestamp());
2169
+ this.reasoningProjection = new CodexReasoningProjection(params, (event) => this.emitAgentEvent(event));
2170
+ }
2171
+ nextTranscriptTimestamp() {
2172
+ this.lastTranscriptTimestamp = Math.max(Date.now(), this.lastTranscriptTimestamp + 1);
2173
+ return this.lastTranscriptTimestamp;
2174
+ }
2175
+ getCompletedTurnStatus() {
2176
+ return this.completedTurn?.status;
2177
+ }
2178
+ hasCompletedTerminalAssistantText() {
2179
+ return this.assistantProjection.hasCompletedTerminalAssistantText(this.completedItemIds);
2180
+ }
2181
+ getLatestTerminalAssistantCandidate() {
2182
+ return this.assistantProjection.getLatestTerminalAssistantCandidate();
2183
+ }
2184
+ hasLatestTerminalAssistantCandidateText() {
2185
+ return this.assistantProjection.hasLatestTerminalAssistantCandidateText();
2186
+ }
2187
+ canReleaseLatestTerminalAssistantAfterToolHandoff() {
2188
+ return this.assistantProjection.canReleaseLatestTerminalAssistantAfterToolHandoff();
2189
+ }
2190
+ /** Restores a completed final item after only the enclosing turn timeout fired. */
2191
+ recoverCompletedTerminalAssistantAfterTurnWatchTimeout() {
2192
+ if (!this.aborted || this.promptError !== "codex app-server attempt timed out" || !this.hasCompletedTerminalAssistantText()) return false;
2193
+ this.aborted = false;
2194
+ this.promptError = void 0;
2195
+ this.promptErrorSource = null;
2196
+ return true;
2197
+ }
2198
+ /** Resolves the shared model-order position for a native tool item. */
2199
+ recordNativeToolOutcome(item) {
2200
+ if (!item || this.nativeToolOutcomeOrdinals.has(item.id) || !shouldClearTerminalPresentationForNativeItem(item)) return;
2201
+ const ordinal = this.params.allocateToolOutcomeOrdinal?.(item.id);
2202
+ if (ordinal !== void 0) this.nativeToolOutcomeOrdinals.set(item.id, ordinal);
2203
+ }
2204
+ recordNativeToolApprovalFailure(toolCallId, disposition) {
2205
+ this.nativeToolLifecycleProjector.recordApprovalFailureDisposition(toolCallId, disposition);
2206
+ }
2207
+ recordNativeToolPreToolUseFailure(failure) {
2208
+ this.nativeToolLifecycleProjector.recordPreToolUseFailure(failure);
2209
+ }
2210
+ async handleNotification(notification) {
2211
+ const params = isJsonObject(notification.params) ? notification.params : void 0;
2212
+ if (!params) return;
2213
+ if (isHookNotificationMethod(notification.method)) {
2214
+ if (!this.isHookNotificationForCurrentThread(params)) return;
2215
+ } else if (notification.method === "guardianWarning") {
2216
+ if (readCodexNotificationThreadId(params) !== this.threadId) return;
2217
+ } else if (!this.isNotificationForTurn(params)) return;
2218
+ this.nativeToolLifecycleProjector.handleNotification(notification);
2219
+ switch (notification.method) {
2220
+ case "item/agentMessage/delta":
2221
+ await this.assistantProjection.handleAssistantDelta(params);
2222
+ break;
2223
+ case "item/reasoning/summaryTextDelta":
2224
+ case "item/reasoning/textDelta":
2225
+ await this.reasoningProjection.handleReasoningDelta(notification.method, params);
2226
+ break;
2227
+ case "item/plan/delta":
2228
+ this.reasoningProjection.handlePlanDelta(params);
2229
+ break;
2230
+ case "turn/plan/updated":
2231
+ this.reasoningProjection.handleTurnPlanUpdated(params);
2232
+ break;
2233
+ case "item/started":
2234
+ await this.handleItemStarted(params);
2235
+ break;
2236
+ case "item/completed":
2237
+ await this.handleItemCompleted(params);
2238
+ break;
2239
+ case "item/commandExecution/outputDelta":
2240
+ this.toolProgressProjection.handleOutputDelta(params, "bash");
2241
+ break;
2242
+ case "item/autoApprovalReview/started":
2243
+ case "item/autoApprovalReview/completed":
2244
+ this.eventProjection.handleGuardianReview(notification.method, params);
2245
+ break;
2246
+ case "guardianWarning":
2247
+ this.eventProjection.handleGuardianWarning(params);
2248
+ break;
2249
+ case "hook/started":
2250
+ case "hook/completed":
2251
+ this.eventProjection.handleHook(notification.method, params);
2252
+ break;
2253
+ case "thread/tokenUsage/updated":
2254
+ projectCodexThreadUsageUpdate(params, this.tokenUsage, (usage) => this.tokenUsage = usage, (data) => this.emitAgentEvent({
2255
+ stream: "codex_app_server.usage",
2256
+ data
2257
+ }));
2258
+ break;
2259
+ case "turn/completed":
2260
+ await this.handleTurnCompleted(params);
2261
+ break;
2262
+ case "rawResponse/completed":
2263
+ this.handleRawResponseCompleted(params);
2264
+ break;
2265
+ case "rawResponseItem/completed":
2266
+ await this.handleRawResponseItemCompleted(params);
2267
+ break;
2268
+ case "error":
2269
+ this.responseUsage = void 0;
2270
+ if (params.willRetry === true) break;
2271
+ this.promptError = this.formatCodexErrorMessage(params) ?? "codex app-server error";
2272
+ this.promptErrorSource = "prompt";
2273
+ break;
2274
+ case "thread/compacted":
2275
+ case "turn/started":
2276
+ case "turn/diff/updated":
2277
+ case "item/reasoning/summaryPartAdded":
2278
+ case "item/commandExecution/terminalInteraction":
2279
+ case "item/fileChange/outputDelta":
2280
+ case "item/fileChange/patchUpdated":
2281
+ case "item/mcpToolCall/progress":
2282
+ case "model/rerouted":
2283
+ case "model/verification":
2284
+ case "turn/moderationMetadata":
2285
+ case "model/safetyBuffering/updated": break;
2286
+ default:
2287
+ this.diagnostics.warnUnknownEvent(notification, params);
2288
+ break;
2289
+ }
2290
+ }
2291
+ buildResult(toolTelemetry, options) {
2292
+ this.nativeToolLifecycleProjector.finalizeActive();
2293
+ const assistantTexts = this.assistantProjection.collectAssistantTexts();
2294
+ const commentaryMessages = this.assistantProjection.collectCommentaryMessages();
2295
+ const reasoningText = this.reasoningProjection.reasoningText();
2296
+ const planText = this.reasoningProjection.planText();
2297
+ const projectedUsage = this.aborted ? this.tokenUsage : this.responseUsage ?? this.tokenUsage;
2298
+ const hasAssistantItemText = this.assistantProjection.hasAssistantItemTextForSynthesis();
2299
+ const legacyFailClosed = !this.completedTurn || this.completedTurn.status !== "completed" || hasAssistantItemText;
2300
+ const hasDeliverableAssistantOnCompletedTurn = this.completedTurn?.status === "completed" && assistantTexts.some((text) => text.trim().length > 0);
2301
+ const synthesizedMissingToolResultError = this.toolTranscriptProjection.synthesizeMissingToolResults({
2302
+ synthesize: legacyFailClosed,
2303
+ recordPromptError: legacyFailClosed && !hasDeliverableAssistantOnCompletedTurn && !this.aborted
2304
+ });
2305
+ if (synthesizedMissingToolResultError) {
2306
+ this.synthesizedMissingToolResultError = synthesizedMissingToolResultError;
2307
+ this.promptErrorSource = this.promptErrorSource ?? "prompt";
2308
+ }
2309
+ const assistantMessageOptions = {
2310
+ tokenUsage: projectedUsage,
2311
+ aborted: this.aborted,
2312
+ promptError: this.promptError
2313
+ };
2314
+ const lastAssistant = assistantTexts.length ? this.assistantProjection.createAssistantMessage(assistantTexts.join("\n\n"), assistantMessageOptions) : void 0;
2315
+ const currentAttemptAssistant = this.assistantProjection.createCurrentAttemptAssistantMessage(assistantMessageOptions);
2316
+ const messagesSnapshot = buildCodexMessagesSnapshot({
2317
+ runParams: this.params,
2318
+ turnId: this.turnId,
2319
+ upstreamUserText: this.options.upstreamUserText,
2320
+ reasoningText,
2321
+ planText,
2322
+ commentaryMessages,
2323
+ toolMessages: this.toolTranscriptProjection.transcriptMessages,
2324
+ lastAssistant,
2325
+ createAssistantMirrorMessage: (title, text) => this.assistantProjection.createAssistantMirrorMessage(title, text)
2326
+ });
2327
+ const turnFailed = this.completedTurn?.status === "failed";
2328
+ const promptError = this.promptError ?? this.synthesizedMissingToolResultError ?? (turnFailed ? this.completedTurn?.error?.message ?? "codex app-server turn failed" : null);
2329
+ const agentHarnessResultClassification = classifyAgentHarnessTerminalOutcome({
2330
+ assistantTexts,
2331
+ reasoningText,
2332
+ planText,
2333
+ promptError,
2334
+ turnCompleted: Boolean(this.completedTurn)
2335
+ });
2336
+ const toolMetas = this.toolProgressProjection.toolMetas;
2337
+ const hadPotentialSideEffects = toolTelemetry.didSendViaMessagingTool || (toolTelemetry.successfulCronAdds ?? 0) > 0 || this.generatedMediaProjection.hasGeneratedMedia() || this.toolProgressProjection.hasPotentialSideEffects;
2338
+ return {
2339
+ terminal: attemptTerminal.normalize({
2340
+ aborted: this.aborted,
2341
+ promptError,
2342
+ promptErrorSource: promptError ? this.promptErrorSource || "prompt" : null
2343
+ }),
2344
+ sessionIdUsed: this.params.sessionId,
2345
+ ...agentHarnessResultClassification ? { agentHarnessResultClassification } : {},
2346
+ bootstrapPromptWarningSignaturesSeen: this.params.bootstrapPromptWarningSignaturesSeen,
2347
+ bootstrapPromptWarningSignature: this.params.bootstrapPromptWarningSignature,
2348
+ messagesSnapshot,
2349
+ assistantTexts,
2350
+ toolMetas,
2351
+ lastAssistant,
2352
+ currentAttemptAssistant,
2353
+ ...this.toolProgressProjection.lastToolError ? { lastToolError: this.toolProgressProjection.lastToolError } : {},
2354
+ didSendViaMessagingTool: toolTelemetry.didSendViaMessagingTool,
2355
+ didDeliverSourceReplyViaMessageTool: toolTelemetry.didDeliverSourceReplyViaMessageTool === true,
2356
+ messagingToolSentTexts: toolTelemetry.messagingToolSentTexts,
2357
+ messagingToolSentMediaUrls: toolTelemetry.messagingToolSentMediaUrls,
2358
+ messagingToolSentTargets: toolTelemetry.messagingToolSentTargets,
2359
+ messagingToolSourceReplyPayloads: toolTelemetry.messagingToolSourceReplyPayloads ?? [],
2360
+ heartbeatToolResponse: toolTelemetry.heartbeatToolResponse,
2361
+ toolMediaUrls: this.generatedMediaProjection.buildToolMediaUrls(toolTelemetry),
2362
+ hostOwnedToolMediaUrls: this.generatedMediaProjection.buildHostOwnedMediaUrls(toolTelemetry),
2363
+ toolAudioAsVoice: toolTelemetry.toolAudioAsVoice,
2364
+ successfulCronAdds: toolTelemetry.successfulCronAdds,
2365
+ cloudCodeAssistFormatError: false,
2366
+ attemptUsage: projectedUsage,
2367
+ ...this.completedCompactionCount > 0 ? { compactionCount: this.completedCompactionCount } : {},
2368
+ replayMetadata: {
2369
+ hadPotentialSideEffects,
2370
+ replaySafe: !hadPotentialSideEffects
2371
+ },
2372
+ itemLifecycle: {
2373
+ startedCount: this.activeItemIds.size + this.completedItemIds.size,
2374
+ completedCount: this.completedItemIds.size,
2375
+ activeCount: this.activeItemIds.size
2376
+ },
2377
+ yieldDetected: options?.yieldDetected || false,
2378
+ didSendDeterministicApprovalPrompt: this.eventProjection.guardianReviewCount > 0 ? false : void 0
2379
+ };
2380
+ }
2381
+ recordDynamicToolCall(params) {
2382
+ this.toolTranscriptProjection.recordDynamicToolCall(params);
2383
+ }
2384
+ recordDynamicToolResult(params) {
2385
+ this.toolProgressProjection.recordDynamicToolResult(params);
2386
+ this.toolTranscriptProjection.recordDynamicToolResult(params);
2387
+ }
2388
+ markTimedOut() {
2389
+ this.aborted = true;
2390
+ this.promptError = "codex app-server attempt timed out";
2391
+ this.promptErrorSource = "prompt";
2392
+ }
2393
+ markAborted() {
2394
+ this.aborted = true;
2395
+ this.responseUsage = void 0;
2396
+ }
2397
+ isCompacting() {
2398
+ return this.activeCompactionItemIds.size > 0;
2399
+ }
2400
+ async handleItemStarted(params) {
2401
+ const item = readItem(params.item);
2402
+ const itemId = item?.id ?? readString$6(params, "itemId");
2403
+ this.assistantProjection.recordItemStarted(item, itemId);
2404
+ if (itemId) this.activeItemIds.add(itemId);
2405
+ this.recordNativeToolOutcome(item);
2406
+ if (item?.type === "contextCompaction" && itemId) {
2407
+ this.activeCompactionItemIds.add(itemId);
2408
+ await runAgentHarnessBeforeCompactionHook({
2409
+ sessionFile: this.params.sessionFile,
2410
+ messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
2411
+ ctx: {
2412
+ runId: this.params.runId,
2413
+ agentId: this.params.agentId,
2414
+ sessionKey: this.params.sessionKey,
2415
+ sessionId: this.params.sessionId,
2416
+ workspaceDir: this.params.workspaceDir,
2417
+ messageProvider: this.params.messageProvider ?? void 0,
2418
+ trigger: this.params.trigger,
2419
+ channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
2420
+ }
2421
+ });
2422
+ this.emitAgentEvent({
2423
+ stream: "compaction",
2424
+ data: {
2425
+ phase: "start",
2426
+ backend: "codex-app-server",
2427
+ threadId: this.threadId,
2428
+ turnId: this.turnId,
2429
+ itemId
2430
+ }
2431
+ });
2432
+ }
2433
+ this.toolProgressProjection.recordToolMeta(item);
2434
+ this.eventProjection.emitStandardItemEvent({
2435
+ phase: "start",
2436
+ item
2437
+ });
2438
+ await this.eventProjection.emitNormalizedToolItemEvent({
2439
+ phase: "start",
2440
+ item
2441
+ });
2442
+ this.toolTranscriptProjection.recordNativeToolCall(item);
2443
+ this.toolProgressProjection.emitToolResultSummary(item);
2444
+ this.emitAgentEvent({
2445
+ stream: "codex_app_server.item",
2446
+ data: {
2447
+ phase: "started",
2448
+ itemId,
2449
+ type: item?.type
2450
+ }
2451
+ });
2452
+ }
2453
+ async handleItemCompleted(params) {
2454
+ const item = readItem(params.item);
2455
+ this.diagnostics.warnUnknownItemStatus(item);
2456
+ this.recordNativeToolOutcome(item);
2457
+ this.clearTerminalPresentationForNativeItem(item);
2458
+ const itemId = item?.id ?? readString$6(params, "itemId");
2459
+ if (itemId) {
2460
+ this.activeItemIds.delete(itemId);
2461
+ this.completedItemIds.add(itemId);
2462
+ }
2463
+ this.assistantProjection.recordItemCompleted(item, itemId, this.activeItemIds);
2464
+ this.reasoningProjection.recordItem(item);
2465
+ this.generatedMediaProjection.recordNative(item);
2466
+ if (item?.type === "contextCompaction" && itemId) {
2467
+ this.activeCompactionItemIds.delete(itemId);
2468
+ this.completedCompactionCount += 1;
2469
+ this.options.onContextCompacted?.();
2470
+ await runAgentHarnessAfterCompactionHook({
2471
+ sessionFile: this.params.sessionFile,
2472
+ messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
2473
+ compactedCount: -1,
2474
+ ctx: {
2475
+ runId: this.params.runId,
2476
+ agentId: this.params.agentId,
2477
+ sessionKey: this.params.sessionKey,
2478
+ sessionId: this.params.sessionId,
2479
+ workspaceDir: this.params.workspaceDir,
2480
+ messageProvider: this.params.messageProvider ?? void 0,
2481
+ trigger: this.params.trigger,
2482
+ channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
2483
+ }
2484
+ });
2485
+ this.emitAgentEvent({
2486
+ stream: "compaction",
2487
+ data: {
2488
+ phase: "end",
2489
+ backend: "codex-app-server",
2490
+ completed: true,
2491
+ threadId: this.threadId,
2492
+ turnId: this.turnId,
2493
+ itemId
2494
+ }
2495
+ });
2496
+ }
2497
+ this.toolProgressProjection.recordToolMeta(item);
2498
+ this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
2499
+ this.eventProjection.emitStandardItemEvent({
2500
+ phase: "end",
2501
+ item
2502
+ });
2503
+ await this.eventProjection.emitNormalizedToolItemEvent({
2504
+ phase: "result",
2505
+ item
2506
+ });
2507
+ this.toolTranscriptProjection.recordNativeToolCall(item);
2508
+ await this.toolTranscriptProjection.recordNativeToolResultWithDetails(item);
2509
+ this.toolProgressProjection.emitToolResultSummary(item);
2510
+ this.toolProgressProjection.emitToolResultOutput(item);
2511
+ this.emitAgentEvent({
2512
+ stream: "codex_app_server.item",
2513
+ data: {
2514
+ phase: "completed",
2515
+ itemId,
2516
+ type: item?.type
2517
+ }
2518
+ });
2519
+ }
2520
+ handleRawResponseCompleted(params) {
2521
+ const usage = isJsonObject(params.usage) ? params.usage : void 0;
2522
+ this.responseUsage = usage ? normalizeCodexResponseTokenUsage(usage) : void 0;
2523
+ }
2524
+ async handleTurnCompleted(params) {
2525
+ const turn = readCodexTurn(params.turn);
2526
+ if (!turn || turn.id !== this.turnId) return;
2527
+ this.completedTurn = turn;
2528
+ if (turn.status !== "completed") this.responseUsage = void 0;
2529
+ if (turn.status === "failed") {
2530
+ const usageLimitMessage = formatCodexUsageLimitErrorMessage({
2531
+ message: turn.error?.message,
2532
+ codexErrorInfo: turn.error?.codexErrorInfo,
2533
+ rateLimits: this.options.readRecentRateLimits?.()
2534
+ });
2535
+ this.promptError = usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : turn.error?.message ?? "codex app-server turn failed";
2536
+ this.promptErrorSource = "prompt";
2537
+ }
2538
+ const turnItems = turn.items ?? [];
2539
+ for (let index = turnItems.length - 1; index >= 0; index -= 1) {
2540
+ const item = turnItems[index];
2541
+ if (!item || !this.isCurrentTurnSnapshotItem(item)) continue;
2542
+ if (item?.type === "dynamicToolCall") break;
2543
+ if (shouldClearTerminalPresentationForNativeItem(item)) {
2544
+ this.clearTerminalPresentationForNativeItem(item);
2545
+ break;
2546
+ }
2547
+ }
2548
+ for (const item of turnItems) {
2549
+ this.diagnostics.warnUnknownItemStatus(item);
2550
+ this.assistantProjection.recordSnapshotItem(item);
2551
+ this.reasoningProjection.recordItem(item);
2552
+ this.generatedMediaProjection.recordNative(item);
2553
+ this.toolProgressProjection.recordToolMeta(item);
2554
+ this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
2555
+ await this.emitSnapshotOnlyNativeToolProgress(item);
2556
+ this.toolTranscriptProjection.recordNativeToolCall(item);
2557
+ await this.toolTranscriptProjection.recordNativeToolResultWithDetails(item);
2558
+ this.toolTranscriptProjection.emitAfterToolCallObservation(item);
2559
+ this.toolProgressProjection.emitToolResultSummary(item);
2560
+ this.toolProgressProjection.emitToolResultOutput(item);
2561
+ }
2562
+ this.assistantProjection.finalizeAnswerCandidate(turn);
2563
+ this.activeCompactionItemIds.clear();
2564
+ await this.reasoningProjection.maybeEndReasoning();
2565
+ }
2566
+ async emitSnapshotOnlyNativeToolProgress(item) {
2567
+ if (!shouldSynthesizeToolProgressForItem(item) || !this.isCurrentTurnSnapshotItem(item) || this.completedItemIds.has(item.id) || itemStatus(item) === "running") return;
2568
+ if (!this.activeItemIds.has(item.id)) {
2569
+ this.eventProjection.emitStandardItemEvent({
2570
+ phase: "start",
2571
+ item
2572
+ });
2573
+ await this.eventProjection.emitNormalizedToolItemEvent({
2574
+ phase: "start",
2575
+ item
2576
+ });
2577
+ }
2578
+ this.activeItemIds.delete(item.id);
2579
+ this.eventProjection.emitStandardItemEvent({
2580
+ phase: "end",
2581
+ item
2582
+ });
2583
+ await this.eventProjection.emitNormalizedToolItemEvent({
2584
+ phase: "result",
2585
+ item
2586
+ });
2587
+ this.completedItemIds.add(item.id);
2588
+ }
2589
+ isCurrentTurnSnapshotItem(item) {
2590
+ const itemTurnId = readItemString(item, "turnId");
2591
+ return itemTurnId === void 0 || itemTurnId === this.turnId;
2592
+ }
2593
+ async handleRawResponseItemCompleted(params) {
2594
+ const item = isJsonObject(params.item) ? params.item : void 0;
2595
+ if (!item) return;
2596
+ this.assistantProjection.handleRawResponseItemCompleted(item, this.activeItemIds);
2597
+ await this.generatedMediaProjection.recordRaw(item);
2598
+ }
2599
+ clearTerminalPresentationForNativeItem(item) {
2600
+ if (!item || this.terminalPresentationClearedItemIds.has(item.id) || !shouldClearTerminalPresentationForNativeItem(item)) return;
2601
+ const toolCallOrdinal = this.nativeToolOutcomeOrdinals.get(item.id);
2602
+ this.terminalPresentationClearedItemIds.add(item.id);
2603
+ this.params.onToolOutcome?.({
2604
+ toolName: itemName(item) ?? item.type,
2605
+ argsHash: "",
2606
+ resultHash: "",
2607
+ ...toolCallOrdinal !== void 0 ? { toolCallOrdinal } : {},
2608
+ terminalPresentation: void 0,
2609
+ presentationOnly: true
2610
+ });
2611
+ }
2612
+ formatCodexErrorMessage(params) {
2613
+ const error = isJsonObject(params.error) ? params.error : void 0;
2614
+ const usageLimitMessage = formatCodexUsageLimitErrorMessage({
2615
+ message: error ? readString$6(error, "message") : void 0,
2616
+ codexErrorInfo: error?.codexErrorInfo,
2617
+ rateLimits: this.options.readRecentRateLimits?.()
2618
+ });
2619
+ return usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : readCodexErrorNotificationMessage(params);
2620
+ }
2621
+ emitAgentEvent(event) {
95
2622
  try {
96
- await params.client.request("turn/steer", {
97
- threadId: params.threadId,
98
- expectedTurnId: params.turnId,
99
- input: liveItems.flatMap((item) => buildCodexUserInput(item.text, item.images)),
100
- clientUserMessageId
2623
+ emitAgentEvent({
2624
+ runId: this.params.runId,
2625
+ stream: event.stream,
2626
+ data: event.data,
2627
+ ...this.params.sessionKey ? { sessionKey: this.params.sessionKey } : {}
101
2628
  });
102
2629
  } catch (error) {
103
- dispatchedBatches.delete(clientUserMessageId);
104
- for (const item of liveItems) rejectItem(item, error);
105
- throw error;
2630
+ embeddedAgentLog.debug("codex app-server global agent event emit failed", { error });
106
2631
  }
107
- };
108
- const enqueueSend = (items) => {
109
- const send = sendChain.then(() => sendBatch(items));
110
- sendChain = send;
111
- send.catch((error) => {
112
- for (const item of items) rejectItem(item, error);
113
- embeddedAgentLog.debug("codex app-server queued steer failed", { error });
114
- });
115
- return send;
116
- };
117
- const flushBatch = () => {
118
- clearBatchTimer();
119
- const items = batchedMessages;
120
- batchedMessages = [];
121
- if (items.length === 0) return sendChain;
122
- const send = enqueueSend(items);
123
- send.catch(() => void 0);
124
- return send;
125
- };
126
- const createPendingMessage = (text, images) => {
127
- let resolveDelivery;
128
- let rejectDelivery;
129
- const delivery = new Promise((resolve, reject) => {
130
- resolveDelivery = resolve;
131
- rejectDelivery = reject;
132
- });
133
- const item = {
134
- text,
135
- images,
136
- resolve: resolveDelivery,
137
- reject: rejectDelivery,
138
- settled: false
139
- };
140
- pendingMessages.add(item);
141
- return {
142
- item,
143
- delivery
2632
+ try {
2633
+ const maybePromise = this.params.onAgentEvent?.(event);
2634
+ Promise.resolve(maybePromise).catch((error) => {
2635
+ embeddedAgentLog.debug("codex app-server agent event handler rejected", { error });
2636
+ });
2637
+ } catch (error) {
2638
+ embeddedAgentLog.debug("codex app-server agent event handler threw", { error });
2639
+ }
2640
+ }
2641
+ isNotificationForTurn(params) {
2642
+ const threadId = readCodexNotificationThreadId(params);
2643
+ const turnId = readCodexNotificationTurnId(params);
2644
+ return threadId === this.threadId && turnId === this.turnId;
2645
+ }
2646
+ isHookNotificationForCurrentThread(params) {
2647
+ const threadId = readString$6(params, "threadId");
2648
+ const turnId = params.turnId;
2649
+ return threadId === this.threadId && (turnId === this.turnId || turnId === null);
2650
+ }
2651
+ };
2652
+ function isHookNotificationMethod(method) {
2653
+ return method === "hook/started" || method === "hook/completed";
2654
+ }
2655
+ //#endregion
2656
+ //#region extensions/codex/src/app-server/native-mcp-app.ts
2657
+ function asRecord(value) {
2658
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
2659
+ }
2660
+ function readString$4(value) {
2661
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
2662
+ }
2663
+ function readMcpAppResourceUri(item) {
2664
+ const uri = readString$4(asRecord(item.appContext)?.resourceUri) ?? readString$4(item.mcpAppResourceUri);
2665
+ return uri?.startsWith("ui://") ? uri : void 0;
2666
+ }
2667
+ function readMcpToolResult(item) {
2668
+ const result = asRecord(item.result);
2669
+ if (!result || !Array.isArray(result.content)) return;
2670
+ const resultMeta = asRecord(result["_meta"]);
2671
+ return {
2672
+ content: result.content,
2673
+ ...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {},
2674
+ ...result.isError === true ? { isError: true } : {},
2675
+ ...resultMeta ? { _meta: resultMeta } : {}
2676
+ };
2677
+ }
2678
+ function statusTools(status) {
2679
+ return Object.entries(status.tools).map(([name, value]) => Object.assign({}, asRecord(value), { name }));
2680
+ }
2681
+ function createNativeMcpRuntime(params) {
2682
+ let catalog = null;
2683
+ let statuses;
2684
+ const createdAt = Date.now();
2685
+ const loadStatuses = async () => {
2686
+ if (statuses) return statuses;
2687
+ statuses = (await params.client.request("mcpServerStatus/list", {
2688
+ threadId: params.threadId,
2689
+ detail: "full"
2690
+ })).data;
2691
+ return statuses;
2692
+ };
2693
+ const getCatalog = async () => {
2694
+ if (catalog) return catalog;
2695
+ const loaded = await loadStatuses();
2696
+ catalog = {
2697
+ version: 1,
2698
+ generatedAt: Date.now(),
2699
+ servers: Object.fromEntries(loaded.map((status) => [status.name, {
2700
+ serverName: status.name,
2701
+ launchSummary: "Codex native MCP connection",
2702
+ toolCount: Object.keys(status.tools).length
2703
+ }])),
2704
+ tools: loaded.flatMap((status) => statusTools(status).map((tool) => ({
2705
+ serverName: status.name,
2706
+ safeServerName: status.name,
2707
+ toolName: String(tool.name),
2708
+ inputSchema: asRecord(tool.inputSchema) ?? { type: "object" },
2709
+ fallbackDescription: readString$4(tool.description) ?? String(tool.name)
2710
+ })))
144
2711
  };
2712
+ return catalog;
145
2713
  };
146
- params.signal.addEventListener("abort", abortQueue, { once: true });
147
- if (params.signal.aborted) abortQueue();
148
- return {
149
- async queue(text, options) {
150
- const pendingUserInput = params.claimPendingUserInput();
151
- if (pendingUserInput) {
152
- if (!options?.images?.length) {
153
- pendingUserInput.answer(text);
154
- return;
155
- }
156
- flushBatch().catch(() => void 0);
157
- const { item, delivery } = createPendingMessage(text, options.images);
158
- await Promise.all([enqueueSend([item]).finally(() => pendingUserInput.cancel()), delivery]);
159
- return;
160
- }
161
- if (closedError) throw closedError;
162
- if (params.signal.aborted) throw new Error("codex app-server steering queue aborted");
163
- const { item, delivery } = createPendingMessage(text, options?.images);
164
- batchedMessages.push(item);
165
- clearBatchTimer();
166
- const debounceMs = normalizeCodexSteerDebounceMs(options?.debounceMs);
167
- if (debounceMs === 0) flushBatch();
168
- else batchTimer = setTimeout(() => {
169
- batchTimer = void 0;
170
- flushBatch();
171
- }, debounceMs);
172
- return await delivery;
2714
+ const runtime = {
2715
+ sessionId: params.attempt.sessionId,
2716
+ sessionKey: params.attempt.sessionKey,
2717
+ workspaceDir: params.attempt.workspaceDir,
2718
+ configFingerprint: `${getCodexAppServerClientInstanceId(params.client)}:${params.threadId}`,
2719
+ mcpAppsEnabled: true,
2720
+ createdAt,
2721
+ lastUsedAt: createdAt,
2722
+ acquireLease: () => retainSharedCodexAppServerClientIfCurrent(params.client) ?? (() => {}),
2723
+ getCatalog,
2724
+ peekCatalog: () => catalog,
2725
+ markUsed: () => {
2726
+ runtime.lastUsedAt = Date.now();
173
2727
  },
174
- async flushPending() {
175
- if (closedError) return;
176
- await flushBatch().catch(() => void 0);
2728
+ callTool: async (serverName, toolName, input) => await params.client.request("mcpServer/tool/call", {
2729
+ threadId: params.threadId,
2730
+ server: serverName,
2731
+ tool: toolName,
2732
+ arguments: asRecord(input) ?? {}
2733
+ }),
2734
+ listTools: async (serverName) => {
2735
+ const status = (await loadStatuses()).find((entry) => entry.name === serverName);
2736
+ return { tools: status ? statusTools(status) : [] };
177
2737
  },
178
- confirmConsumed(clientUserMessageId) {
179
- const batch = dispatchedBatches.get(clientUserMessageId);
180
- if (!batch) return false;
181
- dispatchedBatches.delete(clientUserMessageId);
182
- for (const item of batch.items) resolveItem(item);
183
- return true;
2738
+ readResource: async (serverName, uri) => await params.client.request("mcpServer/resource/read", {
2739
+ threadId: params.threadId,
2740
+ server: serverName,
2741
+ uri
2742
+ }),
2743
+ listResources: async (serverName) => {
2744
+ return { resources: (await loadStatuses()).find((entry) => entry.name === serverName)?.resources ?? [] };
184
2745
  },
185
- cancel: cancelQueue
2746
+ listResourceTemplates: async (serverName) => {
2747
+ return { resourceTemplates: (await loadStatuses()).find((entry) => entry.name === serverName)?.resourceTemplates ?? [] };
2748
+ },
2749
+ dispose: async () => {}
2750
+ };
2751
+ return runtime;
2752
+ }
2753
+ function createCodexNativeMcpAppResultDetailsPreparer(params) {
2754
+ if (params.attempt.config?.mcp?.apps?.enabled !== true) return;
2755
+ const runtime = createNativeMcpRuntime(params);
2756
+ return async (item) => {
2757
+ const serverName = readString$4(item.server);
2758
+ const toolName = readString$4(item.tool);
2759
+ const uiResourceUri = readMcpAppResourceUri(item);
2760
+ const toolResult = readMcpToolResult(item);
2761
+ if (!serverName || !toolName || !uiResourceUri || !toolResult) return;
2762
+ const allowedAppToolNames = new Set((await runtime.getCatalog()).tools.filter((tool) => tool.serverName === serverName).map((tool) => tool.toolName));
2763
+ if (allowedAppToolNames.size === 0) return;
2764
+ return await prepareHarnessNativeMcpAppPreview({
2765
+ runtime,
2766
+ serverName,
2767
+ toolName,
2768
+ uiResourceUri,
2769
+ toolCallId: item.id,
2770
+ toolInput: item.arguments ?? {},
2771
+ toolResult,
2772
+ allowedAppToolNames,
2773
+ ...toolResult["_meta"] !== void 0 ? { resultMetaState: "unavailable" } : {}
2774
+ });
186
2775
  };
187
2776
  }
188
- /** Normalizes steer debounce milliseconds, preserving explicit zero. */
189
- function normalizeCodexSteerDebounceMs(value) {
190
- return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : CODEX_STEER_ALL_DEBOUNCE_MS;
191
- }
192
2777
  //#endregion
193
2778
  //#region extensions/codex/src/app-server/user-input-bridge.ts
194
2779
  /** Bridges Codex request_user_input calls to gateway questions and secret text prompts. */
@@ -258,6 +2843,7 @@ function createCodexUserInputBridge(params) {
258
2843
  questions: requestParams.questions,
259
2844
  sessionKey: params.paramsForRun.sessionKey ?? params.paramsForRun.sessionId,
260
2845
  agentId: params.paramsForRun.agentId,
2846
+ runId: params.paramsForRun.runId,
261
2847
  timeoutMs: requestParams.autoResolutionMs ?? params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS,
262
2848
  gatewayCall,
263
2849
  delivery: params.paramsForRun,
@@ -267,7 +2853,7 @@ function createCodexUserInputBridge(params) {
267
2853
  },
268
2854
  signal: abort.signal
269
2855
  });
270
- return result.status === "answered" ? result.answers : emptyUserInputResponse();
2856
+ return result.status === "answered" ? gatewayAnswersToCodexResponse(result.answers.answers) : emptyUserInputResponse();
271
2857
  } catch (error) {
272
2858
  embeddedAgentLog.warn("failed to bridge codex user input through gateway", { error });
273
2859
  return emptyUserInputResponse();
@@ -350,6 +2936,9 @@ function readOption(value) {
350
2936
  function buildUserInputResponse(questions, inputText) {
351
2937
  return buildAgentHarnessUserInputAnswers(questions, inputText);
352
2938
  }
2939
+ function gatewayAnswersToCodexResponse(answers) {
2940
+ return { answers: Object.fromEntries(Object.entries(answers).map(([questionId, values]) => [questionId, { answers: values }])) };
2941
+ }
353
2942
  function emptyUserInputResponse() {
354
2943
  return emptyAgentHarnessUserInputAnswers();
355
2944
  }
@@ -374,6 +2963,11 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
374
2963
  const { emitExecutionPhaseOnce, emitLifecycleStart, maybeAnnounceFastModeAutoOff } = lifecycle;
375
2964
  const { enqueueNotification } = notifications;
376
2965
  const activeTurnId = turn.turn.id;
2966
+ const prepareNativeMcpAppResultDetails = createCodexNativeMcpAppResultDetailsPreparer({
2967
+ client: resourceState.client,
2968
+ threadId: resourceState.thread.threadId,
2969
+ attempt: dynamicToolParams
2970
+ });
377
2971
  const streamState = {
378
2972
  eventEmitted: false,
379
2973
  needsTerminalSnapshot: false
@@ -406,6 +3000,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
406
3000
  runAbortSignal: runAbortController.signal,
407
3001
  trajectoryRecorder,
408
3002
  onNativeToolResultRecorded: maybeAnnounceFastModeAutoOff,
3003
+ ...prepareNativeMcpAppResultDetails ? { prepareNativeMcpAppResultDetails } : {},
409
3004
  upstreamUserText: turnState.codexTurnPromptText,
410
3005
  onContextCompacted: () => {
411
3006
  computerContextEpoch.value += 1;
@@ -471,9 +3066,11 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
471
3066
  await activeSteeringQueue.queue(text, optionsLocal);
472
3067
  },
473
3068
  isStreaming: () => !state.completed && !runAbortController.signal.aborted,
3069
+ isAborted: () => runAbortController.signal.aborted,
474
3070
  isStopped: () => state.completed || state.timedOut || runAbortController.signal.aborted,
475
3071
  isAbortable: () => !terminalState.terminalOutcomeFrozen || terminalState.sharedAbortAllowedAfterTerminalOutcome,
476
3072
  isCompacting: () => projectorRef.current?.isCompacting() ?? false,
3073
+ supportsTranscriptCommitWait: true,
477
3074
  supportsQueueMessageImages: true,
478
3075
  sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
479
3076
  cancel: () => abortExplicitly("cancelled"),
@@ -536,7 +3133,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
536
3133
  async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRuntime, activeTurn) {
537
3134
  const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, releaseSharedClientLeaseAndRetireOneShotClient, releaseSandboxExecEnvironment } = resources;
538
3135
  const { connection } = prompt.context.runtime;
539
- const { params, options, runAbortController } = connection;
3136
+ const { params, options, runAbortController, terminalState, bindingStore, bindingIdentity } = connection;
540
3137
  const { state, steeringQueueRef, userInputBridgeRef, turnWatches } = turnRuntime;
541
3138
  const { maybeEmitFastModeAutoResetBestEffort, emitLifecycleTerminal, buildLifecycleTerminalMeta } = lifecycle;
542
3139
  const { codexModelCallDiagnostics } = requestRuntime;
@@ -566,10 +3163,17 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
566
3163
  cleanup: async () => trajectoryRecorder?.flush()
567
3164
  });
568
3165
  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
- });
3166
+ const retainLiveIncognitoThread = terminalState.turnSucceeded && isIncognitoSessionKey(params.sessionKey);
3167
+ const bindingReleased = isIncognitoSessionKey(params.sessionKey) && !retainLiveIncognitoThread ? await bindingStore.mutate(bindingIdentity, {
3168
+ kind: "clear",
3169
+ threadId: resourceState.thread.threadId
3170
+ }) : true;
3171
+ if (!state.timedOut && !retainLiveIncognitoThread) {
3172
+ if (bindingReleased) await unsubscribeCodexThreadBestEffort(resourceState.client, {
3173
+ threadId: resourceState.thread.threadId,
3174
+ timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
3175
+ });
3176
+ }
573
3177
  userInputBridgeRef.current?.cancelPending();
574
3178
  turnWatches.clearAllTimers();
575
3179
  releaseCurrentRoute();
@@ -603,7 +3207,8 @@ const codexWorkspaceDirCache = /* @__PURE__ */ new Set();
603
3207
  //#region extensions/codex/src/app-server/run-attempt-lifecycle.ts
604
3208
  const CODEX_APP_SERVER_PROJECTED_CHARS_PER_TOKEN = 4;
605
3209
  function shouldKeepCodexSharedAbortOpen(params) {
606
- if (params.explicitCancellationObserved || params.result.aborted || params.result.externalAbort) return false;
3210
+ const terminal = attemptTerminal.project(params.result.terminal);
3211
+ if (params.explicitCancellationObserved || terminal.aborted || terminal.externalAbort) return false;
607
3212
  return params.trigger === "memory" || !params.attemptSucceeded;
608
3213
  }
609
3214
  function withCodexAppServerFastModeServiceTier(appServer, params) {
@@ -830,19 +3435,11 @@ function readCodexAppServerRolloutTokenSnapshotLine(line) {
830
3435
  return;
831
3436
  }
832
3437
  }
833
- function toNonNegativeInt(value) {
834
- if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return;
835
- return Math.floor(value);
836
- }
837
3438
  function readCompactionConfig(config) {
838
3439
  return isJsonObject(config?.agents?.defaults?.compaction) ? config.agents.defaults.compaction : void 0;
839
3440
  }
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;
3441
+ function resolveCodexAppServerNativeThreadReserveTokens(_config) {
3442
+ return CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS;
846
3443
  }
847
3444
  function resolveCodexAppServerNativeThreadTokenFuse(params) {
848
3445
  const projectedTurnTokens = typeof params.projectedTurnTokens === "number" && Number.isFinite(params.projectedTurnTokens) && params.projectedTurnTokens > 0 ? Math.floor(params.projectedTurnTokens) : 0;
@@ -938,6 +3535,14 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
938
3535
  }
939
3536
  //#endregion
940
3537
  //#region extensions/codex/src/app-server/run-attempt-connection.ts
3538
+ function applyStoredBindingPermissions(params) {
3539
+ if (params.execPolicyTouched || params.binding?.connectionScope === "supervision") return params.appServer;
3540
+ return {
3541
+ ...params.appServer,
3542
+ approvalPolicy: params.binding?.approvalPolicy ?? params.appServer.approvalPolicy,
3543
+ sandbox: params.binding?.sandbox ?? params.appServer.sandbox
3544
+ };
3545
+ }
941
3546
  async function prepareCodexAttemptConnection({ params, options }) {
942
3547
  const attemptStartedAt = Date.now();
943
3548
  const profilerEnabled = isCodexAppServerProfilerEnabled(params.config);
@@ -954,7 +3559,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
954
3559
  const runtimeArtifactRequest = params.captureRuntimeArtifact || params.expectedRuntimeArtifact ? params.expectedRuntimeArtifact ? { expected: params.expectedRuntimeArtifact } : {} : void 0;
955
3560
  const pluginConfig = readCodexPluginConfig(options.pluginConfig);
956
3561
  const computerUseConfig = resolveCodexComputerUseConfig({ pluginConfig });
957
- const { sessionAgentId } = resolveSessionAgentIds$1({
3562
+ const { sessionAgentId } = resolveSessionAgentIds({
958
3563
  sessionKey: params.sessionKey,
959
3564
  config: params.config,
960
3565
  agentId: params.agentId
@@ -978,7 +3583,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
978
3583
  config: params.config,
979
3584
  agentId: sessionAgentId
980
3585
  });
981
- const agentDir = params.agentDir ?? resolveAgentDir(params.config ?? {}, sessionAgentId);
3586
+ const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId);
982
3587
  const bindingIdentity = sessionBindingIdentity({
983
3588
  sessionId: params.sessionId,
984
3589
  sessionKey: params.sessionKey,
@@ -995,23 +3600,27 @@ async function prepareCodexAttemptConnection({ params, options }) {
995
3600
  bindingStore,
996
3601
  identity: bindingIdentity,
997
3602
  config: params.config
998
- })) throw new Error(`Codex session generation is no longer current: ${bindingIdentity.sessionId}`);
3603
+ })) throw createCodexSessionGenerationSupersededError(bindingIdentity.sessionId);
999
3604
  startupBinding = await bindingStore.read(bindingIdentity);
1000
3605
  }
1001
3606
  preDynamicStartupStages.mark("read-binding");
1002
3607
  const usesSupervisionConnection = startupBinding?.connectionScope === "supervision";
1003
3608
  if (usesSupervisionConnection) activeContextEngine = void 0;
1004
3609
  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({
3610
+ const resolveRuntimeOptionsForBinding = (selection) => applyStoredBindingPermissions({
3611
+ appServer: resolveCodexBindingAppServerConnection({
3612
+ binding: startupBinding,
3613
+ pluginConfig,
3614
+ execPolicy,
3615
+ modelProvider: selection.modelProvider,
3616
+ model: selection.model,
3617
+ config: params.config,
3618
+ agentDir,
3619
+ openClawSandboxActive: sandbox?.enabled === true
3620
+ }).appServer,
1006
3621
  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;
3622
+ execPolicyTouched: execPolicy.touched
3623
+ });
1015
3624
  const initialStartupBindingHadInactiveThreadBootstrap = isInactiveThreadBootstrapBinding(startupBinding);
1016
3625
  const preparedAuthRoute = usesSupervisionConnection ? void 0 : params.runtimePlan?.auth.modelRoute;
1017
3626
  const startupAuthProfileCandidate = usesSupervisionConnection ? void 0 : preparedAuthRoute ? params.runtimePlan?.auth.forwardedAuthProfileId : params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId;
@@ -1034,6 +3643,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
1034
3643
  authProfileId: resolvedStartupAuthProfileId,
1035
3644
  authProfileStore: params.authProfileStore,
1036
3645
  agentDir,
3646
+ ...pluginConfig.appServer?.homeScope ? { homeScope: pluginConfig.appServer.homeScope } : {},
1037
3647
  config: params.config,
1038
3648
  subscriptionProfileRequiredError: "Prepared Codex subscription route requires a forwarded OpenAI OAuth or token profile.",
1039
3649
  subscriptionProfileUnusableError: "Prepared Codex subscription auth profile is unusable."
@@ -1087,6 +3697,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
1087
3697
  preDynamicStartupStages.mark("app-server-policy");
1088
3698
  preDynamicStartupStages.mark("native-hook-relay");
1089
3699
  const terminalState = {
3700
+ turnSucceeded: false,
1090
3701
  explicitCancellationObserved: false,
1091
3702
  explicitCancellationReason: void 0,
1092
3703
  terminalOutcomeFrozen: false,
@@ -1148,16 +3759,20 @@ async function prepareCodexAttemptConnection({ params, options }) {
1148
3759
  startupBinding,
1149
3760
  pluginAppServer: appServer
1150
3761
  };
1151
- const resolveRuntimeOptionsForCurrentBinding = (selection) => resolveCodexBindingAppServerConnection({
3762
+ const resolveRuntimeOptionsForCurrentBinding = (selection) => applyStoredBindingPermissions({
3763
+ appServer: resolveCodexBindingAppServerConnection({
3764
+ binding: mutable.startupBinding,
3765
+ pluginConfig,
3766
+ execPolicy,
3767
+ modelProvider: selection.modelProvider,
3768
+ model: selection.model,
3769
+ config: params.config,
3770
+ agentDir,
3771
+ openClawSandboxActive: sandbox?.enabled === true
3772
+ }).appServer,
1152
3773
  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;
3774
+ execPolicyTouched: execPolicy.touched
3775
+ });
1161
3776
  return {
1162
3777
  params,
1163
3778
  options,
@@ -1210,24 +3825,20 @@ async function prepareCodexAttemptConnection({ params, options }) {
1210
3825
  * system-prompt reports, and context-engine projection decisions.
1211
3826
  */
1212
3827
  const CODEX_NATIVE_PROJECT_DOC_BASENAMES = /* @__PURE__ */ new Set(["agents.md"]);
1213
- const CODEX_INHERITED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = /* @__PURE__ */ new Set(["tools.md"]);
1214
3828
  const CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = /* @__PURE__ */ new Set([
1215
3829
  "identity.md",
1216
3830
  "soul.md",
1217
3831
  "user.md"
1218
3832
  ]);
1219
- 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";
3833
+ const CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = new Set(CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES);
1221
3834
  const CODEX_MEMORY_CONTEXT_BASENAME = "memory.md";
1222
3835
  const CODEX_MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set(["memory_search", "memory_get"]);
1223
3836
  const CODEX_BOOTSTRAP_CONTEXT_ORDER = /* @__PURE__ */ new Map([
1224
3837
  ["soul.md", 10],
1225
3838
  ["identity.md", 20],
1226
3839
  ["user.md", 30],
1227
- ["tools.md", 40],
1228
3840
  ["bootstrap.md", 50],
1229
- ["memory.md", 60],
1230
- ["heartbeat.md", 70]
3841
+ ["memory.md", 60]
1231
3842
  ]);
1232
3843
  /** Reads mirrored Codex session history for harness hooks. */
1233
3844
  async function readMirroredSessionHistoryMessages(params) {
@@ -1326,22 +3937,17 @@ async function buildCodexWorkspaceBootstrapContext(params) {
1326
3937
  excludeMemory: memoryToolsAvailable,
1327
3938
  memoryWorkspaceDir: params.effectiveWorkspace
1328
3939
  });
1329
- const developerInstructionFiles = shouldInjectCodexOpenClawPromptContext(params.params) ? selectCodexWorkspaceInheritedDeveloperInstructionFiles(contextFiles) : [];
1330
3940
  const turnScopedDeveloperInstructionFiles = shouldInjectCodexOpenClawPromptContext(params.params) ? selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) : [];
1331
- const heartbeatReferenceFiles = selectCodexWorkspaceHeartbeatReferenceFiles(contextFiles);
1332
3941
  return {
1333
3942
  bootstrapFiles,
1334
3943
  contextFiles,
1335
3944
  promptContextFiles,
1336
- developerInstructionFiles,
1337
3945
  turnScopedDeveloperInstructionFiles,
1338
- heartbeatReferenceFiles,
1339
3946
  memoryReferenceFiles,
1340
3947
  memoryToolRoutedBootstrapFiles,
1341
3948
  memoryToolNames: [...params.memoryToolNames],
1342
3949
  memoryToolRouted: memoryToolsAvailable,
1343
3950
  promptContext: renderCodexWorkspaceBootstrapPromptContext(promptContextFiles),
1344
- developerInstructions: renderCodexWorkspaceThreadDeveloperInstructions(developerInstructionFiles),
1345
3951
  turnScopedDeveloperInstructions: renderCodexWorkspaceCollaborationDeveloperInstructions(turnScopedDeveloperInstructionFiles),
1346
3952
  memoryCollaborationInstructions: shouldInjectCodexOpenClawPromptContext(params.params) ? await renderCodexWorkspaceMemoryCollaborationInstructions({
1347
3953
  files: memoryReferenceFiles,
@@ -1351,8 +3957,7 @@ async function buildCodexWorkspaceBootstrapContext(params) {
1351
3957
  agentId: params.params.agentId ?? params.sessionAgentId,
1352
3958
  agentSessionKey: params.sessionKey,
1353
3959
  sandboxed: params.sandboxed
1354
- }) : void 0,
1355
- heartbeatCollaborationInstructions: renderCodexWorkspaceHeartbeatReference(heartbeatReferenceFiles)
3960
+ }) : void 0
1356
3961
  };
1357
3962
  } catch (error) {
1358
3963
  embeddedAgentLog.warn("failed to load codex workspace bootstrap instructions", { error });
@@ -1391,7 +3996,7 @@ function buildCodexSystemPromptReport(params) {
1391
3996
  injectedWorkspaceFiles: buildCodexBootstrapInjectionStats({
1392
3997
  bootstrapFiles: params.workspaceBootstrapContext.bootstrapFiles,
1393
3998
  injectedFiles: params.workspaceBootstrapContext.promptContextFiles ?? [],
1394
- developerInstructionFiles: [...params.workspaceBootstrapContext.developerInstructionFiles ?? [], ...params.workspaceBootstrapContext.turnScopedDeveloperInstructionFiles ?? []],
3999
+ developerInstructionFiles: params.workspaceBootstrapContext.turnScopedDeveloperInstructionFiles ?? [],
1395
4000
  memoryToolRoutedBootstrapFiles: params.workspaceBootstrapContext.memoryToolRoutedBootstrapFiles ?? [],
1396
4001
  memoryToolRouted: params.workspaceBootstrapContext.memoryToolRouted === true
1397
4002
  }),
@@ -1474,14 +4079,9 @@ function buildCodexBootstrapInjectionStats(params) {
1474
4079
  const injected = memoryToolRoutedFile ? void 0 : readCodexIndexedContextFileContent(injectedIndex, pathValue, fileName) ?? readCodexIndexedContextFileContent(developerInstructionIndex, pathValue, fileName);
1475
4080
  let injectedChars = memoryToolRoutedFile ? 0 : injected?.length ?? 0;
1476
4081
  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
- }
4082
+ if (injected === void 0 && CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName)) {
4083
+ injectedChars = rawChars;
4084
+ truncated = false;
1485
4085
  }
1486
4086
  return {
1487
4087
  name: displayName,
@@ -1605,7 +4205,7 @@ function renderCodexWorkspaceBootstrapPromptContext(contextFiles) {
1605
4205
  const files = contextFiles;
1606
4206
  if (files.length === 0) return;
1607
4207
  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.",
4208
+ "OpenClaw loaded these user-editable workspace files for the current turn. Codex loads AGENTS.md natively. SOUL.md, IDENTITY.md, and USER.md are provided as turn-scoped collaboration instructions so native Codex subagents do not inherit them. Those files are not repeated here.",
1609
4209
  "",
1610
4210
  "# Project Context",
1611
4211
  "",
@@ -1619,15 +4219,12 @@ function selectCodexWorkspacePromptContextFiles(contextFiles, options = {}) {
1619
4219
  const excludeMemory = options.excludeMemory ?? true;
1620
4220
  return contextFiles.filter((file) => {
1621
4221
  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({
4222
+ return baseName && !CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName) && !CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES.has(baseName) && (!excludeMemory || !isCodexWorkspaceRootMemoryContextFile({
1623
4223
  file,
1624
4224
  workspaceDir: options.memoryWorkspaceDir
1625
4225
  })) && !isMissingCodexBootstrapContextFile(file);
1626
4226
  }).toSorted(compareCodexContextFiles);
1627
4227
  }
1628
- function selectCodexWorkspaceInheritedDeveloperInstructionFiles(contextFiles) {
1629
- return selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, CODEX_INHERITED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES);
1630
- }
1631
4228
  function selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) {
1632
4229
  return selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES);
1633
4230
  }
@@ -1637,13 +4234,6 @@ function selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, basenames)
1637
4234
  return baseName && basenames.has(baseName) && !isMissingCodexBootstrapContextFile(file) && file.content.trim().length > 0;
1638
4235
  }).toSorted(compareCodexContextFiles);
1639
4236
  }
1640
- function renderCodexWorkspaceThreadDeveloperInstructions(files) {
1641
- return renderCodexWorkspaceDeveloperInstructions({
1642
- files,
1643
- header: "## OpenClaw Workspace Instructions",
1644
- preamble: "OpenClaw loaded these workspace instruction files from the active agent workspace. Internalize and follow them accordingly."
1645
- });
1646
- }
1647
4237
  function renderCodexWorkspaceCollaborationDeveloperInstructions(files) {
1648
4238
  return renderCodexWorkspaceDeveloperInstructions({
1649
4239
  files,
@@ -1666,22 +4256,6 @@ function renderCodexWorkspaceDeveloperInstructions(params) {
1666
4256
  if (wrapperTag) lines.push(`</${wrapperTag}>`);
1667
4257
  return lines.join("\n").trim();
1668
4258
  }
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
4259
  function selectCodexWorkspaceMemoryReferenceFiles(params) {
1686
4260
  return params.bootstrapFiles.filter((file) => {
1687
4261
  return isCodexWorkspaceRootMemoryBootstrapFile({
@@ -1771,151 +4345,50 @@ function isCodexWorkspaceRootMemoryPath(params) {
1771
4345
  return (path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(params.workspaceDir, filePath)) === path.join(path.resolve(params.workspaceDir), "MEMORY.md");
1772
4346
  }
1773
4347
  function isSameCodexWorkspacePath(left, right) {
1774
- return path.resolve(left) === path.resolve(right);
1775
- }
1776
- /**
1777
- * Remaps bootstrap file paths from the resolved workspace to the effective Codex
1778
- * workspace while preserving platform path separators.
1779
- */
1780
- function remapCodexContextFilePath(params) {
1781
- const relativePath = path.relative(params.sourceWorkspaceDir, params.file.path);
1782
- if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath) || params.sourceWorkspaceDir === params.targetWorkspaceDir) return params.file;
1783
- const targetUsesPosixSeparators = params.targetWorkspaceDir.includes("/") && !params.targetWorkspaceDir.includes("\\");
1784
- const normalizedRelativePath = targetUsesPosixSeparators ? relativePath.replaceAll("\\", "/") : relativePath.replaceAll("/", "\\");
1785
- return {
1786
- ...params.file,
1787
- path: targetUsesPosixSeparators ? path.posix.join(params.targetWorkspaceDir, normalizedRelativePath) : path.win32.join(params.targetWorkspaceDir, normalizedRelativePath)
1788
- };
1789
- }
1790
- function compareCodexContextFiles(left, right) {
1791
- const leftPath = normalizeCodexContextFilePath(left.path);
1792
- const rightPath = normalizeCodexContextFilePath(right.path);
1793
- const leftBase = getCodexContextFileBasename(left.path);
1794
- const rightBase = getCodexContextFileBasename(right.path);
1795
- const leftOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(leftBase) ?? Number.MAX_SAFE_INTEGER;
1796
- const rightOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(rightBase) ?? Number.MAX_SAFE_INTEGER;
1797
- if (leftOrder !== rightOrder) return leftOrder - rightOrder;
1798
- if (leftBase !== rightBase) return leftBase.localeCompare(rightBase);
1799
- return leftPath.localeCompare(rightPath);
1800
- }
1801
- function compareCodexBootstrapFiles(left, right) {
1802
- return compareCodexContextFiles(toCodexEmbeddedContextFile(left), toCodexEmbeddedContextFile(right));
1803
- }
1804
- function normalizeCodexContextFilePath(filePath) {
1805
- return filePath.trim().replaceAll("\\", "/").toLowerCase();
1806
- }
1807
- function getCodexContextFileDisplayBasename(filePath) {
1808
- return filePath.trim().replaceAll("\\", "/").split("/").pop()?.trim() ?? "";
1809
- }
1810
- function getCodexContextFileBasename(filePath) {
1811
- return normalizeCodexContextFilePath(filePath).split("/").pop() ?? "";
1812
- }
1813
- function normalizeCodexDynamicToolName(name) {
1814
- return name.trim().toLowerCase();
1815
- }
1816
- function isNonEmptyString$1(value) {
1817
- return typeof value === "string" && value.length > 0;
1818
- }
1819
- //#endregion
1820
- //#region extensions/codex/src/app-server/run-attempt-state.ts
1821
- async function clearCodexBindingAfterInvalidImagePayload(bindingStore, identity, fields) {
1822
- const currentBinding = await bindingStore.read(identity);
1823
- const expectedThreadId = fields.threadId ?? currentBinding?.threadId;
1824
- if (!expectedThreadId) return;
1825
- if (currentBinding && currentBinding.threadId !== expectedThreadId) {
1826
- embeddedAgentLog.warn("codex app-server image payload error detected for unbound thread; preserving thread binding", {
1827
- ...fields,
1828
- boundThreadId: currentBinding.threadId
1829
- });
1830
- return;
1831
- }
1832
- if (currentBinding?.connectionScope === "supervision") {
1833
- embeddedAgentLog.warn("codex app-server image payload error detected for supervised thread; preserving native binding", fields);
1834
- return;
1835
- }
1836
- embeddedAgentLog.warn("codex app-server image payload error detected; clearing thread binding", fields);
1837
- await bindingStore.mutate(identity, {
1838
- kind: "clear",
1839
- threadId: expectedThreadId
1840
- });
1841
- }
1842
- async function markCodexAppServerBindingCoveredThroughTurn(params) {
1843
- await params.bindingStore.mutate(params.identity, {
1844
- kind: "patch",
1845
- threadId: params.threadId,
1846
- patch: { historyCoveredThrough: (/* @__PURE__ */ new Date()).toISOString() }
1847
- });
1848
- }
1849
- function isNonEmptyString(value) {
1850
- return typeof value === "string" && value.length > 0;
1851
- }
1852
- function shouldUseFreshCodexThreadAfterContextEngineOverflow(params) {
1853
- if (!params.contextEngineActive || params.thread.lifecycle.action !== "resumed") return false;
1854
- const message = formatErrorMessage(params.error);
1855
- return /ran out of room in the model'?s context window/iu.test(message) || /context window/iu.test(message) || /context length/iu.test(message) || /maximum context/iu.test(message) || /too many tokens/iu.test(message);
1856
- }
1857
- function isCodexActiveCompactTurnError(error) {
1858
- if (!(error instanceof CodexAppServerRpcError)) return false;
1859
- const data = isJsonObject(error.data) ? error.data : void 0;
1860
- const codexErrorInfo = isJsonObject(data?.codexErrorInfo) ? data.codexErrorInfo : void 0;
1861
- return (isJsonObject(codexErrorInfo?.activeTurnNotSteerable) ? codexErrorInfo.activeTurnNotSteerable : void 0)?.turnKind === "compact";
4348
+ return path.resolve(left) === path.resolve(right);
1862
4349
  }
1863
- function readCodexFinalizationHookNotification(notification, threadId, turnId) {
1864
- if (notification.method !== "hook/started" && notification.method !== "hook/completed") return;
1865
- const params = isJsonObject(notification.params) ? notification.params : void 0;
1866
- const run = params && isJsonObject(params.run) ? params.run : void 0;
1867
- if (params?.threadId !== threadId || params.turnId !== turnId || run?.eventName !== "stop" && run?.eventName !== "subagentStop" || typeof run.id !== "string" || !run.id) return;
1868
- if (notification.method === "hook/started") return {
1869
- phase: "started",
1870
- runId: run.id
1871
- };
4350
+ /**
4351
+ * Remaps bootstrap file paths from the resolved workspace to the effective Codex
4352
+ * workspace while preserving platform path separators.
4353
+ */
4354
+ function remapCodexContextFilePath(params) {
4355
+ const relativePath = path.relative(params.sourceWorkspaceDir, params.file.path);
4356
+ if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath) || params.sourceWorkspaceDir === params.targetWorkspaceDir) return params.file;
4357
+ const targetUsesPosixSeparators = params.targetWorkspaceDir.includes("/") && !params.targetWorkspaceDir.includes("\\");
4358
+ const normalizedRelativePath = targetUsesPosixSeparators ? relativePath.replaceAll("\\", "/") : relativePath.replaceAll("/", "\\");
1872
4359
  return {
1873
- phase: "completed",
1874
- runId: run.id,
1875
- status: typeof run.status === "string" ? run.status : void 0
4360
+ ...params.file,
4361
+ path: targetUsesPosixSeparators ? path.posix.join(params.targetWorkspaceDir, normalizedRelativePath) : path.win32.join(params.targetWorkspaceDir, normalizedRelativePath)
1876
4362
  };
1877
4363
  }
1878
- function joinPresentSections(...sections) {
1879
- return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
4364
+ function compareCodexContextFiles(left, right) {
4365
+ const leftPath = normalizeCodexContextFilePath(left.path);
4366
+ const rightPath = normalizeCodexContextFilePath(right.path);
4367
+ const leftBase = getCodexContextFileBasename(left.path);
4368
+ const rightBase = getCodexContextFileBasename(right.path);
4369
+ const leftOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(leftBase) ?? Number.MAX_SAFE_INTEGER;
4370
+ const rightOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(rightBase) ?? Number.MAX_SAFE_INTEGER;
4371
+ if (leftOrder !== rightOrder) return leftOrder - rightOrder;
4372
+ if (leftBase !== rightBase) return leftBase.localeCompare(rightBase);
4373
+ return leftPath.localeCompare(rightPath);
1880
4374
  }
1881
- function prependCurrentInboundContext(prompt, context) {
1882
- const text = context?.text.trim();
1883
- return text ? [text, prompt].filter(Boolean).join("\n\n") : prompt;
4375
+ function compareCodexBootstrapFiles(left, right) {
4376
+ return compareCodexContextFiles(toCodexEmbeddedContextFile(left), toCodexEmbeddedContextFile(right));
1884
4377
  }
1885
- function waitForCodexNotificationDispatchTurn() {
1886
- return new Promise((resolve) => {
1887
- setImmediate(resolve);
1888
- });
4378
+ function normalizeCodexContextFilePath(filePath) {
4379
+ return filePath.trim().replaceAll("\\", "/").toLowerCase();
1889
4380
  }
1890
- function buildCodexAppServerTimeoutDiagnostics(params) {
1891
- const readString = (key) => {
1892
- const value = params.details?.[key];
1893
- return typeof value === "string" && value.trim() ? value : void 0;
1894
- };
1895
- const readNumber = (key) => {
1896
- const value = params.details?.[key];
1897
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1898
- };
1899
- const readBoolean = (key) => {
1900
- const value = params.details?.[key];
1901
- return typeof value === "boolean" ? value : void 0;
1902
- };
1903
- return {
1904
- ...params.idleMs !== void 0 ? { idleMs: params.idleMs } : {},
1905
- ...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
1906
- ...params.lastActivityReason ? { lastActivityReason: params.lastActivityReason } : {},
1907
- ...readString("lastNotificationMethod") ? { lastNotificationMethod: readString("lastNotificationMethod") } : {},
1908
- ...readString("lastNotificationItemId") ? { lastNotificationItemId: readString("lastNotificationItemId") } : {},
1909
- ...readString("lastNotificationItemType") ? { lastNotificationItemType: readString("lastNotificationItemType") } : {},
1910
- ...readString("lastNotificationItemRole") ? { lastNotificationItemRole: readString("lastNotificationItemRole") } : {},
1911
- ...readString("lastAssistantTextPreview") ? { lastAssistantTextPreview: readString("lastAssistantTextPreview") } : {},
1912
- ...readNumber("activeAppServerTurnRequests") !== void 0 ? { activeAppServerTurnRequests: readNumber("activeAppServerTurnRequests") } : {},
1913
- ...readNumber("activeTurnItemCount") !== void 0 ? { activeTurnItemCount: readNumber("activeTurnItemCount") } : {},
1914
- ...readBoolean("terminalTurnNotificationQueued") !== void 0 ? { terminalTurnNotificationQueued: readBoolean("terminalTurnNotificationQueued") } : {},
1915
- ...readBoolean("completionIdleWatchArmed") !== void 0 ? { completionIdleWatchArmed: readBoolean("completionIdleWatchArmed") } : {},
1916
- ...readBoolean("assistantCompletionIdleWatchArmed") !== void 0 ? { assistantCompletionIdleWatchArmed: readBoolean("assistantCompletionIdleWatchArmed") } : {},
1917
- ...readBoolean("terminalIdleWatchArmed") !== void 0 ? { terminalIdleWatchArmed: readBoolean("terminalIdleWatchArmed") } : {}
1918
- };
4381
+ function getCodexContextFileDisplayBasename(filePath) {
4382
+ return filePath.trim().replaceAll("\\", "/").split("/").pop()?.trim() ?? "";
4383
+ }
4384
+ function getCodexContextFileBasename(filePath) {
4385
+ return normalizeCodexContextFilePath(filePath).split("/").pop() ?? "";
4386
+ }
4387
+ function normalizeCodexDynamicToolName(name) {
4388
+ return name.trim().toLowerCase();
4389
+ }
4390
+ function isNonEmptyString$1(value) {
4391
+ return typeof value === "string" && value.length > 0;
1919
4392
  }
1920
4393
  //#endregion
1921
4394
  //#region extensions/codex/src/app-server/run-attempt-context.ts
@@ -1988,7 +4461,7 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
1988
4461
  memoryToolNames: getCodexWorkspaceMemoryToolNames(toolBridge.availableSpecs),
1989
4462
  sandboxed: sandbox?.enabled === true
1990
4463
  });
1991
- const baseDeveloperInstructions = joinPresentSections(buildDeveloperInstructions(runtimeParams, { dynamicTools: toolBridge.availableSpecs }), workspaceBootstrapContext.developerInstructions);
4464
+ const baseDeveloperInstructions = buildDeveloperInstructions(runtimeParams, { dynamicTools: toolBridge.availableSpecs });
1992
4465
  return {
1993
4466
  runtime,
1994
4467
  attemptTools,
@@ -2020,7 +4493,7 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
2020
4493
  },
2021
4494
  codexContextProjectionMaxChars: resolveCodexContextEngineProjectionMaxChars({
2022
4495
  contextTokenBudget: effectiveContextTokenBudget,
2023
- reserveTokens: resolveCodexContextEngineProjectionReserveTokens({ config: params.config })
4496
+ reserveTokens: resolveCodexContextEngineProjectionReserveTokens()
2024
4497
  })
2025
4498
  };
2026
4499
  }
@@ -2196,14 +4669,10 @@ function resolveCodexAppServerReplayBlockedReason(result) {
2196
4669
  /** Builds an attempt result for failures before the app-server turn starts. */
2197
4670
  function buildCodexTurnStartFailureResult(params) {
2198
4671
  return {
2199
- aborted: false,
2200
- externalAbort: false,
2201
- timedOut: false,
2202
- idleTimedOut: false,
2203
- timedOutDuringCompaction: false,
2204
- timedOutDuringToolExecution: false,
2205
- promptError: params.promptError ?? params.message,
2206
- promptErrorSource: "prompt",
4672
+ terminal: attemptTerminal.normalize({
4673
+ promptError: params.promptError ?? params.message,
4674
+ promptErrorSource: "prompt"
4675
+ }),
2207
4676
  sessionIdUsed: params.params.sessionId,
2208
4677
  messagesSnapshot: params.messagesSnapshot,
2209
4678
  assistantTexts: [],
@@ -2235,6 +4704,168 @@ function isInvalidCodexImagePayloadError(message) {
2235
4704
  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
4705
  }
2237
4706
  //#endregion
4707
+ //#region extensions/codex/src/app-server/run-attempt-state.ts
4708
+ async function clearCodexBindingAfterInvalidImagePayload(bindingStore, identity, fields) {
4709
+ const currentBinding = await bindingStore.read(identity);
4710
+ const expectedThreadId = fields.threadId ?? currentBinding?.threadId;
4711
+ if (!expectedThreadId) return;
4712
+ if (currentBinding && currentBinding.threadId !== expectedThreadId) {
4713
+ embeddedAgentLog.warn("codex app-server image payload error detected for unbound thread; preserving thread binding", {
4714
+ ...fields,
4715
+ boundThreadId: currentBinding.threadId
4716
+ });
4717
+ return;
4718
+ }
4719
+ if (currentBinding?.connectionScope === "supervision") {
4720
+ embeddedAgentLog.warn("codex app-server image payload error detected for supervised thread; preserving native binding", fields);
4721
+ return;
4722
+ }
4723
+ embeddedAgentLog.warn("codex app-server image payload error detected; clearing thread binding", fields);
4724
+ await bindingStore.mutate(identity, {
4725
+ kind: "clear",
4726
+ threadId: expectedThreadId
4727
+ });
4728
+ }
4729
+ async function markCodexAppServerBindingCoveredThroughTurn(params) {
4730
+ await params.bindingStore.mutate(params.identity, {
4731
+ kind: "patch",
4732
+ threadId: params.threadId,
4733
+ patch: { historyCoveredThrough: (/* @__PURE__ */ new Date()).toISOString() }
4734
+ });
4735
+ }
4736
+ function isNonEmptyString(value) {
4737
+ return typeof value === "string" && value.length > 0;
4738
+ }
4739
+ function shouldUseFreshCodexThreadAfterContextEngineOverflow(params) {
4740
+ if (!params.contextEngineActive || params.thread.lifecycle.action !== "resumed") return false;
4741
+ const message = formatErrorMessage(params.error);
4742
+ return /ran out of room in the model'?s context window/iu.test(message) || /context window/iu.test(message) || /context length/iu.test(message) || /maximum context/iu.test(message) || /too many tokens/iu.test(message);
4743
+ }
4744
+ function isCodexActiveCompactTurnError(error) {
4745
+ if (!(error instanceof CodexAppServerRpcError)) return false;
4746
+ const data = isJsonObject(error.data) ? error.data : void 0;
4747
+ const codexErrorInfo = isJsonObject(data?.codexErrorInfo) ? data.codexErrorInfo : void 0;
4748
+ return (isJsonObject(codexErrorInfo?.activeTurnNotSteerable) ? codexErrorInfo.activeTurnNotSteerable : void 0)?.turnKind === "compact";
4749
+ }
4750
+ function readCodexFinalizationHookNotification(notification, threadId, turnId) {
4751
+ if (notification.method !== "hook/started" && notification.method !== "hook/completed") return;
4752
+ const params = isJsonObject(notification.params) ? notification.params : void 0;
4753
+ const run = params && isJsonObject(params.run) ? params.run : void 0;
4754
+ if (params?.threadId !== threadId || params.turnId !== turnId || run?.eventName !== "stop" && run?.eventName !== "subagentStop" || typeof run.id !== "string" || !run.id) return;
4755
+ if (notification.method === "hook/started") return {
4756
+ phase: "started",
4757
+ runId: run.id
4758
+ };
4759
+ return {
4760
+ phase: "completed",
4761
+ runId: run.id,
4762
+ status: typeof run.status === "string" ? run.status : void 0
4763
+ };
4764
+ }
4765
+ function joinPresentSections(...sections) {
4766
+ return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
4767
+ }
4768
+ function prependCurrentInboundContext(prompt, context) {
4769
+ const text = context?.text.trim();
4770
+ return text ? [text, prompt].filter(Boolean).join("\n\n") : prompt;
4771
+ }
4772
+ function waitForCodexNotificationDispatchTurn() {
4773
+ return new Promise((resolve) => {
4774
+ setImmediate(resolve);
4775
+ });
4776
+ }
4777
+ function buildCodexAppServerTimeoutDiagnostics(params) {
4778
+ const readString = (key) => {
4779
+ const value = params.details?.[key];
4780
+ return typeof value === "string" && value.trim() ? value : void 0;
4781
+ };
4782
+ const readNumber = (key) => {
4783
+ const value = params.details?.[key];
4784
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
4785
+ };
4786
+ const readBoolean = (key) => {
4787
+ const value = params.details?.[key];
4788
+ return typeof value === "boolean" ? value : void 0;
4789
+ };
4790
+ return {
4791
+ ...params.idleMs !== void 0 ? { idleMs: params.idleMs } : {},
4792
+ ...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
4793
+ ...params.lastActivityReason ? { lastActivityReason: params.lastActivityReason } : {},
4794
+ ...readString("lastNotificationMethod") ? { lastNotificationMethod: readString("lastNotificationMethod") } : {},
4795
+ ...readString("lastNotificationItemId") ? { lastNotificationItemId: readString("lastNotificationItemId") } : {},
4796
+ ...readString("lastNotificationItemType") ? { lastNotificationItemType: readString("lastNotificationItemType") } : {},
4797
+ ...readString("lastNotificationItemRole") ? { lastNotificationItemRole: readString("lastNotificationItemRole") } : {},
4798
+ ...readString("lastAssistantTextPreview") ? { lastAssistantTextPreview: readString("lastAssistantTextPreview") } : {},
4799
+ ...readNumber("activeAppServerTurnRequests") !== void 0 ? { activeAppServerTurnRequests: readNumber("activeAppServerTurnRequests") } : {},
4800
+ ...readNumber("activeTurnItemCount") !== void 0 ? { activeTurnItemCount: readNumber("activeTurnItemCount") } : {},
4801
+ ...readBoolean("terminalTurnNotificationQueued") !== void 0 ? { terminalTurnNotificationQueued: readBoolean("terminalTurnNotificationQueued") } : {},
4802
+ ...readBoolean("completionIdleWatchArmed") !== void 0 ? { completionIdleWatchArmed: readBoolean("completionIdleWatchArmed") } : {},
4803
+ ...readBoolean("assistantCompletionIdleWatchArmed") !== void 0 ? { assistantCompletionIdleWatchArmed: readBoolean("assistantCompletionIdleWatchArmed") } : {},
4804
+ ...readBoolean("terminalIdleWatchArmed") !== void 0 ? { terminalIdleWatchArmed: readBoolean("terminalIdleWatchArmed") } : {}
4805
+ };
4806
+ }
4807
+ //#endregion
4808
+ //#region extensions/codex/src/app-server/settled-turn-context.ts
4809
+ function collectUniqueMessageIdentities(messages) {
4810
+ const identities = /* @__PURE__ */ new Map();
4811
+ for (const [index, message] of messages.entries()) {
4812
+ const identity = readMirrorIdentity(message);
4813
+ if (!identity) continue;
4814
+ if (identities.has(identity)) return;
4815
+ identities.set(identity, index);
4816
+ }
4817
+ return identities;
4818
+ }
4819
+ /** Freezes one complete active transcript branch through the settled tool-result boundary. */
4820
+ function buildCodexSettledTurnFinalizationContext(params) {
4821
+ const boundaryMessage = params.settledMessages.findLast((message) => message.role === "toolResult");
4822
+ const boundaryIdentity = boundaryMessage ? readMirrorIdentity(boundaryMessage) : void 0;
4823
+ if (!boundaryMessage || !boundaryIdentity || !boundaryIdentity.startsWith(`${params.turnId}:tool:`)) return;
4824
+ const settledBoundaryIndex = params.settledMessages.indexOf(boundaryMessage);
4825
+ const requiredIdentities = params.settledMessages.slice(0, settledBoundaryIndex + 1).map(readMirrorIdentity);
4826
+ if (requiredIdentities.length === 0 || requiredIdentities.some((identity) => !identity) || new Set(requiredIdentities).size !== requiredIdentities.length || !requiredIdentities.includes(`${params.turnId}:prompt`)) return;
4827
+ const historyIdentities = collectUniqueMessageIdentities(params.historyMessages);
4828
+ const mirroredIdentities = collectUniqueMessageIdentities(params.mirroredMessages);
4829
+ if (!historyIdentities || !mirroredIdentities) return;
4830
+ const mirroredBoundaryIndex = mirroredIdentities.get(boundaryIdentity);
4831
+ if (mirroredBoundaryIndex === void 0) return;
4832
+ const mirroredThroughBoundary = params.mirroredMessages.slice(0, mirroredBoundaryIndex + 1);
4833
+ if (mirroredThroughBoundary.length !== requiredIdentities.length || mirroredThroughBoundary.some((message, index) => readMirrorIdentity(message) !== requiredIdentities[index])) return;
4834
+ const historyBoundaryIndex = historyIdentities.get(boundaryIdentity);
4835
+ if (historyBoundaryIndex === void 0) return;
4836
+ let previousHistoryIndex = -1;
4837
+ for (const mirroredMessage of mirroredThroughBoundary) {
4838
+ const identity = readMirrorIdentity(mirroredMessage);
4839
+ const historyIndex = identity ? historyIdentities.get(identity) : void 0;
4840
+ const historyMessage = historyIndex === void 0 ? void 0 : params.historyMessages[historyIndex];
4841
+ if (historyIndex === void 0 || historyIndex <= previousHistoryIndex || historyIndex > historyBoundaryIndex || !historyMessage || serializeCodexMirrorSourceEvidence(historyMessage) !== serializeCodexMirrorSourceEvidence(mirroredMessage)) return;
4842
+ previousHistoryIndex = historyIndex;
4843
+ }
4844
+ return {
4845
+ source: "openclaw-transcript",
4846
+ messages: Object.freeze(structuredClone(params.historyMessages.slice(0, historyBoundaryIndex + 1)))
4847
+ };
4848
+ }
4849
+ /** Reads and freezes the current active transcript branch after mirroring has settled. */
4850
+ async function captureCodexSettledTurnFinalizationContext(params) {
4851
+ try {
4852
+ const historyMessages = await readCodexMirroredSessionHistoryMessages(params);
4853
+ if (!historyMessages) return;
4854
+ return buildCodexSettledTurnFinalizationContext({
4855
+ historyMessages,
4856
+ mirroredMessages: params.mirroredMessages,
4857
+ settledMessages: params.settledMessages,
4858
+ turnId: params.turnId
4859
+ });
4860
+ } catch (error) {
4861
+ embeddedAgentLog.warn("codex settled-turn finalization context capture failed", {
4862
+ error: formatErrorMessage(error),
4863
+ turnId: params.turnId
4864
+ });
4865
+ return;
4866
+ }
4867
+ }
4868
+ //#endregion
2238
4869
  //#region extensions/codex/src/app-server/trajectory.ts
2239
4870
  const SENSITIVE_FIELD_RE = /(?:authorization|cookie|credential|key|password|passwd|secret|token)/iu;
2240
4871
  const PRIVATE_PAYLOAD_FIELD_RE = /(?:image|screenshot|attachment|fileData|dataUri)/iu;
@@ -2353,13 +4984,14 @@ function recordCodexTrajectoryContext(recorder, params) {
2353
4984
  /** Records final Codex model completion metadata and assistant snapshots. */
2354
4985
  function recordCodexTrajectoryCompletion(recorder, params) {
2355
4986
  if (!recorder) return;
4987
+ const terminal = attemptTerminal.project(params.result.terminal);
2356
4988
  recorder.recordEvent("model.completed", {
2357
4989
  threadId: params.threadId,
2358
4990
  turnId: params.turnId,
2359
4991
  timedOut: params.timedOut,
2360
4992
  yieldDetected: params.yieldDetected ?? false,
2361
- aborted: params.result.aborted,
2362
- promptError: normalizeCodexTrajectoryError(params.result.promptError),
4993
+ aborted: terminal.aborted,
4994
+ promptError: normalizeCodexTrajectoryError(terminal.promptError),
2363
4995
  usage: params.result.attemptUsage,
2364
4996
  assistantTexts: params.result.assistantTexts,
2365
4997
  messagesSnapshot: params.result.messagesSnapshot
@@ -2453,11 +5085,12 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2453
5085
  });
2454
5086
  }
2455
5087
  const result = activeProjector.buildResult(toolBridge.telemetry, { yieldDetected: toolState.yieldDetected });
5088
+ const projectedTerminal = attemptTerminal.project(result.terminal);
2456
5089
  const effectiveTimedOut = state.timedOut && !recoveredTurnWatchTimeout;
2457
5090
  const effectiveTurnCompletionIdleTimedOut = state.turnCompletionIdleTimedOut && !recoveredTurnWatchTimeout;
2458
- const isFinalAborted = () => result.aborted || terminalState.explicitCancellationObserved || runAbortController.signal.aborted && !state.clientClosedAbort && !recoveredTurnWatchTimeout;
5091
+ const isFinalAborted = () => projectedTerminal.aborted || terminalState.explicitCancellationObserved || runAbortController.signal.aborted && !state.clientClosedAbort && !recoveredTurnWatchTimeout;
2459
5092
  const clientClosedPromptErrorForFinal = state.clientClosedPromptError && hasRecoverableCompletedAssistant ? void 0 : state.clientClosedPromptError;
2460
- let finalPromptError = clientClosedPromptErrorForFinal ?? (effectiveTurnCompletionIdleTimedOut ? state.turnCompletionIdleTimeoutMessage : effectiveTimedOut ? "codex app-server attempt timed out" : result.promptError);
5093
+ let finalPromptError = clientClosedPromptErrorForFinal ?? (effectiveTurnCompletionIdleTimedOut ? state.turnCompletionIdleTimeoutMessage : effectiveTimedOut ? "codex app-server attempt timed out" : projectedTerminal.promptError);
2461
5094
  const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError instanceof Error ? finalPromptError.message : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
2462
5095
  if (isInvalidCodexImagePayloadError(finalPromptErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(bindingStore, bindingIdentity, {
2463
5096
  phase: "turn_completed",
@@ -2498,7 +5131,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2498
5131
  authProfileId: startupAuthProfileId,
2499
5132
  rateLimits: readRecentCodexRateLimits(resourceState.client)
2500
5133
  });
2501
- const finalPromptErrorSource = effectiveTimedOut || clientClosedPromptErrorForFinal ? "prompt" : result.promptErrorSource;
5134
+ const finalPromptErrorSource = effectiveTimedOut || clientClosedPromptErrorForFinal ? "prompt" : projectedTerminal.promptErrorSource;
2502
5135
  const codexAppServerFailureKind = clientClosedPromptErrorForFinal ? "client_closed_before_turn_completed" : effectiveTurnCompletionIdleTimedOut ? "turn_completion_idle_timeout" : void 0;
2503
5136
  const replayBlockedReason = codexAppServerFailureKind ? resolveCodexAppServerReplayBlockedReason(result) : void 0;
2504
5137
  const promptTimeoutOutcome = buildCodexAppServerPromptTimeoutOutcome({
@@ -2528,6 +5161,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2528
5161
  const turnSucceeded = !finalAborted && !effectiveTimedOut && (finalPromptError === null || finalPromptError === void 0) && (completedTurnStatus === "completed" || recoveredTurnWatchTimeout || completedWithoutTerminalNotification);
2529
5162
  if (settleCodexSourceReplyFinality(toolBridge.telemetry, turnSucceeded)) result.agentHarnessResultClassification = void 0;
2530
5163
  const attemptSucceeded = turnSucceeded && result.agentHarnessResultClassification === void 0;
5164
+ terminalState.turnSucceeded = turnSucceeded;
2531
5165
  terminalState.sharedAbortAllowedAfterTerminalOutcome = shouldKeepCodexSharedAbortOpen({
2532
5166
  trigger: params.trigger,
2533
5167
  result,
@@ -2547,7 +5181,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2547
5181
  if (modelCallFailureKind) codexModelCallDiagnostics.emitError(finalPromptError ?? "codex app-server attempt interrupted", { failureKind: modelCallFailureKind });
2548
5182
  else if (finalPromptError) codexModelCallDiagnostics.emitError(finalPromptError);
2549
5183
  else codexModelCallDiagnostics.emitCompleted(result);
2550
- const assistantTranscriptOwned = await codexTranscriptMirrorRuntime.mirrorBestEffort({
5184
+ const mirrorOutcome = await codexTranscriptMirrorRuntime.mirrorBestEffort({
2551
5185
  params,
2552
5186
  agentId: sessionAgentId,
2553
5187
  notifyUserMessagePersisted,
@@ -2557,6 +5191,18 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2557
5191
  threadId: resourceState.thread.threadId,
2558
5192
  turnId: activeTurnId
2559
5193
  });
5194
+ const { assistantTranscriptOwned, assistantTranscriptIdempotencyKey } = mirrorOutcome;
5195
+ const shouldCaptureSettledTurnFinalizationContext = turnSucceeded && result.assistantTexts.every((text) => !text.trim()) && result.messagesSnapshot.some((message) => message.role === "toolResult");
5196
+ const settledTurnFinalizationContext = shouldCaptureSettledTurnFinalizationContext ? await captureCodexSettledTurnFinalizationContext({
5197
+ ...activeTranscriptTarget,
5198
+ mirroredMessages: mirrorOutcome.mirroredMessages,
5199
+ settledMessages: result.messagesSnapshot,
5200
+ turnId: activeTurnId
5201
+ }) : void 0;
5202
+ if (shouldCaptureSettledTurnFinalizationContext && !settledTurnFinalizationContext) embeddedAgentLog.warn("codex settled-turn finalization context is unavailable", {
5203
+ threadId: resourceState.thread.threadId,
5204
+ turnId: activeTurnId
5205
+ });
2560
5206
  if (activeContextEngine) {
2561
5207
  const contextEnginePluginId = resolveContextEngineOwnerPluginId(activeContextEngine);
2562
5208
  const isHeartbeat = params.bootstrapContextRunKind === "heartbeat" || params.bootstrapContextRunKind === "commitment-only";
@@ -2680,13 +5326,17 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
2680
5326
  });
2681
5327
  return {
2682
5328
  ...result,
2683
- timedOut: effectiveTimedOut,
2684
- aborted: finalAborted,
2685
- promptError: finalPromptError,
2686
- promptErrorSource: finalPromptErrorSource,
5329
+ terminal: attemptTerminal.normalize({
5330
+ timedOut: effectiveTimedOut,
5331
+ aborted: finalAborted,
5332
+ promptError: finalPromptError,
5333
+ promptErrorSource: finalPromptErrorSource
5334
+ }),
2687
5335
  ...codexAppServerFailure ? { codexAppServerFailure } : {},
2688
5336
  ...promptTimeoutOutcome ? { promptTimeoutOutcome } : {},
2689
5337
  ...assistantTranscriptOwned ? { assistantTranscriptOwned: true } : {},
5338
+ ...assistantTranscriptIdempotencyKey ? { assistantTranscriptIdempotencyKey } : {},
5339
+ ...settledTurnFinalizationContext ? { settledTurnFinalizationContext } : {},
2690
5340
  ...resourceState.runtimeArtifact ? { runtimeArtifact: resourceState.runtimeArtifact } : {},
2691
5341
  ...!finalAborted && !effectiveTimedOut && !finalPromptError && preparedAuthBinding ? { authBindingFingerprint: preparedAuthBinding.fingerprint } : {},
2692
5342
  systemPromptReport
@@ -3011,7 +5661,7 @@ var ClientTurnRouter = class {
3011
5661
  this.nativeTurnCompletionWatchers = /* @__PURE__ */ new Map();
3012
5662
  this.disposed = false;
3013
5663
  client.addNotificationHandler((notification) => this.routeNotification(notification));
3014
- client.addRequestHandler((request) => this.routeRequest(request));
5664
+ client.addRequestHandler((request, signal) => this.routeRequest(request, signal));
3015
5665
  client.addCloseHandler(() => this.dispose());
3016
5666
  }
3017
5667
  reserveThread(options) {
@@ -3172,34 +5822,35 @@ var ClientTurnRouter = class {
3172
5822
  this.enqueueNotification(route, handler, notification, routeScope);
3173
5823
  return route.notificationTail;
3174
5824
  }
3175
- async routeRequest(request) {
3176
- if (this.disposed) return;
5825
+ async routeRequest(request, signal = new AbortController().signal) {
5826
+ if (this.disposed || signal.aborted) return;
3177
5827
  const scope = readScope(request.params);
3178
5828
  if (!scope.threadId) return;
3179
5829
  const route = this.routes.get(scope.threadId);
3180
5830
  if (!route || route.released) return;
3181
- if (!route.handlers) await route.activated.promise;
3182
- if (route.released || !route.handlers) return;
5831
+ if (!route.handlers && !await waitForPromiseOrAbort(route.activated.promise, signal)) return;
5832
+ if (signal.aborted || route.released || !route.handlers) return;
3183
5833
  const handler = route.handlers.onRequest;
3184
5834
  if (!handler) return;
3185
5835
  while (route.gate === "armed") {
3186
- await route.binding?.promise;
3187
- if (route.released) return;
5836
+ const binding = route.binding?.promise;
5837
+ if (!binding || !await waitForPromiseOrAbort(binding, signal)) return;
5838
+ if (signal.aborted || route.released) return;
3188
5839
  }
3189
5840
  if (route.gate === "bound") {
3190
5841
  if (scope.turnId && scope.turnId !== route.turnId) return;
3191
5842
  if (route.released) return;
3192
5843
  }
3193
- await this.waitForNotifications(route);
3194
- if (route.released) return;
5844
+ if (!await waitForPromiseOrAbort(this.waitForNotifications(route), signal)) return;
5845
+ if (signal.aborted || route.released) return;
3195
5846
  try {
3196
5847
  const result = await handler(request, {
3197
5848
  threadId: scope.threadId,
3198
5849
  ...scope.turnId ? { turnId: scope.turnId } : {}
3199
- });
3200
- return route.released ? void 0 : result;
5850
+ }, signal);
5851
+ return signal.aborted || route.released ? void 0 : result;
3201
5852
  } catch (error) {
3202
- if (route.released) return;
5853
+ if (signal.aborted || route.released) return;
3203
5854
  throw error;
3204
5855
  }
3205
5856
  }
@@ -3319,6 +5970,20 @@ function isCodexTerminalTurnNotification(notification) {
3319
5970
  if (notification.method === "turn/completed") return true;
3320
5971
  return notification.method === "error" && isJsonObject(notification.params) && notification.params.willRetry === false;
3321
5972
  }
5973
+ async function waitForPromiseOrAbort(promise, signal) {
5974
+ if (signal.aborted) return false;
5975
+ let removeAbort;
5976
+ try {
5977
+ return await Promise.race([promise.then(() => true), new Promise((resolve) => {
5978
+ const onAbort = () => resolve(false);
5979
+ signal.addEventListener("abort", onAbort, { once: true });
5980
+ removeAbort = () => signal.removeEventListener("abort", onAbort);
5981
+ if (signal.aborted) onAbort();
5982
+ })]);
5983
+ } finally {
5984
+ removeAbort?.();
5985
+ }
5986
+ }
3322
5987
  function deferred() {
3323
5988
  let resolve;
3324
5989
  return {
@@ -3579,8 +6244,7 @@ async function prepareCodexAttemptPrompt(context) {
3579
6244
  developerInstructions: promptState.developerInstructions,
3580
6245
  messages: structuredClone(historyState.messages),
3581
6246
  ctx: hookContext,
3582
- bootstrapContextRunKind: params.bootstrapContextRunKind,
3583
- ..."beforeAgentStartResult" in params ? { beforeAgentStartResult: params.beforeAgentStartResult } : {}
6247
+ bootstrapContextRunKind: params.bootstrapContextRunKind
3584
6248
  });
3585
6249
  const resolveShiftedPromptInputRange = (prompt, promptInputRange, turnPromptText) => {
3586
6250
  if (!promptInputRange || promptInputRange.start < 0 || promptInputRange.end < promptInputRange.start || promptInputRange.end > prompt.length || !turnPromptText.endsWith(prompt)) return;
@@ -3631,8 +6295,7 @@ async function prepareCodexAttemptPrompt(context) {
3631
6295
  const buildRenderedCodexDeveloperInstructions = () => joinPresentSections(turnState.promptBuild.developerInstructions, buildTurnCollaborationMode(params, {
3632
6296
  turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
3633
6297
  skillsCollaborationInstructions,
3634
- memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
3635
- heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
6298
+ memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions
3636
6299
  }).settings.developer_instructions ?? void 0);
3637
6300
  const rebuildCodexPromptBuildFromCurrentProjection = async () => {
3638
6301
  turnState.promptBuild = await buildPromptFromCurrentInputs();
@@ -5595,7 +8258,7 @@ async function readFile(execServer, params) {
5595
8258
  const fsBridge = requireFsBridge(execServer);
5596
8259
  const stat = await fsBridge.stat({ filePath });
5597
8260
  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`);
8261
+ assertSandboxFileReadWithinLimit(stat);
5599
8262
  return { dataBase64: (await fsBridge.readFile({ filePath })).toString("base64") };
5600
8263
  }
5601
8264
  /** Writes base64 data to an existing sandbox directory after write-policy checks. */
@@ -5736,6 +8399,15 @@ async function copySandboxPath(execServer, params) {
5736
8399
  }
5737
8400
  return;
5738
8401
  }
8402
+ if (sourceStat.type === "file" && fsBridge.copyFile) {
8403
+ await fsBridge.copyFile({
8404
+ sourcePath: params.sourcePath,
8405
+ destinationPath: params.destinationPath,
8406
+ mkdir: true
8407
+ });
8408
+ return;
8409
+ }
8410
+ assertSandboxFileReadWithinLimit(sourceStat);
5739
8411
  const data = await fsBridge.readFile({ filePath: params.sourcePath });
5740
8412
  await fsBridge.writeFile({
5741
8413
  filePath: params.destinationPath,
@@ -5743,6 +8415,9 @@ async function copySandboxPath(execServer, params) {
5743
8415
  mkdir: true
5744
8416
  });
5745
8417
  }
8418
+ function assertSandboxFileReadWithinLimit(stat) {
8419
+ 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`);
8420
+ }
5746
8421
  function metadataResponse(stat) {
5747
8422
  return {
5748
8423
  isDirectory: stat?.type === "directory",
@@ -6792,6 +9467,15 @@ function prepareCodexAttemptResources(prompt) {
6792
9467
  timeoutMs: params.timeoutMs,
6793
9468
  timeoutFloorMs: options.startupTimeoutFloorMs
6794
9469
  });
9470
+ const requesterChannel = params.messageChannel ?? params.messageProvider;
9471
+ const requester = {
9472
+ ...requesterChannel ? { channel: requesterChannel } : {},
9473
+ ...params.agentAccountId ? { accountId: params.agentAccountId } : {},
9474
+ ...params.senderId ? { senderId: params.senderId } : {},
9475
+ ...params.senderIsOwner !== void 0 ? { senderIsOwner: params.senderIsOwner } : {},
9476
+ ...params.memberRoleIds?.length ? { roleIds: [...params.memberRoleIds] } : {}
9477
+ };
9478
+ const hasRequester = Object.keys(requester).length > 0;
6795
9479
  const buildNativeHookRelayFinalConfigPatch = (decision) => {
6796
9480
  state.nativeHookRelay?.unregister();
6797
9481
  state.nativeHookRelay = createCodexNativeHookRelay({
@@ -6805,6 +9489,7 @@ function prepareCodexAttemptResources(prompt) {
6805
9489
  config: params.config,
6806
9490
  runId: params.runId,
6807
9491
  channelId: hookChannelId,
9492
+ ...hasRequester ? { requester } : {},
6808
9493
  attemptTimeoutMs: params.timeoutMs,
6809
9494
  startupTimeoutMs,
6810
9495
  turnStartTimeoutMs: params.timeoutMs,
@@ -6914,6 +9599,28 @@ async function prepareCodexAttemptRoute(resources, turnRuntime, notifications, h
6914
9599
  return { ensureCurrentThreadRoute };
6915
9600
  }
6916
9601
  //#endregion
9602
+ //#region extensions/codex/src/app-server/run-attempt-client-prewarm.ts
9603
+ /** Starts the shared process while tools and prompt context are still being prepared. */
9604
+ function prewarmCodexAttemptClient(params) {
9605
+ const { connection, authProfileStore, authBindingFingerprint } = params;
9606
+ const { appServer, attemptClientFactory, options, pluginConfig, runtimeArtifactRequest, startupAuthRequirement, startupClientAuthProfileId, startupPreparedAuth, agentDir, params: runParams, runAbortController } = connection;
9607
+ if (options.clientFactory || attemptClientFactory !== getLeasedSharedCodexAppServerClient || runtimeArtifactRequest) return;
9608
+ getSharedCodexAppServerClient({
9609
+ startOptions: appServer.start,
9610
+ pluginConfig,
9611
+ ...startupPreparedAuth ? { preparedAuth: startupPreparedAuth } : { authProfileId: startupClientAuthProfileId },
9612
+ authRequirement: startupAuthRequirement,
9613
+ authProfileStore,
9614
+ authBindingFingerprint,
9615
+ agentDir,
9616
+ config: runParams.config,
9617
+ timeoutMs: appServer.requestTimeoutMs,
9618
+ abandonSignal: runAbortController.signal
9619
+ }).catch((error) => {
9620
+ embeddedAgentLog.debug("codex app-server client prewarm failed", { error });
9621
+ });
9622
+ }
9623
+ //#endregion
6917
9624
  //#region extensions/codex/src/app-server/run-attempt-runtime.ts
6918
9625
  async function prepareCodexAttemptRuntime(connection) {
6919
9626
  const { params, pluginConfig, usesSupervisionConnection, appServer, startupAuthProfileId, startupPreparedAuth, startupClientAuthProfileId, agentDir, preDynamicStartupStages, effectiveWorkspace, contextSessionKey, sandboxSessionKey, sessionAgentId, sandbox, attemptClientFactory, runAbortController, activeContextEngine, mutable } = connection;
@@ -6924,6 +9631,11 @@ async function prepareCodexAttemptRuntime(connection) {
6924
9631
  config: params.config
6925
9632
  }) : void 0;
6926
9633
  const attemptAuthProfileStore = preparedAuthBinding?.authProfileStore ?? params.authProfileStore;
9634
+ prewarmCodexAttemptClient({
9635
+ connection,
9636
+ authProfileStore: attemptAuthProfileStore,
9637
+ authBindingFingerprint: preparedAuthBinding?.fingerprint
9638
+ });
6927
9639
  const effectiveContextWindowInfo = usesSupervisionConnection ? void 0 : params.contextWindowInfo;
6928
9640
  const effectiveContextTokenBudget = usesSupervisionConnection ? void 0 : params.contextTokenBudget;
6929
9641
  const effectiveRuntimeProviderId = usesSupervisionConnection ? mutable.startupBinding?.modelProvider ?? "codex" : params.provider;
@@ -7052,7 +9764,8 @@ function recordCodexDynamicToolResult(projector, call, response, protocolRespons
7052
9764
  success: protocolResponse.success,
7053
9765
  terminalType: response.diagnosticTerminalType ?? (protocolResponse.success ? "completed" : "error"),
7054
9766
  sideEffectEvidence: response.sideEffectEvidence === true || response.terminalResolution?.sideEffectEvidence === true,
7055
- contentItems: protocolResponse.contentItems
9767
+ contentItems: protocolResponse.contentItems,
9768
+ details: response.transcriptDetails
7056
9769
  });
7057
9770
  }
7058
9771
  //#endregion
@@ -7150,7 +9863,8 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
7150
9863
  const { toolBridge, toolOutcomeOrdinals, suppressedDynamicToolOutcomeOrdinals, allocateCodexToolOutcomeOrdinal } = attemptTools;
7151
9864
  const { state, turnIdRef, userInputBridgeRef, openClawDynamicToolExecutions, pendingOpenClawDynamicToolCompletionIds, postToolRawAssistantCompletionIdleTimeoutMs, turnWatches } = turnRuntime;
7152
9865
  const { emitExecutionPhaseOnce, scheduleTurnReleaseAfterTerminalDynamicTool, scheduleTerminalDynamicToolReleaseCheck } = lifecycle;
7153
- const handleServerRequest = async (request, scope) => {
9866
+ const handleServerRequest = async (request, scope, requestSignal = new AbortController().signal) => {
9867
+ const signal = AbortSignal.any([runAbortController.signal, requestSignal]);
7154
9868
  const turnId = turnIdRef.current;
7155
9869
  const projector = projectorRef.current;
7156
9870
  let armCompletionWatchOnResponse = false;
@@ -7176,7 +9890,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
7176
9890
  turnId,
7177
9891
  pluginAppPolicyContext: resourceState.thread.pluginAppPolicyContext,
7178
9892
  ...computerUseConfig.enabled ? { computerUseMcpServerName: computerUseConfig.mcpServerName } : {},
7179
- signal: runAbortController.signal
9893
+ signal
7180
9894
  });
7181
9895
  }
7182
9896
  if (request.method === "item/tool/requestUserInput") {
@@ -7203,7 +9917,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
7203
9917
  turnId,
7204
9918
  nativeHookRelay: resourceState.nativeHookRelay,
7205
9919
  autoApprove: shouldAutoApproveCodexAppServerApprovals(appServer),
7206
- signal: runAbortController.signal,
9920
+ signal,
7207
9921
  onNativeToolFailureDisposition: (itemId, disposition) => projector?.recordNativeToolApprovalFailure(itemId, disposition)
7208
9922
  });
7209
9923
  }
@@ -7279,7 +9993,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
7279
9993
  const { execution } = openClawDynamicToolExecutions.claim(call, () => handleDynamicToolCallWithTimeout({
7280
9994
  call,
7281
9995
  toolBridge,
7282
- signal: runAbortController.signal,
9996
+ signal,
7283
9997
  timeoutMs: dynamicToolTimeoutMs,
7284
9998
  toolMeta,
7285
9999
  toolCallOrdinal,
@@ -7576,7 +10290,7 @@ function buildMetadataCacheEntryKey(appCacheKey, queryKind) {
7576
10290
  //#endregion
7577
10291
  //#region extensions/codex/src/app-server/plugin-thread-config-deadline.ts
7578
10292
  /** Enforces one bounded startup budget across Codex plugin config discovery. */
7579
- const CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS = 5e3;
10293
+ const CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS = 6e4;
7580
10294
  const CODEX_PLUGIN_THREAD_CONFIG_TIMEOUT_DIVISOR = 4;
7581
10295
  const CODEX_PLUGIN_THREAD_CONFIG_MIN_TIMEOUT_MS = 100;
7582
10296
  var CodexPluginThreadConfigDeadlineError = class extends Error {
@@ -7743,6 +10457,7 @@ async function startCodexAttemptThread(params) {
7743
10457
  const attemptParams = params.buildAttemptParams();
7744
10458
  startupClient = await params.attemptClientFactory({
7745
10459
  startOptions: params.appServer.start,
10460
+ pluginConfig: params.pluginConfig,
7746
10461
  ...params.startupPreparedAuth ? { preparedAuth: params.startupPreparedAuth } : { authProfileId: params.startupAuthProfileId },
7747
10462
  authRequirement: params.startupAuthRequirement,
7748
10463
  authProfileStore: attemptParams.authProfileStore,
@@ -7791,14 +10506,19 @@ async function startCodexAttemptThread(params) {
7791
10506
  config: params.config
7792
10507
  });
7793
10508
  const turnRouter = getCodexAppServerTurnRouter(activeStartupClient);
7794
- await ensureCodexComputerUse({
7795
- client: activeStartupClient,
7796
- pluginConfig: params.pluginConfig,
7797
- config: params.config,
7798
- agentDir: params.agentDir,
7799
- timeoutMs: params.appServer.requestTimeoutMs,
7800
- signal: startupAbandonController.signal
7801
- });
10509
+ try {
10510
+ await ensureCodexComputerUse({
10511
+ client: activeStartupClient,
10512
+ pluginConfig: params.pluginConfig,
10513
+ config: params.config,
10514
+ agentDir: params.agentDir,
10515
+ timeoutMs: params.appServer.requestTimeoutMs,
10516
+ signal: startupAbandonController.signal
10517
+ });
10518
+ } catch (error) {
10519
+ if (startupAbandonController.signal.aborted) throw error;
10520
+ throw new AgentHarnessPreflightError(`Codex Computer Use readiness failed: ${formatErrorMessage(error)}`, { cause: error });
10521
+ }
7802
10522
  const startupRuntimeIdentity = activeStartupClient.getRuntimeIdentity();
7803
10523
  const pluginAppCacheKey = buildCodexPluginAppCacheKey({
7804
10524
  appServer: params.appServer,
@@ -8266,7 +10986,7 @@ async function prepareCodexAttemptTools(runtime) {
8266
10986
  sessionId: params.sessionId,
8267
10987
  sessionKey: params.sessionKey,
8268
10988
  workspaceDir: effectiveWorkspace,
8269
- agentDir: agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId),
10989
+ agentDir: agentDir ?? resolveAgentDir(params.config ?? {}, sessionAgentId),
8270
10990
  cfg: params.config,
8271
10991
  requesterSenderId: params.senderId,
8272
10992
  agentAccountId: params.agentAccountId,
@@ -8280,7 +11000,7 @@ async function prepareCodexAttemptTools(runtime) {
8280
11000
  sessionId: params.sessionId,
8281
11001
  runId: params.runId,
8282
11002
  agentId: sessionAgentId,
8283
- agentDir: agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId),
11003
+ agentDir: agentDir ?? resolveAgentDir(params.config ?? {}, sessionAgentId),
8284
11004
  agentAccountId: params.agentAccountId,
8285
11005
  messageProvider: params.messageProvider ?? params.messageChannel,
8286
11006
  messageChannel: params.messageChannel,
@@ -8332,6 +11052,7 @@ async function prepareCodexAttemptTools(runtime) {
8332
11052
  hookContext: {
8333
11053
  agentId: sessionAgentId,
8334
11054
  config: params.config,
11055
+ contextWindowTokens: params.contextTokenBudget ?? params.model.contextWindow,
8335
11056
  workspaceDir: effectiveWorkspace,
8336
11057
  sessionId: params.sessionId,
8337
11058
  sessionKey: sandboxSessionKey,
@@ -8418,7 +11139,6 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
8418
11139
  turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
8419
11140
  skillsCollaborationInstructions: context.skillsCollaborationInstructions,
8420
11141
  memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
8421
- heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions,
8422
11142
  preserveNativeTurnSettings: usesSupervisionConnection
8423
11143
  });
8424
11144
  codexModelCallDiagnostics.setRequestPayloadBytes(utf8JsonByteLength(turnStartParams));
@@ -8643,7 +11363,11 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
8643
11363
  ctx: hookContext,
8644
11364
  hookRunner
8645
11365
  });
8646
- if (!state.timedOut) await unsubscribeCodexThreadBestEffort(resourceState.client, {
11366
+ const bindingReleased = isIncognitoSessionKey(params.sessionKey) ? await bindingStore.mutate(bindingIdentity, {
11367
+ kind: "clear",
11368
+ threadId: resourceState.thread.threadId
11369
+ }) : true;
11370
+ if (!state.timedOut && bindingReleased) await unsubscribeCodexThreadBestEffort(resourceState.client, {
8647
11371
  threadId: resourceState.thread.threadId,
8648
11372
  timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
8649
11373
  });