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

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 (42) hide show
  1. package/dist/{app-server-policy-BmDgseo_.js → app-server-policy-BSaO2JIT.js} +1 -1
  2. package/dist/{attempt-notifications-CMR2_fmR.js → attempt-notifications-AP-a-Q5k.js} +1 -1
  3. package/dist/{bounded-turn-FEbUXoYT.js → bounded-turn-D2ZAgZVz.js} +29 -22
  4. package/dist/{capabilities-BHRSI6Cn.js → capabilities-BFDTVYr4.js} +1 -1
  5. package/dist/cli-metadata.js +1 -1
  6. package/dist/{command-formatters-ico4ZFnk.js → command-formatters-C336eRVS.js} +2 -2
  7. package/dist/{command-handlers-CRmnwI2N.js → command-handlers-DAHUSry9.js} +12 -12
  8. package/dist/{compact-dEN49UH6.js → compact-D_uvHurS.js} +5 -5
  9. package/dist/{computer-use-BjGylO-E.js → computer-use-CYEc8U3w.js} +111 -113
  10. package/dist/{conversation-control-DE7d9DOj.js → conversation-control-xsIeXbo4.js} +6 -6
  11. package/dist/doctor-contract-api.js +1 -1
  12. package/dist/{dynamic-tools-LIt9ojep.js → dynamic-tools-D2gYkSBO.js} +438 -51
  13. package/dist/effective-mcp-catalog-Bbd98Inw.js +114 -0
  14. package/dist/{event-projector-usage-tvgb1NCX.js → event-projector-usage-Xp4AlR2k.js} +20 -3
  15. package/dist/harness.js +13 -9
  16. package/dist/index.js +131 -108
  17. package/dist/media-understanding-provider.js +1 -1
  18. package/dist/{models-BA01NEez.js → models-BBMKU4jA.js} +2 -2
  19. package/dist/{notification-correlation-Bj_Ak_jI.js → notification-correlation-CU6_AnOb.js} +3 -3
  20. package/dist/{plugin-app-cache-key-DSXX-rXO.js → plugin-app-cache-key-DztPafOA.js} +132 -39
  21. package/dist/{rate-limits-S_PXs0ul.js → rate-limits-CU-gVCCS.js} +1 -1
  22. package/dist/{request-CXpPennK.js → request-qKh331yu.js} +3 -3
  23. package/dist/{run-attempt-C5GTPJOE.js → run-attempt-CY9WlDLc.js} +677 -199
  24. package/dist/{runtime-artifact-C2ITXdhM.js → runtime-artifact-CmtG_t1L.js} +90 -24
  25. package/dist/{sandbox-guard-D1Wky__S.js → sandbox-guard-NuhpXmPB.js} +4 -0
  26. package/dist/{session-binding-DlVQ-Pxs.js → session-binding-BXpo9ymA.js} +60 -7
  27. package/dist/{session-catalog-CP2oCcEb.js → session-catalog-DyOgR4WH.js} +268 -44
  28. package/dist/{session-cli-CqZ0Fp2a.js → session-cli-2PZaFLRh.js} +1 -1
  29. package/dist/{session-upstream-marker-QE-m5QFG.js → session-upstream-marker-B6U7tLw5.js} +1 -1
  30. package/dist/{settled-turn-finalizer-CA_2QXIE.js → settled-turn-finalizer-CXY2Z9dT.js} +19 -6
  31. package/dist/{shared-client-BVKE40c-.js → shared-client-DTbvH-XV.js} +166 -49
  32. package/dist/{side-question-CO12sHxo.js → side-question-_ulBk1AL.js} +10 -10
  33. package/dist/{thread-lifecycle-DRg_FdzC.js → thread-lifecycle-DF53ogiA.js} +968 -214
  34. package/dist/{protocol-validators-Dm4eXZmt.js → transcript-mirror-DzsdNCf5.js} +589 -2
  35. package/dist/{upstream-session-fork-_Vrz4WJr.js → upstream-session-fork-Dy4Xvuoj.js} +3 -3
  36. package/dist/{usage-UpVbdX5G.js → usage-CQ6GhD5-.js} +3 -3
  37. package/dist/{web-search-provider.runtime-CaQMYDbp.js → web-search-provider.runtime-CCFhg2z5.js} +3 -3
  38. package/package.json +6 -7
  39. package/dist/attempt-client-cleanup-Ia52yRWc.js +0 -127
  40. package/dist/realtime-voice-api-BPcA1uN9.js +0 -494
  41. package/dist/realtime-voice-api.js +0 -2
  42. package/dist/transcript-mirror-uKA-A4tB.js +0 -550
