@openclaw/codex 2026.8.1-beta.2 → 2026.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +146 -0
- package/dist/{attempt-client-cleanup-DMLXUfa8.js → attempt-client-cleanup-CVPvp9dL.js} +47 -5
- package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
- package/dist/{binding-connection-I5Bo-AsX.js → binding-connection-CCQFs8lf.js} +15 -3
- package/dist/{bounded-turn-qgZmzy_4.js → bounded-turn-rq5tiSXk.js} +27 -26
- package/dist/{capabilities-CybGI1oz.js → capabilities-CGm_94eL.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-B1AEz8ZA.js → command-formatters-C54Yg3eA.js} +2 -2
- package/dist/{command-handlers-Db8pu_ds.js → command-handlers-BvOAHTrA.js} +111 -67
- package/dist/{compact-LspQaGfl.js → compact-Hd7SAc0N.js} +35 -30
- package/dist/{session-binding-DPxIvMgE.js → config-Cxw3Cl3k.js} +361 -1161
- package/dist/context-compaction-activity-BOeJf7yo.js +58 -0
- package/dist/doctor-contract-api.js +128 -26
- package/dist/{dynamic-tools-BVdyWkUD.js → dynamic-tools-BFoUcRdx.js} +1341 -1464
- package/dist/{effective-mcp-catalog-DIIhAtOZ.js → effective-mcp-catalog-BTJHnDSx.js} +2 -2
- package/dist/elicitation-input-DMkeki8d.js +71 -0
- package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
- package/dist/{event-projector-usage-e5huIQWu.js → event-projector-usage-D3PHFFXh.js} +18 -18
- package/dist/harness-DVfUQBlQ.js +248 -0
- package/dist/harness.js +2 -226
- package/dist/index.js +405 -299
- package/dist/{isolated-completion-C58NbL40.js → isolated-completion-Cbbx_5Ed.js} +4 -4
- package/dist/launch-args-sXOAg0SX.js +84 -0
- package/dist/managed-binary-ZkGodW19.js +248 -0
- package/dist/media-understanding-provider.js +2 -2
- package/dist/model-catalog-o6Cgjoss.js +101 -0
- package/dist/{models-BFlpn1Ex.js → models-DgFWSuxA.js} +25 -28
- package/dist/{native-subagent-monitor-DyTGmTUx.js → native-subagent-monitor-CwFyoylz.js} +385 -94
- package/dist/node-exec-server.runtime-DXrqpw1c.js +195 -0
- package/dist/plugin-approval-roundtrip-D80UZiJ_.js +95 -0
- package/dist/{plugin-marketplace-discovery-CzrGJdCR.js → plugin-marketplace-discovery-mdmScYOj.js} +60 -55
- package/dist/{plugin-metadata-cache-CNJPj4_b.js → plugin-metadata-cache-CulOABwu.js} +164 -134
- package/dist/{protocol-validators-B4F7L8Rf.js → protocol-validators-Bg5rpNxk.js} +203 -7
- package/dist/{rate-limits-DZXmOL8-.js → rate-limits-hFtzt2Up.js} +1 -1
- package/dist/{sandbox-guard-Cmwc9eIk.js → request-CCm4LaED.js} +207 -20
- package/dist/{run-attempt-P8BdxC1I.js → run-attempt-BwNQDH2u.js} +1506 -836
- package/dist/{runtime-artifact-BVSPdd6g.js → runtime-artifact-DeBvleJw.js} +4 -7
- package/dist/session-binding-q2WSTVmC.js +947 -0
- package/dist/{session-catalog-xwNi_SDM.js → session-catalog-C2Tae4rI.js} +1698 -1346
- package/dist/session-catalog-home-id-DAKUrm3C.js +112 -0
- package/dist/{session-cli-7hgXZDV7.js → session-cli-BuDjm5Ou.js} +20 -7
- package/dist/session-permission-policy-gLm40Vtq.js +160 -0
- package/dist/session-retirement-CdkI0bvb.js +90 -0
- package/dist/{session-upstream-marker-CrIFX06J.js → session-upstream-marker-Bcy33kam.js} +2 -3
- package/dist/{settled-turn-finalizer-BRWBO4MO.js → settled-turn-finalizer-B8JJcxCi.js} +27 -22
- package/dist/{shared-client-kIBbGjk4.js → shared-client-kNkljY-R.js} +2023 -607
- package/dist/{side-question-9HAL26l9.js → side-question-GwD73tX6.js} +109 -57
- package/dist/{thread-lifecycle-Bu1BTDXr.js → thread-lifecycle-Ss-uwnC4.js} +1208 -497
- package/dist/{thread-ownership-6kOQHlyC.js → thread-ownership-CeYBqg_4.js} +18 -8
- package/dist/{plugin-app-cache-key-C3H2CVp6.js → thread-resume-DF54hagX.js} +64 -6
- package/dist/{transcript-mirror-B9gGgnJS.js → transcript-mirror-CkEQIna-.js} +158 -41
- package/dist/transport-stdio-C7-s9TLG.js +708 -0
- package/dist/{upstream-prompt-provenance-ClRBije0.js → upstream-prompt-provenance-CFmsKwr9.js} +12 -14
- package/dist/{upstream-session-fork-CE-_LdnP.js → upstream-session-fork-BACGlOFa.js} +86 -88
- package/dist/{usage-CHlV0e-o.js → usage-C2l8Mils.js} +3 -3
- package/dist/{web-search-provider.runtime-DRw2Vl42.js → web-search-provider.runtime-B2XgRdFv.js} +3 -3
- package/openclaw.plugin.json +50 -2
- package/package.json +9 -8
- package/dist/app-server-policy-zcBDc1JU.js +0 -49
- package/dist/incognito-session-ET_ufDH-.js +0 -2
- package/dist/request-BRl5_UfX.js +0 -157
- package/dist/session-retirement-DoMMJFKm.js +0 -36
- package/dist/thread-resume-CPrJNQVM.js +0 -30
- package/dist/transport-stdio-DIImwDVS.js +0 -99
|
@@ -1,42 +1,51 @@
|
|
|
1
|
-
import { C as isCodexRemoteExecPlacementSandbox,
|
|
2
|
-
import { $ as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { l as
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { t as
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { t as
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { n as
|
|
16
|
-
import { n as
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import { a as
|
|
1
|
+
import { C as isCodexRemoteExecPlacementSandbox, D as resolveOpenClawExecPolicyForCodexAppServer, E as resolveCodexPluginsPolicy, P as resolveCodexAppServerHomeDir, S as isCodexPairedNodeRemoteExecPlacementSandbox, T as readCodexPluginConfig, d as withMcpElicitationsApprovalPolicy, m as resolveCodexModelBackedReviewerPolicyContext, o as resolveCodexComputerUseConfig, p as canUseCodexModelBackedApprovalsReviewerForModel, r as resolveCodexAppServerHomeScope, u as shouldAutoApproveCodexAppServerApprovals, v as readCodexRequirementsToml, w as isCodexSandboxExecServerEnabled } from "./config-Cxw3Cl3k.js";
|
|
2
|
+
import { $ as CodexAppServerRpcError, A as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, B as resolveCodexTurnTerminalIdleTimeoutMs, Dt as readCodexRateLimitsRevision, Ft as resolveCodexAppServerFallbackApiKeyCacheKey, G as isCodexAppServerConnectionClosedError, H as getCodexAppServerClientInstanceId, Ht as isJsonObject, I as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, It as resolveCodexAppServerPreparedApiKeyCacheKey, J as isCodexAppServerOverloadError, K as isCodexAppServerIndeterminateRequestCancellationError, L as resolveCodexStartupTimeoutMs, Lt as resolveCodexAppServerPreparedAuthHandoff, M as TURN_FINALIZE_DRAIN_ABORT_GRACE_MS, Mt as resolveCodexAppServerAuthProfileId, N as TURN_TERMINAL_SETTLEMENT_IDLE_TIMEOUT_MS, Nt as resolveCodexAppServerAuthProfileIdForAgent, Ot as readRecentCodexRateLimits, P as isCodexAppServerStartupError, Q as resolveCodexAppServerClientInstanceId, R as resolveCodexTurnAssistantCompletionIdleTimeoutMs, Tt as withAbortableTimeout, U as isCodexAppServerApprovalRequest, V as withCodexStartupTimeout, Vt as flattenCodexDynamicToolFunctions, W as isCodexAppServerBrokenPipeError, X as isCodexAppServerRequestTimeoutError, _t as ensureCodexAppServerClientRuntime, a as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, at as resolveDynamicToolCallTimeoutMs, c as getLeasedSharedCodexAppServerClient, ct as shouldReleaseTurnAfterTerminalDynamicTool, dt as resolveCodexToolAbortTerminalReason, et as createCodexElicitationResponse, f as readCodexAppServerClientDesktopGenerationFingerprint, h as releaseLeasedSharedCodexAppServerClient, i as clearSharedCodexAppServerClientIfCurrent, it as isMatchingDynamicToolTerminalDiagnostic, j as CodexAppServerStartupError, jt as resolveCodexAppServerAuthAccountCacheKey, kt as rememberCodexRateLimitsRead, l as getSharedCodexAppServerClient, lt as toCodexDynamicToolProgressResponse, nt as hasPendingDynamicToolTerminalDiagnostic, ot as resolveTerminalDynamicToolBatchAction, q as isCodexAppServerIndeterminateTransportError, rt as isDynamicToolTerminalDiagnosticEvent, s as createIsolatedCodexAppServerClient, st as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult, tt as handleDynamicToolCallWithTimeout, u as isCodexAppServerStartSelectionChangedError, ut as toCodexDynamicToolProtocolResponse, v as retainSharedCodexAppServerClientIfCurrent, xt as protectCodexAppServerLiveThread, y as retireSharedCodexAppServerClientIfCurrent, z as resolveCodexTurnCompletionIdleTimeoutMs } from "./shared-client-kNkljY-R.js";
|
|
3
|
+
import { c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, i as createCodexSessionGenerationSupersededError, l as resolveCodexRunSessionBindingAuthority, u as scopeCodexRunBindingStore } from "./session-binding-q2WSTVmC.js";
|
|
4
|
+
import { c as assertCodexTurnStartResponse, d as readCodexTurn, f as readCodexTurnCompletedNotification, l as readCodexDynamicToolCallParams } from "./protocol-validators-Bg5rpNxk.js";
|
|
5
|
+
import { B as readNonNegativeInteger, D as itemStatus, E as itemName, H as splitPlanText, I as readItem, L as readItemString, M as extractRawAssistantText, P as readCodexErrorNotificationMessage, V as readNullableString, _ as readCodexNotificationThreadId, a as closeCodexStartupClientBestEffort, d as terminateCodexBackgroundTerminals, f as unsubscribeCodexThreadBestEffort, g as isCodexNotificationForTurn, h as CodexProjectionDiagnostics, j as shouldSynthesizeToolProgressForItem, k as shouldClearTerminalPresentationForNativeItem, l as retireCodexAppServerClientAfterTimedOutTurn, m as getCodexAppServerTurnRouter, o as interruptCodexTurnAndWaitBestEffort, p as CODEX_APP_SERVER_NATIVE_TURN_WAIT_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError, t as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS, u as retireUnsafeCodexTurnClientBestEffort } from "./attempt-client-cleanup-CVPvp9dL.js";
|
|
6
|
+
import { C as readRawResponseToolCallId, E as updateActiveTurnItemIds, S as readNotificationItemId, T as updateActiveCompletionBlockerItemIds, _ as isReasoningItemCompletionNotification, a as codexExecutionToolName, b as isTerminalTurnStatus, c as isAssistantCompletionReleaseNotification, d as isNativeToolProgressNotification, f as isPendingOpenClawDynamicToolCompletionNotification, g as isRawToolOutputCompletionNotification, h as isRawReasoningCompletionNotification, l as isCodexTurnAbortMarkerNotification, m as isRawFunctionToolOutputCompletionNotification, o as describeNotificationActivity, p as isRawAssistantProgressNotification, r as projectCodexThreadUsageUpdate, s as isAssistantCommentaryCompletionNotification, t as CodexResponseCompletionProjection, u as isFileChangePatchUpdatedNotification, v as isReasoningProgressNotification, w as shouldDisarmAssistantCompletionIdleWatch, x as readCodexNotificationItem, y as isRetryableErrorNotification } from "./event-projector-usage-D3PHFFXh.js";
|
|
7
|
+
import { i as buildCodexPluginAppCacheKey, r as buildCodexAppServerRuntimeFingerprint, s as defaultCodexAppInventoryCache } from "./thread-resume-DF54hagX.js";
|
|
8
|
+
import { $ as resolveCodexContinuityProjectionMaxChars, B as isMessageOnlyCodexSourceReply, D as resolveCodexAppServerThreadModelSelection, F as codexDynamicToolsFingerprint, G as buildContextEngineBinding, I as codexLegacyDynamicToolsFingerprint, J as fitCodexProjectedContextForTurnStart, K as isContextEngineBindingCompatible, L as filterCodexDynamicTools, P as areCodexDynamicToolFingerprintsCompatible, Q as resolveCodexContextEngineProjectionReserveTokens, S as buildDeveloperInstructions, V as isSystemAgentOnlyCodexDynamicToolAllowlist, W as resolveCodexDynamicToolsLoadingForRuntime, X as projectContextEngineAssemblyForCodex, Y as neutralizeCodexExplicitMentionSigils, Z as resolveCodexContextEngineProjectionMaxChars, a as isCodexAppServerProfilerEnabled, at as buildPluginAppPolicyContext, c as buildCodexNativeHookRelayConfig, d as emitCodexNativePreToolUseFailureDiagnostic, et as buildCodexPluginAppsConfigPatchFromPolicyContext, f as resolveCodexNativeHookRelayEvents, i as startOrResumeThread, l as buildCodexNativeHookRelayDisabledConfig, m as scheduleCodexNativeHookRelayUnregister, n as buildTurnStartParams, nt as buildCodexPluginThreadConfigInputFingerprint, ot as mergeCodexThreadConfigs, p as resolveCodexNativeHookRelayTtlMs, pt as resolveRecoverableCodexPluginConfigKeys, q as buildCodexContinuityCalibration, r as buildCodexUserInput, rt as buildCodexPluginThreadConfigTimeoutFallback, s as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, st as shouldBuildCodexPluginThreadConfig, t as buildTurnCollaborationMode, tt as buildCodexPluginThreadConfig, u as createCodexNativeHookRelay, x as resolveCodexWebSearchPlan } from "./thread-lifecycle-Ss-uwnC4.js";
|
|
9
|
+
import { l as isIncognitoSessionKey, r as retainCodexAppServerBindingSubscription } from "./thread-ownership-CeYBqg_4.js";
|
|
10
|
+
import { i as readUpstreamUserText, n as attachUpstreamUserText, r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-CFmsKwr9.js";
|
|
11
|
+
import { a as buildCodexUserPromptMessage, i as mirrorPromptAtTurnStartBestEffort, l as readCodexMirrorSourceFingerprint, n as createCodexAppServerUserMessagePersistenceNotifier, o as promptSnapshot, s as applyCodexTranscriptTaint, t as codexTranscriptMirrorRuntime, u as serializeCodexMirrorSourceEvidence } from "./transcript-mirror-CkEQIna-.js";
|
|
12
|
+
import { t as CODEX_CONTROL_METHODS } from "./capabilities-CGm_94eL.js";
|
|
13
|
+
import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-hFtzt2Up.js";
|
|
14
|
+
import { r as formatCodexDisplayText } from "./command-formatters-C54Yg3eA.js";
|
|
15
|
+
import { a as resolveCodexAppServerForModelProvider, i as resolveCodexSessionPermissionCwd, n as applyCodexSessionPermissionPolicy, r as resolveCodexEffectiveSessionPermissionPolicy } from "./session-permission-policy-gLm40Vtq.js";
|
|
16
|
+
import { n as resolveCodexBindingAppServerConnection } from "./binding-connection-CCQFs8lf.js";
|
|
17
|
+
import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-Ds_QVm-X.js";
|
|
18
|
+
import { t as persistCodexContextCompactionActivity } from "./context-compaction-activity-BOeJf7yo.js";
|
|
19
|
+
import { i as createAssistantMirrorMessage, n as createAssistantCommentaryMessage, r as createAssistantMessage, t as createAssistantAsyncMessage } from "./event-projector-assistant-message-C5-Ds8mA.js";
|
|
20
|
+
import { a as readCodexMirroredSessionHistoryMessages, c as inferCodexDynamicToolMeta, d as sanitizeCodexToolArguments, f as sanitizeCodexToolResponse, i as CodexToolTranscriptProjection, l as isCodexCommandBearingToolCall, n as CodexEventProjection, o as CodexToolProgressProjection, r as emitCodexAgentEvent, s as shouldEmitTranscriptToolProgress, t as codexNativeSubagentMonitorRuntime, u as resolveCodexToolProgressDetailMode } from "./native-subagent-monitor-CwFyoylz.js";
|
|
21
|
+
import { C as shouldRequireCodexSandboxExecServerEnvironment, D as CodexNativeToolLifecycleProjector, E as readBoundedCodexRemoteWorkspaceFile, S as shouldEnableCodexAppServerNativeToolSurface, _ as resolveCodexAppServerHookChannelId, a as emitDynamicToolStartedDiagnostic, c as resolveCodexProviderWebSearchSupport, d as releaseCodexSandboxExecServerEnvironment, f as buildDynamicTools, g as resolveCodexAppServerExecutionCwd, h as formatCodexDynamicToolBuildStageSummary, i as emitDynamicToolErrorDiagnostic, m as disableCodexPluginThreadConfig, n as projectCodexExecutableDynamicTools, o as emitDynamicToolTerminalDiagnostic, p as createCodexDynamicToolBuildStageTracker, r as routeCodexAppServerElicitationRequest, s as handleCodexAppServerApprovalRequest, t as createCodexDynamicToolBridge, u as ensureCodexSandboxExecServerEnvironment, v as resolveCodexExternalSandboxPolicyForOpenClawSandbox, w as shouldWarnCodexDynamicToolBuildStageSummary, x as resolveCodexSandboxEnvironmentSelection, y as resolveCodexMessageToolProvider } from "./dynamic-tools-BFoUcRdx.js";
|
|
22
|
+
import { a as runCodexComputerUseLiveTest, n as ensureCodexComputerUse, t as defaultCodexPluginMetadataCache } from "./plugin-metadata-cache-CulOABwu.js";
|
|
22
23
|
import { asBoolean, asFiniteNumber, asOptionalRecord, hasNonEmptyString, normalizeOptionalString, readNonBlankString, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
23
24
|
import fs from "node:fs/promises";
|
|
24
25
|
import path from "node:path";
|
|
25
26
|
import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
|
|
26
27
|
import { asDateTimestampMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
27
|
-
import { AgentHarnessPreflightError, CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, agentHarnessAttemptTerminal, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine,
|
|
28
|
+
import { AgentHarnessPreflightError, CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, agentHarnessAttemptTerminal, agentHarnessStructuredInput, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildBootstrapContextForFiles, buildEmbeddedForegroundPromptContext, buildHarnessContextEngineRuntimeContext, buildWatchedSessionsHarnessContext, callGatewayTool, cancelPendingAgentQuestionForSession, claimPendingAgentQuestionAnswer, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, detectAndLoadAgentHarnessPromptImages, embeddedAgentLog, emitAgentEvent, emptyAgentHarnessUserInputAnswers, formatErrorMessage, formatFastModeAutoProgressText, getAgentHarnessHookRunner, hasBeforeToolCallPolicy, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, prepareHarnessNativeMcpAppPreview, projectAgentHarnessTranscriptMessageForDisplay, resolveAgentDir, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveAttemptFsWorkspaceOnly, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessAfterCompactionHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
28
29
|
import crypto, { createHash } from "node:crypto";
|
|
29
30
|
import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
|
|
31
|
+
import { resolveAgentConfig as resolveAgentConfig$1, resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
30
32
|
import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
31
33
|
import { parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
+
import { addAbortListener } from "node:events";
|
|
35
|
+
import { truncateUtf16Safe, truncateUtf8Prefix } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
34
36
|
import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
37
|
+
import { isPathStrictlyInside, root } from "openclaw/plugin-sdk/file-access-runtime";
|
|
38
|
+
import { captureFinalCodexCronCreatorToolAllowlist, materializeStaticMcpToolsForScheduledHarnessRun, resolveCodexMcpToolOverridesForAgent } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
39
|
+
import { hasPromptImageInput } from "openclaw/plugin-sdk/session-transcript-runtime";
|
|
40
|
+
import { Buffer as Buffer$1 } from "node:buffer";
|
|
41
|
+
import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
|
|
35
42
|
import { prepareMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
|
|
43
|
+
import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-local-roots";
|
|
44
|
+
import { isSilentReplyPayloadText } from "openclaw/plugin-sdk/reply-chunking";
|
|
36
45
|
import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
|
|
37
46
|
import { resolveGeneratedMediaMaxBytes } from "openclaw/plugin-sdk/media-generation-runtime";
|
|
38
47
|
import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
39
|
-
import {
|
|
48
|
+
import { stripInvisibleUnicode } from "openclaw/plugin-sdk/web-content-extractor";
|
|
40
49
|
import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
|
|
41
50
|
//#region extensions/codex/src/app-server/attempt-steering.ts
|
|
42
51
|
/**
|
|
@@ -63,6 +72,12 @@ function createCodexSteeringQueue(params) {
|
|
|
63
72
|
let sendChain = Promise.resolve();
|
|
64
73
|
let sealedError;
|
|
65
74
|
let closedError;
|
|
75
|
+
const assertActive = () => {
|
|
76
|
+
const unavailableError = closedError ?? sealedError;
|
|
77
|
+
if (unavailableError) throw unavailableError;
|
|
78
|
+
params.signal.throwIfAborted();
|
|
79
|
+
params.assertActive();
|
|
80
|
+
};
|
|
66
81
|
const clearBatchTimer = () => {
|
|
67
82
|
if (batchTimer) {
|
|
68
83
|
clearTimeout(batchTimer);
|
|
@@ -115,19 +130,20 @@ function createCodexSteeringQueue(params) {
|
|
|
115
130
|
const sendBatch = async (items) => {
|
|
116
131
|
const liveItems = items.filter((item) => !item.settled);
|
|
117
132
|
if (liveItems.length === 0) return;
|
|
118
|
-
|
|
119
|
-
if (unavailableError) {
|
|
120
|
-
for (const item of liveItems) rejectItem(item, unavailableError);
|
|
121
|
-
throw unavailableError;
|
|
122
|
-
}
|
|
123
|
-
const clientUserMessageId = `openclaw:${params.turnId}:steer:${++batchSequence}`;
|
|
124
|
-
const batch = { items: liveItems };
|
|
125
|
-
dispatchedBatches.set(clientUserMessageId, batch);
|
|
133
|
+
let clientUserMessageId;
|
|
126
134
|
try {
|
|
135
|
+
assertActive();
|
|
136
|
+
const input = [];
|
|
137
|
+
for (const item of liveItems) {
|
|
138
|
+
input.push(...await params.prepareMessage(item.text, item));
|
|
139
|
+
assertActive();
|
|
140
|
+
}
|
|
141
|
+
clientUserMessageId = `openclaw:${params.turnId}:steer:${++batchSequence}`;
|
|
142
|
+
dispatchedBatches.set(clientUserMessageId, { items: liveItems });
|
|
127
143
|
await params.client.request("turn/steer", {
|
|
128
144
|
threadId: params.threadId,
|
|
129
145
|
expectedTurnId: params.turnId,
|
|
130
|
-
input
|
|
146
|
+
input,
|
|
131
147
|
clientUserMessageId
|
|
132
148
|
}, {
|
|
133
149
|
timeoutMs: params.requestTimeoutMs,
|
|
@@ -135,8 +151,8 @@ function createCodexSteeringQueue(params) {
|
|
|
135
151
|
});
|
|
136
152
|
for (const item of liveItems) reportItemAcceptance(item, true);
|
|
137
153
|
} catch (error) {
|
|
138
|
-
dispatchedBatches.delete(clientUserMessageId);
|
|
139
|
-
const acceptedUnconfirmed = isCodexAppServerIndeterminateRequestCancellationError(error) || isCodexAppServerIndeterminateTransportError(error);
|
|
154
|
+
if (clientUserMessageId) dispatchedBatches.delete(clientUserMessageId);
|
|
155
|
+
const acceptedUnconfirmed = clientUserMessageId !== void 0 && (isCodexAppServerIndeterminateRequestCancellationError(error) || isCodexAppServerIndeterminateTransportError(error));
|
|
140
156
|
for (const item of liveItems) {
|
|
141
157
|
if (acceptedUnconfirmed) reportItemAcceptance(item, true);
|
|
142
158
|
rejectItem(item, error);
|
|
@@ -170,10 +186,9 @@ function createCodexSteeringQueue(params) {
|
|
|
170
186
|
rejectDelivery = reject;
|
|
171
187
|
});
|
|
172
188
|
const item = {
|
|
189
|
+
...options,
|
|
173
190
|
acceptance: "open",
|
|
174
191
|
text,
|
|
175
|
-
images: options?.images,
|
|
176
|
-
onQueueAccepted: options?.onQueueAccepted,
|
|
177
192
|
resolve: resolveDelivery,
|
|
178
193
|
reject: rejectDelivery,
|
|
179
194
|
settled: false
|
|
@@ -188,23 +203,11 @@ function createCodexSteeringQueue(params) {
|
|
|
188
203
|
if (params.signal.aborted) abortQueue();
|
|
189
204
|
return {
|
|
190
205
|
async queue(text, options) {
|
|
191
|
-
|
|
192
|
-
|
|
206
|
+
try {
|
|
207
|
+
assertActive();
|
|
208
|
+
} catch (error) {
|
|
193
209
|
options?.onQueueAccepted?.(false);
|
|
194
|
-
throw
|
|
195
|
-
}
|
|
196
|
-
const pendingUserInput = options?.isInboundUserMessage === true ? params.claimPendingUserInput() : void 0;
|
|
197
|
-
if (pendingUserInput) {
|
|
198
|
-
if (!options?.images?.length) {
|
|
199
|
-
const answered = pendingUserInput.answer(text);
|
|
200
|
-
options?.onQueueAccepted?.(answered);
|
|
201
|
-
if (!answered) throw new Error("codex pending user input rejected the answer");
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
flushBatch().catch(() => void 0);
|
|
205
|
-
const { item, delivery } = createPendingMessage(text, options);
|
|
206
|
-
await Promise.all([enqueueSend([item]).finally(() => pendingUserInput.cancel()), delivery]);
|
|
207
|
-
return;
|
|
210
|
+
throw error;
|
|
208
211
|
}
|
|
209
212
|
const { item, delivery } = createPendingMessage(text, options);
|
|
210
213
|
batchedMessages.push(item);
|
|
@@ -221,8 +224,21 @@ function createCodexSteeringQueue(params) {
|
|
|
221
224
|
const batch = dispatchedBatches.get(clientUserMessageId);
|
|
222
225
|
if (!batch) return false;
|
|
223
226
|
dispatchedBatches.delete(clientUserMessageId);
|
|
224
|
-
for (const item of batch.items)
|
|
225
|
-
|
|
227
|
+
for (const item of batch.items) reportItemAcceptance(item, true);
|
|
228
|
+
const resolveBatch = () => {
|
|
229
|
+
for (const item of batch.items) resolveItem(item);
|
|
230
|
+
return true;
|
|
231
|
+
};
|
|
232
|
+
const rejectBatch = (error) => {
|
|
233
|
+
for (const item of batch.items) rejectItem(item, error);
|
|
234
|
+
return true;
|
|
235
|
+
};
|
|
236
|
+
if (!params.beforeConfirmConsumed) return resolveBatch();
|
|
237
|
+
try {
|
|
238
|
+
return params.beforeConfirmConsumed(batch.items).then(resolveBatch, rejectBatch);
|
|
239
|
+
} catch (error) {
|
|
240
|
+
return rejectBatch(error);
|
|
241
|
+
}
|
|
226
242
|
},
|
|
227
243
|
sealAdmission: sealQueueAdmission,
|
|
228
244
|
cancel: cancelQueue
|
|
@@ -235,15 +251,17 @@ function normalizeCodexSteerDebounceMs(value) {
|
|
|
235
251
|
//#endregion
|
|
236
252
|
//#region extensions/codex/src/app-server/event-projector-assistant.ts
|
|
237
253
|
var CodexAssistantProjection = class {
|
|
238
|
-
constructor(params, emitAgentEvent, matchesToolProgressEcho, nextTranscriptTimestamp) {
|
|
254
|
+
constructor(params, emitAgentEvent, matchesToolProgressEcho, nextTranscriptTimestamp, checkpointCommentary) {
|
|
239
255
|
this.params = params;
|
|
240
256
|
this.emitAgentEvent = emitAgentEvent;
|
|
241
257
|
this.matchesToolProgressEcho = matchesToolProgressEcho;
|
|
242
258
|
this.nextTranscriptTimestamp = nextTranscriptTimestamp;
|
|
259
|
+
this.checkpointCommentary = checkpointCommentary;
|
|
243
260
|
this.assistantTextByItem = /* @__PURE__ */ new Map();
|
|
244
261
|
this.assistantItemOrder = [];
|
|
245
262
|
this.assistantTimestampByItem = /* @__PURE__ */ new Map();
|
|
246
263
|
this.assistantPhaseByItem = /* @__PURE__ */ new Map();
|
|
264
|
+
this.assistantDeliveryByItem = /* @__PURE__ */ new Map();
|
|
247
265
|
this.latestTerminalAssistantCandidateSuperseded = false;
|
|
248
266
|
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
|
|
249
267
|
this.terminalAssistantCandidateEarlierActiveItemIds = /* @__PURE__ */ new Set();
|
|
@@ -253,6 +271,10 @@ var CodexAssistantProjection = class {
|
|
|
253
271
|
this.rawPromotedAssistantItemIds = /* @__PURE__ */ new Set();
|
|
254
272
|
this.assistantStarted = false;
|
|
255
273
|
this.streamedPartialAssistantItemReplaceable = false;
|
|
274
|
+
this.persistableAssistantBarrier = 0;
|
|
275
|
+
this.persistedAssistantBoundary = false;
|
|
276
|
+
this.persistableAssistantBarrierItemIds = /* @__PURE__ */ new Set();
|
|
277
|
+
this.completedAssistantItemIds = /* @__PURE__ */ new Set();
|
|
256
278
|
}
|
|
257
279
|
hasCompletedTerminalAssistantText(completedItemIds) {
|
|
258
280
|
const latestCompletedItemId = this.latestCompletedTerminalAssistantItemId;
|
|
@@ -284,7 +306,8 @@ var CodexAssistantProjection = class {
|
|
|
284
306
|
if (!delta) return;
|
|
285
307
|
if (itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
286
308
|
const isCommentary = this.isCommentaryAssistantItem(itemId);
|
|
287
|
-
|
|
309
|
+
const isAsync = this.isAsyncAssistantItem(itemId);
|
|
310
|
+
if (!isCommentary && !isAsync && itemId !== this.latestTerminalAssistantCandidateItemId) this.markTerminalAssistantCandidateSupersededBy();
|
|
288
311
|
if (!this.assistantStarted) {
|
|
289
312
|
this.assistantStarted = true;
|
|
290
313
|
await this.params.onAssistantMessageStart?.();
|
|
@@ -292,6 +315,7 @@ var CodexAssistantProjection = class {
|
|
|
292
315
|
this.rememberAssistantItem(itemId);
|
|
293
316
|
const text = `${this.assistantTextByItem.get(itemId) ?? ""}${delta}`;
|
|
294
317
|
this.assistantTextByItem.set(itemId, text);
|
|
318
|
+
if (isAsync) return;
|
|
295
319
|
if (isCommentary) {
|
|
296
320
|
this.emitCommentaryProgress({
|
|
297
321
|
itemId,
|
|
@@ -322,23 +346,26 @@ var CodexAssistantProjection = class {
|
|
|
322
346
|
if (knownFinalAnswer && !replaceable) await this.params.onPartialReply?.(streamPayload);
|
|
323
347
|
}
|
|
324
348
|
recordItemStarted(item, itemId) {
|
|
325
|
-
|
|
349
|
+
this.noteNativeWorkBarrier(item);
|
|
326
350
|
this.rememberAssistantPhase(item);
|
|
351
|
+
if (item?.type === "agentMessage" && itemId && !this.isNonTerminalAssistantItem(itemId) && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
327
352
|
if (item?.type === "agentMessage" && itemId) this.rememberAssistantItem(itemId);
|
|
328
|
-
if (itemId && itemId !== this.latestTerminalAssistantCandidateItemId) {
|
|
353
|
+
if (itemId && !this.isNonTerminalAssistantItem(itemId) && itemId !== this.latestTerminalAssistantCandidateItemId) {
|
|
329
354
|
this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
|
|
330
355
|
if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
331
356
|
}
|
|
332
357
|
}
|
|
333
358
|
recordItemCompleted(item, itemId, activeItemIds) {
|
|
334
|
-
if (item?.type === "agentMessage"
|
|
335
|
-
|
|
359
|
+
if (itemId && item?.type === "agentMessage") this.completedAssistantItemIds.add(itemId);
|
|
360
|
+
this.noteNativeWorkBarrier(item);
|
|
336
361
|
this.rememberAssistantPhase(item);
|
|
337
|
-
if (item?.type === "agentMessage" && !this.
|
|
362
|
+
if (item?.type === "agentMessage" && itemId && !this.isNonTerminalAssistantItem(itemId) && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
363
|
+
if (itemId && !this.isNonTerminalAssistantItem(itemId)) this.latestCompletedItemId = itemId;
|
|
364
|
+
if (item?.type === "agentMessage" && !this.isNonTerminalAssistantItem(item.id)) {
|
|
338
365
|
this.latestCompletedTerminalAssistantItemId = item.id;
|
|
339
366
|
this.markLatestTerminalAssistantCandidate(item.id, activeItemIds);
|
|
340
367
|
this.pendingRawTerminalAssistantEchoItemId = item.id;
|
|
341
|
-
} else if (itemId) {
|
|
368
|
+
} else if (itemId && !this.isNonTerminalAssistantItem(itemId)) {
|
|
342
369
|
this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
|
|
343
370
|
if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
344
371
|
}
|
|
@@ -351,14 +378,17 @@ var CodexAssistantProjection = class {
|
|
|
351
378
|
text: item.text
|
|
352
379
|
});
|
|
353
380
|
this.pendingRawCommentaryEchoes += 1;
|
|
354
|
-
} else if (item.text && this.isFinalAnswerAssistantItem(item.id)) this.emitAnswerCandidate(item.id, "candidate");
|
|
381
|
+
} else if (item.text && !this.isAsyncAssistantItem(item.id) && this.isFinalAnswerAssistantItem(item.id)) this.emitAnswerCandidate(item.id, "candidate");
|
|
382
|
+
return this.createAsyncDelivery(item.id);
|
|
355
383
|
}
|
|
356
384
|
}
|
|
357
385
|
recordSnapshotItem(item) {
|
|
386
|
+
if (item.type === "agentMessage") this.completedAssistantItemIds.add(item.id);
|
|
358
387
|
this.rememberAssistantPhase(item);
|
|
359
388
|
if (item.type === "agentMessage" && typeof item.text === "string") {
|
|
360
389
|
this.rememberAssistantItem(item.id);
|
|
361
390
|
this.assistantTextByItem.set(item.id, item.text);
|
|
391
|
+
return this.createAsyncDelivery(item.id);
|
|
362
392
|
}
|
|
363
393
|
}
|
|
364
394
|
handleRawResponseItemCompleted(item, activeItemIds) {
|
|
@@ -392,6 +422,7 @@ var CodexAssistantProjection = class {
|
|
|
392
422
|
const isIdlessTerminalAssistantAfterCompletedWork = candidateWasSupersededBeforeRaw && rawItemId === void 0 && pendingTerminalAssistantEchoItemId === void 0 && activeItemIds.size === 0;
|
|
393
423
|
if (text && phase !== "commentary" && candidateWasSupersededBeforeRaw && itemId !== this.streamedPartialAssistantItemId && !isIdlessTerminalAssistantAfterCompletedWork) return;
|
|
394
424
|
if (phase) this.assistantPhaseByItem.set(itemId, phase);
|
|
425
|
+
this.completedAssistantItemIds.add(itemId);
|
|
395
426
|
this.rememberAssistantItem(itemId);
|
|
396
427
|
this.assistantTextByItem.set(itemId, text);
|
|
397
428
|
if (!text) return;
|
|
@@ -403,21 +434,64 @@ var CodexAssistantProjection = class {
|
|
|
403
434
|
else this.markLatestTerminalAssistantCandidate(itemId, activeItemIds, { canReleaseAfterToolHandoff: isIdlessTerminalAssistantAfterCompletedWork });
|
|
404
435
|
}
|
|
405
436
|
collectAssistantTexts() {
|
|
406
|
-
const
|
|
407
|
-
|
|
437
|
+
const afterHandoff = this.collectPersistableAssistantTexts(this.persistableAssistantBarrier);
|
|
438
|
+
const audibleAfterHandoff = afterHandoff.filter((text) => !isSilentReplyPayloadText(text));
|
|
439
|
+
if (audibleAfterHandoff.length > 0) return audibleAfterHandoff;
|
|
440
|
+
if (afterHandoff.length > 0) return afterHandoff.slice(-1);
|
|
441
|
+
if (this.persistedAssistantBoundary) return [];
|
|
442
|
+
const recoveredAudible = this.collectPersistableAssistantTexts(0).filter((text) => !isSilentReplyPayloadText(text));
|
|
443
|
+
if (recoveredAudible.length > 0) return recoveredAudible.slice(-1);
|
|
444
|
+
const recovered = this.resolveFinalAssistantTextItem()?.text;
|
|
445
|
+
return recovered ? [recovered] : [];
|
|
408
446
|
}
|
|
409
447
|
collectCommentaryMessages() {
|
|
410
448
|
return this.assistantItemOrder.flatMap((itemId) => {
|
|
411
|
-
|
|
449
|
+
const message = this.readCommentaryMessage(itemId);
|
|
450
|
+
return message ? [{
|
|
451
|
+
itemId,
|
|
452
|
+
message
|
|
453
|
+
}] : [];
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
readCommentaryMessage(itemId) {
|
|
457
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
458
|
+
const timestamp = this.assistantTimestampByItem.get(itemId);
|
|
459
|
+
return this.isCommentaryAssistantItem(itemId) && text && timestamp !== void 0 ? createAssistantCommentaryMessage(this.params, text, itemId, timestamp) : void 0;
|
|
460
|
+
}
|
|
461
|
+
collectAsyncMessages() {
|
|
462
|
+
return this.assistantItemOrder.flatMap((itemId) => {
|
|
463
|
+
if (!this.isAsyncAssistantItem(itemId)) return [];
|
|
412
464
|
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
413
465
|
const timestamp = this.assistantTimestampByItem.get(itemId);
|
|
414
466
|
if (!text || timestamp === void 0) return [];
|
|
415
467
|
return [{
|
|
416
468
|
itemId,
|
|
417
|
-
message:
|
|
469
|
+
message: createAssistantAsyncMessage(this.params, text, itemId, timestamp)
|
|
418
470
|
}];
|
|
419
471
|
});
|
|
420
472
|
}
|
|
473
|
+
collectCompletedAssistantMessages(completedItemIds, options) {
|
|
474
|
+
return this.assistantItemOrder.flatMap((itemId) => {
|
|
475
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
476
|
+
if (!completedItemIds.has(itemId) || this.isNonTerminalAssistantItem(itemId) || !text || isSilentReplyPayloadText(text) || this.isToolProgressEchoText(itemId, text)) return [];
|
|
477
|
+
const message = this.createAssistantMessage(text, options);
|
|
478
|
+
const timestamp = this.assistantTimestampByItem.get(itemId) ?? message.timestamp;
|
|
479
|
+
return [{
|
|
480
|
+
itemId,
|
|
481
|
+
message: {
|
|
482
|
+
...message,
|
|
483
|
+
timestamp
|
|
484
|
+
}
|
|
485
|
+
}];
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
markAssistantBoundaryPersisted(itemId) {
|
|
489
|
+
const index = this.assistantItemOrder.indexOf(itemId);
|
|
490
|
+
if (index >= 0) {
|
|
491
|
+
this.persistableAssistantBarrier = Math.max(this.persistableAssistantBarrier, index + 1);
|
|
492
|
+
this.persistedAssistantBoundary = true;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
421
495
|
finalizeAnswerCandidate(turn) {
|
|
422
496
|
if (turn.status !== "completed") {
|
|
423
497
|
this.supersedeVisibleAnswerCandidate();
|
|
@@ -427,7 +501,7 @@ var CodexAssistantProjection = class {
|
|
|
427
501
|
const authoritativeIndex = turnItems.findLastIndex((item) => {
|
|
428
502
|
if (item.type !== "agentMessage" || typeof item.text !== "string" || item.text.trim().length === 0) return false;
|
|
429
503
|
const phase = readItemString(item, "phase");
|
|
430
|
-
return phase === "final_answer" || phase === void 0;
|
|
504
|
+
return readItemString(item, "delivery") !== "async" && (phase === "final_answer" || phase === void 0);
|
|
431
505
|
});
|
|
432
506
|
const authoritative = authoritativeIndex >= 0 ? turnItems[authoritativeIndex] : void 0;
|
|
433
507
|
if (turnItems.slice(authoritativeIndex + 1).some(shouldClearTerminalPresentationForNativeItem) || authoritative?.id === this.latestTerminalAssistantCandidateItemId && this.latestTerminalAssistantCandidateSuperseded) {
|
|
@@ -445,7 +519,7 @@ var CodexAssistantProjection = class {
|
|
|
445
519
|
hasAssistantItemTextForSynthesis() {
|
|
446
520
|
for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
|
|
447
521
|
const itemId = this.assistantItemOrder[i];
|
|
448
|
-
if (!itemId || this.
|
|
522
|
+
if (!itemId || this.isNonTerminalAssistantItem(itemId)) continue;
|
|
449
523
|
const text = this.assistantTextByItem.get(itemId);
|
|
450
524
|
if (text && text.length > 0) return true;
|
|
451
525
|
}
|
|
@@ -454,7 +528,7 @@ var CodexAssistantProjection = class {
|
|
|
454
528
|
createCurrentAttemptAssistantMessage(options) {
|
|
455
529
|
for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
|
|
456
530
|
const itemId = this.assistantItemOrder[i];
|
|
457
|
-
if (!itemId || this.
|
|
531
|
+
if (!itemId || this.isNonTerminalAssistantItem(itemId) || !this.assistantTextByItem.has(itemId)) continue;
|
|
458
532
|
const text = this.assistantTextByItem.get(itemId) ?? "";
|
|
459
533
|
const normalizedText = text.trim();
|
|
460
534
|
if (normalizedText && this.isToolProgressEchoText(itemId, normalizedText)) continue;
|
|
@@ -475,10 +549,18 @@ var CodexAssistantProjection = class {
|
|
|
475
549
|
if (item?.type !== "agentMessage") return;
|
|
476
550
|
const phase = readItemString(item, "phase");
|
|
477
551
|
if (phase) this.assistantPhaseByItem.set(item.id, phase);
|
|
552
|
+
const delivery = readItemString(item, "delivery");
|
|
553
|
+
if (delivery) this.assistantDeliveryByItem.set(item.id, delivery);
|
|
478
554
|
}
|
|
479
555
|
isCommentaryAssistantItem(itemId) {
|
|
480
556
|
return this.assistantPhaseByItem.get(itemId) === "commentary";
|
|
481
557
|
}
|
|
558
|
+
isAsyncAssistantItem(itemId) {
|
|
559
|
+
return this.assistantDeliveryByItem.get(itemId) === "async";
|
|
560
|
+
}
|
|
561
|
+
isNonTerminalAssistantItem(itemId) {
|
|
562
|
+
return this.isCommentaryAssistantItem(itemId) || this.isAsyncAssistantItem(itemId);
|
|
563
|
+
}
|
|
482
564
|
isFinalAnswerAssistantItem(itemId) {
|
|
483
565
|
return this.assistantPhaseByItem.get(itemId) === "final_answer";
|
|
484
566
|
}
|
|
@@ -486,7 +568,7 @@ var CodexAssistantProjection = class {
|
|
|
486
568
|
return this.assistantPhaseByItem.get(itemId) === "final_answer";
|
|
487
569
|
}
|
|
488
570
|
emitCommentaryProgress(params) {
|
|
489
|
-
const progressText = params.text.
|
|
571
|
+
const progressText = params.text.trim();
|
|
490
572
|
if (!progressText || this.lastCommentaryProgressTextByItem.get(params.itemId) === progressText) return;
|
|
491
573
|
this.lastCommentaryProgressTextByItem.set(params.itemId, progressText);
|
|
492
574
|
this.emitAgentEvent({
|
|
@@ -553,22 +635,104 @@ var CodexAssistantProjection = class {
|
|
|
553
635
|
const itemId = this.assistantItemOrder[i];
|
|
554
636
|
if (!itemId) continue;
|
|
555
637
|
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
556
|
-
if (this.
|
|
638
|
+
if (this.isNonTerminalAssistantItem(itemId)) continue;
|
|
557
639
|
if (text && !this.isToolProgressEchoText(itemId, text)) return {
|
|
558
640
|
itemId,
|
|
559
641
|
text
|
|
560
642
|
};
|
|
561
643
|
}
|
|
562
644
|
}
|
|
645
|
+
collectPersistableAssistantTexts(minIndex) {
|
|
646
|
+
let texts = [];
|
|
647
|
+
let replaceable = false;
|
|
648
|
+
for (let index = minIndex; index < this.assistantItemOrder.length; index += 1) {
|
|
649
|
+
const itemId = this.assistantItemOrder[index];
|
|
650
|
+
if (!itemId || this.isNonTerminalAssistantItem(itemId)) continue;
|
|
651
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
652
|
+
if (!text || this.isToolProgressEchoText(itemId, text)) continue;
|
|
653
|
+
if (isSilentReplyPayloadText(text)) {
|
|
654
|
+
texts.push(text);
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
657
|
+
const isTerminalFinal = this.assistantPhaseByItem.get(itemId) === "final_answer";
|
|
658
|
+
if (!isTerminalFinal || replaceable) {
|
|
659
|
+
texts = [text];
|
|
660
|
+
replaceable = !isTerminalFinal;
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
texts.push(text);
|
|
664
|
+
}
|
|
665
|
+
return texts;
|
|
666
|
+
}
|
|
667
|
+
noteNativeWorkBarrier(item) {
|
|
668
|
+
if (!item || !shouldAdvancePersistableAssistantBarrier(item)) return;
|
|
669
|
+
if (item.id && this.persistableAssistantBarrierItemIds.has(item.id)) return;
|
|
670
|
+
if (item.id) this.persistableAssistantBarrierItemIds.add(item.id);
|
|
671
|
+
this.persistableAssistantBarrier = this.assistantItemOrder.length;
|
|
672
|
+
}
|
|
563
673
|
rememberAssistantItem(itemId) {
|
|
564
|
-
if (!itemId
|
|
565
|
-
this.
|
|
566
|
-
|
|
674
|
+
if (!itemId) return;
|
|
675
|
+
if (!this.assistantTimestampByItem.has(itemId)) {
|
|
676
|
+
this.assistantItemOrder.push(itemId);
|
|
677
|
+
this.assistantTimestampByItem.set(itemId, this.nextTranscriptTimestamp());
|
|
678
|
+
}
|
|
679
|
+
if (this.isCommentaryAssistantItem(itemId)) this.checkpointCommentary?.(itemId, {
|
|
680
|
+
read: () => this.readCommentaryMessage(itemId),
|
|
681
|
+
ready: () => this.completedAssistantItemIds.has(itemId)
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
createAsyncDelivery(itemId) {
|
|
685
|
+
if (!this.isAsyncAssistantItem(itemId)) return;
|
|
686
|
+
const text = this.assistantTextByItem.get(itemId);
|
|
687
|
+
const timestamp = this.assistantTimestampByItem.get(itemId);
|
|
688
|
+
if (!text?.trim() || timestamp === void 0) return;
|
|
689
|
+
return {
|
|
690
|
+
itemId,
|
|
691
|
+
message: createAssistantAsyncMessage(this.params, text, itemId, timestamp),
|
|
692
|
+
text
|
|
693
|
+
};
|
|
567
694
|
}
|
|
568
695
|
isToolProgressEchoText(itemId, text) {
|
|
569
696
|
return this.rawPromotedAssistantItemIds.has(itemId) && this.matchesToolProgressEcho(text);
|
|
570
697
|
}
|
|
571
698
|
};
|
|
699
|
+
function shouldAdvancePersistableAssistantBarrier(item) {
|
|
700
|
+
return shouldClearTerminalPresentationForNativeItem(item) || item.type === "dynamicToolCall" || item.type === "sleep";
|
|
701
|
+
}
|
|
702
|
+
//#endregion
|
|
703
|
+
//#region extensions/codex/src/app-server/event-projector-async-delivery.ts
|
|
704
|
+
/** Owns authorization, exactly-once settlement, and terminal retry for async user messages. */
|
|
705
|
+
var CodexAsyncDeliveryProjection = class {
|
|
706
|
+
constructor(params, threadId, turnId, options) {
|
|
707
|
+
this.params = params;
|
|
708
|
+
this.threadId = threadId;
|
|
709
|
+
this.turnId = turnId;
|
|
710
|
+
this.options = options;
|
|
711
|
+
this.settledItemIds = /* @__PURE__ */ new Set();
|
|
712
|
+
this.pendingDeliveries = /* @__PURE__ */ new Map();
|
|
713
|
+
}
|
|
714
|
+
allows(item, reportUnauthorized = false) {
|
|
715
|
+
if (item?.type !== "agentMessage" || item.delivery !== "async") return true;
|
|
716
|
+
const allowed = this.params.disableTools !== true && (this.options.asyncUserMessageAllowed ?? (this.params.toolsAllow === void 0 || this.params.toolsAllow.some((name) => name === "*" || name === "message")));
|
|
717
|
+
if (!allowed && reportUnauthorized) embeddedAgentLog.warn("blocked unauthorized codex async user message", {
|
|
718
|
+
itemId: item.id,
|
|
719
|
+
threadId: this.threadId,
|
|
720
|
+
turnId: this.turnId
|
|
721
|
+
});
|
|
722
|
+
return allowed;
|
|
723
|
+
}
|
|
724
|
+
pending() {
|
|
725
|
+
return [...this.pendingDeliveries.values()];
|
|
726
|
+
}
|
|
727
|
+
async deliver(delivery) {
|
|
728
|
+
if (this.settledItemIds.has(delivery.itemId)) return;
|
|
729
|
+
const settlement = await this.options.onAsyncDelivery?.(delivery);
|
|
730
|
+
if (settlement === "settled") {
|
|
731
|
+
this.settledItemIds.add(delivery.itemId);
|
|
732
|
+
this.pendingDeliveries.delete(delivery.itemId);
|
|
733
|
+
} else if (settlement === "retry") this.pendingDeliveries.set(delivery.itemId, delivery);
|
|
734
|
+
}
|
|
735
|
+
};
|
|
572
736
|
//#endregion
|
|
573
737
|
//#region extensions/codex/src/app-server/event-projector-media.ts
|
|
574
738
|
const GENERATED_IMAGE_MEDIA_SUBDIR = "tool-image-generation";
|
|
@@ -739,9 +903,10 @@ function isBase64WhitespaceCode(code) {
|
|
|
739
903
|
//#endregion
|
|
740
904
|
//#region extensions/codex/src/app-server/event-projector-reasoning.ts
|
|
741
905
|
var CodexReasoningProjection = class {
|
|
742
|
-
constructor(params, emitAgentEvent) {
|
|
906
|
+
constructor(params, emitAgentEvent, onNativePlanUpdate) {
|
|
743
907
|
this.params = params;
|
|
744
908
|
this.emitAgentEvent = emitAgentEvent;
|
|
909
|
+
this.onNativePlanUpdate = onNativePlanUpdate;
|
|
745
910
|
this.reasoningTextByGroup = /* @__PURE__ */ new Map();
|
|
746
911
|
this.reasoningItemOrder = /* @__PURE__ */ new Map();
|
|
747
912
|
this.planTextByItem = /* @__PURE__ */ new Map();
|
|
@@ -782,7 +947,7 @@ var CodexReasoningProjection = class {
|
|
|
782
947
|
}))
|
|
783
948
|
});
|
|
784
949
|
}
|
|
785
|
-
handleTurnPlanUpdated(params, source = "codex-app-server") {
|
|
950
|
+
async handleTurnPlanUpdated(params, source = "codex-app-server") {
|
|
786
951
|
const explanation = readNullableString(params, "explanation");
|
|
787
952
|
const plan = Array.isArray(params.plan) ? params.plan.flatMap((entry) => {
|
|
788
953
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [];
|
|
@@ -796,6 +961,10 @@ var CodexReasoningProjection = class {
|
|
|
796
961
|
}) : void 0;
|
|
797
962
|
const planText = [explanation, ...(plan ?? []).map(({ step, status }) => `- [${status}] ${step}`)].filter((part) => Boolean(part)).join("\n");
|
|
798
963
|
if (planText) this.turnPlanText = planText;
|
|
964
|
+
if (source === "codex-app-server" && plan) await this.onNativePlanUpdate?.({
|
|
965
|
+
...typeof explanation === "string" ? { markdown: explanation } : {},
|
|
966
|
+
steps: plan
|
|
967
|
+
});
|
|
799
968
|
this.emitPlanUpdate({
|
|
800
969
|
explanation,
|
|
801
970
|
steps: plan
|
|
@@ -825,7 +994,7 @@ var CodexReasoningProjection = class {
|
|
|
825
994
|
return this.turnPlanText ?? [...this.planTextByItem.values()].filter((text) => text.trim().length > 0).join("\n\n");
|
|
826
995
|
}
|
|
827
996
|
emitPlanUpdate(params, source = "codex-app-server") {
|
|
828
|
-
if (!params.explanation &&
|
|
997
|
+
if (!params.explanation && params.steps === void 0) return;
|
|
829
998
|
this.emitAgentEvent({
|
|
830
999
|
stream: "plan",
|
|
831
1000
|
data: {
|
|
@@ -833,7 +1002,7 @@ var CodexReasoningProjection = class {
|
|
|
833
1002
|
title: "Plan updated",
|
|
834
1003
|
source,
|
|
835
1004
|
...params.explanation ? { explanation: params.explanation } : {},
|
|
836
|
-
...params.steps
|
|
1005
|
+
...params.steps ? { steps: params.steps } : {}
|
|
837
1006
|
}
|
|
838
1007
|
});
|
|
839
1008
|
}
|
|
@@ -858,50 +1027,64 @@ function reasoningMethodOrder(method) {
|
|
|
858
1027
|
const attemptTerminal = agentHarnessAttemptTerminal;
|
|
859
1028
|
//#endregion
|
|
860
1029
|
//#region extensions/codex/src/app-server/event-projector-snapshot.ts
|
|
861
|
-
function readTurnTaintMetadata(message) {
|
|
862
|
-
const metadata = message["__openclaw"];
|
|
863
|
-
return metadata && typeof metadata === "object" && !Array.isArray(metadata) ? metadata : void 0;
|
|
864
|
-
}
|
|
865
|
-
function applyStickyTurnTaint(messages) {
|
|
866
|
-
let tainted = false;
|
|
867
|
-
return messages.map((message) => {
|
|
868
|
-
if (message.role === "user") {
|
|
869
|
-
tainted = false;
|
|
870
|
-
return message;
|
|
871
|
-
}
|
|
872
|
-
const metadata = readTurnTaintMetadata(message);
|
|
873
|
-
tainted ||= metadata?.turnTainted === true || metadata?.resultContentSource === "network";
|
|
874
|
-
return message.role === "assistant" && tainted ? {
|
|
875
|
-
...message,
|
|
876
|
-
__openclaw: {
|
|
877
|
-
...metadata,
|
|
878
|
-
turnTainted: true
|
|
879
|
-
}
|
|
880
|
-
} : message;
|
|
881
|
-
});
|
|
882
|
-
}
|
|
883
1030
|
function buildCodexMessagesSnapshot(params) {
|
|
884
1031
|
const messages = promptSnapshot(params.runParams, params.turnId, params.upstreamUserText);
|
|
885
1032
|
if (params.reasoningText) messages.push(attachCodexMirrorIdentity(params.createAssistantMirrorMessage("Codex reasoning", params.reasoningText), `${params.turnId}:reasoning`));
|
|
886
|
-
|
|
887
|
-
const
|
|
1033
|
+
const commentaryMessages = params.runParams.config?.ui?.prefs?.chatPersistCommentary === false ? [] : params.commentaryMessages.map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:commentary:${itemId}`));
|
|
1034
|
+
const asyncMessages = params.asyncMessages.map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:async:${itemId}`));
|
|
1035
|
+
const visibleWorkMessages = [
|
|
1036
|
+
...commentaryMessages,
|
|
1037
|
+
...asyncMessages,
|
|
1038
|
+
...(params.assistantMessages ?? []).map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:assistant:${itemId}`)),
|
|
1039
|
+
...params.toolMessages
|
|
1040
|
+
].toSorted((left, right) => (asDateTimestampMs(left.timestamp) ?? 0) - (asDateTimestampMs(right.timestamp) ?? 0));
|
|
888
1041
|
messages.push(...visibleWorkMessages);
|
|
889
1042
|
if (params.lastAssistant) messages.push(attachCodexMirrorIdentity(params.lastAssistant, `${params.turnId}:assistant`));
|
|
890
|
-
|
|
1043
|
+
const taint = { tainted: false };
|
|
1044
|
+
return messages.map((message) => projectAgentHarnessTranscriptMessageForDisplay({
|
|
891
1045
|
hidden: params.runParams.trigger === "memory",
|
|
892
|
-
message
|
|
1046
|
+
message: applyCodexTranscriptTaint(message, taint)
|
|
893
1047
|
}));
|
|
894
1048
|
}
|
|
1049
|
+
function buildCodexSteeringMessagesSnapshot(params) {
|
|
1050
|
+
const asyncMessages = params.assistantProjection.collectAsyncMessages().filter(({ itemId }) => params.completedItemIds.has(itemId));
|
|
1051
|
+
const commentaryMessages = params.assistantProjection.collectCommentaryMessages().filter(({ itemId }) => params.completedItemIds.has(itemId));
|
|
1052
|
+
const assistantMessages = params.assistantProjection.collectCompletedAssistantMessages(params.completedItemIds, {
|
|
1053
|
+
tokenUsage: void 0,
|
|
1054
|
+
aborted: false,
|
|
1055
|
+
promptError: void 0
|
|
1056
|
+
});
|
|
1057
|
+
return {
|
|
1058
|
+
messages: buildCodexMessagesSnapshot({
|
|
1059
|
+
runParams: params.runParams,
|
|
1060
|
+
turnId: params.turnId,
|
|
1061
|
+
upstreamUserText: params.upstreamUserText,
|
|
1062
|
+
reasoningText: void 0,
|
|
1063
|
+
asyncMessages,
|
|
1064
|
+
commentaryMessages,
|
|
1065
|
+
assistantMessages,
|
|
1066
|
+
toolMessages: params.toolMessages,
|
|
1067
|
+
lastAssistant: void 0,
|
|
1068
|
+
createAssistantMirrorMessage: (title, text) => params.assistantProjection.createAssistantMirrorMessage(title, text)
|
|
1069
|
+
}).filter((message) => message.role !== "user"),
|
|
1070
|
+
assistantBoundaryItemId: assistantMessages.at(-1)?.itemId
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
895
1073
|
//#endregion
|
|
896
1074
|
//#region extensions/codex/src/app-server/event-projector-result.ts
|
|
897
1075
|
function buildCodexAttemptResult(input) {
|
|
898
1076
|
input.nativeToolLifecycleProjection.finalizeActive();
|
|
899
1077
|
const assistantTexts = input.assistantProjection.collectAssistantTexts();
|
|
1078
|
+
const asyncMessages = input.assistantProjection.collectAsyncMessages();
|
|
900
1079
|
const commentaryMessages = input.assistantProjection.collectCommentaryMessages();
|
|
901
1080
|
const reasoningText = input.reasoningProjection.reasoningText();
|
|
902
1081
|
const planText = input.reasoningProjection.planText();
|
|
903
|
-
const
|
|
904
|
-
|
|
1082
|
+
const unavailableThreadUsage = input.tokenUsage ? {
|
|
1083
|
+
...input.tokenUsage,
|
|
1084
|
+
contextUsage: { state: "unavailable" }
|
|
1085
|
+
} : void 0;
|
|
1086
|
+
const completedUsage = input.responseCompletions.usage ?? (input.responseCompletions.modelIterations > 0 ? unavailableThreadUsage : input.tokenUsage);
|
|
1087
|
+
const projectedUsage = input.aborted ? unavailableThreadUsage : completedUsage;
|
|
905
1088
|
const hasAssistantItemText = input.assistantProjection.hasAssistantItemTextForSynthesis();
|
|
906
1089
|
const legacyFailClosed = !input.completedTurn || input.completedTurn.status !== "completed" || hasAssistantItemText;
|
|
907
1090
|
const hasDeliverableAssistantOnCompletedTurn = input.completedTurn?.status === "completed" && assistantTexts.some((text) => text.trim().length > 0);
|
|
@@ -927,7 +1110,7 @@ function buildCodexAttemptResult(input) {
|
|
|
927
1110
|
turnId: input.turnId,
|
|
928
1111
|
upstreamUserText: input.upstreamUserText,
|
|
929
1112
|
reasoningText,
|
|
930
|
-
|
|
1113
|
+
asyncMessages,
|
|
931
1114
|
commentaryMessages,
|
|
932
1115
|
toolMessages: input.toolTranscriptProjection.transcriptMessages,
|
|
933
1116
|
lastAssistant,
|
|
@@ -976,6 +1159,7 @@ function buildCodexAttemptResult(input) {
|
|
|
976
1159
|
acceptedSessionSpawns: input.toolTelemetry.acceptedSessionSpawns,
|
|
977
1160
|
cloudCodeAssistFormatError: false,
|
|
978
1161
|
contextTokens: input.contextTokens,
|
|
1162
|
+
contextTokensSource: input.contextTokensSource,
|
|
979
1163
|
attemptUsage: projectedUsage,
|
|
980
1164
|
...input.completedCompactionCount > 0 ? { compactionCount: input.completedCompactionCount } : {},
|
|
981
1165
|
replayMetadata: {
|
|
@@ -992,6 +1176,78 @@ function buildCodexAttemptResult(input) {
|
|
|
992
1176
|
};
|
|
993
1177
|
}
|
|
994
1178
|
//#endregion
|
|
1179
|
+
//#region extensions/codex/src/app-server/transcript-checkpoint.ts
|
|
1180
|
+
/** Commits completed work in receipt order without waiting for the enclosing turn. */
|
|
1181
|
+
var CodexTranscriptCheckpoint = class {
|
|
1182
|
+
constructor(params, threadId, turnId) {
|
|
1183
|
+
this.params = params;
|
|
1184
|
+
this.threadId = threadId;
|
|
1185
|
+
this.turnId = turnId;
|
|
1186
|
+
this.pending = [];
|
|
1187
|
+
this.commentaryItemIds = /* @__PURE__ */ new Set();
|
|
1188
|
+
this.lastTimestamp = 0;
|
|
1189
|
+
this.writing = Promise.resolve();
|
|
1190
|
+
this.tainted = false;
|
|
1191
|
+
this.closed = false;
|
|
1192
|
+
this.nextTimestamp = () => {
|
|
1193
|
+
this.lastTimestamp = Math.max(Date.now(), this.lastTimestamp + 1);
|
|
1194
|
+
return this.lastTimestamp;
|
|
1195
|
+
};
|
|
1196
|
+
this.enqueueCommentary = (itemId, entry) => {
|
|
1197
|
+
if (this.params.config?.ui?.prefs?.chatPersistCommentary === false || this.commentaryItemIds.has(itemId)) return;
|
|
1198
|
+
this.commentaryItemIds.add(itemId);
|
|
1199
|
+
this.enqueue({
|
|
1200
|
+
...entry,
|
|
1201
|
+
read: () => {
|
|
1202
|
+
const message = entry.read();
|
|
1203
|
+
return message ? attachCodexMirrorIdentity(message, `${this.turnId}:commentary:${itemId}`) : void 0;
|
|
1204
|
+
}
|
|
1205
|
+
});
|
|
1206
|
+
};
|
|
1207
|
+
this.enqueue = (entry) => {
|
|
1208
|
+
if (this.params.sessionTarget && !this.closed) this.pending.push(entry);
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
flush(close = false) {
|
|
1212
|
+
if (this.closed) return this.writing;
|
|
1213
|
+
this.closed = close;
|
|
1214
|
+
this.writing = this.writing.then(async () => {
|
|
1215
|
+
const blocked = close ? -1 : this.pending.findIndex((entry) => entry.ready?.() === false);
|
|
1216
|
+
const count = blocked < 0 ? this.pending.length : blocked;
|
|
1217
|
+
if (count === 0) return;
|
|
1218
|
+
const taint = { tainted: this.tainted };
|
|
1219
|
+
const messages = this.pending.slice(0, count).flatMap((entry) => {
|
|
1220
|
+
const message = entry.read();
|
|
1221
|
+
return message ? [projectAgentHarnessTranscriptMessageForDisplay({
|
|
1222
|
+
hidden: this.params.trigger === "memory",
|
|
1223
|
+
message: applyCodexTranscriptTaint(message, taint)
|
|
1224
|
+
})] : [];
|
|
1225
|
+
});
|
|
1226
|
+
try {
|
|
1227
|
+
await codexTranscriptMirrorRuntime.mirror({
|
|
1228
|
+
...this.params.sessionTarget,
|
|
1229
|
+
sessionId: this.params.sessionId,
|
|
1230
|
+
cwd: this.params.workspaceDir,
|
|
1231
|
+
messages,
|
|
1232
|
+
idempotencyScope: `codex-app-server:${this.threadId}`,
|
|
1233
|
+
runId: this.params.runId,
|
|
1234
|
+
runMirrorIdentityPrefix: `${this.turnId}:`,
|
|
1235
|
+
config: this.params.config
|
|
1236
|
+
});
|
|
1237
|
+
this.pending.splice(0, count);
|
|
1238
|
+
this.tainted = taint.tainted;
|
|
1239
|
+
} catch (error) {
|
|
1240
|
+
embeddedAgentLog.warn("failed to checkpoint codex app-server transcript", {
|
|
1241
|
+
runId: this.params.runId,
|
|
1242
|
+
sessionId: this.params.sessionId,
|
|
1243
|
+
error: formatErrorMessage(error)
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
});
|
|
1247
|
+
return this.writing;
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
//#endregion
|
|
995
1251
|
//#region extensions/codex/src/app-server/usage-limit-error.ts
|
|
996
1252
|
/**
|
|
997
1253
|
* Enriches Codex usage-limit failures with current rate-limit information and
|
|
@@ -1146,8 +1402,10 @@ var CodexAppServerEventProjector = class {
|
|
|
1146
1402
|
this.aborted = false;
|
|
1147
1403
|
this.responseCompletions = new CodexResponseCompletionProjection();
|
|
1148
1404
|
this.completedCompactionCount = 0;
|
|
1149
|
-
this.
|
|
1405
|
+
this.transcriptCheckpoint = new CodexTranscriptCheckpoint(params, threadId, turnId);
|
|
1406
|
+
this.asyncDeliveryProjection = new CodexAsyncDeliveryProjection(params, threadId, turnId, options);
|
|
1150
1407
|
this.contextTokens = options.initialContextTokens;
|
|
1408
|
+
this.contextTokensSource = options.initialContextTokens === void 0 ? void 0 : "resolved";
|
|
1151
1409
|
this.diagnostics = new CodexProjectionDiagnostics(threadId, turnId);
|
|
1152
1410
|
this.nativeToolLifecycleProjector = new CodexNativeToolLifecycleProjector(params, threadId, turnId, { runAbortSignal: options.runAbortSignal });
|
|
1153
1411
|
this.generatedMediaProjection = new CodexGeneratedMediaProjection(params.config, {
|
|
@@ -1157,22 +1415,38 @@ var CodexAppServerEventProjector = class {
|
|
|
1157
1415
|
signal: options.runAbortSignal
|
|
1158
1416
|
});
|
|
1159
1417
|
this.toolProgressProjection = new CodexToolProgressProjection(params);
|
|
1160
|
-
this.toolTranscriptProjection = new CodexToolTranscriptProjection(params, threadId, turnId, this.toolProgressProjection,
|
|
1418
|
+
this.toolTranscriptProjection = new CodexToolTranscriptProjection(params, threadId, turnId, this.toolProgressProjection, this.transcriptCheckpoint.nextTimestamp, {
|
|
1161
1419
|
nativePostToolUseRelayEnabled: options.nativePostToolUseRelayEnabled,
|
|
1162
1420
|
prepareNativeMcpAppResultDetails: options.prepareNativeMcpAppResultDetails,
|
|
1163
|
-
trajectoryRecorder: options.trajectoryRecorder
|
|
1421
|
+
trajectoryRecorder: options.trajectoryRecorder,
|
|
1422
|
+
checkpointMessage: this.transcriptCheckpoint.enqueue
|
|
1164
1423
|
});
|
|
1165
1424
|
this.eventProjection = new CodexEventProjection(threadId, turnId, (event) => this.emitAgentEvent(event), this.toolProgressProjection, this.toolTranscriptProjection, options.onNativeToolResultRecorded);
|
|
1166
|
-
this.assistantProjection = new CodexAssistantProjection(params, (event) => this.emitAgentEvent(event), (text) => this.toolProgressProjection.matchesEcho(text),
|
|
1167
|
-
this.reasoningProjection = new CodexReasoningProjection(params, (event) => this.emitAgentEvent(event));
|
|
1168
|
-
}
|
|
1169
|
-
nextTranscriptTimestamp() {
|
|
1170
|
-
this.lastTranscriptTimestamp = Math.max(Date.now(), this.lastTranscriptTimestamp + 1);
|
|
1171
|
-
return this.lastTranscriptTimestamp;
|
|
1425
|
+
this.assistantProjection = new CodexAssistantProjection(params, (event) => this.emitAgentEvent(event), (text) => this.toolProgressProjection.matchesEcho(text), this.transcriptCheckpoint.nextTimestamp, this.transcriptCheckpoint.enqueueCommentary);
|
|
1426
|
+
this.reasoningProjection = new CodexReasoningProjection(params, (event) => this.emitAgentEvent(event), options.onNativePlanUpdate);
|
|
1172
1427
|
}
|
|
1173
1428
|
getCompletedTurnStatus() {
|
|
1174
1429
|
return this.completedTurn?.status;
|
|
1175
1430
|
}
|
|
1431
|
+
buildSteeringTranscriptPrefix() {
|
|
1432
|
+
const snapshot = buildCodexSteeringMessagesSnapshot({
|
|
1433
|
+
runParams: this.params,
|
|
1434
|
+
turnId: this.turnId,
|
|
1435
|
+
upstreamUserText: this.options.upstreamUserText,
|
|
1436
|
+
completedItemIds: this.completedItemIds,
|
|
1437
|
+
assistantProjection: this.assistantProjection,
|
|
1438
|
+
toolMessages: this.toolTranscriptProjection.transcriptMessages
|
|
1439
|
+
});
|
|
1440
|
+
this.pendingSteeringAssistantBoundaryItemId = snapshot.assistantBoundaryItemId;
|
|
1441
|
+
return snapshot.messages;
|
|
1442
|
+
}
|
|
1443
|
+
markSteeringTranscriptPersisted() {
|
|
1444
|
+
const itemId = this.pendingSteeringAssistantBoundaryItemId;
|
|
1445
|
+
if (itemId) {
|
|
1446
|
+
this.assistantProjection.markAssistantBoundaryPersisted(itemId);
|
|
1447
|
+
this.pendingSteeringAssistantBoundaryItemId = void 0;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1176
1450
|
hasCompletedTerminalAssistantText() {
|
|
1177
1451
|
return this.assistantProjection.hasCompletedTerminalAssistantText(this.completedItemIds);
|
|
1178
1452
|
}
|
|
@@ -1199,8 +1473,9 @@ var CodexAppServerEventProjector = class {
|
|
|
1199
1473
|
const ordinal = this.params.allocateToolOutcomeOrdinal?.(item.id);
|
|
1200
1474
|
if (ordinal !== void 0) this.nativeToolOutcomeOrdinals.set(item.id, ordinal);
|
|
1201
1475
|
}
|
|
1202
|
-
recordNativeToolApprovalFailure(toolCallId, disposition) {
|
|
1476
|
+
recordNativeToolApprovalFailure(toolCallId, disposition, approvalKind) {
|
|
1203
1477
|
this.nativeToolLifecycleProjector.recordApprovalFailureDisposition(toolCallId, disposition);
|
|
1478
|
+
if (disposition === "timed_out" && approvalKind) this.toolProgressProjection.approvalTimeoutKinds.set(toolCallId, approvalKind);
|
|
1204
1479
|
}
|
|
1205
1480
|
recordNativeToolPreToolUseFailure(failure) {
|
|
1206
1481
|
this.nativeToolLifecycleProjector.recordPreToolUseFailure(failure);
|
|
@@ -1210,9 +1485,11 @@ var CodexAppServerEventProjector = class {
|
|
|
1210
1485
|
if (!params) return;
|
|
1211
1486
|
if (notification.method === "hook/started" || notification.method === "hook/completed") {
|
|
1212
1487
|
if (!this.isHookNotificationForCurrentThread(params)) return;
|
|
1213
|
-
} else if (notification.method === "guardianWarning") {
|
|
1214
|
-
|
|
1488
|
+
} else if (notification.method === "guardianWarning" || notification.method === "warning" || notification.method === "configWarning") {
|
|
1489
|
+
const warningThreadId = readCodexNotificationThreadId(params);
|
|
1490
|
+
if (notification.method === "guardianWarning" && warningThreadId !== this.threadId || warningThreadId && warningThreadId !== this.threadId) return;
|
|
1215
1491
|
} else if (!isCodexNotificationForTurn(params, this.threadId, this.turnId)) return;
|
|
1492
|
+
if (notification.method !== "guardianWarning" && notification.method !== "item/autoApprovalReview/started" && notification.method !== "item/autoApprovalReview/completed") this.eventProjection.flushPendingGuardianWarning();
|
|
1216
1493
|
this.nativeToolLifecycleProjector.handleNotification(notification);
|
|
1217
1494
|
this.assistantProjection.handleNotification(notification.method, params);
|
|
1218
1495
|
switch (notification.method) {
|
|
@@ -1227,13 +1504,15 @@ var CodexAppServerEventProjector = class {
|
|
|
1227
1504
|
this.reasoningProjection.handlePlanDelta(params);
|
|
1228
1505
|
break;
|
|
1229
1506
|
case "turn/plan/updated":
|
|
1230
|
-
this.reasoningProjection.handleTurnPlanUpdated(params);
|
|
1507
|
+
await this.reasoningProjection.handleTurnPlanUpdated(params);
|
|
1231
1508
|
break;
|
|
1232
1509
|
case "item/started":
|
|
1233
1510
|
await this.handleItemStarted(params);
|
|
1511
|
+
await this.transcriptCheckpoint.flush();
|
|
1234
1512
|
break;
|
|
1235
1513
|
case "item/completed":
|
|
1236
1514
|
await this.handleItemCompleted(params);
|
|
1515
|
+
await this.transcriptCheckpoint.flush();
|
|
1237
1516
|
break;
|
|
1238
1517
|
case "item/commandExecution/outputDelta":
|
|
1239
1518
|
this.toolProgressProjection.handleOutputDelta(params, "bash");
|
|
@@ -1242,18 +1521,28 @@ var CodexAppServerEventProjector = class {
|
|
|
1242
1521
|
case "item/autoApprovalReview/completed":
|
|
1243
1522
|
this.eventProjection.handleGuardianReview(notification.method, params);
|
|
1244
1523
|
break;
|
|
1524
|
+
case "autoApprovalReview/strictReviewRequired":
|
|
1525
|
+
this.eventProjection.handleStrictReviewRequired(params);
|
|
1526
|
+
break;
|
|
1245
1527
|
case "guardianWarning":
|
|
1246
1528
|
this.eventProjection.handleGuardianWarning(params);
|
|
1247
1529
|
break;
|
|
1530
|
+
case "warning":
|
|
1531
|
+
case "configWarning":
|
|
1532
|
+
this.eventProjection.handleWarning(params);
|
|
1533
|
+
break;
|
|
1248
1534
|
case "hook/started":
|
|
1249
1535
|
case "hook/completed":
|
|
1250
1536
|
this.eventProjection.handleHook(notification.method, params);
|
|
1251
1537
|
break;
|
|
1252
1538
|
case "thread/tokenUsage/updated":
|
|
1253
1539
|
projectCodexThreadUsageUpdate(params, this.tokenUsage, (usage) => this.tokenUsage = usage, (data) => {
|
|
1254
|
-
|
|
1540
|
+
if (data.modelContextWindow !== void 0) {
|
|
1541
|
+
this.contextTokens = data.modelContextWindow;
|
|
1542
|
+
this.contextTokensSource = this.params.authoredContextTokenCap === void 0 ? "runtime" : "runtime-configured";
|
|
1543
|
+
}
|
|
1255
1544
|
this.emitAgentEvent({
|
|
1256
|
-
stream: "
|
|
1545
|
+
stream: "usage",
|
|
1257
1546
|
data
|
|
1258
1547
|
});
|
|
1259
1548
|
});
|
|
@@ -1266,14 +1555,21 @@ var CodexAppServerEventProjector = class {
|
|
|
1266
1555
|
break;
|
|
1267
1556
|
case "rawResponseItem/completed":
|
|
1268
1557
|
await this.handleRawResponseItemCompleted(params);
|
|
1558
|
+
await this.transcriptCheckpoint.flush();
|
|
1559
|
+
break;
|
|
1560
|
+
case "model/rerouted":
|
|
1561
|
+
this.eventProjection.handleModelRerouted(params);
|
|
1269
1562
|
break;
|
|
1270
|
-
case "error":
|
|
1563
|
+
case "error": {
|
|
1271
1564
|
this.responseCompletions.clear();
|
|
1272
1565
|
if (params.willRetry === true) break;
|
|
1273
|
-
|
|
1566
|
+
const codexErrorInfo = isJsonObject(params.error) ? params.error.codexErrorInfo : void 0;
|
|
1567
|
+
const compactionFailure = codexErrorInfo === "other" && this.isCompacting();
|
|
1568
|
+
this.settledTurnFailureFinalizationAllowed = codexErrorInfo === "serverOverloaded" || compactionFailure;
|
|
1274
1569
|
this.promptError = this.formatCodexErrorMessage(params) ?? "codex app-server error";
|
|
1275
|
-
this.promptErrorSource = "prompt";
|
|
1570
|
+
this.promptErrorSource = compactionFailure ? "compaction" : "prompt";
|
|
1276
1571
|
break;
|
|
1572
|
+
}
|
|
1277
1573
|
case "thread/compacted":
|
|
1278
1574
|
case "turn/started":
|
|
1279
1575
|
case "turn/diff/updated":
|
|
@@ -1282,7 +1578,6 @@ var CodexAppServerEventProjector = class {
|
|
|
1282
1578
|
case "item/fileChange/outputDelta":
|
|
1283
1579
|
case "item/fileChange/patchUpdated":
|
|
1284
1580
|
case "item/mcpToolCall/progress":
|
|
1285
|
-
case "model/rerouted":
|
|
1286
1581
|
case "model/verification":
|
|
1287
1582
|
case "turn/moderationMetadata":
|
|
1288
1583
|
case "model/safetyBuffering/updated": break;
|
|
@@ -1292,6 +1587,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1292
1587
|
}
|
|
1293
1588
|
}
|
|
1294
1589
|
buildResult(toolTelemetry, options) {
|
|
1590
|
+
this.eventProjection.flushPendingGuardianWarning();
|
|
1295
1591
|
return buildCodexAttemptResult({
|
|
1296
1592
|
runParams: this.params,
|
|
1297
1593
|
turnId: this.turnId,
|
|
@@ -1307,6 +1603,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1307
1603
|
aborted: this.aborted,
|
|
1308
1604
|
tokenUsage: this.tokenUsage,
|
|
1309
1605
|
contextTokens: this.contextTokens,
|
|
1606
|
+
contextTokensSource: this.contextTokensSource,
|
|
1310
1607
|
completedCompactionCount: this.completedCompactionCount,
|
|
1311
1608
|
activeItemCount: this.activeItemIds.size,
|
|
1312
1609
|
completedItemCount: this.completedItemIds.size,
|
|
@@ -1325,9 +1622,12 @@ var CodexAppServerEventProjector = class {
|
|
|
1325
1622
|
recordDynamicToolCall(params) {
|
|
1326
1623
|
this.toolTranscriptProjection.recordDynamicToolCall(params);
|
|
1327
1624
|
}
|
|
1328
|
-
/** Projects a successful OpenClaw
|
|
1329
|
-
|
|
1330
|
-
if (isJsonObject(params))
|
|
1625
|
+
/** Projects a successful OpenClaw progress_card call through the native plan stream. */
|
|
1626
|
+
async recordDynamicProgressCardUpdate(params) {
|
|
1627
|
+
if (isJsonObject(params)) {
|
|
1628
|
+
const projected = { plan: Array.isArray(params.plan) ? params.plan : [] };
|
|
1629
|
+
await this.reasoningProjection.handleTurnPlanUpdated(projected, "openclaw");
|
|
1630
|
+
}
|
|
1331
1631
|
}
|
|
1332
1632
|
recordDynamicToolResult(params) {
|
|
1333
1633
|
this.toolProgressProjection.recordDynamicToolResult(params);
|
|
@@ -1409,13 +1709,15 @@ var CodexAppServerEventProjector = class {
|
|
|
1409
1709
|
this.activeItemIds.delete(itemId);
|
|
1410
1710
|
this.completedItemIds.add(itemId);
|
|
1411
1711
|
}
|
|
1412
|
-
this.
|
|
1712
|
+
if (!this.asyncDeliveryProjection.allows(item, true)) return;
|
|
1713
|
+
const asyncMessage = this.assistantProjection.recordItemCompleted(item, itemId, this.activeItemIds);
|
|
1714
|
+
if (asyncMessage) await this.asyncDeliveryProjection.deliver(asyncMessage);
|
|
1413
1715
|
this.reasoningProjection.recordItem(item);
|
|
1414
1716
|
await this.generatedMediaProjection.recordNative(item);
|
|
1415
1717
|
if (item?.type === "contextCompaction" && itemId) {
|
|
1416
1718
|
this.activeCompactionItemIds.delete(itemId);
|
|
1417
1719
|
this.completedCompactionCount += 1;
|
|
1418
|
-
this.options.onContextCompacted?.();
|
|
1720
|
+
await this.options.onContextCompacted?.();
|
|
1419
1721
|
await runAgentHarnessAfterCompactionHook({
|
|
1420
1722
|
sessionFile: this.params.sessionFile,
|
|
1421
1723
|
messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
|
|
@@ -1431,17 +1733,17 @@ var CodexAppServerEventProjector = class {
|
|
|
1431
1733
|
channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
|
|
1432
1734
|
}
|
|
1433
1735
|
});
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
}
|
|
1736
|
+
await persistCodexContextCompactionActivity({
|
|
1737
|
+
sessionTarget: this.params.sessionTarget,
|
|
1738
|
+
config: this.params.config,
|
|
1739
|
+
cwd: this.params.workspaceDir,
|
|
1740
|
+
runId: this.params.runId,
|
|
1741
|
+
threadId: this.threadId,
|
|
1742
|
+
turnId: this.turnId,
|
|
1743
|
+
itemId,
|
|
1744
|
+
timestamp: this.transcriptCheckpoint.nextTimestamp()
|
|
1444
1745
|
});
|
|
1746
|
+
this.eventProjection.emitCompactionEnd(itemId, true);
|
|
1445
1747
|
}
|
|
1446
1748
|
this.toolProgressProjection.recordToolMeta(item);
|
|
1447
1749
|
this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
|
|
@@ -1470,7 +1772,8 @@ var CodexAppServerEventProjector = class {
|
|
|
1470
1772
|
const turn = readCodexTurn(params.turn);
|
|
1471
1773
|
if (!turn || turn.id !== this.turnId) return;
|
|
1472
1774
|
this.completedTurn = turn;
|
|
1473
|
-
|
|
1775
|
+
const compactionFailure = turn.status === "failed" && (this.promptErrorSource === "compaction" || turn.error?.codexErrorInfo === "other" && this.isCompacting());
|
|
1776
|
+
this.settledTurnFailureFinalizationAllowed = turn.status === "failed" && (turn.error?.codexErrorInfo === "serverOverloaded" || compactionFailure);
|
|
1474
1777
|
if (turn.status !== "completed") this.responseCompletions.clear();
|
|
1475
1778
|
if (turn.status === "failed") {
|
|
1476
1779
|
const usageLimitMessage = formatCodexUsageLimitErrorMessage({
|
|
@@ -1479,9 +1782,18 @@ var CodexAppServerEventProjector = class {
|
|
|
1479
1782
|
rateLimits: this.options.readRecentRateLimits?.()
|
|
1480
1783
|
});
|
|
1481
1784
|
this.promptError = usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : turn.error?.message ?? "codex app-server turn failed";
|
|
1482
|
-
this.promptErrorSource = "prompt";
|
|
1785
|
+
this.promptErrorSource = compactionFailure ? "compaction" : "prompt";
|
|
1786
|
+
}
|
|
1787
|
+
if (compactionFailure) {
|
|
1788
|
+
const failedCompactionItemIds = [...this.activeCompactionItemIds];
|
|
1789
|
+
for (const itemId of failedCompactionItemIds) {
|
|
1790
|
+
this.activeItemIds.delete(itemId);
|
|
1791
|
+
this.activeCompactionItemIds.delete(itemId);
|
|
1792
|
+
this.eventProjection.emitCompactionEnd(itemId, false);
|
|
1793
|
+
}
|
|
1483
1794
|
}
|
|
1484
1795
|
const turnItems = turn.items ?? [];
|
|
1796
|
+
const unsettledAsyncDeliveries = this.asyncDeliveryProjection.pending();
|
|
1485
1797
|
for (let index = turnItems.length - 1; index >= 0; index -= 1) {
|
|
1486
1798
|
const item = turnItems[index];
|
|
1487
1799
|
if (!item || !this.isCurrentTurnSnapshotItem(item)) continue;
|
|
@@ -1492,8 +1804,10 @@ var CodexAppServerEventProjector = class {
|
|
|
1492
1804
|
}
|
|
1493
1805
|
}
|
|
1494
1806
|
for (const item of turnItems) {
|
|
1807
|
+
if (!this.asyncDeliveryProjection.allows(item)) continue;
|
|
1495
1808
|
this.diagnostics.warnUnknownItemStatus(item);
|
|
1496
|
-
this.assistantProjection.recordSnapshotItem(item);
|
|
1809
|
+
const asyncMessage = this.assistantProjection.recordSnapshotItem(item);
|
|
1810
|
+
if (asyncMessage) await this.asyncDeliveryProjection.deliver(asyncMessage);
|
|
1497
1811
|
this.reasoningProjection.recordItem(item);
|
|
1498
1812
|
await this.generatedMediaProjection.recordNative(item);
|
|
1499
1813
|
this.toolProgressProjection.recordToolMeta(item);
|
|
@@ -1505,6 +1819,8 @@ var CodexAppServerEventProjector = class {
|
|
|
1505
1819
|
this.toolProgressProjection.emitToolResultSummary(item);
|
|
1506
1820
|
this.toolProgressProjection.emitToolResultOutput(item);
|
|
1507
1821
|
}
|
|
1822
|
+
this.toolProgressProjection.approvalTimeoutKinds.clear();
|
|
1823
|
+
for (const delivery of unsettledAsyncDeliveries) await this.asyncDeliveryProjection.deliver(delivery);
|
|
1508
1824
|
this.assistantProjection.finalizeAnswerCandidate(turn);
|
|
1509
1825
|
this.activeCompactionItemIds.clear();
|
|
1510
1826
|
await this.reasoningProjection.maybeEndReasoning();
|
|
@@ -1566,24 +1882,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1566
1882
|
return usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : readCodexErrorNotificationMessage(params);
|
|
1567
1883
|
}
|
|
1568
1884
|
emitAgentEvent(event) {
|
|
1569
|
-
|
|
1570
|
-
emitAgentEvent({
|
|
1571
|
-
runId: this.params.runId,
|
|
1572
|
-
stream: event.stream,
|
|
1573
|
-
data: event.data,
|
|
1574
|
-
...this.params.sessionKey ? { sessionKey: this.params.sessionKey } : {}
|
|
1575
|
-
});
|
|
1576
|
-
} catch (error) {
|
|
1577
|
-
embeddedAgentLog.debug("codex app-server global agent event emit failed", { error });
|
|
1578
|
-
}
|
|
1579
|
-
try {
|
|
1580
|
-
const maybePromise = this.params.onAgentEvent?.(event);
|
|
1581
|
-
Promise.resolve(maybePromise).catch((error) => {
|
|
1582
|
-
embeddedAgentLog.debug("codex app-server agent event handler rejected", { error });
|
|
1583
|
-
});
|
|
1584
|
-
} catch (error) {
|
|
1585
|
-
embeddedAgentLog.debug("codex app-server agent event handler threw", { error });
|
|
1586
|
-
}
|
|
1885
|
+
emitCodexAgentEvent(this.params, event);
|
|
1587
1886
|
}
|
|
1588
1887
|
isHookNotificationForCurrentThread(params) {
|
|
1589
1888
|
const threadId = readStringField(params, "threadId");
|
|
@@ -1592,11 +1891,28 @@ var CodexAppServerEventProjector = class {
|
|
|
1592
1891
|
}
|
|
1593
1892
|
};
|
|
1594
1893
|
//#endregion
|
|
1894
|
+
//#region extensions/codex/src/app-server/mcp-tool-metadata.ts
|
|
1895
|
+
/** Hosted app ownership is authoritative only on metadata supplied by Codex. */
|
|
1896
|
+
function readCodexMcpToolConnectorId(tool) {
|
|
1897
|
+
const metadata = asOptionalRecord(asOptionalRecord(tool)?.["_meta"]);
|
|
1898
|
+
return normalizeOptionalString(metadata?.connector_id) ?? normalizeOptionalString(metadata?.connectorId);
|
|
1899
|
+
}
|
|
1900
|
+
/** Preserve MCP App visibility so model-only tools cannot become widget authority. */
|
|
1901
|
+
function readCodexMcpToolUiVisibility(tool) {
|
|
1902
|
+
const visibility = asOptionalRecord(asOptionalRecord(asOptionalRecord(tool)?.["_meta"])?.ui)?.visibility;
|
|
1903
|
+
if (!Array.isArray(visibility)) return;
|
|
1904
|
+
return [...new Set(visibility.filter((value) => value === "app" || value === "model"))].toSorted();
|
|
1905
|
+
}
|
|
1906
|
+
//#endregion
|
|
1595
1907
|
//#region extensions/codex/src/app-server/native-mcp-app.ts
|
|
1908
|
+
const CODEX_APPS_MCP_SERVER$1 = "codex_apps";
|
|
1596
1909
|
function readMcpAppResourceUri(item) {
|
|
1597
1910
|
const uri = normalizeOptionalString(asOptionalRecord(item.appContext)?.resourceUri) ?? normalizeOptionalString(item.mcpAppResourceUri);
|
|
1598
1911
|
return uri?.startsWith("ui://") ? uri : void 0;
|
|
1599
1912
|
}
|
|
1913
|
+
function readMcpAppConnectorId(item) {
|
|
1914
|
+
return normalizeOptionalString(asOptionalRecord(item.appContext)?.connectorId);
|
|
1915
|
+
}
|
|
1600
1916
|
function readMcpToolResult(item) {
|
|
1601
1917
|
const result = asOptionalRecord(item.result);
|
|
1602
1918
|
if (!result || !Array.isArray(result.content)) return;
|
|
@@ -1634,13 +1950,16 @@ function createNativeMcpRuntime(params) {
|
|
|
1634
1950
|
launchSummary: "Codex native MCP connection",
|
|
1635
1951
|
toolCount: Object.keys(status.tools).length
|
|
1636
1952
|
}])),
|
|
1637
|
-
tools: loaded.flatMap((status) => statusTools(status).map((tool) =>
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1953
|
+
tools: loaded.flatMap((status) => statusTools(status).map((tool) => {
|
|
1954
|
+
const uiVisibility = readCodexMcpToolUiVisibility(tool);
|
|
1955
|
+
return Object.assign({
|
|
1956
|
+
serverName: status.name,
|
|
1957
|
+
safeServerName: status.name,
|
|
1958
|
+
toolName: String(tool.name),
|
|
1959
|
+
inputSchema: asOptionalRecord(tool.inputSchema) ?? { type: "object" },
|
|
1960
|
+
fallbackDescription: normalizeOptionalString(tool.description) ?? String(tool.name)
|
|
1961
|
+
}, uiVisibility ? { uiVisibility } : {});
|
|
1962
|
+
}))
|
|
1644
1963
|
};
|
|
1645
1964
|
return catalog;
|
|
1646
1965
|
};
|
|
@@ -1668,11 +1987,18 @@ function createNativeMcpRuntime(params) {
|
|
|
1668
1987
|
const status = (await loadStatuses()).find((entry) => entry.name === serverName);
|
|
1669
1988
|
return { tools: status ? statusTools(status) : [] };
|
|
1670
1989
|
},
|
|
1671
|
-
readResource: async (serverName, uri) =>
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1990
|
+
readResource: async (serverName, uri) => {
|
|
1991
|
+
const isCodexAppsServer = serverName === CODEX_APPS_MCP_SERVER$1;
|
|
1992
|
+
const response = await params.client.request("mcpServer/resource/read", {
|
|
1993
|
+
threadId: params.threadId,
|
|
1994
|
+
...isCodexAppsServer ? { originCallId: params.originCallId } : {},
|
|
1995
|
+
server: serverName,
|
|
1996
|
+
uri,
|
|
1997
|
+
...params.connectorId ? { connectorId: params.connectorId } : {}
|
|
1998
|
+
});
|
|
1999
|
+
if (isCodexAppsServer && response.originCallId !== params.originCallId) throw new Error(`Codex MCP resource response originCallId mismatch: expected ${params.originCallId}, received ${response.originCallId}`);
|
|
2000
|
+
return response;
|
|
2001
|
+
},
|
|
1676
2002
|
listResources: async (serverName) => {
|
|
1677
2003
|
return { resources: (await loadStatuses()).find((entry) => entry.name === serverName)?.resources ?? [] };
|
|
1678
2004
|
},
|
|
@@ -1685,15 +2011,25 @@ function createNativeMcpRuntime(params) {
|
|
|
1685
2011
|
}
|
|
1686
2012
|
function createCodexNativeMcpAppResultDetailsPreparer(params) {
|
|
1687
2013
|
if (params.attempt.config?.mcp?.apps?.enabled !== true) return;
|
|
1688
|
-
const runtime = createNativeMcpRuntime(params);
|
|
1689
2014
|
return async (item) => {
|
|
1690
2015
|
const serverName = normalizeOptionalString(item.server);
|
|
1691
2016
|
const toolName = normalizeOptionalString(item.tool);
|
|
1692
2017
|
const uiResourceUri = readMcpAppResourceUri(item);
|
|
2018
|
+
const connectorId = readMcpAppConnectorId(item);
|
|
1693
2019
|
const toolResult = readMcpToolResult(item);
|
|
1694
2020
|
if (!serverName || !toolName || !uiResourceUri || !toolResult) return;
|
|
1695
|
-
|
|
1696
|
-
|
|
2021
|
+
if (serverName === CODEX_APPS_MCP_SERVER$1 && !connectorId) return;
|
|
2022
|
+
const runtime = createNativeMcpRuntime({
|
|
2023
|
+
...params,
|
|
2024
|
+
originCallId: item.id,
|
|
2025
|
+
...connectorId ? { connectorId } : {}
|
|
2026
|
+
});
|
|
2027
|
+
const tools = (await runtime.listTools?.(serverName))?.tools ?? [];
|
|
2028
|
+
const allowedAppToolNames = new Set(tools.filter((tool) => {
|
|
2029
|
+
const uiVisibility = readCodexMcpToolUiVisibility(tool);
|
|
2030
|
+
return (uiVisibility === void 0 || uiVisibility.includes("app")) && (serverName !== CODEX_APPS_MCP_SERVER$1 || readCodexMcpToolConnectorId(tool) === connectorId);
|
|
2031
|
+
}).map((tool) => tool.name));
|
|
2032
|
+
if (!allowedAppToolNames.has(toolName)) return;
|
|
1697
2033
|
return await prepareHarnessNativeMcpAppPreview({
|
|
1698
2034
|
runtime,
|
|
1699
2035
|
serverName,
|
|
@@ -1708,184 +2044,347 @@ function createCodexNativeMcpAppResultDetailsPreparer(params) {
|
|
|
1708
2044
|
};
|
|
1709
2045
|
}
|
|
1710
2046
|
//#endregion
|
|
2047
|
+
//#region extensions/codex/src/app-server/plan-compaction-state.ts
|
|
2048
|
+
const RESTORED_PLAN_PREAMBLE = "OpenClaw restored the session progress card after context compaction. This is application state, not a new user request. Continue the current task and call progress_card whenever the status meaningfully changes.";
|
|
2049
|
+
const PROGRESS_CARD_MAX_STEPS = 50;
|
|
2050
|
+
const PROGRESS_CARD_MAX_STEP_UTF8_BYTES = 512;
|
|
2051
|
+
const PROGRESS_CARD_MAX_UTF8_BYTES = 8 * 1024;
|
|
2052
|
+
const RESTORED_PLAN_MAX_MARKDOWN_BYTES = 2 * 1024;
|
|
2053
|
+
const RESTORED_PLAN_MAX_PAYLOAD_BYTES = 32 * 1024;
|
|
2054
|
+
const RESTORED_PLAN_TRUNCATION_SUFFIX = "…";
|
|
2055
|
+
function canonicalizeNativeProgressCardInput(input) {
|
|
2056
|
+
const markdown = input.markdown === void 0 ? void 0 : truncateUtf8(stripInvisibleUnicode(input.markdown), PROGRESS_CARD_MAX_UTF8_BYTES);
|
|
2057
|
+
const plan = [];
|
|
2058
|
+
let hasInProgressStep = false;
|
|
2059
|
+
for (const step of input.steps.slice(0, PROGRESS_CARD_MAX_STEPS)) {
|
|
2060
|
+
const text = truncateUtf8(stripInvisibleUnicode(step.step), PROGRESS_CARD_MAX_STEP_UTF8_BYTES);
|
|
2061
|
+
if (!text.trim()) continue;
|
|
2062
|
+
let status = step.status;
|
|
2063
|
+
if (status === "in_progress") if (hasInProgressStep) status = "pending";
|
|
2064
|
+
else hasInProgressStep = true;
|
|
2065
|
+
plan.push({
|
|
2066
|
+
step: text,
|
|
2067
|
+
status
|
|
2068
|
+
});
|
|
2069
|
+
}
|
|
2070
|
+
return {
|
|
2071
|
+
...markdown !== void 0 ? { markdown } : {},
|
|
2072
|
+
plan
|
|
2073
|
+
};
|
|
2074
|
+
}
|
|
2075
|
+
/** Retains the latest projected plan so Codex compaction cannot discard it. */
|
|
2076
|
+
var CodexCompactionPlanState = class {
|
|
2077
|
+
record(event) {
|
|
2078
|
+
if (event.stream !== "plan") return;
|
|
2079
|
+
const plan = readBoundedPlan(event.data.explanation, event.data.steps);
|
|
2080
|
+
this.latestPlan = plan;
|
|
2081
|
+
}
|
|
2082
|
+
/** Retains markdown that migration-only plan events intentionally omit. */
|
|
2083
|
+
recordProgressCardInput(value) {
|
|
2084
|
+
if (!isJsonObject(value)) return;
|
|
2085
|
+
this.latestPlan = readBoundedPlan(value.markdown, value.plan);
|
|
2086
|
+
}
|
|
2087
|
+
async restore(params) {
|
|
2088
|
+
if (!this.latestPlan) return;
|
|
2089
|
+
await params.client.request("thread/inject_items", {
|
|
2090
|
+
threadId: params.threadId,
|
|
2091
|
+
items: [{
|
|
2092
|
+
type: "message",
|
|
2093
|
+
role: "user",
|
|
2094
|
+
content: [{
|
|
2095
|
+
type: "input_text",
|
|
2096
|
+
text: `${RESTORED_PLAN_PREAMBLE}\n${serializePlan(this.latestPlan)}`
|
|
2097
|
+
}]
|
|
2098
|
+
}]
|
|
2099
|
+
}, {
|
|
2100
|
+
timeoutMs: params.timeoutMs,
|
|
2101
|
+
signal: params.signal
|
|
2102
|
+
});
|
|
2103
|
+
}
|
|
2104
|
+
};
|
|
2105
|
+
function readBoundedPlan(markdownValue, stepsValue) {
|
|
2106
|
+
const canonical = canonicalizeNativeProgressCardInput({
|
|
2107
|
+
...typeof markdownValue === "string" ? { markdown: markdownValue } : {},
|
|
2108
|
+
steps: readPlanSteps(stepsValue)
|
|
2109
|
+
});
|
|
2110
|
+
const markdown = canonical.markdown === void 0 ? void 0 : truncateUtf8(canonical.markdown, RESTORED_PLAN_MAX_MARKDOWN_BYTES);
|
|
2111
|
+
const steps = [];
|
|
2112
|
+
for (const step of canonical.plan) {
|
|
2113
|
+
const candidate = {
|
|
2114
|
+
...markdown?.trim() ? { markdown } : {},
|
|
2115
|
+
steps: [...steps, step]
|
|
2116
|
+
};
|
|
2117
|
+
if (Buffer$1.byteLength(serializePlan(candidate), "utf8") > RESTORED_PLAN_MAX_PAYLOAD_BYTES) break;
|
|
2118
|
+
steps.push(step);
|
|
2119
|
+
}
|
|
2120
|
+
return markdown?.trim() || steps.length > 0 ? {
|
|
2121
|
+
...markdown?.trim() ? { markdown } : {},
|
|
2122
|
+
steps
|
|
2123
|
+
} : void 0;
|
|
2124
|
+
}
|
|
2125
|
+
function serializePlan(plan) {
|
|
2126
|
+
return JSON.stringify({
|
|
2127
|
+
markdown: plan.markdown,
|
|
2128
|
+
plan: plan.steps
|
|
2129
|
+
});
|
|
2130
|
+
}
|
|
2131
|
+
function truncateUtf8(value, maxBytes) {
|
|
2132
|
+
if (Buffer$1.byteLength(value, "utf8") <= maxBytes) return value;
|
|
2133
|
+
return `${truncateUtf8Prefix(value, maxBytes - Buffer$1.byteLength(RESTORED_PLAN_TRUNCATION_SUFFIX, "utf8"))}${RESTORED_PLAN_TRUNCATION_SUFFIX}`;
|
|
2134
|
+
}
|
|
2135
|
+
function readPlanSteps(value) {
|
|
2136
|
+
if (!Array.isArray(value)) return [];
|
|
2137
|
+
return value.flatMap((entry) => {
|
|
2138
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [];
|
|
2139
|
+
const { step, status } = entry;
|
|
2140
|
+
if (typeof step !== "string" || !isPlanStatus(status)) return [];
|
|
2141
|
+
return [{
|
|
2142
|
+
step,
|
|
2143
|
+
status
|
|
2144
|
+
}];
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
function isPlanStatus(value) {
|
|
2148
|
+
return value === "pending" || value === "in_progress" || value === "completed";
|
|
2149
|
+
}
|
|
2150
|
+
//#endregion
|
|
1711
2151
|
//#region extensions/codex/src/app-server/user-input-bridge.ts
|
|
1712
|
-
/**
|
|
2152
|
+
/** Owns per-turn Codex request_user_input and ordinary MCP elicitation lifecycles. */
|
|
1713
2153
|
const DEFAULT_USER_INPUT_TIMEOUT_MS = 15 * 6e4;
|
|
1714
2154
|
const NONBLOCKING_USER_INPUT_TIMEOUT_MS = 12e4;
|
|
1715
|
-
|
|
2155
|
+
const MAX_USER_INPUT_QUESTIONS = 3;
|
|
2156
|
+
const MAX_USER_INPUT_OPTIONS = 4;
|
|
2157
|
+
const MAX_USER_INPUT_ID = 256;
|
|
2158
|
+
const MAX_USER_INPUT_HEADER = 64;
|
|
2159
|
+
const MAX_USER_INPUT_TEXT = 4096;
|
|
2160
|
+
/** Creates the single per-turn owner for Codex operator input. */
|
|
1716
2161
|
function createCodexUserInputBridge(params) {
|
|
1717
|
-
let sensitiveInput;
|
|
1718
|
-
let pendingGateway;
|
|
1719
2162
|
const gatewayCall = params.gatewayCall ?? callGatewayTool;
|
|
1720
|
-
const
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
2163
|
+
const jobs = [];
|
|
2164
|
+
let activeCompletion;
|
|
2165
|
+
const inputSessionKey = params.paramsForRun.sessionKey ?? params.paramsForRun.sessionId;
|
|
2166
|
+
const pump = () => {
|
|
2167
|
+
const job = jobs[0];
|
|
2168
|
+
if (activeCompletion || !job) return;
|
|
2169
|
+
activeCompletion = job.run(job.abort.signal).catch((error) => {
|
|
2170
|
+
embeddedAgentLog.warn("failed to bridge codex operator input", { error });
|
|
2171
|
+
return job.abort.signal.aborted ? job.cancelValue : job.failureValue;
|
|
2172
|
+
}).then((value) => {
|
|
2173
|
+
job.resolve(job.abort.signal.aborted ? job.cancelValue : value ?? job.failureValue);
|
|
2174
|
+
}).finally(() => {
|
|
2175
|
+
if (jobs[0] === job) jobs.shift();
|
|
2176
|
+
activeCompletion = void 0;
|
|
2177
|
+
pump();
|
|
2178
|
+
});
|
|
1731
2179
|
};
|
|
1732
|
-
const
|
|
1733
|
-
|
|
2180
|
+
const enqueue = (definition) => {
|
|
2181
|
+
if (params.signal?.aborted) return Promise.resolve(definition.cancelValue);
|
|
2182
|
+
return new Promise((resolve) => {
|
|
2183
|
+
jobs.push({
|
|
2184
|
+
...definition,
|
|
2185
|
+
resolve
|
|
2186
|
+
});
|
|
2187
|
+
pump();
|
|
2188
|
+
});
|
|
1734
2189
|
};
|
|
2190
|
+
const cancelJob = (job) => {
|
|
2191
|
+
const index = jobs.indexOf(job);
|
|
2192
|
+
if (index < 0) return;
|
|
2193
|
+
if (index === 0) {
|
|
2194
|
+
job.abort.abort(/* @__PURE__ */ new Error("Codex operator input request cancelled"));
|
|
2195
|
+
return;
|
|
2196
|
+
}
|
|
2197
|
+
jobs.splice(index, 1);
|
|
2198
|
+
job.resolve(job.cancelValue);
|
|
2199
|
+
};
|
|
2200
|
+
const cancelPending = async () => {
|
|
2201
|
+
const pendingCompletion = activeCompletion;
|
|
2202
|
+
const queuedJobs = jobs.splice(1);
|
|
2203
|
+
for (const job of queuedJobs) job.resolve(job.cancelValue);
|
|
2204
|
+
jobs[0]?.abort.abort(/* @__PURE__ */ new Error("Codex operator input request cancelled"));
|
|
2205
|
+
await pendingCompletion;
|
|
2206
|
+
};
|
|
2207
|
+
const execute = (input, timeoutMs, signal) => agentHarnessStructuredInput.run({
|
|
2208
|
+
input,
|
|
2209
|
+
sessionKey: inputSessionKey,
|
|
2210
|
+
agentId: params.paramsForRun.agentId,
|
|
2211
|
+
runId: params.paramsForRun.runId,
|
|
2212
|
+
timeoutMs,
|
|
2213
|
+
gatewayCall,
|
|
2214
|
+
delivery: params.paramsForRun,
|
|
2215
|
+
signal,
|
|
2216
|
+
promptOptions: {
|
|
2217
|
+
formatText: formatCodexDisplayText,
|
|
2218
|
+
unsupportedIntro: "Codex input request could not be shown:",
|
|
2219
|
+
urlIntro: "Codex needs confirmation:"
|
|
2220
|
+
}
|
|
2221
|
+
});
|
|
2222
|
+
params.signal?.addEventListener("abort", () => void cancelPending(), { once: true });
|
|
1735
2223
|
return {
|
|
1736
2224
|
async handleRequest(request) {
|
|
1737
2225
|
const requestParams = readUserInputParams(request.params);
|
|
1738
|
-
if (!requestParams) return;
|
|
1739
|
-
if (requestParams.threadId !== params.threadId || requestParams.turnId !== params.turnId) return;
|
|
2226
|
+
if (!requestParams || requestParams.threadId !== params.threadId || requestParams.turnId !== params.turnId) return;
|
|
1740
2227
|
if (requestParams.questions.length === 0) return emptyUserInputResponse();
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
requestId: request.id,
|
|
1753
|
-
threadId: requestParams.threadId,
|
|
1754
|
-
questions: requestParams.questions,
|
|
1755
|
-
claimed: false,
|
|
1756
|
-
resolve,
|
|
1757
|
-
cleanup
|
|
1758
|
-
};
|
|
1759
|
-
sensitiveInput = current;
|
|
1760
|
-
params.signal?.addEventListener("abort", abortListener, { once: true });
|
|
1761
|
-
if (params.signal?.aborted) {
|
|
1762
|
-
resolveSecret(emptyUserInputResponse());
|
|
1763
|
-
return;
|
|
2228
|
+
const timeoutMs = requestParams.isBlocking ? params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS : NONBLOCKING_USER_INPUT_TIMEOUT_MS;
|
|
2229
|
+
const input = compileUserInputQuestions(requestParams.questions);
|
|
2230
|
+
const cancelValue = emptyUserInputResponse();
|
|
2231
|
+
return await enqueue({
|
|
2232
|
+
requestId: request.id,
|
|
2233
|
+
abort: new AbortController(),
|
|
2234
|
+
cancelValue,
|
|
2235
|
+
failureValue: cancelValue,
|
|
2236
|
+
run: async (signal) => {
|
|
2237
|
+
const result = await execute(input, timeoutMs, signal);
|
|
2238
|
+
return result.status === "answered" ? gatewayAnswersToCodexResponse(result.answers) : cancelValue;
|
|
1764
2239
|
}
|
|
1765
|
-
deliverAgentHarnessUserInputPrompt(params.paramsForRun, requestParams.questions, {
|
|
1766
|
-
formatText: formatCodexDisplayText,
|
|
1767
|
-
intro: "Codex needs input:"
|
|
1768
|
-
}).catch((error) => {
|
|
1769
|
-
embeddedAgentLog.warn("failed to deliver secret codex user input prompt", { error });
|
|
1770
|
-
resolveSecretIfCurrent(current, emptyUserInputResponse());
|
|
1771
|
-
});
|
|
1772
2240
|
});
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
params
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
promptOptions: {
|
|
1792
|
-
formatText: formatCodexDisplayText,
|
|
1793
|
-
intro: "Codex needs input:"
|
|
1794
|
-
},
|
|
1795
|
-
signal: abort.signal
|
|
2241
|
+
},
|
|
2242
|
+
async handleElicitationRequest(request) {
|
|
2243
|
+
if (readRawOwnString(request.params, "threadId") !== params.threadId) return;
|
|
2244
|
+
const requestSnapshot = agentHarnessStructuredInput.snapshot(request.params);
|
|
2245
|
+
if (requestSnapshot === void 0) {
|
|
2246
|
+
const cancelValue = createCodexElicitationResponse("cancel");
|
|
2247
|
+
return await enqueue({
|
|
2248
|
+
requestId: request.id,
|
|
2249
|
+
abort: new AbortController(),
|
|
2250
|
+
cancelValue,
|
|
2251
|
+
failureValue: declineElicitation("OpenClaw could not handle this elicitation."),
|
|
2252
|
+
run: async (signal) => {
|
|
2253
|
+
const result = await execute({
|
|
2254
|
+
kind: "unsupported",
|
|
2255
|
+
message: "OpenClaw declined a malformed or over-limit MCP elicitation request."
|
|
2256
|
+
}, params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS, signal);
|
|
2257
|
+
return result.status === "unsupported" ? declineElicitation(result.message) : cancelValue;
|
|
2258
|
+
}
|
|
1796
2259
|
});
|
|
1797
|
-
return result.status === "answered" ? gatewayAnswersToCodexResponse(result.answers.answers) : emptyUserInputResponse();
|
|
1798
|
-
} catch (error) {
|
|
1799
|
-
embeddedAgentLog.warn("failed to bridge codex user input through gateway", { error });
|
|
1800
|
-
return emptyUserInputResponse();
|
|
1801
|
-
} finally {
|
|
1802
|
-
params.signal?.removeEventListener("abort", abortFromRun);
|
|
1803
|
-
if (pendingGateway?.abort === abort) pendingGateway = void 0;
|
|
1804
2260
|
}
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
2261
|
+
const { compileCodexOrdinaryElicitation } = await import("./elicitation-input-DMkeki8d.js");
|
|
2262
|
+
const compiled = compileCodexOrdinaryElicitation({
|
|
2263
|
+
value: requestSnapshot,
|
|
2264
|
+
threadId: params.threadId,
|
|
2265
|
+
turnId: params.turnId
|
|
2266
|
+
});
|
|
2267
|
+
if (compiled.kind === "ignored") return;
|
|
2268
|
+
const cancelValue = createCodexElicitationResponse("cancel");
|
|
2269
|
+
const timeoutMs = params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS;
|
|
2270
|
+
return await enqueue({
|
|
2271
|
+
requestId: request.id,
|
|
2272
|
+
abort: new AbortController(),
|
|
2273
|
+
cancelValue,
|
|
2274
|
+
failureValue: declineElicitation("OpenClaw could not handle this elicitation."),
|
|
2275
|
+
run: async (signal) => {
|
|
2276
|
+
const result = await execute(compiled.input, timeoutMs, signal);
|
|
2277
|
+
if (result.status === "answered") return createCodexElicitationResponse("accept", compiled.input.kind === "ready" && compiled.input.plan.kind === "url" ? null : result.content);
|
|
2278
|
+
if (result.status === "declined") return declineElicitation(result.message);
|
|
2279
|
+
if (result.status === "unsupported") return declineElicitation(result.message);
|
|
2280
|
+
return cancelValue;
|
|
2281
|
+
}
|
|
2282
|
+
});
|
|
1814
2283
|
},
|
|
1815
2284
|
handleNotification(notification) {
|
|
1816
|
-
if (notification.method !== "serverRequest/resolved") return;
|
|
1817
|
-
const
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
if (
|
|
1821
|
-
if (pendingGateway && readStringField(notificationParams, "threadId") === pendingGateway.threadId && String(requestId) === String(pendingGateway.requestId)) pendingGateway.abort.abort(/* @__PURE__ */ new Error("Codex server request resolved"));
|
|
2285
|
+
if (notification.method !== "serverRequest/resolved" || !isJsonObject(notification.params)) return;
|
|
2286
|
+
const requestId = readRequestId(notification.params);
|
|
2287
|
+
if (requestId === void 0 || readOwnString(notification.params, "threadId") !== params.threadId) return;
|
|
2288
|
+
const job = jobs.find((candidate) => typeof candidate.requestId === typeof requestId && candidate.requestId === requestId);
|
|
2289
|
+
if (job) cancelJob(job);
|
|
1822
2290
|
},
|
|
1823
|
-
cancelPending
|
|
1824
|
-
resolveSecret(emptyUserInputResponse());
|
|
1825
|
-
cancelGateway();
|
|
1826
|
-
}
|
|
2291
|
+
cancelPending
|
|
1827
2292
|
};
|
|
1828
2293
|
}
|
|
2294
|
+
function compileUserInputQuestions(questions) {
|
|
2295
|
+
return agentHarnessStructuredInput.compileQuestions({
|
|
2296
|
+
questions,
|
|
2297
|
+
intro: "Codex needs input:"
|
|
2298
|
+
});
|
|
2299
|
+
}
|
|
1829
2300
|
function readUserInputParams(value) {
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
const
|
|
1833
|
-
const
|
|
1834
|
-
const
|
|
1835
|
-
|
|
2301
|
+
const snapshot = agentHarnessStructuredInput.snapshot(value);
|
|
2302
|
+
if (!agentHarnessStructuredInput.isRecord(snapshot)) return;
|
|
2303
|
+
const threadId = readBoundedUserInputText(snapshot, "threadId", MAX_USER_INPUT_ID);
|
|
2304
|
+
const turnId = readBoundedUserInputText(snapshot, "turnId", MAX_USER_INPUT_ID);
|
|
2305
|
+
const itemId = readBoundedUserInputText(snapshot, "itemId", MAX_USER_INPUT_ID);
|
|
2306
|
+
const questions = readArray(snapshot, "questions", MAX_USER_INPUT_QUESTIONS);
|
|
2307
|
+
if (!threadId || !turnId || !itemId || !questions) return;
|
|
2308
|
+
const parsed = [];
|
|
2309
|
+
for (const questionValue of questions) {
|
|
2310
|
+
const question = readQuestion(questionValue);
|
|
2311
|
+
if (!question) return;
|
|
2312
|
+
parsed.push(question);
|
|
2313
|
+
}
|
|
1836
2314
|
return {
|
|
1837
2315
|
threadId,
|
|
1838
2316
|
turnId,
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
const question = readQuestion(rawQuestion);
|
|
1842
|
-
if (question && isJsonObject(rawQuestion) && rawQuestion.multiSelect === true) question.multiSelect = true;
|
|
1843
|
-
return question;
|
|
1844
|
-
}).filter((question) => Boolean(question)),
|
|
1845
|
-
isBlocking: value.isBlocking !== false
|
|
2317
|
+
questions: parsed,
|
|
2318
|
+
isBlocking: readValue(snapshot, "isBlocking") !== false
|
|
1846
2319
|
};
|
|
1847
2320
|
}
|
|
1848
2321
|
function readQuestion(value) {
|
|
1849
|
-
if (!
|
|
1850
|
-
const id =
|
|
1851
|
-
const header =
|
|
1852
|
-
const question =
|
|
2322
|
+
if (!agentHarnessStructuredInput.isRecord(value)) return;
|
|
2323
|
+
const id = readBoundedUserInputText(value, "id", MAX_USER_INPUT_ID);
|
|
2324
|
+
const header = readBoundedUserInputText(value, "header", MAX_USER_INPUT_HEADER);
|
|
2325
|
+
const question = readBoundedUserInputText(value, "question", MAX_USER_INPUT_TEXT);
|
|
1853
2326
|
if (!id || !header || !question) return;
|
|
2327
|
+
const options = readOptions(readValue(value, "options"));
|
|
2328
|
+
if (options === void 0) return;
|
|
1854
2329
|
return {
|
|
1855
2330
|
id,
|
|
1856
2331
|
header,
|
|
1857
2332
|
question,
|
|
1858
|
-
isOther: value
|
|
1859
|
-
isSecret: value
|
|
1860
|
-
|
|
2333
|
+
isOther: readValue(value, "isOther") === true,
|
|
2334
|
+
isSecret: readValue(value, "isSecret") === true,
|
|
2335
|
+
...readValue(value, "multiSelect") === true ? { multiSelect: true } : {},
|
|
2336
|
+
options
|
|
1861
2337
|
};
|
|
1862
2338
|
}
|
|
1863
2339
|
function readOptions(value) {
|
|
1864
|
-
if (
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
2340
|
+
if (value === void 0 || value === null) return null;
|
|
2341
|
+
if (!Array.isArray(value) || value.length > MAX_USER_INPUT_OPTIONS) return;
|
|
2342
|
+
const options = [];
|
|
2343
|
+
for (const entry of value) {
|
|
2344
|
+
if (!agentHarnessStructuredInput.isRecord(entry)) return;
|
|
2345
|
+
const label = readBoundedUserInputText(entry, "label", MAX_USER_INPUT_ID);
|
|
2346
|
+
const description = readBoundedUserInputText(entry, "description", MAX_USER_INPUT_TEXT, true);
|
|
2347
|
+
if (!label) return;
|
|
2348
|
+
options.push({
|
|
2349
|
+
label,
|
|
2350
|
+
...description ? { description } : {}
|
|
2351
|
+
});
|
|
2352
|
+
}
|
|
2353
|
+
return options;
|
|
2354
|
+
}
|
|
2355
|
+
function readValue(record, key) {
|
|
2356
|
+
return Object.hasOwn(record, key) ? record[key] : void 0;
|
|
2357
|
+
}
|
|
2358
|
+
function readBoundedUserInputText(record, key, maximum, allowEmpty = false) {
|
|
2359
|
+
const value = readValue(record, key);
|
|
2360
|
+
return typeof value === "string" && value.length <= maximum && (allowEmpty || value.length > 0) ? value : void 0;
|
|
2361
|
+
}
|
|
2362
|
+
function readArray(record, key, maximum) {
|
|
2363
|
+
const value = readValue(record, key);
|
|
2364
|
+
return Array.isArray(value) && value.length <= maximum ? value : void 0;
|
|
1876
2365
|
}
|
|
1877
|
-
function
|
|
1878
|
-
|
|
2366
|
+
function readOwnString(record, key) {
|
|
2367
|
+
const descriptor = Object.getOwnPropertyDescriptor(record, key);
|
|
2368
|
+
return descriptor && "value" in descriptor && typeof descriptor.value === "string" ? descriptor.value : void 0;
|
|
2369
|
+
}
|
|
2370
|
+
function readRawOwnString(value, key) {
|
|
2371
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
2372
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
2373
|
+
return descriptor && "value" in descriptor && typeof descriptor.value === "string" ? descriptor.value : void 0;
|
|
2374
|
+
}
|
|
2375
|
+
function readRequestId(record) {
|
|
2376
|
+
const descriptor = Object.getOwnPropertyDescriptor(record, "requestId");
|
|
2377
|
+
const value = descriptor && "value" in descriptor ? descriptor.value : void 0;
|
|
2378
|
+
return typeof value === "string" || typeof value === "number" ? value : void 0;
|
|
1879
2379
|
}
|
|
1880
2380
|
function gatewayAnswersToCodexResponse(answers) {
|
|
1881
2381
|
return { answers: Object.fromEntries(Object.entries(answers).map(([questionId, values]) => [questionId, { answers: values }])) };
|
|
1882
2382
|
}
|
|
1883
2383
|
function emptyUserInputResponse() {
|
|
1884
|
-
return emptyAgentHarnessUserInputAnswers();
|
|
2384
|
+
return { ...emptyAgentHarnessUserInputAnswers() };
|
|
1885
2385
|
}
|
|
1886
|
-
function
|
|
1887
|
-
|
|
1888
|
-
return typeof value === "string" || typeof value === "number" ? value : void 0;
|
|
2386
|
+
function declineElicitation(message) {
|
|
2387
|
+
return createCodexElicitationResponse("decline", null, message ? { message } : null);
|
|
1889
2388
|
}
|
|
1890
2389
|
//#endregion
|
|
1891
2390
|
//#region extensions/codex/src/app-server/run-attempt-active-turn.ts
|
|
@@ -1894,12 +2393,14 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
1894
2393
|
const { context, turnState } = prompt;
|
|
1895
2394
|
const { runtime, attemptTools } = context;
|
|
1896
2395
|
const { connection } = runtime;
|
|
1897
|
-
const { params, runAbortController, terminalState, abortExplicitly, abortFromUpstream, bindingStore, bindingIdentity, sessionAgentId, sandboxSessionKey, effectiveCwd } = connection;
|
|
1898
|
-
const { dynamicToolParams, computerContextEpoch, toolBridge } = attemptTools;
|
|
2396
|
+
const { params, runAbortController, terminalState, abortExplicitly, abortFromUpstream, bindingStore, bindingIdentity, sessionAgentId, sandboxSessionKey, contextSessionKey, effectiveCwd } = connection;
|
|
2397
|
+
const { dynamicToolParams, compactionPlanState, computerContextEpoch, toolBridge } = attemptTools;
|
|
1899
2398
|
const { state, userInputBridgeRef, steeringQueueRef, turnWatches, completeTurn, interruptTurn } = turnRuntime;
|
|
1900
2399
|
const { emitExecutionPhaseOnce, emitLifecycleStart, maybeAnnounceFastModeAutoOff } = lifecycle;
|
|
1901
2400
|
const { enqueueNotification } = notifications;
|
|
1902
2401
|
const activeTurnId = turn.turn.id;
|
|
2402
|
+
const progressCardTool = toolBridge.availableTools.find((tool) => tool.name === "progress_card");
|
|
2403
|
+
let nativePlanUpdateOrdinal = 0;
|
|
1903
2404
|
const prepareNativeMcpAppResultDetails = createCodexNativeMcpAppResultDetailsPreparer({
|
|
1904
2405
|
client: resourceState.client,
|
|
1905
2406
|
threadId: resourceState.thread.threadId,
|
|
@@ -1934,6 +2435,16 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
1934
2435
|
}, resourceState.thread.threadId, activeTurnId, {
|
|
1935
2436
|
initialContextTokens: connection.mutable.startupContextTokens,
|
|
1936
2437
|
nativePostToolUseRelayEnabled: resourceState.nativeHookRelay?.allowedEvents.includes("post_tool_use") === true && resourceState.nativeHookRelay.shouldRelayEvent("post_tool_use"),
|
|
2438
|
+
asyncUserMessageAllowed: params.disableTools !== true && (params.toolsAllow === void 0 || toolBridge.availableTools.some((tool) => tool.name === "message")),
|
|
2439
|
+
onAsyncDelivery: async (delivery) => {
|
|
2440
|
+
return await codexTranscriptMirrorRuntime.deliverAsyncMessageBestEffort({
|
|
2441
|
+
params: dynamicToolParams,
|
|
2442
|
+
cwd: effectiveCwd,
|
|
2443
|
+
threadId: resourceState.thread.threadId,
|
|
2444
|
+
turnId: activeTurnId,
|
|
2445
|
+
...delivery
|
|
2446
|
+
});
|
|
2447
|
+
},
|
|
1937
2448
|
readRecentRateLimits: () => readRecentCodexRateLimits(resourceState.client),
|
|
1938
2449
|
runAbortSignal: runAbortController.signal,
|
|
1939
2450
|
remoteWorkspaceRoot: connection.appServer.remoteWorkspaceRoot,
|
|
@@ -1948,12 +2459,39 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
1948
2459
|
trajectoryRecorder,
|
|
1949
2460
|
resolveDynamicToolResultContentSource: toolBridge.resultContentSourceForTool,
|
|
1950
2461
|
onNativeToolResultRecorded: maybeAnnounceFastModeAutoOff,
|
|
2462
|
+
...progressCardTool ? { onNativePlanUpdate: async (update) => {
|
|
2463
|
+
nativePlanUpdateOrdinal += 1;
|
|
2464
|
+
try {
|
|
2465
|
+
const input = canonicalizeNativeProgressCardInput(update);
|
|
2466
|
+
await progressCardTool.execute(`codex-native-plan:${activeTurnId}:${nativePlanUpdateOrdinal}`, input, runAbortController.signal);
|
|
2467
|
+
} catch (error) {
|
|
2468
|
+
embeddedAgentLog.warn("failed to persist native Codex plan to progress card", {
|
|
2469
|
+
runId: params.runId,
|
|
2470
|
+
threadId: resourceState.thread.threadId,
|
|
2471
|
+
error: formatErrorMessage(error)
|
|
2472
|
+
});
|
|
2473
|
+
}
|
|
2474
|
+
} } : {},
|
|
1951
2475
|
...prepareNativeMcpAppResultDetails ? { prepareNativeMcpAppResultDetails } : {},
|
|
1952
2476
|
upstreamUserText: turnState.codexTurnPromptText,
|
|
1953
|
-
onContextCompacted: () => {
|
|
2477
|
+
onContextCompacted: async () => {
|
|
1954
2478
|
computerContextEpoch.value += 1;
|
|
1955
2479
|
delete computerContextEpoch.frameToolCallId;
|
|
1956
2480
|
delete computerContextEpoch.frameImageIdentity;
|
|
2481
|
+
try {
|
|
2482
|
+
await compactionPlanState.restore({
|
|
2483
|
+
client: resourceState.client,
|
|
2484
|
+
threadId: resourceState.thread.threadId,
|
|
2485
|
+
timeoutMs: connection.appServer.requestTimeoutMs,
|
|
2486
|
+
signal: runAbortController.signal
|
|
2487
|
+
});
|
|
2488
|
+
} catch (error) {
|
|
2489
|
+
embeddedAgentLog.warn("failed to restore Codex plan state after compaction", {
|
|
2490
|
+
runId: params.runId,
|
|
2491
|
+
threadId: resourceState.thread.threadId,
|
|
2492
|
+
error: formatErrorMessage(error)
|
|
2493
|
+
});
|
|
2494
|
+
}
|
|
1957
2495
|
}
|
|
1958
2496
|
});
|
|
1959
2497
|
if (isTerminalTurnStatus(turn.turn.status)) state.terminalTurnNotificationQueued = true;
|
|
@@ -1964,6 +2502,18 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
1964
2502
|
turnWatches.armAttemptIdleWatch();
|
|
1965
2503
|
turnWatches.touchActivity("turn:start", { attemptProgress: true });
|
|
1966
2504
|
for (const failure of pendingNativePreToolUseFailures.splice(0)) activeProjector.recordNativeToolPreToolUseFailure(failure);
|
|
2505
|
+
const notifyUserMessagePersisted = createCodexAppServerUserMessagePersistenceNotifier(params);
|
|
2506
|
+
const promptMirrorPromise = mirrorPromptAtTurnStartBestEffort({
|
|
2507
|
+
params,
|
|
2508
|
+
agentId: sessionAgentId,
|
|
2509
|
+
notifyUserMessagePersisted,
|
|
2510
|
+
sessionKey: sandboxSessionKey,
|
|
2511
|
+
cwd: effectiveCwd,
|
|
2512
|
+
threadId: resourceState.thread.threadId,
|
|
2513
|
+
turnId: activeTurnId,
|
|
2514
|
+
upstreamUserText: turnState.codexTurnPromptText
|
|
2515
|
+
});
|
|
2516
|
+
await promptMirrorPromise;
|
|
1967
2517
|
if (resourceState.turnRoute) try {
|
|
1968
2518
|
await resourceState.turnRoute.bindTurn(activeTurnId);
|
|
1969
2519
|
} catch (error) {
|
|
@@ -1974,28 +2524,91 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
1974
2524
|
throw error;
|
|
1975
2525
|
}
|
|
1976
2526
|
}
|
|
1977
|
-
if (!state.completed && isTerminalTurnStatus(turn.turn.status))
|
|
1978
|
-
|
|
1979
|
-
|
|
2527
|
+
if (!state.completed && isTerminalTurnStatus(turn.turn.status)) {
|
|
2528
|
+
if (!isJsonObject(turn.turn)) throw new Error("Codex turn completion payload is not a JSON object");
|
|
2529
|
+
await enqueueNotification({
|
|
2530
|
+
method: "turn/completed",
|
|
2531
|
+
params: {
|
|
2532
|
+
threadId: resourceState.thread.threadId,
|
|
2533
|
+
turnId: activeTurnId,
|
|
2534
|
+
turn: turn.turn
|
|
2535
|
+
}
|
|
2536
|
+
}, {
|
|
1980
2537
|
threadId: resourceState.thread.threadId,
|
|
1981
|
-
turnId: activeTurnId
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
2538
|
+
turnId: activeTurnId
|
|
2539
|
+
});
|
|
2540
|
+
}
|
|
2541
|
+
const assertSteeringActive = () => {
|
|
2542
|
+
params.hostCapabilities.assertActive();
|
|
2543
|
+
runAbortController.signal.throwIfAborted();
|
|
2544
|
+
if (state.completed || state.terminalTurnNotificationQueued || state.timedOut) throw new Error("codex app-server turn is no longer accepting steering");
|
|
2545
|
+
};
|
|
2546
|
+
const workspaceOnly = resolveAttemptFsWorkspaceOnly({
|
|
2547
|
+
config: params.config,
|
|
2548
|
+
sessionAgentId
|
|
1987
2549
|
});
|
|
2550
|
+
const imageContext = {
|
|
2551
|
+
workspaceDir: connection.effectiveWorkspace,
|
|
2552
|
+
model: params.model,
|
|
2553
|
+
config: params.config,
|
|
2554
|
+
workspaceOnly,
|
|
2555
|
+
localRoots: workspaceOnly ? void 0 : getAgentScopedMediaLocalRoots(params.config ?? {}, sessionAgentId),
|
|
2556
|
+
sandbox: connection.sandbox?.enabled && connection.sandbox.fsBridge ? {
|
|
2557
|
+
root: connection.sandbox.workspaceDir,
|
|
2558
|
+
bridge: connection.sandbox.fsBridge
|
|
2559
|
+
} : void 0
|
|
2560
|
+
};
|
|
1988
2561
|
const activeSteeringQueue = createCodexSteeringQueue({
|
|
1989
2562
|
client: resourceState.client,
|
|
1990
2563
|
threadId: resourceState.thread.threadId,
|
|
1991
2564
|
turnId: activeTurnId,
|
|
1992
2565
|
requestTimeoutMs: connection.appServer.requestTimeoutMs,
|
|
1993
|
-
|
|
1994
|
-
|
|
2566
|
+
signal: runAbortController.signal,
|
|
2567
|
+
assertActive: assertSteeringActive,
|
|
2568
|
+
prepareMessage: async (text, options) => {
|
|
2569
|
+
const result = await detectAndLoadAgentHarnessPromptImages({
|
|
2570
|
+
...imageContext,
|
|
2571
|
+
prompt: text,
|
|
2572
|
+
existingImages: options.images,
|
|
2573
|
+
imageOrder: options.imageOrder,
|
|
2574
|
+
media: options.media,
|
|
2575
|
+
userTurnTranscriptRecorder: options.userTurnTranscriptRecorder
|
|
2576
|
+
});
|
|
2577
|
+
if (result.failedMediaCount) throw new Error(`failed to hydrate ${result.failedMediaCount} structured image attachment(s) for Codex steering`);
|
|
2578
|
+
return buildCodexUserInput(text, result.images);
|
|
2579
|
+
},
|
|
2580
|
+
beforeConfirmConsumed: async (items) => {
|
|
2581
|
+
const inboundItems = items.filter((item) => item.isInboundUserMessage === true);
|
|
2582
|
+
if (inboundItems.length === 0) return;
|
|
2583
|
+
await promptMirrorPromise;
|
|
2584
|
+
const messages = activeProjector.buildSteeringTranscriptPrefix();
|
|
2585
|
+
if (params.sessionTarget && messages.length > 0) {
|
|
2586
|
+
await codexTranscriptMirrorRuntime.mirror({
|
|
2587
|
+
agentId: sessionAgentId,
|
|
2588
|
+
sessionKey: contextSessionKey,
|
|
2589
|
+
sessionId: params.sessionId,
|
|
2590
|
+
storePath: params.sessionTarget.storePath,
|
|
2591
|
+
cwd: effectiveCwd,
|
|
2592
|
+
messages,
|
|
2593
|
+
idempotencyScope: `codex-app-server:${resourceState.thread.threadId}`,
|
|
2594
|
+
runId: params.runId,
|
|
2595
|
+
runMirrorIdentityPrefix: `${activeTurnId}:`,
|
|
2596
|
+
config: params.config
|
|
2597
|
+
});
|
|
2598
|
+
activeProjector.markSteeringTranscriptPersisted();
|
|
2599
|
+
}
|
|
2600
|
+
for (const item of inboundItems) {
|
|
2601
|
+
const recorder = item.userTurnTranscriptRecorder;
|
|
2602
|
+
if (!recorder) continue;
|
|
2603
|
+
await recorder.persistApproved();
|
|
2604
|
+
if (!recorder.hasPersisted()) throw new Error("Codex consumed steering before its user turn was persisted");
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
1995
2607
|
});
|
|
1996
2608
|
steeringQueueRef.current = activeSteeringQueue;
|
|
1997
2609
|
const claimPendingUserInputAnswer = async (text, optionsLocal) => {
|
|
1998
|
-
if (optionsLocal?.isInboundUserMessage !== true || optionsLocal
|
|
2610
|
+
if (optionsLocal?.isInboundUserMessage !== true || hasPromptImageInput(optionsLocal)) return false;
|
|
2611
|
+
assertSteeringActive();
|
|
1999
2612
|
return await claimPendingAgentQuestionAnswer({
|
|
2000
2613
|
sessionKey: params.sessionKey ?? params.sessionId,
|
|
2001
2614
|
text,
|
|
@@ -2009,14 +2622,17 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2009
2622
|
resolvedBy
|
|
2010
2623
|
});
|
|
2011
2624
|
const queueMessage = async (text, optionsLocal) => {
|
|
2012
|
-
const isInboundUserMessage = optionsLocal?.isInboundUserMessage === true;
|
|
2013
2625
|
if (await claimPendingUserInputAnswer(text, optionsLocal)) {
|
|
2014
2626
|
optionsLocal?.onQueueAccepted?.(true);
|
|
2015
2627
|
return;
|
|
2016
|
-
}
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2628
|
+
}
|
|
2629
|
+
if (optionsLocal?.isInboundUserMessage === true && hasPromptImageInput(optionsLocal)) {
|
|
2630
|
+
assertSteeringActive();
|
|
2631
|
+
try {
|
|
2632
|
+
await cancelPendingUserInput("image-reply");
|
|
2633
|
+
} catch (error) {
|
|
2634
|
+
embeddedAgentLog.warn("failed to cancel codex gateway question before image steering", { error });
|
|
2635
|
+
}
|
|
2020
2636
|
}
|
|
2021
2637
|
try {
|
|
2022
2638
|
await activeSteeringQueue.queue(text, optionsLocal);
|
|
@@ -2031,6 +2647,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2031
2647
|
const handle = {
|
|
2032
2648
|
kind: "embedded",
|
|
2033
2649
|
runId: params.runId,
|
|
2650
|
+
startedAtMs: params.startedAtMs,
|
|
2034
2651
|
toolAuthorityFingerprint: params.toolAuthorityFingerprint,
|
|
2035
2652
|
claimPendingUserInputAnswer,
|
|
2036
2653
|
cancelPendingUserInput,
|
|
@@ -2045,7 +2662,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2045
2662
|
isAbortable: () => !terminalState.terminalOutcomeFrozen || terminalState.sharedAbortAllowedAfterTerminalOutcome,
|
|
2046
2663
|
isCompacting: () => projectorRef.current?.isCompacting() ?? false,
|
|
2047
2664
|
supportsTranscriptCommitWait: true,
|
|
2048
|
-
supportsQueueMessageImages:
|
|
2665
|
+
supportsQueueMessageImages: params.model.input.includes("image"),
|
|
2049
2666
|
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
|
2050
2667
|
taskSuggestionDeliveryMode: params.taskSuggestionDeliveryMode,
|
|
2051
2668
|
cancel: () => abortExplicitly("cancelled"),
|
|
@@ -2058,17 +2675,6 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2058
2675
|
terminalState.terminalOutcomeFrozen = true;
|
|
2059
2676
|
params.abortSignal?.removeEventListener("abort", abortFromUpstream);
|
|
2060
2677
|
};
|
|
2061
|
-
const notifyUserMessagePersisted = createCodexAppServerUserMessagePersistenceNotifier(params);
|
|
2062
|
-
mirrorPromptAtTurnStartBestEffort({
|
|
2063
|
-
params,
|
|
2064
|
-
agentId: sessionAgentId,
|
|
2065
|
-
notifyUserMessagePersisted,
|
|
2066
|
-
sessionKey: sandboxSessionKey,
|
|
2067
|
-
cwd: effectiveCwd,
|
|
2068
|
-
threadId: resourceState.thread.threadId,
|
|
2069
|
-
turnId: activeTurnId,
|
|
2070
|
-
upstreamUserText: turnState.codexTurnPromptText
|
|
2071
|
-
});
|
|
2072
2678
|
const abortListener = () => {
|
|
2073
2679
|
if (state.timedOut) {
|
|
2074
2680
|
(async () => {
|
|
@@ -2085,7 +2691,15 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
2085
2691
|
})().finally(completeTurn);
|
|
2086
2692
|
return;
|
|
2087
2693
|
}
|
|
2088
|
-
interruptTurn(activeTurnId)
|
|
2694
|
+
const interrupted = interruptTurn(activeTurnId);
|
|
2695
|
+
if (terminalState.explicitCancellationObserved) state.abortCleanup = interrupted.then(async (confirmed) => {
|
|
2696
|
+
if (!confirmed) throw new Error("Codex cancellation could not confirm the turn stopped; background terminals may still be running.");
|
|
2697
|
+
await terminateCodexBackgroundTerminals(resourceState.client, resourceState.thread.threadId);
|
|
2698
|
+
});
|
|
2699
|
+
(terminalState.explicitCancellationObserved ? state.abortCleanup : interrupted).then(completeTurn, (error) => {
|
|
2700
|
+
embeddedAgentLog.warn("codex app-server cancellation cleanup failed", { error });
|
|
2701
|
+
completeTurn();
|
|
2702
|
+
});
|
|
2089
2703
|
};
|
|
2090
2704
|
runAbortController.signal.addEventListener("abort", abortListener, { once: true });
|
|
2091
2705
|
if (runAbortController.signal.aborted) abortListener();
|
|
@@ -2110,6 +2724,8 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2110
2724
|
const { codexModelCallDiagnostics } = requestRuntime;
|
|
2111
2725
|
const { activeTurnId, abortListener, handle, freezeRunTerminalOutcome } = activeTurn;
|
|
2112
2726
|
prompt.context.attemptTools.scheduledAppAuthoritySourceRef.current = void 0;
|
|
2727
|
+
freezeRunTerminalOutcome();
|
|
2728
|
+
await state.abortCleanup.catch(() => void 0);
|
|
2113
2729
|
try {
|
|
2114
2730
|
steeringQueueRef.current?.cancel();
|
|
2115
2731
|
if (params.isFinalFallbackAttempt !== false) await maybeEmitFastModeAutoResetBestEffort();
|
|
@@ -2133,15 +2749,11 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2133
2749
|
const retainLiveIncognitoThread = terminalState.turnSucceeded && isIncognitoSessionKey(params.sessionKey);
|
|
2134
2750
|
const retainedPersistentThread = terminalState.turnSucceeded && !isIncognitoSessionKey(params.sessionKey) && params.cleanupBundleMcpOnRunEnd !== true && resourceState.thread.liveThreadConfigFingerprint !== void 0 && resourceState.thread.clientId === resolveCodexAppServerClientInstanceId(resourceState.client) && resourceState.thread.preserveNativeModel !== true && resourceState.thread.connectionScope !== "supervision" && !resourceState.thread.ringZeroConfigFingerprint ? (await bindingStore.read(bindingIdentity))?.threadId === resourceState.thread.threadId && await bindingStore.withLease(bindingIdentity, async () => {
|
|
2135
2751
|
if ((await bindingStore.read(bindingIdentity))?.threadId !== resourceState.thread.threadId) return false;
|
|
2136
|
-
return await
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
await closeCodexStartupClientBestEffort(resourceState.client);
|
|
2142
|
-
throw new CodexAppServerUnsafeSubscriptionError(`Codex retained thread subscription could not be released: ${threadId}`);
|
|
2143
|
-
}
|
|
2144
|
-
}), resourceState.thread.liveThreadConfigFingerprint, connection.mutable.pluginAppServer.serviceTier);
|
|
2752
|
+
return await retainCodexAppServerBindingSubscription(resourceState.client, resourceState.thread.threadId, {
|
|
2753
|
+
release: resourceState.thread.liveThreadOwnership?.release,
|
|
2754
|
+
configFingerprint: resourceState.thread.liveThreadConfigFingerprint,
|
|
2755
|
+
serviceTier: connection.mutable.pluginAppServer.serviceTier
|
|
2756
|
+
});
|
|
2145
2757
|
}) : false;
|
|
2146
2758
|
const retainLiveThread = retainLiveIncognitoThread || retainedPersistentThread;
|
|
2147
2759
|
const bindingReleased = isIncognitoSessionKey(params.sessionKey) && !retainLiveIncognitoThread ? await bindingStore.mutate(bindingIdentity, {
|
|
@@ -2159,7 +2771,13 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2159
2771
|
} finally {
|
|
2160
2772
|
await runCleanupStep("codex-user-input-cancel", () => userInputBridgeRef.current?.cancelPending());
|
|
2161
2773
|
await runCleanupStep("codex-turn-watch-clear", () => turnWatches.clearAllTimers());
|
|
2774
|
+
await runCleanupStep("codex-dynamic-tool-cleanup", async () => {
|
|
2775
|
+
const cleanupReason = terminalState.turnSucceeded ? "completion" : state.timedOut ? "timeout" : runAbortController.signal.aborted ? "cancel" : "error";
|
|
2776
|
+
const cleanups = prompt.context.attemptTools.runCleanups.splice(0);
|
|
2777
|
+
await Promise.allSettled(cleanups.map(async (cleanup) => await cleanup(cleanupReason)));
|
|
2778
|
+
});
|
|
2162
2779
|
await runCleanupStep("codex-route-release", releaseCurrentRoute);
|
|
2780
|
+
await runCleanupStep("codex-transcript-checkpoint", () => activeTurn.activeProjector.transcriptCheckpoint.flush(true));
|
|
2163
2781
|
await runCleanupStep("codex-shared-client-release", releaseSharedClientLeaseAndRetireOneShotClient);
|
|
2164
2782
|
const nativeHookRelay = resourceState.nativeHookRelay;
|
|
2165
2783
|
resourceState.nativeHookRelay = void 0;
|
|
@@ -2178,12 +2796,12 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
2178
2796
|
runAbortController.signal.removeEventListener("abort", abortListener);
|
|
2179
2797
|
});
|
|
2180
2798
|
await runCleanupStep("codex-steering-cancel", () => steeringQueueRef.current?.cancel());
|
|
2181
|
-
await runCleanupStep("codex-terminal-freeze", freezeRunTerminalOutcome);
|
|
2182
2799
|
await runCleanupStep("codex-reply-backend-detach", () => params.replyOperation?.detachBackend(handle));
|
|
2183
2800
|
await runCleanupStep("codex-active-run-clear", () => {
|
|
2184
2801
|
clearActiveEmbeddedRun(params.sessionId, handle, params.sessionKey, params.sessionFile);
|
|
2185
2802
|
});
|
|
2186
2803
|
}
|
|
2804
|
+
await state.abortCleanup;
|
|
2187
2805
|
}
|
|
2188
2806
|
//#endregion
|
|
2189
2807
|
//#region extensions/codex/src/app-server/workspace-dir-cache.ts
|
|
@@ -2295,10 +2913,7 @@ async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codex
|
|
|
2295
2913
|
path.join(resolvedAgentDir, "agent", "codex-home", "sessions"),
|
|
2296
2914
|
path.join(path.dirname(resolvedAgentDir), "codex-home", "sessions")
|
|
2297
2915
|
];
|
|
2298
|
-
const rolloutRoot = rolloutPath ? roots.find((root) =>
|
|
2299
|
-
const relativePath = path.relative(root, rolloutPath);
|
|
2300
|
-
return relativePath !== "" && relativePath !== ".." && !relativePath.startsWith(`..${path.sep}`) && !path.isAbsolute(relativePath);
|
|
2301
|
-
}) : void 0;
|
|
2916
|
+
const rolloutRoot = rolloutPath ? roots.find((root) => isPathStrictlyInside(root, rolloutPath)) : void 0;
|
|
2302
2917
|
if (rolloutPath && rolloutRoot && path.isAbsolute(rolloutPath) && path.extname(rolloutPath) === ".jsonl" && path.basename(rolloutPath).includes(threadId)) try {
|
|
2303
2918
|
const opened = await (await root(rolloutRoot, {
|
|
2304
2919
|
hardlinks: "reject",
|
|
@@ -2555,14 +3170,6 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
|
2555
3170
|
}
|
|
2556
3171
|
//#endregion
|
|
2557
3172
|
//#region extensions/codex/src/app-server/run-attempt-connection.ts
|
|
2558
|
-
function applyStoredBindingPermissions(params) {
|
|
2559
|
-
if (params.execPolicyTouched || params.binding?.connectionScope === "supervision") return params.appServer;
|
|
2560
|
-
return {
|
|
2561
|
-
...params.appServer,
|
|
2562
|
-
approvalPolicy: params.binding?.approvalPolicy ?? params.appServer.approvalPolicy,
|
|
2563
|
-
sandbox: params.binding?.sandbox ?? params.appServer.sandbox
|
|
2564
|
-
};
|
|
2565
|
-
}
|
|
2566
3173
|
async function prepareCodexAttemptConnection({ params, options }) {
|
|
2567
3174
|
const attemptStartedAt = Date.now();
|
|
2568
3175
|
const profilerEnabled = isCodexAppServerProfilerEnabled(params.config);
|
|
@@ -2575,16 +3182,15 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
2575
3182
|
resetAnnounced: false
|
|
2576
3183
|
};
|
|
2577
3184
|
const preDynamicStartupStages = createCodexDynamicToolBuildStageTracker({ enabled: profilerEnabled });
|
|
2578
|
-
const attemptClientFactory = options.clientFactory ?? getLeasedSharedCodexAppServerClient;
|
|
2579
3185
|
const runtimeArtifactRequest = params.captureRuntimeArtifact || params.expectedRuntimeArtifact ? params.expectedRuntimeArtifact ? { expected: params.expectedRuntimeArtifact } : {} : void 0;
|
|
2580
3186
|
const pluginConfig = readCodexPluginConfig(options.pluginConfig);
|
|
3187
|
+
const requirementsToml = readCodexRequirementsToml({});
|
|
2581
3188
|
const computerUseConfig = resolveCodexComputerUseConfig({ pluginConfig });
|
|
2582
|
-
const { sessionAgentId } =
|
|
3189
|
+
const { sessionAgentId } = resolveSessionAgentIdsStrict({
|
|
2583
3190
|
sessionKey: params.sessionKey,
|
|
2584
3191
|
config: params.config,
|
|
2585
3192
|
agentId: params.agentId
|
|
2586
3193
|
});
|
|
2587
|
-
const beforeToolCallPolicy = getBeforeToolCallPolicyDiagnosticState();
|
|
2588
3194
|
preDynamicStartupStages.mark("config");
|
|
2589
3195
|
const resolvedWorkspace = resolveUserPath(params.workspaceDir);
|
|
2590
3196
|
await ensureCodexWorkspaceDirOnce(resolvedWorkspace);
|
|
@@ -2596,14 +3202,36 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
2596
3202
|
sessionKey: sandboxSessionKey,
|
|
2597
3203
|
workspaceDir: resolvedWorkspace
|
|
2598
3204
|
});
|
|
3205
|
+
const attemptClientFactory = options.clientFactory ?? (isCodexPairedNodeRemoteExecPlacementSandbox(sandbox) ? createIsolatedCodexAppServerClient : getLeasedSharedCodexAppServerClient);
|
|
2599
3206
|
preDynamicStartupStages.mark("sandbox");
|
|
2600
3207
|
const execPolicy = resolveOpenClawExecPolicyForCodexAppServer({
|
|
3208
|
+
permissionMode: params.permissionMode,
|
|
2601
3209
|
execOverrides: params.execOverrides,
|
|
2602
|
-
approvals: loadExecApprovals(),
|
|
3210
|
+
approvals: params.permissionMode === "full" ? void 0 : loadExecApprovals(),
|
|
2603
3211
|
config: params.config,
|
|
2604
3212
|
agentId: sessionAgentId
|
|
2605
3213
|
});
|
|
2606
3214
|
const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId);
|
|
3215
|
+
const preparedEnvironment = params.hostCapabilities.preparedEnvironment?.();
|
|
3216
|
+
const remoteExec = isCodexRemoteExecPlacementSandbox(sandbox);
|
|
3217
|
+
const preparedShellEnvironment = preparedEnvironment ? {
|
|
3218
|
+
...preparedEnvironment.credentialScrubEnv,
|
|
3219
|
+
...!remoteExec ? preparedEnvironment.localIdentityEnv : void 0
|
|
3220
|
+
} : void 0;
|
|
3221
|
+
const shellEnvironment = preparedShellEnvironment && Object.keys(preparedShellEnvironment).length > 0 ? preparedShellEnvironment : void 0;
|
|
3222
|
+
const disableLoginShell = remoteExec || preparedEnvironment?.managedLocalIdentity === true || preparedEnvironment !== void 0 && Object.keys(preparedEnvironment.credentialScrubEnv).length > 0;
|
|
3223
|
+
const withPreparedProcessEnv = (appServer) => {
|
|
3224
|
+
return shellEnvironment ? {
|
|
3225
|
+
...appServer,
|
|
3226
|
+
start: {
|
|
3227
|
+
...appServer.start,
|
|
3228
|
+
env: {
|
|
3229
|
+
...appServer.start.env,
|
|
3230
|
+
...shellEnvironment
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
} : appServer;
|
|
3234
|
+
};
|
|
2607
3235
|
let bindingIdentity = sessionBindingIdentity({
|
|
2608
3236
|
sessionId: params.sessionId,
|
|
2609
3237
|
sessionKey: params.sessionKey,
|
|
@@ -2650,21 +3278,20 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
2650
3278
|
const usesSupervisionConnection = startupBinding?.connectionScope === "supervision";
|
|
2651
3279
|
if (usesSupervisionConnection) activeContextEngine = void 0;
|
|
2652
3280
|
if (usesSupervisionConnection && pluginConfig.supervision?.enabled !== true) throw new Error("Codex supervision is disabled; refusing to open a native user-home supervised session");
|
|
2653
|
-
const resolveRuntimeOptionsForBinding = (selection) =>
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
execPolicyTouched: execPolicy.touched
|
|
2666
|
-
});
|
|
3281
|
+
const resolveRuntimeOptionsForBinding = (binding, selection) => resolveCodexBindingAppServerConnection({
|
|
3282
|
+
binding,
|
|
3283
|
+
pluginConfig,
|
|
3284
|
+
execPolicy,
|
|
3285
|
+
modelProvider: selection.modelProvider,
|
|
3286
|
+
model: selection.model,
|
|
3287
|
+
config: params.config,
|
|
3288
|
+
agentDir,
|
|
3289
|
+
requirementsToml,
|
|
3290
|
+
openClawSandboxActive: sandbox?.enabled === true,
|
|
3291
|
+
sessionPermissionMode: params.permissionMode
|
|
3292
|
+
}).appServer;
|
|
2667
3293
|
const initialStartupBindingHadInactiveThreadBootstrap = isInactiveThreadBootstrapBinding(startupBinding);
|
|
3294
|
+
const appServerHomeScope = resolveCodexAppServerHomeScope({ appServer: pluginConfig.appServer });
|
|
2668
3295
|
const preparedAuthRoute = usesSupervisionConnection ? void 0 : params.runtimePlan?.auth.modelRoute;
|
|
2669
3296
|
const startupAuthProfileCandidate = usesSupervisionConnection ? void 0 : preparedAuthRoute ? params.runtimePlan?.auth.forwardedAuthProfileId : params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId;
|
|
2670
3297
|
const resolvedStartupAuthProfileId = usesSupervisionConnection ? void 0 : preparedAuthRoute ? startupAuthProfileCandidate : params.authProfileStore ? resolveCodexAppServerAuthProfileId({
|
|
@@ -2686,13 +3313,13 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
2686
3313
|
authProfileId: resolvedStartupAuthProfileId,
|
|
2687
3314
|
authProfileStore: params.authProfileStore,
|
|
2688
3315
|
agentDir,
|
|
2689
|
-
homeScope:
|
|
3316
|
+
homeScope: appServerHomeScope,
|
|
2690
3317
|
requirePreparedAuth: isCodexRemoteExecPlacementSandbox(sandbox),
|
|
2691
3318
|
config: params.config,
|
|
2692
3319
|
subscriptionProfileRequiredError: "Prepared Codex subscription route requires a forwarded OpenAI OAuth or token profile.",
|
|
2693
3320
|
subscriptionProfileUnusableError: "Prepared Codex subscription auth profile is unusable."
|
|
2694
3321
|
});
|
|
2695
|
-
const startupClientAuthProfileId = usesSupervisionConnection || startupPreparedAuth?.kind === "api-key" ? null : startupAuthProfileId;
|
|
3322
|
+
const startupClientAuthProfileId = usesSupervisionConnection || appServerHomeScope === "user" || startupPreparedAuth?.kind === "api-key" ? null : startupAuthProfileId;
|
|
2696
3323
|
const resolveReviewerPolicyContext = (binding) => {
|
|
2697
3324
|
const nativeModelOwned = binding?.preserveNativeModel === true;
|
|
2698
3325
|
return resolveCodexModelBackedReviewerPolicyContext({
|
|
@@ -2705,41 +3332,67 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
2705
3332
|
};
|
|
2706
3333
|
let reviewerPolicyContext = resolveReviewerPolicyContext(startupBinding);
|
|
2707
3334
|
preDynamicStartupStages.mark("auth-profile");
|
|
2708
|
-
let configuredAppServer = resolveRuntimeOptionsForBinding({
|
|
3335
|
+
let configuredAppServer = resolveRuntimeOptionsForBinding(startupBinding, {
|
|
2709
3336
|
modelProvider: reviewerPolicyContext.modelProvider,
|
|
2710
3337
|
model: reviewerPolicyContext.model
|
|
2711
3338
|
});
|
|
2712
3339
|
const effectiveWorkspace = sandbox?.enabled ? sandbox.workspaceAccess === "rw" ? resolvedWorkspace : sandbox.workspaceDir : resolvedWorkspace;
|
|
2713
3340
|
const requestedCwd = params.cwd ? resolveUserPath(params.cwd) : void 0;
|
|
2714
3341
|
if (sandbox?.enabled && requestedCwd && requestedCwd !== resolvedWorkspace) throw new Error("cwd override is not supported for sandboxed Codex app-server runs; omit cwd or use the agent workspace as cwd");
|
|
2715
|
-
const
|
|
3342
|
+
const sessionPermissionCwd = resolveCodexSessionPermissionCwd({
|
|
3343
|
+
permissionMode: params.permissionMode,
|
|
3344
|
+
sessionRoot: params.sessionRoot,
|
|
3345
|
+
defaultRoot: effectiveWorkspace,
|
|
3346
|
+
requestedCwd,
|
|
3347
|
+
fallbackCwd: effectiveWorkspace
|
|
3348
|
+
});
|
|
3349
|
+
const effectiveCwd = sandbox?.enabled ? effectiveWorkspace : sessionPermissionCwd;
|
|
2716
3350
|
if (effectiveWorkspace !== resolvedWorkspace) await ensureCodexWorkspaceDirOnce(effectiveWorkspace);
|
|
2717
3351
|
preDynamicStartupStages.mark("effective-workspace");
|
|
2718
|
-
const
|
|
2719
|
-
|
|
2720
|
-
|
|
3352
|
+
const applySessionPermissionPolicy = (appServer, selection) => applyCodexSessionPermissionPolicy({
|
|
3353
|
+
appServer,
|
|
3354
|
+
permissionMode: params.permissionMode,
|
|
3355
|
+
sessionRoot: params.sessionRoot,
|
|
3356
|
+
defaultRoot: effectiveWorkspace,
|
|
2721
3357
|
pluginConfig,
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
from: "never",
|
|
2739
|
-
to: "untrusted",
|
|
2740
|
-
beforeToolCallHook: beforeToolCallPolicy.hasBeforeToolCallHook,
|
|
2741
|
-
trustedToolPolicies: beforeToolCallPolicy.trustedToolPolicies
|
|
3358
|
+
canUseAutoReview: canUseCodexModelBackedApprovalsReviewerForModel({
|
|
3359
|
+
modelProvider: selection.modelProvider,
|
|
3360
|
+
model: selection.model,
|
|
3361
|
+
config: params.config,
|
|
3362
|
+
env: {
|
|
3363
|
+
...process.env,
|
|
3364
|
+
...appServer.start.env,
|
|
3365
|
+
...shellEnvironment
|
|
3366
|
+
},
|
|
3367
|
+
agentDir,
|
|
3368
|
+
homeScope: appServer.start.homeScope,
|
|
3369
|
+
codexArgs: appServer.start.args
|
|
3370
|
+
}),
|
|
3371
|
+
requirementsToml,
|
|
3372
|
+
policyLocked: startupBinding?.connectionScope === "supervision",
|
|
3373
|
+
execMode: execPolicy.mode
|
|
2742
3374
|
});
|
|
3375
|
+
const resolveFinalAppServer = (configured, selection) => {
|
|
3376
|
+
const session = applySessionPermissionPolicy(configured, selection);
|
|
3377
|
+
const trusted = resolveCodexAppServerForModelProvider({
|
|
3378
|
+
appServer: session,
|
|
3379
|
+
provider: selection.modelProvider,
|
|
3380
|
+
model: selection.model,
|
|
3381
|
+
config: params.config,
|
|
3382
|
+
env: {
|
|
3383
|
+
...process.env,
|
|
3384
|
+
...session.start.env,
|
|
3385
|
+
...shellEnvironment
|
|
3386
|
+
},
|
|
3387
|
+
agentDir
|
|
3388
|
+
});
|
|
3389
|
+
return {
|
|
3390
|
+
session,
|
|
3391
|
+
appServer: withPreparedProcessEnv(trusted)
|
|
3392
|
+
};
|
|
3393
|
+
};
|
|
3394
|
+
let resolvedAppServer = resolveFinalAppServer(configuredAppServer, reviewerPolicyContext);
|
|
3395
|
+
let appServer = resolvedAppServer.appServer;
|
|
2743
3396
|
preDynamicStartupStages.mark("app-server-policy");
|
|
2744
3397
|
preDynamicStartupStages.mark("native-hook-relay");
|
|
2745
3398
|
const terminalState = {
|
|
@@ -2787,20 +3440,23 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
2787
3440
|
preDynamicStartupStages.mark("rotate-binding");
|
|
2788
3441
|
if (startupBinding !== startupBindingBeforeRotation) {
|
|
2789
3442
|
reviewerPolicyContext = resolveReviewerPolicyContext(startupBinding);
|
|
2790
|
-
configuredAppServer = resolveRuntimeOptionsForBinding({
|
|
3443
|
+
configuredAppServer = resolveRuntimeOptionsForBinding(startupBinding, {
|
|
2791
3444
|
modelProvider: reviewerPolicyContext.modelProvider,
|
|
2792
3445
|
model: reviewerPolicyContext.model
|
|
2793
3446
|
});
|
|
2794
|
-
|
|
2795
|
-
appServer =
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
3447
|
+
resolvedAppServer = resolveFinalAppServer(configuredAppServer, reviewerPolicyContext);
|
|
3448
|
+
appServer = resolvedAppServer.appServer;
|
|
3449
|
+
}
|
|
3450
|
+
const sessionPermissionPolicy = resolveCodexEffectiveSessionPermissionPolicy({
|
|
3451
|
+
appServer,
|
|
3452
|
+
permissionMode: params.permissionMode,
|
|
3453
|
+
sessionRoot: params.sessionRoot,
|
|
3454
|
+
defaultRoot: effectiveWorkspace
|
|
3455
|
+
});
|
|
3456
|
+
if (sessionPermissionPolicy) {
|
|
3457
|
+
params.permissionMode = sessionPermissionPolicy.mode;
|
|
3458
|
+
params.sessionRoot = sessionPermissionPolicy.root;
|
|
3459
|
+
(params.execOverrides ??= {}).mode = sessionPermissionPolicy.execMode;
|
|
2804
3460
|
}
|
|
2805
3461
|
const nativeHookRelayEvents = resolveCodexNativeHookRelayEvents({
|
|
2806
3462
|
configuredEvents: options.nativeHookRelay?.events,
|
|
@@ -2809,22 +3465,10 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
2809
3465
|
const mutable = {
|
|
2810
3466
|
startupBinding,
|
|
2811
3467
|
startupContextTokens: startupBindingResolution.startupContextTokens,
|
|
2812
|
-
pluginAppServer: appServer
|
|
3468
|
+
pluginAppServer: appServer,
|
|
3469
|
+
continuityCalibration: startupBindingBeforeRotation?.continuityCalibration
|
|
2813
3470
|
};
|
|
2814
|
-
const resolveRuntimeOptionsForCurrentBinding = (selection) =>
|
|
2815
|
-
appServer: resolveCodexBindingAppServerConnection({
|
|
2816
|
-
binding: mutable.startupBinding,
|
|
2817
|
-
pluginConfig,
|
|
2818
|
-
execPolicy,
|
|
2819
|
-
modelProvider: selection.modelProvider,
|
|
2820
|
-
model: selection.model,
|
|
2821
|
-
config: params.config,
|
|
2822
|
-
agentDir,
|
|
2823
|
-
openClawSandboxActive: sandbox?.enabled === true
|
|
2824
|
-
}).appServer,
|
|
2825
|
-
binding: mutable.startupBinding,
|
|
2826
|
-
execPolicyTouched: execPolicy.touched
|
|
2827
|
-
});
|
|
3471
|
+
const resolveRuntimeOptionsForCurrentBinding = (selection) => resolveFinalAppServer(resolveRuntimeOptionsForBinding(mutable.startupBinding, selection), selection).appServer;
|
|
2828
3472
|
return {
|
|
2829
3473
|
params,
|
|
2830
3474
|
options,
|
|
@@ -2846,6 +3490,8 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
2846
3490
|
contextSessionKey,
|
|
2847
3491
|
sandbox,
|
|
2848
3492
|
agentDir,
|
|
3493
|
+
shellEnvironment,
|
|
3494
|
+
disableLoginShell,
|
|
2849
3495
|
bindingIdentity,
|
|
2850
3496
|
bindingStore,
|
|
2851
3497
|
activeContextEngine,
|
|
@@ -2858,7 +3504,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
2858
3504
|
effectiveWorkspace,
|
|
2859
3505
|
effectiveCwd,
|
|
2860
3506
|
appServer,
|
|
2861
|
-
|
|
3507
|
+
sessionPermissionPolicy,
|
|
2862
3508
|
nativeHookRelayEvents,
|
|
2863
3509
|
runAbortController,
|
|
2864
3510
|
terminalState,
|
|
@@ -2951,10 +3597,12 @@ function resolveContextEngineBootstrapProjectionDecision(params) {
|
|
|
2951
3597
|
*/
|
|
2952
3598
|
async function buildCodexWorkspaceBootstrapContext(params) {
|
|
2953
3599
|
try {
|
|
3600
|
+
const inheritsAgentWorkspace = (params.executionWorkspace ?? params.resolvedWorkspace) !== params.resolvedWorkspace;
|
|
3601
|
+
const promptWorkspace = inheritsAgentWorkspace ? params.resolvedWorkspace : params.effectiveWorkspace;
|
|
2954
3602
|
const memoryToolsAvailable = params.memoryToolNames.length > 0 && canRouteCodexWorkspaceMemoryThroughTools({
|
|
2955
3603
|
config: params.params.config,
|
|
2956
3604
|
agentId: params.params.agentId ?? params.sessionAgentId,
|
|
2957
|
-
workspaceDir: params.effectiveWorkspace
|
|
3605
|
+
workspaceDir: inheritsAgentWorkspace ? params.resolvedWorkspace : params.effectiveWorkspace
|
|
2958
3606
|
});
|
|
2959
3607
|
const bootstrapFiles = await resolveBootstrapFilesForRun({
|
|
2960
3608
|
workspaceDir: params.resolvedWorkspace,
|
|
@@ -2974,7 +3622,7 @@ async function buildCodexWorkspaceBootstrapContext(params) {
|
|
|
2974
3622
|
const memoryReferenceFiles = memoryToolRoutedBootstrapFiles.map((file) => remapCodexContextFilePath({
|
|
2975
3623
|
file: toCodexEmbeddedContextFile(file),
|
|
2976
3624
|
sourceWorkspaceDir: params.resolvedWorkspace,
|
|
2977
|
-
targetWorkspaceDir:
|
|
3625
|
+
targetWorkspaceDir: promptWorkspace
|
|
2978
3626
|
}));
|
|
2979
3627
|
const contextFiles = buildBootstrapContextForFiles(memoryToolsAvailable ? bootstrapFiles.filter((file) => !isCodexWorkspaceRootMemoryBootstrapFile({
|
|
2980
3628
|
file,
|
|
@@ -2986,23 +3634,33 @@ async function buildCodexWorkspaceBootstrapContext(params) {
|
|
|
2986
3634
|
}).map((file) => remapCodexContextFilePath({
|
|
2987
3635
|
file,
|
|
2988
3636
|
sourceWorkspaceDir: params.resolvedWorkspace,
|
|
2989
|
-
targetWorkspaceDir:
|
|
3637
|
+
targetWorkspaceDir: promptWorkspace
|
|
2990
3638
|
}));
|
|
2991
3639
|
const promptContextFiles = selectCodexWorkspacePromptContextFiles(contextFiles, {
|
|
2992
3640
|
excludeMemory: memoryToolsAvailable,
|
|
2993
3641
|
memoryWorkspaceDir: params.effectiveWorkspace
|
|
2994
3642
|
});
|
|
2995
|
-
const
|
|
3643
|
+
const injectOpenClawContext = shouldInjectCodexOpenClawPromptContext(params.params);
|
|
3644
|
+
const restrictedProjectDocNeedsOpenClawCarrier = params.params.pluginHarnessToolPolicyRestricted === true && !params.params.disableTools && !isMessageOnlyCodexSourceReply(params.params) && params.params.bootstrapContextMode !== "lightweight";
|
|
3645
|
+
const threadDeveloperInstructionFiles = injectOpenClawContext && !params.ringZeroActive && (inheritsAgentWorkspace || restrictedProjectDocNeedsOpenClawCarrier) ? selectCodexWorkspaceAgentProjectInstructionFiles(contextFiles, params.resolvedWorkspace) : [];
|
|
3646
|
+
const turnScopedDeveloperInstructionFiles = injectOpenClawContext ? selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) : [];
|
|
2996
3647
|
return {
|
|
2997
3648
|
bootstrapFiles,
|
|
2998
3649
|
contextFiles,
|
|
3650
|
+
inheritsAgentWorkspace,
|
|
2999
3651
|
promptContextFiles,
|
|
3652
|
+
threadDeveloperInstructionFiles,
|
|
3000
3653
|
turnScopedDeveloperInstructionFiles,
|
|
3001
3654
|
memoryReferenceFiles,
|
|
3002
3655
|
memoryToolRoutedBootstrapFiles,
|
|
3003
3656
|
memoryToolNames: [...params.memoryToolNames],
|
|
3004
3657
|
memoryToolRouted: memoryToolsAvailable,
|
|
3005
3658
|
promptContext: renderCodexWorkspaceBootstrapPromptContext(promptContextFiles),
|
|
3659
|
+
threadDeveloperInstructions: renderCodexWorkspaceDeveloperInstructions({
|
|
3660
|
+
files: threadDeveloperInstructionFiles,
|
|
3661
|
+
header: "## OpenClaw Agent Workspace Instructions",
|
|
3662
|
+
preamble: "OpenClaw loaded this bounded snapshot from the configured agent workspace."
|
|
3663
|
+
}),
|
|
3006
3664
|
turnScopedDeveloperInstructions: renderCodexWorkspaceCollaborationDeveloperInstructions(turnScopedDeveloperInstructionFiles),
|
|
3007
3665
|
memoryCollaborationInstructions: shouldInjectCodexOpenClawPromptContext(params.params) ? await renderCodexWorkspaceMemoryCollaborationInstructions({
|
|
3008
3666
|
files: memoryReferenceFiles,
|
|
@@ -3018,7 +3676,8 @@ async function buildCodexWorkspaceBootstrapContext(params) {
|
|
|
3018
3676
|
embeddedAgentLog.warn("failed to load codex workspace bootstrap instructions", { error });
|
|
3019
3677
|
return {
|
|
3020
3678
|
bootstrapFiles: [],
|
|
3021
|
-
contextFiles: []
|
|
3679
|
+
contextFiles: [],
|
|
3680
|
+
inheritsAgentWorkspace: false
|
|
3022
3681
|
};
|
|
3023
3682
|
}
|
|
3024
3683
|
}
|
|
@@ -3051,7 +3710,7 @@ function buildCodexSystemPromptReport(params) {
|
|
|
3051
3710
|
injectedWorkspaceFiles: buildCodexBootstrapInjectionStats({
|
|
3052
3711
|
bootstrapFiles: params.workspaceBootstrapContext.bootstrapFiles,
|
|
3053
3712
|
injectedFiles: params.workspaceBootstrapContext.promptContextFiles ?? [],
|
|
3054
|
-
developerInstructionFiles: params.workspaceBootstrapContext.turnScopedDeveloperInstructionFiles ?? [],
|
|
3713
|
+
developerInstructionFiles: [...params.workspaceBootstrapContext.threadDeveloperInstructionFiles ?? [], ...params.workspaceBootstrapContext.turnScopedDeveloperInstructionFiles ?? []],
|
|
3055
3714
|
memoryToolRoutedBootstrapFiles: params.workspaceBootstrapContext.memoryToolRoutedBootstrapFiles ?? [],
|
|
3056
3715
|
memoryToolRouted: params.workspaceBootstrapContext.memoryToolRouted === true
|
|
3057
3716
|
}),
|
|
@@ -3132,12 +3791,17 @@ function buildCodexBootstrapInjectionStats(params) {
|
|
|
3132
3791
|
const rawChars = file.missing ? 0 : (file.content ?? "").trimEnd().length;
|
|
3133
3792
|
const memoryToolRoutedFile = baseName === CODEX_MEMORY_CONTEXT_BASENAME && params.memoryToolRouted === true && memoryToolRoutedPaths.has(normalizeCodexContextFilePath(pathValue));
|
|
3134
3793
|
const injected = memoryToolRoutedFile ? void 0 : readCodexIndexedContextFileContent(injectedIndex, pathValue, fileName) ?? readCodexIndexedContextFileContent(developerInstructionIndex, pathValue, fileName);
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3794
|
+
if (!file.missing && injected === void 0 && CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName)) return {
|
|
3795
|
+
name: displayName,
|
|
3796
|
+
path: pathValue,
|
|
3797
|
+
missing: false,
|
|
3798
|
+
rawChars,
|
|
3799
|
+
injectionStatus: "native_unverified",
|
|
3800
|
+
injectedChars: null,
|
|
3801
|
+
truncated: null
|
|
3802
|
+
};
|
|
3803
|
+
const injectedChars = memoryToolRoutedFile ? 0 : injected?.length ?? 0;
|
|
3804
|
+
const truncated = memoryToolRoutedFile ? false : !file.missing && injectedChars < rawChars;
|
|
3141
3805
|
return {
|
|
3142
3806
|
name: displayName,
|
|
3143
3807
|
path: pathValue,
|
|
@@ -3272,7 +3936,7 @@ function renderCodexWorkspaceBootstrapPromptContext(contextFiles) {
|
|
|
3272
3936
|
const files = contextFiles;
|
|
3273
3937
|
if (files.length === 0) return;
|
|
3274
3938
|
const lines = [
|
|
3275
|
-
"OpenClaw loaded these user-editable workspace files for the current turn. Codex loads AGENTS.md natively. SOUL.md, IDENTITY.md, and USER.md
|
|
3939
|
+
"OpenClaw loaded these user-editable workspace files for the current turn. Codex loads project-local AGENTS.md natively. When execution uses another folder, OpenClaw supplies the agent workspace AGENTS.md as thread-level developer instructions. SOUL.md, IDENTITY.md, and USER.md remain turn-scoped collaboration instructions. Those files are not repeated here.",
|
|
3276
3940
|
"",
|
|
3277
3941
|
"# Project Context",
|
|
3278
3942
|
"",
|
|
@@ -3295,6 +3959,10 @@ function selectCodexWorkspacePromptContextFiles(contextFiles, options = {}) {
|
|
|
3295
3959
|
function selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) {
|
|
3296
3960
|
return selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES);
|
|
3297
3961
|
}
|
|
3962
|
+
function selectCodexWorkspaceAgentProjectInstructionFiles(contextFiles, agentWorkspaceDir) {
|
|
3963
|
+
const agentProjectDocPath = path.join(path.resolve(agentWorkspaceDir), "AGENTS.md");
|
|
3964
|
+
return selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, CODEX_NATIVE_PROJECT_DOC_BASENAMES).filter((file) => path.resolve(file.path) === agentProjectDocPath);
|
|
3965
|
+
}
|
|
3298
3966
|
function selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, basenames) {
|
|
3299
3967
|
return contextFiles.filter((file) => {
|
|
3300
3968
|
const baseName = getCodexContextFileBasename(file.path);
|
|
@@ -3439,23 +4107,120 @@ function compareCodexContextFiles(left, right) {
|
|
|
3439
4107
|
if (leftBase !== rightBase) return leftBase.localeCompare(rightBase);
|
|
3440
4108
|
return leftPath.localeCompare(rightPath);
|
|
3441
4109
|
}
|
|
3442
|
-
function compareCodexBootstrapFiles(left, right) {
|
|
3443
|
-
return compareCodexContextFiles(toCodexEmbeddedContextFile(left), toCodexEmbeddedContextFile(right));
|
|
4110
|
+
function compareCodexBootstrapFiles(left, right) {
|
|
4111
|
+
return compareCodexContextFiles(toCodexEmbeddedContextFile(left), toCodexEmbeddedContextFile(right));
|
|
4112
|
+
}
|
|
4113
|
+
function normalizeCodexContextFilePath(filePath) {
|
|
4114
|
+
return filePath.trim().replaceAll("\\", "/").toLowerCase();
|
|
4115
|
+
}
|
|
4116
|
+
function getCodexContextFileDisplayBasename(filePath) {
|
|
4117
|
+
return filePath.trim().replaceAll("\\", "/").split("/").pop()?.trim() ?? "";
|
|
4118
|
+
}
|
|
4119
|
+
function getCodexContextFileBasename(filePath) {
|
|
4120
|
+
return normalizeCodexContextFilePath(filePath).split("/").pop() ?? "";
|
|
4121
|
+
}
|
|
4122
|
+
function normalizeCodexDynamicToolName(name) {
|
|
4123
|
+
return name.trim().toLowerCase();
|
|
4124
|
+
}
|
|
4125
|
+
function isNonEmptyString$1(value) {
|
|
4126
|
+
return typeof value === "string" && value.length > 0;
|
|
4127
|
+
}
|
|
4128
|
+
//#endregion
|
|
4129
|
+
//#region extensions/codex/src/app-server/run-attempt-state.ts
|
|
4130
|
+
async function clearCodexBindingAfterInvalidImagePayload(bindingStore, identity, fields) {
|
|
4131
|
+
const currentBinding = await bindingStore.read(identity);
|
|
4132
|
+
const expectedThreadId = fields.threadId ?? currentBinding?.threadId;
|
|
4133
|
+
if (!expectedThreadId) return;
|
|
4134
|
+
if (currentBinding && currentBinding.threadId !== expectedThreadId) {
|
|
4135
|
+
embeddedAgentLog.warn("codex app-server image payload error detected for unbound thread; preserving thread binding", {
|
|
4136
|
+
...fields,
|
|
4137
|
+
boundThreadId: currentBinding.threadId
|
|
4138
|
+
});
|
|
4139
|
+
return;
|
|
4140
|
+
}
|
|
4141
|
+
if (currentBinding?.connectionScope === "supervision") {
|
|
4142
|
+
embeddedAgentLog.warn("codex app-server image payload error detected for supervised thread; preserving native binding", fields);
|
|
4143
|
+
return;
|
|
4144
|
+
}
|
|
4145
|
+
embeddedAgentLog.warn("codex app-server image payload error detected; clearing thread binding", fields);
|
|
4146
|
+
await bindingStore.mutate(identity, {
|
|
4147
|
+
kind: "clear",
|
|
4148
|
+
threadId: expectedThreadId
|
|
4149
|
+
});
|
|
4150
|
+
}
|
|
4151
|
+
async function markCodexAppServerBindingCoveredThroughTurn(params) {
|
|
4152
|
+
await params.bindingStore.mutate(params.identity, {
|
|
4153
|
+
kind: "patch",
|
|
4154
|
+
threadId: params.threadId,
|
|
4155
|
+
patch: {
|
|
4156
|
+
historyCoveredThrough: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4157
|
+
...params.continuityCalibration ? { continuityCalibration: params.continuityCalibration } : {}
|
|
4158
|
+
}
|
|
4159
|
+
});
|
|
4160
|
+
}
|
|
4161
|
+
function isNonEmptyString(value) {
|
|
4162
|
+
return typeof value === "string" && value.length > 0;
|
|
3444
4163
|
}
|
|
3445
|
-
function
|
|
3446
|
-
|
|
4164
|
+
function shouldUseFreshCodexThreadAfterContextEngineOverflow(params) {
|
|
4165
|
+
if (!params.contextEngineActive || params.thread.lifecycle.action !== "resumed") return false;
|
|
4166
|
+
const message = formatErrorMessage(params.error);
|
|
4167
|
+
return /ran out of room in the model'?s context window/iu.test(message) || /context window/iu.test(message) || /context length/iu.test(message) || /maximum context/iu.test(message) || /too many tokens/iu.test(message);
|
|
3447
4168
|
}
|
|
3448
|
-
function
|
|
3449
|
-
|
|
4169
|
+
function isCodexActiveCompactTurnError(error) {
|
|
4170
|
+
if (!(error instanceof CodexAppServerRpcError)) return false;
|
|
4171
|
+
const data = isJsonObject(error.data) ? error.data : void 0;
|
|
4172
|
+
const codexErrorInfo = isJsonObject(data?.codexErrorInfo) ? data.codexErrorInfo : void 0;
|
|
4173
|
+
return (isJsonObject(codexErrorInfo?.activeTurnNotSteerable) ? codexErrorInfo.activeTurnNotSteerable : void 0)?.turnKind === "compact";
|
|
3450
4174
|
}
|
|
3451
|
-
function
|
|
3452
|
-
|
|
4175
|
+
function readCodexFinalizationHookNotification(notification, threadId, turnId) {
|
|
4176
|
+
if (notification.method !== "hook/started" && notification.method !== "hook/completed") return;
|
|
4177
|
+
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
4178
|
+
const run = params && isJsonObject(params.run) ? params.run : void 0;
|
|
4179
|
+
if (params?.threadId !== threadId || params.turnId !== turnId || run?.eventName !== "stop" && run?.eventName !== "subagentStop" || typeof run.id !== "string" || !run.id) return;
|
|
4180
|
+
if (notification.method === "hook/started") return {
|
|
4181
|
+
phase: "started",
|
|
4182
|
+
runId: run.id
|
|
4183
|
+
};
|
|
4184
|
+
return {
|
|
4185
|
+
phase: "completed",
|
|
4186
|
+
runId: run.id,
|
|
4187
|
+
status: typeof run.status === "string" ? run.status : void 0
|
|
4188
|
+
};
|
|
3453
4189
|
}
|
|
3454
|
-
function
|
|
3455
|
-
return
|
|
4190
|
+
function joinPresentSections(...sections) {
|
|
4191
|
+
return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
|
|
3456
4192
|
}
|
|
3457
|
-
function
|
|
3458
|
-
|
|
4193
|
+
function prependCurrentInboundContext(prompt, context) {
|
|
4194
|
+
const text = context?.text.trim();
|
|
4195
|
+
return text ? [neutralizeCodexExplicitMentionSigils(text), prompt].filter(Boolean).join("\n\n") : prompt;
|
|
4196
|
+
}
|
|
4197
|
+
function buildCodexAppServerTimeoutDiagnostics(params) {
|
|
4198
|
+
const readNonBlankDetailString = (key) => {
|
|
4199
|
+
const value = params.details?.[key];
|
|
4200
|
+
return hasNonEmptyString(value) ? value : void 0;
|
|
4201
|
+
};
|
|
4202
|
+
const activeAppServerTurnRequests = asFiniteNumber(params.details?.activeAppServerTurnRequests);
|
|
4203
|
+
const activeTurnItemCount = asFiniteNumber(params.details?.activeTurnItemCount);
|
|
4204
|
+
const terminalTurnNotificationQueued = asBoolean(params.details?.terminalTurnNotificationQueued);
|
|
4205
|
+
const completionIdleWatchArmed = asBoolean(params.details?.completionIdleWatchArmed);
|
|
4206
|
+
const assistantCompletionIdleWatchArmed = asBoolean(params.details?.assistantCompletionIdleWatchArmed);
|
|
4207
|
+
const terminalIdleWatchArmed = asBoolean(params.details?.terminalIdleWatchArmed);
|
|
4208
|
+
return {
|
|
4209
|
+
...params.idleMs !== void 0 ? { idleMs: params.idleMs } : {},
|
|
4210
|
+
...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
|
|
4211
|
+
...params.lastActivityReason ? { lastActivityReason: params.lastActivityReason } : {},
|
|
4212
|
+
...readNonBlankDetailString("lastNotificationMethod") ? { lastNotificationMethod: readNonBlankDetailString("lastNotificationMethod") } : {},
|
|
4213
|
+
...readNonBlankDetailString("lastNotificationItemId") ? { lastNotificationItemId: readNonBlankDetailString("lastNotificationItemId") } : {},
|
|
4214
|
+
...readNonBlankDetailString("lastNotificationItemType") ? { lastNotificationItemType: readNonBlankDetailString("lastNotificationItemType") } : {},
|
|
4215
|
+
...readNonBlankDetailString("lastNotificationItemRole") ? { lastNotificationItemRole: readNonBlankDetailString("lastNotificationItemRole") } : {},
|
|
4216
|
+
...readNonBlankDetailString("lastAssistantTextPreview") ? { lastAssistantTextPreview: readNonBlankDetailString("lastAssistantTextPreview") } : {},
|
|
4217
|
+
...activeAppServerTurnRequests !== void 0 ? { activeAppServerTurnRequests } : {},
|
|
4218
|
+
...activeTurnItemCount !== void 0 ? { activeTurnItemCount } : {},
|
|
4219
|
+
...terminalTurnNotificationQueued !== void 0 ? { terminalTurnNotificationQueued } : {},
|
|
4220
|
+
...completionIdleWatchArmed !== void 0 ? { completionIdleWatchArmed } : {},
|
|
4221
|
+
...assistantCompletionIdleWatchArmed !== void 0 ? { assistantCompletionIdleWatchArmed } : {},
|
|
4222
|
+
...terminalIdleWatchArmed !== void 0 ? { terminalIdleWatchArmed } : {}
|
|
4223
|
+
};
|
|
3459
4224
|
}
|
|
3460
4225
|
//#endregion
|
|
3461
4226
|
//#region extensions/codex/src/app-server/run-attempt-context.ts
|
|
@@ -3527,16 +4292,20 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
|
3527
4292
|
});
|
|
3528
4293
|
historyState.messages = await readFencedHistory() ?? historyState.messages;
|
|
3529
4294
|
}
|
|
4295
|
+
const memoryToolNames = getCodexWorkspaceMemoryToolNames(toolBridge.availableSpecs);
|
|
3530
4296
|
const workspaceBootstrapContext = await buildCodexWorkspaceBootstrapContext({
|
|
3531
4297
|
params: runtimeParams,
|
|
3532
|
-
resolvedWorkspace,
|
|
4298
|
+
resolvedWorkspace: runtimeParams.bootstrapWorkspaceDir ?? resolvedWorkspace,
|
|
4299
|
+
executionWorkspace: resolvedWorkspace,
|
|
3533
4300
|
effectiveWorkspace,
|
|
3534
4301
|
sessionKey: contextSessionKey,
|
|
3535
4302
|
sessionAgentId,
|
|
3536
|
-
memoryToolNames
|
|
4303
|
+
memoryToolNames,
|
|
4304
|
+
ringZeroActive: isHostScopedAgentToolActive("openclaw") && isSystemAgentOnlyCodexDynamicToolAllowlist(runtimeParams.toolsAllow),
|
|
3537
4305
|
sandboxed: sandbox?.enabled === true
|
|
3538
4306
|
});
|
|
3539
|
-
const
|
|
4307
|
+
const agentWorkspaceDeveloperInstructions = workspaceBootstrapContext.threadDeveloperInstructions ? connection.mutable.startupBinding?.agentWorkspaceDeveloperInstructions ?? workspaceBootstrapContext.threadDeveloperInstructions : void 0;
|
|
4308
|
+
const baseDeveloperInstructions = joinPresentSections(buildDeveloperInstructions(runtimeParams, { dynamicTools: toolBridge.availableSpecs }), agentWorkspaceDeveloperInstructions);
|
|
3540
4309
|
return {
|
|
3541
4310
|
runtime,
|
|
3542
4311
|
attemptTools,
|
|
@@ -3547,6 +4316,7 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
|
3547
4316
|
hookRunner,
|
|
3548
4317
|
buildActiveContextEngineRuntimeContext,
|
|
3549
4318
|
workspaceBootstrapContext,
|
|
4319
|
+
agentWorkspaceDeveloperInstructions,
|
|
3550
4320
|
baseDeveloperInstructions,
|
|
3551
4321
|
openClawPromptContext: buildCodexOpenClawPromptContext({
|
|
3552
4322
|
params: runtimeParams,
|
|
@@ -3570,11 +4340,16 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
|
3570
4340
|
contextEngineProjection: void 0,
|
|
3571
4341
|
precomputedStaleBindingContinuityProjectionApplied: false,
|
|
3572
4342
|
staleBindingContinuityForcedFreshStart: false,
|
|
4343
|
+
noEngineContinuityProjectionApplied: false,
|
|
3573
4344
|
inactiveThreadBootstrapBindingForcedFreshStart: initialInactiveThreadBootstrapBindingForcedFreshStart
|
|
3574
4345
|
},
|
|
3575
4346
|
codexContextProjectionMaxChars: resolveCodexContextEngineProjectionMaxChars({
|
|
3576
4347
|
contextTokenBudget: effectiveContextTokenBudget,
|
|
3577
4348
|
reserveTokens: resolveCodexContextEngineProjectionReserveTokens()
|
|
4349
|
+
}),
|
|
4350
|
+
codexContinuityProjectionMaxChars: resolveCodexContinuityProjectionMaxChars({
|
|
4351
|
+
contextTokenBudget: effectiveContextTokenBudget,
|
|
4352
|
+
calibration: connection.mutable.continuityCalibration
|
|
3578
4353
|
})
|
|
3579
4354
|
};
|
|
3580
4355
|
}
|
|
@@ -3785,105 +4560,6 @@ function isInvalidCodexImagePayloadError(message) {
|
|
|
3785
4560
|
return /\b(?:invalid|malformed)\b[\s\S]{0,120}\b(?:image|image url|base64)\b/iu.test(normalizedMessage) || /\b(?:image|image url|base64)\b[\s\S]{0,120}\b(?:invalid|malformed)\b/iu.test(normalizedMessage);
|
|
3786
4561
|
}
|
|
3787
4562
|
//#endregion
|
|
3788
|
-
//#region extensions/codex/src/app-server/run-attempt-state.ts
|
|
3789
|
-
async function clearCodexBindingAfterInvalidImagePayload(bindingStore, identity, fields) {
|
|
3790
|
-
const currentBinding = await bindingStore.read(identity);
|
|
3791
|
-
const expectedThreadId = fields.threadId ?? currentBinding?.threadId;
|
|
3792
|
-
if (!expectedThreadId) return;
|
|
3793
|
-
if (currentBinding && currentBinding.threadId !== expectedThreadId) {
|
|
3794
|
-
embeddedAgentLog.warn("codex app-server image payload error detected for unbound thread; preserving thread binding", {
|
|
3795
|
-
...fields,
|
|
3796
|
-
boundThreadId: currentBinding.threadId
|
|
3797
|
-
});
|
|
3798
|
-
return;
|
|
3799
|
-
}
|
|
3800
|
-
if (currentBinding?.connectionScope === "supervision") {
|
|
3801
|
-
embeddedAgentLog.warn("codex app-server image payload error detected for supervised thread; preserving native binding", fields);
|
|
3802
|
-
return;
|
|
3803
|
-
}
|
|
3804
|
-
embeddedAgentLog.warn("codex app-server image payload error detected; clearing thread binding", fields);
|
|
3805
|
-
await bindingStore.mutate(identity, {
|
|
3806
|
-
kind: "clear",
|
|
3807
|
-
threadId: expectedThreadId
|
|
3808
|
-
});
|
|
3809
|
-
}
|
|
3810
|
-
async function markCodexAppServerBindingCoveredThroughTurn(params) {
|
|
3811
|
-
await params.bindingStore.mutate(params.identity, {
|
|
3812
|
-
kind: "patch",
|
|
3813
|
-
threadId: params.threadId,
|
|
3814
|
-
patch: { historyCoveredThrough: (/* @__PURE__ */ new Date()).toISOString() }
|
|
3815
|
-
});
|
|
3816
|
-
}
|
|
3817
|
-
function isNonEmptyString(value) {
|
|
3818
|
-
return typeof value === "string" && value.length > 0;
|
|
3819
|
-
}
|
|
3820
|
-
function shouldUseFreshCodexThreadAfterContextEngineOverflow(params) {
|
|
3821
|
-
if (!params.contextEngineActive || params.thread.lifecycle.action !== "resumed") return false;
|
|
3822
|
-
const message = formatErrorMessage(params.error);
|
|
3823
|
-
return /ran out of room in the model'?s context window/iu.test(message) || /context window/iu.test(message) || /context length/iu.test(message) || /maximum context/iu.test(message) || /too many tokens/iu.test(message);
|
|
3824
|
-
}
|
|
3825
|
-
function isCodexActiveCompactTurnError(error) {
|
|
3826
|
-
if (!(error instanceof CodexAppServerRpcError)) return false;
|
|
3827
|
-
const data = isJsonObject(error.data) ? error.data : void 0;
|
|
3828
|
-
const codexErrorInfo = isJsonObject(data?.codexErrorInfo) ? data.codexErrorInfo : void 0;
|
|
3829
|
-
return (isJsonObject(codexErrorInfo?.activeTurnNotSteerable) ? codexErrorInfo.activeTurnNotSteerable : void 0)?.turnKind === "compact";
|
|
3830
|
-
}
|
|
3831
|
-
function readCodexFinalizationHookNotification(notification, threadId, turnId) {
|
|
3832
|
-
if (notification.method !== "hook/started" && notification.method !== "hook/completed") return;
|
|
3833
|
-
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
3834
|
-
const run = params && isJsonObject(params.run) ? params.run : void 0;
|
|
3835
|
-
if (params?.threadId !== threadId || params.turnId !== turnId || run?.eventName !== "stop" && run?.eventName !== "subagentStop" || typeof run.id !== "string" || !run.id) return;
|
|
3836
|
-
if (notification.method === "hook/started") return {
|
|
3837
|
-
phase: "started",
|
|
3838
|
-
runId: run.id
|
|
3839
|
-
};
|
|
3840
|
-
return {
|
|
3841
|
-
phase: "completed",
|
|
3842
|
-
runId: run.id,
|
|
3843
|
-
status: typeof run.status === "string" ? run.status : void 0
|
|
3844
|
-
};
|
|
3845
|
-
}
|
|
3846
|
-
function joinPresentSections(...sections) {
|
|
3847
|
-
return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
|
|
3848
|
-
}
|
|
3849
|
-
function prependCurrentInboundContext(prompt, context) {
|
|
3850
|
-
const text = context?.text.trim();
|
|
3851
|
-
return text ? [neutralizeCodexExplicitMentionSigils(text), prompt].filter(Boolean).join("\n\n") : prompt;
|
|
3852
|
-
}
|
|
3853
|
-
function waitForCodexNotificationDispatchTurn() {
|
|
3854
|
-
return new Promise((resolve) => {
|
|
3855
|
-
setImmediate(resolve);
|
|
3856
|
-
});
|
|
3857
|
-
}
|
|
3858
|
-
function buildCodexAppServerTimeoutDiagnostics(params) {
|
|
3859
|
-
const readNonBlankDetailString = (key) => {
|
|
3860
|
-
const value = params.details?.[key];
|
|
3861
|
-
return hasNonEmptyString(value) ? value : void 0;
|
|
3862
|
-
};
|
|
3863
|
-
const activeAppServerTurnRequests = asFiniteNumber(params.details?.activeAppServerTurnRequests);
|
|
3864
|
-
const activeTurnItemCount = asFiniteNumber(params.details?.activeTurnItemCount);
|
|
3865
|
-
const terminalTurnNotificationQueued = asBoolean(params.details?.terminalTurnNotificationQueued);
|
|
3866
|
-
const completionIdleWatchArmed = asBoolean(params.details?.completionIdleWatchArmed);
|
|
3867
|
-
const assistantCompletionIdleWatchArmed = asBoolean(params.details?.assistantCompletionIdleWatchArmed);
|
|
3868
|
-
const terminalIdleWatchArmed = asBoolean(params.details?.terminalIdleWatchArmed);
|
|
3869
|
-
return {
|
|
3870
|
-
...params.idleMs !== void 0 ? { idleMs: params.idleMs } : {},
|
|
3871
|
-
...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
|
|
3872
|
-
...params.lastActivityReason ? { lastActivityReason: params.lastActivityReason } : {},
|
|
3873
|
-
...readNonBlankDetailString("lastNotificationMethod") ? { lastNotificationMethod: readNonBlankDetailString("lastNotificationMethod") } : {},
|
|
3874
|
-
...readNonBlankDetailString("lastNotificationItemId") ? { lastNotificationItemId: readNonBlankDetailString("lastNotificationItemId") } : {},
|
|
3875
|
-
...readNonBlankDetailString("lastNotificationItemType") ? { lastNotificationItemType: readNonBlankDetailString("lastNotificationItemType") } : {},
|
|
3876
|
-
...readNonBlankDetailString("lastNotificationItemRole") ? { lastNotificationItemRole: readNonBlankDetailString("lastNotificationItemRole") } : {},
|
|
3877
|
-
...readNonBlankDetailString("lastAssistantTextPreview") ? { lastAssistantTextPreview: readNonBlankDetailString("lastAssistantTextPreview") } : {},
|
|
3878
|
-
...activeAppServerTurnRequests !== void 0 ? { activeAppServerTurnRequests } : {},
|
|
3879
|
-
...activeTurnItemCount !== void 0 ? { activeTurnItemCount } : {},
|
|
3880
|
-
...terminalTurnNotificationQueued !== void 0 ? { terminalTurnNotificationQueued } : {},
|
|
3881
|
-
...completionIdleWatchArmed !== void 0 ? { completionIdleWatchArmed } : {},
|
|
3882
|
-
...assistantCompletionIdleWatchArmed !== void 0 ? { assistantCompletionIdleWatchArmed } : {},
|
|
3883
|
-
...terminalIdleWatchArmed !== void 0 ? { terminalIdleWatchArmed } : {}
|
|
3884
|
-
};
|
|
3885
|
-
}
|
|
3886
|
-
//#endregion
|
|
3887
4563
|
//#region extensions/codex/src/app-server/settled-turn-context.ts
|
|
3888
4564
|
function collectUniqueMessageIdentities(messages) {
|
|
3889
4565
|
const identities = /* @__PURE__ */ new Map();
|
|
@@ -3973,100 +4649,17 @@ async function captureCodexSettledTurnFinalizationContext(params) {
|
|
|
3973
4649
|
}
|
|
3974
4650
|
//#endregion
|
|
3975
4651
|
//#region extensions/codex/src/app-server/trajectory.ts
|
|
3976
|
-
|
|
3977
|
-
const PRIVATE_PAYLOAD_FIELD_RE = /(?:image|screenshot|attachment|fileData|dataUri)/iu;
|
|
3978
|
-
const AUTHORIZATION_VALUE_RE = /\b(Bearer|Basic)\s+[A-Za-z0-9+/._~=-]{8,}/giu;
|
|
3979
|
-
const JWT_VALUE_RE = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/gu;
|
|
3980
|
-
const COOKIE_PAIR_RE = /\b([A-Za-z][A-Za-z0-9_.-]{1,64})=([A-Za-z0-9+/._~%=-]{16,})(?=;|\s|$)/gu;
|
|
3981
|
-
const TRAJECTORY_RUNTIME_EVENT_MAX_BYTES = 256 * 1024;
|
|
3982
|
-
const TRAJECTORY_RUNTIME_OVERSIZE_PRESERVED_DATA_KEYS = ["usage", "promptCache"];
|
|
3983
|
-
function boundedTrajectoryEvent(event) {
|
|
3984
|
-
const line = JSON.stringify(event);
|
|
3985
|
-
const bytes = Buffer.byteLength(line, "utf8");
|
|
3986
|
-
if (bytes <= TRAJECTORY_RUNTIME_EVENT_MAX_BYTES) return event;
|
|
3987
|
-
const originalData = event.data && typeof event.data === "object" && !Array.isArray(event.data) ? event.data : {};
|
|
3988
|
-
const originalDataKeys = Object.keys(originalData);
|
|
3989
|
-
const preservedDataKeys = /* @__PURE__ */ new Set();
|
|
3990
|
-
const baseData = {
|
|
3991
|
-
truncated: true,
|
|
3992
|
-
originalBytes: bytes,
|
|
3993
|
-
limitBytes: TRAJECTORY_RUNTIME_EVENT_MAX_BYTES,
|
|
3994
|
-
reason: "trajectory-event-size-limit"
|
|
3995
|
-
};
|
|
3996
|
-
const buildTruncatedEvent = (includeDroppedFields) => {
|
|
3997
|
-
const data = { ...baseData };
|
|
3998
|
-
for (const key of TRAJECTORY_RUNTIME_OVERSIZE_PRESERVED_DATA_KEYS) if (preservedDataKeys.has(key)) data[key] = originalData[key];
|
|
3999
|
-
if (includeDroppedFields) {
|
|
4000
|
-
const droppedFields = originalDataKeys.filter((key) => !preservedDataKeys.has(key));
|
|
4001
|
-
if (droppedFields.length > 0) data.droppedFields = droppedFields;
|
|
4002
|
-
}
|
|
4003
|
-
const truncatedEvent = {
|
|
4004
|
-
...event,
|
|
4005
|
-
data
|
|
4006
|
-
};
|
|
4007
|
-
const truncated = JSON.stringify(truncatedEvent);
|
|
4008
|
-
if (Buffer.byteLength(truncated, "utf8") <= TRAJECTORY_RUNTIME_EVENT_MAX_BYTES) return truncatedEvent;
|
|
4009
|
-
};
|
|
4010
|
-
let best = buildTruncatedEvent(true) ?? buildTruncatedEvent(false);
|
|
4011
|
-
if (!best) return;
|
|
4012
|
-
for (const key of TRAJECTORY_RUNTIME_OVERSIZE_PRESERVED_DATA_KEYS) {
|
|
4013
|
-
if (!Object.hasOwn(originalData, key)) continue;
|
|
4014
|
-
preservedDataKeys.add(key);
|
|
4015
|
-
const next = buildTruncatedEvent(true) ?? buildTruncatedEvent(false);
|
|
4016
|
-
if (next) {
|
|
4017
|
-
best = next;
|
|
4018
|
-
continue;
|
|
4019
|
-
}
|
|
4020
|
-
preservedDataKeys.delete(key);
|
|
4021
|
-
}
|
|
4022
|
-
return best;
|
|
4023
|
-
}
|
|
4024
|
-
function createCodexHostTrajectorySink(params) {
|
|
4025
|
-
return {
|
|
4026
|
-
write: (event) => {
|
|
4027
|
-
params.recorder.recordEvent(event.type, event.data);
|
|
4028
|
-
},
|
|
4029
|
-
flush: async () => {
|
|
4030
|
-
await params.recorder.flush();
|
|
4031
|
-
}
|
|
4032
|
-
};
|
|
4033
|
-
}
|
|
4034
|
-
/** Creates a trajectory recorder when trajectory capture is enabled for the environment. */
|
|
4652
|
+
/** Creates a trajectory recorder when the host exposes its capture capability. */
|
|
4035
4653
|
function createCodexTrajectoryRecorder(params) {
|
|
4036
|
-
if (!
|
|
4037
|
-
|
|
4038
|
-
params.warn?.("codex trajectory capture requires the SQLite host recorder", {
|
|
4039
|
-
sessionId: params.attempt.sessionId,
|
|
4040
|
-
reason: "sqlite-recorder-unavailable"
|
|
4041
|
-
});
|
|
4042
|
-
return null;
|
|
4043
|
-
}
|
|
4044
|
-
const sink = createCodexHostTrajectorySink({ recorder: params.trajectoryRecorder });
|
|
4045
|
-
let seq = 0;
|
|
4046
|
-
const attribution = resolveCodexLocalRuntimeAttribution(params.attempt);
|
|
4654
|
+
if (!params.trajectory) return null;
|
|
4655
|
+
const trajectory = params.trajectory;
|
|
4047
4656
|
return {
|
|
4048
4657
|
recordEvent: (type, data) => {
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
traceId: params.attempt.sessionId,
|
|
4053
|
-
source: "runtime",
|
|
4054
|
-
type,
|
|
4055
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4056
|
-
seq: seq += 1,
|
|
4057
|
-
sourceSeq: seq,
|
|
4058
|
-
sessionId: params.attempt.sessionId,
|
|
4059
|
-
sessionKey: params.attempt.sessionKey,
|
|
4060
|
-
runId: params.attempt.runId,
|
|
4061
|
-
workspaceDir: params.cwd,
|
|
4062
|
-
provider: attribution.provider,
|
|
4063
|
-
modelId: params.attempt.modelId,
|
|
4064
|
-
modelApi: attribution.api,
|
|
4065
|
-
data: data ? sanitizeValue(data) : void 0
|
|
4066
|
-
});
|
|
4067
|
-
if (event) sink.write(event);
|
|
4658
|
+
try {
|
|
4659
|
+
trajectory.recordEvent(type, data);
|
|
4660
|
+
} catch {}
|
|
4068
4661
|
},
|
|
4069
|
-
flush:
|
|
4662
|
+
flush: trajectory.flush
|
|
4070
4663
|
};
|
|
4071
4664
|
}
|
|
4072
4665
|
/** Records compiled prompt/tool context at the start of a Codex runtime attempt. */
|
|
@@ -4095,12 +4688,6 @@ function recordCodexTrajectoryCompletion(recorder, params) {
|
|
|
4095
4688
|
messagesSnapshot: params.result.messagesSnapshot
|
|
4096
4689
|
});
|
|
4097
4690
|
}
|
|
4098
|
-
function parseTrajectoryEnabled(env) {
|
|
4099
|
-
const value = env.OPENCLAW_TRAJECTORY?.trim().toLowerCase();
|
|
4100
|
-
if (value === "1" || value === "true" || value === "yes" || value === "on") return true;
|
|
4101
|
-
if (value === "0" || value === "false" || value === "no" || value === "off") return false;
|
|
4102
|
-
return true;
|
|
4103
|
-
}
|
|
4104
4691
|
function toTrajectoryToolDefinitions(tools) {
|
|
4105
4692
|
if (!tools || tools.length === 0) return;
|
|
4106
4693
|
return flattenCodexDynamicToolFunctions(tools).flatMap((tool) => {
|
|
@@ -4109,31 +4696,10 @@ function toTrajectoryToolDefinitions(tools) {
|
|
|
4109
4696
|
return [{
|
|
4110
4697
|
name,
|
|
4111
4698
|
description: tool.description,
|
|
4112
|
-
parameters:
|
|
4699
|
+
parameters: tool.inputSchema
|
|
4113
4700
|
}];
|
|
4114
4701
|
}).toSorted((left, right) => left.name.localeCompare(right.name));
|
|
4115
4702
|
}
|
|
4116
|
-
function sanitizeValue(value, depth = 0, key = "") {
|
|
4117
|
-
if (value == null || typeof value === "boolean" || typeof value === "number") return value;
|
|
4118
|
-
if (typeof value === "string") {
|
|
4119
|
-
if (SENSITIVE_FIELD_RE.test(key)) return "<redacted>";
|
|
4120
|
-
if (value.startsWith("data:") && value.length > 256) return `<redacted data-uri ${value.slice(0, value.indexOf(",")).length} chars>`;
|
|
4121
|
-
if (PRIVATE_PAYLOAD_FIELD_RE.test(key) && value.length > 256) return "<redacted payload>";
|
|
4122
|
-
const redacted = redactSensitiveString(value);
|
|
4123
|
-
return redacted.length > 2e4 ? `${truncateUtf16Safe(redacted, 2e4)}…` : redacted;
|
|
4124
|
-
}
|
|
4125
|
-
if (depth >= 6) return "<truncated>";
|
|
4126
|
-
if (Array.isArray(value)) return value.slice(0, 100).map((entry) => sanitizeValue(entry, depth + 1, key));
|
|
4127
|
-
if (typeof value === "object") {
|
|
4128
|
-
const next = {};
|
|
4129
|
-
for (const [keyLocal, child] of Object.entries(value).slice(0, 100)) next[keyLocal] = sanitizeValue(child, depth + 1, keyLocal);
|
|
4130
|
-
return next;
|
|
4131
|
-
}
|
|
4132
|
-
return JSON.stringify(value);
|
|
4133
|
-
}
|
|
4134
|
-
function redactSensitiveString(value) {
|
|
4135
|
-
return value.replace(AUTHORIZATION_VALUE_RE, "$1 <redacted>").replace(JWT_VALUE_RE, "<redacted-jwt>").replace(COOKIE_PAIR_RE, "$1=<redacted>");
|
|
4136
|
-
}
|
|
4137
4703
|
/** Converts arbitrary prompt errors into trajectory-safe text. */
|
|
4138
4704
|
function normalizeCodexTrajectoryError(value) {
|
|
4139
4705
|
if (!value) return null;
|
|
@@ -4154,7 +4720,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4154
4720
|
const { hookContextWindowFields, hookRunner } = context;
|
|
4155
4721
|
const { connection, preparedAuthBinding } = runtime;
|
|
4156
4722
|
const { effectiveRuntimeProviderId, effectiveRuntimeModelId } = runtime;
|
|
4157
|
-
const { params, terminalState, runAbortController, activeContextEngine, bindingStore, bindingIdentity, appServer, usesSupervisionConnection, sessionAgentId, contextSessionKey, effectiveCwd, attemptStartedAt, startupAuthProfileId } = connection;
|
|
4723
|
+
const { params, terminalState, runAbortController, activeContextEngine, bindingStore, bindingIdentity, appServer, usesSupervisionConnection, sessionAgentId, contextSessionKey, effectiveCwd, agentDir, attemptStartedAt, startupAuthProfileId } = connection;
|
|
4158
4724
|
const { toolBridge, toolState } = attemptTools;
|
|
4159
4725
|
const { state, completion, pendingOpenClawDynamicToolCompletionIds, activeTurnItemIds, activeCompletionBlockerItemIds, activeFinalizationHookRunIds, turnWatches } = turnRuntime;
|
|
4160
4726
|
const { emitLifecycleTerminal, buildLifecycleTerminalMeta } = lifecycle;
|
|
@@ -4162,7 +4728,20 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4162
4728
|
const { codexModelCallDiagnostics } = requestRuntime;
|
|
4163
4729
|
const { activeTurnId, activeProjector, streamState, freezeRunTerminalOutcome, notifyUserMessagePersisted } = activeTurn;
|
|
4164
4730
|
await completion;
|
|
4165
|
-
await
|
|
4731
|
+
await state.abortCleanup;
|
|
4732
|
+
const drain = drainNotificationQueue();
|
|
4733
|
+
const abortGraceElapsed = createDeferred();
|
|
4734
|
+
let abortGraceTimer;
|
|
4735
|
+
const abortListener = addAbortListener(runAbortController.signal, () => {
|
|
4736
|
+
abortGraceTimer = setTimeout(() => abortGraceElapsed.resolve(), TURN_FINALIZE_DRAIN_ABORT_GRACE_MS);
|
|
4737
|
+
abortGraceTimer.unref?.();
|
|
4738
|
+
});
|
|
4739
|
+
try {
|
|
4740
|
+
await Promise.race([drain, abortGraceElapsed.promise]);
|
|
4741
|
+
} finally {
|
|
4742
|
+
abortListener[Symbol.dispose]();
|
|
4743
|
+
clearTimeout(abortGraceTimer);
|
|
4744
|
+
}
|
|
4166
4745
|
const hasQuiescentCompletedAssistant = activeProjector.hasCompletedTerminalAssistantText() && state.activeAppServerTurnRequests === 0 && activeTurnItemIds.size === 0 && activeCompletionBlockerItemIds.size === 0 && pendingOpenClawDynamicToolCompletionIds.size === 0 && activeFinalizationHookRunIds.size === 0 && state.unsettledFinalizationHookCount === 0 && state.rejectedFinalizationHookAssistant === void 0;
|
|
4167
4746
|
const hasRecoverableCompletedAssistant = !turnWatches.isCompletionIdleWatchPinnedByTerminalError() && turnWatches.isAssistantCompletionIdleWatchArmed() && hasQuiescentCompletedAssistant;
|
|
4168
4747
|
const recoveredTurnWatchTimeout = state.turnCompletionIdleTimedOut && !terminalState.explicitCancellationObserved && hasRecoverableCompletedAssistant && activeProjector.recoverCompletedTerminalAssistantAfterTurnWatchTimeout();
|
|
@@ -4186,9 +4765,9 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4186
4765
|
const projectedTerminal = attemptTerminal.project(result.terminal);
|
|
4187
4766
|
const effectiveTimedOut = state.timedOut && !recoveredTurnWatchTimeout;
|
|
4188
4767
|
const effectiveTurnCompletionIdleTimedOut = state.turnCompletionIdleTimedOut && !recoveredTurnWatchTimeout;
|
|
4189
|
-
const isFinalAborted = () =>
|
|
4768
|
+
const isFinalAborted = () => terminalState.explicitCancellationObserved || !resourceState.executionDisconnectError && (projectedTerminal.aborted || runAbortController.signal.aborted && !state.clientClosedAbort && !recoveredTurnWatchTimeout);
|
|
4190
4769
|
const clientClosedPromptErrorForFinal = state.clientClosedPromptError && hasRecoverableCompletedAssistant ? void 0 : state.clientClosedPromptError;
|
|
4191
|
-
let finalPromptError = clientClosedPromptErrorForFinal ?? (effectiveTurnCompletionIdleTimedOut ? state.turnCompletionIdleTimeoutMessage : effectiveTimedOut ? "codex app-server attempt timed out" : projectedTerminal.promptError);
|
|
4770
|
+
let finalPromptError = resourceState.executionDisconnectError ?? clientClosedPromptErrorForFinal ?? (effectiveTurnCompletionIdleTimedOut ? state.turnCompletionIdleTimeoutMessage : effectiveTimedOut ? "codex app-server attempt timed out" : projectedTerminal.promptError);
|
|
4192
4771
|
const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError instanceof Error ? finalPromptError.message : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
|
|
4193
4772
|
if (isInvalidCodexImagePayloadError(finalPromptErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(bindingStore, bindingIdentity, {
|
|
4194
4773
|
phase: "turn_completed",
|
|
@@ -4229,6 +4808,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4229
4808
|
authProfileId: startupAuthProfileId,
|
|
4230
4809
|
rateLimits: readRecentCodexRateLimits(resourceState.client)
|
|
4231
4810
|
});
|
|
4811
|
+
finalPromptError = resourceState.executionDisconnectError ?? finalPromptError;
|
|
4232
4812
|
const finalPromptErrorSource = effectiveTimedOut || clientClosedPromptErrorForFinal ? "prompt" : projectedTerminal.promptErrorSource;
|
|
4233
4813
|
const codexAppServerFailureKind = clientClosedPromptErrorForFinal ? "client_closed_before_turn_completed" : effectiveTurnCompletionIdleTimedOut ? "turn_completion_idle_timeout" : void 0;
|
|
4234
4814
|
const replayBlockedReason = codexAppServerFailureKind ? resolveCodexAppServerReplayBlockedReason(result) : void 0;
|
|
@@ -4332,20 +4912,11 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4332
4912
|
modelIterations: result.modelIterations ?? 0,
|
|
4333
4913
|
skillWorkshopAvailable: flattenCodexDynamicToolFunctions(attemptTools.toolBridge.availableSpecs).some((tool) => tool.name === "skill_workshop"),
|
|
4334
4914
|
compacted: (result.compactionCount ?? 0) > 0,
|
|
4335
|
-
messageChannel: params.messageChannel,
|
|
4336
|
-
messageProvider: params.messageProvider,
|
|
4337
|
-
chatType: params.chatType,
|
|
4338
|
-
agentAccountId: params.agentAccountId,
|
|
4339
|
-
groupId: params.groupId,
|
|
4340
|
-
groupChannel: params.groupChannel,
|
|
4341
|
-
groupSpace: params.groupSpace,
|
|
4342
|
-
memberRoleIds: params.memberRoleIds,
|
|
4343
|
-
spawnedBy: params.spawnedBy,
|
|
4344
4915
|
senderId: params.senderId ?? void 0,
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4916
|
+
foregroundPromptContext: buildEmbeddedForegroundPromptContext({
|
|
4917
|
+
...params,
|
|
4918
|
+
agentId: sessionAgentId
|
|
4919
|
+
}, agentDir)
|
|
4349
4920
|
},
|
|
4350
4921
|
hookRunner
|
|
4351
4922
|
});
|
|
@@ -4354,7 +4925,11 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4354
4925
|
await markCodexAppServerBindingCoveredThroughTurn({
|
|
4355
4926
|
bindingStore,
|
|
4356
4927
|
identity: bindingIdentity,
|
|
4357
|
-
threadId: resourceState.thread.threadId
|
|
4928
|
+
threadId: resourceState.thread.threadId,
|
|
4929
|
+
continuityCalibration: context.promptState.noEngineContinuityProjectionApplied ? buildCodexContinuityCalibration({
|
|
4930
|
+
promptChars: prompt.turnState.codexTurnPromptText.length,
|
|
4931
|
+
inputTokens: (result.attemptUsage?.input ?? 0) + (result.attemptUsage?.cacheRead ?? 0) + (result.attemptUsage?.cacheWrite ?? 0)
|
|
4932
|
+
}) : void 0
|
|
4358
4933
|
});
|
|
4359
4934
|
} catch (error) {
|
|
4360
4935
|
if (resourceState.thread.connectionScope === "supervision") throw error;
|
|
@@ -4407,6 +4982,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4407
4982
|
});
|
|
4408
4983
|
const finalizedResult = {
|
|
4409
4984
|
...result,
|
|
4985
|
+
...toolState.yieldAcknowledgment ? { yieldAcknowledgment: toolState.yieldAcknowledgment } : {},
|
|
4410
4986
|
terminal: attemptTerminal.normalize({
|
|
4411
4987
|
timedOut: effectiveTimedOut,
|
|
4412
4988
|
aborted: finalAborted,
|
|
@@ -4420,6 +4996,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
4420
4996
|
...terminalAnchor ? { contextEngineTerminalAnchor: terminalAnchor } : {},
|
|
4421
4997
|
...settledTurnFinalizationContext ? { settledTurnFinalizationContext } : {},
|
|
4422
4998
|
...resourceState.runtimeArtifact ? { runtimeArtifact: resourceState.runtimeArtifact } : {},
|
|
4999
|
+
...resourceState.runtimeContinuationStarted ? { runtimeContinuationStarted: true } : {},
|
|
4423
5000
|
...!finalAborted && !effectiveTimedOut && !finalPromptError && preparedAuthBinding ? { authBindingFingerprint: preparedAuthBinding.fingerprint } : {},
|
|
4424
5001
|
systemPromptReport
|
|
4425
5002
|
};
|
|
@@ -4764,7 +5341,7 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
4764
5341
|
state.turnCrossedToolHandoff = notificationState.turnCrossedToolHandoff;
|
|
4765
5342
|
if (notificationState.isCurrentTurnNotification && notification.method === "item/completed") {
|
|
4766
5343
|
const item = readCodexNotificationItem(notification.params);
|
|
4767
|
-
if (item?.type === "userMessage" && typeof item.clientId === "string") steeringQueue?.confirmConsumed(item.clientId);
|
|
5344
|
+
if (item?.type === "userMessage" && typeof item.clientId === "string") await steeringQueue?.confirmConsumed(item.clientId);
|
|
4768
5345
|
}
|
|
4769
5346
|
if (notificationState.isTurnAbortMarker) state.sawCodexInterruptMarker = true;
|
|
4770
5347
|
const hookNotification = readCodexFinalizationHookNotification(notification, resourceState.thread.threadId, turnId);
|
|
@@ -4775,7 +5352,6 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
4775
5352
|
}
|
|
4776
5353
|
if (notificationState.isTurnTerminal) state.terminalTurnNotificationQueued = true;
|
|
4777
5354
|
try {
|
|
4778
|
-
await waitForCodexNotificationDispatchTurn();
|
|
4779
5355
|
await projector.handleNotification(notification);
|
|
4780
5356
|
const canRelease = isAssistantCompletionReleaseNotification(notification, state.turnCrossedToolHandoff) || notificationState.isCurrentTurnNotification && state.turnCrossedToolHandoff && notification.method === "rawResponseItem/completed" && projector.canReleaseLatestTerminalAssistantAfterToolHandoff();
|
|
4781
5357
|
if (notificationState.isCurrentTurnNotification && canRelease) {
|
|
@@ -4871,11 +5447,12 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
4871
5447
|
}
|
|
4872
5448
|
//#endregion
|
|
4873
5449
|
//#region extensions/codex/src/app-server/run-attempt-prompt.ts
|
|
5450
|
+
const CODEX_META_KEY = "__openclaw";
|
|
4874
5451
|
function isRestrictivePromptToolsAllow(toolsAllow) {
|
|
4875
5452
|
return toolsAllow !== void 0 && !toolsAllow.some((name) => name.trim() === "*");
|
|
4876
5453
|
}
|
|
4877
5454
|
async function prepareCodexAttemptPrompt(context) {
|
|
4878
|
-
const { runtime, attemptTools, historyState, hookContext, workspaceBootstrapContext, buildActiveContextEngineRuntimeContext, baseDeveloperInstructions, openClawPromptContext, skillsCollaborationInstructions, promptState, codexContextProjectionMaxChars } = context;
|
|
5455
|
+
const { runtime, attemptTools, historyState, hookContext, workspaceBootstrapContext, buildActiveContextEngineRuntimeContext, baseDeveloperInstructions, openClawPromptContext, skillsCollaborationInstructions, promptState, codexContextProjectionMaxChars, codexContinuityProjectionMaxChars } = context;
|
|
4879
5456
|
const { connection, buildActiveRunAttemptParams, effectiveContextTokenBudget, effectiveRuntimeModelId, effectiveRuntimeProviderId } = runtime;
|
|
4880
5457
|
const { params, activeContextEngine, usesSupervisionConnection, mutable, isInactiveThreadBootstrapBinding, bindingStore, bindingIdentity, agentDir, appServer, contextSessionKey, effectiveWorkspace, sandbox } = connection;
|
|
4881
5458
|
const { toolBridge } = attemptTools;
|
|
@@ -4884,11 +5461,12 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
4884
5461
|
assembledMessages: historyState.messages,
|
|
4885
5462
|
originalHistoryMessages: historyState.messages,
|
|
4886
5463
|
prompt: params.prompt,
|
|
4887
|
-
maxRenderedContextChars:
|
|
5464
|
+
maxRenderedContextChars: codexContinuityProjectionMaxChars
|
|
4888
5465
|
});
|
|
4889
5466
|
promptState.promptText = projection.promptText;
|
|
4890
5467
|
promptState.promptContextRange = projection.promptContextRange;
|
|
4891
5468
|
promptState.prePromptMessageCount = projection.prePromptMessageCount;
|
|
5469
|
+
promptState.noEngineContinuityProjectionApplied = true;
|
|
4892
5470
|
};
|
|
4893
5471
|
const applyActiveContextEngineProjection = async (decisionStartupBinding) => {
|
|
4894
5472
|
if (!activeContextEngine) return;
|
|
@@ -4962,15 +5540,21 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
4962
5540
|
}
|
|
4963
5541
|
const codexModelInputHistoryMessages = [];
|
|
4964
5542
|
const buildPromptFromCurrentInputs = async () => {
|
|
4965
|
-
|
|
5543
|
+
return await resolveAgentHarnessBeforePromptBuildResult({
|
|
4966
5544
|
prompt: prependCurrentInboundContext(promptState.promptText, params.currentInboundContext),
|
|
4967
|
-
developerInstructions:
|
|
5545
|
+
developerInstructions: { build: ({ toolsAllow }) => {
|
|
5546
|
+
if (isRestrictivePromptToolsAllow(toolsAllow)) throw new Error("Codex app-server cannot enforce before_prompt_build toolsAllow; use the embedded or Copilot runtime for turn-scoped tool policy.");
|
|
5547
|
+
return promptState.developerInstructions;
|
|
5548
|
+
} },
|
|
4968
5549
|
messages: structuredClone(historyState.messages),
|
|
4969
5550
|
ctx: hookContext,
|
|
4970
|
-
bootstrapContextRunKind: params.bootstrapContextRunKind
|
|
5551
|
+
bootstrapContextRunKind: params.bootstrapContextRunKind,
|
|
5552
|
+
toolAuthority: {
|
|
5553
|
+
fingerprint: params.toolAuthorityFingerprint,
|
|
5554
|
+
activeToolNames: () => flattenCodexDynamicToolFunctions(toolBridge.availableSpecs).map((tool) => tool.name).filter(isNonEmptyString),
|
|
5555
|
+
assertActive: params.hostCapabilities.assertActive
|
|
5556
|
+
}
|
|
4971
5557
|
});
|
|
4972
|
-
if (isRestrictivePromptToolsAllow(result.toolsAllow)) throw new Error("Codex app-server cannot enforce before_prompt_build toolsAllow; use the embedded or Copilot runtime for turn-scoped tool policy.");
|
|
4973
|
-
return result;
|
|
4974
5558
|
};
|
|
4975
5559
|
const resolveShiftedPromptInputRange = (prompt, promptInputRange, turnPromptText) => {
|
|
4976
5560
|
if (!promptInputRange || promptInputRange.start < 0 || promptInputRange.end < promptInputRange.start || promptInputRange.end > prompt.length || !turnPromptText.endsWith(prompt)) return;
|
|
@@ -5040,12 +5624,11 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
5040
5624
|
const cutoff = Date.parse(binding.historyCoveredThrough ?? "");
|
|
5041
5625
|
return historyState.messages.filter((message) => {
|
|
5042
5626
|
if (message.role !== "user" && message.role !== "assistant") return false;
|
|
5043
|
-
const
|
|
5044
|
-
const meta = record["__openclaw"];
|
|
5627
|
+
const meta = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
|
|
5045
5628
|
const mirrorIdentity = meta && typeof meta === "object" && !Array.isArray(meta) ? meta.mirrorIdentity : void 0;
|
|
5046
5629
|
const mirrorOrigin = meta && typeof meta === "object" && !Array.isArray(meta) ? meta.mirrorOrigin : void 0;
|
|
5047
5630
|
const timestamp = typeof message.timestamp === "number" ? message.timestamp : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
|
|
5048
|
-
return !(typeof
|
|
5631
|
+
return !("idempotencyKey" in message && typeof message.idempotencyKey === "string" && message.idempotencyKey.startsWith("codex-app-server:")) && mirrorOrigin !== "codex-app-server" && !(typeof mirrorIdentity === "string" && mirrorIdentity.startsWith("codex-app-server:")) && Number.isFinite(timestamp) && timestamp > (Number.isFinite(cutoff) ? cutoff : 0);
|
|
5049
5632
|
});
|
|
5050
5633
|
};
|
|
5051
5634
|
const applyResumeStaleBindingContinuityProjection = (binding) => {
|
|
@@ -5055,11 +5638,12 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
5055
5638
|
assembledMessages: newerVisibleMessages,
|
|
5056
5639
|
originalHistoryMessages: historyState.messages,
|
|
5057
5640
|
prompt: params.prompt,
|
|
5058
|
-
maxRenderedContextChars:
|
|
5641
|
+
maxRenderedContextChars: codexContinuityProjectionMaxChars
|
|
5059
5642
|
});
|
|
5060
5643
|
promptState.promptText = projection.promptText;
|
|
5061
5644
|
promptState.promptContextRange = projection.promptContextRange;
|
|
5062
5645
|
promptState.prePromptMessageCount = projection.prePromptMessageCount;
|
|
5646
|
+
promptState.noEngineContinuityProjectionApplied = true;
|
|
5063
5647
|
return true;
|
|
5064
5648
|
};
|
|
5065
5649
|
const precomputeNoContextEngineStaleBindingProjection = () => {
|
|
@@ -5171,15 +5755,13 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5171
5755
|
const { connection, hookChannelId } = runtime;
|
|
5172
5756
|
const { appServer, params, effectiveCwd, sessionAgentId, sandboxSessionKey, runAbortController, sandbox, options, nativeHookRelayEvents } = connection;
|
|
5173
5757
|
const { toolBridge } = attemptTools;
|
|
5174
|
-
const hostTrajectoryRecorder = params.trajectoryRecorder;
|
|
5175
5758
|
const trajectoryRecorder = createCodexTrajectoryRecorder({
|
|
5176
5759
|
attempt: params,
|
|
5177
5760
|
cwd: effectiveCwd,
|
|
5178
5761
|
developerInstructions: buildRenderedCodexDeveloperInstructions(),
|
|
5179
5762
|
prompt: turnState.codexTurnPromptText,
|
|
5180
|
-
|
|
5181
|
-
tools: toolBridge.availableSpecs
|
|
5182
|
-
warn: (message, fields) => embeddedAgentLog.warn(message, fields)
|
|
5763
|
+
trajectory: params.hostCapabilities.trajectory,
|
|
5764
|
+
tools: toolBridge.availableSpecs
|
|
5183
5765
|
});
|
|
5184
5766
|
const state = {
|
|
5185
5767
|
client: void 0,
|
|
@@ -5192,12 +5774,14 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5192
5774
|
trajectoryEndRecorded: false,
|
|
5193
5775
|
nativeHookRelay: void 0,
|
|
5194
5776
|
nativeSubagentMonitor: void 0,
|
|
5777
|
+
runtimeContinuationStarted: false,
|
|
5195
5778
|
nativePreToolUseFailureFallbackActive: false,
|
|
5196
5779
|
nativePreToolUseFailureFallbackTerminalReason: void 0,
|
|
5197
5780
|
releaseSharedClientLease: void 0,
|
|
5198
5781
|
startupClientUnsafe: false,
|
|
5199
5782
|
sharedCodexClientRetiredForOneShotCleanup: false,
|
|
5200
|
-
|
|
5783
|
+
sandboxExecEnvironment: void 0,
|
|
5784
|
+
executionDisconnectError: void 0,
|
|
5201
5785
|
codexEnvironmentSelection: void 0,
|
|
5202
5786
|
codexExecutionCwd: effectiveCwd,
|
|
5203
5787
|
codexSandboxPolicy: void 0,
|
|
@@ -5236,7 +5820,7 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5236
5820
|
if (params.cleanupBundleMcpOnRunEnd !== true || state.sharedCodexClientRetiredForOneShotCleanup) return;
|
|
5237
5821
|
state.sharedCodexClientRetiredForOneShotCleanup = true;
|
|
5238
5822
|
const retired = clearSharedCodexAppServerClientIfCurrentAndUnclaimed(state.client);
|
|
5239
|
-
embeddedAgentLog.
|
|
5823
|
+
embeddedAgentLog.debug("codex app-server one-shot cleanup checked shared client retirement", {
|
|
5240
5824
|
runId: params.runId,
|
|
5241
5825
|
sessionId: params.sessionId,
|
|
5242
5826
|
sessionKey: params.sessionKey,
|
|
@@ -5250,16 +5834,27 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5250
5834
|
forceKillDelayMs: 250
|
|
5251
5835
|
});
|
|
5252
5836
|
};
|
|
5837
|
+
const releaseSandboxExecEnvironment = async () => {
|
|
5838
|
+
if (state.sandboxExecEnvironment) {
|
|
5839
|
+
const environment = state.sandboxExecEnvironment;
|
|
5840
|
+
state.sandboxExecEnvironment = void 0;
|
|
5841
|
+
await releaseCodexSandboxExecServerEnvironment(sandbox, environment);
|
|
5842
|
+
}
|
|
5843
|
+
};
|
|
5253
5844
|
const releaseSharedClientLeaseAndRetireOneShotClient = async () => {
|
|
5845
|
+
if (connection.attemptClientFactory === createIsolatedCodexAppServerClient) {
|
|
5846
|
+
await releaseSandboxExecEnvironment();
|
|
5847
|
+
const ownedClient = state.releaseSharedClientLease ? state.client : void 0;
|
|
5848
|
+
releaseSharedClientLeaseOnce();
|
|
5849
|
+
await ownedClient?.closeAndWait({
|
|
5850
|
+
exitTimeoutMs: 2e3,
|
|
5851
|
+
forceKillDelayMs: 250
|
|
5852
|
+
});
|
|
5853
|
+
return;
|
|
5854
|
+
}
|
|
5254
5855
|
releaseSharedClientLeaseOnce();
|
|
5255
5856
|
await retireSharedCodexClientForOneShotCleanup();
|
|
5256
5857
|
};
|
|
5257
|
-
const releaseSandboxExecEnvironment = async () => {
|
|
5258
|
-
if (state.sandboxExecEnvironmentAcquired) {
|
|
5259
|
-
state.sandboxExecEnvironmentAcquired = false;
|
|
5260
|
-
await releaseCodexSandboxExecServerEnvironment(sandbox);
|
|
5261
|
-
}
|
|
5262
|
-
};
|
|
5263
5858
|
const runCleanupStep = (step, operation) => runAgentCleanupStep({
|
|
5264
5859
|
runId: params.runId,
|
|
5265
5860
|
sessionId: params.sessionId,
|
|
@@ -5284,7 +5879,10 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5284
5879
|
retainClient: () => retainSharedCodexAppServerClientIfCurrent(state.client),
|
|
5285
5880
|
retainParentThread: (protectedThreadId) => protectCodexAppServerLiveThread(state.client, protectedThreadId),
|
|
5286
5881
|
claimDirectChild: (childThreadId) => state.nativeHookRelay?.claimDirectChild(childThreadId),
|
|
5287
|
-
rejectPendingDirectChild: (childThreadId, reason) => state.nativeHookRelay?.rejectPendingDirectChild(childThreadId, reason)
|
|
5882
|
+
rejectPendingDirectChild: (childThreadId, reason) => state.nativeHookRelay?.rejectPendingDirectChild(childThreadId, reason),
|
|
5883
|
+
...params.sessionKey && params.agentHarnessTaskRuntimeScope ? { onDirectChildAccepted: () => {
|
|
5884
|
+
state.runtimeContinuationStarted = true;
|
|
5885
|
+
} } : {}
|
|
5288
5886
|
});
|
|
5289
5887
|
};
|
|
5290
5888
|
const releaseCurrentRoute = () => {
|
|
@@ -5347,8 +5945,7 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
5347
5945
|
configPatch: state.nativeHookRelay ? buildCodexNativeHookRelayConfig({
|
|
5348
5946
|
relay: state.nativeHookRelay,
|
|
5349
5947
|
events: nativeHookRelayEvents,
|
|
5350
|
-
hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec
|
|
5351
|
-
loopDetectionPreToolUseRelay: appServer.loopDetectionPreToolUseRelay
|
|
5948
|
+
hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec
|
|
5352
5949
|
}) : options.nativeHookRelay?.enabled === false ? buildCodexNativeHookRelayDisabledConfig() : void 0,
|
|
5353
5950
|
nativeHookRelayGeneration: state.nativeHookRelay?.generation
|
|
5354
5951
|
};
|
|
@@ -5480,10 +6077,6 @@ function resolveScheduledCodexAppCreatorCaptureDecision(params) {
|
|
|
5480
6077
|
...unavailableReason ? { unavailableReason } : {}
|
|
5481
6078
|
};
|
|
5482
6079
|
}
|
|
5483
|
-
function readConnectorId(tool) {
|
|
5484
|
-
const meta = asOptionalRecord(asOptionalRecord(tool)?.["_meta"]);
|
|
5485
|
-
return normalizeOptionalString(meta?.connector_id) ?? normalizeOptionalString(meta?.connectorId);
|
|
5486
|
-
}
|
|
5487
6080
|
function normalizeApprovalMode(value) {
|
|
5488
6081
|
return value === "allow" || value === "deny" || value === "auto" || value === "ask" ? value : void 0;
|
|
5489
6082
|
}
|
|
@@ -5550,7 +6143,7 @@ async function readCodexScheduledAppToolNamesByApp(params) {
|
|
|
5550
6143
|
if (!isJsonObject(status) || !isJsonObject(status.tools)) throw new Error("Codex scheduled app inventory contained an invalid server status");
|
|
5551
6144
|
if (status.name !== CODEX_APPS_MCP_SERVER) continue;
|
|
5552
6145
|
for (const [toolName, tool] of Object.entries(status.tools)) {
|
|
5553
|
-
const connectorId =
|
|
6146
|
+
const connectorId = readCodexMcpToolConnectorId(tool);
|
|
5554
6147
|
if (connectorId) {
|
|
5555
6148
|
const names = toolNamesByApp.get(connectorId) ?? /* @__PURE__ */ new Set();
|
|
5556
6149
|
names.add(toolName);
|
|
@@ -5783,8 +6376,8 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
5783
6376
|
const effectiveContextWindowInfo = usesSupervisionConnection ? void 0 : params.contextWindowInfo;
|
|
5784
6377
|
const effectiveContextTokenBudget = usesSupervisionConnection ? void 0 : params.contextTokenBudget;
|
|
5785
6378
|
const effectiveRuntimeProviderId = usesSupervisionConnection ? mutable.startupBinding?.modelProvider ?? "codex" : params.provider;
|
|
5786
|
-
const effectiveRuntimeModelId = usesSupervisionConnection ? mutable.startupBinding?.model ?? "codex-native" : params.modelId;
|
|
5787
|
-
const { authProfileId: _outerAuthProfileId, contextWindowInfo: _outerContextWindowInfo, contextTokenBudget: _outerContextTokenBudget, model: _outerModel, modelId: _outerModelId, provider: _outerProvider, runtimePlan: _outerRuntimePlan, requestedModelId: _outerRequestedModelId, fallbackReason: _outerFallbackReason, degradedReason: _outerDegradedReason, thinkLevel: _outerThinkLevel, fastMode: _outerFastMode, ...paramsWithoutOuterNativeOwnership } = params;
|
|
6379
|
+
const effectiveRuntimeModelId = usesSupervisionConnection ? mutable.startupBinding?.model ?? "codex-native" : connection.options.runtimeModelId ?? params.modelId;
|
|
6380
|
+
const { authProfileId: _outerAuthProfileId, authoredContextTokenCap: _outerAuthoredContextTokenCap, contextWindowInfo: _outerContextWindowInfo, contextTokenBudget: _outerContextTokenBudget, model: _outerModel, modelId: _outerModelId, provider: _outerProvider, runtimePlan: _outerRuntimePlan, requestedModelId: _outerRequestedModelId, fallbackReason: _outerFallbackReason, degradedReason: _outerDegradedReason, thinkLevel: _outerThinkLevel, fastMode: _outerFastMode, ...paramsWithoutOuterNativeOwnership } = params;
|
|
5788
6381
|
const supervisedRuntimeModel = {
|
|
5789
6382
|
id: effectiveRuntimeModelId,
|
|
5790
6383
|
name: effectiveRuntimeModelId,
|
|
@@ -6017,18 +6610,23 @@ function resolveCodexDynamicToolDirectNames(params, hostSystemAgentActive = fals
|
|
|
6017
6610
|
const names = [];
|
|
6018
6611
|
if (hostSystemAgentActive && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow)) names.push("openclaw");
|
|
6019
6612
|
if (params.sourceReplyDeliveryMode === "message_tool_only") names.push("message");
|
|
6020
|
-
|
|
6613
|
+
names.push("progress_card");
|
|
6021
6614
|
return names;
|
|
6022
6615
|
}
|
|
6023
6616
|
//#endregion
|
|
6024
6617
|
//#region extensions/codex/src/app-server/run-attempt-server-requests.ts
|
|
6618
|
+
const DYNAMIC_TOOL_TERMINAL_DIAGNOSTIC_TYPES = [
|
|
6619
|
+
"tool.execution.completed",
|
|
6620
|
+
"tool.execution.error",
|
|
6621
|
+
"tool.execution.blocked"
|
|
6622
|
+
];
|
|
6025
6623
|
function createCodexAttemptServerRequestController(resources, turnRuntime, lifecycle) {
|
|
6026
6624
|
const { prompt, state: resourceState, projectorRef, trajectoryRecorder } = resources;
|
|
6027
6625
|
const { context } = prompt;
|
|
6028
6626
|
const { runtime, attemptTools } = context;
|
|
6029
6627
|
const { connection } = runtime;
|
|
6030
|
-
const { params, computerUseConfig, runAbortController, appServer,
|
|
6031
|
-
const { toolBridge, toolOutcomeOrdinals, suppressedDynamicToolOutcomeOrdinals, allocateCodexToolOutcomeOrdinal } = attemptTools;
|
|
6628
|
+
const { params, computerUseConfig, runAbortController, appServer, sessionAgentId } = connection;
|
|
6629
|
+
const { compactionPlanState, toolBridge, toolOutcomeOrdinals, suppressedDynamicToolOutcomeOrdinals, allocateCodexToolOutcomeOrdinal } = attemptTools;
|
|
6032
6630
|
const { state, turnIdRef, userInputBridgeRef, openClawDynamicToolExecutions, pendingOpenClawDynamicToolCompletionIds, postToolRawAssistantCompletionIdleTimeoutMs, turnWatches } = turnRuntime;
|
|
6033
6631
|
const { emitExecutionPhaseOnce, scheduleTurnReleaseAfterTerminalDynamicTool, scheduleTerminalDynamicToolReleaseCheck } = lifecycle;
|
|
6034
6632
|
const handleServerRequest = async (request, scope, requestSignal = new AbortController().signal) => {
|
|
@@ -6054,7 +6652,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6054
6652
|
armCompletionWatchOnResponse = true;
|
|
6055
6653
|
markCurrentTurnRequestProgress();
|
|
6056
6654
|
}
|
|
6057
|
-
|
|
6655
|
+
const approvalResult = await routeCodexAppServerElicitationRequest({
|
|
6058
6656
|
requestParams: request.params,
|
|
6059
6657
|
paramsForRun: params,
|
|
6060
6658
|
threadId: resourceState.thread.threadId,
|
|
@@ -6063,6 +6661,11 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6063
6661
|
...computerUseConfig.enabled ? { computerUseMcpServerName: computerUseConfig.mcpServerName } : {},
|
|
6064
6662
|
signal
|
|
6065
6663
|
});
|
|
6664
|
+
if (approvalResult.kind === "handled") return approvalResult.response;
|
|
6665
|
+
return await userInputBridgeRef.current?.handleElicitationRequest({
|
|
6666
|
+
id: request.id,
|
|
6667
|
+
params: request.params
|
|
6668
|
+
});
|
|
6066
6669
|
}
|
|
6067
6670
|
if (request.method === "item/tool/requestUserInput") {
|
|
6068
6671
|
if (scope.turnId === turnId) {
|
|
@@ -6088,9 +6691,8 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6088
6691
|
turnId,
|
|
6089
6692
|
nativeHookRelay: resourceState.nativeHookRelay,
|
|
6090
6693
|
autoApprove: shouldAutoApproveCodexAppServerApprovals(appServer),
|
|
6091
|
-
autoApproveOpenClawToolPolicy: approvalPolicyPromotedForOpenClawToolPolicy,
|
|
6092
6694
|
signal,
|
|
6093
|
-
onNativeToolFailureDisposition: (itemId, disposition) => projector?.recordNativeToolApprovalFailure(itemId, disposition)
|
|
6695
|
+
onNativeToolFailureDisposition: (itemId, disposition, approvalKind) => projector?.recordNativeToolApprovalFailure(itemId, disposition, approvalKind)
|
|
6094
6696
|
});
|
|
6095
6697
|
}
|
|
6096
6698
|
return;
|
|
@@ -6126,13 +6728,6 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6126
6728
|
tool: call.tool,
|
|
6127
6729
|
toolCallId: call.callId
|
|
6128
6730
|
});
|
|
6129
|
-
emitDynamicToolStartedDiagnostic({
|
|
6130
|
-
call,
|
|
6131
|
-
agentId: sessionAgentId,
|
|
6132
|
-
runId: params.runId,
|
|
6133
|
-
sessionId: params.sessionId,
|
|
6134
|
-
sessionKey: params.sessionKey
|
|
6135
|
-
});
|
|
6136
6731
|
const toolMeta = inferCodexDynamicToolMeta(call, resolveCodexToolProgressDetailMode(params.toolProgressDetail));
|
|
6137
6732
|
const toolArgs = sanitizeCodexToolArguments(call.arguments);
|
|
6138
6733
|
const commandBearing = isCodexCommandBearingToolCall(call.tool, toolArgs);
|
|
@@ -6142,6 +6737,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6142
6737
|
data: {
|
|
6143
6738
|
phase: "start",
|
|
6144
6739
|
name: call.tool,
|
|
6740
|
+
itemId: call.callId,
|
|
6145
6741
|
toolCallId: call.callId,
|
|
6146
6742
|
...toolMeta ? { meta: toolMeta } : {},
|
|
6147
6743
|
...toolArgs ? { args: toolArgs } : {},
|
|
@@ -6162,30 +6758,43 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6162
6758
|
sessionId: params.sessionId,
|
|
6163
6759
|
sessionKey: params.sessionKey
|
|
6164
6760
|
})) terminalDiagnosticObserved = true;
|
|
6165
|
-
});
|
|
6761
|
+
}, { include: DYNAMIC_TOOL_TERMINAL_DIAGNOSTIC_TYPES });
|
|
6166
6762
|
try {
|
|
6167
|
-
const { execution } = openClawDynamicToolExecutions.claim(call, () =>
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6763
|
+
const { execution } = openClawDynamicToolExecutions.claim(call, async () => {
|
|
6764
|
+
await projector?.transcriptCheckpoint.flush();
|
|
6765
|
+
emitDynamicToolStartedDiagnostic({
|
|
6766
|
+
call,
|
|
6767
|
+
agentId: sessionAgentId,
|
|
6768
|
+
runId: params.runId,
|
|
6769
|
+
sessionId: params.sessionId,
|
|
6770
|
+
sessionKey: params.sessionKey
|
|
6771
|
+
});
|
|
6772
|
+
const response = await handleDynamicToolCallWithTimeout({
|
|
6773
|
+
call,
|
|
6774
|
+
toolBridge,
|
|
6775
|
+
signal,
|
|
6776
|
+
timeoutMs: dynamicToolTimeoutMs,
|
|
6777
|
+
toolMeta,
|
|
6778
|
+
toolCallOrdinal,
|
|
6779
|
+
onAgentToolResult: params.onAgentToolResult,
|
|
6780
|
+
observeToolTerminal: params.observeToolTerminal,
|
|
6781
|
+
onFallbackSelected: () => {
|
|
6782
|
+
if (toolCallOrdinal !== void 0) suppressedDynamicToolOutcomeOrdinals.add(toolCallOrdinal);
|
|
6783
|
+
},
|
|
6784
|
+
onTimeout: () => {
|
|
6785
|
+
trajectoryRecorder?.recordEvent("tool.timeout", {
|
|
6786
|
+
threadId: call.threadId,
|
|
6787
|
+
turnId: call.turnId,
|
|
6788
|
+
toolCallId: call.callId,
|
|
6789
|
+
name: call.tool,
|
|
6790
|
+
timeoutMs: dynamicToolTimeoutMs
|
|
6791
|
+
});
|
|
6792
|
+
}
|
|
6793
|
+
});
|
|
6794
|
+
recordCodexDynamicToolResult(projector, call, response, toCodexDynamicToolProtocolResponse(response));
|
|
6795
|
+
await projector?.transcriptCheckpoint.flush();
|
|
6796
|
+
return response;
|
|
6797
|
+
});
|
|
6189
6798
|
const response = await execution;
|
|
6190
6799
|
const protocolResponse = toCodexDynamicToolProtocolResponse(response);
|
|
6191
6800
|
if (!protocolResponse.success && toolCallOrdinal !== void 0) {
|
|
@@ -6208,8 +6817,11 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6208
6817
|
success: protocolResponse.success,
|
|
6209
6818
|
contentItems: protocolResponse.contentItems
|
|
6210
6819
|
});
|
|
6211
|
-
|
|
6212
|
-
|
|
6820
|
+
if (protocolResponse.success && call.tool === "progress_card") {
|
|
6821
|
+
const progressCardInput = response.executedArguments ?? call.arguments;
|
|
6822
|
+
await projector?.recordDynamicProgressCardUpdate(progressCardInput);
|
|
6823
|
+
compactionPlanState.recordProgressCardInput(progressCardInput);
|
|
6824
|
+
}
|
|
6213
6825
|
if (shouldEmitDynamicToolProgress) {
|
|
6214
6826
|
const progressResponse = toCodexDynamicToolProgressResponse(response, protocolResponse);
|
|
6215
6827
|
emitCodexAppServerEvent(params, {
|
|
@@ -6217,6 +6829,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6217
6829
|
data: {
|
|
6218
6830
|
phase: "result",
|
|
6219
6831
|
name: call.tool,
|
|
6832
|
+
itemId: call.callId,
|
|
6220
6833
|
toolCallId: call.callId,
|
|
6221
6834
|
...toolMeta ? { meta: toolMeta } : {},
|
|
6222
6835
|
...commandBearing ? { commandBearing: true } : {},
|
|
@@ -6289,6 +6902,20 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
6289
6902
|
return { handleServerRequest };
|
|
6290
6903
|
}
|
|
6291
6904
|
//#endregion
|
|
6905
|
+
//#region extensions/codex/src/app-server/attempt-runtime-artifact.ts
|
|
6906
|
+
async function verifyStartupArtifact(params) {
|
|
6907
|
+
if (!params.request) return;
|
|
6908
|
+
const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-DeBvleJw.js");
|
|
6909
|
+
const runtimeArtifact = readCodexAppServerClientRuntimeArtifact(params.client);
|
|
6910
|
+
const expected = params.request.expected;
|
|
6911
|
+
const matchesExpected = !expected || runtimeArtifact?.id === expected.id && runtimeArtifact.fingerprint === expected.fingerprint;
|
|
6912
|
+
if (!runtimeArtifact || !matchesExpected || !await validateCodexAppServerRuntimeArtifact(runtimeArtifact, params.signal)) {
|
|
6913
|
+
retireSharedCodexAppServerClientIfCurrent(params.client);
|
|
6914
|
+
throw new Error(expected ? "Codex app-server runtime artifact does not match verified inference" : "Codex app-server runtime artifact is unavailable or stale");
|
|
6915
|
+
}
|
|
6916
|
+
return runtimeArtifact;
|
|
6917
|
+
}
|
|
6918
|
+
//#endregion
|
|
6292
6919
|
//#region extensions/codex/src/app-server/computer-use-health.ts
|
|
6293
6920
|
const COMPUTER_USE_HEALTH_MONITOR_STATE = Symbol.for("openclaw.codexComputerUseHealthMonitorState");
|
|
6294
6921
|
function getComputerUseHealthMonitorState() {
|
|
@@ -6308,19 +6935,17 @@ function startCodexComputerUseHealthMonitor(params) {
|
|
|
6308
6935
|
}
|
|
6309
6936
|
const fingerprint = buildComputerUseHealthMonitorFingerprint(params.config);
|
|
6310
6937
|
const intervalMs = params.config.healthCheckIntervalMinutes * 6e4;
|
|
6311
|
-
if (existing?.fingerprint === fingerprint
|
|
6938
|
+
if (existing?.fingerprint === fingerprint) return {
|
|
6312
6939
|
started: false,
|
|
6313
6940
|
intervalMs,
|
|
6314
6941
|
reason: "already_started"
|
|
6315
6942
|
};
|
|
6316
6943
|
if (existing) clearComputerUseHealthMonitor(params.client, existing);
|
|
6317
|
-
const repairComputerUseMcpChildren = params.repairComputerUseMcpChildren ?? (() => killStaleComputerUseMcpChildren({ ancestorPid: params.client.getTransportPid() }));
|
|
6318
6944
|
const monitor = {
|
|
6319
6945
|
fingerprint,
|
|
6320
6946
|
intervalMs,
|
|
6321
|
-
repairComputerUseMcpChildren: params.repairComputerUseMcpChildren,
|
|
6322
6947
|
timer: setInterval(() => {
|
|
6323
|
-
runCodexComputerUseHealthProbe(params.client, params.config, monitor
|
|
6948
|
+
runCodexComputerUseHealthProbe(params.client, params.config, monitor);
|
|
6324
6949
|
}, intervalMs),
|
|
6325
6950
|
disposeCloseHandler: () => void 0,
|
|
6326
6951
|
running: false
|
|
@@ -6345,13 +6970,12 @@ function buildComputerUseHealthMonitorFingerprint(config) {
|
|
|
6345
6970
|
toolCallTimeoutMs: config.toolCallTimeoutMs
|
|
6346
6971
|
});
|
|
6347
6972
|
}
|
|
6348
|
-
async function runCodexComputerUseHealthProbe(client, config, monitor
|
|
6973
|
+
async function runCodexComputerUseHealthProbe(client, config, monitor) {
|
|
6349
6974
|
if (monitor.running) return;
|
|
6350
6975
|
monitor.running = true;
|
|
6351
6976
|
try {
|
|
6352
6977
|
const { liveTest, repair } = await runCodexComputerUseLiveTest({
|
|
6353
6978
|
config,
|
|
6354
|
-
repairComputerUseMcpChildren: options.repairComputerUseMcpChildren,
|
|
6355
6979
|
request: async (method, requestParams, requestOptions) => await client.request(method, requestParams, { timeoutMs: requestOptions?.timeoutMs ?? config.liveTestTimeoutMs })
|
|
6356
6980
|
});
|
|
6357
6981
|
if (!liveTest.ok) {
|
|
@@ -6364,10 +6988,7 @@ async function runCodexComputerUseHealthProbe(client, config, monitor, options)
|
|
|
6364
6988
|
});
|
|
6365
6989
|
return;
|
|
6366
6990
|
}
|
|
6367
|
-
if (repair?.
|
|
6368
|
-
mcpServerName: config.mcpServerName,
|
|
6369
|
-
killedPids: repair.killedPids
|
|
6370
|
-
});
|
|
6991
|
+
if (repair?.attempted && repair.warnings.length === 0) embeddedAgentLog.info("codex computer-use periodic health reloaded MCP servers", { mcpServerName: config.mcpServerName });
|
|
6371
6992
|
} catch (error) {
|
|
6372
6993
|
embeddedAgentLog.warn("codex computer-use periodic health probe crashed", {
|
|
6373
6994
|
mcpServerName: config.mcpServerName,
|
|
@@ -6462,6 +7083,7 @@ function createCodexPluginThreadConfigStartupProvider(params) {
|
|
|
6462
7083
|
build: async (buildOptions) => {
|
|
6463
7084
|
const config = await buildCodexPluginThreadConfigWithinDeadline({
|
|
6464
7085
|
...buildParams,
|
|
7086
|
+
threadId: buildOptions?.threadId,
|
|
6465
7087
|
appCache: appCache ?? defaultCodexAppInventoryCache,
|
|
6466
7088
|
metadataCache,
|
|
6467
7089
|
failClosedOnTimeout: Boolean(params.scheduledRuntimeAuthority),
|
|
@@ -6494,7 +7116,7 @@ function isCodexPluginThreadConfigTimeoutError(error) {
|
|
|
6494
7116
|
* Startup orchestration for Codex app-server attempts, including shared-client
|
|
6495
7117
|
* leasing, plugin thread config, sandbox environment, and thread lifecycle binding.
|
|
6496
7118
|
*/
|
|
6497
|
-
const
|
|
7119
|
+
const CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS = 3;
|
|
6498
7120
|
const CODEX_APP_SERVER_CONTEXT_RESTART_SELECTION_CHANGED = "CODEX_APP_SERVER_CONTEXT_RESTART_SELECTION_CHANGED";
|
|
6499
7121
|
/** True when a pre-write context restart must replay on the newly selected owner. */
|
|
6500
7122
|
function isCodexContextRestartSelectionChangedError(error) {
|
|
@@ -6575,24 +7197,19 @@ async function startCodexAttemptThread(params) {
|
|
|
6575
7197
|
startupClientLease = () => {
|
|
6576
7198
|
if (startupClientLeaseReleased) return;
|
|
6577
7199
|
startupClientLeaseReleased = true;
|
|
6578
|
-
|
|
7200
|
+
if (params.attemptClientFactory === createIsolatedCodexAppServerClient) activeStartupClient.close();
|
|
7201
|
+
else releaseLeasedSharedCodexAppServerClient(activeStartupClient);
|
|
6579
7202
|
};
|
|
6580
7203
|
releaseSharedClientLease = startupClientLease;
|
|
6581
7204
|
attemptedClient = activeStartupClient;
|
|
6582
7205
|
startupClientForAbandonedRequestCleanup = activeStartupClient;
|
|
6583
7206
|
if (startupAbandoned) throw new CodexAppServerStartupError("timed_out");
|
|
6584
7207
|
if (startupAbandonController.signal.aborted) throw new CodexAppServerStartupError("aborted");
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
const matchesExpected = !expected || Boolean(runtimeArtifact && runtimeArtifact.id === expected.id && runtimeArtifact.fingerprint === expected.fingerprint);
|
|
6591
|
-
if (!runtimeArtifact || !matchesExpected || !await validateCodexAppServerRuntimeArtifact(runtimeArtifact, startupAbandonController.signal)) {
|
|
6592
|
-
retireSharedCodexAppServerClientIfCurrent(activeStartupClient);
|
|
6593
|
-
throw new Error(expected ? "Codex app-server runtime artifact does not match verified inference" : "Codex app-server runtime artifact is unavailable or stale");
|
|
6594
|
-
}
|
|
6595
|
-
}
|
|
7208
|
+
const runtimeArtifact = await verifyStartupArtifact({
|
|
7209
|
+
client: activeStartupClient,
|
|
7210
|
+
request: params.runtimeArtifactRequest,
|
|
7211
|
+
signal: startupAbandonController.signal
|
|
7212
|
+
});
|
|
6596
7213
|
ensureCodexAppServerClientRuntime(activeStartupClient, {
|
|
6597
7214
|
agentDir: params.agentDir,
|
|
6598
7215
|
authProfileId: startupRuntimeAuthProfileId,
|
|
@@ -6611,7 +7228,7 @@ async function startCodexAttemptThread(params) {
|
|
|
6611
7228
|
signal: startupAbandonController.signal
|
|
6612
7229
|
});
|
|
6613
7230
|
} catch (error) {
|
|
6614
|
-
if (startupAbandonController.signal.aborted) throw error;
|
|
7231
|
+
if (startupAbandonController.signal.aborted || isCodexAppServerStartSelectionChangedError(error)) throw error;
|
|
6615
7232
|
throw new AgentHarnessPreflightError(`Codex Computer Use readiness failed: ${formatErrorMessage(error)}`, {
|
|
6616
7233
|
cause: error,
|
|
6617
7234
|
scope: "harness"
|
|
@@ -6625,7 +7242,8 @@ async function startCodexAttemptThread(params) {
|
|
|
6625
7242
|
accountId: params.startupAuthAccountCacheKey,
|
|
6626
7243
|
envApiKeyFingerprint: params.startupEnvApiKeyCacheKey,
|
|
6627
7244
|
appServerVersion: activeStartupClient.getServerVersion(),
|
|
6628
|
-
runtimeIdentity: startupRuntimeIdentity
|
|
7245
|
+
runtimeIdentity: startupRuntimeIdentity,
|
|
7246
|
+
desktopGenerationFingerprint: readCodexAppServerClientDesktopGenerationFingerprint(activeStartupClient)
|
|
6629
7247
|
});
|
|
6630
7248
|
const appServerRuntimeFingerprint = buildCodexAppServerRuntimeFingerprint({
|
|
6631
7249
|
appServer: params.appServer,
|
|
@@ -6652,7 +7270,7 @@ async function startCodexAttemptThread(params) {
|
|
|
6652
7270
|
const releaseStartupSandboxEnvironment = async () => {
|
|
6653
7271
|
if (startupSandboxEnvironmentAcquired) {
|
|
6654
7272
|
startupSandboxEnvironmentAcquired = false;
|
|
6655
|
-
await releaseCodexSandboxExecServerEnvironment(params.sandbox);
|
|
7273
|
+
await releaseCodexSandboxExecServerEnvironment(params.sandbox, startupSandboxEnvironment);
|
|
6656
7274
|
}
|
|
6657
7275
|
};
|
|
6658
7276
|
releaseStartupResourcesOnTimeout = releaseStartupSandboxEnvironment;
|
|
@@ -6665,9 +7283,11 @@ async function startCodexAttemptThread(params) {
|
|
|
6665
7283
|
startupSandboxEnvironment = sandboxEnvironmentRequired ? await ensureCodexSandboxExecServerEnvironment({
|
|
6666
7284
|
client: activeStartupClient,
|
|
6667
7285
|
sandbox: params.sandbox ?? null,
|
|
7286
|
+
runtime: params.runtime,
|
|
6668
7287
|
appServerStartOptions: params.appServer.start,
|
|
6669
7288
|
timeoutMs: params.appServer.requestTimeoutMs,
|
|
6670
|
-
signal: startupAbandonController.signal
|
|
7289
|
+
signal: AbortSignal.any([params.signal, startupAbandonController.signal]),
|
|
7290
|
+
onExecutionDisconnect: params.onExecutionDisconnect
|
|
6671
7291
|
}) : void 0;
|
|
6672
7292
|
startupSandboxEnvironmentAcquired = Boolean(startupSandboxEnvironment);
|
|
6673
7293
|
if (startupAbandonController.signal.aborted) {
|
|
@@ -6711,17 +7331,23 @@ async function startCodexAttemptThread(params) {
|
|
|
6711
7331
|
reserveResumeThread,
|
|
6712
7332
|
bindingStore: params.bindingStore,
|
|
6713
7333
|
params: params.buildAttemptParams(),
|
|
7334
|
+
runtimeModelId: params.runtimeModelId,
|
|
6714
7335
|
agentId: params.sessionAgentId,
|
|
7336
|
+
agentDir: params.agentDir,
|
|
6715
7337
|
cwd: startupExecutionCwd,
|
|
6716
7338
|
dynamicTools: params.dynamicTools,
|
|
6717
7339
|
persistentWebSearchAllowed: params.persistentWebSearchAllowed,
|
|
6718
7340
|
webSearchAllowed: params.webSearchAllowed,
|
|
6719
7341
|
appServer: pluginAppServer,
|
|
6720
7342
|
developerInstructions: params.developerInstructions,
|
|
7343
|
+
agentWorkspaceDeveloperInstructions: params.agentWorkspaceDeveloperInstructions,
|
|
6721
7344
|
config: threadConfig,
|
|
7345
|
+
shellEnvironment: params.shellEnvironment,
|
|
7346
|
+
disableLoginShell: params.disableLoginShell,
|
|
6722
7347
|
finalConfigPatch: params.finalConfigPatch,
|
|
6723
7348
|
buildFinalConfigPatch: params.buildFinalConfigPatch,
|
|
6724
7349
|
nativeHookRelayGeneration: params.nativeHookRelayGeneration,
|
|
7350
|
+
nativeHookRelayRequired: params.nativeHookRelayRequired,
|
|
6725
7351
|
nativeCodeModeEnabled: params.nativeToolSurfaceEnabled,
|
|
6726
7352
|
nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
|
|
6727
7353
|
nativeCodeModeOnlyEnabled: params.appServer.codeModeOnly,
|
|
@@ -6816,30 +7442,31 @@ async function startCodexAttemptThread(params) {
|
|
|
6816
7442
|
}
|
|
6817
7443
|
}
|
|
6818
7444
|
};
|
|
6819
|
-
for (let attempt = 1; attempt <=
|
|
7445
|
+
for (let attempt = 1; attempt <= CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS; attempt += 1) try {
|
|
6820
7446
|
return await startupAttempt();
|
|
6821
7447
|
} catch (error) {
|
|
6822
7448
|
const selectionChanged = isCodexAppServerStartSelectionChangedError(error);
|
|
6823
7449
|
if (startupAbandoned || params.signal.aborted || !selectionChanged && !isCodexAppServerConnectionClosedError(error)) throw error;
|
|
6824
|
-
const
|
|
6825
|
-
|
|
6826
|
-
if (
|
|
6827
|
-
if (attempt >= CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS) {
|
|
7450
|
+
const refreshedSharedClient = selectionChanged ? retireSharedCodexAppServerClientIfCurrent(attemptedClient) : clearSharedCodexAppServerClientIfCurrent(attemptedClient);
|
|
7451
|
+
if (startupClientForAbandonedRequestCleanup === attemptedClient) startupClientForAbandonedRequestCleanup = void 0;
|
|
7452
|
+
if (attempt >= CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS) {
|
|
6828
7453
|
embeddedAgentLog.warn(selectionChanged ? "codex app-server executable selection kept changing during startup; retries exhausted" : "codex app-server connection closed during startup; retries exhausted", {
|
|
6829
7454
|
attempt,
|
|
6830
|
-
maxAttempts:
|
|
7455
|
+
maxAttempts: CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS,
|
|
6831
7456
|
refreshedSharedClient,
|
|
6832
7457
|
error: formatErrorMessage(error)
|
|
6833
7458
|
});
|
|
6834
7459
|
throw error;
|
|
6835
7460
|
}
|
|
7461
|
+
const retryDelayMs = selectionChanged ? 0 : 1e3 * 2 ** (attempt - 1);
|
|
6836
7462
|
embeddedAgentLog.warn(selectionChanged ? "codex app-server executable selection changed during startup; restarting app-server and retrying" : "codex app-server connection closed during startup; restarting app-server and retrying", {
|
|
6837
7463
|
attempt,
|
|
6838
7464
|
nextAttempt: attempt + 1,
|
|
6839
|
-
maxAttempts:
|
|
7465
|
+
maxAttempts: CODEX_APP_SERVER_STARTUP_MAX_ATTEMPTS,
|
|
6840
7466
|
refreshedSharedClient,
|
|
6841
7467
|
error: formatErrorMessage(error)
|
|
6842
7468
|
});
|
|
7469
|
+
await sleepWithAbort(retryDelayMs, startupAbandonController.signal);
|
|
6843
7470
|
}
|
|
6844
7471
|
throw new Error("codex app-server startup retry loop exited unexpectedly");
|
|
6845
7472
|
}
|
|
@@ -6852,7 +7479,7 @@ async function startCodexAttemptThread(params) {
|
|
|
6852
7479
|
releaseSharedClientLease
|
|
6853
7480
|
};
|
|
6854
7481
|
} catch (error) {
|
|
6855
|
-
if (params.signal.aborted ||
|
|
7482
|
+
if (params.signal.aborted || isCodexAppServerStartupError(error)) {
|
|
6856
7483
|
releaseSharedClientLease?.();
|
|
6857
7484
|
releaseSharedClientLease = void 0;
|
|
6858
7485
|
await closeCodexStartupClientBestEffort(startupClientForAbandonedRequestCleanup);
|
|
@@ -6871,13 +7498,11 @@ async function startCodexAttemptThread(params) {
|
|
|
6871
7498
|
params.signal.removeEventListener("abort", abandonStartupAcquire);
|
|
6872
7499
|
}
|
|
6873
7500
|
}
|
|
6874
|
-
function shouldClearSharedClientAfterStartupAbandon(error) {
|
|
6875
|
-
return isCodexAppServerStartupError(error);
|
|
6876
|
-
}
|
|
6877
7501
|
function shouldClearSharedClientAfterStartupRace(error) {
|
|
6878
|
-
return
|
|
7502
|
+
return isCodexAppServerStartupError(error) || isCodexAppServerRequestTimeoutError(error);
|
|
6879
7503
|
}
|
|
6880
7504
|
function shouldClearSharedClientAfterStartupFailure(params) {
|
|
7505
|
+
if (isCodexAppServerOverloadError(params.error)) return false;
|
|
6881
7506
|
return isCodexAppServerBrokenPipeError(params.error) || !params.spawnedBy;
|
|
6882
7507
|
}
|
|
6883
7508
|
//#endregion
|
|
@@ -6886,11 +7511,12 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
6886
7511
|
const { prompt, state, trajectoryRecorder, activateNativePreToolUseFailureFallback, releaseSandboxExecEnvironment, releaseSharedClientLeaseAndRetireOneShotClient, releaseCurrentRoute, runCleanupStep, startupTimeoutMs, buildNativeHookRelayFinalConfigPatch } = resources;
|
|
6887
7512
|
const { context, turnState, buildRenderedCodexDeveloperInstructions, rebuildCodexTurnPromptTextFromCurrentProjection, applyNoContextEngineContinuityProjection } = prompt;
|
|
6888
7513
|
const { runtime, attemptTools, promptState } = context;
|
|
6889
|
-
const { connection, runtimeParams, preparedAuthBinding, buildActiveRunAttemptParams, startupAuthAccountCacheKey, startupEnvApiKeyCacheKey, bundleMcpThreadConfig, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, sandboxExecServerEnabled } = runtime;
|
|
7514
|
+
const { connection, runtimeParams, preparedAuthBinding, buildActiveRunAttemptParams, startupAuthAccountCacheKey, startupEnvApiKeyCacheKey, bundleMcpThreadConfig, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, effectiveRuntimeModelId, sandboxExecServerEnabled } = runtime;
|
|
6890
7515
|
const { toolBridge, toolState } = attemptTools;
|
|
6891
7516
|
const developerInstructions = joinPresentSections(turnState.promptBuild.developerInstructions, attemptTools.scheduledConfiguredMcp?.diagnosticNotice);
|
|
6892
7517
|
const { params, attemptClientFactory, bindingStore, appServer, pluginConfig, computerUseConfig, startupClientAuthProfileId, runtimeArtifactRequest, startupPreparedAuth, agentDir, sessionAgentId, effectiveWorkspace, effectiveCwd, sandbox, runAbortController, usesSupervisionConnection, resolveReviewerPolicyContext, resolveRuntimeOptionsForCurrentBinding, startupAuthProfileId, startupAuthRequirement, abortFromUpstream } = connection;
|
|
6893
7518
|
let pluginAppServer = withCodexAppServerFastModeServiceTier(appServer, runtimeParams);
|
|
7519
|
+
const loopDetectionEnabled = (sessionAgentId && params.config ? resolveAgentConfig$1(params.config, sessionAgentId)?.tools?.loopDetection?.enabled : void 0) ?? params.config?.tools?.loopDetection?.enabled ?? false;
|
|
6894
7520
|
try {
|
|
6895
7521
|
emitCodexAppServerEvent(params, {
|
|
6896
7522
|
stream: "codex_app_server.lifecycle",
|
|
@@ -6899,6 +7525,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
6899
7525
|
const startupResult = await startCodexAttemptThread({
|
|
6900
7526
|
attemptClientFactory,
|
|
6901
7527
|
bindingStore,
|
|
7528
|
+
runtime: connection.options.runtime,
|
|
6902
7529
|
appServer: pluginAppServer,
|
|
6903
7530
|
pluginConfig,
|
|
6904
7531
|
computerUseConfig,
|
|
@@ -6911,7 +7538,10 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
6911
7538
|
startupEnvApiKeyCacheKey,
|
|
6912
7539
|
agentDir,
|
|
6913
7540
|
config: params.config,
|
|
7541
|
+
shellEnvironment: connection.shellEnvironment,
|
|
7542
|
+
disableLoginShell: connection.disableLoginShell,
|
|
6914
7543
|
buildAttemptParams: buildActiveRunAttemptParams,
|
|
7544
|
+
...effectiveRuntimeModelId !== runtimeParams.modelId ? { runtimeModelId: effectiveRuntimeModelId } : {},
|
|
6915
7545
|
sessionAgentId,
|
|
6916
7546
|
effectiveWorkspace,
|
|
6917
7547
|
effectiveCwd,
|
|
@@ -6919,7 +7549,9 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
6919
7549
|
persistentWebSearchAllowed: toolState.persistentWebSearchAllowed,
|
|
6920
7550
|
webSearchAllowed: toolState.webSearchAllowed,
|
|
6921
7551
|
developerInstructions,
|
|
7552
|
+
agentWorkspaceDeveloperInstructions: context.agentWorkspaceDeveloperInstructions,
|
|
6922
7553
|
buildFinalConfigPatch: buildNativeHookRelayFinalConfigPatch,
|
|
7554
|
+
nativeHookRelayRequired: connection.options.nativeHookRelay?.enabled !== false && params.pluginHarnessToolPolicyRestricted !== true && connection.nativeHookRelayEvents.includes("pre_tool_use") && (hasBeforeToolCallPolicy() || appServer.loopDetectionPreToolUseRelay && Boolean(connection.sandboxSessionKey) && loopDetectionEnabled),
|
|
6923
7555
|
bundleMcpThreadConfig,
|
|
6924
7556
|
configuredMcpOwnershipVersion: attemptTools.configuredMcpOwnershipVersion,
|
|
6925
7557
|
nativeToolSurfaceEnabled,
|
|
@@ -6930,6 +7562,11 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
6930
7562
|
startupTimeoutMs,
|
|
6931
7563
|
signal: runAbortController.signal,
|
|
6932
7564
|
onStartupTimeout: () => runAbortController.abort("codex_startup_timeout"),
|
|
7565
|
+
onExecutionDisconnect: (error) => {
|
|
7566
|
+
state.executionDisconnectError = error;
|
|
7567
|
+
embeddedAgentLog.warn(error.message);
|
|
7568
|
+
runAbortController.abort("client_closed");
|
|
7569
|
+
},
|
|
6933
7570
|
spawnedBy: params.spawnedBy
|
|
6934
7571
|
});
|
|
6935
7572
|
state.client = startupResult.client;
|
|
@@ -6937,7 +7574,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
6937
7574
|
state.runtimeArtifact = startupResult.runtimeArtifact;
|
|
6938
7575
|
state.turnRouter = startupResult.turnRouter;
|
|
6939
7576
|
state.turnRoute = startupResult.turnRoute;
|
|
6940
|
-
state.
|
|
7577
|
+
state.sandboxExecEnvironment = startupResult.sandboxEnvironment;
|
|
6941
7578
|
state.releaseSharedClientLease = startupResult.releaseSharedClientLease;
|
|
6942
7579
|
state.restartContextEngineCodexThread = startupResult.restartContextEngineCodexThread;
|
|
6943
7580
|
pluginAppServer = startupResult.pluginAppServer;
|
|
@@ -7011,7 +7648,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
7011
7648
|
await runCleanupStep("codex-start-failure-sandbox-release", releaseSandboxExecEnvironment);
|
|
7012
7649
|
await runCleanupStep("codex-start-failure-shared-client-release", releaseSharedClientLeaseAndRetireOneShotClient);
|
|
7013
7650
|
await runCleanupStep("codex-start-failure-abort-listener", () => params.abortSignal?.removeEventListener("abort", abortFromUpstream));
|
|
7014
|
-
throw error;
|
|
7651
|
+
throw state.executionDisconnectError ?? error;
|
|
7015
7652
|
}
|
|
7016
7653
|
}
|
|
7017
7654
|
//#endregion
|
|
@@ -7021,7 +7658,7 @@ function isAuthorityResolutionOperationAbort(error, signal) {
|
|
|
7021
7658
|
}
|
|
7022
7659
|
async function prepareCodexAttemptTools(runtime) {
|
|
7023
7660
|
const { connection, bundleMcpThreadConfig, bundleManifestRegistry, runtimeParams, effectiveRuntimeModelId, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, hookChannelId, codexMcpToolOverrides, authenticatedScheduledMode, ownsScheduledConfiguredMcpSurface, canResolveScheduledConfiguredMcpCreatorAuthority } = runtime;
|
|
7024
|
-
const { params, preDynamicStartupStages, mutable, startupAuthProfileId, resolvedWorkspace, effectiveWorkspace, effectiveCwd, sandboxSessionKey, sandbox, runAbortController, sessionAgentId, pluginConfig, profilerEnabled, agentDir } = connection;
|
|
7661
|
+
const { params, preDynamicStartupStages, mutable, startupAuthProfileId, resolvedWorkspace, effectiveWorkspace, effectiveCwd, sandboxSessionKey, sandbox, sessionPermissionPolicy, runAbortController, sessionAgentId, pluginConfig, profilerEnabled, agentDir } = connection;
|
|
7025
7662
|
const preDynamicSummary = preDynamicStartupStages.snapshot();
|
|
7026
7663
|
if (shouldWarnCodexDynamicToolBuildStageSummary(preDynamicSummary)) embeddedAgentLog.warn(`codex app-server pre-dynamic startup timings runId=${params.runId} sessionId=${params.sessionId} totalMs=${preDynamicSummary.totalMs} stages=${formatCodexDynamicToolBuildStageSummary(preDynamicSummary)}`, {
|
|
7027
7664
|
runId: params.runId,
|
|
@@ -7035,6 +7672,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7035
7672
|
});
|
|
7036
7673
|
const toolState = {
|
|
7037
7674
|
yieldDetected: false,
|
|
7675
|
+
yieldAcknowledgment: void 0,
|
|
7038
7676
|
persistentWebSearchAllowed: void 0,
|
|
7039
7677
|
webSearchAllowed: false
|
|
7040
7678
|
};
|
|
@@ -7052,12 +7690,18 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7052
7690
|
if (toolCallId) toolOutcomeOrdinals.set(toolCallId, ordinal);
|
|
7053
7691
|
return ordinal;
|
|
7054
7692
|
} : void 0;
|
|
7055
|
-
const
|
|
7693
|
+
const compactionPlanState = new CodexCompactionPlanState();
|
|
7694
|
+
const dynamicToolParams = {
|
|
7056
7695
|
...runtimeParams,
|
|
7696
|
+
onAgentEvent: (event) => {
|
|
7697
|
+
compactionPlanState.record(event);
|
|
7698
|
+
return runtimeParams.onAgentEvent?.(event);
|
|
7699
|
+
},
|
|
7057
7700
|
...allocateCodexToolOutcomeOrdinal ? { allocateToolOutcomeOrdinal: allocateCodexToolOutcomeOrdinal } : {},
|
|
7058
7701
|
...onCodexToolOutcome ? { onToolOutcome: onCodexToolOutcome } : {}
|
|
7059
|
-
}
|
|
7702
|
+
};
|
|
7060
7703
|
const computerContextEpoch = { value: 0 };
|
|
7704
|
+
const runCleanups = [];
|
|
7061
7705
|
const cronCreatorToolAllowlist = [];
|
|
7062
7706
|
const cronCreatorToolAllowlistCaptureRef = {};
|
|
7063
7707
|
const scheduledAppAuthoritySourceRef = {};
|
|
@@ -7080,6 +7724,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7080
7724
|
let toolBridge;
|
|
7081
7725
|
let creatorAuthorityPromise;
|
|
7082
7726
|
let resolveCreatorAuthorityImpl;
|
|
7727
|
+
const runtimeYieldCompletionClaim = {};
|
|
7083
7728
|
const commonToolParams = {
|
|
7084
7729
|
params: dynamicToolParams,
|
|
7085
7730
|
resolvedWorkspace,
|
|
@@ -7087,6 +7732,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7087
7732
|
effectiveCwd,
|
|
7088
7733
|
sandboxSessionKey,
|
|
7089
7734
|
sandbox,
|
|
7735
|
+
sessionPermissionPolicy,
|
|
7090
7736
|
nativeToolSurfaceEnabled,
|
|
7091
7737
|
nativeProviderWebSearchSupport,
|
|
7092
7738
|
runAbortController,
|
|
@@ -7094,9 +7740,11 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7094
7740
|
pluginConfig,
|
|
7095
7741
|
profilerEnabled,
|
|
7096
7742
|
...params.cronCreatorAuthorityUnavailableReason === "queued-local-operator" && bundleMcpThreadConfig.staticServerNames.length > 0 ? { cronCreatorAuthorityUnavailableReason: "queued-local-operator-configured-mcp" } : {},
|
|
7097
|
-
onYieldDetected: () => {
|
|
7743
|
+
onYieldDetected: (acknowledgment) => {
|
|
7098
7744
|
toolState.yieldDetected = true;
|
|
7745
|
+
toolState.yieldAcknowledgment = acknowledgment;
|
|
7099
7746
|
},
|
|
7747
|
+
claimYieldCompletion: () => runtimeYieldCompletionClaim.current?.() ?? false,
|
|
7100
7748
|
onCodexAppServerEvent: (event) => {
|
|
7101
7749
|
emitCodexAppServerEvent(params, event);
|
|
7102
7750
|
},
|
|
@@ -7115,6 +7763,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7115
7763
|
};
|
|
7116
7764
|
const tools = await buildDynamicTools({
|
|
7117
7765
|
...commonToolParams,
|
|
7766
|
+
registerRunCleanup: (cleanup) => runCleanups.push(cleanup),
|
|
7118
7767
|
cronCreatorToolAllowlistRef: cronCreatorToolAllowlist,
|
|
7119
7768
|
cronCreatorToolAllowlistCaptureRef,
|
|
7120
7769
|
onPersistentWebSearchPolicyResolved: (allowed) => {
|
|
@@ -7333,13 +7982,16 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
7333
7982
|
cronCreatorToolAllowlistCaptureRef,
|
|
7334
7983
|
scheduledAppAuthoritySourceRef,
|
|
7335
7984
|
dynamicToolParams,
|
|
7985
|
+
compactionPlanState,
|
|
7336
7986
|
computerContextEpoch,
|
|
7987
|
+
runCleanups,
|
|
7337
7988
|
toolBridge,
|
|
7338
7989
|
toolState,
|
|
7339
7990
|
toolOutcomeOrdinals,
|
|
7340
7991
|
suppressedDynamicToolOutcomeOrdinals,
|
|
7341
7992
|
onCodexToolOutcome,
|
|
7342
|
-
allocateCodexToolOutcomeOrdinal
|
|
7993
|
+
allocateCodexToolOutcomeOrdinal,
|
|
7994
|
+
runtimeYieldCompletionClaim
|
|
7343
7995
|
};
|
|
7344
7996
|
} catch (error) {
|
|
7345
7997
|
await scopedMcpTools?.dispose();
|
|
@@ -7457,7 +8109,7 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
|
|
|
7457
8109
|
data: {
|
|
7458
8110
|
phase: "turn_starting",
|
|
7459
8111
|
threadId: resourceState.thread.threadId,
|
|
7460
|
-
model:
|
|
8112
|
+
model: params.modelId,
|
|
7461
8113
|
effort: turnStartParams.effort,
|
|
7462
8114
|
collaborationEffort: turnStartParams.collaborationMode?.settings.reasoning_effort,
|
|
7463
8115
|
serviceTier: turnStartParams.serviceTier
|
|
@@ -7814,8 +8466,10 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
7814
8466
|
function scheduleAttemptIdleWatch() {
|
|
7815
8467
|
scheduleWatch("attempt", fireAttemptIdleTimeout, attemptLastProgressAt, attemptIdleTimeoutOverrideMs ?? turnAttemptIdleTimeoutMs, attemptIdleWatchArmed && !shouldPauseAttemptIdleWatch());
|
|
7816
8468
|
}
|
|
8469
|
+
const terminalWorkIsActive = () => params.getActiveAppServerTurnRequests() > 0 || params.isTerminalTurnNotificationQueued() && params.getActiveFinalizationHookCount() > 0;
|
|
8470
|
+
const terminalIdleTimeoutMs = () => params.isTerminalTurnNotificationQueued() && !terminalWorkIsActive() ? Math.min(TURN_TERMINAL_SETTLEMENT_IDLE_TIMEOUT_MS, turnTerminalIdleTimeoutMs) : turnTerminalIdleTimeoutMs;
|
|
7817
8471
|
function scheduleTerminalIdleWatch() {
|
|
7818
|
-
scheduleWatch("terminal", fireTerminalIdleTimeout, completionLastActivityAt,
|
|
8472
|
+
scheduleWatch("terminal", fireTerminalIdleTimeout, completionLastActivityAt, terminalIdleTimeoutMs(), terminalIdleWatchArmed && (params.isTerminalTurnNotificationQueued() || params.getActiveAppServerTurnRequests() === 0));
|
|
7819
8473
|
}
|
|
7820
8474
|
function scheduleProgressWatches() {
|
|
7821
8475
|
scheduleAttemptIdleWatch();
|
|
@@ -7936,18 +8590,26 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
7936
8590
|
});
|
|
7937
8591
|
}
|
|
7938
8592
|
function fireTerminalIdleTimeout() {
|
|
7939
|
-
if (params.isCompleted() || params.
|
|
8593
|
+
if (params.isCompleted() || params.signal.aborted || !terminalIdleWatchArmed) return;
|
|
8594
|
+
if (!params.isTerminalTurnNotificationQueued() && params.getActiveAppServerTurnRequests() > 0) {
|
|
8595
|
+
scheduleTerminalIdleWatch();
|
|
8596
|
+
return;
|
|
8597
|
+
}
|
|
8598
|
+
const timeoutMs = terminalIdleTimeoutMs();
|
|
7940
8599
|
const idleMs = Math.max(0, Date.now() - completionLastActivityAt);
|
|
7941
|
-
if (idleMs <
|
|
8600
|
+
if (idleMs < timeoutMs) {
|
|
7942
8601
|
scheduleTerminalIdleWatch();
|
|
7943
8602
|
return;
|
|
7944
8603
|
}
|
|
7945
8604
|
reportTimeout({
|
|
7946
8605
|
kind: "terminal",
|
|
7947
8606
|
idleMs,
|
|
7948
|
-
timeoutMs
|
|
8607
|
+
timeoutMs,
|
|
7949
8608
|
lastActivityReason: completionLastActivityReason,
|
|
7950
|
-
details:
|
|
8609
|
+
details: {
|
|
8610
|
+
...completionLastActivityDetails,
|
|
8611
|
+
terminalTurnNotificationQueued: params.isTerminalTurnNotificationQueued()
|
|
8612
|
+
}
|
|
7951
8613
|
});
|
|
7952
8614
|
}
|
|
7953
8615
|
return {
|
|
@@ -8004,6 +8666,7 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
8004
8666
|
completionLastActivityReason = `notification:${method}`;
|
|
8005
8667
|
if (options?.details !== void 0) completionLastActivityDetails = options.details;
|
|
8006
8668
|
if (options?.attemptProgress) recordAttemptProgress(completionLastActivityReason, options);
|
|
8669
|
+
if (params.isTerminalTurnNotificationQueued()) scheduleTerminalIdleWatch();
|
|
8007
8670
|
},
|
|
8008
8671
|
extendAttemptIdleWatch: (timeoutMs) => {
|
|
8009
8672
|
attemptIdleTimeoutOverrideMs = resolveWatchTimeoutMs(timeoutMs);
|
|
@@ -8026,6 +8689,7 @@ function createCodexAttemptTurnState(resources) {
|
|
|
8026
8689
|
latestStartupErrorNotification: void 0,
|
|
8027
8690
|
rateLimitsRevisionBeforeLastTurnStart: void 0,
|
|
8028
8691
|
completed: false,
|
|
8692
|
+
abortCleanup: Promise.resolve(),
|
|
8029
8693
|
localCompletionRequested: false,
|
|
8030
8694
|
terminalTurnNotificationQueued: false,
|
|
8031
8695
|
sawCodexInterruptMarker: false,
|
|
@@ -8179,11 +8843,14 @@ function createCodexAttemptTurnState(resources) {
|
|
|
8179
8843
|
//#endregion
|
|
8180
8844
|
//#region extensions/codex/src/app-server/run-attempt.ts
|
|
8181
8845
|
async function runCodexAppServerAttempt(params, options) {
|
|
8182
|
-
const
|
|
8846
|
+
const connection = await prepareCodexAttemptConnection({
|
|
8183
8847
|
params,
|
|
8184
8848
|
options
|
|
8185
|
-
})
|
|
8186
|
-
const
|
|
8849
|
+
});
|
|
8850
|
+
const runtime = await prepareCodexAttemptRuntime(connection);
|
|
8851
|
+
const attemptTools = await prepareCodexAttemptTools(runtime);
|
|
8852
|
+
const resources = prepareCodexAttemptResources(await prepareCodexAttemptPrompt(await prepareCodexAttemptContext(runtime, attemptTools)));
|
|
8853
|
+
attemptTools.runtimeYieldCompletionClaim.current = () => resources.state.nativeHookRelay?.hasClaimedDirectChild() ?? false;
|
|
8187
8854
|
await startCodexAttemptRuntime(resources);
|
|
8188
8855
|
const turnRuntime = createCodexAttemptTurnState(resources);
|
|
8189
8856
|
const lifecycle = createCodexAttemptLifecycleController(resources, turnRuntime);
|
|
@@ -8193,11 +8860,14 @@ async function runCodexAppServerAttempt(params, options) {
|
|
|
8193
8860
|
const turnStart = await startCodexAttemptTurn(resources, turnRuntime, notifications, turnRequest);
|
|
8194
8861
|
if ("result" in turnStart) return turnStart.result;
|
|
8195
8862
|
const activeTurn = await activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notifications, turnStart.turn);
|
|
8863
|
+
let finalizedResult;
|
|
8196
8864
|
try {
|
|
8197
|
-
|
|
8865
|
+
finalizedResult = await finalizeCodexAttempt(resources, turnRuntime, lifecycle, notifications, turnRequest, activeTurn);
|
|
8198
8866
|
} finally {
|
|
8199
8867
|
await cleanupCodexAttempt(resources, turnRuntime, lifecycle, turnRequest, activeTurn);
|
|
8200
8868
|
}
|
|
8869
|
+
if (resources.state.executionDisconnectError && !connection.terminalState.explicitCancellationObserved) throw resources.state.executionDisconnectError;
|
|
8870
|
+
return finalizedResult;
|
|
8201
8871
|
}
|
|
8202
8872
|
//#endregion
|
|
8203
8873
|
export { runCodexAppServerAttempt };
|