@openclaw/codex 2026.7.2-beta.1 → 2026.7.2-beta.2
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/README.md +1 -1
- package/dist/{app-server-policy-DVcxdse_.js → app-server-policy-Scc-Wevo.js} +1 -1
- package/dist/{attempt-notifications-DEv9h7iC.js → attempt-notifications-BFmNhqFl.js} +3 -6
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-D6ZlGNmb.js → command-formatters-Dq9InZUK.js} +34 -3
- package/dist/{command-handlers-Cpl9fUWv.js → command-handlers-IgqmL_kv.js} +10 -13
- package/dist/{compact-FnJmiPNA.js → compact-DCTmg3id.js} +4 -5
- package/dist/{computer-use-DVzr8OP1.js → computer-use-CPcU8TjG.js} +4 -4
- package/dist/{conversation-control-DtQ-E7mr.js → conversation-control-CGkBlfc5.js} +5 -7
- package/dist/doctor-contract-api.js +1 -1
- package/dist/{dynamic-tools-BMLoaTeG.js → dynamic-tools-C_1tEs34.js} +608 -330
- package/dist/harness.js +9 -5
- package/dist/index.js +52 -31
- package/dist/{media-understanding-provider-D580L0P8.js → media-understanding-provider-D31dOJwb.js} +11 -12
- package/dist/media-understanding-provider.js +1 -1
- package/dist/{models-DuKzZA6G.js → models-uh26C8QU.js} +5 -9
- package/dist/{notification-correlation-DfaCm0mx.js → notification-correlation-KmfV4EkP.js} +3 -3
- package/dist/{plugin-app-cache-key-BKNjHMEs.js → plugin-app-cache-key-Ceb-lm2c.js} +2 -2
- package/dist/{rate-limits-Dhp04Rqo.js → rate-limits-DyXaYAxU.js} +7 -6
- package/dist/{request-DborTWgw.js → request-B_oQsCXy.js} +54 -8
- package/dist/{run-attempt-VPVJoYDP.js → run-attempt-MLzoMe_m.js} +499 -295
- package/dist/{config-c48K5HP9.js → session-binding-h1mmCGnl.js} +786 -3
- package/dist/{session-catalog-7H112Tr_.js → session-catalog-CEvoXWHA.js} +45 -29
- package/dist/{session-cli-B28RhCyp.js → session-cli-XsEuWb_C.js} +1 -1
- package/dist/{shared-client-D4mFI9al.js → shared-client-JiAnW6pc.js} +255 -81
- package/dist/{side-question-CgJBz52s.js → side-question-DqDvIwSU.js} +15 -13
- package/dist/{thread-lifecycle-BgLXzjvV.js → thread-lifecycle-CN_pPtPh.js} +1787 -1579
- package/dist/{protocol-validators-dZQ-UTOa.js → transcript-mirror-D9rTxx2P.js} +485 -2
- package/dist/usage-D5Rohxoc.js +25 -0
- package/dist/{web-search-provider.runtime-Bs-eTn5U.js → web-search-provider.runtime-CKVBn3fP.js} +3 -3
- package/npm-shrinkwrap.json +30 -30
- package/openclaw.plugin.json +10 -5
- package/package.json +6 -6
- package/dist/capabilities-42Dfn2TV.js +0 -33
- package/dist/prompt-overlay.js +0 -15
- package/dist/protocol-BMifTfdW.js +0 -15
- package/dist/provider-catalog.js +0 -118
- package/dist/provider-discovery.js +0 -34
- package/dist/provider.js +0 -307
- package/dist/session-binding-BMfX1OX-.js +0 -786
- package/dist/transcript-mirror-DhLwFIL4.js +0 -485
|
@@ -1,26 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { S as updateActiveTurnItemIds, _ as readCodexNotificationItem, a as isCodexTurnAbortMarkerNotification, b as shouldDisarmAssistantCompletionIdleWatch, c as isPendingOpenClawDynamicToolCompletionNotification, d as isRawReasoningCompletionNotification, f as isRawToolOutputCompletionNotification, g as isTerminalTurnStatus, h as isRetryableErrorNotification, i as isAssistantCompletionReleaseNotification, l as isRawAssistantProgressNotification, m as isReasoningProgressNotification, n as describeNotificationActivity, o as isFileChangePatchUpdatedNotification, p as isReasoningItemCompletionNotification, r as isAssistantCommentaryCompletionNotification, s as isNativeToolProgressNotification, t as codexExecutionToolName, u as isRawFunctionToolOutputCompletionNotification, v as readNotificationItemId, x as updateActiveCompletionBlockerItemIds, y as readRawResponseToolCallId } from "./attempt-notifications-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { i as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-
|
|
6
|
-
import { A as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { a as
|
|
10
|
-
import { i as mirrorPromptAtTurnStartBestEffort, n as createCodexAppServerUserMessagePersistenceNotifier, o as buildCodexUserPromptMessage, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-DhLwFIL4.js";
|
|
11
|
-
import { t as CODEX_CONTROL_METHODS } from "./capabilities-42Dfn2TV.js";
|
|
12
|
-
import { r as formatCodexDisplayText } from "./command-formatters-D6ZlGNmb.js";
|
|
13
|
-
import { n as resolveCodexAppServerForOpenClawToolPolicy, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-DVcxdse_.js";
|
|
14
|
-
import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId, t as isCodexNotificationForTurn } from "./notification-correlation-DfaCm0mx.js";
|
|
1
|
+
import { A as isCodexAppServerStartupError, B as isCodexAppServerApprovalRequest, C as resolveCodexAppServerFallbackApiKeyCacheKey, D as resolveCodexAppServerHomeDir, F as resolveCodexTurnCompletionIdleTimeoutMs, H as isCodexAppServerConnectionClosedError, I as resolveCodexTurnTerminalIdleTimeoutMs, K as isCodexAppServerRequestTimeoutError, L as withCodexStartupTimeout, M as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, N as resolveCodexStartupTimeoutMs, O as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, P as resolveCodexTurnAssistantCompletionIdleTimeoutMs, R as CodexAppServerRpcError, S as resolveCodexAppServerAuthProfileIdForAgent, T as resolveCodexAppServerPreparedAuthHandoff, V as isCodexAppServerBrokenPipeError, X as flattenCodexDynamicToolFunctions, Z as isJsonObject, _ as readCodexRateLimitsRevision, a as getLeasedSharedCodexAppServerClient, b as resolveCodexAppServerAuthAccountCacheKey, c as releaseLeasedSharedCodexAppServerClient, d as retireSharedCodexAppServerClientIfCurrent, g as ensureCodexAppServerClientRuntime, k as CodexAppServerStartupError, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as isCodexAppServerStartSelectionChangedError, t as clearSharedCodexAppServerClientIfCurrent, u as retainSharedCodexAppServerClientIfCurrent, v as readRecentCodexRateLimits, w as resolveCodexAppServerPreparedApiKeyCacheKey, x as resolveCodexAppServerAuthProfileId } from "./shared-client-JiAnW6pc.js";
|
|
2
|
+
import { S as updateActiveTurnItemIds, _ as readCodexNotificationItem, a as isCodexTurnAbortMarkerNotification, b as shouldDisarmAssistantCompletionIdleWatch, c as isPendingOpenClawDynamicToolCompletionNotification, d as isRawReasoningCompletionNotification, f as isRawToolOutputCompletionNotification, g as isTerminalTurnStatus, h as isRetryableErrorNotification, i as isAssistantCompletionReleaseNotification, l as isRawAssistantProgressNotification, m as isReasoningProgressNotification, n as describeNotificationActivity, o as isFileChangePatchUpdatedNotification, p as isReasoningItemCompletionNotification, r as isAssistantCommentaryCompletionNotification, s as isNativeToolProgressNotification, t as codexExecutionToolName, u as isRawFunctionToolOutputCompletionNotification, v as readNotificationItemId, x as updateActiveCompletionBlockerItemIds, y as readRawResponseToolCallId } from "./attempt-notifications-BFmNhqFl.js";
|
|
3
|
+
import { C as resolveCodexComputerUseConfig, D as resolveOpenClawExecPolicyForCodexAppServer, O as shouldAutoApproveCodexAppServerApprovals, T as resolveCodexPluginsPolicy, c as sessionBindingIdentity, g as isCodexAppServerApprovalPolicyAllowedByRequirements, k as withMcpElicitationsApprovalPolicy, s as reclaimCurrentCodexSessionGeneration, v as isCodexSandboxExecServerEnabled, w as resolveCodexModelBackedReviewerPolicyContext, y as readCodexPluginConfig } from "./session-binding-h1mmCGnl.js";
|
|
4
|
+
import { _ as readCodexTurnCompletedNotification, f as assertCodexTurnStartResponse, i as mirrorPromptAtTurnStartBestEffort, n as createCodexAppServerUserMessagePersistenceNotifier, o as buildCodexUserPromptMessage, p as readCodexDynamicToolCallParams, t as codexTranscriptMirrorRuntime } from "./transcript-mirror-D9rTxx2P.js";
|
|
5
|
+
import { i as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-Ceb-lm2c.js";
|
|
6
|
+
import { A as CodexAppServerUnsafeSubscriptionError, B as fitCodexProjectedContextForTurnStart, D as resolveCodexDynamicToolsLoadingForRuntime, F as areCodexDynamicToolFingerprintsCompatible, G as buildCodexPluginThreadConfig, H as resolveCodexContextEngineProjectionMaxChars, I as codexDynamicToolsFingerprint, J as mergeCodexThreadConfigs, K as buildCodexPluginThreadConfigInputFingerprint, L as codexLegacyDynamicToolsFingerprint, M as interruptCodexTurnBestEffort, N as retireCodexAppServerClientAfterTimedOutTurn, O as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS, P as unsubscribeCodexThreadBestEffort, Q as resolveRecoverableCodexPluginConfigKeys, R as buildContextEngineBinding, U as resolveCodexContextEngineProjectionReserveTokens, V as projectContextEngineAssemblyForCodex, Y as shouldBuildCodexPluginThreadConfig, b as isCodexAppServerProfilerEnabled, d as resolveCodexWebSearchPlan, f as buildDeveloperInstructions, g as resolveCodexAppServerThreadModelSelection, j as closeCodexStartupClientBestEffort, k as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, n as buildTurnStartParams, q as buildCodexPluginThreadConfigTimeoutFallback, r as buildCodexUserInput, s as startOrResumeThread, t as buildTurnCollaborationMode, w as isSystemAgentOnlyCodexDynamicToolAllowlist, x as filterCodexDynamicTools, z as isContextEngineBindingCompatible } from "./thread-lifecycle-CN_pPtPh.js";
|
|
7
|
+
import { r as formatCodexDisplayText } from "./command-formatters-Dq9InZUK.js";
|
|
8
|
+
import { n as resolveCodexAppServerForOpenClawToolPolicy, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-Scc-Wevo.js";
|
|
9
|
+
import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId, t as isCodexNotificationForTurn } from "./notification-correlation-KmfV4EkP.js";
|
|
15
10
|
import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-C1czuHPA.js";
|
|
16
|
-
import { $ as
|
|
17
|
-
import { a as runCodexComputerUseLiveTest, r as killStaleComputerUseMcpChildren, t as ensureCodexComputerUse } from "./computer-use-
|
|
11
|
+
import { $ as resolveCodexToolProgressDetailMode, B as hasPendingDynamicToolTerminalDiagnostic, C as CodexAppServerEventProjector, D as markCodexAuthProfileBlockedFromRateLimits, E as isCodexUsageLimitPromptError, F as emitCodexNativePreToolUseFailureDiagnostic, G as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult, H as isMatchingDynamicToolTerminalDiagnostic, I as resolveCodexNativeHookRelayEvents, J as toCodexDynamicToolProtocolResponse, K as shouldReleaseTurnAfterTerminalDynamicTool, L as resolveCodexNativeHookRelayTtlMs, M as buildCodexNativeHookRelayConfig, N as buildCodexNativeHookRelayDisabledConfig, O as refreshCodexUsageLimitPromptError, P as createCodexNativeHookRelay, Q as inferCodexDynamicToolMeta, R as scheduleCodexNativeHookRelayUnregister, T as formatCodexTurnStartUsageLimitError, U as resolveDynamicToolCallTimeoutMs, V as isDynamicToolTerminalDiagnosticEvent, W as resolveTerminalDynamicToolBatchAction, X as readCodexMirroredSessionHistoryMessages, Y as resolveCodexToolAbortTerminalReason, Z as shouldEmitTranscriptToolProgress, _ as resolveCodexMessageToolProvider, a as emitDynamicToolStartedDiagnostic, b as shouldRequireCodexSandboxExecServerEnvironment, d as createCodexDynamicToolBuildStageTracker, et as sanitizeCodexToolArguments, f as disableCodexPluginThreadConfig, g as resolveCodexExternalSandboxPolicyForOpenClawSandbox, h as resolveCodexAppServerHookChannelId, i as emitDynamicToolErrorDiagnostic, j as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, l as settleCodexSourceReplyFinality, m as resolveCodexAppServerExecutionCwd, n as handleCodexAppServerApprovalRequest, nt as resolveCodexLocalRuntimeAttribution, o as emitDynamicToolTerminalDiagnostic, p as formatCodexDynamicToolBuildStageSummary, q as toCodexDynamicToolProgressResponse, r as handleCodexAppServerElicitationRequest, s as resolveCodexProviderWebSearchSupport, t as createCodexDynamicToolBridge, tt as sanitizeCodexToolResponse, u as buildDynamicTools, v as resolveCodexSandboxEnvironmentSelection, w as createCodexUsageLimitPromptError, x as shouldWarnCodexDynamicToolBuildStageSummary, y as shouldEnableCodexAppServerNativeToolSurface, z as handleDynamicToolCallWithTimeout } from "./dynamic-tools-C_1tEs34.js";
|
|
12
|
+
import { a as runCodexComputerUseLiveTest, r as killStaleComputerUseMcpChildren, t as ensureCodexComputerUse } from "./computer-use-CPcU8TjG.js";
|
|
18
13
|
import fs from "node:fs/promises";
|
|
19
14
|
import path, { posix } from "node:path";
|
|
20
15
|
import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
21
|
-
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
16
|
+
import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
22
17
|
import { createHash, randomUUID } from "node:crypto";
|
|
23
|
-
import {
|
|
18
|
+
import { resolveAgentDir, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
|
|
24
19
|
import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
25
20
|
import { asFiniteNumber, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
26
21
|
import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildAgentHarnessUserInputAnswers, buildBootstrapContextForFiles, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, clearActiveEmbeddedRun, deliverAgentHarnessUserInputPrompt, embeddedAgentLog, emitAgentEvent, emptyAgentHarnessUserInputAnswers, finalizeHarnessContextEngineTurn, formatErrorMessage, formatFastModeAutoProgressText, getAgentHarnessHookRunner, getBeforeToolCallPolicyDiagnosticState, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, resolveAgentDir as resolveAgentDir$1, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds as resolveSessionAgentIds$1, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
@@ -29,103 +24,171 @@ import { once } from "node:events";
|
|
|
29
24
|
import { isIP } from "node:net";
|
|
30
25
|
import { WebSocketServer } from "ws";
|
|
31
26
|
import { parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
|
|
32
|
-
import {
|
|
27
|
+
import { fileURLToPath } from "node:url";
|
|
33
28
|
import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
29
|
+
import { buildMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
|
|
34
30
|
import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
|
|
35
31
|
import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
|
|
36
32
|
import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
37
33
|
//#region extensions/codex/src/app-server/attempt-steering.ts
|
|
38
34
|
/**
|
|
39
|
-
* Debounced steering queue for forwarding user
|
|
35
|
+
* Debounced steering queue for forwarding user messages to an active Codex
|
|
40
36
|
* app-server turn.
|
|
41
37
|
*/
|
|
42
38
|
const CODEX_STEER_ALL_DEBOUNCE_MS = 500;
|
|
43
39
|
/**
|
|
44
|
-
* Creates a queue that batches steer
|
|
45
|
-
* `turn/steer` requests.
|
|
40
|
+
* Creates a queue that batches steer messages while still serializing
|
|
41
|
+
* app-server `turn/steer` requests.
|
|
46
42
|
*/
|
|
47
43
|
function createCodexSteeringQueue(params) {
|
|
48
|
-
let
|
|
44
|
+
let batchedMessages = [];
|
|
45
|
+
const dispatchedBatches = /* @__PURE__ */ new Map();
|
|
46
|
+
const pendingMessages = /* @__PURE__ */ new Set();
|
|
49
47
|
let batchTimer;
|
|
48
|
+
let batchSequence = 0;
|
|
50
49
|
let sendChain = Promise.resolve();
|
|
50
|
+
let closedError;
|
|
51
51
|
const clearBatchTimer = () => {
|
|
52
52
|
if (batchTimer) {
|
|
53
53
|
clearTimeout(batchTimer);
|
|
54
54
|
batchTimer = void 0;
|
|
55
55
|
}
|
|
56
56
|
};
|
|
57
|
-
const
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
const resolveItem = (item) => {
|
|
58
|
+
if (item.settled) return;
|
|
59
|
+
item.settled = true;
|
|
60
|
+
pendingMessages.delete(item);
|
|
61
|
+
item.resolve();
|
|
62
|
+
};
|
|
63
|
+
const rejectItem = (item, error) => {
|
|
64
|
+
if (item.settled) return;
|
|
65
|
+
item.settled = true;
|
|
66
|
+
pendingMessages.delete(item);
|
|
67
|
+
item.reject(error);
|
|
68
|
+
};
|
|
69
|
+
const closeQueue = (error) => {
|
|
70
|
+
if (closedError) return;
|
|
71
|
+
closedError = error;
|
|
72
|
+
params.signal.removeEventListener("abort", abortQueue);
|
|
73
|
+
clearBatchTimer();
|
|
74
|
+
batchedMessages = [];
|
|
75
|
+
dispatchedBatches.clear();
|
|
76
|
+
for (const item of pendingMessages) rejectItem(item, error);
|
|
77
|
+
};
|
|
78
|
+
const abortQueue = () => {
|
|
79
|
+
closeQueue(/* @__PURE__ */ new Error("codex app-server steering queue aborted"));
|
|
80
|
+
};
|
|
81
|
+
const cancelQueue = () => {
|
|
82
|
+
closeQueue(/* @__PURE__ */ new Error("codex app-server steering queue cancelled"));
|
|
83
|
+
};
|
|
84
|
+
const sendBatch = async (items) => {
|
|
85
|
+
const liveItems = items.filter((item) => !item.settled);
|
|
86
|
+
if (liveItems.length === 0) return;
|
|
87
|
+
const unavailableError = closedError ?? (params.signal.aborted ? /* @__PURE__ */ new Error("codex app-server steering queue aborted") : void 0);
|
|
88
|
+
if (unavailableError) {
|
|
89
|
+
for (const item of liveItems) rejectItem(item, unavailableError);
|
|
90
|
+
throw unavailableError;
|
|
91
|
+
}
|
|
92
|
+
const clientUserMessageId = `openclaw:${params.turnId}:steer:${++batchSequence}`;
|
|
93
|
+
const batch = { items: liveItems };
|
|
94
|
+
dispatchedBatches.set(clientUserMessageId, batch);
|
|
95
|
+
try {
|
|
96
|
+
await params.client.request("turn/steer", {
|
|
97
|
+
threadId: params.threadId,
|
|
98
|
+
expectedTurnId: params.turnId,
|
|
99
|
+
input: liveItems.flatMap((item) => buildCodexUserInput(item.text, item.images)),
|
|
100
|
+
clientUserMessageId
|
|
101
|
+
});
|
|
102
|
+
} catch (error) {
|
|
103
|
+
dispatchedBatches.delete(clientUserMessageId);
|
|
104
|
+
for (const item of liveItems) rejectItem(item, error);
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
65
107
|
};
|
|
66
|
-
const enqueueSend = (
|
|
67
|
-
const send = sendChain.then(() =>
|
|
68
|
-
sendChain = send
|
|
108
|
+
const enqueueSend = (items) => {
|
|
109
|
+
const send = sendChain.then(() => sendBatch(items));
|
|
110
|
+
sendChain = send;
|
|
111
|
+
send.catch((error) => {
|
|
112
|
+
for (const item of items) rejectItem(item, error);
|
|
69
113
|
embeddedAgentLog.debug("codex app-server queued steer failed", { error });
|
|
70
114
|
});
|
|
71
115
|
return send;
|
|
72
116
|
};
|
|
73
117
|
const flushBatch = () => {
|
|
74
118
|
clearBatchTimer();
|
|
75
|
-
const items =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
send
|
|
79
|
-
|
|
80
|
-
}, (error) => {
|
|
81
|
-
for (const item of items) item.reject(error);
|
|
82
|
-
});
|
|
119
|
+
const items = batchedMessages;
|
|
120
|
+
batchedMessages = [];
|
|
121
|
+
if (items.length === 0) return sendChain;
|
|
122
|
+
const send = enqueueSend(items);
|
|
123
|
+
send.catch(() => void 0);
|
|
83
124
|
return send;
|
|
84
125
|
};
|
|
126
|
+
const createPendingMessage = (text, images) => {
|
|
127
|
+
let resolveDelivery;
|
|
128
|
+
let rejectDelivery;
|
|
129
|
+
const delivery = new Promise((resolve, reject) => {
|
|
130
|
+
resolveDelivery = resolve;
|
|
131
|
+
rejectDelivery = reject;
|
|
132
|
+
});
|
|
133
|
+
const item = {
|
|
134
|
+
text,
|
|
135
|
+
images,
|
|
136
|
+
resolve: resolveDelivery,
|
|
137
|
+
reject: rejectDelivery,
|
|
138
|
+
settled: false
|
|
139
|
+
};
|
|
140
|
+
pendingMessages.add(item);
|
|
141
|
+
return {
|
|
142
|
+
item,
|
|
143
|
+
delivery
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
params.signal.addEventListener("abort", abortQueue, { once: true });
|
|
147
|
+
if (params.signal.aborted) abortQueue();
|
|
85
148
|
return {
|
|
86
149
|
async queue(text, options) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
text
|
|
91
|
-
resolve,
|
|
92
|
-
reject
|
|
93
|
-
});
|
|
94
|
-
clearBatchTimer();
|
|
95
|
-
const debounceMs = normalizeCodexSteerDebounceMs(options?.debounceMs);
|
|
96
|
-
if (debounceMs === 0) {
|
|
97
|
-
flushBatch().catch(() => void 0);
|
|
150
|
+
const pendingUserInput = params.claimPendingUserInput();
|
|
151
|
+
if (pendingUserInput) {
|
|
152
|
+
if (!options?.images?.length) {
|
|
153
|
+
pendingUserInput.answer(text);
|
|
98
154
|
return;
|
|
99
155
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
156
|
+
flushBatch().catch(() => void 0);
|
|
157
|
+
const { item, delivery } = createPendingMessage(text, options.images);
|
|
158
|
+
await Promise.all([enqueueSend([item]).finally(() => pendingUserInput.cancel()), delivery]);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (closedError) throw closedError;
|
|
162
|
+
if (params.signal.aborted) throw new Error("codex app-server steering queue aborted");
|
|
163
|
+
const { item, delivery } = createPendingMessage(text, options?.images);
|
|
164
|
+
batchedMessages.push(item);
|
|
165
|
+
clearBatchTimer();
|
|
166
|
+
const debounceMs = normalizeCodexSteerDebounceMs(options?.debounceMs);
|
|
167
|
+
if (debounceMs === 0) flushBatch();
|
|
168
|
+
else batchTimer = setTimeout(() => {
|
|
169
|
+
batchTimer = void 0;
|
|
170
|
+
flushBatch();
|
|
171
|
+
}, debounceMs);
|
|
172
|
+
return await delivery;
|
|
105
173
|
},
|
|
106
174
|
async flushPending() {
|
|
175
|
+
if (closedError) return;
|
|
107
176
|
await flushBatch().catch(() => void 0);
|
|
108
177
|
},
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
for (const item of items) item
|
|
114
|
-
|
|
178
|
+
confirmConsumed(clientUserMessageId) {
|
|
179
|
+
const batch = dispatchedBatches.get(clientUserMessageId);
|
|
180
|
+
if (!batch) return false;
|
|
181
|
+
dispatchedBatches.delete(clientUserMessageId);
|
|
182
|
+
for (const item of batch.items) resolveItem(item);
|
|
183
|
+
return true;
|
|
184
|
+
},
|
|
185
|
+
cancel: cancelQueue
|
|
115
186
|
};
|
|
116
187
|
}
|
|
117
188
|
/** Normalizes steer debounce milliseconds, preserving explicit zero. */
|
|
118
189
|
function normalizeCodexSteerDebounceMs(value) {
|
|
119
190
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : CODEX_STEER_ALL_DEBOUNCE_MS;
|
|
120
191
|
}
|
|
121
|
-
/** Converts plain text into the Codex app-server user-input shape. */
|
|
122
|
-
function toCodexTextInput(text) {
|
|
123
|
-
return {
|
|
124
|
-
type: "text",
|
|
125
|
-
text,
|
|
126
|
-
text_elements: []
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
192
|
//#endregion
|
|
130
193
|
//#region extensions/codex/src/app-server/user-input-bridge.ts
|
|
131
194
|
/**
|
|
@@ -142,6 +205,11 @@ function createCodexUserInputBridge(params) {
|
|
|
142
205
|
current.cleanup();
|
|
143
206
|
current.resolve(value);
|
|
144
207
|
};
|
|
208
|
+
const resolvePendingIfCurrent = (current, value) => {
|
|
209
|
+
if (pending !== current) return false;
|
|
210
|
+
resolvePending(value);
|
|
211
|
+
return true;
|
|
212
|
+
};
|
|
145
213
|
return {
|
|
146
214
|
async handleRequest(request) {
|
|
147
215
|
const requestParams = readUserInputParams(request.params);
|
|
@@ -158,6 +226,7 @@ function createCodexUserInputBridge(params) {
|
|
|
158
226
|
turnId: requestParams.turnId,
|
|
159
227
|
itemId: requestParams.itemId,
|
|
160
228
|
questions: requestParams.questions,
|
|
229
|
+
claimed: false,
|
|
161
230
|
resolve,
|
|
162
231
|
cleanup
|
|
163
232
|
};
|
|
@@ -171,9 +240,18 @@ function createCodexUserInputBridge(params) {
|
|
|
171
240
|
});
|
|
172
241
|
});
|
|
173
242
|
},
|
|
243
|
+
claimPendingRequest() {
|
|
244
|
+
const current = pending;
|
|
245
|
+
if (!current || current.claimed) return;
|
|
246
|
+
current.claimed = true;
|
|
247
|
+
return {
|
|
248
|
+
answer: (text) => resolvePendingIfCurrent(current, buildUserInputResponse(current.questions, text)),
|
|
249
|
+
cancel: () => resolvePendingIfCurrent(current, emptyUserInputResponse())
|
|
250
|
+
};
|
|
251
|
+
},
|
|
174
252
|
handleQueuedMessage(text) {
|
|
175
253
|
const current = pending;
|
|
176
|
-
if (!current) return false;
|
|
254
|
+
if (!current || current.claimed) return false;
|
|
177
255
|
resolvePending(buildUserInputResponse(current.questions, text));
|
|
178
256
|
return true;
|
|
179
257
|
},
|
|
@@ -181,7 +259,7 @@ function createCodexUserInputBridge(params) {
|
|
|
181
259
|
if (notification.method !== "serverRequest/resolved" || !pending) return;
|
|
182
260
|
const notificationParams = isJsonObject(notification.params) ? notification.params : void 0;
|
|
183
261
|
const requestId = notificationParams ? readRequestId(notificationParams) : void 0;
|
|
184
|
-
if (notificationParams && readString$
|
|
262
|
+
if (notificationParams && readString$3(notificationParams, "threadId") === pending.threadId && requestId !== void 0 && String(requestId) === String(pending.requestId)) resolvePending(emptyUserInputResponse());
|
|
185
263
|
},
|
|
186
264
|
cancelPending() {
|
|
187
265
|
resolvePending(emptyUserInputResponse());
|
|
@@ -190,9 +268,9 @@ function createCodexUserInputBridge(params) {
|
|
|
190
268
|
}
|
|
191
269
|
function readUserInputParams(value) {
|
|
192
270
|
if (!isJsonObject(value)) return;
|
|
193
|
-
const threadId = readString$
|
|
194
|
-
const turnId = readString$
|
|
195
|
-
const itemId = readString$
|
|
271
|
+
const threadId = readString$3(value, "threadId");
|
|
272
|
+
const turnId = readString$3(value, "turnId");
|
|
273
|
+
const itemId = readString$3(value, "itemId");
|
|
196
274
|
const questionsRaw = value.questions;
|
|
197
275
|
if (!threadId || !turnId || !itemId || !Array.isArray(questionsRaw)) return;
|
|
198
276
|
return {
|
|
@@ -204,9 +282,9 @@ function readUserInputParams(value) {
|
|
|
204
282
|
}
|
|
205
283
|
function readQuestion(value) {
|
|
206
284
|
if (!isJsonObject(value)) return;
|
|
207
|
-
const id = readString$
|
|
208
|
-
const header = readString$
|
|
209
|
-
const question = readString$
|
|
285
|
+
const id = readString$3(value, "id");
|
|
286
|
+
const header = readString$3(value, "header");
|
|
287
|
+
const question = readString$3(value, "question");
|
|
210
288
|
if (!id || !header || !question) return;
|
|
211
289
|
return {
|
|
212
290
|
id,
|
|
@@ -224,8 +302,8 @@ function readOptions(value) {
|
|
|
224
302
|
}
|
|
225
303
|
function readOption(value) {
|
|
226
304
|
if (!isJsonObject(value)) return;
|
|
227
|
-
const label = readString$
|
|
228
|
-
const description = readString$
|
|
305
|
+
const label = readString$3(value, "label");
|
|
306
|
+
const description = readString$3(value, "description") ?? "";
|
|
229
307
|
return label ? {
|
|
230
308
|
label,
|
|
231
309
|
description
|
|
@@ -243,7 +321,7 @@ function buildUserInputResponse(questions, inputText) {
|
|
|
243
321
|
function emptyUserInputResponse() {
|
|
244
322
|
return emptyAgentHarnessUserInputAnswers();
|
|
245
323
|
}
|
|
246
|
-
function readString$
|
|
324
|
+
function readString$3(record, key) {
|
|
247
325
|
const value = record[key];
|
|
248
326
|
return typeof value === "string" ? value : void 0;
|
|
249
327
|
}
|
|
@@ -336,7 +414,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
336
414
|
client: resourceState.client,
|
|
337
415
|
threadId: resourceState.thread.threadId,
|
|
338
416
|
turnId: activeTurnId,
|
|
339
|
-
|
|
417
|
+
claimPendingUserInput: () => userInputBridgeRef.current?.claimPendingRequest(),
|
|
340
418
|
signal: runAbortController.signal
|
|
341
419
|
});
|
|
342
420
|
steeringQueueRef.current = activeSteeringQueue;
|
|
@@ -348,6 +426,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
348
426
|
isStopped: () => state.completed || state.timedOut || runAbortController.signal.aborted,
|
|
349
427
|
isAbortable: () => !terminalState.terminalOutcomeFrozen || terminalState.sharedAbortAllowedAfterTerminalOutcome,
|
|
350
428
|
isCompacting: () => projectorRef.current?.isCompacting() ?? false,
|
|
429
|
+
supportsQueueMessageImages: true,
|
|
351
430
|
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
|
352
431
|
cancel: () => abortExplicitly("cancelled"),
|
|
353
432
|
abort: () => abortExplicitly("aborted")
|
|
@@ -1058,6 +1137,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
1058
1137
|
isInactiveThreadBootstrapBinding,
|
|
1059
1138
|
usesSupervisionConnection,
|
|
1060
1139
|
startupAuthProfileId,
|
|
1140
|
+
startupAuthRequirement: preparedAuthRoute?.authRequirement,
|
|
1061
1141
|
startupPreparedAuth,
|
|
1062
1142
|
startupClientAuthProfileId,
|
|
1063
1143
|
effectiveWorkspace,
|
|
@@ -2070,7 +2150,7 @@ function buildCodexTurnStartFailureResult(params) {
|
|
|
2070
2150
|
idleTimedOut: false,
|
|
2071
2151
|
timedOutDuringCompaction: false,
|
|
2072
2152
|
timedOutDuringToolExecution: false,
|
|
2073
|
-
promptError: params.message,
|
|
2153
|
+
promptError: params.promptError ?? params.message,
|
|
2074
2154
|
promptErrorSource: "prompt",
|
|
2075
2155
|
sessionIdUsed: params.params.sessionId,
|
|
2076
2156
|
messagesSnapshot: params.messagesSnapshot,
|
|
@@ -2284,139 +2364,6 @@ function normalizeCodexTrajectoryError(value) {
|
|
|
2284
2364
|
}
|
|
2285
2365
|
}
|
|
2286
2366
|
//#endregion
|
|
2287
|
-
//#region extensions/codex/src/app-server/usage-limit-error.ts
|
|
2288
|
-
/**
|
|
2289
|
-
* Enriches Codex usage-limit failures with current rate-limit information and
|
|
2290
|
-
* marks blocked auth profiles when Codex exposes a reset time.
|
|
2291
|
-
*/
|
|
2292
|
-
const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
|
|
2293
|
-
/** Marks a Codex auth profile blocked until the reset time advertised by rate limits. */
|
|
2294
|
-
async function markCodexAuthProfileBlockedFromRateLimits(params) {
|
|
2295
|
-
const authProfileId = params.authProfileId?.trim();
|
|
2296
|
-
if (!authProfileId || !params.params.authProfileStore) return;
|
|
2297
|
-
const blockedUntil = resolveCodexUsageLimitResetAtMs(params.rateLimits);
|
|
2298
|
-
if (!blockedUntil) return;
|
|
2299
|
-
try {
|
|
2300
|
-
await markAuthProfileBlockedUntil({
|
|
2301
|
-
store: params.params.authProfileStore,
|
|
2302
|
-
profileId: authProfileId,
|
|
2303
|
-
blockedUntil,
|
|
2304
|
-
source: "codex_rate_limits",
|
|
2305
|
-
agentDir: params.params.agentDir,
|
|
2306
|
-
runId: params.params.runId,
|
|
2307
|
-
modelId: params.params.modelId
|
|
2308
|
-
});
|
|
2309
|
-
} catch (error) {
|
|
2310
|
-
embeddedAgentLog.debug("failed to mark Codex auth profile blocked from app-server limits", {
|
|
2311
|
-
authProfileId,
|
|
2312
|
-
error: formatErrorMessage(error)
|
|
2313
|
-
});
|
|
2314
|
-
}
|
|
2315
|
-
}
|
|
2316
|
-
/** Formats a turn-start usage-limit error, refreshing rate limits when needed. */
|
|
2317
|
-
async function formatCodexTurnStartUsageLimitError(params) {
|
|
2318
|
-
return refreshCodexUsageLimitError({
|
|
2319
|
-
client: params.client,
|
|
2320
|
-
source: readCodexTurnStartUsageLimitErrorSource(params.client, params.error, params.errorNotification, params.rateLimitsRevisionBeforeTurnStart),
|
|
2321
|
-
timeoutMs: params.timeoutMs,
|
|
2322
|
-
signal: params.signal
|
|
2323
|
-
});
|
|
2324
|
-
}
|
|
2325
|
-
/** Refreshes a generic prompt usage-limit message into a reset-aware message. */
|
|
2326
|
-
async function refreshCodexUsageLimitPromptError(params) {
|
|
2327
|
-
if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(params.message)) return;
|
|
2328
|
-
return (await refreshCodexUsageLimitError({
|
|
2329
|
-
client: params.client,
|
|
2330
|
-
source: {
|
|
2331
|
-
message: params.message,
|
|
2332
|
-
codexErrorInfo: "usageLimitExceeded",
|
|
2333
|
-
rateLimits: readRecentCodexRateLimits(params.client)
|
|
2334
|
-
},
|
|
2335
|
-
timeoutMs: params.timeoutMs,
|
|
2336
|
-
signal: params.signal
|
|
2337
|
-
}))?.message;
|
|
2338
|
-
}
|
|
2339
|
-
async function refreshCodexUsageLimitError(params) {
|
|
2340
|
-
const initialMessage = formatCodexUsageLimitErrorMessage(params.source);
|
|
2341
|
-
if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(initialMessage)) return initialMessage ? {
|
|
2342
|
-
message: initialMessage,
|
|
2343
|
-
...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
|
|
2344
|
-
} : void 0;
|
|
2345
|
-
const rateLimits = await readCodexRateLimitsFromAppServerForUsageLimitError({
|
|
2346
|
-
client: params.client,
|
|
2347
|
-
timeoutMs: params.timeoutMs,
|
|
2348
|
-
signal: params.signal
|
|
2349
|
-
});
|
|
2350
|
-
if (!rateLimits) return initialMessage ? {
|
|
2351
|
-
message: initialMessage,
|
|
2352
|
-
...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
|
|
2353
|
-
} : void 0;
|
|
2354
|
-
const message = formatCodexUsageLimitErrorMessage({
|
|
2355
|
-
message: params.source.message,
|
|
2356
|
-
codexErrorInfo: params.source.codexErrorInfo,
|
|
2357
|
-
rateLimits
|
|
2358
|
-
}) ?? initialMessage;
|
|
2359
|
-
return message ? {
|
|
2360
|
-
message,
|
|
2361
|
-
rateLimitsForProfile: rateLimits
|
|
2362
|
-
} : void 0;
|
|
2363
|
-
}
|
|
2364
|
-
async function readCodexRateLimitsFromAppServerForUsageLimitError(params) {
|
|
2365
|
-
if (params.signal?.aborted) return;
|
|
2366
|
-
try {
|
|
2367
|
-
const rateLimits = await params.client.request(CODEX_CONTROL_METHODS.rateLimits, void 0, {
|
|
2368
|
-
timeoutMs: resolveCodexUsageLimitRateLimitRefreshTimeoutMs(params.timeoutMs),
|
|
2369
|
-
signal: params.signal
|
|
2370
|
-
});
|
|
2371
|
-
rememberCodexRateLimitsRead(params.client, rateLimits);
|
|
2372
|
-
return rateLimits;
|
|
2373
|
-
} catch (error) {
|
|
2374
|
-
embeddedAgentLog.debug("codex app-server rate-limit refresh failed after usage-limit error", { error: formatErrorMessage(error) });
|
|
2375
|
-
return;
|
|
2376
|
-
}
|
|
2377
|
-
}
|
|
2378
|
-
function resolveCodexUsageLimitRateLimitRefreshTimeoutMs(timeoutMs) {
|
|
2379
|
-
if (timeoutMs === void 0 || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS;
|
|
2380
|
-
return Math.max(100, Math.min(timeoutMs, CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS));
|
|
2381
|
-
}
|
|
2382
|
-
function readCodexTurnStartUsageLimitErrorSource(client, error, errorNotification, rateLimitsRevisionBeforeTurnStart) {
|
|
2383
|
-
const notificationError = readCodexErrorNotification(errorNotification);
|
|
2384
|
-
const errorPayload = readCodexErrorPayload(error);
|
|
2385
|
-
const rateLimits = errorPayload.rateLimits ?? readRecentCodexRateLimits(client);
|
|
2386
|
-
const cacheUpdatedDuringTurnStart = rateLimitsRevisionBeforeTurnStart !== void 0 && readCodexRateLimitsRevision(client) > rateLimitsRevisionBeforeTurnStart;
|
|
2387
|
-
return {
|
|
2388
|
-
message: notificationError?.message ?? errorPayload.message ?? formatErrorMessage(error),
|
|
2389
|
-
codexErrorInfo: notificationError?.codexErrorInfo ?? errorPayload.codexErrorInfo,
|
|
2390
|
-
rateLimits,
|
|
2391
|
-
rateLimitsTrustedForProfile: errorPayload.rateLimits !== void 0 || cacheUpdatedDuringTurnStart
|
|
2392
|
-
};
|
|
2393
|
-
}
|
|
2394
|
-
function readCodexErrorNotification(notification) {
|
|
2395
|
-
if (notification?.method !== "error" || !isJsonObject(notification.params)) return;
|
|
2396
|
-
const error = notification.params.error;
|
|
2397
|
-
return isJsonObject(error) ? {
|
|
2398
|
-
message: readString$3(error, "message"),
|
|
2399
|
-
codexErrorInfo: error.codexErrorInfo
|
|
2400
|
-
} : void 0;
|
|
2401
|
-
}
|
|
2402
|
-
function readCodexErrorPayload(error) {
|
|
2403
|
-
const message = error instanceof Error ? error.message : void 0;
|
|
2404
|
-
if (!error || typeof error !== "object" || !("data" in error)) return { message };
|
|
2405
|
-
const data = error.data;
|
|
2406
|
-
if (!isJsonObject(data)) return { message };
|
|
2407
|
-
const nestedError = isJsonObject(data.error) ? data.error : data;
|
|
2408
|
-
const rateLimits = nestedError.rateLimits ?? data.rateLimits;
|
|
2409
|
-
return {
|
|
2410
|
-
message: readString$3(nestedError, "message") ?? message,
|
|
2411
|
-
codexErrorInfo: nestedError.codexErrorInfo,
|
|
2412
|
-
rateLimits
|
|
2413
|
-
};
|
|
2414
|
-
}
|
|
2415
|
-
function readString$3(record, key) {
|
|
2416
|
-
const value = record[key];
|
|
2417
|
-
return typeof value === "string" ? value : void 0;
|
|
2418
|
-
}
|
|
2419
|
-
//#endregion
|
|
2420
2367
|
//#region extensions/codex/src/app-server/run-attempt-finalize.ts
|
|
2421
2368
|
async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notifications, requestRuntime, activeTurn) {
|
|
2422
2369
|
const { prompt, state: resourceState, trajectoryRecorder, markTrajectoryEndRecorded } = resources;
|
|
@@ -2425,7 +2372,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2425
2372
|
const { hookContextWindowFields, hookRunner, promptState } = context;
|
|
2426
2373
|
const { connection, preparedAuthBinding, activeSessionId, activeSessionFile } = runtime;
|
|
2427
2374
|
const { buildActiveRunAttemptParams, effectiveContextTokenBudget, effectiveRuntimeProviderId, effectiveRuntimeModelId } = runtime;
|
|
2428
|
-
const { params, terminalState, runAbortController, activeContextEngine, bindingStore, bindingIdentity, appServer, usesSupervisionConnection, sessionAgentId, contextSessionKey, effectiveCwd, effectiveWorkspace, agentDir, attemptStartedAt } = connection;
|
|
2375
|
+
const { params, terminalState, runAbortController, activeContextEngine, bindingStore, bindingIdentity, appServer, usesSupervisionConnection, sessionAgentId, contextSessionKey, effectiveCwd, effectiveWorkspace, agentDir, attemptStartedAt, startupAuthProfileId } = connection;
|
|
2429
2376
|
const { toolBridge, toolState } = attemptTools;
|
|
2430
2377
|
const { state, completion, pendingOpenClawDynamicToolCompletionIds, activeTurnItemIds, activeCompletionBlockerItemIds, activeFinalizationHookRunIds, turnWatches } = turnRuntime;
|
|
2431
2378
|
const { emitLifecycleTerminal, buildLifecycleTerminalMeta } = lifecycle;
|
|
@@ -2459,7 +2406,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2459
2406
|
const isFinalAborted = () => result.aborted || terminalState.explicitCancellationObserved || runAbortController.signal.aborted && !state.clientClosedAbort && !recoveredTurnWatchTimeout;
|
|
2460
2407
|
const clientClosedPromptErrorForFinal = state.clientClosedPromptError && hasRecoverableCompletedAssistant ? void 0 : state.clientClosedPromptError;
|
|
2461
2408
|
let finalPromptError = clientClosedPromptErrorForFinal ?? (effectiveTurnCompletionIdleTimedOut ? state.turnCompletionIdleTimeoutMessage : effectiveTimedOut ? "codex app-server attempt timed out" : result.promptError);
|
|
2462
|
-
const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
|
|
2409
|
+
const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError instanceof Error ? finalPromptError.message : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
|
|
2463
2410
|
if (isInvalidCodexImagePayloadError(finalPromptErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(bindingStore, bindingIdentity, {
|
|
2464
2411
|
phase: "turn_completed",
|
|
2465
2412
|
threadId: resourceState.thread.threadId,
|
|
@@ -2487,7 +2434,18 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2487
2434
|
timeoutMs: appServer.requestTimeoutMs,
|
|
2488
2435
|
signal: runAbortController.signal
|
|
2489
2436
|
});
|
|
2490
|
-
if (refreshedUsageLimitPromptError)
|
|
2437
|
+
if (refreshedUsageLimitPromptError) {
|
|
2438
|
+
await markCodexAuthProfileBlockedFromRateLimits({
|
|
2439
|
+
params,
|
|
2440
|
+
authProfileId: startupAuthProfileId,
|
|
2441
|
+
rateLimits: refreshedUsageLimitPromptError.rateLimitsForProfile
|
|
2442
|
+
});
|
|
2443
|
+
finalPromptError = createCodexUsageLimitPromptError(refreshedUsageLimitPromptError.message);
|
|
2444
|
+
} else if (isCodexUsageLimitPromptError(finalPromptError) && state.rateLimitsRevisionBeforeLastTurnStart !== void 0 && readCodexRateLimitsRevision(resourceState.client) > state.rateLimitsRevisionBeforeLastTurnStart) await markCodexAuthProfileBlockedFromRateLimits({
|
|
2445
|
+
params,
|
|
2446
|
+
authProfileId: startupAuthProfileId,
|
|
2447
|
+
rateLimits: readRecentCodexRateLimits(resourceState.client)
|
|
2448
|
+
});
|
|
2491
2449
|
const finalPromptErrorSource = effectiveTimedOut || clientClosedPromptErrorForFinal ? "prompt" : result.promptErrorSource;
|
|
2492
2450
|
const codexAppServerFailureKind = clientClosedPromptErrorForFinal ? "client_closed_before_turn_completed" : effectiveTurnCompletionIdleTimedOut ? "turn_completion_idle_timeout" : void 0;
|
|
2493
2451
|
const replayBlockedReason = codexAppServerFailureKind ? resolveCodexAppServerReplayBlockedReason(result) : void 0;
|
|
@@ -2515,7 +2473,9 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2515
2473
|
const finalAborted = isFinalAborted();
|
|
2516
2474
|
const completedTurnStatus = activeProjector.getCompletedTurnStatus();
|
|
2517
2475
|
const completedWithoutTerminalNotification = state.completed && !state.terminalTurnNotificationQueued && !state.timedOut && clientClosedPromptErrorForFinal === void 0;
|
|
2518
|
-
const
|
|
2476
|
+
const turnSucceeded = !finalAborted && !effectiveTimedOut && (finalPromptError === null || finalPromptError === void 0) && (completedTurnStatus === "completed" || recoveredTurnWatchTimeout || completedWithoutTerminalNotification);
|
|
2477
|
+
if (settleCodexSourceReplyFinality(toolBridge.telemetry, turnSucceeded)) result.agentHarnessResultClassification = void 0;
|
|
2478
|
+
const attemptSucceeded = turnSucceeded && result.agentHarnessResultClassification === void 0;
|
|
2519
2479
|
terminalState.sharedAbortAllowedAfterTerminalOutcome = shouldKeepCodexSharedAbortOpen({
|
|
2520
2480
|
trigger: params.trigger,
|
|
2521
2481
|
result,
|
|
@@ -2662,7 +2622,8 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2662
2622
|
phase: "end",
|
|
2663
2623
|
...buildLifecycleTerminalMeta({
|
|
2664
2624
|
aborted: finalAborted,
|
|
2665
|
-
timedOut: effectiveTimedOut
|
|
2625
|
+
timedOut: effectiveTimedOut,
|
|
2626
|
+
yielded: toolState.yieldDetected
|
|
2666
2627
|
})
|
|
2667
2628
|
});
|
|
2668
2629
|
return {
|
|
@@ -2708,7 +2669,7 @@ function reportCodexExecutionNotification(params) {
|
|
|
2708
2669
|
/** Returns true when a notification ends the current app-server turn. */
|
|
2709
2670
|
function isTerminalCodexTurnNotificationForTurn(params) {
|
|
2710
2671
|
if (!isCodexNotificationForTurn(params.notification.params, params.threadId, params.turnId)) return false;
|
|
2711
|
-
return params.notification.method === "turn/completed"
|
|
2672
|
+
return params.notification.method === "turn/completed";
|
|
2712
2673
|
}
|
|
2713
2674
|
/**
|
|
2714
2675
|
* Applies one notification to active item tracking, idle watches, and terminal
|
|
@@ -2778,13 +2739,33 @@ function applyCodexTurnNotificationState(params) {
|
|
|
2778
2739
|
isTurnTerminal: isTerminalCodexTurnNotificationForTurn({
|
|
2779
2740
|
notification,
|
|
2780
2741
|
threadId: params.threadId,
|
|
2781
|
-
turnId: params.turnId
|
|
2782
|
-
currentPromptTexts: params.currentPromptTexts
|
|
2742
|
+
turnId: params.turnId
|
|
2783
2743
|
}),
|
|
2784
2744
|
turnCrossedToolHandoff
|
|
2785
2745
|
};
|
|
2786
2746
|
}
|
|
2787
2747
|
//#endregion
|
|
2748
|
+
//#region extensions/codex/src/app-server/run-attempt-lifecycle-terminal.ts
|
|
2749
|
+
function buildCodexLifecycleTerminalMeta(input) {
|
|
2750
|
+
if (input.timedOut || input.abortStopReason === "timeout") return {
|
|
2751
|
+
aborted: true,
|
|
2752
|
+
status: "timed_out",
|
|
2753
|
+
stopReason: "timeout",
|
|
2754
|
+
timeoutPhase: "provider",
|
|
2755
|
+
providerStarted: true
|
|
2756
|
+
};
|
|
2757
|
+
if (input.yielded && !input.aborted) return {
|
|
2758
|
+
yielded: true,
|
|
2759
|
+
livenessState: "paused",
|
|
2760
|
+
stopReason: "end_turn"
|
|
2761
|
+
};
|
|
2762
|
+
return input.aborted ? {
|
|
2763
|
+
aborted: true,
|
|
2764
|
+
status: "cancelled",
|
|
2765
|
+
stopReason: "stop"
|
|
2766
|
+
} : void 0;
|
|
2767
|
+
}
|
|
2768
|
+
//#endregion
|
|
2788
2769
|
//#region extensions/codex/src/app-server/run-attempt-lifecycle-controller.ts
|
|
2789
2770
|
function createCodexAttemptLifecycleController(resources, turnRuntime) {
|
|
2790
2771
|
const { prompt, state: resourceState, trajectoryRecorder } = resources;
|
|
@@ -2816,6 +2797,7 @@ function createCodexAttemptLifecycleController(resources, turnRuntime) {
|
|
|
2816
2797
|
tool: value.call.tool,
|
|
2817
2798
|
durationMs: value.durationMs
|
|
2818
2799
|
});
|
|
2800
|
+
turnRuntime.steeringQueueRef.current?.cancel();
|
|
2819
2801
|
interruptCodexTurnBestEffort(resourceState.client, {
|
|
2820
2802
|
threadId: value.call.threadId,
|
|
2821
2803
|
turnId: value.call.turnId,
|
|
@@ -2832,6 +2814,7 @@ function createCodexAttemptLifecycleController(resources, turnRuntime) {
|
|
|
2832
2814
|
state.terminalDynamicToolReleaseCheckScheduled = true;
|
|
2833
2815
|
setImmediate(() => {
|
|
2834
2816
|
state.terminalDynamicToolReleaseCheckScheduled = false;
|
|
2817
|
+
if (state.pendingTerminalDynamicToolRelease?.response.success === true && !state.currentTurnHadNonTerminalDynamicToolResult && state.activeAppServerTurnRequests === 0 && pendingOpenClawDynamicToolCompletionIds.size === 0) turnRuntime.steeringQueueRef.current?.cancel();
|
|
2835
2818
|
const action = resolveTerminalDynamicToolBatchAction({
|
|
2836
2819
|
activeAppServerTurnRequests: state.activeAppServerTurnRequests,
|
|
2837
2820
|
activeTurnItemIdsCount: activeTurnItemIds.size,
|
|
@@ -2875,18 +2858,10 @@ function createCodexAttemptLifecycleController(resources, turnRuntime) {
|
|
|
2875
2858
|
};
|
|
2876
2859
|
const buildLifecycleTerminalMeta = (input) => {
|
|
2877
2860
|
const abortFields = input.aborted ? resolveAgentRunAbortLifecycleFields(runAbortController.signal) : void 0;
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
timeoutPhase: "provider",
|
|
2883
|
-
providerStarted: true
|
|
2884
|
-
};
|
|
2885
|
-
return input.aborted ? {
|
|
2886
|
-
aborted: true,
|
|
2887
|
-
status: "cancelled",
|
|
2888
|
-
stopReason: "stop"
|
|
2889
|
-
} : void 0;
|
|
2861
|
+
return buildCodexLifecycleTerminalMeta({
|
|
2862
|
+
...input,
|
|
2863
|
+
abortStopReason: abortFields?.stopReason
|
|
2864
|
+
});
|
|
2890
2865
|
};
|
|
2891
2866
|
const executionPhaseKeys = /* @__PURE__ */ new Set();
|
|
2892
2867
|
const emitExecutionPhaseOnce = (key, info) => {
|
|
@@ -3307,8 +3282,7 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
3307
3282
|
const isTerminalTurnNotificationForTurn = (notification, notificationTurnId) => isTerminalCodexTurnNotificationForTurn({
|
|
3308
3283
|
notification,
|
|
3309
3284
|
threadId: resourceState.thread.threadId,
|
|
3310
|
-
turnId: notificationTurnId
|
|
3311
|
-
currentPromptTexts: [turnState.codexTurnPromptText]
|
|
3285
|
+
turnId: notificationTurnId
|
|
3312
3286
|
});
|
|
3313
3287
|
const handleNotification = async (notification) => {
|
|
3314
3288
|
const projector = projectorRef.current;
|
|
@@ -3335,6 +3309,11 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
3335
3309
|
onReportExecutionNotification: reportExecutionNotification
|
|
3336
3310
|
});
|
|
3337
3311
|
state.turnCrossedToolHandoff = notificationState.turnCrossedToolHandoff;
|
|
3312
|
+
if (notificationState.isCurrentTurnNotification && notification.method === "item/completed") {
|
|
3313
|
+
const item = readCodexNotificationItem(notification.params);
|
|
3314
|
+
if (item?.type === "userMessage" && typeof item.clientId === "string") steeringQueue?.confirmConsumed(item.clientId);
|
|
3315
|
+
}
|
|
3316
|
+
if (notificationState.isTurnAbortMarker) state.sawCodexInterruptMarker = true;
|
|
3338
3317
|
const hookNotification = readCodexFinalizationHookNotification(notification, resourceState.thread.threadId, turnId);
|
|
3339
3318
|
if (hookNotification?.phase === "started") {
|
|
3340
3319
|
if (activeFinalizationHookRunIds.size === 0) finalizationHookBatchStatuses.clear();
|
|
@@ -3378,7 +3357,7 @@ function createCodexAttemptNotificationController(resources, turnRuntime, lifecy
|
|
|
3378
3357
|
});
|
|
3379
3358
|
}
|
|
3380
3359
|
if (notificationState.isTurnTerminal) {
|
|
3381
|
-
if (
|
|
3360
|
+
if ((readCodexTurnCompletedNotification(notification.params)?.turn)?.status === "interrupted" && state.sawCodexInterruptMarker) projector.markAborted();
|
|
3382
3361
|
if (!state.timedOut && !runAbortController.signal.aborted) await steeringQueue?.flushPending();
|
|
3383
3362
|
state.completed = true;
|
|
3384
3363
|
turnWatches.clearCompletionIdleTimer();
|
|
@@ -5265,6 +5244,30 @@ function sendError(socket, id, code, message) {
|
|
|
5265
5244
|
}));
|
|
5266
5245
|
}
|
|
5267
5246
|
//#endregion
|
|
5247
|
+
//#region extensions/codex/src/app-server/sandbox-exec-server/path-uri.ts
|
|
5248
|
+
/** Converts Codex PathUri protocol values into sandbox-backend path strings. */
|
|
5249
|
+
const WINDOWS_DRIVE_PATH_RE = /^\/[A-Za-z]:(?:\/|$)/u;
|
|
5250
|
+
/** Resolves one Codex exec-server PathUri into a POSIX sandbox path. */
|
|
5251
|
+
function resolveExecServerPath(rawPath, label) {
|
|
5252
|
+
let pathUrl;
|
|
5253
|
+
try {
|
|
5254
|
+
pathUrl = new URL(rawPath);
|
|
5255
|
+
} catch (error) {
|
|
5256
|
+
throw new Error(`${label} must be a valid file URI: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
5257
|
+
}
|
|
5258
|
+
if (pathUrl.protocol !== "file:") throw new Error(`${label} URI must use the file scheme, received ${pathUrl.protocol.slice(0, -1)}.`);
|
|
5259
|
+
if (pathUrl.search || pathUrl.hash) throw new Error(`${label} file URI must not include a query or fragment.`);
|
|
5260
|
+
let resolved;
|
|
5261
|
+
try {
|
|
5262
|
+
resolved = fileURLToPath(pathUrl, { windows: false });
|
|
5263
|
+
} catch (error) {
|
|
5264
|
+
throw new Error(`${label} file URI is not valid for the sandbox: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
5265
|
+
}
|
|
5266
|
+
if (WINDOWS_DRIVE_PATH_RE.test(resolved)) throw new Error(`${label} Windows file URI is not supported by the sandbox.`);
|
|
5267
|
+
if (resolved.includes("\0")) throw new Error(`${label} file URI must not contain a null byte.`);
|
|
5268
|
+
return resolved;
|
|
5269
|
+
}
|
|
5270
|
+
//#endregion
|
|
5268
5271
|
//#region extensions/codex/src/app-server/sandbox-exec-server/fs-policy.ts
|
|
5269
5272
|
/**
|
|
5270
5273
|
* Resolves Codex filesystem sandbox policy payloads into OpenClaw path/glob
|
|
@@ -5304,7 +5307,7 @@ function resolveFsSandboxPolicy(execServer, record) {
|
|
|
5304
5307
|
}
|
|
5305
5308
|
function readFsSandboxCwd(execServer, sandbox) {
|
|
5306
5309
|
if (sandbox.cwd === void 0 || sandbox.cwd === null) return normalizeSandboxAbsolutePath(execServer.sandbox.containerWorkdir, "sandbox cwd");
|
|
5307
|
-
return normalizeSandboxAbsolutePath(requireString(sandbox.cwd, "sandbox cwd"), "sandbox cwd");
|
|
5310
|
+
return normalizeSandboxAbsolutePath(resolveExecServerPath(requireString(sandbox.cwd, "sandbox cwd"), "sandbox cwd"), "sandbox cwd");
|
|
5308
5311
|
}
|
|
5309
5312
|
function resolveFsSandboxEntry(entry, cwd) {
|
|
5310
5313
|
const access = readFsAccessMode(entry.access);
|
|
@@ -5312,7 +5315,7 @@ function resolveFsSandboxEntry(entry, cwd) {
|
|
|
5312
5315
|
const pathType = requireString(pathSpec.type, "fs sandbox entry path type");
|
|
5313
5316
|
if (pathType === "path") return {
|
|
5314
5317
|
kind: "path",
|
|
5315
|
-
path: normalizeSandboxAbsolutePath(requireString(pathSpec.path, "fs sandbox path"), "fs sandbox path"),
|
|
5318
|
+
path: normalizeSandboxAbsolutePath(resolveExecServerPath(requireString(pathSpec.path, "fs sandbox path"), "fs sandbox path"), "fs sandbox path"),
|
|
5316
5319
|
access
|
|
5317
5320
|
};
|
|
5318
5321
|
if (pathType === "special") {
|
|
@@ -5506,7 +5509,7 @@ const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES = 512 * 1024 * 1024;
|
|
|
5506
5509
|
/** Reads a sandbox file as base64 after read-policy and size checks. */
|
|
5507
5510
|
async function readFile(execServer, params) {
|
|
5508
5511
|
const record = requireObject(params, "fs/readFile params");
|
|
5509
|
-
const filePath = requireString(record.path, "path");
|
|
5512
|
+
const filePath = resolveExecServerPath(requireString(record.path, "path"), "read path");
|
|
5510
5513
|
assertFsSandboxAccess(execServer, record, [{
|
|
5511
5514
|
path: filePath,
|
|
5512
5515
|
access: "read"
|
|
@@ -5520,7 +5523,7 @@ async function readFile(execServer, params) {
|
|
|
5520
5523
|
/** Writes base64 data to an existing sandbox directory after write-policy checks. */
|
|
5521
5524
|
async function writeFile(execServer, params) {
|
|
5522
5525
|
const record = requireObject(params, "fs/writeFile params");
|
|
5523
|
-
const filePath = requireString(record.path, "path");
|
|
5526
|
+
const filePath = resolveExecServerPath(requireString(record.path, "path"), "write path");
|
|
5524
5527
|
assertFsSandboxAccess(execServer, record, [{
|
|
5525
5528
|
path: filePath,
|
|
5526
5529
|
access: "write"
|
|
@@ -5536,7 +5539,7 @@ async function writeFile(execServer, params) {
|
|
|
5536
5539
|
/** Creates a sandbox directory, respecting recursive and parent-directory semantics. */
|
|
5537
5540
|
async function createDirectory(execServer, params) {
|
|
5538
5541
|
const record = requireObject(params, "fs/createDirectory params");
|
|
5539
|
-
const filePath = requireString(record.path, "path");
|
|
5542
|
+
const filePath = resolveExecServerPath(requireString(record.path, "path"), "create-directory path");
|
|
5540
5543
|
assertFsSandboxAccess(execServer, record, [{
|
|
5541
5544
|
path: filePath,
|
|
5542
5545
|
access: "write"
|
|
@@ -5551,7 +5554,7 @@ async function createDirectory(execServer, params) {
|
|
|
5551
5554
|
/** Returns normalized metadata for a sandbox path. */
|
|
5552
5555
|
async function getMetadata(execServer, params) {
|
|
5553
5556
|
const record = requireObject(params, "fs/getMetadata params");
|
|
5554
|
-
const filePath = requireString(record.path, "path");
|
|
5557
|
+
const filePath = resolveExecServerPath(requireString(record.path, "path"), "metadata path");
|
|
5555
5558
|
assertFsSandboxAccess(execServer, record, [{
|
|
5556
5559
|
path: filePath,
|
|
5557
5560
|
access: "read"
|
|
@@ -5563,7 +5566,7 @@ async function getMetadata(execServer, params) {
|
|
|
5563
5566
|
/** Lists sandbox directory entries visible under the resolved filesystem policy. */
|
|
5564
5567
|
async function readDirectory(execServer, params) {
|
|
5565
5568
|
const record = requireObject(params, "fs/readDirectory params");
|
|
5566
|
-
return { entries: await listDirectoryEntries(execServer, requireString(record.path, "path"), resolveFsSandboxPolicy(execServer, record)) };
|
|
5569
|
+
return { entries: await listDirectoryEntries(execServer, resolveExecServerPath(requireString(record.path, "path"), "read-directory path"), resolveFsSandboxPolicy(execServer, record)) };
|
|
5567
5570
|
}
|
|
5568
5571
|
async function listDirectoryEntries(execServer, filePath, fsSandboxPolicy) {
|
|
5569
5572
|
assertResolvedFsSandboxAccess(fsSandboxPolicy, [{
|
|
@@ -5595,7 +5598,7 @@ async function listDirectoryEntries(execServer, filePath, fsSandboxPolicy) {
|
|
|
5595
5598
|
/** Removes a sandbox path after rejecting writes outside policy or under read-only descendants. */
|
|
5596
5599
|
async function removePath(execServer, params) {
|
|
5597
5600
|
const record = requireObject(params, "fs/remove params");
|
|
5598
|
-
const filePath = requireString(record.path, "path");
|
|
5601
|
+
const filePath = resolveExecServerPath(requireString(record.path, "path"), "remove path");
|
|
5599
5602
|
const fsSandboxPolicy = resolveFsSandboxPolicy(execServer, record);
|
|
5600
5603
|
assertResolvedFsSandboxAccess(fsSandboxPolicy, [{
|
|
5601
5604
|
path: filePath,
|
|
@@ -5611,8 +5614,8 @@ async function removePath(execServer, params) {
|
|
|
5611
5614
|
/** Copies sandbox files or recursive directories while enforcing source and destination policy. */
|
|
5612
5615
|
async function copyPath(execServer, params) {
|
|
5613
5616
|
const record = requireObject(params, "fs/copy params");
|
|
5614
|
-
const sourcePath = requireString(record.sourcePath ?? record.source, "sourcePath");
|
|
5615
|
-
const destinationPath = requireString(record.destinationPath ?? record.destination, "destinationPath");
|
|
5617
|
+
const sourcePath = resolveExecServerPath(requireString(record.sourcePath ?? record.source, "sourcePath"), "copy source path");
|
|
5618
|
+
const destinationPath = resolveExecServerPath(requireString(record.destinationPath ?? record.destination, "destinationPath"), "copy destination path");
|
|
5616
5619
|
const fsSandboxPolicy = resolveFsSandboxPolicy(execServer, record);
|
|
5617
5620
|
assertResolvedFsSandboxAccess(fsSandboxPolicy, [{
|
|
5618
5621
|
path: sourcePath,
|
|
@@ -5812,8 +5815,9 @@ function readStreamingSandboxHttpResponse(params) {
|
|
|
5812
5815
|
}
|
|
5813
5816
|
reject(new Error(message));
|
|
5814
5817
|
};
|
|
5818
|
+
params.child.stdout.setEncoding("utf8");
|
|
5815
5819
|
params.child.stdout.on("data", (chunk) => {
|
|
5816
|
-
stdoutBuffer += chunk
|
|
5820
|
+
stdoutBuffer += chunk;
|
|
5817
5821
|
let newline = stdoutBuffer.indexOf("\n");
|
|
5818
5822
|
while (newline >= 0) {
|
|
5819
5823
|
const line = stdoutBuffer.slice(0, newline).trim();
|
|
@@ -5849,8 +5853,9 @@ function readStreamingSandboxHttpResponse(params) {
|
|
|
5849
5853
|
fail(`sandbox http/request produced an unterminated stdout line longer than ${SANDBOX_HTTP_STREAM_LINE_MAX_CHARS} characters`, null);
|
|
5850
5854
|
}
|
|
5851
5855
|
});
|
|
5856
|
+
params.child.stderr.setEncoding("utf8");
|
|
5852
5857
|
params.child.stderr.on("data", (chunk) => {
|
|
5853
|
-
stderr = `${stderr}${chunk
|
|
5858
|
+
stderr = sliceUtf16Safe(`${stderr}${chunk}`, -4096);
|
|
5854
5859
|
});
|
|
5855
5860
|
params.child.once("error", (error) => {
|
|
5856
5861
|
childFailure ??= error.message;
|
|
@@ -6101,7 +6106,7 @@ async function startProcess(execServer, processes, socket, params) {
|
|
|
6101
6106
|
const processId = requireString(record.processId, "processId");
|
|
6102
6107
|
if (processes.has(processId)) throw new Error(`process already exists: ${processId}`);
|
|
6103
6108
|
const argv = requireStringArray(record.argv, "argv");
|
|
6104
|
-
const cwd = requireString(record.cwd, "cwd");
|
|
6109
|
+
const cwd = resolveExecServerPath(requireString(record.cwd, "cwd"), "process cwd");
|
|
6105
6110
|
rejectUnsupportedArg0(record.arg0);
|
|
6106
6111
|
const env = readProcessEnv(record);
|
|
6107
6112
|
const managed = {
|
|
@@ -6591,7 +6596,7 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
6591
6596
|
const { context, turnState, buildRenderedCodexDeveloperInstructions } = prompt;
|
|
6592
6597
|
const { runtime, attemptTools } = context;
|
|
6593
6598
|
const { connection, hookChannelId } = runtime;
|
|
6594
|
-
const { params, effectiveCwd, sessionAgentId, sandboxSessionKey, runAbortController, sandbox, options, nativeHookRelayEvents } = connection;
|
|
6599
|
+
const { appServer, params, effectiveCwd, sessionAgentId, sandboxSessionKey, runAbortController, sandbox, options, nativeHookRelayEvents } = connection;
|
|
6595
6600
|
const { toolBridge } = attemptTools;
|
|
6596
6601
|
const hostTrajectoryRecorder = params.trajectoryRecorder;
|
|
6597
6602
|
const trajectoryRecorder = createCodexTrajectoryRecorder({
|
|
@@ -6724,6 +6729,7 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
6724
6729
|
attemptTimeoutMs: params.timeoutMs,
|
|
6725
6730
|
startupTimeoutMs,
|
|
6726
6731
|
turnStartTimeoutMs: params.timeoutMs,
|
|
6732
|
+
loopDetectionPreToolUseRelay: appServer.loopDetectionPreToolUseRelay,
|
|
6727
6733
|
signal: runAbortController.signal,
|
|
6728
6734
|
onPreToolUseFailure: (failure) => {
|
|
6729
6735
|
const projector = projectorRef.current;
|
|
@@ -6736,7 +6742,8 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
6736
6742
|
configPatch: state.nativeHookRelay ? buildCodexNativeHookRelayConfig({
|
|
6737
6743
|
relay: state.nativeHookRelay,
|
|
6738
6744
|
events: nativeHookRelayEvents,
|
|
6739
|
-
hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec
|
|
6745
|
+
hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec,
|
|
6746
|
+
loopDetectionPreToolUseRelay: appServer.loopDetectionPreToolUseRelay
|
|
6740
6747
|
}) : options.nativeHookRelay?.enabled === false ? buildCodexNativeHookRelayDisabledConfig() : void 0,
|
|
6741
6748
|
nativeHookRelayGeneration: state.nativeHookRelay?.generation
|
|
6742
6749
|
};
|
|
@@ -6955,6 +6962,21 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
6955
6962
|
};
|
|
6956
6963
|
}
|
|
6957
6964
|
//#endregion
|
|
6965
|
+
//#region extensions/codex/src/app-server/dynamic-tool-result-projection.ts
|
|
6966
|
+
/** Project one OpenClaw dynamic-tool response with its executed mutation identity. */
|
|
6967
|
+
function recordCodexDynamicToolResult(projector, call, response, protocolResponse) {
|
|
6968
|
+
projector?.recordDynamicToolResult({
|
|
6969
|
+
callId: call.callId,
|
|
6970
|
+
tool: call.tool,
|
|
6971
|
+
asyncStarted: response.asyncStarted === true,
|
|
6972
|
+
terminalResolution: response.terminalResolution,
|
|
6973
|
+
success: protocolResponse.success,
|
|
6974
|
+
terminalType: response.diagnosticTerminalType ?? (protocolResponse.success ? "completed" : "error"),
|
|
6975
|
+
sideEffectEvidence: response.sideEffectEvidence === true || response.terminalResolution?.sideEffectEvidence === true,
|
|
6976
|
+
contentItems: protocolResponse.contentItems
|
|
6977
|
+
});
|
|
6978
|
+
}
|
|
6979
|
+
//#endregion
|
|
6958
6980
|
//#region extensions/codex/src/app-server/run-attempt-tools.ts
|
|
6959
6981
|
function toTranscriptToolResult(response) {
|
|
6960
6982
|
const sanitized = sanitizeCodexToolResponse(response);
|
|
@@ -7180,8 +7202,10 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
7180
7202
|
toolBridge,
|
|
7181
7203
|
signal: runAbortController.signal,
|
|
7182
7204
|
timeoutMs: dynamicToolTimeoutMs,
|
|
7205
|
+
toolMeta,
|
|
7183
7206
|
toolCallOrdinal,
|
|
7184
7207
|
onAgentToolResult: params.onAgentToolResult,
|
|
7208
|
+
observeToolTerminal: params.observeToolTerminal,
|
|
7185
7209
|
onFallbackSelected: () => {
|
|
7186
7210
|
if (toolCallOrdinal !== void 0) suppressedDynamicToolOutcomeOrdinals.add(toolCallOrdinal);
|
|
7187
7211
|
},
|
|
@@ -7217,15 +7241,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
7217
7241
|
success: protocolResponse.success,
|
|
7218
7242
|
contentItems: protocolResponse.contentItems
|
|
7219
7243
|
});
|
|
7220
|
-
projector
|
|
7221
|
-
callId: call.callId,
|
|
7222
|
-
tool: call.tool,
|
|
7223
|
-
asyncStarted: response.asyncStarted === true,
|
|
7224
|
-
success: protocolResponse.success,
|
|
7225
|
-
terminalType: response.diagnosticTerminalType ?? (protocolResponse.success ? "completed" : "error"),
|
|
7226
|
-
sideEffectEvidence: response.sideEffectEvidence === true,
|
|
7227
|
-
contentItems: protocolResponse.contentItems
|
|
7228
|
-
});
|
|
7244
|
+
recordCodexDynamicToolResult(projector, call, response, protocolResponse);
|
|
7229
7245
|
if (shouldEmitDynamicToolProgress) {
|
|
7230
7246
|
const progressResponse = toCodexDynamicToolProgressResponse(response, protocolResponse);
|
|
7231
7247
|
emitCodexAppServerEvent(params, {
|
|
@@ -7255,7 +7271,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
7255
7271
|
durationMs: toolDurationMs
|
|
7256
7272
|
});
|
|
7257
7273
|
pendingOpenClawDynamicToolCompletionIds.delete(call.callId);
|
|
7258
|
-
if (response.terminate === true) scheduleTurnReleaseAfterTerminalDynamicTool({
|
|
7274
|
+
if (response.terminate === true && response.success) scheduleTurnReleaseAfterTerminalDynamicTool({
|
|
7259
7275
|
call,
|
|
7260
7276
|
response,
|
|
7261
7277
|
durationMs: toolDurationMs
|
|
@@ -7397,11 +7413,200 @@ function clearComputerUseHealthMonitor(client, monitor) {
|
|
|
7397
7413
|
getComputerUseHealthMonitorState().monitors.delete(client);
|
|
7398
7414
|
}
|
|
7399
7415
|
//#endregion
|
|
7416
|
+
//#region extensions/codex/src/app-server/plugin-metadata-cache.ts
|
|
7417
|
+
const CODEX_PLUGIN_METADATA_CACHE_TTL_MS = 3600 * 1e3;
|
|
7418
|
+
/** Process-local plugin metadata cache with coalesced loads per query. */
|
|
7419
|
+
var CodexPluginMetadataCache = class {
|
|
7420
|
+
constructor(nowMs = Date.now) {
|
|
7421
|
+
this.nowMs = nowMs;
|
|
7422
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
7423
|
+
this.inFlight = /* @__PURE__ */ new Map();
|
|
7424
|
+
this.generations = /* @__PURE__ */ new Map();
|
|
7425
|
+
this.clearGeneration = 0;
|
|
7426
|
+
}
|
|
7427
|
+
/** Returns a fresh cached snapshot without issuing a request. */
|
|
7428
|
+
read(appCacheKey, queryKind) {
|
|
7429
|
+
const entryKey = buildMetadataCacheEntryKey(appCacheKey, queryKind);
|
|
7430
|
+
const entry = this.entries.get(entryKey);
|
|
7431
|
+
if (!entry) return;
|
|
7432
|
+
if (entry.expiresAtMs <= this.nowMs()) {
|
|
7433
|
+
this.entries.delete(entryKey);
|
|
7434
|
+
return;
|
|
7435
|
+
}
|
|
7436
|
+
return entry.snapshot;
|
|
7437
|
+
}
|
|
7438
|
+
/** Returns a fresh cached snapshot or coalesces one plugin/list request. */
|
|
7439
|
+
async load(params) {
|
|
7440
|
+
const entryKey = buildMetadataCacheEntryKey(params.appCacheKey, params.queryKind);
|
|
7441
|
+
const cached = this.read(params.appCacheKey, params.queryKind);
|
|
7442
|
+
if (cached) return cached;
|
|
7443
|
+
const pending = this.inFlight.get(entryKey);
|
|
7444
|
+
if (pending) try {
|
|
7445
|
+
return await pending.promise;
|
|
7446
|
+
} catch {
|
|
7447
|
+
if (this.inFlight.get(entryKey) === pending) this.inFlight.delete(entryKey);
|
|
7448
|
+
return await this.load(params);
|
|
7449
|
+
}
|
|
7450
|
+
const generation = this.generations.get(params.appCacheKey) ?? 0;
|
|
7451
|
+
const clearGeneration = this.clearGeneration;
|
|
7452
|
+
const promise = (async () => {
|
|
7453
|
+
const response = await params.request("plugin/list", params.requestParams);
|
|
7454
|
+
const snapshot = {
|
|
7455
|
+
appCacheKey: params.appCacheKey,
|
|
7456
|
+
queryKind: params.queryKind,
|
|
7457
|
+
response
|
|
7458
|
+
};
|
|
7459
|
+
if (generation === (this.generations.get(params.appCacheKey) ?? 0) && clearGeneration === this.clearGeneration && !hasMarketplaceLoadErrors(response) && (params.cacheable?.(response) ?? true)) this.entries.set(entryKey, {
|
|
7460
|
+
snapshot,
|
|
7461
|
+
expiresAtMs: this.nowMs() + CODEX_PLUGIN_METADATA_CACHE_TTL_MS
|
|
7462
|
+
});
|
|
7463
|
+
return snapshot;
|
|
7464
|
+
})();
|
|
7465
|
+
this.inFlight.set(entryKey, {
|
|
7466
|
+
appCacheKey: params.appCacheKey,
|
|
7467
|
+
promise
|
|
7468
|
+
});
|
|
7469
|
+
try {
|
|
7470
|
+
return await promise;
|
|
7471
|
+
} finally {
|
|
7472
|
+
if (this.inFlight.get(entryKey)?.promise === promise) this.inFlight.delete(entryKey);
|
|
7473
|
+
}
|
|
7474
|
+
}
|
|
7475
|
+
/** Invalidates all plugin metadata queries for one app-server runtime. */
|
|
7476
|
+
invalidate(appCacheKey) {
|
|
7477
|
+
this.generations.set(appCacheKey, (this.generations.get(appCacheKey) ?? 0) + 1);
|
|
7478
|
+
for (const [entryKey, entry] of this.entries) if (entry.snapshot.appCacheKey === appCacheKey) this.entries.delete(entryKey);
|
|
7479
|
+
for (const [entryKey, pending] of this.inFlight) if (pending.appCacheKey === appCacheKey) this.inFlight.delete(entryKey);
|
|
7480
|
+
}
|
|
7481
|
+
/** Clears snapshots and prevents late in-flight loads from repopulating them. */
|
|
7482
|
+
clear() {
|
|
7483
|
+
this.clearGeneration += 1;
|
|
7484
|
+
this.generations.clear();
|
|
7485
|
+
this.entries.clear();
|
|
7486
|
+
this.inFlight.clear();
|
|
7487
|
+
}
|
|
7488
|
+
};
|
|
7489
|
+
/** Shared plugin metadata cache used by Codex app-server runtime paths. */
|
|
7490
|
+
const defaultCodexPluginMetadataCache = new CodexPluginMetadataCache();
|
|
7491
|
+
function hasMarketplaceLoadErrors(response) {
|
|
7492
|
+
return (response.marketplaceLoadErrors?.length ?? 0) > 0;
|
|
7493
|
+
}
|
|
7494
|
+
function buildMetadataCacheEntryKey(appCacheKey, queryKind) {
|
|
7495
|
+
return JSON.stringify([appCacheKey, queryKind]);
|
|
7496
|
+
}
|
|
7497
|
+
//#endregion
|
|
7498
|
+
//#region extensions/codex/src/app-server/plugin-thread-config-deadline.ts
|
|
7499
|
+
/** Enforces one bounded startup budget across Codex plugin config discovery. */
|
|
7500
|
+
const CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS = 5e3;
|
|
7501
|
+
const CODEX_PLUGIN_THREAD_CONFIG_TIMEOUT_DIVISOR = 4;
|
|
7502
|
+
const CODEX_PLUGIN_THREAD_CONFIG_MIN_TIMEOUT_MS = 100;
|
|
7503
|
+
var CodexPluginThreadConfigDeadlineError = class extends Error {
|
|
7504
|
+
constructor() {
|
|
7505
|
+
super("Codex plugin thread config deadline elapsed");
|
|
7506
|
+
this.name = "CodexPluginThreadConfigDeadlineError";
|
|
7507
|
+
}
|
|
7508
|
+
};
|
|
7509
|
+
/** Resolves the plugin policy state reused throughout app-server startup. */
|
|
7510
|
+
function resolveCodexPluginThreadConfigStartupPolicy(params) {
|
|
7511
|
+
const pluginThreadConfigRequired = !params.nativeToolSurfaceEnabled || shouldBuildCodexPluginThreadConfig(params.pluginConfig);
|
|
7512
|
+
const pluginThreadConfigPluginConfig = params.nativeToolSurfaceEnabled ? params.pluginConfig : disableCodexPluginThreadConfig(params.pluginConfig);
|
|
7513
|
+
const resolvedPluginPolicy = pluginThreadConfigRequired ? resolveCodexPluginsPolicy(pluginThreadConfigPluginConfig) : void 0;
|
|
7514
|
+
return {
|
|
7515
|
+
pluginThreadConfigRequired,
|
|
7516
|
+
pluginThreadConfigPluginConfig,
|
|
7517
|
+
resolvedPluginPolicy,
|
|
7518
|
+
enabledPluginConfigKeys: resolvedPluginPolicy ? resolvedPluginPolicy.pluginPolicies.filter((plugin) => plugin.enabled).map((plugin) => plugin.configKey).toSorted() : void 0
|
|
7519
|
+
};
|
|
7520
|
+
}
|
|
7521
|
+
/** Builds plugin config without allowing sequential RPC timeouts to consume the turn. */
|
|
7522
|
+
async function buildCodexPluginThreadConfigWithinDeadline(params) {
|
|
7523
|
+
const { requestTimeoutMs, signal, request, ...buildParams } = params;
|
|
7524
|
+
const timeoutMs = resolveCodexPluginThreadConfigTimeoutMs(requestTimeoutMs);
|
|
7525
|
+
const deadlineMs = Date.now() + timeoutMs;
|
|
7526
|
+
try {
|
|
7527
|
+
return await waitForCodexPluginThreadConfigBuild({
|
|
7528
|
+
signal,
|
|
7529
|
+
timeoutMs,
|
|
7530
|
+
build: () => buildCodexPluginThreadConfig({
|
|
7531
|
+
...buildParams,
|
|
7532
|
+
request: (method, requestParams) => {
|
|
7533
|
+
const remainingTimeoutMs = deadlineMs - Date.now();
|
|
7534
|
+
if (remainingTimeoutMs <= 0) throw new CodexPluginThreadConfigDeadlineError();
|
|
7535
|
+
return request(method, requestParams, {
|
|
7536
|
+
timeoutMs: remainingTimeoutMs,
|
|
7537
|
+
signal
|
|
7538
|
+
});
|
|
7539
|
+
}
|
|
7540
|
+
})
|
|
7541
|
+
});
|
|
7542
|
+
} catch (error) {
|
|
7543
|
+
if (signal.aborted || !isCodexPluginThreadConfigTimeoutError(error)) throw error;
|
|
7544
|
+
return buildCodexPluginThreadConfigTimeoutFallback({
|
|
7545
|
+
pluginConfig: buildParams.pluginConfig,
|
|
7546
|
+
appCacheKey: buildParams.appCacheKey,
|
|
7547
|
+
message: `Codex plugin discovery exceeded its ${timeoutMs} ms startup budget; plugin apps were disabled for this turn.`
|
|
7548
|
+
});
|
|
7549
|
+
}
|
|
7550
|
+
}
|
|
7551
|
+
function waitForCodexPluginThreadConfigBuild(params) {
|
|
7552
|
+
if (params.signal.aborted) return Promise.reject(resolveAbortReason(params.signal));
|
|
7553
|
+
return new Promise((resolve, reject) => {
|
|
7554
|
+
let settled = false;
|
|
7555
|
+
const finish = () => {
|
|
7556
|
+
if (settled) return false;
|
|
7557
|
+
settled = true;
|
|
7558
|
+
clearTimeout(timer);
|
|
7559
|
+
params.signal.removeEventListener("abort", onAbort);
|
|
7560
|
+
return true;
|
|
7561
|
+
};
|
|
7562
|
+
const resolveOnce = (config) => {
|
|
7563
|
+
if (finish()) resolve(config);
|
|
7564
|
+
};
|
|
7565
|
+
const rejectOnce = (error) => {
|
|
7566
|
+
if (finish()) reject(error instanceof Error ? error : new Error(String(error)));
|
|
7567
|
+
};
|
|
7568
|
+
const onAbort = () => rejectOnce(resolveAbortReason(params.signal));
|
|
7569
|
+
const timer = setTimeout(() => rejectOnce(new CodexPluginThreadConfigDeadlineError()), params.timeoutMs);
|
|
7570
|
+
params.signal.addEventListener("abort", onAbort, { once: true });
|
|
7571
|
+
params.build().then(resolveOnce, rejectOnce);
|
|
7572
|
+
});
|
|
7573
|
+
}
|
|
7574
|
+
function resolveAbortReason(signal) {
|
|
7575
|
+
return signal.reason instanceof Error ? signal.reason : /* @__PURE__ */ new Error("Codex plugin thread config aborted");
|
|
7576
|
+
}
|
|
7577
|
+
/** Creates the recovery metadata and bounded builder used by thread startup. */
|
|
7578
|
+
function createCodexPluginThreadConfigStartupProvider(params) {
|
|
7579
|
+
const { client, policy, inputFingerprint, enabledPluginConfigKeys, appCache, metadataCache: configuredMetadataCache, ...buildParams } = params;
|
|
7580
|
+
const metadataCache = configuredMetadataCache ?? defaultCodexPluginMetadataCache;
|
|
7581
|
+
return {
|
|
7582
|
+
enabled: true,
|
|
7583
|
+
inputFingerprint,
|
|
7584
|
+
enabledPluginConfigKeys,
|
|
7585
|
+
accountAppRecoveryEnabled: policy?.allowAllPlugins,
|
|
7586
|
+
recoverablePluginConfigKeys: policy ? resolveRecoverableCodexPluginConfigKeys({
|
|
7587
|
+
policy,
|
|
7588
|
+
metadataCache,
|
|
7589
|
+
appCacheKey: params.appCacheKey
|
|
7590
|
+
}) : void 0,
|
|
7591
|
+
build: () => buildCodexPluginThreadConfigWithinDeadline({
|
|
7592
|
+
...buildParams,
|
|
7593
|
+
appCache: appCache ?? defaultCodexAppInventoryCache,
|
|
7594
|
+
metadataCache,
|
|
7595
|
+
request: (method, requestParams, options) => client.request(method, requestParams, options)
|
|
7596
|
+
})
|
|
7597
|
+
};
|
|
7598
|
+
}
|
|
7599
|
+
function resolveCodexPluginThreadConfigTimeoutMs(requestTimeoutMs) {
|
|
7600
|
+
return Math.min(CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS, Math.max(CODEX_PLUGIN_THREAD_CONFIG_MIN_TIMEOUT_MS, Math.floor((Number.isFinite(requestTimeoutMs) && requestTimeoutMs > 0 ? requestTimeoutMs : CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS * CODEX_PLUGIN_THREAD_CONFIG_TIMEOUT_DIVISOR) / CODEX_PLUGIN_THREAD_CONFIG_TIMEOUT_DIVISOR)));
|
|
7601
|
+
}
|
|
7602
|
+
function isCodexPluginThreadConfigTimeoutError(error) {
|
|
7603
|
+
return error instanceof CodexPluginThreadConfigDeadlineError || error instanceof Error && "code" in error && error.code === "CODEX_APP_SERVER_LOCAL_REQUEST_CANCELLED" && error.message.endsWith(" timed out");
|
|
7604
|
+
}
|
|
7605
|
+
//#endregion
|
|
7400
7606
|
//#region extensions/codex/src/app-server/attempt-startup.ts
|
|
7401
7607
|
/**
|
|
7402
7608
|
* Startup orchestration for Codex app-server attempts, including shared-client
|
|
7403
|
-
* leasing, plugin thread config, sandbox
|
|
7404
|
-
* lifecycle binding.
|
|
7609
|
+
* leasing, plugin thread config, sandbox environment, and thread lifecycle binding.
|
|
7405
7610
|
*/
|
|
7406
7611
|
const CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS = 3;
|
|
7407
7612
|
const CODEX_APP_SERVER_CONTEXT_RESTART_SELECTION_CHANGED = "CODEX_APP_SERVER_CONTEXT_RESTART_SELECTION_CHANGED";
|
|
@@ -7440,13 +7645,12 @@ async function startCodexAttemptThread(params) {
|
|
|
7440
7645
|
},
|
|
7441
7646
|
operation: async () => {
|
|
7442
7647
|
const threadConfig = mergeCodexThreadConfigs(params.bundleMcpThreadConfig?.configPatch);
|
|
7443
|
-
const pluginThreadConfigRequired
|
|
7444
|
-
|
|
7445
|
-
|
|
7648
|
+
const { pluginThreadConfigRequired, pluginThreadConfigPluginConfig, resolvedPluginPolicy, enabledPluginConfigKeys } = resolveCodexPluginThreadConfigStartupPolicy({
|
|
7649
|
+
pluginConfig: params.pluginConfig,
|
|
7650
|
+
nativeToolSurfaceEnabled: params.nativeToolSurfaceEnabled
|
|
7651
|
+
});
|
|
7446
7652
|
const computerUseMcpElicitationDelegationRequired = params.computerUseConfig.enabled;
|
|
7447
|
-
|
|
7448
|
-
const enabledPluginConfigKeys = resolvedPluginPolicy ? resolvedPluginPolicy.pluginPolicies.filter((plugin) => plugin.enabled).map((plugin) => plugin.configKey).toSorted() : void 0;
|
|
7449
|
-
pluginAppServer = mcpElicitationDelegationRequired ? {
|
|
7653
|
+
pluginAppServer = resolvedPluginPolicy?.enabled === true || computerUseMcpElicitationDelegationRequired ? {
|
|
7450
7654
|
...params.appServer,
|
|
7451
7655
|
approvalPolicy: withMcpElicitationsApprovalPolicy(params.appServer.approvalPolicy)
|
|
7452
7656
|
} : params.appServer;
|
|
@@ -7461,6 +7665,7 @@ async function startCodexAttemptThread(params) {
|
|
|
7461
7665
|
startupClient = await params.attemptClientFactory({
|
|
7462
7666
|
startOptions: params.appServer.start,
|
|
7463
7667
|
...params.startupPreparedAuth ? { preparedAuth: params.startupPreparedAuth } : { authProfileId: params.startupAuthProfileId },
|
|
7668
|
+
authRequirement: params.startupAuthRequirement,
|
|
7464
7669
|
authProfileStore: attemptParams.authProfileStore,
|
|
7465
7670
|
authBindingFingerprint: params.startupAuthBindingFingerprint,
|
|
7466
7671
|
...params.runtimeArtifactRequest ? {
|
|
@@ -7486,8 +7691,8 @@ async function startCodexAttemptThread(params) {
|
|
|
7486
7691
|
releaseSharedClientLease = startupClientLease;
|
|
7487
7692
|
attemptedClient = activeStartupClient;
|
|
7488
7693
|
startupClientForAbandonedRequestCleanup = activeStartupClient;
|
|
7489
|
-
if (startupAbandoned) throw new
|
|
7490
|
-
if (startupAbandonController.signal.aborted) throw new
|
|
7694
|
+
if (startupAbandoned) throw new CodexAppServerStartupError("timed_out");
|
|
7695
|
+
if (startupAbandonController.signal.aborted) throw new CodexAppServerStartupError("aborted");
|
|
7491
7696
|
let runtimeArtifact;
|
|
7492
7697
|
if (params.runtimeArtifactRequest) {
|
|
7493
7698
|
const { readCodexAppServerClientRuntimeArtifact, validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-C2ITXdhM.js");
|
|
@@ -7568,7 +7773,7 @@ async function startCodexAttemptThread(params) {
|
|
|
7568
7773
|
startupSandboxEnvironmentAcquired = Boolean(startupSandboxEnvironment);
|
|
7569
7774
|
if (startupAbandonController.signal.aborted) {
|
|
7570
7775
|
await releaseStartupSandboxEnvironment();
|
|
7571
|
-
throw new
|
|
7776
|
+
throw new CodexAppServerStartupError("aborted");
|
|
7572
7777
|
}
|
|
7573
7778
|
if (params.sandbox?.enabled && params.nativeToolSurfaceEnabled && params.sandboxExecServerEnabled && !startupSandboxEnvironment) throw new Error("Codex app-server did not register an OpenClaw sandbox exec-server environment.");
|
|
7574
7779
|
} catch (error) {
|
|
@@ -7631,21 +7836,17 @@ async function startCodexAttemptThread(params) {
|
|
|
7631
7836
|
appServerRuntimeFingerprint,
|
|
7632
7837
|
contextEngineProjection: params.contextEngineProjection,
|
|
7633
7838
|
signal,
|
|
7634
|
-
pluginThreadConfig: pluginThreadConfigRequired ? {
|
|
7635
|
-
enabled: true,
|
|
7839
|
+
pluginThreadConfig: pluginThreadConfigRequired ? createCodexPluginThreadConfigStartupProvider({
|
|
7636
7840
|
inputFingerprint: pluginThreadConfigInputFingerprint,
|
|
7637
7841
|
enabledPluginConfigKeys,
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
appCacheKey: pluginAppCacheKey
|
|
7647
|
-
})
|
|
7648
|
-
} : void 0
|
|
7842
|
+
policy: resolvedPluginPolicy,
|
|
7843
|
+
requestTimeoutMs: params.appServer.requestTimeoutMs,
|
|
7844
|
+
signal,
|
|
7845
|
+
pluginConfig: pluginThreadConfigPluginConfig,
|
|
7846
|
+
client: activeStartupClient,
|
|
7847
|
+
configCwd: startupExecutionCwd,
|
|
7848
|
+
appCacheKey: pluginAppCacheKey
|
|
7849
|
+
}) : void 0
|
|
7649
7850
|
});
|
|
7650
7851
|
try {
|
|
7651
7852
|
const startupThread = await startOrResumeThread(buildThreadLifecycleParams(startupAbandonController.signal, reserveStartupThread));
|
|
@@ -7658,7 +7859,7 @@ async function startCodexAttemptThread(params) {
|
|
|
7658
7859
|
})) throw new CodexAppServerUnsafeSubscriptionError("Codex startup subscription cleanup failed", { cause: error });
|
|
7659
7860
|
throw error;
|
|
7660
7861
|
}
|
|
7661
|
-
if (startupAbandonController.signal.aborted) throw new
|
|
7862
|
+
if (startupAbandonController.signal.aborted) throw new CodexAppServerStartupError("aborted");
|
|
7662
7863
|
const startupRoute = startupReservation;
|
|
7663
7864
|
if (!startupRoute) throw new Error("codex app-server startup did not reserve its thread route");
|
|
7664
7865
|
startupSandboxEnvironmentAcquired = false;
|
|
@@ -7773,14 +7974,14 @@ async function startCodexAttemptThread(params) {
|
|
|
7773
7974
|
}
|
|
7774
7975
|
}
|
|
7775
7976
|
function shouldClearSharedClientAfterStartupAbandon(error) {
|
|
7776
|
-
return
|
|
7977
|
+
return isCodexAppServerStartupError(error);
|
|
7777
7978
|
}
|
|
7778
7979
|
function shouldClearSharedClientAfterStartupRace(error) {
|
|
7779
|
-
return
|
|
7980
|
+
return shouldClearSharedClientAfterStartupAbandon(error) || isCodexAppServerRequestTimeoutError(error);
|
|
7780
7981
|
}
|
|
7781
7982
|
function shouldClearSharedClientAfterStartupFailure(params) {
|
|
7782
7983
|
if (!(params.error instanceof Error)) return !params.spawnedBy;
|
|
7783
|
-
if (params.error
|
|
7984
|
+
if (isCodexAppServerBrokenPipeError(params.error)) return true;
|
|
7784
7985
|
return !params.spawnedBy;
|
|
7785
7986
|
}
|
|
7786
7987
|
//#endregion
|
|
@@ -7791,7 +7992,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
7791
7992
|
const { runtime, attemptTools, promptState } = context;
|
|
7792
7993
|
const { connection, runtimeParams, preparedAuthBinding, buildActiveRunAttemptParams, startupAuthAccountCacheKey, startupEnvApiKeyCacheKey, bundleMcpThreadConfig, nativeToolSurfaceEnabled, nativeProviderWebSearchSupport, sandboxExecServerEnabled } = runtime;
|
|
7793
7994
|
const { toolBridge, toolState } = attemptTools;
|
|
7794
|
-
const { params, attemptClientFactory, bindingStore, appServer, pluginConfig, computerUseConfig, startupClientAuthProfileId, runtimeArtifactRequest, startupPreparedAuth, agentDir, sessionAgentId, effectiveWorkspace, effectiveCwd, sandbox, runAbortController, usesSupervisionConnection, resolveReviewerPolicyContext, resolveRuntimeOptionsForCurrentBinding, startupAuthProfileId, abortFromUpstream } = connection;
|
|
7995
|
+
const { params, attemptClientFactory, bindingStore, appServer, pluginConfig, computerUseConfig, startupClientAuthProfileId, runtimeArtifactRequest, startupPreparedAuth, agentDir, sessionAgentId, effectiveWorkspace, effectiveCwd, sandbox, runAbortController, usesSupervisionConnection, resolveReviewerPolicyContext, resolveRuntimeOptionsForCurrentBinding, startupAuthProfileId, startupAuthRequirement, abortFromUpstream } = connection;
|
|
7795
7996
|
let pluginAppServer = withCodexAppServerFastModeServiceTier(appServer, runtimeParams);
|
|
7796
7997
|
try {
|
|
7797
7998
|
emitCodexAppServerEvent(params, {
|
|
@@ -7805,6 +8006,7 @@ async function startCodexAttemptRuntime(resources) {
|
|
|
7805
8006
|
pluginConfig,
|
|
7806
8007
|
computerUseConfig,
|
|
7807
8008
|
startupAuthProfileId: startupClientAuthProfileId,
|
|
8009
|
+
startupAuthRequirement,
|
|
7808
8010
|
startupAuthBindingFingerprint: preparedAuthBinding?.fingerprint,
|
|
7809
8011
|
...runtimeArtifactRequest ? { runtimeArtifactRequest } : {},
|
|
7810
8012
|
startupPreparedAuth,
|
|
@@ -8385,6 +8587,7 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
8385
8587
|
return { result: buildCodexTurnStartFailureResult({
|
|
8386
8588
|
params,
|
|
8387
8589
|
message: usageLimitError.message,
|
|
8590
|
+
promptError: createCodexUsageLimitPromptError(usageLimitError.message),
|
|
8388
8591
|
messagesSnapshot,
|
|
8389
8592
|
systemPromptReport
|
|
8390
8593
|
}) };
|
|
@@ -8771,6 +8974,7 @@ function createCodexAttemptTurnState(resources) {
|
|
|
8771
8974
|
rateLimitsRevisionBeforeLastTurnStart: void 0,
|
|
8772
8975
|
completed: false,
|
|
8773
8976
|
terminalTurnNotificationQueued: false,
|
|
8977
|
+
sawCodexInterruptMarker: false,
|
|
8774
8978
|
timedOut: false,
|
|
8775
8979
|
turnCompletionIdleTimedOut: false,
|
|
8776
8980
|
turnWatchTimeoutKind: void 0,
|