@openclaw/codex 2026.6.1 → 2026.6.5-beta.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/client-factory-Bt49r45B.js +17 -0
- package/dist/{client-BnOmn0y-.js → client-kMCtlApt.js} +43 -1
- package/dist/{command-handlers-VhJdcXcI.js → command-handlers-DMn2M7W7.js} +10 -10
- package/dist/{compact-D1dSrNrT.js → compact-CwnPeYnM.js} +16 -5
- package/dist/{computer-use-DYLSxIfq.js → computer-use-ClweWaMz.js} +12 -2
- package/dist/{config-AlzuNKCY.js → config-BT6SLiE6.js} +4 -12
- package/dist/{conversation-binding-CqVPKJPp.js → conversation-binding-CzpvaBs1.js} +8 -8
- package/dist/doctor-contract-api.js +5 -0
- package/dist/harness.js +9 -5
- package/dist/index.js +12 -13
- package/dist/media-understanding-provider.js +14 -6
- package/dist/{models-DAJvlyJu.js → models-DXorTaja.js} +9 -2
- package/dist/{native-hook-relay-CIJt8cLN.js → native-hook-relay-DZ3Oon0b.js} +61 -3
- package/dist/{notification-correlation-BykOI_jh.js → notification-correlation-o8quHmTK.js} +30 -1
- package/dist/prompt-overlay.js +7 -0
- package/dist/{protocol-validators-DIt7cXIp.js → protocol-validators-CIpP8IJ2.js} +13 -0
- package/dist/provider-catalog.js +8 -0
- package/dist/provider-discovery.js +1 -0
- package/dist/provider.js +17 -2
- package/dist/{rate-limit-cache-N66I-Rd7.js → rate-limit-cache-C7qmZ0Jh.js} +2 -0
- package/dist/{request-CPtFWp-f.js → request-D64BfplD.js} +16 -4
- package/dist/{run-attempt-DM53zFlW.js → run-attempt-B_6VkFQN.js} +432 -35
- package/dist/{sandbox-guard-DMCJlzmz.js → sandbox-guard-C-Yv9uwY.js} +5 -0
- package/dist/{session-binding-DWiEGATW.js → session-binding-BgTv_YGm.js} +13 -2
- package/dist/{shared-client-DUWLidr5.js → shared-client-xytpSKD0.js} +92 -5
- package/dist/{side-question-dIZf9RBV.js → side-question-BEpALo9c.js} +10 -10
- package/dist/{thread-lifecycle-6nrEQZMV.js → thread-lifecycle-BJsazZ8j.js} +79 -46
- package/npm-shrinkwrap.json +2 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +4 -4
- package/dist/client-factory-3ykiiX2z.js +0 -20
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-
|
|
3
|
-
import { a as isCodexAppServerConnectionClosedError, i as isCodexAppServerApprovalRequest, l as isJsonObject, r as compareCodexAppServerVersions, s as MIN_CODEX_SANDBOX_EXEC_SERVER_APP_SERVER_VERSION } from "./client-
|
|
4
|
-
import { A as projectContextEngineAssemblyForCodex, C as sanitizeCodexHistoryImagePayloads, D as normalizeCodexDynamicToolName$1, E as isForcedPrivateQaCodexRuntime, M as resolveCodexContextEngineProjectionReserveTokens, T as filterCodexDynamicTools, _ as shouldBuildCodexPluginThreadConfig, a as buildDeveloperInstructions, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as mergeCodexThreadConfigs, h as buildCodexPluginThreadConfigInputFingerprint, i as buildContextEngineBinding, j as resolveCodexContextEngineProjectionMaxChars, k as resolveCodexDynamicToolsLoadingForModel, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfig, n as areCodexDynamicToolFingerprintsCompatible, o as buildTurnCollaborationMode, p as isCodexAppServerProfilerEnabled, s as buildTurnStartParams, x as defaultCodexAppInventoryCache } from "./thread-lifecycle-
|
|
5
|
-
import { a as readCodexAppServerBinding, n as clearCodexAppServerBindingForThread, s as writeCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-
|
|
6
|
-
import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-
|
|
7
|
-
import { _ as shouldRefreshCodexRateLimitsForUsageLimitMessage, g as resolveCodexUsageLimitResetAtMs, h as formatCodexUsageLimitErrorMessage, i as readCodexNotificationTurnId, n as isCodexNotificationForTurn, r as readCodexNotificationThreadId, s as formatCodexDisplayText, t as describeCodexNotificationCorrelation } from "./notification-correlation-
|
|
8
|
-
import {
|
|
9
|
-
import { i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-
|
|
10
|
-
import {
|
|
11
|
-
import { S as withCodexStartupTimeout, _ as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, a as createCodexNativeHookRelay, b as resolveCodexTurnCompletionIdleTimeoutMs, c as scheduleCodexNativeHookRelayUnregister, d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, g as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, h as handleCodexAppServerApprovalRequest, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerElicitationRequest, m as filterToolsForVisionInputs, n as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, o as resolveCodexNativeHookRelayEvents, p as emitDynamicToolTerminalDiagnostic, r as buildCodexNativeHookRelayConfig, s as resolveCodexNativeHookRelayTtlMs, u as createCodexDynamicToolBridge, v as resolveCodexStartupTimeoutMs, x as resolveCodexTurnTerminalIdleTimeoutMs, y as resolveCodexTurnAssistantCompletionIdleTimeoutMs } from "./native-hook-relay-
|
|
12
|
-
import { t as ensureCodexComputerUse } from "./computer-use-
|
|
13
|
-
import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-
|
|
1
|
+
import { c as readCodexPluginConfig, d as resolveCodexPluginsPolicy, f as resolveOpenClawExecPolicyForCodexAppServer, i as isCodexAppServerApprovalPolicyAllowedByRequirements, l as resolveCodexAppServerRuntimeOptions, m as withMcpElicitationsApprovalPolicy, o as isCodexSandboxExecServerEnabled, p as shouldAutoApproveCodexAppServerApprovals, u as resolveCodexComputerUseConfig } from "./config-BT6SLiE6.js";
|
|
2
|
+
import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-CIpP8IJ2.js";
|
|
3
|
+
import { a as isCodexAppServerConnectionClosedError, i as isCodexAppServerApprovalRequest, l as isJsonObject, r as compareCodexAppServerVersions, s as MIN_CODEX_SANDBOX_EXEC_SERVER_APP_SERVER_VERSION } from "./client-kMCtlApt.js";
|
|
4
|
+
import { A as projectContextEngineAssemblyForCodex, C as sanitizeCodexHistoryImagePayloads, D as normalizeCodexDynamicToolName$1, E as isForcedPrivateQaCodexRuntime, M as resolveCodexContextEngineProjectionReserveTokens, T as filterCodexDynamicTools, _ as shouldBuildCodexPluginThreadConfig, a as buildDeveloperInstructions, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as mergeCodexThreadConfigs, h as buildCodexPluginThreadConfigInputFingerprint, i as buildContextEngineBinding, j as resolveCodexContextEngineProjectionMaxChars, k as resolveCodexDynamicToolsLoadingForModel, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfig, n as areCodexDynamicToolFingerprintsCompatible, o as buildTurnCollaborationMode, p as isCodexAppServerProfilerEnabled, s as buildTurnStartParams, x as defaultCodexAppInventoryCache } from "./thread-lifecycle-BJsazZ8j.js";
|
|
5
|
+
import { a as readCodexAppServerBinding, n as clearCodexAppServerBindingForThread, s as writeCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-BgTv_YGm.js";
|
|
6
|
+
import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-D64BfplD.js";
|
|
7
|
+
import { _ as shouldRefreshCodexRateLimitsForUsageLimitMessage, g as resolveCodexUsageLimitResetAtMs, h as formatCodexUsageLimitErrorMessage, i as readCodexNotificationTurnId, n as isCodexNotificationForTurn, r as readCodexNotificationThreadId, s as formatCodexDisplayText, t as describeCodexNotificationCorrelation } from "./notification-correlation-o8quHmTK.js";
|
|
8
|
+
import { d as resolveCodexAppServerAuthAccountCacheKey, f as resolveCodexAppServerAuthProfileId, h as resolveCodexAppServerHomeDir, m as resolveCodexAppServerFallbackApiKeyCacheKey, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as releaseLeasedSharedCodexAppServerClient, p as resolveCodexAppServerAuthProfileIdForAgent, s as retireSharedCodexAppServerClientIfCurrent, t as clearSharedCodexAppServerClientIfCurrent, u as refreshCodexAppServerAuthTokens } from "./shared-client-xytpSKD0.js";
|
|
9
|
+
import { i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-C-Yv9uwY.js";
|
|
10
|
+
import { t as defaultLeasedCodexAppServerClientFactory } from "./client-factory-Bt49r45B.js";
|
|
11
|
+
import { S as withCodexStartupTimeout, _ as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, a as createCodexNativeHookRelay, b as resolveCodexTurnCompletionIdleTimeoutMs, c as scheduleCodexNativeHookRelayUnregister, d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, g as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, h as handleCodexAppServerApprovalRequest, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerElicitationRequest, m as filterToolsForVisionInputs, n as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, o as resolveCodexNativeHookRelayEvents, p as emitDynamicToolTerminalDiagnostic, r as buildCodexNativeHookRelayConfig, s as resolveCodexNativeHookRelayTtlMs, u as createCodexDynamicToolBridge, v as resolveCodexStartupTimeoutMs, x as resolveCodexTurnTerminalIdleTimeoutMs, y as resolveCodexTurnAssistantCompletionIdleTimeoutMs } from "./native-hook-relay-DZ3Oon0b.js";
|
|
12
|
+
import { t as ensureCodexComputerUse } from "./computer-use-ClweWaMz.js";
|
|
13
|
+
import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-C7qmZ0Jh.js";
|
|
14
14
|
import { asDateTimestampMs, parseStrictNonNegativeInteger, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
15
15
|
import { createHash, randomUUID } from "node:crypto";
|
|
16
16
|
import fsSync from "node:fs";
|
|
@@ -33,6 +33,10 @@ import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generat
|
|
|
33
33
|
import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
34
34
|
import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
|
|
35
35
|
//#region extensions/codex/src/app-server/app-server-policy.ts
|
|
36
|
+
/**
|
|
37
|
+
* Promotes implicit `never` approval policy to `untrusted` only when runtime
|
|
38
|
+
* requirements allow OpenClaw to handle tool approvals.
|
|
39
|
+
*/
|
|
36
40
|
function resolveCodexAppServerForOpenClawToolPolicy(params) {
|
|
37
41
|
if (!params.shouldPromote || !params.canUseUntrustedApprovalPolicy || params.appServer.approvalPolicy !== "never") return params.appServer;
|
|
38
42
|
const explicitMode = params.execPolicy?.mode === "full" || params.pluginConfig.appServer?.mode !== void 0 || isCodexAppServerPolicyMode(params.env.OPENCLAW_CODEX_APP_SERVER_MODE);
|
|
@@ -51,8 +55,14 @@ function isCodexAppServerApprovalPolicy(value) {
|
|
|
51
55
|
}
|
|
52
56
|
//#endregion
|
|
53
57
|
//#region extensions/codex/src/app-server/attempt-client-cleanup.ts
|
|
58
|
+
/**
|
|
59
|
+
* Best-effort cleanup helpers for timed-out or aborted Codex app-server turns.
|
|
60
|
+
*/
|
|
61
|
+
/** Timeout for best-effort app-server turn interruption during cleanup. */
|
|
54
62
|
const CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS = 5e3;
|
|
63
|
+
/** Timeout for best-effort thread unsubscribe during cleanup. */
|
|
55
64
|
const CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS = 5e3;
|
|
65
|
+
/** Sends a turn interrupt without blocking abort cleanup on app-server errors. */
|
|
56
66
|
function interruptCodexTurnBestEffort(client, params) {
|
|
57
67
|
const requestOptions = params.timeoutMs && Number.isFinite(params.timeoutMs) && params.timeoutMs > 0 ? { timeoutMs: params.timeoutMs } : void 0;
|
|
58
68
|
const requestParams = {
|
|
@@ -68,6 +78,7 @@ function interruptCodexTurnBestEffort(client, params) {
|
|
|
68
78
|
embeddedAgentLog.debug("codex app-server turn interrupt failed during abort", { error });
|
|
69
79
|
}
|
|
70
80
|
}
|
|
81
|
+
/** Unsubscribes from a thread while swallowing cleanup-only failures. */
|
|
71
82
|
async function unsubscribeCodexThreadBestEffort(client, params) {
|
|
72
83
|
try {
|
|
73
84
|
await client.request("thread/unsubscribe", { threadId: params.threadId }, { timeoutMs: params.timeoutMs });
|
|
@@ -78,6 +89,10 @@ async function unsubscribeCodexThreadBestEffort(client, params) {
|
|
|
78
89
|
});
|
|
79
90
|
}
|
|
80
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Retires the shared client after a timed-out turn so later runs do not reuse a
|
|
94
|
+
* potentially wedged app-server connection.
|
|
95
|
+
*/
|
|
81
96
|
async function retireCodexAppServerClientAfterTimedOutTurn(client, params) {
|
|
82
97
|
const retiredSharedClient = retireSharedCodexAppServerClientIfCurrent(client);
|
|
83
98
|
const detachedSharedClient = Boolean(retiredSharedClient);
|
|
@@ -115,9 +130,14 @@ async function retireCodexAppServerClientAfterTimedOutTurn(client, params) {
|
|
|
115
130
|
}
|
|
116
131
|
//#endregion
|
|
117
132
|
//#region extensions/codex/src/app-server/session-history.ts
|
|
133
|
+
/**
|
|
134
|
+
* Reads OpenClaw session history for Codex transcript mirroring and sanitizes
|
|
135
|
+
* image payloads before replaying messages into the app-server projector.
|
|
136
|
+
*/
|
|
118
137
|
function isMissingFileError(error) {
|
|
119
138
|
return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
|
|
120
139
|
}
|
|
140
|
+
/** Returns sanitized session-context messages for a Codex mirrored session file. */
|
|
121
141
|
async function readCodexMirroredSessionHistoryMessages(sessionFile) {
|
|
122
142
|
try {
|
|
123
143
|
const entries = parseSessionEntries(await fs.readFile(sessionFile, "utf-8"));
|
|
@@ -132,6 +152,10 @@ async function readCodexMirroredSessionHistoryMessages(sessionFile) {
|
|
|
132
152
|
}
|
|
133
153
|
//#endregion
|
|
134
154
|
//#region extensions/codex/src/app-server/attempt-context.ts
|
|
155
|
+
/**
|
|
156
|
+
* Builds Codex app-server prompt context, workspace bootstrap injections,
|
|
157
|
+
* system-prompt reports, and context-engine projection decisions.
|
|
158
|
+
*/
|
|
135
159
|
const CODEX_NATIVE_PROJECT_DOC_BASENAMES = new Set(["agents.md"]);
|
|
136
160
|
const CODEX_INHERITED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = new Set(["tools.md"]);
|
|
137
161
|
const CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = new Set([
|
|
@@ -152,11 +176,13 @@ const CODEX_BOOTSTRAP_CONTEXT_ORDER = new Map([
|
|
|
152
176
|
["memory.md", 60],
|
|
153
177
|
["heartbeat.md", 70]
|
|
154
178
|
]);
|
|
179
|
+
/** Reads mirrored Codex session history for harness hooks. */
|
|
155
180
|
async function readMirroredSessionHistoryMessages(sessionFile) {
|
|
156
181
|
const messages = await readCodexMirroredSessionHistoryMessages(sessionFile);
|
|
157
182
|
if (!messages) embeddedAgentLog.warn("failed to read mirrored session history for codex harness hooks", { sessionFile });
|
|
158
183
|
return messages;
|
|
159
184
|
}
|
|
185
|
+
/** Reads a valid thread-bootstrap projection request from context-engine output. */
|
|
160
186
|
function readContextEngineThreadBootstrapProjection(projection) {
|
|
161
187
|
if (projection?.mode !== "thread_bootstrap") return;
|
|
162
188
|
const epoch = projection.epoch?.trim();
|
|
@@ -171,6 +197,10 @@ function readContextEngineThreadBootstrapProjection(projection) {
|
|
|
171
197
|
...fingerprint ? { fingerprint } : {}
|
|
172
198
|
};
|
|
173
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Decides whether an existing Codex thread can reuse its context-engine
|
|
202
|
+
* bootstrap projection or must be reprojected.
|
|
203
|
+
*/
|
|
174
204
|
function resolveContextEngineBootstrapProjectionDecision(params) {
|
|
175
205
|
const bindingProjection = params.startupBinding?.contextEngine?.projection;
|
|
176
206
|
if (!params.startupBinding?.threadId || !bindingProjection) return {
|
|
@@ -196,6 +226,10 @@ function resolveContextEngineBootstrapProjectionDecision(params) {
|
|
|
196
226
|
reason: "matching-thread-bootstrap-binding"
|
|
197
227
|
};
|
|
198
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Loads workspace bootstrap files and partitions them into Codex-native prompt,
|
|
231
|
+
* developer-instruction, heartbeat, and memory-tool contexts.
|
|
232
|
+
*/
|
|
199
233
|
async function buildCodexWorkspaceBootstrapContext(params) {
|
|
200
234
|
try {
|
|
201
235
|
const memoryToolsAvailable = params.memoryToolNames.length > 0 && canRouteCodexWorkspaceMemoryThroughTools({
|
|
@@ -269,6 +303,10 @@ async function buildCodexWorkspaceBootstrapContext(params) {
|
|
|
269
303
|
};
|
|
270
304
|
}
|
|
271
305
|
}
|
|
306
|
+
/**
|
|
307
|
+
* Builds the prompt-size, bootstrap-file, skill, and tool-schema accounting
|
|
308
|
+
* report for a Codex run.
|
|
309
|
+
*/
|
|
272
310
|
function buildCodexSystemPromptReport(params) {
|
|
273
311
|
const toolEntries = params.tools.map(buildCodexToolReportEntry);
|
|
274
312
|
const schemaChars = toolEntries.reduce((sum, tool) => sum + tool.schemaChars, 0);
|
|
@@ -427,6 +465,9 @@ function readPositiveNumber(value) {
|
|
|
427
465
|
function readNonEmptyString$1(value) {
|
|
428
466
|
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
429
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* Builds OpenClaw-provided workspace prompt context for the current Codex turn.
|
|
470
|
+
*/
|
|
430
471
|
function buildCodexOpenClawPromptContext(params) {
|
|
431
472
|
if (!shouldInjectCodexOpenClawPromptContext(params.params)) return;
|
|
432
473
|
const sections = [params.workspacePromptContext?.trim() ? [
|
|
@@ -445,6 +486,7 @@ function buildCodexOpenClawPromptContext(params) {
|
|
|
445
486
|
function shouldInjectCodexOpenClawPromptContext(params) {
|
|
446
487
|
return !(params.bootstrapContextMode === "lightweight" && params.bootstrapContextRunKind === "cron");
|
|
447
488
|
}
|
|
489
|
+
/** Renders loaded OpenClaw skill prompts as Codex collaboration instructions. */
|
|
448
490
|
function renderCodexSkillsCollaborationInstructions(params) {
|
|
449
491
|
if (!shouldInjectCodexOpenClawPromptContext(params.attempt)) return;
|
|
450
492
|
return params.skillsPrompt?.trim() ? [
|
|
@@ -453,6 +495,10 @@ function renderCodexSkillsCollaborationInstructions(params) {
|
|
|
453
495
|
params.skillsPrompt.trim()
|
|
454
496
|
].join("\n") : void 0;
|
|
455
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* Prepends OpenClaw context while preserving leading delivery metadata as
|
|
500
|
+
* routing guidance instead of user request text.
|
|
501
|
+
*/
|
|
456
502
|
function prependCodexOpenClawPromptContext(prompt, context, options = {}) {
|
|
457
503
|
const { deliveryHint, prompt: promptWithoutDeliveryHint } = splitLeadingCodexDeliveryHint(prompt);
|
|
458
504
|
if (!context?.trim() && (!deliveryHint || options.preservePromptWithoutContext)) return prompt;
|
|
@@ -567,6 +613,10 @@ function selectCodexWorkspaceMemoryReferenceFiles(params) {
|
|
|
567
613
|
}) && !file.missing && (file.content ?? "").trim().length > 0;
|
|
568
614
|
}).toSorted(compareCodexBootstrapFiles);
|
|
569
615
|
}
|
|
616
|
+
/**
|
|
617
|
+
* Renders a memory-file reference that points Codex at memory tools instead of
|
|
618
|
+
* embedding MEMORY.md contents.
|
|
619
|
+
*/
|
|
570
620
|
function renderCodexWorkspaceMemoryReference(params) {
|
|
571
621
|
if (params.files.length === 0) return;
|
|
572
622
|
const lines = [
|
|
@@ -578,6 +628,7 @@ function renderCodexWorkspaceMemoryReference(params) {
|
|
|
578
628
|
for (const file of params.files) lines.push(`- ${file.path}`);
|
|
579
629
|
return lines.join("\n").trim();
|
|
580
630
|
}
|
|
631
|
+
/** Lists available memory tool names understood by Codex workspace memory routing. */
|
|
581
632
|
function getCodexWorkspaceMemoryToolNames(tools) {
|
|
582
633
|
const availableToolNames = new Set(tools.map((tool) => normalizeCodexDynamicToolName(tool.name)));
|
|
583
634
|
return Array.from(CODEX_MEMORY_TOOL_NAMES).filter((name) => availableToolNames.has(name));
|
|
@@ -616,6 +667,10 @@ function isCodexWorkspaceRootMemoryPath(params) {
|
|
|
616
667
|
function isSameCodexWorkspacePath(left, right) {
|
|
617
668
|
return path.resolve(left) === path.resolve(right);
|
|
618
669
|
}
|
|
670
|
+
/**
|
|
671
|
+
* Remaps bootstrap file paths from the resolved workspace to the effective Codex
|
|
672
|
+
* workspace while preserving platform path separators.
|
|
673
|
+
*/
|
|
619
674
|
function remapCodexContextFilePath(params) {
|
|
620
675
|
const relativePath = path.relative(params.sourceWorkspaceDir, params.file.path);
|
|
621
676
|
if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath) || params.sourceWorkspaceDir === params.targetWorkspaceDir) return params.file;
|
|
@@ -657,9 +712,15 @@ function isNonEmptyString$2(value) {
|
|
|
657
712
|
}
|
|
658
713
|
//#endregion
|
|
659
714
|
//#region extensions/codex/src/app-server/attempt-diagnostics.ts
|
|
715
|
+
/**
|
|
716
|
+
* Diagnostic helpers for Codex app-server model calls and plugin-thread config
|
|
717
|
+
* eligibility.
|
|
718
|
+
*/
|
|
719
|
+
/** Reads a tool schema field in either app-server or OpenClaw naming. */
|
|
660
720
|
function readCodexDiagnosticToolParameters(tool) {
|
|
661
721
|
return tool.inputSchema ?? tool.parameters;
|
|
662
722
|
}
|
|
723
|
+
/** Builds compact diagnostic tool definitions for trusted private telemetry. */
|
|
663
724
|
function buildCodexDiagnosticToolDefinitions(tools) {
|
|
664
725
|
return tools.map((tool) => ({
|
|
665
726
|
name: tool.name,
|
|
@@ -667,6 +728,7 @@ function buildCodexDiagnosticToolDefinitions(tools) {
|
|
|
667
728
|
parameters: readCodexDiagnosticToolParameters(tool)
|
|
668
729
|
}));
|
|
669
730
|
}
|
|
731
|
+
/** Returns the serialized UTF-8 byte length for a JSON-compatible value. */
|
|
670
732
|
function utf8JsonByteLength(value) {
|
|
671
733
|
try {
|
|
672
734
|
return Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
@@ -674,6 +736,7 @@ function utf8JsonByteLength(value) {
|
|
|
674
736
|
return;
|
|
675
737
|
}
|
|
676
738
|
}
|
|
739
|
+
/** Builds a short namespaced fingerprint for sensitive log values. */
|
|
677
740
|
function fingerprintCodexLogValue(namespace, value) {
|
|
678
741
|
const hash = createHash("sha256");
|
|
679
742
|
hash.update(namespace);
|
|
@@ -681,6 +744,10 @@ function fingerprintCodexLogValue(namespace, value) {
|
|
|
681
744
|
hash.update(value);
|
|
682
745
|
return `sha256:${hash.digest("hex").slice(0, 16)}`;
|
|
683
746
|
}
|
|
747
|
+
/**
|
|
748
|
+
* Builds redacted diagnostics explaining whether plugin thread config was
|
|
749
|
+
* eligible for a Codex app-server attempt.
|
|
750
|
+
*/
|
|
684
751
|
function buildCodexPluginThreadConfigEligibilityLogData(params) {
|
|
685
752
|
return {
|
|
686
753
|
sessionId: params.sessionId,
|
|
@@ -696,6 +763,10 @@ function buildCodexPluginThreadConfigEligibilityLogData(params) {
|
|
|
696
763
|
appServerCommandSource: params.appServer.start.commandSource
|
|
697
764
|
};
|
|
698
765
|
}
|
|
766
|
+
/**
|
|
767
|
+
* Creates lifecycle emitters for trusted model-call diagnostics with optional
|
|
768
|
+
* private payload capture.
|
|
769
|
+
*/
|
|
699
770
|
function createCodexModelCallDiagnosticEmitter(params) {
|
|
700
771
|
const now = params.now ?? (() => Date.now());
|
|
701
772
|
const toolDefinitions = params.capture.toolDefinitions ? buildCodexDiagnosticToolDefinitions(params.tools) : void 0;
|
|
@@ -756,6 +827,7 @@ function createCodexModelCallDiagnosticEmitter(params) {
|
|
|
756
827
|
}
|
|
757
828
|
};
|
|
758
829
|
}
|
|
830
|
+
/** Classifies model-call failures into timeout/abort buckets for diagnostics. */
|
|
759
831
|
function classifyCodexModelCallFailureKind(params) {
|
|
760
832
|
if (params.timedOut || params.turnCompletionIdleTimedOut) return "timeout";
|
|
761
833
|
const errorMessage = params.error ? params.formatError(params.error).toLowerCase() : "";
|
|
@@ -765,10 +837,14 @@ function classifyCodexModelCallFailureKind(params) {
|
|
|
765
837
|
}
|
|
766
838
|
//#endregion
|
|
767
839
|
//#region extensions/codex/src/app-server/attempt-notifications.ts
|
|
840
|
+
/**
|
|
841
|
+
* Predicates and readers for Codex app-server notification envelopes.
|
|
842
|
+
*/
|
|
768
843
|
const CODEX_TURN_ABORT_MARKER_START = "<turn_aborted>";
|
|
769
844
|
const CODEX_TURN_ABORT_MARKER_END = "</turn_aborted>";
|
|
770
845
|
const CODEX_INTERRUPTED_USER_GUIDANCE = "The user interrupted the previous turn on purpose. Any running unified exec processes may still be running in the background. If any tools/commands were aborted, they may have partially executed.";
|
|
771
846
|
const CODEX_INTERRUPTED_DEVELOPER_GUIDANCE = "The previous turn was interrupted on purpose. Any running unified exec processes may still be running in the background. If any tools/commands were aborted, they may have partially executed.";
|
|
847
|
+
/** Builds compact activity metadata for watchdog and diagnostic updates. */
|
|
772
848
|
function describeNotificationActivity(notification) {
|
|
773
849
|
if (!isJsonObject(notification.params)) return { lastNotificationMethod: notification.method };
|
|
774
850
|
if (notification.method !== "rawResponseItem/completed") return { lastNotificationMethod: notification.method };
|
|
@@ -782,6 +858,7 @@ function describeNotificationActivity(notification) {
|
|
|
782
858
|
lastAssistantTextPreview: readRawAssistantTextPreview(item)
|
|
783
859
|
};
|
|
784
860
|
}
|
|
861
|
+
/** Tracks active app-server item ids from item start/completion notifications. */
|
|
785
862
|
function updateActiveTurnItemIds(notification, activeItemIds) {
|
|
786
863
|
if (notification.method !== "item/started" && notification.method !== "item/completed") return;
|
|
787
864
|
const itemId = readNotificationItemId(notification);
|
|
@@ -798,36 +875,43 @@ function isCompletedAssistantNotification(notification) {
|
|
|
798
875
|
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
799
876
|
return Boolean(item && readString$6(item, "type") === "agentMessage" && readString$6(item, "phase") !== "commentary");
|
|
800
877
|
}
|
|
878
|
+
/** Returns true for completed app-server reasoning items. */
|
|
801
879
|
function isReasoningItemCompletionNotification(notification) {
|
|
802
880
|
if (!isJsonObject(notification.params) || notification.method !== "item/completed") return false;
|
|
803
881
|
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
804
882
|
return item ? readString$6(item, "type") === "reasoning" : false;
|
|
805
883
|
}
|
|
884
|
+
/** Returns true for completed assistant commentary items. */
|
|
806
885
|
function isAssistantCommentaryCompletionNotification(notification) {
|
|
807
886
|
if (!isJsonObject(notification.params) || notification.method !== "item/completed") return false;
|
|
808
887
|
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
809
888
|
return Boolean(item && readString$6(item, "type") === "agentMessage" && readString$6(item, "phase") === "commentary");
|
|
810
889
|
}
|
|
890
|
+
/** Returns true for completed raw response reasoning items. */
|
|
811
891
|
function isRawReasoningCompletionNotification(notification) {
|
|
812
892
|
if (!isJsonObject(notification.params) || notification.method !== "rawResponseItem/completed") return false;
|
|
813
893
|
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
814
894
|
return item ? readString$6(item, "type") === "reasoning" : false;
|
|
815
895
|
}
|
|
896
|
+
/** Returns true when assistant completion can release the short idle watch. */
|
|
816
897
|
function isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff) {
|
|
817
898
|
if (isCompletedAssistantNotification(notification)) return true;
|
|
818
899
|
return !turnCrossedToolHandoff && isRawAssistantCompletionNotification(notification);
|
|
819
900
|
}
|
|
901
|
+
/** Returns true when a notification proves assistant output is still active. */
|
|
820
902
|
function shouldDisarmAssistantCompletionIdleWatch(notification) {
|
|
821
903
|
if (!isJsonObject(notification.params)) return false;
|
|
822
904
|
if (notification.method === "item/started") return true;
|
|
823
905
|
if (notification.method === "item/agentMessage/delta") return true;
|
|
824
906
|
return false;
|
|
825
907
|
}
|
|
908
|
+
/** Reads an item id from supported notification envelope shapes. */
|
|
826
909
|
function readNotificationItemId(notification) {
|
|
827
910
|
if (!isJsonObject(notification.params)) return;
|
|
828
911
|
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
829
912
|
return (item ? readString$6(item, "id") : void 0) ?? readString$6(notification.params, "itemId") ?? readString$6(notification.params, "id");
|
|
830
913
|
}
|
|
914
|
+
/** Detects completion for an OpenClaw dynamic tool result still awaited by Codex. */
|
|
831
915
|
function isPendingOpenClawDynamicToolCompletionNotification(notification, pendingOpenClawDynamicToolCompletionIds) {
|
|
832
916
|
if (notification.method !== "item/completed" || !isJsonObject(notification.params)) return false;
|
|
833
917
|
const itemId = readNotificationItemId(notification);
|
|
@@ -836,11 +920,13 @@ function isPendingOpenClawDynamicToolCompletionNotification(notification, pendin
|
|
|
836
920
|
const itemType = item ? readString$6(item, "type") : void 0;
|
|
837
921
|
return itemType === void 0 || itemType === "dynamicToolCall";
|
|
838
922
|
}
|
|
923
|
+
/** Returns true for raw response tool-output completion notifications. */
|
|
839
924
|
function isRawToolOutputCompletionNotification(notification) {
|
|
840
925
|
if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
|
|
841
926
|
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
842
927
|
return item ? readString$6(item, "type") === "custom_tool_call_output" : false;
|
|
843
928
|
}
|
|
929
|
+
/** Returns true for progress on Codex-native tool item types. */
|
|
844
930
|
function isNativeToolProgressNotification(notification) {
|
|
845
931
|
if (notification.method !== "item/started" && notification.method !== "item/completed" && notification.method !== "item/updated") return false;
|
|
846
932
|
if (!isJsonObject(notification.params)) return false;
|
|
@@ -853,17 +939,21 @@ function isNativeToolProgressNotification(notification) {
|
|
|
853
939
|
default: return false;
|
|
854
940
|
}
|
|
855
941
|
}
|
|
942
|
+
/** Returns true for raw native response stream delta events. */
|
|
856
943
|
function isNativeResponseStreamDeltaNotification(notification) {
|
|
857
944
|
return notification.method.startsWith("response.") && notification.method.endsWith(".delta");
|
|
858
945
|
}
|
|
946
|
+
/** Returns true for file-change patch update notifications. */
|
|
859
947
|
function isFileChangePatchUpdatedNotification(notification) {
|
|
860
948
|
return notification.method === "item/fileChange/patchUpdated" && isJsonObject(notification.params);
|
|
861
949
|
}
|
|
950
|
+
/** Returns true for raw assistant message progress with readable text. */
|
|
862
951
|
function isRawAssistantProgressNotification(notification) {
|
|
863
952
|
if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
|
|
864
953
|
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
865
954
|
return Boolean(item && readString$6(item, "type") === "message" && readString$6(item, "role") === "assistant" && readRawAssistantTextPreview(item));
|
|
866
955
|
}
|
|
956
|
+
/** Returns true for raw assistant completion outside commentary phase. */
|
|
867
957
|
function isRawAssistantCompletionNotification(notification) {
|
|
868
958
|
if (!isRawAssistantProgressNotification(notification) || !isJsonObject(notification.params)) return false;
|
|
869
959
|
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
@@ -879,34 +969,45 @@ function readRawAssistantTextPreview(item) {
|
|
|
879
969
|
if (!text) return;
|
|
880
970
|
return text.length > 240 ? `${text.slice(0, 237)}...` : text;
|
|
881
971
|
}
|
|
972
|
+
/** Returns true when notification params correlate to a specific thread/turn. */
|
|
882
973
|
function isTurnNotification(value, threadId, turnId) {
|
|
883
974
|
return isCodexNotificationForTurn(value, threadId, turnId);
|
|
884
975
|
}
|
|
976
|
+
/** Returns true when a correlated notification belongs to another active run. */
|
|
885
977
|
function isCodexNotificationOutsideActiveRun(correlation) {
|
|
886
978
|
if (!Boolean(correlation.threadId || correlation.nestedTurnThreadId)) return false;
|
|
887
979
|
if (!correlation.matchesActiveThread) return true;
|
|
888
980
|
return Boolean(correlation.turnId || correlation.nestedTurnId) && correlation.matchesActiveTurn === false;
|
|
889
981
|
}
|
|
982
|
+
/** Checks request params that must contain the current thread and turn ids. */
|
|
890
983
|
function isCurrentThreadTurnRequestParams(value, threadId, turnId) {
|
|
891
984
|
if (!isJsonObject(value)) return false;
|
|
892
985
|
return readString$6(value, "threadId") === threadId && readString$6(value, "turnId") === turnId;
|
|
893
986
|
}
|
|
987
|
+
/** Checks approval request params, accepting `conversationId` as thread id. */
|
|
894
988
|
function isCurrentApprovalTurnRequestParams(value, threadId, turnId) {
|
|
895
989
|
if (!isJsonObject(value)) return false;
|
|
896
990
|
return (readString$6(value, "threadId") ?? readString$6(value, "conversationId")) === threadId && readString$6(value, "turnId") === turnId;
|
|
897
991
|
}
|
|
992
|
+
/** Checks request params where `turnId` may be omitted or null for the thread. */
|
|
898
993
|
function isCurrentThreadOptionalTurnRequestParams(value, threadId, turnId) {
|
|
899
994
|
if (!isJsonObject(value) || readString$6(value, "threadId") !== threadId) return false;
|
|
900
995
|
const requestTurnId = value.turnId;
|
|
901
996
|
return requestTurnId === null || requestTurnId === void 0 || requestTurnId === turnId;
|
|
902
997
|
}
|
|
998
|
+
/** Returns true for app-server error notifications that will retry. */
|
|
903
999
|
function isRetryableErrorNotification(value) {
|
|
904
1000
|
if (!isJsonObject(value)) return false;
|
|
905
1001
|
return readBoolean$1(value, "willRetry") === true || readBoolean$1(value, "will_retry") === true;
|
|
906
1002
|
}
|
|
1003
|
+
/** Returns true for terminal app-server thread status strings. */
|
|
907
1004
|
function isTerminalTurnStatus(status) {
|
|
908
1005
|
return status === "completed" || status === "interrupted" || status === "failed";
|
|
909
1006
|
}
|
|
1007
|
+
/**
|
|
1008
|
+
* Detects Codex's synthetic interrupted-turn marker while ignoring the current
|
|
1009
|
+
* user prompt echoed through raw response events.
|
|
1010
|
+
*/
|
|
910
1011
|
function isCodexTurnAbortMarkerNotification(notification, options = {}) {
|
|
911
1012
|
if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
|
|
912
1013
|
const item = notification.params.item;
|
|
@@ -940,11 +1041,13 @@ function readString$6(record, key) {
|
|
|
940
1041
|
function readBoolean$1(record, key) {
|
|
941
1042
|
return asBoolean(record[key]);
|
|
942
1043
|
}
|
|
1044
|
+
/** Reads a typed Codex item from notification params when id/type are present. */
|
|
943
1045
|
function readCodexNotificationItem(params) {
|
|
944
1046
|
if (!isJsonObject(params) || !isJsonObject(params.item)) return;
|
|
945
1047
|
const item = params.item;
|
|
946
1048
|
return typeof item.id === "string" && typeof item.type === "string" ? item : void 0;
|
|
947
1049
|
}
|
|
1050
|
+
/** Maps Codex item types to the tool name shown in execution progress. */
|
|
948
1051
|
function codexExecutionToolName(item) {
|
|
949
1052
|
if (item.type === "dynamicToolCall" && typeof item.tool === "string") return item.tool;
|
|
950
1053
|
if (item.type === "mcpToolCall" && typeof item.tool === "string") {
|
|
@@ -960,6 +1063,10 @@ function isNonEmptyString$1(value) {
|
|
|
960
1063
|
}
|
|
961
1064
|
//#endregion
|
|
962
1065
|
//#region extensions/codex/src/app-server/attempt-notification-state.ts
|
|
1066
|
+
/**
|
|
1067
|
+
* State machine for Codex app-server turn notifications and idle-watch updates.
|
|
1068
|
+
*/
|
|
1069
|
+
/** Emits coarse execution phases exactly once from app-server notifications. */
|
|
963
1070
|
function reportCodexExecutionNotification(params) {
|
|
964
1071
|
const { notification } = params;
|
|
965
1072
|
if (notification.method === "turn/started") {
|
|
@@ -980,10 +1087,15 @@ function reportCodexExecutionNotification(params) {
|
|
|
980
1087
|
itemId: item.id
|
|
981
1088
|
});
|
|
982
1089
|
}
|
|
1090
|
+
/** Returns true when a notification ends the current app-server turn. */
|
|
983
1091
|
function isTerminalCodexTurnNotificationForTurn(params) {
|
|
984
1092
|
if (!isTurnNotification(params.notification.params, params.threadId, params.turnId)) return false;
|
|
985
1093
|
return params.notification.method === "turn/completed" || isCodexTurnAbortMarkerNotification(params.notification, { currentPromptTexts: params.currentPromptTexts });
|
|
986
1094
|
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Applies one notification to active item tracking, idle watches, and terminal
|
|
1097
|
+
* turn state.
|
|
1098
|
+
*/
|
|
987
1099
|
function applyCodexTurnNotificationState(params) {
|
|
988
1100
|
const { notification, turnWatches } = params;
|
|
989
1101
|
const isCurrentTurnNotification = isTurnNotification(notification.params, params.threadId, params.turnId);
|
|
@@ -1058,12 +1170,18 @@ function applyCodexTurnNotificationState(params) {
|
|
|
1058
1170
|
//#region extensions/codex/src/app-server/attempt-results.ts
|
|
1059
1171
|
const CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_USER_MESSAGE = "Codex stopped before confirming the turn was complete. The response may be incomplete; retry if needed.";
|
|
1060
1172
|
const CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_SIDE_EFFECT_USER_MESSAGE = "Codex stopped before confirming the turn was complete. Some work may already have been performed; verify the current state before retrying.";
|
|
1173
|
+
/** Joins terminal assistant text blocks into the final attempt answer. */
|
|
1061
1174
|
function collectTerminalAssistantText(result) {
|
|
1062
1175
|
return result.assistantTexts.join("\n\n").trim();
|
|
1063
1176
|
}
|
|
1177
|
+
/** Returns whether attempt metadata saw potential side effects. */
|
|
1064
1178
|
function hasCodexAppServerPotentialSideEffectEvidence(result) {
|
|
1065
1179
|
return result.replayMetadata.hadPotentialSideEffects;
|
|
1066
1180
|
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Builds the user-facing timeout outcome when Codex stops without a terminal
|
|
1183
|
+
* turn event.
|
|
1184
|
+
*/
|
|
1067
1185
|
function buildCodexAppServerPromptTimeoutOutcome(params) {
|
|
1068
1186
|
const completionIdleTimeoutHadPotentialSideEffects = hasCodexAppServerPotentialSideEffectEvidence(params.result);
|
|
1069
1187
|
const replayBlockedReason = resolveCodexAppServerReplayBlockedReason(params.result);
|
|
@@ -1076,12 +1194,14 @@ function buildCodexAppServerPromptTimeoutOutcome(params) {
|
|
|
1076
1194
|
} : {}
|
|
1077
1195
|
};
|
|
1078
1196
|
}
|
|
1197
|
+
/** Explains why an incomplete app-server turn cannot be safely replayed. */
|
|
1079
1198
|
function resolveCodexAppServerReplayBlockedReason(result) {
|
|
1080
1199
|
if (result.replayMetadata.hadPotentialSideEffects) return "potential_side_effect";
|
|
1081
1200
|
if (result.assistantTexts.some((text) => text.trim().length > 0)) return "assistant_output";
|
|
1082
1201
|
if (result.toolMetas.length > 0 || result.clientToolCalls || result.lastToolError || result.didSendDeterministicApprovalPrompt) return "tool_activity";
|
|
1083
1202
|
if (result.itemLifecycle.startedCount > 0 || result.itemLifecycle.activeCount > 0) return "active_item";
|
|
1084
1203
|
}
|
|
1204
|
+
/** Builds an attempt result for failures before the app-server turn starts. */
|
|
1085
1205
|
function buildCodexTurnStartFailureResult(params) {
|
|
1086
1206
|
return {
|
|
1087
1207
|
aborted: false,
|
|
@@ -1115,6 +1235,7 @@ function buildCodexTurnStartFailureResult(params) {
|
|
|
1115
1235
|
systemPromptReport: params.systemPromptReport
|
|
1116
1236
|
};
|
|
1117
1237
|
}
|
|
1238
|
+
/** Detects app-server errors caused by invalid image payload data. */
|
|
1118
1239
|
function isInvalidCodexImagePayloadError(message) {
|
|
1119
1240
|
if (typeof message !== "string" || !message.trim()) return false;
|
|
1120
1241
|
const normalizedMessage = message.replace(/[_-]+/gu, " ");
|
|
@@ -1122,6 +1243,11 @@ function isInvalidCodexImagePayloadError(message) {
|
|
|
1122
1243
|
}
|
|
1123
1244
|
//#endregion
|
|
1124
1245
|
//#region extensions/codex/src/app-server/dynamic-tool-build.ts
|
|
1246
|
+
/**
|
|
1247
|
+
* Builds the Codex app-server dynamic tool list for one turn, including
|
|
1248
|
+
* OpenClaw-owned tools, Codex native-tool fallback rules, sandbox shell shims,
|
|
1249
|
+
* and provider allowlist normalization.
|
|
1250
|
+
*/
|
|
1125
1251
|
const CODEX_NATIVE_SANDBOX_TOOL_REQUIREMENTS = [
|
|
1126
1252
|
"exec",
|
|
1127
1253
|
"process",
|
|
@@ -1131,12 +1257,14 @@ const CODEX_NATIVE_SANDBOX_TOOL_REQUIREMENTS = [
|
|
|
1131
1257
|
"apply_patch"
|
|
1132
1258
|
];
|
|
1133
1259
|
const CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW = new Set(["read", "write"]);
|
|
1260
|
+
/** Splits sandbox and run session keys so tool calls can bind to both scopes when needed. */
|
|
1134
1261
|
function resolveOpenClawCodingToolsSessionKeys(params, sandboxSessionKey) {
|
|
1135
1262
|
return {
|
|
1136
1263
|
sessionKey: sandboxSessionKey,
|
|
1137
1264
|
runSessionKey: params.sessionKey && params.sessionKey !== sandboxSessionKey ? params.sessionKey : void 0
|
|
1138
1265
|
};
|
|
1139
1266
|
}
|
|
1267
|
+
/** Resolves the channel id that hook events should target for this Codex app-server turn. */
|
|
1140
1268
|
function resolveCodexAppServerHookChannelId(params, sandboxSessionKey) {
|
|
1141
1269
|
return buildAgentHookContextChannelFields({
|
|
1142
1270
|
sessionKey: sandboxSessionKey,
|
|
@@ -1148,6 +1276,7 @@ function resolveCodexAppServerHookChannelId(params, sandboxSessionKey) {
|
|
|
1148
1276
|
}
|
|
1149
1277
|
const CODEX_DYNAMIC_TOOL_BUILD_WARN_TOTAL_MS = 1e3;
|
|
1150
1278
|
const CODEX_DYNAMIC_TOOL_BUILD_WARN_STAGE_MS = 500;
|
|
1279
|
+
/** Creates cheap optional timing instrumentation for the dynamic-tool hot path. */
|
|
1151
1280
|
function createCodexDynamicToolBuildStageTracker(options = {}) {
|
|
1152
1281
|
if (!options.enabled) return {
|
|
1153
1282
|
mark() {},
|
|
@@ -1180,12 +1309,15 @@ function createCodexDynamicToolBuildStageTracker(options = {}) {
|
|
|
1180
1309
|
}
|
|
1181
1310
|
};
|
|
1182
1311
|
}
|
|
1312
|
+
/** Returns true when dynamic-tool construction is slow enough to warrant a warning log. */
|
|
1183
1313
|
function shouldWarnCodexDynamicToolBuildStageSummary(summary) {
|
|
1184
1314
|
return summary.totalMs >= CODEX_DYNAMIC_TOOL_BUILD_WARN_TOTAL_MS || summary.stages.some((stage) => stage.durationMs >= CODEX_DYNAMIC_TOOL_BUILD_WARN_STAGE_MS);
|
|
1185
1315
|
}
|
|
1316
|
+
/** Formats per-stage timings into the compact form used by Codex app-server logs. */
|
|
1186
1317
|
function formatCodexDynamicToolBuildStageSummary(summary) {
|
|
1187
1318
|
return summary.stages.length > 0 ? summary.stages.map((stage) => `${stage.name}:${stage.durationMs}ms@${stage.elapsedMs}ms`).join(",") : "none";
|
|
1188
1319
|
}
|
|
1320
|
+
/** Builds, filters, and normalizes Codex-compatible runtime tools for a single turn. */
|
|
1189
1321
|
async function buildDynamicTools(input) {
|
|
1190
1322
|
const { params } = input;
|
|
1191
1323
|
if (params.disableTools || !supportsModelTools(params.model)) return [];
|
|
@@ -1323,6 +1455,7 @@ async function buildDynamicTools(input) {
|
|
|
1323
1455
|
}
|
|
1324
1456
|
return normalizedTools;
|
|
1325
1457
|
}
|
|
1458
|
+
/** Preserves delivery-critical tools when a narrow allowlist would otherwise hide them. */
|
|
1326
1459
|
function includeForcedCodexDynamicToolAllow(toolsAllow, params) {
|
|
1327
1460
|
if (toolsAllow === void 0 || hasWildcardCodexToolsAllow(toolsAllow)) return toolsAllow;
|
|
1328
1461
|
const forcedToolNames = shouldForceMessageTool(params) ? ["message"] : [];
|
|
@@ -1332,6 +1465,7 @@ function includeForcedCodexDynamicToolAllow(toolsAllow, params) {
|
|
|
1332
1465
|
const missingToolNames = forcedToolNames.filter((toolName) => !normalized.has(normalizeCodexDynamicToolName$1(toolName)));
|
|
1333
1466
|
return missingToolNames.length === 0 ? toolsAllow : [...toolsAllow, ...missingToolNames];
|
|
1334
1467
|
}
|
|
1468
|
+
/** Decides whether Codex native code mode can own shell/file tools for this turn. */
|
|
1335
1469
|
function shouldEnableCodexAppServerNativeToolSurface(params, sandbox, options = {}) {
|
|
1336
1470
|
if (isCodexMemoryFlushRun(params)) return false;
|
|
1337
1471
|
if (isCodexNativeExecutionBlockedByNodeExecHost(params, {
|
|
@@ -1343,6 +1477,7 @@ function shouldEnableCodexAppServerNativeToolSurface(params, sandbox, options =
|
|
|
1343
1477
|
if (toolsAllow === void 0) return canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
|
|
1344
1478
|
return hasWildcardCodexToolsAllow(toolsAllow) && canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
|
|
1345
1479
|
}
|
|
1480
|
+
/** Returns true when OpenClaw policy requires the Node-owned exec/process tools instead. */
|
|
1346
1481
|
function isCodexNativeExecutionBlockedByNodeExecHost(params, options = {}) {
|
|
1347
1482
|
return !resolveCodexNativeExecutionPolicy({
|
|
1348
1483
|
config: params.config,
|
|
@@ -1371,15 +1506,19 @@ function isCodexMemoryFlushRun(params) {
|
|
|
1371
1506
|
function filterCodexMemoryFlushDynamicTools(tools) {
|
|
1372
1507
|
return tools.filter((tool) => CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW.has(normalizeCodexDynamicToolName$1(tool.name)));
|
|
1373
1508
|
}
|
|
1509
|
+
/** Requires a Codex sandbox environment only when native tools must run inside OpenClaw sandboxing. */
|
|
1374
1510
|
function shouldRequireCodexSandboxExecServerEnvironment(params) {
|
|
1375
1511
|
return Boolean(params.sandbox?.enabled && params.nativeToolSurfaceEnabled && params.sandboxExecServerEnabled);
|
|
1376
1512
|
}
|
|
1513
|
+
/** Selects the sandbox exec-server environment passed through the Codex app-server protocol. */
|
|
1377
1514
|
function resolveCodexSandboxEnvironmentSelection(environment, nativeToolSurfaceEnabled) {
|
|
1378
1515
|
return environment && nativeToolSurfaceEnabled ? [environment] : void 0;
|
|
1379
1516
|
}
|
|
1517
|
+
/** Chooses the cwd visible to Codex native execution after sandbox exec-server setup. */
|
|
1380
1518
|
function resolveCodexAppServerExecutionCwd(params) {
|
|
1381
1519
|
return params.environment && params.nativeToolSurfaceEnabled ? params.environment.cwd : params.effectiveCwd;
|
|
1382
1520
|
}
|
|
1521
|
+
/** Converts OpenClaw sandbox networking into Codex's external-sandbox policy shape. */
|
|
1383
1522
|
function resolveCodexExternalSandboxPolicyForOpenClawSandbox(sandbox) {
|
|
1384
1523
|
return {
|
|
1385
1524
|
type: "externalSandbox",
|
|
@@ -1391,6 +1530,7 @@ function codexNetworkAccessForOpenClawSandbox(sandbox) {
|
|
|
1391
1530
|
const network = sandbox?.docker?.network?.trim().toLowerCase();
|
|
1392
1531
|
return Boolean(network && network !== "none");
|
|
1393
1532
|
}
|
|
1533
|
+
/** Returns a Codex config copy with app-server Codex plugin loading disabled for thread tools. */
|
|
1394
1534
|
function disableCodexPluginThreadConfig(pluginConfig) {
|
|
1395
1535
|
const config = readCodexPluginConfig(pluginConfig);
|
|
1396
1536
|
return {
|
|
@@ -1401,6 +1541,7 @@ function disableCodexPluginThreadConfig(pluginConfig) {
|
|
|
1401
1541
|
}
|
|
1402
1542
|
};
|
|
1403
1543
|
}
|
|
1544
|
+
/** Adds sandbox_exec/process aliases when native Code Mode cannot directly honor the sandbox. */
|
|
1404
1545
|
function addSandboxShellDynamicToolsIfAvailable(filteredTools, allTools, input) {
|
|
1405
1546
|
if (!shouldExposeSandboxExecDynamicTool(input) || isSandboxShellDynamicToolExcluded(input.pluginConfig)) return filteredTools;
|
|
1406
1547
|
const execTool = allTools.find((tool) => normalizeCodexDynamicToolName$1(tool.name) === "exec");
|
|
@@ -1471,6 +1612,7 @@ function addNodeShellDynamicToolsIfNeeded(filteredTools, allTools, input) {
|
|
|
1471
1612
|
}
|
|
1472
1613
|
return next;
|
|
1473
1614
|
}
|
|
1615
|
+
/** Applies a normalized tool allowlist while preserving sandbox shell aliases for exec/process. */
|
|
1474
1616
|
function filterCodexDynamicToolsForAllowlist(tools, toolsAllow) {
|
|
1475
1617
|
if (!toolsAllow) return tools;
|
|
1476
1618
|
if (toolsAllow.length === 0) return [];
|
|
@@ -1481,46 +1623,57 @@ function filterCodexDynamicToolsForAllowlist(tools, toolsAllow) {
|
|
|
1481
1623
|
return allowSet.has(normalized) || normalized === "sandbox_exec" && allowSet.has("exec") || normalized === "sandbox_process" && (allowSet.has("exec") || allowSet.has("process"));
|
|
1482
1624
|
});
|
|
1483
1625
|
}
|
|
1626
|
+
/** Detects the wildcard allowlist marker after Codex tool-name normalization. */
|
|
1484
1627
|
function hasWildcardCodexToolsAllow(toolsAllow) {
|
|
1485
1628
|
return toolsAllow.some((name) => normalizeCodexDynamicToolName$1(name) === "*");
|
|
1486
1629
|
}
|
|
1630
|
+
/** Forces message delivery through the message tool when the source channel requires it. */
|
|
1487
1631
|
function shouldForceMessageTool(params) {
|
|
1488
1632
|
return params.disableMessageTool !== true && params.sourceReplyDeliveryMode === "message_tool_only";
|
|
1489
1633
|
}
|
|
1490
1634
|
//#endregion
|
|
1491
1635
|
//#region extensions/codex/src/app-server/sandbox-exec-server/json-rpc.ts
|
|
1636
|
+
/** JSON-RPC error code used when a sandbox exec-server method is unknown. */
|
|
1492
1637
|
const JSON_RPC_NOT_FOUND = -32004;
|
|
1638
|
+
/** Protocol-level error carrying the JSON-RPC error code to send to the client. */
|
|
1493
1639
|
var JsonRpcProtocolError = class extends Error {
|
|
1494
1640
|
constructor(code, message) {
|
|
1495
1641
|
super(message);
|
|
1496
1642
|
this.code = code;
|
|
1497
1643
|
}
|
|
1498
1644
|
};
|
|
1645
|
+
/** Parses raw WebSocket data into a JSON-RPC request object. */
|
|
1499
1646
|
function parseRequest(data) {
|
|
1500
1647
|
const text = (Array.isArray(data) ? Buffer.concat(data) : Buffer.isBuffer(data) ? data : Buffer.from(data)).toString("utf8");
|
|
1501
1648
|
return requireObject(JSON.parse(text), "JSON-RPC request");
|
|
1502
1649
|
}
|
|
1650
|
+
/** Validates that a JSON value is a non-array object. */
|
|
1503
1651
|
function requireObject(value, label) {
|
|
1504
1652
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object.`);
|
|
1505
1653
|
return value;
|
|
1506
1654
|
}
|
|
1655
|
+
/** Validates a non-empty string JSON-RPC parameter. */
|
|
1507
1656
|
function requireString(value, label) {
|
|
1508
1657
|
if (typeof value !== "string" || !value) throw new Error(`${label} must be a non-empty string.`);
|
|
1509
1658
|
return value;
|
|
1510
1659
|
}
|
|
1660
|
+
/** Validates a base64 payload parameter as a string; decoding happens at call sites. */
|
|
1511
1661
|
function requireBase64String(value, label) {
|
|
1512
1662
|
if (typeof value !== "string") throw new Error(`${label} must be a string.`);
|
|
1513
1663
|
return value;
|
|
1514
1664
|
}
|
|
1665
|
+
/** Validates a finite numeric JSON-RPC parameter. */
|
|
1515
1666
|
function requireNumber(value, label) {
|
|
1516
1667
|
if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`${label} must be a finite number.`);
|
|
1517
1668
|
return value;
|
|
1518
1669
|
}
|
|
1670
|
+
/** Validates a non-empty string-array JSON-RPC parameter. */
|
|
1519
1671
|
function requireStringArray(value, label) {
|
|
1520
1672
|
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) throw new Error(`${label} must be a string array.`);
|
|
1521
1673
|
if (value.length === 0) throw new Error(`${label} must not be empty.`);
|
|
1522
1674
|
return value;
|
|
1523
1675
|
}
|
|
1676
|
+
/** Reads HTTP headers from JSON-RPC params, defaulting to an empty header list. */
|
|
1524
1677
|
function readHttpHeaders(value) {
|
|
1525
1678
|
if (!Array.isArray(value)) return [];
|
|
1526
1679
|
return value.map((entry, index) => {
|
|
@@ -1531,6 +1684,7 @@ function readHttpHeaders(value) {
|
|
|
1531
1684
|
};
|
|
1532
1685
|
});
|
|
1533
1686
|
}
|
|
1687
|
+
/** Sends a JSON-RPC success response over the WebSocket. */
|
|
1534
1688
|
function sendResult(socket, id, result) {
|
|
1535
1689
|
socket.send(JSON.stringify({
|
|
1536
1690
|
jsonrpc: "2.0",
|
|
@@ -1538,6 +1692,7 @@ function sendResult(socket, id, result) {
|
|
|
1538
1692
|
result: result === void 0 ? {} : result
|
|
1539
1693
|
}));
|
|
1540
1694
|
}
|
|
1695
|
+
/** Sends a JSON-RPC error response over the WebSocket. */
|
|
1541
1696
|
function sendError(socket, id, code, message) {
|
|
1542
1697
|
socket.send(JSON.stringify({
|
|
1543
1698
|
jsonrpc: "2.0",
|
|
@@ -1550,9 +1705,15 @@ function sendError(socket, id, code, message) {
|
|
|
1550
1705
|
}
|
|
1551
1706
|
//#endregion
|
|
1552
1707
|
//#region extensions/codex/src/app-server/sandbox-exec-server/fs-policy.ts
|
|
1708
|
+
/**
|
|
1709
|
+
* Resolves Codex filesystem sandbox policy payloads into OpenClaw path/glob
|
|
1710
|
+
* checks for sandbox exec-server filesystem operations.
|
|
1711
|
+
*/
|
|
1712
|
+
/** Resolves request-local sandbox policy and asserts each requested path has the needed access. */
|
|
1553
1713
|
function assertFsSandboxAccess(execServer, record, requests) {
|
|
1554
1714
|
assertResolvedFsSandboxAccess(resolveFsSandboxPolicy(execServer, record), requests);
|
|
1555
1715
|
}
|
|
1716
|
+
/** Parses a Codex managed filesystem sandbox context into normalized access entries. */
|
|
1556
1717
|
function resolveFsSandboxPolicy(execServer, record) {
|
|
1557
1718
|
if (record.sandbox === void 0 || record.sandbox === null) return;
|
|
1558
1719
|
const sandbox = requireObject(record.sandbox, "fs sandbox context");
|
|
@@ -1633,6 +1794,7 @@ function resolveFsSpecialPath(value, cwd) {
|
|
|
1633
1794
|
if (kind === "slash_tmp" || kind === "tmpdir") return "/tmp";
|
|
1634
1795
|
throw new Error(`Unsupported Codex fs sandbox special path: ${kind}`);
|
|
1635
1796
|
}
|
|
1797
|
+
/** Asserts access against an already resolved filesystem sandbox policy. */
|
|
1636
1798
|
function assertResolvedFsSandboxAccess(policy, requests) {
|
|
1637
1799
|
if (!policy?.unrestricted && policy) for (const request of requests) {
|
|
1638
1800
|
const access = resolveFsAccess(policy, request.path);
|
|
@@ -1655,6 +1817,7 @@ function resolveFsAccess(policy, rawPath) {
|
|
|
1655
1817
|
}
|
|
1656
1818
|
return selected?.access ?? "none";
|
|
1657
1819
|
}
|
|
1820
|
+
/** Rejects recursive writes/removes that would cross protected read-only descendants. */
|
|
1658
1821
|
function assertNoReadOnlyDescendant(policy, rawPath, operation) {
|
|
1659
1822
|
if (!policy || policy.unrestricted) return;
|
|
1660
1823
|
const target = normalizeSandboxAbsolutePath(rawPath, "fs path");
|
|
@@ -1669,11 +1832,13 @@ function assertNoReadOnlyDescendant(policy, rawPath, operation) {
|
|
|
1669
1832
|
throw new Error(`Codex fs sandbox denied recursive ${operation} of ${rawPath} because ${protectedPath} is not writable.`);
|
|
1670
1833
|
}
|
|
1671
1834
|
}
|
|
1835
|
+
/** Normalizes and validates an absolute POSIX path inside the sandbox namespace. */
|
|
1672
1836
|
function normalizeSandboxAbsolutePath(rawPath, label) {
|
|
1673
1837
|
if (!rawPath || rawPath.includes("\0") || !rawPath.startsWith("/")) throw new Error(`${label} must be an absolute sandbox path.`);
|
|
1674
1838
|
const normalized = posix.normalize(rawPath);
|
|
1675
1839
|
return normalized === "//" ? "/" : normalized;
|
|
1676
1840
|
}
|
|
1841
|
+
/** Returns true when target is root itself or a descendant of root. */
|
|
1677
1842
|
function pathContains(root, target) {
|
|
1678
1843
|
return root === "/" || target === root || target.startsWith(`${root}/`);
|
|
1679
1844
|
}
|
|
@@ -1751,17 +1916,20 @@ function sandboxGlobLiteralPrefix(pattern) {
|
|
|
1751
1916
|
if (slash <= 0) return "/";
|
|
1752
1917
|
return normalizeSandboxAbsolutePath(prefix.slice(0, slash), "fs sandbox glob prefix");
|
|
1753
1918
|
}
|
|
1919
|
+
/** Safely joins a single directory entry name onto a sandbox parent path. */
|
|
1754
1920
|
function joinSandboxChildPath(parent, child) {
|
|
1755
1921
|
if (!child || child === "." || child === ".." || child.includes("/") || child.includes("\0")) throw new Error(`Invalid sandbox directory entry name: ${child}`);
|
|
1756
1922
|
return parent.endsWith("/") ? `${parent}${child}` : `${parent}/${child}`;
|
|
1757
1923
|
}
|
|
1758
1924
|
//#endregion
|
|
1759
1925
|
//#region extensions/codex/src/app-server/sandbox-exec-server/runtime.ts
|
|
1926
|
+
/** Returns the configured sandbox backend or fails the current JSON-RPC request. */
|
|
1760
1927
|
function requireBackend(execServer) {
|
|
1761
1928
|
const backend = execServer.sandbox.backend;
|
|
1762
1929
|
if (!backend) throw new Error("OpenClaw sandbox backend is unavailable.");
|
|
1763
1930
|
return backend;
|
|
1764
1931
|
}
|
|
1932
|
+
/** Returns the configured filesystem bridge or fails the current JSON-RPC request. */
|
|
1765
1933
|
function requireFsBridge(execServer) {
|
|
1766
1934
|
const fsBridge = execServer.sandbox.fsBridge;
|
|
1767
1935
|
if (!fsBridge) throw new Error("Sandbox filesystem bridge is unavailable.");
|
|
@@ -1769,7 +1937,12 @@ function requireFsBridge(execServer) {
|
|
|
1769
1937
|
}
|
|
1770
1938
|
//#endregion
|
|
1771
1939
|
//#region extensions/codex/src/app-server/sandbox-exec-server/filesystem.ts
|
|
1940
|
+
/**
|
|
1941
|
+
* Implements filesystem JSON-RPC handlers for the Codex sandbox exec-server
|
|
1942
|
+
* with OpenClaw sandbox policy checks before every bridge operation.
|
|
1943
|
+
*/
|
|
1772
1944
|
const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES = 512 * 1024 * 1024;
|
|
1945
|
+
/** Reads a sandbox file as base64 after read-policy and size checks. */
|
|
1773
1946
|
async function readFile(execServer, params) {
|
|
1774
1947
|
const record = requireObject(params, "fs/readFile params");
|
|
1775
1948
|
const filePath = requireString(record.path, "path");
|
|
@@ -1783,6 +1956,7 @@ async function readFile(execServer, params) {
|
|
|
1783
1956
|
if (stat.type === "file" && stat.size > CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES) throw new Error(`file is too large to read through Codex sandbox exec-server: ${stat.size} bytes`);
|
|
1784
1957
|
return { dataBase64: (await fsBridge.readFile({ filePath })).toString("base64") };
|
|
1785
1958
|
}
|
|
1959
|
+
/** Writes base64 data to an existing sandbox directory after write-policy checks. */
|
|
1786
1960
|
async function writeFile(execServer, params) {
|
|
1787
1961
|
const record = requireObject(params, "fs/writeFile params");
|
|
1788
1962
|
const filePath = requireString(record.path, "path");
|
|
@@ -1798,6 +1972,7 @@ async function writeFile(execServer, params) {
|
|
|
1798
1972
|
mkdir: false
|
|
1799
1973
|
});
|
|
1800
1974
|
}
|
|
1975
|
+
/** Creates a sandbox directory, respecting recursive and parent-directory semantics. */
|
|
1801
1976
|
async function createDirectory(execServer, params) {
|
|
1802
1977
|
const record = requireObject(params, "fs/createDirectory params");
|
|
1803
1978
|
const filePath = requireString(record.path, "path");
|
|
@@ -1812,6 +1987,7 @@ async function createDirectory(execServer, params) {
|
|
|
1812
1987
|
}
|
|
1813
1988
|
await fsBridge.mkdirp({ filePath });
|
|
1814
1989
|
}
|
|
1990
|
+
/** Returns normalized metadata for a sandbox path. */
|
|
1815
1991
|
async function getMetadata(execServer, params) {
|
|
1816
1992
|
const record = requireObject(params, "fs/getMetadata params");
|
|
1817
1993
|
const filePath = requireString(record.path, "path");
|
|
@@ -1823,6 +1999,7 @@ async function getMetadata(execServer, params) {
|
|
|
1823
1999
|
if (!stat) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, "file not found");
|
|
1824
2000
|
return metadataResponse(stat);
|
|
1825
2001
|
}
|
|
2002
|
+
/** Lists sandbox directory entries visible under the resolved filesystem policy. */
|
|
1826
2003
|
async function readDirectory(execServer, params) {
|
|
1827
2004
|
const record = requireObject(params, "fs/readDirectory params");
|
|
1828
2005
|
return { entries: await listDirectoryEntries(execServer, requireString(record.path, "path"), resolveFsSandboxPolicy(execServer, record)) };
|
|
@@ -1854,6 +2031,7 @@ async function listDirectoryEntries(execServer, filePath, fsSandboxPolicy) {
|
|
|
1854
2031
|
};
|
|
1855
2032
|
});
|
|
1856
2033
|
}
|
|
2034
|
+
/** Removes a sandbox path after rejecting writes outside policy or under read-only descendants. */
|
|
1857
2035
|
async function removePath(execServer, params) {
|
|
1858
2036
|
const record = requireObject(params, "fs/remove params");
|
|
1859
2037
|
const filePath = requireString(record.path, "path");
|
|
@@ -1869,6 +2047,7 @@ async function removePath(execServer, params) {
|
|
|
1869
2047
|
force: record.force !== false
|
|
1870
2048
|
});
|
|
1871
2049
|
}
|
|
2050
|
+
/** Copies sandbox files or recursive directories while enforcing source and destination policy. */
|
|
1872
2051
|
async function copyPath(execServer, params) {
|
|
1873
2052
|
const record = requireObject(params, "fs/copy params");
|
|
1874
2053
|
const sourcePath = requireString(record.sourcePath ?? record.source, "sourcePath");
|
|
@@ -1933,7 +2112,13 @@ function metadataResponse(stat) {
|
|
|
1933
2112
|
}
|
|
1934
2113
|
//#endregion
|
|
1935
2114
|
//#region extensions/codex/src/app-server/sandbox-exec-server/http.ts
|
|
2115
|
+
/**
|
|
2116
|
+
* Implements sandboxed HTTP requests for Codex native tools by routing network
|
|
2117
|
+
* access through the active OpenClaw sandbox backend.
|
|
2118
|
+
*/
|
|
2119
|
+
/** Maximum JSON-line size accepted from the streaming HTTP helper process. */
|
|
1936
2120
|
const SANDBOX_HTTP_STREAM_LINE_MAX_CHARS = 256 * 1024;
|
|
2121
|
+
/** Handles one sandbox HTTP JSON-RPC request, optionally streaming response body deltas. */
|
|
1937
2122
|
async function httpRequest(execServer, socket, params) {
|
|
1938
2123
|
const record = requireObject(params, "http/request params");
|
|
1939
2124
|
const requestId = requireString(record.requestId, "requestId");
|
|
@@ -2182,9 +2367,14 @@ function sendHttpBodyDelta(socket, params) {
|
|
|
2182
2367
|
}
|
|
2183
2368
|
//#endregion
|
|
2184
2369
|
//#region extensions/codex/src/app-server/sandbox-exec-server/processes.ts
|
|
2370
|
+
/**
|
|
2371
|
+
* Manages subprocess lifecycle, streaming output buffers, stdin writes, and
|
|
2372
|
+
* termination for Codex sandbox exec-server process RPCs.
|
|
2373
|
+
*/
|
|
2185
2374
|
const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
2186
2375
|
const RETAINED_PROCESS_OUTPUT_BYTES = 1024 * 1024;
|
|
2187
2376
|
const CLOSED_PROCESS_EVICTION_MS = 6e4;
|
|
2377
|
+
/** Starts a sandbox-backed process and registers it in the connection-local process table. */
|
|
2188
2378
|
async function startProcess(execServer, processes, socket, params) {
|
|
2189
2379
|
const record = requireObject(params, "process/start params");
|
|
2190
2380
|
const processId = requireString(record.processId, "processId");
|
|
@@ -2365,6 +2555,7 @@ function limitProcessChunks(chunks, maxBytes) {
|
|
|
2365
2555
|
}
|
|
2366
2556
|
return retained;
|
|
2367
2557
|
}
|
|
2558
|
+
/** Reads buffered process output, optionally waiting for new output or process close. */
|
|
2368
2559
|
async function readProcess(processes, params) {
|
|
2369
2560
|
const record = requireObject(params, "process/read params");
|
|
2370
2561
|
const managed = requireProcess(processes, requireString(record.processId, "processId"));
|
|
@@ -2382,6 +2573,7 @@ async function readProcess(processes, params) {
|
|
|
2382
2573
|
failure: managed.failure
|
|
2383
2574
|
};
|
|
2384
2575
|
}
|
|
2576
|
+
/** Writes base64 stdin data to a running process when stdin is still open. */
|
|
2385
2577
|
function writeProcess(processes, params) {
|
|
2386
2578
|
const record = requireObject(params, "process/write params");
|
|
2387
2579
|
const processId = requireString(record.processId, "processId");
|
|
@@ -2392,6 +2584,7 @@ function writeProcess(processes, params) {
|
|
|
2392
2584
|
managed.child.stdin.write(chunk);
|
|
2393
2585
|
return { status: "accepted" };
|
|
2394
2586
|
}
|
|
2587
|
+
/** Requests process termination and reports whether it was running at call time. */
|
|
2395
2588
|
function terminateProcess(processes, params) {
|
|
2396
2589
|
const processId = requireString(requireObject(params, "process/terminate params").processId, "processId");
|
|
2397
2590
|
const managed = processes.get(processId);
|
|
@@ -2471,7 +2664,12 @@ function readStringList(value) {
|
|
|
2471
2664
|
}
|
|
2472
2665
|
//#endregion
|
|
2473
2666
|
//#region extensions/codex/src/app-server/sandbox-exec-server.ts
|
|
2667
|
+
/**
|
|
2668
|
+
* Hosts the local OpenClaw sandbox exec-server that Codex app-server native
|
|
2669
|
+
* execution can register as an external environment.
|
|
2670
|
+
*/
|
|
2474
2671
|
const SANDBOX_EXEC_SERVERS = /* @__PURE__ */ new Map();
|
|
2672
|
+
/** Starts or reuses a sandbox exec-server and registers it with Codex app-server. */
|
|
2475
2673
|
async function ensureCodexSandboxExecServerEnvironment(params) {
|
|
2476
2674
|
if (!params.sandbox?.enabled || !params.sandbox.backend) return;
|
|
2477
2675
|
if (!canExposeLocalExecServerToAppServer(params.appServerStartOptions)) throw new Error("OpenClaw Codex exec-server uses a local loopback URL and cannot be registered with a remote Codex app-server.");
|
|
@@ -2498,6 +2696,7 @@ async function ensureCodexSandboxExecServerEnvironment(params) {
|
|
|
2498
2696
|
cwd: params.sandbox.containerWorkdir
|
|
2499
2697
|
};
|
|
2500
2698
|
}
|
|
2699
|
+
/** Releases the sandbox exec-server lease associated with a sandbox runtime. */
|
|
2501
2700
|
async function releaseCodexSandboxExecServerEnvironment(sandbox) {
|
|
2502
2701
|
if (!sandbox?.enabled) return;
|
|
2503
2702
|
const server = await SANDBOX_EXEC_SERVERS.get(sandbox.runtimeId)?.catch(() => void 0);
|
|
@@ -2659,19 +2858,38 @@ async function dispatchRequest(execServer, processes, socket, request) {
|
|
|
2659
2858
|
}
|
|
2660
2859
|
//#endregion
|
|
2661
2860
|
//#region extensions/codex/src/app-server/attempt-startup.ts
|
|
2861
|
+
/**
|
|
2862
|
+
* Startup orchestration for Codex app-server attempts, including shared-client
|
|
2863
|
+
* leasing, plugin thread config, sandbox execution environment, and thread
|
|
2864
|
+
* lifecycle binding.
|
|
2865
|
+
*/
|
|
2662
2866
|
const CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS = 3;
|
|
2867
|
+
/**
|
|
2868
|
+
* Starts or resumes the Codex app-server thread and returns the resources the
|
|
2869
|
+
* run loop must later release.
|
|
2870
|
+
*/
|
|
2663
2871
|
async function startCodexAttemptThread(params) {
|
|
2664
2872
|
let pluginAppServer = params.appServer;
|
|
2665
2873
|
let releaseSharedClientLease;
|
|
2666
2874
|
let startupClientForAbandonedRequestCleanup;
|
|
2667
2875
|
let releaseStartupResourcesOnTimeout;
|
|
2876
|
+
let startupAbandoned = false;
|
|
2877
|
+
const startupAbandonController = new AbortController();
|
|
2878
|
+
const abandonStartupAcquire = () => startupAbandonController.abort();
|
|
2879
|
+
params.signal.addEventListener("abort", abandonStartupAcquire, { once: true });
|
|
2668
2880
|
try {
|
|
2669
2881
|
const startupResult = await withCodexStartupTimeout({
|
|
2670
2882
|
timeoutMs: params.startupTimeoutMs,
|
|
2671
2883
|
signal: params.signal,
|
|
2672
2884
|
onTimeout: async () => {
|
|
2885
|
+
startupAbandoned = true;
|
|
2886
|
+
startupAbandonController.abort();
|
|
2673
2887
|
await params.onStartupTimeout();
|
|
2674
2888
|
await releaseStartupResourcesOnTimeout?.();
|
|
2889
|
+
releaseSharedClientLease?.();
|
|
2890
|
+
releaseSharedClientLease = void 0;
|
|
2891
|
+
await closeAbandonedStartupClient(startupClientForAbandonedRequestCleanup);
|
|
2892
|
+
startupClientForAbandonedRequestCleanup = void 0;
|
|
2675
2893
|
},
|
|
2676
2894
|
operation: async () => {
|
|
2677
2895
|
const threadConfig = mergeCodexThreadConfigs(params.bundleMcpThreadConfig?.configPatch);
|
|
@@ -2710,20 +2928,34 @@ async function startCodexAttemptThread(params) {
|
|
|
2710
2928
|
let attemptedClient;
|
|
2711
2929
|
const startupAttempt = async () => {
|
|
2712
2930
|
let startupClientLease;
|
|
2931
|
+
let startupClient;
|
|
2932
|
+
let startupAttemptError;
|
|
2713
2933
|
let startupAttemptSucceeded = false;
|
|
2714
2934
|
try {
|
|
2715
|
-
|
|
2935
|
+
startupClient = await params.attemptClientFactory(params.appServer.start, params.startupAuthProfileId, params.agentDir, params.config, {
|
|
2936
|
+
onStartedClient: (client) => {
|
|
2937
|
+
startupClientForAbandonedRequestCleanup = client;
|
|
2938
|
+
if (startupAbandoned || startupAbandonController.signal.aborted) closeAbandonedStartupClient(client);
|
|
2939
|
+
},
|
|
2940
|
+
abandonSignal: startupAbandonController.signal
|
|
2941
|
+
});
|
|
2942
|
+
const activeStartupClient = startupClient;
|
|
2943
|
+
let startupClientLeaseReleased = false;
|
|
2716
2944
|
startupClientLease = () => {
|
|
2717
|
-
|
|
2945
|
+
if (startupClientLeaseReleased) return;
|
|
2946
|
+
startupClientLeaseReleased = true;
|
|
2947
|
+
releaseLeasedSharedCodexAppServerClient(activeStartupClient);
|
|
2718
2948
|
};
|
|
2719
2949
|
releaseSharedClientLease = startupClientLease;
|
|
2720
|
-
attemptedClient =
|
|
2721
|
-
startupClientForAbandonedRequestCleanup =
|
|
2950
|
+
attemptedClient = activeStartupClient;
|
|
2951
|
+
startupClientForAbandonedRequestCleanup = activeStartupClient;
|
|
2952
|
+
if (startupAbandoned) throw new Error("codex app-server startup timed out");
|
|
2953
|
+
if (startupAbandonController.signal.aborted) throw new Error("codex app-server startup aborted");
|
|
2722
2954
|
await ensureCodexComputerUse({
|
|
2723
|
-
client:
|
|
2955
|
+
client: activeStartupClient,
|
|
2724
2956
|
pluginConfig: params.pluginConfig,
|
|
2725
2957
|
timeoutMs: params.appServer.requestTimeoutMs,
|
|
2726
|
-
signal:
|
|
2958
|
+
signal: startupAbandonController.signal
|
|
2727
2959
|
});
|
|
2728
2960
|
let startupSandboxEnvironment;
|
|
2729
2961
|
let startupSandboxEnvironmentAcquired = false;
|
|
@@ -2740,14 +2972,14 @@ async function startCodexAttemptThread(params) {
|
|
|
2740
2972
|
nativeToolSurfaceEnabled: params.nativeToolSurfaceEnabled,
|
|
2741
2973
|
sandboxExecServerEnabled: params.sandboxExecServerEnabled
|
|
2742
2974
|
}) ? await ensureCodexSandboxExecServerEnvironment({
|
|
2743
|
-
client:
|
|
2975
|
+
client: activeStartupClient,
|
|
2744
2976
|
sandbox: params.sandbox ?? null,
|
|
2745
2977
|
appServerStartOptions: params.appServer.start,
|
|
2746
2978
|
timeoutMs: params.appServer.requestTimeoutMs,
|
|
2747
|
-
signal:
|
|
2979
|
+
signal: startupAbandonController.signal
|
|
2748
2980
|
}) : void 0;
|
|
2749
2981
|
startupSandboxEnvironmentAcquired = Boolean(startupSandboxEnvironment);
|
|
2750
|
-
if (
|
|
2982
|
+
if (startupAbandonController.signal.aborted) {
|
|
2751
2983
|
await releaseStartupSandboxEnvironment();
|
|
2752
2984
|
throw new Error("codex app-server startup aborted");
|
|
2753
2985
|
}
|
|
@@ -2763,8 +2995,8 @@ async function startCodexAttemptThread(params) {
|
|
|
2763
2995
|
nativeToolSurfaceEnabled: params.nativeToolSurfaceEnabled
|
|
2764
2996
|
});
|
|
2765
2997
|
const startupSandboxPolicy = startupSandboxEnvironment ? resolveCodexExternalSandboxPolicyForOpenClawSandbox(params.sandbox) : void 0;
|
|
2766
|
-
const buildThreadLifecycleParams = () => ({
|
|
2767
|
-
client:
|
|
2998
|
+
const buildThreadLifecycleParams = (signal) => ({
|
|
2999
|
+
client: activeStartupClient,
|
|
2768
3000
|
params: params.buildAttemptParams(),
|
|
2769
3001
|
agentId: params.sessionAgentId,
|
|
2770
3002
|
cwd: startupExecutionCwd,
|
|
@@ -2782,16 +3014,16 @@ async function startCodexAttemptThread(params) {
|
|
|
2782
3014
|
mcpServersFingerprintEvaluated: params.bundleMcpThreadConfig.evaluated,
|
|
2783
3015
|
environmentSelection: startupEnvironmentSelection,
|
|
2784
3016
|
contextEngineProjection: params.contextEngineProjection,
|
|
2785
|
-
signal
|
|
3017
|
+
signal,
|
|
2786
3018
|
pluginThreadConfig: pluginThreadConfigRequired ? {
|
|
2787
3019
|
enabled: true,
|
|
2788
3020
|
inputFingerprint: pluginThreadConfigInputFingerprint,
|
|
2789
3021
|
enabledPluginConfigKeys,
|
|
2790
3022
|
build: () => buildCodexPluginThreadConfig({
|
|
2791
3023
|
pluginConfig: pluginThreadConfigPluginConfig,
|
|
2792
|
-
request: (method, requestParams) =>
|
|
3024
|
+
request: (method, requestParams) => activeStartupClient.request(method, requestParams, {
|
|
2793
3025
|
timeoutMs: params.appServer.requestTimeoutMs,
|
|
2794
|
-
signal
|
|
3026
|
+
signal
|
|
2795
3027
|
}),
|
|
2796
3028
|
appCache: defaultCodexAppInventoryCache,
|
|
2797
3029
|
appCacheKey: pluginAppCacheKey
|
|
@@ -2799,21 +3031,21 @@ async function startCodexAttemptThread(params) {
|
|
|
2799
3031
|
} : void 0
|
|
2800
3032
|
});
|
|
2801
3033
|
try {
|
|
2802
|
-
const startupThread = await startOrResumeThread(buildThreadLifecycleParams());
|
|
2803
|
-
if (
|
|
3034
|
+
const startupThread = await startOrResumeThread(buildThreadLifecycleParams(startupAbandonController.signal));
|
|
3035
|
+
if (startupAbandonController.signal.aborted) {
|
|
2804
3036
|
await releaseStartupSandboxEnvironment();
|
|
2805
3037
|
throw new Error("codex app-server startup aborted");
|
|
2806
3038
|
}
|
|
2807
3039
|
startupSandboxEnvironmentAcquired = false;
|
|
2808
3040
|
startupAttemptSucceeded = true;
|
|
2809
3041
|
return {
|
|
2810
|
-
client:
|
|
3042
|
+
client: activeStartupClient,
|
|
2811
3043
|
thread: startupThread,
|
|
2812
3044
|
sandboxEnvironment: startupSandboxEnvironment,
|
|
2813
3045
|
environmentSelection: startupEnvironmentSelection,
|
|
2814
3046
|
executionCwd: startupExecutionCwd,
|
|
2815
3047
|
sandboxPolicy: startupSandboxPolicy,
|
|
2816
|
-
restartContextEngineCodexThread: () => startOrResumeThread(buildThreadLifecycleParams())
|
|
3048
|
+
restartContextEngineCodexThread: () => startOrResumeThread(buildThreadLifecycleParams(params.signal))
|
|
2817
3049
|
};
|
|
2818
3050
|
} catch (error) {
|
|
2819
3051
|
await releaseStartupSandboxEnvironment();
|
|
@@ -2821,10 +3053,23 @@ async function startCodexAttemptThread(params) {
|
|
|
2821
3053
|
} finally {
|
|
2822
3054
|
if (releaseStartupResourcesOnTimeout === releaseStartupSandboxEnvironment) releaseStartupResourcesOnTimeout = void 0;
|
|
2823
3055
|
}
|
|
3056
|
+
} catch (error) {
|
|
3057
|
+
startupAttemptError = error;
|
|
3058
|
+
throw error;
|
|
2824
3059
|
} finally {
|
|
2825
3060
|
if (!startupAttemptSucceeded) {
|
|
2826
3061
|
if (releaseSharedClientLease === startupClientLease) releaseSharedClientLease = void 0;
|
|
2827
3062
|
startupClientLease?.();
|
|
3063
|
+
if (startupAbandoned || params.signal.aborted) {
|
|
3064
|
+
if (startupClientForAbandonedRequestCleanup === startupClient) startupClientForAbandonedRequestCleanup = void 0;
|
|
3065
|
+
await closeAbandonedStartupClient(startupClient);
|
|
3066
|
+
} else if (shouldClearSharedClientAfterStartupRace(startupAttemptError) || shouldClearSharedClientAfterStartupFailure({
|
|
3067
|
+
error: startupAttemptError,
|
|
3068
|
+
spawnedBy: params.spawnedBy
|
|
3069
|
+
})) {
|
|
3070
|
+
if (startupClientForAbandonedRequestCleanup === startupClient) startupClientForAbandonedRequestCleanup = void 0;
|
|
3071
|
+
await evictFailedStartupClient(startupClient);
|
|
3072
|
+
}
|
|
2828
3073
|
}
|
|
2829
3074
|
}
|
|
2830
3075
|
};
|
|
@@ -2863,15 +3108,82 @@ async function startCodexAttemptThread(params) {
|
|
|
2863
3108
|
releaseSharedClientLease
|
|
2864
3109
|
};
|
|
2865
3110
|
} catch (error) {
|
|
2866
|
-
if (params.signal.aborted ||
|
|
3111
|
+
if (params.signal.aborted || shouldClearSharedClientAfterStartupAbandon(error)) {
|
|
3112
|
+
releaseSharedClientLease?.();
|
|
3113
|
+
releaseSharedClientLease = void 0;
|
|
3114
|
+
await closeAbandonedStartupClient(startupClientForAbandonedRequestCleanup);
|
|
3115
|
+
startupClientForAbandonedRequestCleanup = void 0;
|
|
3116
|
+
} else if (shouldClearSharedClientAfterStartupRace(error) || shouldClearSharedClientAfterStartupFailure({
|
|
2867
3117
|
error,
|
|
2868
3118
|
spawnedBy: params.spawnedBy
|
|
2869
|
-
}))
|
|
3119
|
+
})) {
|
|
3120
|
+
releaseSharedClientLease?.();
|
|
3121
|
+
releaseSharedClientLease = void 0;
|
|
3122
|
+
await evictFailedStartupClient(startupClientForAbandonedRequestCleanup);
|
|
3123
|
+
startupClientForAbandonedRequestCleanup = void 0;
|
|
3124
|
+
}
|
|
2870
3125
|
throw error;
|
|
3126
|
+
} finally {
|
|
3127
|
+
params.signal.removeEventListener("abort", abandonStartupAcquire);
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
async function closeAbandonedStartupClient(client) {
|
|
3131
|
+
if (!client) return;
|
|
3132
|
+
const unclaimedSharedClient = clearSharedCodexAppServerClientIfCurrentAndUnclaimed(client);
|
|
3133
|
+
if (unclaimedSharedClient.closed) {
|
|
3134
|
+
await closeClientAndWaitIfAvailable(client);
|
|
3135
|
+
return;
|
|
3136
|
+
}
|
|
3137
|
+
if (unclaimedSharedClient.found) {
|
|
3138
|
+
if (retireSharedCodexAppServerClientIfCurrent(client)?.closed) await closeClientAndWaitIfAvailable(client);
|
|
3139
|
+
return;
|
|
3140
|
+
}
|
|
3141
|
+
const retiredSharedClient = retireSharedCodexAppServerClientIfCurrent(client);
|
|
3142
|
+
if (retiredSharedClient) {
|
|
3143
|
+
if (retiredSharedClient.closed) await closeClientAndWaitIfAvailable(client);
|
|
3144
|
+
return;
|
|
3145
|
+
}
|
|
3146
|
+
if (clearSharedCodexAppServerClientIfCurrent(client)) {
|
|
3147
|
+
await closeClientAndWaitIfAvailable(client);
|
|
3148
|
+
return;
|
|
3149
|
+
}
|
|
3150
|
+
await closeClientAndWaitIfAvailable(client);
|
|
3151
|
+
}
|
|
3152
|
+
async function closeClientAndWaitIfAvailable(client) {
|
|
3153
|
+
const closeable = client;
|
|
3154
|
+
if (typeof closeable.closeAndWait === "function") {
|
|
3155
|
+
await closeable.closeAndWait();
|
|
3156
|
+
return;
|
|
3157
|
+
}
|
|
3158
|
+
closeable.close?.();
|
|
3159
|
+
}
|
|
3160
|
+
async function evictFailedStartupClient(client) {
|
|
3161
|
+
if (!client) return;
|
|
3162
|
+
const unclaimedSharedClient = clearSharedCodexAppServerClientIfCurrentAndUnclaimed(client);
|
|
3163
|
+
if (unclaimedSharedClient.closed) {
|
|
3164
|
+
await closeClientAndWaitIfAvailable(client);
|
|
3165
|
+
return;
|
|
3166
|
+
}
|
|
3167
|
+
if (unclaimedSharedClient.found) {
|
|
3168
|
+
if (retireSharedCodexAppServerClientIfCurrent(client)?.closed) await closeClientAndWaitIfAvailable(client);
|
|
3169
|
+
return;
|
|
3170
|
+
}
|
|
3171
|
+
const retiredSharedClient = retireSharedCodexAppServerClientIfCurrent(client);
|
|
3172
|
+
if (retiredSharedClient) {
|
|
3173
|
+
if (retiredSharedClient.closed) await closeClientAndWaitIfAvailable(client);
|
|
3174
|
+
return;
|
|
3175
|
+
}
|
|
3176
|
+
if (clearSharedCodexAppServerClientIfCurrent(client)) {
|
|
3177
|
+
await closeClientAndWaitIfAvailable(client);
|
|
3178
|
+
return;
|
|
2871
3179
|
}
|
|
3180
|
+
await closeClientAndWaitIfAvailable(client);
|
|
3181
|
+
}
|
|
3182
|
+
function shouldClearSharedClientAfterStartupAbandon(error) {
|
|
3183
|
+
return error instanceof Error && (error.message === "codex app-server startup timed out" || error.message === "codex app-server startup aborted");
|
|
2872
3184
|
}
|
|
2873
3185
|
function shouldClearSharedClientAfterStartupRace(error) {
|
|
2874
|
-
return error instanceof Error && (error
|
|
3186
|
+
return error instanceof Error && (shouldClearSharedClientAfterStartupAbandon(error) || error.message.endsWith(" timed out"));
|
|
2875
3187
|
}
|
|
2876
3188
|
function shouldClearSharedClientAfterStartupFailure(params) {
|
|
2877
3189
|
if (!(params.error instanceof Error)) return !params.spawnedBy;
|
|
@@ -2880,7 +3192,15 @@ function shouldClearSharedClientAfterStartupFailure(params) {
|
|
|
2880
3192
|
}
|
|
2881
3193
|
//#endregion
|
|
2882
3194
|
//#region extensions/codex/src/app-server/attempt-steering.ts
|
|
3195
|
+
/**
|
|
3196
|
+
* Debounced steering queue for forwarding user text to an active Codex
|
|
3197
|
+
* app-server turn.
|
|
3198
|
+
*/
|
|
2883
3199
|
const CODEX_STEER_ALL_DEBOUNCE_MS = 500;
|
|
3200
|
+
/**
|
|
3201
|
+
* Creates a queue that batches steer text while still serializing app-server
|
|
3202
|
+
* `turn/steer` requests.
|
|
3203
|
+
*/
|
|
2884
3204
|
function createCodexSteeringQueue(params) {
|
|
2885
3205
|
let batchedTexts = [];
|
|
2886
3206
|
let batchTimer;
|
|
@@ -2951,9 +3271,11 @@ function createCodexSteeringQueue(params) {
|
|
|
2951
3271
|
}
|
|
2952
3272
|
};
|
|
2953
3273
|
}
|
|
3274
|
+
/** Normalizes steer debounce milliseconds, preserving explicit zero. */
|
|
2954
3275
|
function normalizeCodexSteerDebounceMs(value) {
|
|
2955
3276
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : CODEX_STEER_ALL_DEBOUNCE_MS;
|
|
2956
3277
|
}
|
|
3278
|
+
/** Converts plain text into the Codex app-server user-input shape. */
|
|
2957
3279
|
function toCodexTextInput(text) {
|
|
2958
3280
|
return {
|
|
2959
3281
|
type: "text",
|
|
@@ -2963,6 +3285,14 @@ function toCodexTextInput(text) {
|
|
|
2963
3285
|
}
|
|
2964
3286
|
//#endregion
|
|
2965
3287
|
//#region extensions/codex/src/app-server/attempt-turn-watches.ts
|
|
3288
|
+
/**
|
|
3289
|
+
* Idle-watch controller for Codex app-server turn progress, completion, and
|
|
3290
|
+
* terminal-event gaps.
|
|
3291
|
+
*/
|
|
3292
|
+
/**
|
|
3293
|
+
* Creates a controller that arms/disarms timers as Codex app-server
|
|
3294
|
+
* notifications and tool handoffs progress.
|
|
3295
|
+
*/
|
|
2966
3296
|
function createCodexAttemptTurnWatchController(params) {
|
|
2967
3297
|
let completionIdleTimer;
|
|
2968
3298
|
let completionIdleWatchArmed = false;
|
|
@@ -3281,8 +3611,10 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3281
3611
|
clearAllTimers
|
|
3282
3612
|
};
|
|
3283
3613
|
}
|
|
3614
|
+
/** Hard cap for per-call Codex dynamic tool timeout overrides. */
|
|
3284
3615
|
const CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 6e5;
|
|
3285
3616
|
const CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS = 12e4;
|
|
3617
|
+
/** Timeout for message-delivery dynamic tool calls. */
|
|
3286
3618
|
const CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS = 12e4;
|
|
3287
3619
|
const LOG_FIELD_MAX_LENGTH = 160;
|
|
3288
3620
|
function normalizeLogField(value) {
|
|
@@ -3332,6 +3664,10 @@ function formatDynamicToolTimeoutDetails(params) {
|
|
|
3332
3664
|
}
|
|
3333
3665
|
};
|
|
3334
3666
|
}
|
|
3667
|
+
/**
|
|
3668
|
+
* Runs a dynamic tool call with run-abort and per-call timeout handling,
|
|
3669
|
+
* returning a Codex protocol response instead of throwing.
|
|
3670
|
+
*/
|
|
3335
3671
|
async function handleDynamicToolCallWithTimeout(params) {
|
|
3336
3672
|
if (params.signal.aborted) return failedDynamicToolResponse("OpenClaw dynamic tool call aborted before execution.");
|
|
3337
3673
|
const controller = new AbortController();
|
|
@@ -3401,12 +3737,14 @@ function failedDynamicToolResponse(message, options) {
|
|
|
3401
3737
|
});
|
|
3402
3738
|
return response;
|
|
3403
3739
|
}
|
|
3740
|
+
/** Strips OpenClaw-only metadata before sending a dynamic tool response to Codex. */
|
|
3404
3741
|
function toCodexDynamicToolProtocolResponse(response) {
|
|
3405
3742
|
return {
|
|
3406
3743
|
contentItems: response.contentItems,
|
|
3407
3744
|
success: response.success
|
|
3408
3745
|
};
|
|
3409
3746
|
}
|
|
3747
|
+
/** Adds async-started progress details when a tool result continues out of band. */
|
|
3410
3748
|
function toCodexDynamicToolProgressResponse(response, protocolResponse) {
|
|
3411
3749
|
if (response.asyncStarted !== true) return protocolResponse;
|
|
3412
3750
|
return {
|
|
@@ -3417,21 +3755,26 @@ function toCodexDynamicToolProgressResponse(response, protocolResponse) {
|
|
|
3417
3755
|
}
|
|
3418
3756
|
};
|
|
3419
3757
|
}
|
|
3758
|
+
/** Decides whether a terminal dynamic tool response can release the Codex turn. */
|
|
3420
3759
|
function shouldReleaseTurnAfterTerminalDynamicTool(state) {
|
|
3421
3760
|
return !state.completed && !state.aborted && state.responseSuccess && !state.currentTurnHadNonTerminalDynamicToolResult && state.activeAppServerTurnRequests === 0 && state.activeTurnItemIdsCount === 0 && state.pendingOpenClawDynamicToolCompletionIdsCount === 0;
|
|
3422
3761
|
}
|
|
3762
|
+
/** Returns true when a non-async result should block terminal-release shortcuts. */
|
|
3423
3763
|
function shouldBlockTerminalReleaseForNonTerminalDynamicToolResult(response) {
|
|
3424
3764
|
return response.asyncStarted !== true;
|
|
3425
3765
|
}
|
|
3766
|
+
/** Resolves whether terminal diagnostic state should release, wait, or stay idle. */
|
|
3426
3767
|
function resolveTerminalDynamicToolBatchAction(state) {
|
|
3427
3768
|
if (state.activeAppServerTurnRequests > 0 || state.activeTurnItemIdsCount > 0 || state.pendingOpenClawDynamicToolCompletionIdsCount > 0) return "wait";
|
|
3428
3769
|
if (state.currentTurnHadNonTerminalDynamicToolResult) return "clear-nonterminal-batch";
|
|
3429
3770
|
if (state.hasPendingTerminalDynamicToolRelease) return "release-pending-terminal";
|
|
3430
3771
|
return "idle";
|
|
3431
3772
|
}
|
|
3773
|
+
/** Returns true for diagnostic events that terminate a dynamic tool call. */
|
|
3432
3774
|
function isDynamicToolTerminalDiagnosticEvent(event) {
|
|
3433
3775
|
return event.type === "tool.execution.completed" || event.type === "tool.execution.error" || event.type === "tool.execution.blocked";
|
|
3434
3776
|
}
|
|
3777
|
+
/** Matches terminal diagnostics to a specific dynamic tool call id/name. */
|
|
3435
3778
|
function isMatchingDynamicToolTerminalDiagnostic(params) {
|
|
3436
3779
|
if (params.event.toolCallId !== params.call.callId || params.event.toolName !== params.call.tool) return false;
|
|
3437
3780
|
if (params.runId !== void 0) return params.event.runId === params.runId;
|
|
@@ -3439,6 +3782,7 @@ function isMatchingDynamicToolTerminalDiagnostic(params) {
|
|
|
3439
3782
|
if (params.sessionKey !== void 0) return params.event.sessionKey === params.sessionKey;
|
|
3440
3783
|
return params.event.runId === void 0 && params.event.sessionId === void 0 && params.event.sessionKey === void 0;
|
|
3441
3784
|
}
|
|
3785
|
+
/** Checks pending diagnostics for a terminal event matching a tool call. */
|
|
3442
3786
|
function hasPendingDynamicToolTerminalDiagnostic(params) {
|
|
3443
3787
|
return hasPendingInternalDiagnosticEvent((event) => {
|
|
3444
3788
|
if (!isDynamicToolTerminalDiagnosticEvent(event)) return false;
|
|
@@ -3451,6 +3795,7 @@ function hasPendingDynamicToolTerminalDiagnostic(params) {
|
|
|
3451
3795
|
});
|
|
3452
3796
|
});
|
|
3453
3797
|
}
|
|
3798
|
+
/** Resolves per-tool timeout, applying media/message defaults and hard caps. */
|
|
3454
3799
|
function resolveDynamicToolCallTimeoutMs(params) {
|
|
3455
3800
|
return clampDynamicToolTimeoutMs(readDynamicToolCallTimeoutMs(params.call.arguments) ?? readConfiguredDynamicToolTimeoutMs(params.call.tool, params.config) ?? 9e4);
|
|
3456
3801
|
}
|
|
@@ -3485,6 +3830,7 @@ const OPENAI_CODEX_RESPONSES_API = "openai-chatgpt-responses";
|
|
|
3485
3830
|
function normalizeRuntimeId(value) {
|
|
3486
3831
|
return value?.trim().toLowerCase() ?? "";
|
|
3487
3832
|
}
|
|
3833
|
+
/** Maps local Codex runtime plans onto the provider/api pair exposed to event projection. */
|
|
3488
3834
|
function resolveCodexLocalRuntimeAttribution(params) {
|
|
3489
3835
|
const authProfileProvider = normalizeRuntimeId(params.runtimePlan?.auth?.authProfileProviderForAuth);
|
|
3490
3836
|
if (normalizeRuntimeId(params.runtimePlan?.observability.harnessId) === "codex" && authProfileProvider !== OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.provider) === OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.api) === OPENAI_RESPONSES_API) return {
|
|
@@ -3498,9 +3844,15 @@ function resolveCodexLocalRuntimeAttribution(params) {
|
|
|
3498
3844
|
}
|
|
3499
3845
|
//#endregion
|
|
3500
3846
|
//#region extensions/codex/src/app-server/tool-progress-normalization.ts
|
|
3847
|
+
/**
|
|
3848
|
+
* Normalizes and sanitizes Codex dynamic-tool progress payloads before they are
|
|
3849
|
+
* emitted into OpenClaw events or logs.
|
|
3850
|
+
*/
|
|
3851
|
+
/** Maps OpenClaw tool-progress config to the mode used by Codex progress metadata. */
|
|
3501
3852
|
function resolveCodexToolProgressDetailMode(value) {
|
|
3502
3853
|
return value === "raw" ? "raw" : "explain";
|
|
3503
3854
|
}
|
|
3855
|
+
/** Recursively redacts sensitive strings and handles circular values in event payloads. */
|
|
3504
3856
|
function sanitizeCodexAgentEventValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
3505
3857
|
if (typeof value === "string") return redactToolPayloadText(value);
|
|
3506
3858
|
if (Array.isArray(value)) {
|
|
@@ -3517,16 +3869,20 @@ function sanitizeCodexAgentEventValue(value, seen = /* @__PURE__ */ new WeakSet(
|
|
|
3517
3869
|
}
|
|
3518
3870
|
return value;
|
|
3519
3871
|
}
|
|
3872
|
+
/** Sanitizes a record-shaped Codex agent event payload. */
|
|
3520
3873
|
function sanitizeCodexAgentEventRecord(value) {
|
|
3521
3874
|
return sanitizeCodexAgentEventValue(value);
|
|
3522
3875
|
}
|
|
3876
|
+
/** Sanitizes dynamic-tool arguments before diagnostic/event emission. */
|
|
3523
3877
|
function sanitizeCodexToolArguments(value) {
|
|
3524
3878
|
if (!isJsonObject(value)) return;
|
|
3525
3879
|
return sanitizeCodexAgentEventRecord(value);
|
|
3526
3880
|
}
|
|
3881
|
+
/** Sanitizes a Codex dynamic-tool response before diagnostic/event emission. */
|
|
3527
3882
|
function sanitizeCodexToolResponse(response) {
|
|
3528
3883
|
return sanitizeCodexAgentEventRecord(response);
|
|
3529
3884
|
}
|
|
3885
|
+
/** Infers compact human-readable tool metadata from Codex dynamic-tool arguments. */
|
|
3530
3886
|
function inferCodexDynamicToolMeta(call, detailMode) {
|
|
3531
3887
|
return inferToolMetaFromArgs(call.tool, call.arguments, { detailMode });
|
|
3532
3888
|
}
|
|
@@ -5442,6 +5798,7 @@ function readTurn(value) {
|
|
|
5442
5798
|
//#region extensions/codex/src/app-server/native-subagent-notification.ts
|
|
5443
5799
|
const CODEX_SUBAGENT_NOTIFICATION_START = "<subagent_notification>";
|
|
5444
5800
|
const CODEX_SUBAGENT_NOTIFICATION_END = "</subagent_notification>";
|
|
5801
|
+
/** Extracts trusted subagent completion payloads from a Codex server notification. */
|
|
5445
5802
|
function extractCodexNativeSubagentCompletions(notification) {
|
|
5446
5803
|
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
5447
5804
|
if (!params) return [];
|
|
@@ -5452,6 +5809,7 @@ function extractCodexNativeSubagentCompletions(notification) {
|
|
|
5452
5809
|
const author = readTrustedInterAgentCommunicationAuthor(item);
|
|
5453
5810
|
return extractCodexNativeSubagentCompletionsFromText(text).filter((completion) => completion.agentPath === author);
|
|
5454
5811
|
}
|
|
5812
|
+
/** Parses one or more tagged subagent completion payloads from commentary text. */
|
|
5455
5813
|
function extractCodexNativeSubagentCompletionsFromText(text) {
|
|
5456
5814
|
const completions = [];
|
|
5457
5815
|
let cursor = 0;
|
|
@@ -5552,11 +5910,19 @@ function normalizeStatusKey(value) {
|
|
|
5552
5910
|
}
|
|
5553
5911
|
//#endregion
|
|
5554
5912
|
//#region extensions/codex/src/app-server/native-subagent-task-ids.ts
|
|
5913
|
+
/**
|
|
5914
|
+
* Shared identifiers for representing Codex native subagents as OpenClaw task
|
|
5915
|
+
* runtime rows.
|
|
5916
|
+
*/
|
|
5917
|
+
/** Task runtime namespace for Codex native subagent task rows. */
|
|
5555
5918
|
const CODEX_NATIVE_SUBAGENT_RUNTIME = "subagent";
|
|
5919
|
+
/** Task kind used to distinguish native Codex subagents from other subagent runtimes. */
|
|
5556
5920
|
const CODEX_NATIVE_SUBAGENT_TASK_KIND = "codex-native";
|
|
5921
|
+
/** Run id prefix for task rows keyed by Codex child thread ids. */
|
|
5557
5922
|
const CODEX_NATIVE_SUBAGENT_RUN_ID_PREFIX = "codex-thread:";
|
|
5558
5923
|
//#endregion
|
|
5559
5924
|
//#region extensions/codex/src/app-server/native-subagent-task-mirror.ts
|
|
5925
|
+
/** Projects Codex thread and collab-agent notifications into task lifecycle updates. */
|
|
5560
5926
|
var CodexNativeSubagentTaskMirror = class {
|
|
5561
5927
|
constructor(params, runtime) {
|
|
5562
5928
|
this.params = params;
|
|
@@ -5771,9 +6137,11 @@ var CodexNativeSubagentTaskMirror = class {
|
|
|
5771
6137
|
});
|
|
5772
6138
|
}
|
|
5773
6139
|
};
|
|
6140
|
+
/** Converts a Codex child thread id into the OpenClaw task-runtime run id. */
|
|
5774
6141
|
function codexNativeSubagentRunId(threadId) {
|
|
5775
6142
|
return `${CODEX_NATIVE_SUBAGENT_RUN_ID_PREFIX}${threadId.trim()}`;
|
|
5776
6143
|
}
|
|
6144
|
+
/** Reads a subagent thread-spawn source only when it belongs to the expected parent thread. */
|
|
5777
6145
|
function readSubagentThreadSpawnSource(source, parentThreadId) {
|
|
5778
6146
|
if (!source || typeof source !== "object" || !("subAgent" in source)) return;
|
|
5779
6147
|
const subAgent = source.subAgent;
|
|
@@ -5866,6 +6234,10 @@ function trimOptional(value) {
|
|
|
5866
6234
|
}
|
|
5867
6235
|
//#endregion
|
|
5868
6236
|
//#region extensions/codex/src/app-server/native-subagent-monitor.ts
|
|
6237
|
+
/**
|
|
6238
|
+
* Monitors Codex native subagent threads and mirrors their lifecycle/completion
|
|
6239
|
+
* into OpenClaw task runtime records for parent sessions.
|
|
6240
|
+
*/
|
|
5869
6241
|
const DEFAULT_TRANSCRIPT_POLL_DELAYS_MS = [
|
|
5870
6242
|
2e3,
|
|
5871
6243
|
5e3,
|
|
@@ -5891,6 +6263,7 @@ const defaultRuntime = {
|
|
|
5891
6263
|
deliverAgentHarnessTaskCompletion
|
|
5892
6264
|
};
|
|
5893
6265
|
const monitors = /* @__PURE__ */ new WeakMap();
|
|
6266
|
+
/** Registers or updates the monitor bound to a Codex app-server client. */
|
|
5894
6267
|
function registerCodexNativeSubagentMonitor(params) {
|
|
5895
6268
|
let monitor = monitors.get(params.client);
|
|
5896
6269
|
if (!monitor) {
|
|
@@ -5904,6 +6277,7 @@ function registerCodexNativeSubagentMonitor(params) {
|
|
|
5904
6277
|
agentId: params.agentId
|
|
5905
6278
|
});
|
|
5906
6279
|
}
|
|
6280
|
+
/** Tracks native subagent thread notifications, transcript completions, and task delivery. */
|
|
5907
6281
|
var CodexNativeSubagentMonitor = class {
|
|
5908
6282
|
constructor(client, runtime = defaultRuntime, options = {}) {
|
|
5909
6283
|
this.runtime = runtime;
|
|
@@ -6701,6 +7075,7 @@ function minFiniteNumber(values) {
|
|
|
6701
7075
|
function hasContextEngineThreadBootstrapProjection(binding) {
|
|
6702
7076
|
return binding.contextEngine?.projection?.mode === "thread_bootstrap";
|
|
6703
7077
|
}
|
|
7078
|
+
/** Clears and drops a binding when the native Codex thread is too large to resume safely. */
|
|
6704
7079
|
async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
6705
7080
|
const binding = params.binding;
|
|
6706
7081
|
if (!binding?.threadId) return binding;
|
|
@@ -6767,6 +7142,10 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
|
6767
7142
|
}
|
|
6768
7143
|
//#endregion
|
|
6769
7144
|
//#region extensions/codex/src/app-server/trajectory.ts
|
|
7145
|
+
/**
|
|
7146
|
+
* Records optional Codex runtime trajectory sidecars with bounded, redacted
|
|
7147
|
+
* context and completion events.
|
|
7148
|
+
*/
|
|
6770
7149
|
const SENSITIVE_FIELD_RE = /(?:authorization|cookie|credential|key|password|passwd|secret|token)/iu;
|
|
6771
7150
|
const PRIVATE_PAYLOAD_FIELD_RE = /(?:image|screenshot|attachment|fileData|dataUri)/iu;
|
|
6772
7151
|
const AUTHORIZATION_VALUE_RE = /\b(Bearer|Basic)\s+[A-Za-z0-9+/._~=-]{8,}/giu;
|
|
@@ -6774,6 +7153,7 @@ const JWT_VALUE_RE = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]
|
|
|
6774
7153
|
const COOKIE_PAIR_RE = /\b([A-Za-z][A-Za-z0-9_.-]{1,64})=([A-Za-z0-9+/._~%=-]{16,})(?=;|\s|$)/gu;
|
|
6775
7154
|
const TRAJECTORY_RUNTIME_FILE_MAX_BYTES = 50 * 1024 * 1024;
|
|
6776
7155
|
const TRAJECTORY_RUNTIME_EVENT_MAX_BYTES = 256 * 1024;
|
|
7156
|
+
/** Resolves secure create/truncate flags for trajectory pointer files. */
|
|
6777
7157
|
function resolveCodexTrajectoryPointerFlags(constants = fsSync.constants) {
|
|
6778
7158
|
const noFollow = constants.O_NOFOLLOW;
|
|
6779
7159
|
return constants.O_CREAT | constants.O_TRUNC | constants.O_WRONLY | (typeof noFollow === "number" ? noFollow : 0);
|
|
@@ -6828,6 +7208,7 @@ function writeTrajectoryPointerBestEffort(params) {
|
|
|
6828
7208
|
}
|
|
6829
7209
|
} catch {}
|
|
6830
7210
|
}
|
|
7211
|
+
/** Creates a trajectory recorder when trajectory capture is enabled for the environment. */
|
|
6831
7212
|
function createCodexTrajectoryRecorder(params) {
|
|
6832
7213
|
const env = params.env ?? process.env;
|
|
6833
7214
|
if (!parseTrajectoryEnabled(env)) return null;
|
|
@@ -6877,6 +7258,7 @@ function createCodexTrajectoryRecorder(params) {
|
|
|
6877
7258
|
}
|
|
6878
7259
|
};
|
|
6879
7260
|
}
|
|
7261
|
+
/** Records compiled prompt/tool context at the start of a Codex runtime attempt. */
|
|
6880
7262
|
function recordCodexTrajectoryContext(recorder, params) {
|
|
6881
7263
|
if (!recorder) return;
|
|
6882
7264
|
recorder.recordEvent("context.compiled", {
|
|
@@ -6886,6 +7268,7 @@ function recordCodexTrajectoryContext(recorder, params) {
|
|
|
6886
7268
|
tools: toTrajectoryToolDefinitions(params.tools)
|
|
6887
7269
|
});
|
|
6888
7270
|
}
|
|
7271
|
+
/** Records final Codex model completion metadata and assistant snapshots. */
|
|
6889
7272
|
function recordCodexTrajectoryCompletion(recorder, params) {
|
|
6890
7273
|
if (!recorder) return;
|
|
6891
7274
|
recorder.recordEvent("model.completed", {
|
|
@@ -6955,6 +7338,7 @@ function sanitizeValue(value, depth = 0, key = "") {
|
|
|
6955
7338
|
function redactSensitiveString(value) {
|
|
6956
7339
|
return value.replace(AUTHORIZATION_VALUE_RE, "$1 <redacted>").replace(JWT_VALUE_RE, "<redacted-jwt>").replace(COOKIE_PAIR_RE, "$1=<redacted>");
|
|
6957
7340
|
}
|
|
7341
|
+
/** Converts arbitrary prompt errors into trajectory-safe text. */
|
|
6958
7342
|
function normalizeCodexTrajectoryError(value) {
|
|
6959
7343
|
if (!value) return null;
|
|
6960
7344
|
if (value instanceof Error) return value.message;
|
|
@@ -6967,7 +7351,12 @@ function normalizeCodexTrajectoryError(value) {
|
|
|
6967
7351
|
}
|
|
6968
7352
|
//#endregion
|
|
6969
7353
|
//#region extensions/codex/src/app-server/usage-limit-error.ts
|
|
7354
|
+
/**
|
|
7355
|
+
* Enriches Codex usage-limit failures with current rate-limit information and
|
|
7356
|
+
* marks blocked auth profiles when Codex exposes a reset time.
|
|
7357
|
+
*/
|
|
6970
7358
|
const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
|
|
7359
|
+
/** Marks a Codex auth profile blocked until the reset time advertised by rate limits. */
|
|
6971
7360
|
async function markCodexAuthProfileBlockedFromRateLimits(params) {
|
|
6972
7361
|
const authProfileId = params.authProfileId?.trim();
|
|
6973
7362
|
if (!authProfileId || !params.params.authProfileStore) return;
|
|
@@ -6990,6 +7379,7 @@ async function markCodexAuthProfileBlockedFromRateLimits(params) {
|
|
|
6990
7379
|
});
|
|
6991
7380
|
}
|
|
6992
7381
|
}
|
|
7382
|
+
/** Formats a turn-start usage-limit error, refreshing rate limits when needed. */
|
|
6993
7383
|
async function formatCodexTurnStartUsageLimitError(params) {
|
|
6994
7384
|
return refreshCodexUsageLimitError({
|
|
6995
7385
|
client: params.client,
|
|
@@ -6998,6 +7388,7 @@ async function formatCodexTurnStartUsageLimitError(params) {
|
|
|
6998
7388
|
signal: params.signal
|
|
6999
7389
|
});
|
|
7000
7390
|
}
|
|
7391
|
+
/** Refreshes a generic prompt usage-limit message into a reset-aware message. */
|
|
7001
7392
|
async function refreshCodexUsageLimitPromptError(params) {
|
|
7002
7393
|
if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(params.message)) return;
|
|
7003
7394
|
return (await refreshCodexUsageLimitError({
|
|
@@ -7107,6 +7498,11 @@ function readString$1(record, key) {
|
|
|
7107
7498
|
}
|
|
7108
7499
|
//#endregion
|
|
7109
7500
|
//#region extensions/codex/src/app-server/user-input-bridge.ts
|
|
7501
|
+
/**
|
|
7502
|
+
* Bridges Codex item/tool user-input requests to OpenClaw messaging prompts and
|
|
7503
|
+
* turns replies into app-server answer payloads.
|
|
7504
|
+
*/
|
|
7505
|
+
/** Creates a per-turn bridge for pending Codex user-input requests. */
|
|
7110
7506
|
function createCodexUserInputBridge(params) {
|
|
7111
7507
|
let pending;
|
|
7112
7508
|
const resolvePending = (value) => {
|
|
@@ -8916,7 +9312,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8916
9312
|
}),
|
|
8917
9313
|
runMaintenance: runHarnessContextEngineMaintenance,
|
|
8918
9314
|
config: params.config,
|
|
8919
|
-
warn: (message) => embeddedAgentLog.warn(message)
|
|
9315
|
+
warn: (message) => embeddedAgentLog.warn(message),
|
|
9316
|
+
isHeartbeat: params.bootstrapContextRunKind === "heartbeat"
|
|
8920
9317
|
});
|
|
8921
9318
|
}
|
|
8922
9319
|
runAgentHarnessLlmOutputHook({
|