@@ -1,37 +1,36 @@
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";
1
+ import { $ as resolveCodexTurnAssistantCompletionIdleTimeoutMs, A as retainCodexAppServerLiveThread, D as resolveCodexAppServerClientInstanceId, E as isCodexAppServerRequestTimeoutError, F as resolveCodexAppServerAuthProfileId, I as resolveCodexAppServerAuthProfileIdForAgent, J as CodexAppServerStartupError, K as resolveCodexAppServerHomeDir, L as resolveCodexAppServerFallbackApiKeyCacheKey, M as readRecentCodexRateLimits, N as rememberCodexRateLimitsRead, P as resolveCodexAppServerAuthAccountCacheKey, Q as resolveCodexStartupTimeoutMs, R as resolveCodexAppServerPreparedApiKeyCacheKey, S as isCodexAppServerConnectionClosedError, U as flattenCodexDynamicToolFunctions, W as isJsonObject, Y as isCodexAppServerStartupError, Z as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, a as getLeasedSharedCodexAppServerClient, b as isCodexAppServerApprovalRequest, et as resolveCodexTurnCompletionIdleTimeoutMs, f as retainSharedCodexAppServerClientIfCurrent, j as readCodexRateLimitsRevision, k as ensureCodexAppServerClientRuntime, l as releaseLeasedSharedCodexAppServerClient, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, nt as withCodexStartupTimeout, o as getSharedCodexAppServerClient, p as retireSharedCodexAppServerClientIfCurrent, q as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, s as isCodexAppServerStartSelectionChangedError, t as clearSharedCodexAppServerClientIfCurrent, tt as resolveCodexTurnTerminalIdleTimeoutMs, v as CodexAppServerRpcError, x as isCodexAppServerBrokenPipeError, y as getCodexAppServerClientInstanceId, z as resolveCodexAppServerPreparedAuthHandoff } from "./shared-client-DTbvH-XV.js";
2
+ import { A as resolveOpenClawExecPolicyForCodexAppServer, D as isCodexSandboxExecServerEnabled, E as isCodexAppServerApprovalPolicyAllowedByRequirements, O as readCodexPluginConfig, S as withMcpElicitationsApprovalPolicy, T as resolveCodexModelBackedReviewerPolicyContext, c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, h as resolveCodexAppServerHomeScope, i as createCodexSessionGenerationSupersededError, k as resolveCodexPluginsPolicy, l as resolveCodexRunSessionBindingAuthority, u as scopeCodexRunBindingStore, v as resolveCodexComputerUseConfig, x as shouldAutoApproveCodexAppServerApprovals } from "./session-binding-BXpo9ymA.js";
3
+ import { $ as readCodexErrorNotificationMessage, 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 normalizeNonEmptyString, R as projectContextEngineAssemblyForCodex, T as filterCodexDynamicTools, U as buildCodexPluginThreadConfigInputFingerprint, W as buildCodexPluginThreadConfigTimeoutFallback, X as resolveRecoverableCodexPluginConfigKeys, Z as extractRawAssistantText, _ as buildDeveloperInstructions, _t as unsubscribeCodexThreadBestEffort, a as sanitizeCodexHistoryImagePayloads, at as readNonNegativeInteger, c as isCodexAppServerProfilerEnabled, ct as readString$6, dt as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, et as readHookOutputEntries, ft as CodexAppServerUnsafeSubscriptionError, g as resolveCodexWebSearchPlan, gt as retireCodexAppServerClientAfterTimedOutTurn, ht as interruptCodexTurnBestEffort, it as readNonEmptyStringArray, j as resolveCodexDynamicToolsLoadingForRuntime, lt as splitPlanText, n as buildTurnStartParams, nt as readItemString, ot as readNullableString$1, pt as closeCodexStartupClientBestEffort, r as buildCodexUserInput, rt as readNonEmptyString$1, s as startOrResumeThread, st as readNumber, t as buildTurnCollaborationMode, tt as readItem, ut as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS, x as resolveCodexAppServerThreadModelSelection, z as resolveCodexContextEngineProjectionMaxChars } from "./thread-lifecycle-DF53ogiA.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-AP-a-Q5k.js";
5
+ import { r as projectCodexThreadUsageUpdate, t as CodexResponseCompletionProjection } from "./event-projector-usage-Xp4AlR2k.js";
6
+ import { C as readCodexTurnCompletedNotification, S as readCodexTurn, d as attachCodexMirrorIdentity, f as readMirrorIdentity, i as mirrorPromptAtTurnStartBestEffort, n as createCodexAppServerUserMessagePersistenceNotifier, o as buildCodexUserPromptMessage, s as promptSnapshot, t as codexTranscriptMirrorRuntime, u as serializeCodexMirrorSourceEvidence, v as assertCodexTurnStartResponse, y as readCodexDynamicToolCallParams } from "./transcript-mirror-DzsdNCf5.js";
7
+ import { i as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-DztPafOA.js";
9
8
  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";
9
+ import { t as CODEX_CONTROL_METHODS } from "./capabilities-BFDTVYr4.js";
10
+ import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-CU-gVCCS.js";
11
+ import { r as formatCodexDisplayText } from "./command-formatters-C336eRVS.js";
12
+ import { n as resolveCodexAppServerForOpenClawToolPolicy, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-BSaO2JIT.js";
13
+ import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId, t as isCodexNotificationForTurn } from "./notification-correlation-CU6_AnOb.js";
16
14
  import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-B4FfbcCg.js";
17
15
  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";
16
+ import { $ as shouldClearTerminalPresentationForNativeItem, A as createCodexNativeHookRelay, B as resolveTerminalDynamicToolBatchAction, D as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, F as handleDynamicToolCallWithTimeout, G as resolveCodexToolAbortTerminalReason, H as shouldReleaseTurnAfterTerminalDynamicTool, I as hasPendingDynamicToolTerminalDiagnostic, J as isSideEffectingNativeToolItem, K as isMutatingNativeToolItem, L as isDynamicToolTerminalDiagnosticEvent, M as resolveCodexNativeHookRelayEvents, N as resolveCodexNativeHookRelayTtlMs, O as buildCodexNativeHookRelayConfig, P as scheduleCodexNativeHookRelayUnregister, Q as itemTitle, R as isMatchingDynamicToolTerminalDiagnostic, S as shouldWarnCodexDynamicToolBuildStageSummary, T as CodexNativeToolLifecycleProjector, U as toCodexDynamicToolProgressResponse, V as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult, W as toCodexDynamicToolProtocolResponse, X as itemName, Y as itemKind, Z as itemStatus, _ as resolveCodexExternalSandboxPolicyForOpenClawSandbox, a as emitDynamicToolStartedDiagnostic, b as shouldEnableCodexAppServerNativeToolSurface, d as buildDynamicTools, et as shouldRecordNativeToolTranscript, f as createCodexDynamicToolBuildStageTracker, g as resolveCodexAppServerHookChannelId, h as resolveCodexAppServerExecutionCwd, i as emitDynamicToolErrorDiagnostic, j as emitCodexNativePreToolUseFailureDiagnostic, k as buildCodexNativeHookRelayDisabledConfig, l as buildCodexHookRequester, m as formatCodexDynamicToolBuildStageSummary, n as handleCodexAppServerApprovalRequest, nt as unknownItemStatus, o as emitDynamicToolTerminalDiagnostic, p as disableCodexPluginThreadConfig, q as isNonSuccessItemStatus, r as handleCodexAppServerElicitationRequest, s as resolveCodexProviderWebSearchSupport, t as createCodexDynamicToolBridge, tt as shouldSynthesizeToolProgressForItem, u as settleCodexSourceReplyFinality, v as resolveCodexMessageToolProvider, w as readBoundedCodexRemoteWorkspaceFile, x as shouldRequireCodexSandboxExecServerEnvironment, y as resolveCodexSandboxEnvironmentSelection, z as resolveDynamicToolCallTimeoutMs } from "./dynamic-tools-D2gYkSBO.js";
17
+ import { a as killStaleComputerUseMcpChildren, i as runCodexComputerUseLiveTest, t as ensureCodexComputerUse } from "./computer-use-CYEc8U3w.js";
20
18
  import fs from "node:fs/promises";
21
19
  import path, { posix } from "node:path";
22
20
  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";
21
+ 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, buildWatchedSessionsHarnessContext, 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";
24
22
  import { createHash, randomUUID } from "node:crypto";
25
23
  import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
26
24
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
27
25
  import { asFiniteNumber, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
28
- import { listSessionEntries, parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
26
+ import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
27
+ import { getSessionEntry, parseSqliteSessionFileMarker, resolveTranscriptSessionKeyBySessionId } from "openclaw/plugin-sdk/session-store-runtime";
29
28
  import { spawn } from "node:child_process";
30
29
  import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
31
30
  import { once } from "node:events";
32
31
  import { isIP } from "node:net";
33
32
  import { WebSocketServer } from "ws";
34
- import { fileURLToPath } from "node:url";
33
+ import { fileURLToPath, pathToFileURL } from "node:url";
35
34
  import { redactSensitiveFieldValue, redactSensitiveText, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
36
35
  import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
37
36
  import { readSessionTranscriptEvents } from "openclaw/plugin-sdk/session-transcript-runtime";
@@ -41,9 +40,9 @@ import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from
41
40
  import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
42
41
  import { resolveGeneratedMediaMaxBytes } from "openclaw/plugin-sdk/media-generation-runtime";
43
42
  import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
43
+ import { root } from "openclaw/plugin-sdk/file-access-runtime";
44
44
  import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
45
45
  import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
46
- import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
47
46
  //#region extensions/codex/src/app-server/attempt-steering.ts
48
47
  /**
49
48
  * Debounced steering queue for forwarding user messages to an active Codex
@@ -394,7 +393,11 @@ var CodexAssistantProjection = class {
394
393
  return;
395
394
  }
396
395
  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);
396
+ const authoritativeIndex = turnItems.findLastIndex((item) => {
397
+ if (item.type !== "agentMessage" || typeof item.text !== "string" || item.text.trim().length === 0) return false;
398
+ const phase = readItemString(item, "phase");
399
+ return phase === "final_answer" || phase === void 0;
400
+ });
398
401
  const authoritative = authoritativeIndex >= 0 ? turnItems[authoritativeIndex] : void 0;
399
402
  if (turnItems.slice(authoritativeIndex + 1).some(shouldClearTerminalPresentationForNativeItem) || authoritative?.id === this.latestTerminalAssistantCandidateItemId && this.latestTerminalAssistantCandidateSuperseded) {
400
403
  this.supersedeVisibleAnswerCandidate();
@@ -1282,13 +1285,6 @@ var CodexToolProgressProjection = class {
1282
1285
  function isMissingFileError(error) {
1283
1286
  return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
1284
1287
  }
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
1288
  /** Returns sanitized session-context messages for a Codex mirrored session file. */
1293
1289
  async function readCodexMirroredSessionHistoryMessages(target) {
1294
1290
  try {
@@ -1323,16 +1319,19 @@ async function readCodexMirroredSessionEntries(target) {
1323
1319
  }
1324
1320
  function resolveSqliteMarkerSessionKey(target, marker) {
1325
1321
  const explicitSessionKey = target.sessionKey?.trim();
1326
- const entries = listSessionEntries({
1322
+ if (explicitSessionKey) {
1323
+ const explicitEntry = getSessionEntry({
1324
+ agentId: marker.agentId,
1325
+ sessionKey: explicitSessionKey,
1326
+ storePath: marker.storePath
1327
+ });
1328
+ if (explicitEntry) return explicitEntry.sessionId === marker.sessionId ? explicitSessionKey : void 0;
1329
+ }
1330
+ return resolveTranscriptSessionKeyBySessionId({
1327
1331
  agentId: marker.agentId,
1328
- readOnly: true,
1332
+ sessionId: marker.sessionId,
1329
1333
  storePath: marker.storePath
1330
1334
  });
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
1335
  }
1337
1336
  //#endregion
1338
1337
  //#region extensions/codex/src/app-server/event-projector-tool-transcript.ts
@@ -1351,6 +1350,35 @@ const ZERO_USAGE = {
1351
1350
  }
1352
1351
  };
1353
1352
  const MISSING_TOOL_RESULT_ERROR = "OpenClaw recorded a native Codex tool.call without a matching tool.result before the turn completed.";
1353
+ const NATIVE_PATCH_REJECTION_RE = /^\s*patch rejected:\s*writing outside of the project;\s*rejected by user approval settings\s*$/iu;
1354
+ const CODE_MODE_NATIVE_PATCH_SOURCE_RE = /^\s*(?:\/\/[^\r\n]*\r?\n\s*)?(?:const|let)\s+([A-Za-z_$][\w$]*)\s*=\s*await\s+tools\.apply_patch\(\s*("(?:\\[\s\S]|[^"\\])*")\s*\)\s*;?\s*text\(\s*\1\s*\)\s*;?\s*$/u;
1355
+ const CODE_MODE_NATIVE_PATCH_RESULT_RE = /^\s*Script (completed|failed)\s*\r?\nWall time\s+\d+(?:\.\d+)?\s+seconds\s*\r?\nOutput:\s*([\s\S]*?)\s*$/iu;
1356
+ function readCodeModeNativePatchInput(source) {
1357
+ if (typeof source !== "string") return;
1358
+ const match = CODE_MODE_NATIVE_PATCH_SOURCE_RE.exec(source);
1359
+ if (!match?.[2]) return;
1360
+ try {
1361
+ const patch = JSON.parse(match[2]);
1362
+ return typeof patch === "string" && /^\*\*\* Begin Patch\r?\n[\s\S]*\r?\n\*\*\* End Patch(?:\r?\n)?$/u.test(patch) ? patch : void 0;
1363
+ } catch {
1364
+ return;
1365
+ }
1366
+ }
1367
+ function readInterceptedNativePatchInput(command) {
1368
+ if (typeof command !== "string") return;
1369
+ const lines = command.replace(/\r\n?/gu, "\n").split("\n");
1370
+ const patchStart = lines.indexOf("*** Begin Patch");
1371
+ const invocation = /^[\t ]*(?:cd[\t ]+(?:'([^'\n]+)'|([A-Za-z0-9_./-]+))[\t ]+&&[\t ]+)?apply_patch[\t ]*<<-?[\t ]*'([^'\n]+)'[\t ]*$/u.exec(lines[0] ?? "");
1372
+ if (!invocation || patchStart !== 1) return;
1373
+ const patchEnd = lines.indexOf("*** End Patch", patchStart + 1);
1374
+ const cwd = invocation[1] ?? invocation[2];
1375
+ const delimiter = invocation[3];
1376
+ if (patchEnd < 0 || lines[patchEnd + 1] !== delimiter || lines.slice(patchEnd + 2).some((line) => line.trim().length > 0)) return;
1377
+ return {
1378
+ input: `${lines.slice(patchStart, patchEnd + 1).join("\n")}\n`,
1379
+ ...cwd ? { cwd } : {}
1380
+ };
1381
+ }
1354
1382
  var CodexToolTranscriptProjection = class {
1355
1383
  constructor(params, threadId, turnId, progress, nextTranscriptTimestamp, options = {}) {
1356
1384
  this.params = params;
@@ -1370,6 +1398,8 @@ var CodexToolTranscriptProjection = class {
1370
1398
  this.afterToolCallObservedItemIds = /* @__PURE__ */ new Set();
1371
1399
  this.nativeMcpAppResultDetails = /* @__PURE__ */ new Map();
1372
1400
  this.nativeMcpAppResultDetailsAttempted = /* @__PURE__ */ new Set();
1401
+ this.rawNativeToolOutputByCallId = /* @__PURE__ */ new Map();
1402
+ this.codeModeNativePatchInputsByCallId = /* @__PURE__ */ new Map();
1373
1403
  }
1374
1404
  get transcriptMessages() {
1375
1405
  return this.messages;
@@ -1381,13 +1411,14 @@ var CodexToolTranscriptProjection = class {
1381
1411
  arguments: sanitizeCodexToolArguments(params.arguments)
1382
1412
  });
1383
1413
  }
1384
- recordDynamicToolResult(params) {
1414
+ recordDynamicToolResult(params, resultContentSource) {
1385
1415
  this.recordToolResult({
1386
1416
  id: params.callId,
1387
1417
  name: params.tool,
1388
1418
  text: collectDynamicToolContentText(params.contentItems),
1389
1419
  isError: !params.success,
1390
- details: params.details
1420
+ details: params.details,
1421
+ ...resultContentSource ? { resultContentSource } : {}
1391
1422
  });
1392
1423
  }
1393
1424
  recordNativeToolCall(item) {
@@ -1405,10 +1436,91 @@ var CodexToolTranscriptProjection = class {
1405
1436
  if (name) this.recordToolResult({
1406
1437
  id: item.id,
1407
1438
  name,
1408
- text: itemTranscriptResultText(item, this.progress.outputTextByItem),
1439
+ text: this.rawNativeToolOutputByCallId.get(item.id) ?? itemTranscriptResultText(item, this.progress.outputTextByItem),
1409
1440
  isError: isNonSuccessItemStatus(itemStatus(item)),
1410
- details
1411
- });
1441
+ details,
1442
+ ...item.type === "webSearch" ? { resultContentSource: "network" } : {}
1443
+ });
1444
+ }
1445
+ recordRawNativeToolItem(item) {
1446
+ const type = typeof item.type === "string" ? item.type : void 0;
1447
+ const callId = typeof item.call_id === "string" ? item.call_id : typeof item.callId === "string" ? item.callId : void 0;
1448
+ if (!callId) return;
1449
+ if ((type === "custom_tool_call" || type === "function_call") && (item.name === "apply_patch" || item.name === "exec_command" || item.name === "exec")) {
1450
+ let args;
1451
+ if (type === "custom_tool_call" && item.name === "apply_patch" && typeof item.input === "string") args = { input: item.input };
1452
+ else if (type === "custom_tool_call" && item.name === "exec") {
1453
+ const input = readCodeModeNativePatchInput(item.input);
1454
+ if (input) this.codeModeNativePatchInputsByCallId.set(callId, input);
1455
+ return;
1456
+ } else if (type === "function_call" && typeof item.arguments === "string") try {
1457
+ const parsed = JSON.parse(item.arguments);
1458
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
1459
+ const parsedArguments = parsed;
1460
+ if (item.name === "apply_patch") args = parsedArguments;
1461
+ else {
1462
+ const patch = readInterceptedNativePatchInput(typeof parsedArguments.cmd === "string" ? parsedArguments.cmd : typeof parsedArguments.command === "string" ? parsedArguments.command : void 0);
1463
+ if (patch) {
1464
+ const workdir = typeof parsedArguments.workdir === "string" ? parsedArguments.workdir : typeof parsedArguments.cwd === "string" ? parsedArguments.cwd : void 0;
1465
+ const cwd = patch.cwd ? workdir && !path.isAbsolute(patch.cwd) ? path.join(workdir, patch.cwd) : patch.cwd : workdir;
1466
+ args = {
1467
+ input: patch.input,
1468
+ ...cwd ? { cwd } : {}
1469
+ };
1470
+ }
1471
+ }
1472
+ }
1473
+ } catch {
1474
+ return;
1475
+ }
1476
+ if (args) this.recordToolCall({
1477
+ id: callId,
1478
+ name: "apply_patch",
1479
+ arguments: args
1480
+ });
1481
+ return;
1482
+ }
1483
+ if (type !== "custom_tool_call_output" && type !== "function_call_output" || this.namesById.get(callId) !== "apply_patch" && !this.codeModeNativePatchInputsByCallId.has(callId)) return;
1484
+ const text = typeof item.output === "string" ? item.output : Array.isArray(item.output) ? collectDynamicToolContentText(item.output) : "";
1485
+ if (!text.trim()) return;
1486
+ const codeModePatchInput = this.codeModeNativePatchInputsByCallId.get(callId);
1487
+ if (codeModePatchInput) {
1488
+ this.codeModeNativePatchInputsByCallId.delete(callId);
1489
+ const execution = CODE_MODE_NATIVE_PATCH_RESULT_RE.exec(text);
1490
+ if (execution?.[1]?.toLowerCase() === "completed" && execution[2]?.trim() === "{}") return;
1491
+ if (execution?.[1]?.toLowerCase() === "failed") {
1492
+ const failure = execution[2]?.replace(/^Script error:\s*/iu, "").trim() || text;
1493
+ this.recordToolCall({
1494
+ id: callId,
1495
+ name: "apply_patch",
1496
+ arguments: { input: codeModePatchInput }
1497
+ });
1498
+ this.recordToolResult({
1499
+ id: callId,
1500
+ name: "apply_patch",
1501
+ text: failure,
1502
+ isError: true
1503
+ });
1504
+ }
1505
+ return;
1506
+ }
1507
+ this.rawNativeToolOutputByCallId.set(callId, text);
1508
+ const result = this.messages.find((message) => message.role === "toolResult" && message.toolCallId === callId);
1509
+ if (!result) {
1510
+ if (NATIVE_PATCH_REJECTION_RE.test(text)) this.recordToolResult({
1511
+ id: callId,
1512
+ name: "apply_patch",
1513
+ text,
1514
+ isError: true
1515
+ });
1516
+ return;
1517
+ }
1518
+ result.content = this.createToolResultMessage({
1519
+ id: callId,
1520
+ name: "apply_patch",
1521
+ text,
1522
+ isError: result.isError === true
1523
+ }).content;
1412
1524
  }
1413
1525
  async recordNativeToolResultWithDetails(item) {
1414
1526
  this.recordNativeToolResult(item, await this.prepareNativeMcpAppResultDetails(item));
@@ -1525,10 +1637,11 @@ var CodexToolTranscriptProjection = class {
1525
1637
  output: text
1526
1638
  });
1527
1639
  }
1528
- if (!params.recordPromptError) {
1640
+ if (params.terminalDisposition === "tool_error") {
1529
1641
  this.recordMissingToolError(missingTranscriptIds, missingTrajectoryIds);
1530
1642
  return;
1531
1643
  }
1644
+ if (params.terminalDisposition === "diagnostic_only") return;
1532
1645
  const missingCount = (/* @__PURE__ */ new Set([...missingTranscriptIds, ...missingTrajectoryIds])).size;
1533
1646
  return missingCount === 1 ? MISSING_TOOL_RESULT_ERROR : `${MISSING_TOOL_RESULT_ERROR} missingToolResultCount=${missingCount}`;
1534
1647
  }
@@ -1615,6 +1728,7 @@ var CodexToolTranscriptProjection = class {
1615
1728
  text
1616
1729
  }],
1617
1730
  ...params.details !== void 0 ? { details: params.details } : {},
1731
+ ...params.resultContentSource ? { __openclaw: { resultContentSource: params.resultContentSource } } : {},
1618
1732
  timestamp: this.nextTranscriptTimestamp()
1619
1733
  };
1620
1734
  }
@@ -1774,56 +1888,127 @@ var CodexEventProjection = class {
1774
1888
  //#region extensions/codex/src/app-server/event-projector-media.ts
1775
1889
  const GENERATED_IMAGE_MEDIA_SUBDIR = "tool-image-generation";
1776
1890
  var CodexGeneratedMediaProjection = class {
1777
- constructor(config) {
1891
+ constructor(config, remote) {
1778
1892
  this.config = config;
1893
+ this.remote = remote;
1779
1894
  this.itemIds = /* @__PURE__ */ new Set();
1780
1895
  this.urlsByItemId = /* @__PURE__ */ new Map();
1896
+ this.gatewayMaterializedItemIds = /* @__PURE__ */ new Set();
1897
+ this.pendingMaterializationsByItemId = /* @__PURE__ */ new Map();
1781
1898
  }
1782
1899
  hasGeneratedMedia() {
1783
1900
  return this.itemIds.size > 0;
1784
1901
  }
1785
- recordNative(item) {
1902
+ async recordNative(item) {
1786
1903
  if (item?.type !== "imageGeneration") return;
1904
+ this.itemIds.add(item.id);
1905
+ const result = readItemString(item, "result");
1906
+ if (result) {
1907
+ await this.recordImage({
1908
+ itemId: item.id,
1909
+ result,
1910
+ revisedPrompt: readItemString(item, "revisedPrompt"),
1911
+ source: "native"
1912
+ });
1913
+ return;
1914
+ }
1787
1915
  const savedPath = readItemString(item, "savedPath")?.trim();
1788
- if (savedPath) this.recordUrl({
1789
- itemId: item.id,
1790
- mediaUrl: savedPath
1791
- });
1916
+ if (savedPath) {
1917
+ if (this.remote?.remoteWorkspaceRoot) {
1918
+ if (!this.remote.readFile) {
1919
+ embeddedAgentLog.warn("codex remote image has no app-server file transfer", { itemId: item.id });
1920
+ return;
1921
+ }
1922
+ try {
1923
+ const response = await this.remote.readFile({
1924
+ path: savedPath,
1925
+ maxBytes: resolveGeneratedMediaMaxBytes(this.config, "image"),
1926
+ signal: this.remote.signal,
1927
+ timeoutMs: this.remote.requestTimeoutMs
1928
+ });
1929
+ if (!response || typeof response.dataBase64 !== "string" || !response.dataBase64) {
1930
+ embeddedAgentLog.warn("codex remote image file returned no inline bytes", { itemId: item.id });
1931
+ return;
1932
+ }
1933
+ await this.recordImage({
1934
+ itemId: item.id,
1935
+ result: response.dataBase64,
1936
+ revisedPrompt: readItemString(item, "revisedPrompt"),
1937
+ source: "native"
1938
+ });
1939
+ } catch (error) {
1940
+ embeddedAgentLog.warn("codex app-server remote image file read failed", {
1941
+ itemId: item.id,
1942
+ error
1943
+ });
1944
+ }
1945
+ return;
1946
+ }
1947
+ this.recordUrl({
1948
+ itemId: item.id,
1949
+ mediaUrl: savedPath
1950
+ });
1951
+ }
1792
1952
  }
1793
1953
  async recordRaw(item) {
1794
1954
  if (readString$6(item, "type") !== "image_generation_call") return;
1795
1955
  const result = readString$6(item, "result");
1796
1956
  if (!result) return;
1797
1957
  const itemId = readString$6(item, "id") ?? `raw-image-${this.itemIds.size}`;
1798
- this.itemIds.add(itemId);
1958
+ await this.recordImage({
1959
+ itemId,
1960
+ result,
1961
+ revisedPrompt: readString$6(item, "revised_prompt") ?? readString$6(item, "revisedPrompt"),
1962
+ source: "raw"
1963
+ });
1964
+ }
1965
+ async recordImage(params) {
1966
+ this.itemIds.add(params.itemId);
1967
+ if (this.gatewayMaterializedItemIds.has(params.itemId)) return;
1968
+ let pending = this.pendingMaterializationsByItemId.get(params.itemId);
1969
+ while (pending) {
1970
+ await pending;
1971
+ if (this.gatewayMaterializedItemIds.has(params.itemId)) return;
1972
+ pending = this.pendingMaterializationsByItemId.get(params.itemId);
1973
+ }
1974
+ const materialization = this.materializeImage(params);
1975
+ this.pendingMaterializationsByItemId.set(params.itemId, materialization);
1976
+ try {
1977
+ await materialization;
1978
+ } finally {
1979
+ if (this.pendingMaterializationsByItemId.get(params.itemId) === materialization) this.pendingMaterializationsByItemId.delete(params.itemId);
1980
+ }
1981
+ }
1982
+ async materializeImage(params) {
1799
1983
  const maxBytes = resolveGeneratedMediaMaxBytes(this.config, "image");
1800
- const estimatedDecodedBytes = estimateBase64DecodedBytes(result);
1984
+ const estimatedDecodedBytes = estimateBase64DecodedBytes(params.result);
1801
1985
  if (estimatedDecodedBytes !== void 0 && estimatedDecodedBytes > maxBytes) {
1802
- embeddedAgentLog.warn("codex app-server raw image generation result exceeds media limit", {
1803
- itemId,
1986
+ embeddedAgentLog.warn(`codex app-server ${params.source} image generation result exceeds media limit`, {
1987
+ itemId: params.itemId,
1804
1988
  estimatedDecodedBytes,
1805
1989
  maxBytes
1806
1990
  });
1807
1991
  return;
1808
1992
  }
1809
1993
  const asset = generatedImageAssetFromBase64({
1810
- base64: result,
1994
+ base64: params.result,
1811
1995
  index: this.itemIds.size,
1812
- revisedPrompt: readString$6(item, "revised_prompt") ?? readString$6(item, "revisedPrompt"),
1996
+ revisedPrompt: params.revisedPrompt,
1813
1997
  fileNamePrefix: "codex-image-generation",
1814
1998
  sniffMimeType: true
1815
1999
  });
1816
2000
  if (!asset) return;
1817
2001
  try {
1818
2002
  const saved = await saveMediaBuffer(asset.buffer, asset.mimeType, GENERATED_IMAGE_MEDIA_SUBDIR, maxBytes, asset.fileName);
2003
+ this.gatewayMaterializedItemIds.add(params.itemId);
1819
2004
  this.recordUrl({
1820
- itemId,
2005
+ itemId: params.itemId,
1821
2006
  mediaUrl: saved.path,
1822
2007
  replaceExisting: true
1823
2008
  });
1824
2009
  } catch (error) {
1825
- embeddedAgentLog.warn("codex app-server raw image generation result save failed", {
1826
- itemId,
2010
+ embeddedAgentLog.warn(`codex app-server ${params.source} image generation result save failed`, {
2011
+ itemId: params.itemId,
1827
2012
  error
1828
2013
  });
1829
2014
  }
@@ -1985,6 +2170,28 @@ function reasoningMethodOrder(method) {
1985
2170
  }
1986
2171
  //#endregion
1987
2172
  //#region extensions/codex/src/app-server/event-projector-snapshot.ts
2173
+ function readTurnTaintMetadata(message) {
2174
+ const metadata = message["__openclaw"];
2175
+ return metadata && typeof metadata === "object" && !Array.isArray(metadata) ? metadata : void 0;
2176
+ }
2177
+ function applyStickyTurnTaint(messages) {
2178
+ let tainted = false;
2179
+ return messages.map((message) => {
2180
+ if (message.role === "user") {
2181
+ tainted = false;
2182
+ return message;
2183
+ }
2184
+ const metadata = readTurnTaintMetadata(message);
2185
+ tainted ||= metadata?.turnTainted === true || metadata?.resultContentSource === "network";
2186
+ return message.role === "assistant" && tainted ? {
2187
+ ...message,
2188
+ __openclaw: {
2189
+ ...metadata,
2190
+ turnTainted: true
2191
+ }
2192
+ } : message;
2193
+ });
2194
+ }
1988
2195
  function buildCodexMessagesSnapshot(params) {
1989
2196
  const messages = promptSnapshot(params.runParams, params.turnId, params.upstreamUserText);
1990
2197
  if (params.reasoningText) messages.push(attachCodexMirrorIdentity(params.createAssistantMirrorMessage("Codex reasoning", params.reasoningText), `${params.turnId}:reasoning`));
@@ -1992,7 +2199,7 @@ function buildCodexMessagesSnapshot(params) {
1992
2199
  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
2200
  messages.push(...visibleWorkMessages);
1994
2201
  if (params.lastAssistant) messages.push(attachCodexMirrorIdentity(params.lastAssistant, `${params.turnId}:assistant`));
1995
- return messages.map((message) => projectAgentHarnessTranscriptMessageForDisplay({
2202
+ return applyStickyTurnTaint(messages).map((message) => projectAgentHarnessTranscriptMessageForDisplay({
1996
2203
  hidden: params.runParams.trigger === "memory",
1997
2204
  message
1998
2205
  }));
@@ -2153,11 +2360,17 @@ var CodexAppServerEventProjector = class {
2153
2360
  this.promptErrorSource = null;
2154
2361
  this.synthesizedMissingToolResultError = null;
2155
2362
  this.aborted = false;
2363
+ this.responseCompletions = new CodexResponseCompletionProjection();
2156
2364
  this.completedCompactionCount = 0;
2157
2365
  this.lastTranscriptTimestamp = 0;
2158
2366
  this.diagnostics = new CodexProjectionDiagnostics(threadId, turnId);
2159
2367
  this.nativeToolLifecycleProjector = new CodexNativeToolLifecycleProjector(params, threadId, turnId, { runAbortSignal: options.runAbortSignal });
2160
- this.generatedMediaProjection = new CodexGeneratedMediaProjection(params.config);
2368
+ this.generatedMediaProjection = new CodexGeneratedMediaProjection(params.config, {
2369
+ remoteWorkspaceRoot: options.remoteWorkspaceRoot,
2370
+ readFile: options.readRemoteWorkspaceFile,
2371
+ requestTimeoutMs: options.remoteWorkspaceRequestTimeoutMs,
2372
+ signal: options.runAbortSignal
2373
+ });
2161
2374
  this.toolProgressProjection = new CodexToolProgressProjection(params);
2162
2375
  this.toolTranscriptProjection = new CodexToolTranscriptProjection(params, threadId, turnId, this.toolProgressProjection, () => this.nextTranscriptTimestamp(), {
2163
2376
  nativePostToolUseRelayEnabled: options.nativePostToolUseRelayEnabled,
@@ -2260,13 +2473,13 @@ var CodexAppServerEventProjector = class {
2260
2473
  await this.handleTurnCompleted(params);
2261
2474
  break;
2262
2475
  case "rawResponse/completed":
2263
- this.handleRawResponseCompleted(params);
2476
+ this.responseCompletions.record(params);
2264
2477
  break;
2265
2478
  case "rawResponseItem/completed":
2266
2479
  await this.handleRawResponseItemCompleted(params);
2267
2480
  break;
2268
2481
  case "error":
2269
- this.responseUsage = void 0;
2482
+ this.responseCompletions.clear();
2270
2483
  if (params.willRetry === true) break;
2271
2484
  this.promptError = this.formatCodexErrorMessage(params) ?? "codex app-server error";
2272
2485
  this.promptErrorSource = "prompt";
@@ -2294,13 +2507,14 @@ var CodexAppServerEventProjector = class {
2294
2507
  const commentaryMessages = this.assistantProjection.collectCommentaryMessages();
2295
2508
  const reasoningText = this.reasoningProjection.reasoningText();
2296
2509
  const planText = this.reasoningProjection.planText();
2297
- const projectedUsage = this.aborted ? this.tokenUsage : this.responseUsage ?? this.tokenUsage;
2510
+ const completedUsage = this.responseCompletions.usage ?? this.tokenUsage;
2511
+ const projectedUsage = this.aborted ? this.tokenUsage : completedUsage;
2298
2512
  const hasAssistantItemText = this.assistantProjection.hasAssistantItemTextForSynthesis();
2299
2513
  const legacyFailClosed = !this.completedTurn || this.completedTurn.status !== "completed" || hasAssistantItemText;
2300
2514
  const hasDeliverableAssistantOnCompletedTurn = this.completedTurn?.status === "completed" && assistantTexts.some((text) => text.trim().length > 0);
2301
2515
  const synthesizedMissingToolResultError = this.toolTranscriptProjection.synthesizeMissingToolResults({
2302
2516
  synthesize: legacyFailClosed,
2303
- recordPromptError: legacyFailClosed && !hasDeliverableAssistantOnCompletedTurn && !this.aborted
2517
+ terminalDisposition: this.aborted ? "tool_error" : hasDeliverableAssistantOnCompletedTurn ? "diagnostic_only" : "prompt_error"
2304
2518
  });
2305
2519
  if (synthesizedMissingToolResultError) {
2306
2520
  this.synthesizedMissingToolResultError = synthesizedMissingToolResultError;
@@ -2345,6 +2559,7 @@ var CodexAppServerEventProjector = class {
2345
2559
  ...agentHarnessResultClassification ? { agentHarnessResultClassification } : {},
2346
2560
  bootstrapPromptWarningSignaturesSeen: this.params.bootstrapPromptWarningSignaturesSeen,
2347
2561
  bootstrapPromptWarningSignature: this.params.bootstrapPromptWarningSignature,
2562
+ ...this.responseCompletions.modelIterations > 0 ? { modelIterations: this.responseCompletions.modelIterations } : {},
2348
2563
  messagesSnapshot,
2349
2564
  assistantTexts,
2350
2565
  toolMetas,
@@ -2383,7 +2598,8 @@ var CodexAppServerEventProjector = class {
2383
2598
  }
2384
2599
  recordDynamicToolResult(params) {
2385
2600
  this.toolProgressProjection.recordDynamicToolResult(params);
2386
- this.toolTranscriptProjection.recordDynamicToolResult(params);
2601
+ const source = this.options.resolveDynamicToolResultContentSource?.(params.tool);
2602
+ this.toolTranscriptProjection.recordDynamicToolResult(params, source);
2387
2603
  }
2388
2604
  markTimedOut() {
2389
2605
  this.aborted = true;
@@ -2392,7 +2608,7 @@ var CodexAppServerEventProjector = class {
2392
2608
  }
2393
2609
  markAborted() {
2394
2610
  this.aborted = true;
2395
- this.responseUsage = void 0;
2611
+ this.responseCompletions.clear();
2396
2612
  }
2397
2613
  isCompacting() {
2398
2614
  return this.activeCompactionItemIds.size > 0;
@@ -2462,7 +2678,7 @@ var CodexAppServerEventProjector = class {
2462
2678
  }
2463
2679
  this.assistantProjection.recordItemCompleted(item, itemId, this.activeItemIds);
2464
2680
  this.reasoningProjection.recordItem(item);
2465
- this.generatedMediaProjection.recordNative(item);
2681
+ await this.generatedMediaProjection.recordNative(item);
2466
2682
  if (item?.type === "contextCompaction" && itemId) {
2467
2683
  this.activeCompactionItemIds.delete(itemId);
2468
2684
  this.completedCompactionCount += 1;
@@ -2517,15 +2733,11 @@ var CodexAppServerEventProjector = class {
2517
2733
  }
2518
2734
  });
2519
2735
  }
2520
- handleRawResponseCompleted(params) {
2521
- const usage = isJsonObject(params.usage) ? params.usage : void 0;
2522
- this.responseUsage = usage ? normalizeCodexResponseTokenUsage(usage) : void 0;
2523
- }
2524
2736
  async handleTurnCompleted(params) {
2525
2737
  const turn = readCodexTurn(params.turn);
2526
2738
  if (!turn || turn.id !== this.turnId) return;
2527
2739
  this.completedTurn = turn;
2528
- if (turn.status !== "completed") this.responseUsage = void 0;
2740
+ if (turn.status !== "completed") this.responseCompletions.clear();
2529
2741
  if (turn.status === "failed") {
2530
2742
  const usageLimitMessage = formatCodexUsageLimitErrorMessage({
2531
2743
  message: turn.error?.message,
@@ -2549,7 +2761,7 @@ var CodexAppServerEventProjector = class {
2549
2761
  this.diagnostics.warnUnknownItemStatus(item);
2550
2762
  this.assistantProjection.recordSnapshotItem(item);
2551
2763
  this.reasoningProjection.recordItem(item);
2552
- this.generatedMediaProjection.recordNative(item);
2764
+ await this.generatedMediaProjection.recordNative(item);
2553
2765
  this.toolProgressProjection.recordToolMeta(item);
2554
2766
  this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
2555
2767
  await this.emitSnapshotOnlyNativeToolProgress(item);
@@ -2593,6 +2805,7 @@ var CodexAppServerEventProjector = class {
2593
2805
  async handleRawResponseItemCompleted(params) {
2594
2806
  const item = isJsonObject(params.item) ? params.item : void 0;
2595
2807
  if (!item) return;
2808
+ this.toolTranscriptProjection.recordRawNativeToolItem(item);
2596
2809
  this.assistantProjection.handleRawResponseItemCompleted(item, this.activeItemIds);
2597
2810
  await this.generatedMediaProjection.recordRaw(item);
2598
2811
  }
@@ -2958,7 +3171,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
2958
3171
  const { runtime, attemptTools } = context;
2959
3172
  const { connection } = runtime;
2960
3173
  const { params, runAbortController, terminalState, abortExplicitly, abortFromUpstream, bindingStore, bindingIdentity, sessionAgentId, sandboxSessionKey, effectiveCwd } = connection;
2961
- const { dynamicToolParams, computerContextEpoch } = attemptTools;
3174
+ const { dynamicToolParams, computerContextEpoch, toolBridge } = attemptTools;
2962
3175
  const { state, userInputBridgeRef, steeringQueueRef, turnWatches } = turnRuntime;
2963
3176
  const { emitExecutionPhaseOnce, emitLifecycleStart, maybeAnnounceFastModeAutoOff } = lifecycle;
2964
3177
  const { enqueueNotification } = notifications;
@@ -2998,7 +3211,17 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
2998
3211
  nativePostToolUseRelayEnabled: resourceState.nativeHookRelay?.allowedEvents.includes("post_tool_use") === true && resourceState.nativeHookRelay.shouldRelayEvent("post_tool_use"),
2999
3212
  readRecentRateLimits: () => readRecentCodexRateLimits(resourceState.client),
3000
3213
  runAbortSignal: runAbortController.signal,
3214
+ remoteWorkspaceRoot: connection.appServer.remoteWorkspaceRoot,
3215
+ remoteWorkspaceRequestTimeoutMs: connection.appServer.requestTimeoutMs,
3216
+ readRemoteWorkspaceFile: ({ path, maxBytes, signal, timeoutMs }) => readBoundedCodexRemoteWorkspaceFile({
3217
+ client: resourceState.client,
3218
+ path,
3219
+ maxBytes,
3220
+ signal,
3221
+ timeoutMs
3222
+ }),
3001
3223
  trajectoryRecorder,
3224
+ resolveDynamicToolResultContentSource: toolBridge.resultContentSourceForTool,
3002
3225
  onNativeToolResultRecorded: maybeAnnounceFastModeAutoOff,
3003
3226
  ...prepareNativeMcpAppResultDetails ? { prepareNativeMcpAppResultDetails } : {},
3004
3227
  upstreamUserText: turnState.codexTurnPromptText,
@@ -3164,15 +3387,27 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
3164
3387
  });
3165
3388
  if (!state.timedOut && !runAbortController.signal.aborted) await steeringQueueRef.current?.flushPending();
3166
3389
  const retainLiveIncognitoThread = terminalState.turnSucceeded && isIncognitoSessionKey(params.sessionKey);
3390
+ const retainedPersistentThread = terminalState.turnSucceeded && !isIncognitoSessionKey(params.sessionKey) && params.cleanupBundleMcpOnRunEnd !== true && !params.contextEngine && resourceState.thread.liveThreadConfigFingerprint !== void 0 && resourceState.thread.clientId === resolveCodexAppServerClientInstanceId(resourceState.client) && resourceState.thread.preserveNativeModel !== true && resourceState.thread.connectionScope !== "supervision" && !resourceState.thread.ringZeroConfigFingerprint && !resourceState.thread.contextEngine ? await retainCodexAppServerLiveThread(resourceState.client, resourceState.thread.threadId, async (previousThreadId) => {
3391
+ if (!await unsubscribeCodexThreadBestEffort(resourceState.client, {
3392
+ threadId: previousThreadId,
3393
+ timeoutMs: 5e3
3394
+ })) {
3395
+ await closeCodexStartupClientBestEffort(resourceState.client);
3396
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex retained thread subscription could not be released: ${previousThreadId}`);
3397
+ }
3398
+ }, resourceState.thread.liveThreadConfigFingerprint) : void 0;
3399
+ const retainLiveThread = retainLiveIncognitoThread || retainedPersistentThread !== void 0;
3167
3400
  const bindingReleased = isIncognitoSessionKey(params.sessionKey) && !retainLiveIncognitoThread ? await bindingStore.mutate(bindingIdentity, {
3168
3401
  kind: "clear",
3169
3402
  threadId: resourceState.thread.threadId
3170
3403
  }) : 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
- });
3404
+ if (!state.timedOut && !retainLiveThread) {
3405
+ if (bindingReleased) {
3406
+ if (!await unsubscribeCodexThreadBestEffort(resourceState.client, {
3407
+ threadId: resourceState.thread.threadId,
3408
+ timeoutMs: 5e3
3409
+ })) await closeCodexStartupClientBestEffort(resourceState.client);
3410
+ }
3176
3411
  }
3177
3412
  userInputBridgeRef.current?.cancelPending();
3178
3413
  turnWatches.clearAllTimers();
@@ -3230,14 +3465,7 @@ function estimateCodexAppServerProjectedTurnTokens(params) {
3230
3465
  }
3231
3466
  async function ensureCodexWorkspaceDirOnce(workspaceDir) {
3232
3467
  const normalized = path.resolve(workspaceDir);
3233
- if (codexWorkspaceDirCache.has(normalized)) {
3234
- try {
3235
- if ((await fs.stat(normalized)).isDirectory()) return;
3236
- } catch (error) {
3237
- if ((typeof error === "object" && error ? error.code : void 0) !== "ENOENT") throw error;
3238
- }
3239
- codexWorkspaceDirCache.delete(normalized);
3240
- }
3468
+ if (codexWorkspaceDirCache.has(normalized)) return;
3241
3469
  await fs.mkdir(normalized, { recursive: true });
3242
3470
  codexWorkspaceDirCache.add(normalized);
3243
3471
  }
@@ -3278,6 +3506,7 @@ const CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS = 3e5;
3278
3506
  const CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS = 2e4;
3279
3507
  const CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_TOKENS = 8e3;
3280
3508
  const CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_RATIO = .5;
3509
+ const CODEX_APP_SERVER_ROLLOUT_TAIL_READ_BYTES = 64 * 1024;
3281
3510
  const CODEX_APP_SERVER_BYTE_UNITS = {
3282
3511
  b: 1,
3283
3512
  k: 1024,
@@ -3306,7 +3535,7 @@ function parseCodexAppServerByteLimit(value) {
3306
3535
  if (multiplier === void 0) return;
3307
3536
  return Math.max(1, Math.round(amount * multiplier));
3308
3537
  }
3309
- async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codexHome) {
3538
+ async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codexHome, rolloutPath) {
3310
3539
  const resolvedAgentDir = path.resolve(agentDir);
3311
3540
  const resolvedCodexHome = codexHome?.trim() ? path.resolve(codexHome) : resolveCodexAppServerHomeDir(resolvedAgentDir);
3312
3541
  const roots = [
@@ -3315,6 +3544,22 @@ async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codex
3315
3544
  path.join(resolvedAgentDir, "agent", "codex-home", "sessions"),
3316
3545
  path.join(path.dirname(resolvedAgentDir), "codex-home", "sessions")
3317
3546
  ];
3547
+ const rolloutRoot = rolloutPath ? roots.find((root) => {
3548
+ const relativePath = path.relative(root, rolloutPath);
3549
+ return relativePath !== "" && relativePath !== ".." && !relativePath.startsWith(`..${path.sep}`) && !path.isAbsolute(relativePath);
3550
+ }) : void 0;
3551
+ if (rolloutPath && rolloutRoot && path.isAbsolute(rolloutPath) && path.extname(rolloutPath) === ".jsonl" && path.basename(rolloutPath).includes(threadId)) try {
3552
+ const opened = await (await root(rolloutRoot, {
3553
+ hardlinks: "reject",
3554
+ maxBytes: Number.MAX_SAFE_INTEGER,
3555
+ symlinks: "reject"
3556
+ })).open(path.relative(rolloutRoot, rolloutPath));
3557
+ return [{
3558
+ path: opened.realPath,
3559
+ bytes: opened.stat.size,
3560
+ handle: opened.handle
3561
+ }];
3562
+ } catch {}
3318
3563
  const files = [];
3319
3564
  const visited = /* @__PURE__ */ new Set();
3320
3565
  for (const root of roots) {
@@ -3393,23 +3638,48 @@ async function readCodexSessionRecordForSessionFile(sessionFile) {
3393
3638
  function isSqliteSessionFileMarker(sessionFile) {
3394
3639
  return parseSqliteSessionFileMarker(sessionFile) !== void 0;
3395
3640
  }
3396
- async function readCodexAppServerRolloutTokenSnapshot(file) {
3397
- let handle;
3398
- try {
3641
+ async function readCodexAppServerRolloutTokenSnapshot(file, openedHandle) {
3642
+ let handle = openedHandle;
3643
+ if (!handle) try {
3399
3644
  handle = await fs.open(file, "r");
3400
3645
  } catch {
3401
3646
  return;
3402
3647
  }
3403
3648
  let snapshot;
3404
3649
  try {
3405
- for await (const line of handle.readLines()) {
3650
+ let position = (await handle.stat()).size;
3651
+ const partialLineFragments = [];
3652
+ const applySnapshotLine = (line) => {
3406
3653
  const lineSnapshot = readCodexAppServerRolloutTokenSnapshotLine(line);
3407
- if (lineSnapshot !== void 0) {
3408
- snapshot ??= {};
3409
- if (lineSnapshot.totalTokens !== void 0) snapshot.totalTokens = lineSnapshot.totalTokens;
3410
- if (lineSnapshot.modelContextWindow !== void 0) snapshot.modelContextWindow = lineSnapshot.modelContextWindow;
3654
+ if (lineSnapshot === void 0) return false;
3655
+ snapshot ??= {};
3656
+ snapshot.totalTokens ??= lineSnapshot.totalTokens;
3657
+ snapshot.modelContextWindow ??= lineSnapshot.modelContextWindow;
3658
+ return snapshot.totalTokens !== void 0 && snapshot.modelContextWindow !== void 0;
3659
+ };
3660
+ while (position > 0) {
3661
+ const bytesToRead = Math.min(position, CODEX_APP_SERVER_ROLLOUT_TAIL_READ_BYTES);
3662
+ const nextPosition = position - bytesToRead;
3663
+ const chunk = Buffer.allocUnsafe(bytesToRead);
3664
+ let bytesRead = 0;
3665
+ while (bytesRead < bytesToRead) {
3666
+ const result = await handle.read(chunk, bytesRead, bytesToRead - bytesRead, nextPosition + bytesRead);
3667
+ if (result.bytesRead === 0) return snapshot;
3668
+ bytesRead += result.bytesRead;
3669
+ }
3670
+ let lineEnd = bytesRead;
3671
+ for (let index = bytesRead - 1; index >= 0; index -= 1) {
3672
+ if (chunk[index] !== 10) continue;
3673
+ const lineFragment = chunk.subarray(index + 1, lineEnd);
3674
+ const line = partialLineFragments.length === 0 ? lineFragment.toString("utf8") : Buffer.concat([lineFragment, ...partialLineFragments.toReversed()]).toString("utf8");
3675
+ partialLineFragments.length = 0;
3676
+ if (applySnapshotLine(line)) return snapshot;
3677
+ lineEnd = index;
3411
3678
  }
3679
+ if (lineEnd > 0) partialLineFragments.push(chunk.subarray(0, lineEnd));
3680
+ position = nextPosition;
3412
3681
  }
3682
+ if (partialLineFragments.length > 0) applySnapshotLine(Buffer.concat(partialLineFragments.toReversed()).toString("utf8"));
3413
3683
  } finally {
3414
3684
  await handle.close();
3415
3685
  }
@@ -3467,31 +3737,36 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
3467
3737
  if (!binding?.threadId) return binding;
3468
3738
  if (binding.connectionScope === "supervision") return binding;
3469
3739
  const sessionRecord = await readCodexSessionRecordForSessionFile(params.sessionFile);
3470
- const rolloutFiles = await listCodexAppServerRolloutFilesForThread(params.agentDir, binding.threadId, params.codexHome);
3471
- const compaction = readCompactionConfig(params.config);
3472
- const shouldDeferByteGuard = compaction?.truncateAfterCompaction === true && params.contextEngineActive === true && hasContextEngineThreadBootstrapProjection(binding);
3473
- if (compaction?.truncateAfterCompaction === true && !shouldDeferByteGuard) {
3474
- const maxBytes = parseCodexAppServerByteLimit(compaction.maxActiveTranscriptBytes);
3475
- if (maxBytes !== void 0) {
3476
- const oversizedFiles = rolloutFiles.filter((file) => file.bytes >= maxBytes);
3477
- if (oversizedFiles.length > 0) {
3478
- embeddedAgentLog.warn("codex app-server native transcript exceeded active byte limit; starting a fresh thread", {
3479
- threadId: binding.threadId,
3480
- maxBytes,
3481
- files: oversizedFiles.map((file) => ({
3482
- path: file.path,
3483
- bytes: file.bytes
3484
- }))
3485
- });
3486
- await params.bindingStore.mutate(params.identity, {
3487
- kind: "clear",
3488
- threadId: binding.threadId
3489
- });
3490
- return;
3491
- }
3740
+ const rolloutFiles = await listCodexAppServerRolloutFilesForThread(params.agentDir, binding.threadId, params.codexHome, binding.rolloutPath);
3741
+ const maxBytes = parseCodexAppServerByteLimit(readCompactionConfig(params.config)?.maxActiveTranscriptBytes);
3742
+ if (maxBytes !== void 0 && params.contextEngineActive === true && hasContextEngineThreadBootstrapProjection(binding)) embeddedAgentLog.debug("codex app-server deferring native transcript byte guard for context-engine thread bootstrap", {
3743
+ threadId: binding.threadId,
3744
+ engineId: binding.contextEngine?.engineId,
3745
+ epoch: binding.contextEngine?.projection?.epoch,
3746
+ fingerprint: binding.contextEngine?.projection?.fingerprint
3747
+ });
3748
+ else if (maxBytes !== void 0) {
3749
+ const oversizedFiles = rolloutFiles.filter((file) => file.bytes >= maxBytes);
3750
+ if (oversizedFiles.length > 0) {
3751
+ await Promise.all(rolloutFiles.map(async (file) => {
3752
+ await file.handle?.close();
3753
+ }));
3754
+ embeddedAgentLog.warn("codex app-server native transcript exceeded active byte limit; starting a fresh thread", {
3755
+ threadId: binding.threadId,
3756
+ maxBytes,
3757
+ files: oversizedFiles.map((file) => ({
3758
+ path: file.path,
3759
+ bytes: file.bytes
3760
+ }))
3761
+ });
3762
+ await params.bindingStore.mutate(params.identity, {
3763
+ kind: "clear",
3764
+ threadId: binding.threadId
3765
+ });
3766
+ return;
3492
3767
  }
3493
3768
  }
3494
- const nativeTokenSnapshots = await Promise.all(rolloutFiles.map(async (file) => readCodexAppServerRolloutTokenSnapshot(file.path)));
3769
+ const nativeTokenSnapshots = await Promise.all(rolloutFiles.map(async (file) => readCodexAppServerRolloutTokenSnapshot(file.path, file.handle)));
3495
3770
  const nativeTokens = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.totalTokens));
3496
3771
  const nativeModelContextWindow = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.modelContextWindow));
3497
3772
  const sessionModelContextWindow = typeof sessionRecord?.contextTokens === "number" && Number.isFinite(sessionRecord.contextTokens) && sessionRecord.contextTokens > 0 ? Math.floor(sessionRecord.contextTokens) : void 0;
@@ -3521,16 +3796,6 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
3521
3796
  });
3522
3797
  return;
3523
3798
  }
3524
- if (compaction?.truncateAfterCompaction !== true) return binding;
3525
- if (shouldDeferByteGuard) {
3526
- embeddedAgentLog.debug("codex app-server deferring native transcript byte guard for context-engine thread bootstrap", {
3527
- threadId: binding.threadId,
3528
- engineId: binding.contextEngine?.engineId,
3529
- epoch: binding.contextEngine?.projection?.epoch,
3530
- fingerprint: binding.contextEngine?.projection?.fingerprint
3531
- });
3532
- return binding;
3533
- }
3534
3799
  return binding;
3535
3800
  }
3536
3801
  //#endregion
@@ -3584,22 +3849,45 @@ async function prepareCodexAttemptConnection({ params, options }) {
3584
3849
  agentId: sessionAgentId
3585
3850
  });
3586
3851
  const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId);
3587
- const bindingIdentity = sessionBindingIdentity({
3852
+ let bindingIdentity = sessionBindingIdentity({
3588
3853
  sessionId: params.sessionId,
3589
3854
  sessionKey: params.sessionKey,
3590
3855
  agentId: params.agentId,
3591
3856
  config: params.config
3592
3857
  });
3593
- const bindingStore = options.bindingStore;
3858
+ let bindingStore = options.bindingStore;
3594
3859
  preDynamicStartupStages.mark("session-agent");
3595
3860
  let activeContextEngine = isActiveHarnessContextEngine(params.contextEngine) ? params.contextEngine : void 0;
3596
3861
  const isInactiveThreadBootstrapBinding = (binding) => !activeContextEngine && binding?.contextEngine?.projection?.mode === "thread_bootstrap";
3862
+ if (bindingIdentity.kind === "session" && bindingIdentity.sessionKey && (params.sessionTarget?.storePath || params.config?.session?.store)) {
3863
+ const authority = resolveCodexRunSessionBindingAuthority({
3864
+ identity: bindingIdentity,
3865
+ config: params.config,
3866
+ storePath: params.sessionTarget?.storePath
3867
+ });
3868
+ if (authority === "superseded") throw createCodexSessionGenerationSupersededError(bindingIdentity.sessionId);
3869
+ if (authority === "ephemeral") {
3870
+ const logicalIdentity = bindingIdentity;
3871
+ const physicalIdentity = {
3872
+ kind: "session",
3873
+ agentId: bindingIdentity.agentId,
3874
+ sessionId: bindingIdentity.sessionId
3875
+ };
3876
+ bindingStore = scopeCodexRunBindingStore({
3877
+ bindingStore,
3878
+ logicalIdentity,
3879
+ physicalIdentity
3880
+ });
3881
+ bindingIdentity = physicalIdentity;
3882
+ }
3883
+ }
3597
3884
  let startupBinding = await bindingStore.read(bindingIdentity);
3598
3885
  if (!startupBinding && bindingIdentity.kind === "session" && bindingIdentity.sessionKey) {
3599
3886
  if (!await reclaimCurrentCodexSessionGeneration({
3600
3887
  bindingStore,
3601
3888
  identity: bindingIdentity,
3602
- config: params.config
3889
+ config: params.config,
3890
+ storePath: params.sessionTarget?.storePath
3603
3891
  })) throw createCodexSessionGenerationSupersededError(bindingIdentity.sessionId);
3604
3892
  startupBinding = await bindingStore.read(bindingIdentity);
3605
3893
  }
@@ -3643,7 +3931,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
3643
3931
  authProfileId: resolvedStartupAuthProfileId,
3644
3932
  authProfileStore: params.authProfileStore,
3645
3933
  agentDir,
3646
- ...pluginConfig.appServer?.homeScope ? { homeScope: pluginConfig.appServer.homeScope } : {},
3934
+ homeScope: resolveCodexAppServerHomeScope({ appServer: pluginConfig.appServer }),
3647
3935
  config: params.config,
3648
3936
  subscriptionProfileRequiredError: "Prepared Codex subscription route requires a forwarded OpenAI OAuth or token profile.",
3649
3937
  subscriptionProfileUnusableError: "Prepared Codex subscription auth profile is unusable."
@@ -3669,15 +3957,16 @@ async function prepareCodexAttemptConnection({ params, options }) {
3669
3957
  const requestedCwd = params.cwd ? resolveUserPath(params.cwd) : void 0;
3670
3958
  if (sandbox?.enabled && requestedCwd && requestedCwd !== resolvedWorkspace) throw new Error("cwd override is not supported for sandboxed Codex app-server runs; omit cwd or use the agent workspace as cwd");
3671
3959
  const effectiveCwd = sandbox?.enabled ? effectiveWorkspace : requestedCwd ?? effectiveWorkspace;
3672
- await ensureCodexWorkspaceDirOnce(effectiveWorkspace);
3960
+ if (effectiveWorkspace !== resolvedWorkspace) await ensureCodexWorkspaceDirOnce(effectiveWorkspace);
3673
3961
  preDynamicStartupStages.mark("effective-workspace");
3962
+ const shouldPromoteApprovalPolicy = beforeToolCallPolicy.hasBeforeToolCallHook || beforeToolCallPolicy.trustedToolPolicies.length > 0;
3674
3963
  const resolvePolicyAppServer = () => resolveCodexAppServerForOpenClawToolPolicy({
3675
3964
  appServer: configuredAppServer,
3676
3965
  pluginConfig,
3677
3966
  env: process.env,
3678
- shouldPromote: beforeToolCallPolicy.hasBeforeToolCallHook || beforeToolCallPolicy.trustedToolPolicies.length > 0,
3967
+ shouldPromote: shouldPromoteApprovalPolicy,
3679
3968
  execPolicy,
3680
- canUseUntrustedApprovalPolicy: configuredAppServer.start.transport !== "stdio" || isCodexAppServerApprovalPolicyAllowedByRequirements("untrusted")
3969
+ canUseUntrustedApprovalPolicy: shouldPromoteApprovalPolicy && configuredAppServer.approvalPolicy === "never" && (configuredAppServer.start.transport !== "stdio" || isCodexAppServerApprovalPolicyAllowedByRequirements("untrusted"))
3681
3970
  });
3682
3971
  let policyAppServer = resolvePolicyAppServer();
3683
3972
  let appServer = resolveCodexAppServerForModelProvider({
@@ -3688,7 +3977,8 @@ async function prepareCodexAttemptConnection({ params, options }) {
3688
3977
  env: process.env,
3689
3978
  agentDir
3690
3979
  });
3691
- if (configuredAppServer.approvalPolicy === "never" && appServer.approvalPolicy === "untrusted") embeddedAgentLog.info("codex app-server approval policy promoted for OpenClaw tool policy", {
3980
+ let approvalPolicyPromotedForOpenClawToolPolicy = configuredAppServer.approvalPolicy === "never" && appServer.approvalPolicy === "untrusted";
3981
+ if (approvalPolicyPromotedForOpenClawToolPolicy) embeddedAgentLog.info("codex app-server approval policy promoted for OpenClaw tool policy", {
3692
3982
  from: "never",
3693
3983
  to: "untrusted",
3694
3984
  beforeToolCallHook: beforeToolCallPolicy.hasBeforeToolCallHook,
@@ -3725,6 +4015,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
3725
4015
  };
3726
4016
  if (params.abortSignal?.aborted) abortFromUpstream();
3727
4017
  else params.abortSignal?.addEventListener("abort", abortFromUpstream, { once: true });
4018
+ const startupBindingBeforeRotation = startupBinding;
3728
4019
  startupBinding = await rotateOversizedCodexAppServerStartupBinding({
3729
4020
  binding: startupBinding,
3730
4021
  bindingStore,
@@ -3737,20 +4028,23 @@ async function prepareCodexAttemptConnection({ params, options }) {
3737
4028
  });
3738
4029
  const initialInactiveThreadBootstrapBindingForcedFreshStart = initialStartupBindingHadInactiveThreadBootstrap && !startupBinding?.threadId;
3739
4030
  preDynamicStartupStages.mark("rotate-binding");
3740
- reviewerPolicyContext = resolveReviewerPolicyContext(startupBinding);
3741
- configuredAppServer = resolveRuntimeOptionsForBinding({
3742
- modelProvider: reviewerPolicyContext.modelProvider,
3743
- model: reviewerPolicyContext.model
3744
- });
3745
- policyAppServer = resolvePolicyAppServer();
3746
- appServer = resolveCodexAppServerForModelProvider({
3747
- appServer: policyAppServer,
3748
- provider: reviewerPolicyContext.modelProvider,
3749
- model: reviewerPolicyContext.model,
3750
- config: params.config,
3751
- env: process.env,
3752
- agentDir
3753
- });
4031
+ if (startupBinding !== startupBindingBeforeRotation) {
4032
+ reviewerPolicyContext = resolveReviewerPolicyContext(startupBinding);
4033
+ configuredAppServer = resolveRuntimeOptionsForBinding({
4034
+ modelProvider: reviewerPolicyContext.modelProvider,
4035
+ model: reviewerPolicyContext.model
4036
+ });
4037
+ policyAppServer = resolvePolicyAppServer();
4038
+ appServer = resolveCodexAppServerForModelProvider({
4039
+ appServer: policyAppServer,
4040
+ provider: reviewerPolicyContext.modelProvider,
4041
+ model: reviewerPolicyContext.model,
4042
+ config: params.config,
4043
+ env: process.env,
4044
+ agentDir
4045
+ });
4046
+ approvalPolicyPromotedForOpenClawToolPolicy = configuredAppServer.approvalPolicy === "never" && appServer.approvalPolicy === "untrusted";
4047
+ }
3754
4048
  const nativeHookRelayEvents = resolveCodexNativeHookRelayEvents({
3755
4049
  configuredEvents: options.nativeHookRelay?.events,
3756
4050
  appServer
@@ -3806,6 +4100,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
3806
4100
  effectiveWorkspace,
3807
4101
  effectiveCwd,
3808
4102
  appServer,
4103
+ approvalPolicyPromotedForOpenClawToolPolicy,
3809
4104
  nativeHookRelayEvents,
3810
4105
  runAbortController,
3811
4106
  terminalState,
@@ -4133,7 +4428,7 @@ function buildCodexOpenClawPromptContext(params) {
4133
4428
  "## OpenClaw Workspace Context",
4134
4429
  "",
4135
4430
  params.workspacePromptContext.trim()
4136
- ].join("\n") : void 0].filter(isNonEmptyString$1);
4431
+ ].join("\n") : void 0, params.watchedSessionsContext?.trim() || void 0].filter(isNonEmptyString$1);
4137
4432
  if (sections.length === 0) return;
4138
4433
  return [
4139
4434
  "OpenClaw runtime context for this turn:",
@@ -4142,6 +4437,21 @@ function buildCodexOpenClawPromptContext(params) {
4142
4437
  ...sections
4143
4438
  ].join("\n");
4144
4439
  }
4440
+ /**
4441
+ * Renders the watched-sessions block for the Codex per-turn runtime context.
4442
+ * Codex builds its own instruction layers, so the embedded prompt's Watched
4443
+ * Sessions section must be re-surfaced here or Codex-backed main sessions
4444
+ * keep refusing cross-session questions (openclaw#114797).
4445
+ */
4446
+ function buildCodexWatchedSessionsContext(params) {
4447
+ if (!shouldInjectCodexOpenClawPromptContext(params.attempt)) return;
4448
+ return buildWatchedSessionsHarnessContext({
4449
+ config: params.attempt.config,
4450
+ sessionKey: params.sessionKey,
4451
+ sandboxed: params.sandboxed,
4452
+ toolNames: flattenCodexDynamicToolFunctions(params.dynamicTools).map((tool) => normalizeCodexDynamicToolName(tool.name))
4453
+ });
4454
+ }
4145
4455
  function shouldInjectCodexOpenClawPromptContext(params) {
4146
4456
  return !(params.bootstrapContextMode === "lightweight" && params.bootstrapContextRunKind === "cron");
4147
4457
  }
@@ -4475,7 +4785,13 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
4475
4785
  baseDeveloperInstructions,
4476
4786
  openClawPromptContext: buildCodexOpenClawPromptContext({
4477
4787
  params: runtimeParams,
4478
- workspacePromptContext: workspaceBootstrapContext.promptContext
4788
+ workspacePromptContext: workspaceBootstrapContext.promptContext,
4789
+ watchedSessionsContext: buildCodexWatchedSessionsContext({
4790
+ attempt: runtimeParams,
4791
+ dynamicTools: toolBridge.availableSpecs,
4792
+ sessionKey: contextSessionKey,
4793
+ sandboxed: sandbox?.enabled === true
4794
+ })
4479
4795
  }),
4480
4796
  skillsCollaborationInstructions: renderCodexSkillsCollaborationInstructions({
4481
4797
  attempt: runtimeParams,
@@ -4928,14 +5244,6 @@ function createCodexHostTrajectorySink(params) {
4928
5244
  /** Creates a trajectory recorder when trajectory capture is enabled for the environment. */
4929
5245
  function createCodexTrajectoryRecorder(params) {
4930
5246
  if (!parseTrajectoryEnabled(params.env ?? process.env)) return null;
4931
- const sqliteMarker = parseSqliteSessionFileMarker(params.trajectorySessionFile ?? params.attempt.sessionFile);
4932
- if (!sqliteMarker || sqliteMarker.sessionId !== params.attempt.sessionId) {
4933
- params.warn?.("codex trajectory capture requires a matching SQLite session target", {
4934
- sessionId: params.attempt.sessionId,
4935
- reason: sqliteMarker ? "session-id-mismatch" : "non-sqlite-session-target"
4936
- });
4937
- return null;
4938
- }
4939
5247
  if (!params.trajectoryRecorder) {
4940
5248
  params.warn?.("codex trajectory capture requires the SQLite host recorder", {
4941
5249
  sessionId: params.attempt.sessionId,
@@ -5265,7 +5573,29 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
5265
5573
  ...finalPromptError ? { error: formatErrorMessage(finalPromptError) } : {},
5266
5574
  durationMs: Date.now() - attemptStartedAt
5267
5575
  },
5268
- ctx: hookContext,
5576
+ ctx: {
5577
+ ...hookContext,
5578
+ modelProviderId: resourceState.thread.modelProvider ?? effectiveRuntimeProviderId,
5579
+ modelId: resourceState.thread.model ?? effectiveRuntimeModelId,
5580
+ authProfileId: resourceState.thread.authProfileId ?? startupAuthProfileId,
5581
+ modelIterations: result.modelIterations ?? 0,
5582
+ skillWorkshopAvailable: flattenCodexDynamicToolFunctions(attemptTools.toolBridge.availableSpecs).some((tool) => tool.name === "skill_workshop"),
5583
+ compacted: (result.compactionCount ?? 0) > 0,
5584
+ messageChannel: params.messageChannel,
5585
+ messageProvider: params.messageProvider,
5586
+ chatType: params.chatType,
5587
+ agentAccountId: params.agentAccountId,
5588
+ groupId: params.groupId,
5589
+ groupChannel: params.groupChannel,
5590
+ groupSpace: params.groupSpace,
5591
+ memberRoleIds: params.memberRoleIds,
5592
+ spawnedBy: params.spawnedBy,
5593
+ senderId: params.senderId ?? void 0,
5594
+ senderName: params.senderName,
5595
+ senderUsername: params.senderUsername,
5596
+ senderE164: params.senderE164,
5597
+ senderIsOwner: params.senderIsOwner
5598
+ },
5269
5599
  hookRunner
5270
5600
  });
5271
5601
  state.shouldDelayNativeHookRelayUnregister = completedTurnStatus === "completed" && !effectiveTimedOut && !runAbortController.signal.aborted && !finalAborted && !finalPromptError;
@@ -6154,6 +6484,9 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
6154
6484
  }
6155
6485
  //#endregion
6156
6486
  //#region extensions/codex/src/app-server/run-attempt-prompt.ts
6487
+ function isRestrictivePromptToolsAllow(toolsAllow) {
6488
+ return toolsAllow !== void 0 && !toolsAllow.some((name) => name.trim() === "*");
6489
+ }
6157
6490
  async function prepareCodexAttemptPrompt(context) {
6158
6491
  const { runtime, attemptTools, historyState, hookContext, workspaceBootstrapContext, baseDeveloperInstructions, openClawPromptContext, skillsCollaborationInstructions, promptState, codexContextProjectionMaxChars } = context;
6159
6492
  const { connection, buildActiveRunAttemptParams, effectiveContextTokenBudget, effectiveRuntimeModelId, effectiveRuntimeProviderId } = runtime;
@@ -6239,13 +6572,17 @@ async function prepareCodexAttemptPrompt(context) {
6239
6572
  embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
6240
6573
  }
6241
6574
  const codexModelInputHistoryMessages = [];
6242
- const buildPromptFromCurrentInputs = () => resolveAgentHarnessBeforePromptBuildResult({
6243
- prompt: prependCurrentInboundContext(promptState.promptText, params.currentInboundContext),
6244
- developerInstructions: promptState.developerInstructions,
6245
- messages: structuredClone(historyState.messages),
6246
- ctx: hookContext,
6247
- bootstrapContextRunKind: params.bootstrapContextRunKind
6248
- });
6575
+ const buildPromptFromCurrentInputs = async () => {
6576
+ const result = await resolveAgentHarnessBeforePromptBuildResult({
6577
+ prompt: prependCurrentInboundContext(promptState.promptText, params.currentInboundContext),
6578
+ developerInstructions: promptState.developerInstructions,
6579
+ messages: structuredClone(historyState.messages),
6580
+ ctx: hookContext,
6581
+ bootstrapContextRunKind: params.bootstrapContextRunKind
6582
+ });
6583
+ if (isRestrictivePromptToolsAllow(result.toolsAllow)) throw new Error("Codex app-server cannot enforce before_prompt_build toolsAllow; use the embedded or Copilot runtime for turn-scoped tool policy.");
6584
+ return result;
6585
+ };
6249
6586
  const resolveShiftedPromptInputRange = (prompt, promptInputRange, turnPromptText) => {
6250
6587
  if (!promptInputRange || promptInputRange.start < 0 || promptInputRange.end < promptInputRange.start || promptInputRange.end > prompt.length || !turnPromptText.endsWith(prompt)) return;
6251
6588
  const turnPromptOffset = turnPromptText.length - prompt.length;
@@ -7914,8 +8251,10 @@ const sandboxExecServerRegistry = {
7914
8251
  };
7915
8252
  //#endregion
7916
8253
  //#region extensions/codex/src/app-server/sandbox-exec-server/json-rpc.ts
7917
- /** JSON-RPC error code used when a sandbox exec-server method is unknown. */
8254
+ /** JSON-RPC error code used when a sandbox filesystem resource does not exist. */
7918
8255
  const JSON_RPC_NOT_FOUND = -32004;
8256
+ /** JSON-RPC error code used when a sandbox exec-server method is unsupported. */
8257
+ const JSON_RPC_METHOD_NOT_FOUND = -32601;
7919
8258
  /** Protocol-level error carrying the JSON-RPC error code to send to the client. */
7920
8259
  var JsonRpcProtocolError = class extends Error {
7921
8260
  constructor(code, message) {
@@ -8247,6 +8586,101 @@ function requireFsBridge(execServer) {
8247
8586
  * with OpenClaw sandbox policy checks before every bridge operation.
8248
8587
  */
8249
8588
  const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES = 512 * 1024 * 1024;
8589
+ const CODEX_SANDBOX_EXEC_SERVER_MAX_OPEN_FILE_READS = 128;
8590
+ const CODEX_SANDBOX_EXEC_SERVER_MAX_BUFFERED_FILE_READ_BYTES = 64 * 1024 * 1024;
8591
+ const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_BLOCK_BYTES = 1024 * 1024;
8592
+ const CODEX_SANDBOX_EXEC_SERVER_MAX_FILE_READ_HANDLE_ID_BYTES = 32;
8593
+ /** Opens a policy-checked sandbox file under a bounded, connection-owned handle. */
8594
+ async function openFile(execServer, handles, params) {
8595
+ const record = requireObject(params, "fs/open params");
8596
+ const handleId = requireFileReadHandleId(record.handleId);
8597
+ if (handles.closed) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, `unknown file read handle \`${handleId}\``);
8598
+ if (handles.has(handleId)) throw new JsonRpcProtocolError(-32600, `file read handle \`${handleId}\` already exists`);
8599
+ if (handles.size >= CODEX_SANDBOX_EXEC_SERVER_MAX_OPEN_FILE_READS) throw new JsonRpcProtocolError(-32600, `at most ${CODEX_SANDBOX_EXEC_SERVER_MAX_OPEN_FILE_READS} file reads may be open per connection`);
8600
+ const filePath = resolveExecServerPath(requireString(record.path, "path"), "read path");
8601
+ assertFsSandboxAccess(execServer, record, [{
8602
+ path: filePath,
8603
+ access: "read"
8604
+ }]);
8605
+ const fsBridge = requireFsBridge(execServer);
8606
+ const handle = {
8607
+ abortController: new AbortController(),
8608
+ closeRequested: false,
8609
+ reservedBytes: 0
8610
+ };
8611
+ handles.set(handleId, handle);
8612
+ try {
8613
+ const stat = await fsBridge.stat({
8614
+ filePath,
8615
+ signal: handle.abortController.signal
8616
+ });
8617
+ if (handles.get(handleId) !== handle || handle.closeRequested || handles.closed) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, `unknown file read handle \`${handleId}\``);
8618
+ if (!stat) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, "file not found");
8619
+ if (stat.type !== "file") throw new JsonRpcProtocolError(-32600, "file read handle requires a regular file");
8620
+ if (!Number.isSafeInteger(stat.size) || stat.size < 0) throw new JsonRpcProtocolError(-32600, "file size must be a non-negative safe integer");
8621
+ if (stat.size > CODEX_SANDBOX_EXEC_SERVER_MAX_BUFFERED_FILE_READ_BYTES - bufferedFileReadBytes(handles)) throw new JsonRpcProtocolError(-32600, "sandbox file read exceeds the per-connection buffered file limit");
8622
+ handle.reservedBytes = stat.size;
8623
+ const data = await fsBridge.readFile({
8624
+ filePath,
8625
+ maxBytes: handle.reservedBytes,
8626
+ signal: handle.abortController.signal
8627
+ });
8628
+ if (handles.get(handleId) !== handle || handle.closeRequested || handles.closed) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, `unknown file read handle \`${handleId}\``);
8629
+ if (data.byteLength > handle.reservedBytes) throw new JsonRpcProtocolError(-32600, "sandbox file read exceeds the per-connection buffered file limit");
8630
+ handle.reservedBytes = data.byteLength;
8631
+ handle.data = data;
8632
+ return { handleId };
8633
+ } catch (error) {
8634
+ if (handles.get(handleId) === handle) handles.delete(handleId);
8635
+ throw error;
8636
+ }
8637
+ }
8638
+ /** Reads a bounded base64 block from a handle belonging to this connection. */
8639
+ function readFileBlock(handles, params) {
8640
+ const record = requireObject(params, "fs/readBlock params");
8641
+ const handleId = requireFileReadHandleId(record.handleId);
8642
+ const handle = handles.get(handleId);
8643
+ if (!handle?.data) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, `unknown file read handle \`${handleId}\``);
8644
+ const offset = requireNumber(record.offset, "offset");
8645
+ const length = requireNumber(record.len, "len");
8646
+ if (!Number.isSafeInteger(offset) || offset < 0) throw new JsonRpcProtocolError(-32600, "file read offset must be a non-negative safe integer");
8647
+ if (!Number.isSafeInteger(length) || length < 1 || length > CODEX_SANDBOX_EXEC_SERVER_MAX_READ_BLOCK_BYTES) throw new JsonRpcProtocolError(-32600, `file read block length must be between 1 and ${CODEX_SANDBOX_EXEC_SERVER_MAX_READ_BLOCK_BYTES}`);
8648
+ const chunk = handle.data.subarray(offset, Math.min(offset + length, handle.data.byteLength));
8649
+ return {
8650
+ chunk: chunk.toString("base64"),
8651
+ eof: offset + chunk.byteLength >= handle.data.byteLength
8652
+ };
8653
+ }
8654
+ /** Closes one connection-owned file handle; repeated closes are harmless. */
8655
+ function closeFile(handles, params) {
8656
+ closeFileReadHandle(handles, requireFileReadHandleId(requireObject(params, "fs/close params").handleId));
8657
+ return {};
8658
+ }
8659
+ /** Cancels a disconnected socket without releasing unsettled read reservations. */
8660
+ function closeAllFileReads(handles) {
8661
+ handles.closed = true;
8662
+ for (const handleId of handles.keys()) closeFileReadHandle(handles, handleId);
8663
+ }
8664
+ function closeFileReadHandle(handles, handleId) {
8665
+ const handle = handles.get(handleId);
8666
+ if (!handle) return;
8667
+ handle.closeRequested = true;
8668
+ if (handle.data !== void 0) {
8669
+ handles.delete(handleId);
8670
+ return;
8671
+ }
8672
+ handle.abortController.abort();
8673
+ }
8674
+ function bufferedFileReadBytes(handles) {
8675
+ let total = 0;
8676
+ for (const handle of handles.values()) total += handle.reservedBytes;
8677
+ return total;
8678
+ }
8679
+ function requireFileReadHandleId(value) {
8680
+ const handleId = requireString(value, "handleId");
8681
+ if (Buffer.byteLength(handleId, "utf8") > CODEX_SANDBOX_EXEC_SERVER_MAX_FILE_READ_HANDLE_ID_BYTES) throw new JsonRpcProtocolError(-32600, `file read handle ID must not exceed ${CODEX_SANDBOX_EXEC_SERVER_MAX_FILE_READ_HANDLE_ID_BYTES} bytes`);
8682
+ return handleId;
8683
+ }
8250
8684
  /** Reads a sandbox file as base64 after read-policy and size checks. */
8251
8685
  async function readFile(execServer, params) {
8252
8686
  const record = requireObject(params, "fs/readFile params");
@@ -8259,7 +8693,10 @@ async function readFile(execServer, params) {
8259
8693
  const stat = await fsBridge.stat({ filePath });
8260
8694
  if (!stat) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, "file not found");
8261
8695
  assertSandboxFileReadWithinLimit(stat);
8262
- return { dataBase64: (await fsBridge.readFile({ filePath })).toString("base64") };
8696
+ return { dataBase64: (await fsBridge.readFile({
8697
+ filePath,
8698
+ maxBytes: CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES
8699
+ })).toString("base64") };
8263
8700
  }
8264
8701
  /** Writes base64 data to an existing sandbox directory after write-policy checks. */
8265
8702
  async function writeFile(execServer, params) {
@@ -8408,7 +8845,10 @@ async function copySandboxPath(execServer, params) {
8408
8845
  return;
8409
8846
  }
8410
8847
  assertSandboxFileReadWithinLimit(sourceStat);
8411
- const data = await fsBridge.readFile({ filePath: params.sourcePath });
8848
+ const data = await fsBridge.readFile({
8849
+ filePath: params.sourcePath,
8850
+ maxBytes: CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES
8851
+ });
8412
8852
  await fsBridge.writeFile({
8413
8853
  filePath: params.destinationPath,
8414
8854
  data,
@@ -8423,6 +8863,7 @@ function metadataResponse(stat) {
8423
8863
  isDirectory: stat?.type === "directory",
8424
8864
  isFile: stat?.type === "file",
8425
8865
  isSymlink: false,
8866
+ size: stat?.size ?? 0,
8426
8867
  createdAtMs: 0,
8427
8868
  modifiedAtMs: stat?.mtimeMs ?? 0
8428
8869
  };
@@ -9284,19 +9725,21 @@ function isAuthorizedExecServerRequest(execServer, request) {
9284
9725
  }
9285
9726
  function handleConnection(execServer, socket) {
9286
9727
  const processes = /* @__PURE__ */ new Map();
9728
+ const fileReads = /* @__PURE__ */ new Map();
9287
9729
  socket.on("message", (data) => {
9288
- handleMessage(execServer, processes, socket, data).catch((error) => {
9730
+ handleMessage(execServer, processes, fileReads, socket, data).catch((error) => {
9289
9731
  embeddedAgentLog.warn("codex sandbox exec-server message failed", { error });
9290
9732
  });
9291
9733
  });
9292
9734
  socket.on("close", () => {
9735
+ closeAllFileReads(fileReads);
9293
9736
  for (const process of processes.values()) process.abortController.abort();
9294
9737
  });
9295
9738
  }
9296
9739
  function handleExecServerSocketError(error) {
9297
9740
  embeddedAgentLog.debug("codex sandbox exec-server websocket failed", { error });
9298
9741
  }
9299
- async function handleMessage(execServer, processes, socket, data) {
9742
+ async function handleMessage(execServer, processes, fileReads, socket, data) {
9300
9743
  const request = parseRequest(data);
9301
9744
  if (!request.method) {
9302
9745
  sendError(socket, request.id, -32600, "Invalid Request");
@@ -9308,7 +9751,7 @@ async function handleMessage(execServer, processes, socket, data) {
9308
9751
  return;
9309
9752
  }
9310
9753
  try {
9311
- const result = await dispatchRequest(execServer, processes, socket, {
9754
+ const result = await dispatchRequest(execServer, processes, fileReads, socket, {
9312
9755
  ...request,
9313
9756
  method
9314
9757
  });
@@ -9317,13 +9760,25 @@ async function handleMessage(execServer, processes, socket, data) {
9317
9760
  sendError(socket, request.id, error instanceof JsonRpcProtocolError ? error.code : -32603, error instanceof Error ? error.message : String(error));
9318
9761
  }
9319
9762
  }
9320
- async function dispatchRequest(execServer, processes, socket, request) {
9763
+ async function dispatchRequest(execServer, processes, fileReads, socket, request) {
9321
9764
  switch (request.method) {
9322
9765
  case "initialize": return { sessionId: randomUUID() };
9766
+ case "environment/info": return {
9767
+ shell: {
9768
+ name: "sh",
9769
+ path: "/bin/sh"
9770
+ },
9771
+ cwd: pathToFileURL(execServer.sandbox.containerWorkdir, { windows: false }).href,
9772
+ capabilities: { networkProxyLaunch: false }
9773
+ };
9774
+ case "environment/status": return { status: "ready" };
9323
9775
  case "process/start": return startProcess(execServer, processes, socket, request.params);
9324
9776
  case "process/read": return await readProcess(processes, request.params);
9325
9777
  case "process/write": return writeProcess(processes, request.params);
9326
9778
  case "process/terminate": return terminateProcess(processes, request.params);
9779
+ case "fs/open": return await openFile(execServer, fileReads, request.params);
9780
+ case "fs/readBlock": return readFileBlock(fileReads, request.params);
9781
+ case "fs/close": return closeFile(fileReads, request.params);
9327
9782
  case "fs/readFile": return await readFile(execServer, request.params);
9328
9783
  case "fs/writeFile":
9329
9784
  await writeFile(execServer, request.params);
@@ -9340,7 +9795,7 @@ async function dispatchRequest(execServer, processes, socket, request) {
9340
9795
  await copyPath(execServer, request.params);
9341
9796
  return {};
9342
9797
  case "http/request": return await httpRequest(execServer, socket, request.params);
9343
- default: throw new Error(`Unsupported OpenClaw sandbox exec-server method: ${request.method}`);
9798
+ default: throw new JsonRpcProtocolError(JSON_RPC_METHOD_NOT_FOUND, `Unsupported OpenClaw sandbox exec-server method: ${request.method}`);
9344
9799
  }
9345
9800
  }
9346
9801
  //#endregion
@@ -9358,7 +9813,6 @@ function prepareCodexAttemptResources(prompt) {
9358
9813
  developerInstructions: buildRenderedCodexDeveloperInstructions(),
9359
9814
  prompt: turnState.codexTurnPromptText,
9360
9815
  trajectoryRecorder: hostTrajectoryRecorder,
9361
- trajectorySessionFile: params.trajectorySessionFile,
9362
9816
  tools: toolBridge.availableSpecs,
9363
9817
  warn: (message, fields) => embeddedAgentLog.warn(message, fields)
9364
9818
  });
@@ -9468,14 +9922,7 @@ function prepareCodexAttemptResources(prompt) {
9468
9922
  timeoutFloorMs: options.startupTimeoutFloorMs
9469
9923
  });
9470
9924
  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;
9925
+ const requester = buildCodexHookRequester(params);
9479
9926
  const buildNativeHookRelayFinalConfigPatch = (decision) => {
9480
9927
  state.nativeHookRelay?.unregister();
9481
9928
  state.nativeHookRelay = createCodexNativeHookRelay({
@@ -9489,7 +9936,15 @@ function prepareCodexAttemptResources(prompt) {
9489
9936
  config: params.config,
9490
9937
  runId: params.runId,
9491
9938
  channelId: hookChannelId,
9492
- ...hasRequester ? { requester } : {},
9939
+ ...requester ? { requester } : {},
9940
+ approvalContext: {
9941
+ trigger: params.trigger,
9942
+ approvalReviewerDeviceId: params.approvalReviewerDeviceId,
9943
+ turnSourceChannel: requesterChannel,
9944
+ turnSourceTo: params.currentMessagingTarget ?? params.currentChannelId,
9945
+ turnSourceAccountId: params.agentAccountId,
9946
+ turnSourceThreadId: params.currentThreadTs
9947
+ },
9493
9948
  attemptTimeoutMs: params.timeoutMs,
9494
9949
  startupTimeoutMs,
9495
9950
  turnStartTimeoutMs: params.timeoutMs,
@@ -9663,6 +10118,7 @@ async function prepareCodexAttemptRuntime(connection) {
9663
10118
  modelId: effectiveRuntimeModelId,
9664
10119
  model: supervisedRuntimeModel,
9665
10120
  thinkLevel: _outerThinkLevel,
10121
+ fastMode: _outerFastMode,
9666
10122
  sessionKey: contextSessionKey
9667
10123
  } : {
9668
10124
  ...params,
@@ -9690,7 +10146,8 @@ async function prepareCodexAttemptRuntime(connection) {
9690
10146
  cfg: params.config,
9691
10147
  toolsEnabled: usesSupervisionConnection || supportsModelTools(params.model),
9692
10148
  disableTools: params.disableTools,
9693
- toolsAllow: params.toolsAllow
10149
+ toolsAllow: params.toolsAllow,
10150
+ toolOverrides: params.toolOverrides
9694
10151
  });
9695
10152
  preDynamicStartupStages.mark("bundle-mcp");
9696
10153
  const sandboxExecServerEnabled = isCodexSandboxExecServerEnabled(pluginConfig);
@@ -9842,6 +10299,7 @@ function handleApprovalRequest(params) {
9842
10299
  turnId: params.turnId,
9843
10300
  nativeHookRelay: params.nativeHookRelay,
9844
10301
  autoApprove: params.autoApprove,
10302
+ autoApproveOpenClawToolPolicy: params.autoApproveOpenClawToolPolicy,
9845
10303
  signal: params.signal,
9846
10304
  onNativeToolFailureDisposition: params.onNativeToolFailureDisposition
9847
10305
  });
@@ -9859,7 +10317,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
9859
10317
  const { context } = prompt;
9860
10318
  const { runtime, attemptTools } = context;
9861
10319
  const { connection } = runtime;
9862
- const { params, computerUseConfig, runAbortController, appServer, sessionAgentId } = connection;
10320
+ const { params, computerUseConfig, runAbortController, appServer, approvalPolicyPromotedForOpenClawToolPolicy, sessionAgentId } = connection;
9863
10321
  const { toolBridge, toolOutcomeOrdinals, suppressedDynamicToolOutcomeOrdinals, allocateCodexToolOutcomeOrdinal } = attemptTools;
9864
10322
  const { state, turnIdRef, userInputBridgeRef, openClawDynamicToolExecutions, pendingOpenClawDynamicToolCompletionIds, postToolRawAssistantCompletionIdleTimeoutMs, turnWatches } = turnRuntime;
9865
10323
  const { emitExecutionPhaseOnce, scheduleTurnReleaseAfterTerminalDynamicTool, scheduleTerminalDynamicToolReleaseCheck } = lifecycle;
@@ -9917,6 +10375,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
9917
10375
  turnId,
9918
10376
  nativeHookRelay: resourceState.nativeHookRelay,
9919
10377
  autoApprove: shouldAutoApproveCodexAppServerApprovals(appServer),
10378
+ autoApproveOpenClawToolPolicy: approvalPolicyPromotedForOpenClawToolPolicy,
9920
10379
  signal,
9921
10380
  onNativeToolFailureDisposition: (itemId, disposition) => projector?.recordNativeToolApprovalFailure(itemId, disposition)
9922
10381
  });
@@ -10218,8 +10677,8 @@ var CodexPluginMetadataCache = class {
10218
10677
  this.clearGeneration = 0;
10219
10678
  }
10220
10679
  /** Returns a fresh cached snapshot without issuing a request. */
10221
- read(appCacheKey, queryKind) {
10222
- const entryKey = buildMetadataCacheEntryKey(appCacheKey, queryKind);
10680
+ read(appCacheKey, queryKind, requestParams) {
10681
+ const entryKey = buildMetadataCacheEntryKey(appCacheKey, queryKind, requestParams);
10223
10682
  const entry = this.entries.get(entryKey);
10224
10683
  if (!entry) return;
10225
10684
  if (entry.expiresAtMs <= this.nowMs()) {
@@ -10228,10 +10687,10 @@ var CodexPluginMetadataCache = class {
10228
10687
  }
10229
10688
  return entry.snapshot;
10230
10689
  }
10231
- /** Returns a fresh cached snapshot or coalesces one plugin/list request. */
10690
+ /** Returns a fresh snapshot or coalesces one catalog or installed-plugin request. */
10232
10691
  async load(params) {
10233
- const entryKey = buildMetadataCacheEntryKey(params.appCacheKey, params.queryKind);
10234
- const cached = this.read(params.appCacheKey, params.queryKind);
10692
+ const entryKey = buildMetadataCacheEntryKey(params.appCacheKey, params.queryKind, params.requestParams);
10693
+ const cached = this.read(params.appCacheKey, params.queryKind, params.requestParams);
10235
10694
  if (cached) return cached;
10236
10695
  const pending = this.inFlight.get(entryKey);
10237
10696
  if (pending) try {
@@ -10243,7 +10702,8 @@ var CodexPluginMetadataCache = class {
10243
10702
  const generation = this.generations.get(params.appCacheKey) ?? 0;
10244
10703
  const clearGeneration = this.clearGeneration;
10245
10704
  const promise = (async () => {
10246
- const response = await params.request("plugin/list", params.requestParams);
10705
+ const method = params.queryKind === "installed" ? "plugin/installed" : "plugin/list";
10706
+ const response = await params.request(method, params.requestParams);
10247
10707
  const snapshot = {
10248
10708
  appCacheKey: params.appCacheKey,
10249
10709
  queryKind: params.queryKind,
@@ -10282,10 +10742,17 @@ var CodexPluginMetadataCache = class {
10282
10742
  /** Shared plugin metadata cache used by Codex app-server runtime paths. */
10283
10743
  const defaultCodexPluginMetadataCache = new CodexPluginMetadataCache();
10284
10744
  function hasMarketplaceLoadErrors(response) {
10285
- return (response.marketplaceLoadErrors?.length ?? 0) > 0;
10286
- }
10287
- function buildMetadataCacheEntryKey(appCacheKey, queryKind) {
10288
- return JSON.stringify([appCacheKey, queryKind]);
10745
+ return response.marketplaceLoadErrors.length > 0;
10746
+ }
10747
+ function buildMetadataCacheEntryKey(appCacheKey, queryKind, requestParams) {
10748
+ if (queryKind !== "installed") return JSON.stringify([appCacheKey, queryKind]);
10749
+ const installedParams = requestParams;
10750
+ return JSON.stringify([
10751
+ appCacheKey,
10752
+ queryKind,
10753
+ installedParams?.cwds ?? [],
10754
+ Array.from(new Set(installedParams?.installSuggestionPluginNames ?? [])).toSorted()
10755
+ ]);
10289
10756
  }
10290
10757
  //#endregion
10291
10758
  //#region extensions/codex/src/app-server/plugin-thread-config-deadline.ts
@@ -10379,7 +10846,8 @@ function createCodexPluginThreadConfigStartupProvider(params) {
10379
10846
  recoverablePluginConfigKeys: policy ? resolveRecoverableCodexPluginConfigKeys({
10380
10847
  policy,
10381
10848
  metadataCache,
10382
- appCacheKey: params.appCacheKey
10849
+ appCacheKey: params.appCacheKey,
10850
+ configCwd: params.configCwd
10383
10851
  }) : void 0,
10384
10852
  build: () => buildCodexPluginThreadConfigWithinDeadline({
10385
10853
  ...buildParams,
@@ -10489,7 +10957,7 @@ async function startCodexAttemptThread(params) {
10489
10957
  if (startupAbandonController.signal.aborted) throw new CodexAppServerStartupError("aborted");
10490
10958
  let runtimeArtifact;
10491
10959
  if (params.runtimeArtifactRequest) {
10492
- const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-C2ITXdhM.js");
10960
+ const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-CmtG_t1L.js");
10493
10961
  runtimeArtifact = readCodexAppServerClientRuntimeArtifact(activeStartupClient);
10494
10962
  const expected = params.runtimeArtifactRequest.expected;
10495
10963
  const matchesExpected = !expected || Boolean(runtimeArtifact && runtimeArtifact.id === expected.id && runtimeArtifact.fingerprint === expected.fingerprint);
@@ -10834,6 +11302,14 @@ async function startCodexAttemptRuntime(resources) {
10834
11302
  spawnedBy: params.spawnedBy
10835
11303
  });
10836
11304
  state.client = startupResult.client;
11305
+ toolBridge.setRemoteWorkspaceFileReader?.(({ path, maxBytes, workspaceRoot, signal, timeoutMs }) => readBoundedCodexRemoteWorkspaceFile({
11306
+ client: startupResult.client,
11307
+ path,
11308
+ maxBytes,
11309
+ workspaceRoot,
11310
+ signal,
11311
+ timeoutMs
11312
+ }));
10837
11313
  state.thread = startupResult.thread;
10838
11314
  state.runtimeArtifact = startupResult.runtimeArtifact;
10839
11315
  state.turnRouter = startupResult.turnRouter;
@@ -11054,6 +11530,8 @@ async function prepareCodexAttemptTools(runtime) {
11054
11530
  config: params.config,
11055
11531
  contextWindowTokens: params.contextTokenBudget ?? params.model.contextWindow,
11056
11532
  workspaceDir: effectiveWorkspace,
11533
+ remoteWorkspaceRoot: connection.appServer.remoteWorkspaceRoot,
11534
+ remoteWorkspaceRequestTimeoutMs: connection.appServer.requestTimeoutMs,
11057
11535
  sessionId: params.sessionId,
11058
11536
  sessionKey: sandboxSessionKey,
11059
11537
  runId: params.runId,