@openclaw/codex 2026.8.1-beta.3 → 2026.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +5 -6
- package/dist/{attempt-client-cleanup-URjUlCHg.js → attempt-client-cleanup-CpVfwctT.js} +47 -5
- package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
- package/dist/{binding-connection-DAvZwp96.js → binding-connection-CF7BmrDk.js} +2 -2
- package/dist/{bounded-turn-4BjrZEwW.js → bounded-turn-DRC3hcjm.js} +16 -20
- package/dist/{capabilities-CH3K57v4.js → capabilities-D6m_TdVy.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-D0nZ3qtd.js → command-formatters--UToCokS.js} +4 -3
- package/dist/{command-handlers-DC86lgT4.js → command-handlers-CLFx2Ypa.js} +114 -79
- package/dist/{compact-COqgBRny.js → compact-5xqW1oCh.js} +13 -12
- package/dist/{config-CpNeo5AE.js → config-CcYL77O6.js} +350 -288
- package/dist/{conversation-binding-data-CW2GuupV.js → conversation-binding-data-BiodpIzq.js} +2 -1
- package/dist/doctor-contract-api.js +121 -16
- package/dist/{dynamic-tools-fJZhl4CE.js → dynamic-tools-BmeXjwNZ.js} +243 -1002
- package/dist/{effective-mcp-catalog-4YKn51aG.js → effective-mcp-catalog-XXQKgK1U.js} +2 -2
- package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
- package/dist/{event-projector-usage-CLwNEJqW.js → event-projector-usage-B2r5vhWH.js} +9 -14
- package/dist/{harness-DoKQcF8n.js → harness-BgeB7LnD.js} +42 -52
- package/dist/harness.js +1 -1
- package/dist/index.js +308 -306
- package/dist/{isolated-completion-DPMtlH9r.js → isolated-completion-CxTus3vZ.js} +4 -4
- package/dist/launch-args-sXOAg0SX.js +84 -0
- package/dist/{managed-binary-By4FZC6i.js → managed-binary-ZkGodW19.js} +43 -7
- package/dist/media-understanding-provider.js +1 -1
- package/dist/model-catalog-DULBcniB.js +101 -0
- package/dist/{models-CZw1wClT.js → models-DaWfETQk.js} +27 -29
- package/dist/{native-subagent-monitor-GGq3RnOo.js → native-subagent-monitor-vXYUZH37.js} +226 -129
- package/dist/{node-exec-server.runtime-Bsu1LdFZ.js → node-exec-server.runtime-DirKVZ5h.js} +9 -6
- package/dist/{plugin-approval-roundtrip-C75Yiiwc.js → plugin-approval-roundtrip-CCWQGlAI.js} +2 -1
- package/dist/{plugin-marketplace-discovery-CSWDkMrP.js → plugin-marketplace-discovery-BXjIFEiw.js} +38 -46
- package/dist/{plugin-metadata-cache-BXH5NF-4.js → plugin-metadata-cache-DQQm4gWT.js} +163 -136
- package/dist/{protocol-validators-VAVyEnDp.js → protocol-validators-Bg5rpNxk.js} +148 -5
- package/dist/{rate-limits-BI1dMHDG.js → rate-limits-BqHEHXQJ.js} +3 -2
- package/dist/{sandbox-guard-C1qEeZ5C.js → request-BWxweEdK.js} +183 -2
- package/dist/{run-attempt-BV3HzuCf.js → run-attempt-BVLE4Gbi.js} +706 -517
- package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-D9pYp4zL.js} +3 -3
- package/dist/{session-binding-BTrLf9Qm.js → session-binding-D0zinCP1.js} +195 -122
- package/dist/{session-catalog-ezP_UcRM.js → session-catalog-eMhVm0Ql.js} +448 -313
- package/dist/session-catalog-home-id-Dt2GiG5o.js +112 -0
- package/dist/{session-cli-B1hKvfkI.js → session-cli-B2lyjJA0.js} +1 -1
- package/dist/session-history-C5J1AKzG.js +87 -0
- package/dist/session-permission-policy-ScnAyG90.js +160 -0
- package/dist/session-retirement-CtUtUTr9.js +90 -0
- package/dist/{session-upstream-marker-D_2npHlA.js → session-upstream-marker-gqrYIRHk.js} +2 -3
- package/dist/settled-turn-context-Bk3IUwod.js +290 -0
- package/dist/settled-turn-finalizer-BXLN9PfJ.js +104 -0
- package/dist/{shared-client-Dw-rzii0.js → shared-client-B1tT5U6r.js} +1738 -806
- package/dist/{side-question-DbXkJZzg.js → side-question-CZ-mCw-t.js} +76 -43
- package/dist/{thread-lifecycle-DKdrnTMX.js → thread-lifecycle-CGGKP720.js} +991 -455
- package/dist/{thread-ownership-i2NBwDUL.js → thread-ownership-RkaoZCmQ.js} +18 -8
- package/dist/{plugin-app-cache-key-DMNQ8Zi8.js → thread-resume-BFt1-ZDa.js} +55 -8
- package/dist/{transcript-mirror-BU0_LKAL.js → transcript-mirror-1ep4XjzF.js} +124 -18
- package/dist/transport-stdio-NT_Dpd9V.js +724 -0
- package/dist/{upstream-prompt-provenance-CFmsKwr9.js → upstream-prompt-provenance-LphB8slG.js} +8 -4
- package/dist/{upstream-session-fork-BDVJCLAD.js → upstream-session-fork-Dc8BFExw.js} +76 -90
- package/dist/{usage-9dKJCgcy.js → usage-DUhd58gI.js} +3 -3
- package/dist/{web-search-provider.runtime-DCdx4DGu.js → web-search-provider.runtime-BEmlE7ov.js} +3 -3
- package/openclaw.plugin.json +19 -1
- package/package.json +8 -8
- package/dist/app-server-policy-bg5QPSVP.js +0 -25
- package/dist/command-rpc-xUIIonsO.js +0 -90
- package/dist/incognito-session-ET_ufDH-.js +0 -2
- package/dist/model-catalog-CmGoqVKB.js +0 -48
- package/dist/request-DSK0W6YI.js +0 -157
- package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
- package/dist/session-retirement-CE4iMiLh.js +0 -36
- package/dist/settled-turn-finalizer-Dx1onIqg.js +0 -328
- package/dist/thread-resume-CdJk2Ehf.js +0 -30
- package/dist/transport-stdio-DhoGy33Z.js +0 -99
|
@@ -1,818 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { C as isCodexRemoteExecPlacementSandbox, T as readCodexPluginConfig } from "./config-CcYL77O6.js";
|
|
2
|
+
import { Bt as CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE, Ht as isJsonObject, dt as resolveCodexToolAbortTerminalReason, et as createCodexElicitationResponse, ft as createFailedDynamicToolResponse, h as releaseLeasedSharedCodexAppServerClient, mt as withDynamicToolTranscriptDetails, pt as withDynamicToolExecutionState } from "./shared-client-B1tT5U6r.js";
|
|
3
|
+
import { d as readCodexTurn } from "./protocol-validators-Bg5rpNxk.js";
|
|
4
|
+
import { D as itemStatus, I as readItem, b as auditNativeToolTerminalStatus, g as isCodexNotificationForTurn, x as auditNativeToolUnfinishedStatus, y as auditNativeToolName } from "./attempt-client-cleanup-CpVfwctT.js";
|
|
5
|
+
import { H as normalizeCodexDynamicToolName, L as filterCodexDynamicTools, R as filterCodexDynamicToolsForDisabledNativeSurface, V as isSystemAgentOnlyCodexDynamicToolAllowlist, d as emitCodexNativePreToolUseFailureDiagnostic, x as resolveCodexWebSearchPlan, z as isForcedPrivateQaCodexRuntime } from "./thread-lifecycle-CGGKP720.js";
|
|
6
|
+
import { l as resolveCodexNativeExecutionPolicy, u as resolveCodexNodeExecToolOverrides } from "./request-BWxweEdK.js";
|
|
6
7
|
import { r as sanitizeInlineImageDataUrl, t as invalidInlineImageText } from "./image-payload-sanitizer-CnfoUPCE.js";
|
|
7
|
-
import { r as formatCodexDisplayText } from "./command-formatters
|
|
8
|
-
import { a as
|
|
9
|
-
import { a as sanitizeCodexApprovalVisibleText, c as waitForPluginApprovalDecision, i as requestPluginApproval, n as codexApprovalTimeoutText, o as stripDanglingCodexApprovalTerminalSequence, r as mapExecDecisionToOutcome, s as truncateCodexApprovalDisplayText, t as approvalRequestExplicitlyUnavailable } from "./plugin-approval-roundtrip-C75Yiiwc.js";
|
|
8
|
+
import { r as formatCodexDisplayText } from "./command-formatters--UToCokS.js";
|
|
9
|
+
import { a as sanitizeCodexApprovalVisibleText, c as waitForPluginApprovalDecision, i as requestPluginApproval, n as codexApprovalTimeoutText, o as stripDanglingCodexApprovalTerminalSequence, r as mapExecDecisionToOutcome, s as truncateCodexApprovalDisplayText, t as approvalRequestExplicitlyUnavailable } from "./plugin-approval-roundtrip-CCWQGlAI.js";
|
|
10
10
|
import { asNonArrayRecord, asOptionalRecord, isRecord, normalizeOptionalString, normalizeTrimmedStringList, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
11
11
|
import { validateJsonSchemaValue } from "openclaw/plugin-sdk/json-schema-runtime";
|
|
12
12
|
import path, { posix } from "node:path";
|
|
13
13
|
import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
|
|
14
|
-
import {
|
|
14
|
+
import { asDateTimestampMs } from "openclaw/plugin-sdk/number-runtime";
|
|
15
15
|
import { HEARTBEAT_RESPONSE_TOOL_NAME, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, consumeAdjustedParamsForToolCall, consumePreExecutionBlockedToolCall, createAgentToolResultMiddlewareRunner, createCodexAppServerToolResultExtensionRunner, embeddedAgentLog, extractMessagingToolSend, extractMessagingToolSendResult, extractToolResultMediaArtifact, filterProviderNormalizableTools, filterToolResultMediaUrls, finalizeToolTerminalPresentation, formatApprovalDisplayPath, formatToolExecutionErrorMessage, getBeforeToolCallFailureDisposition, getChannelAgentToolMeta, getPluginToolMeta, getPluginToolSideEffectOwnerKey, hasNativeHookRelayInvocation, invokeNativeHookRelay, isDeliveredMessageToolOnlySourceReplyResult, isDeliveredMessagingToolResult, isHostScopedAgentToolActive, isMessagingTool, isMessagingToolSendAction, isReplaySafeToolCall, isSubagentSessionKey, isToolResultError, isToolWrappedWithBeforeToolCallHook, normalizeAgentRuntimeTools, normalizeHeartbeatToolResponse, projectRuntimeToolInputSchema, resolveAttemptSpawnWorkspaceDir, resolveModelAuthMode, resolveNativeHookRelayDeferredToolApproval, resolveToolExecutionErrorKind, resolveToolResultFailureKind, runAgentHarnessAfterToolCallHook, sanitizeToolResult, setBeforeToolCallDiagnosticsEnabled, supportsModelTools, wrapToolWithBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
16
16
|
import { createHash, randomUUID } from "node:crypto";
|
|
17
17
|
import { resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
|
|
18
|
-
import { killProcessTree } from "openclaw/plugin-sdk/process-runtime";
|
|
19
18
|
import { formatErrorMessage as formatErrorMessage$1, redactSensitiveText } from "openclaw/plugin-sdk/security-runtime";
|
|
19
|
+
import { killProcessTree } from "openclaw/plugin-sdk/process-runtime";
|
|
20
20
|
import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
21
21
|
import { spawn } from "node:child_process";
|
|
22
|
+
import { once } from "node:events";
|
|
22
23
|
import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
23
24
|
import { DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS, estimateToolResultTextChars, resolveLiveToolResultMaxChars, sliceToolResultTextToBudget, sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
24
|
-
import {
|
|
25
|
+
import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
25
26
|
import { isIP } from "node:net";
|
|
26
27
|
import { WebSocketServer } from "ws";
|
|
27
28
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
28
29
|
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
29
30
|
import { redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
|
|
30
31
|
import { isPathStrictlyInside, root } from "openclaw/plugin-sdk/file-access-runtime";
|
|
31
|
-
import { runWithCronCreatorAuthorityCapabilityResolver } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
32
|
-
import { emitTrustedDiagnosticEvent, hasPendingInternalDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
33
32
|
import { buildRemoteCommand, isToolAllowed, sanitizeEnvVars } from "openclaw/plugin-sdk/sandbox";
|
|
33
|
+
import { pinExecToolTarget, resolveCodexScheduledToolProjectionFactory, runWithCronCreatorAuthorityCapabilityResolver } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
34
34
|
import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
35
|
-
import { registerRetainedNativeHookRelayForBundledRuntime } from "openclaw/plugin-sdk/native-hook-relay-runtime";
|
|
36
35
|
import { getMediaDir } from "openclaw/plugin-sdk/media-runtime";
|
|
36
|
+
import { getCoreTtsToolResultMediaUrls } from "openclaw/plugin-sdk/agent-harness-tool-runtime";
|
|
37
37
|
import { normalizeOpenAIToolSchemas } from "openclaw/plugin-sdk/provider-tools";
|
|
38
|
-
//#region extensions/codex/src/app-server/dynamic-tool-response-state.ts
|
|
39
|
-
/** Retains the host-owned app preview without adding it to Codex's response payload. */
|
|
40
|
-
function withDynamicToolTranscriptDetails(response, details) {
|
|
41
|
-
if (details === void 0) return response;
|
|
42
|
-
Object.defineProperty(response, "transcriptDetails", {
|
|
43
|
-
configurable: true,
|
|
44
|
-
enumerable: false,
|
|
45
|
-
value: details
|
|
46
|
-
});
|
|
47
|
-
return response;
|
|
48
|
-
}
|
|
49
|
-
function withDynamicToolTerminalResolution(response, terminalResolution) {
|
|
50
|
-
if (terminalResolution) {
|
|
51
|
-
Object.defineProperties(response, {
|
|
52
|
-
terminalResolution: {
|
|
53
|
-
configurable: true,
|
|
54
|
-
enumerable: false,
|
|
55
|
-
value: terminalResolution
|
|
56
|
-
},
|
|
57
|
-
executionStarted: {
|
|
58
|
-
configurable: true,
|
|
59
|
-
enumerable: false,
|
|
60
|
-
value: terminalResolution.executionStarted
|
|
61
|
-
},
|
|
62
|
-
...terminalResolution.executedArguments ? { executedArguments: {
|
|
63
|
-
configurable: true,
|
|
64
|
-
enumerable: false,
|
|
65
|
-
value: terminalResolution.executedArguments
|
|
66
|
-
} } : {}
|
|
67
|
-
});
|
|
68
|
-
withDynamicToolSideEffectEvidence(response, terminalResolution.sideEffectEvidence);
|
|
69
|
-
}
|
|
70
|
-
return response;
|
|
71
|
-
}
|
|
72
|
-
function withDynamicToolExecutionState(response, state) {
|
|
73
|
-
Object.defineProperties(response, {
|
|
74
|
-
executedArguments: {
|
|
75
|
-
configurable: true,
|
|
76
|
-
enumerable: false,
|
|
77
|
-
value: state.executedArguments
|
|
78
|
-
},
|
|
79
|
-
executionStarted: {
|
|
80
|
-
configurable: true,
|
|
81
|
-
enumerable: false,
|
|
82
|
-
value: state.executionStarted
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
return withDynamicToolSideEffectEvidence(response, state.sideEffectEvidence === true);
|
|
86
|
-
}
|
|
87
|
-
function withDynamicToolSideEffectEvidence(response, sideEffectEvidence) {
|
|
88
|
-
if (!sideEffectEvidence) {
|
|
89
|
-
delete response.sideEffectEvidence;
|
|
90
|
-
return response;
|
|
91
|
-
}
|
|
92
|
-
Object.defineProperty(response, "sideEffectEvidence", {
|
|
93
|
-
configurable: true,
|
|
94
|
-
enumerable: false,
|
|
95
|
-
value: true
|
|
96
|
-
});
|
|
97
|
-
return response;
|
|
98
|
-
}
|
|
99
|
-
function createFailedDynamicToolResponse(message, options) {
|
|
100
|
-
const response = {
|
|
101
|
-
contentItems: [{
|
|
102
|
-
type: "inputText",
|
|
103
|
-
text: message
|
|
104
|
-
}],
|
|
105
|
-
success: false
|
|
106
|
-
};
|
|
107
|
-
Object.defineProperties(response, {
|
|
108
|
-
diagnosticTerminalReason: {
|
|
109
|
-
configurable: true,
|
|
110
|
-
enumerable: false,
|
|
111
|
-
value: options?.terminalReason ?? "failed"
|
|
112
|
-
},
|
|
113
|
-
diagnosticTerminalType: {
|
|
114
|
-
configurable: true,
|
|
115
|
-
enumerable: false,
|
|
116
|
-
value: "error"
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
if (options?.executionStarted !== void 0) Object.defineProperty(response, "executionStarted", {
|
|
120
|
-
configurable: true,
|
|
121
|
-
enumerable: false,
|
|
122
|
-
value: options.executionStarted
|
|
123
|
-
});
|
|
124
|
-
if (options?.executedArguments !== void 0) Object.defineProperty(response, "executedArguments", {
|
|
125
|
-
configurable: true,
|
|
126
|
-
enumerable: false,
|
|
127
|
-
value: options.executedArguments
|
|
128
|
-
});
|
|
129
|
-
return withDynamicToolSideEffectEvidence(response, options?.sideEffectEvidence === true);
|
|
130
|
-
}
|
|
131
|
-
//#endregion
|
|
132
|
-
//#region extensions/codex/src/app-server/tool-abort-terminal-reason.ts
|
|
133
|
-
/** Leaf helper shared by native and dynamic tool diagnostics. */
|
|
134
|
-
const CODEX_TIMEOUT_ABORT_REASONS = /* @__PURE__ */ new Set([
|
|
135
|
-
"codex_startup_timeout",
|
|
136
|
-
"turn_completion_idle_timeout",
|
|
137
|
-
"turn_progress_idle_timeout",
|
|
138
|
-
"turn_terminal_idle_timeout"
|
|
139
|
-
]);
|
|
140
|
-
/** Preserves timeout provenance when an enclosing run aborts an active tool. */
|
|
141
|
-
function resolveCodexToolAbortTerminalReason(signal) {
|
|
142
|
-
try {
|
|
143
|
-
const reason = signal.reason;
|
|
144
|
-
if (typeof reason === "string") {
|
|
145
|
-
if (CODEX_TIMEOUT_ABORT_REASONS.has(reason)) return "timed_out";
|
|
146
|
-
return reason === "client_closed" ? "failed" : "cancelled";
|
|
147
|
-
}
|
|
148
|
-
if (reason && typeof reason === "object") {
|
|
149
|
-
const record = reason;
|
|
150
|
-
if (record.name === "TimeoutError" || record.reason === "timeout") return "timed_out";
|
|
151
|
-
}
|
|
152
|
-
} catch {
|
|
153
|
-
return "cancelled";
|
|
154
|
-
}
|
|
155
|
-
return "cancelled";
|
|
156
|
-
}
|
|
157
|
-
//#endregion
|
|
158
|
-
//#region extensions/codex/src/app-server/dynamic-tool-execution.ts
|
|
159
|
-
/**
|
|
160
|
-
* Timeout, terminal-release, and diagnostic helpers for Codex dynamic tool
|
|
161
|
-
* calls.
|
|
162
|
-
*/
|
|
163
|
-
/** Default timeout for Codex dynamic tool calls. */
|
|
164
|
-
const CODEX_DYNAMIC_TOOL_TIMEOUT_MS = 9e4;
|
|
165
|
-
/** Hard cap for per-call Codex dynamic tool timeout overrides. */
|
|
166
|
-
const CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 6e5;
|
|
167
|
-
const CODEX_DYNAMIC_TOOL_TIMEOUT_SECONDS_GRACE_MS = 3e4;
|
|
168
|
-
const CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS = 12e4;
|
|
169
|
-
const CODEX_DYNAMIC_COMPUTER_GATEWAY_TIMEOUT_MS = 3e4;
|
|
170
|
-
const CODEX_DYNAMIC_COMPUTER_COMPLETION_GRACE_MS = 3e4;
|
|
171
|
-
/** Timeout for image-understanding style dynamic tool calls. */
|
|
172
|
-
const CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS = 6e4;
|
|
173
|
-
/** Timeout for message-delivery dynamic tool calls. */
|
|
174
|
-
const CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS = 6e5;
|
|
175
|
-
/** Outer default for collector waits: full swarm budget plus completion grace. */
|
|
176
|
-
const CODEX_DYNAMIC_AGENTS_WAIT_TOOL_TIMEOUT_MS = 63e4;
|
|
177
|
-
const LOG_FIELD_MAX_LENGTH = 160;
|
|
178
|
-
function normalizeLogField(value) {
|
|
179
|
-
if (typeof value !== "string") return;
|
|
180
|
-
const normalized = value.replaceAll(String.fromCharCode(27), " ").replaceAll("\r", " ").replaceAll("\n", " ").replaceAll(" ", " ").trim();
|
|
181
|
-
if (!normalized) return;
|
|
182
|
-
return normalized.length > LOG_FIELD_MAX_LENGTH ? `${truncateUtf16Safe(normalized, LOG_FIELD_MAX_LENGTH - 3)}...` : normalized;
|
|
183
|
-
}
|
|
184
|
-
function readNumericTimeoutMs(value) {
|
|
185
|
-
if (typeof value === "number" && Number.isFinite(value)) return Math.max(0, Math.floor(value));
|
|
186
|
-
if (typeof value === "string") {
|
|
187
|
-
const parsed = parseStrictNonNegativeInteger(value);
|
|
188
|
-
if (parsed !== void 0) return Math.max(0, Math.floor(parsed));
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
function formatDynamicToolTimeoutDetails(params) {
|
|
192
|
-
const tool = normalizeLogField(params.call.tool) ?? "unknown";
|
|
193
|
-
const baseMeta = {
|
|
194
|
-
tool: params.call.tool,
|
|
195
|
-
toolCallId: params.call.callId,
|
|
196
|
-
threadId: params.call.threadId,
|
|
197
|
-
turnId: params.call.turnId,
|
|
198
|
-
timeoutMs: params.timeoutMs,
|
|
199
|
-
timeoutKind: "codex_dynamic_tool_rpc"
|
|
200
|
-
};
|
|
201
|
-
if (tool !== "process" || !isJsonObject(params.call.arguments)) return {
|
|
202
|
-
responseMessage: `OpenClaw dynamic tool call timed out after ${params.timeoutMs}ms while running tool ${tool}.`,
|
|
203
|
-
consoleMessage: `codex dynamic tool timeout: tool=${tool} toolTimeoutMs=${params.timeoutMs}; per-tool-call watchdog, not session idle`,
|
|
204
|
-
meta: baseMeta
|
|
205
|
-
};
|
|
206
|
-
const action = normalizeLogField(params.call.arguments.action);
|
|
207
|
-
const sessionId = normalizeLogField(params.call.arguments.sessionId);
|
|
208
|
-
const requestedTimeoutMs = readNumericTimeoutMs(params.call.arguments.timeout);
|
|
209
|
-
const actionPart = action ? ` action=${action}` : "";
|
|
210
|
-
const sessionPart = sessionId ? ` sessionId=${sessionId}` : "";
|
|
211
|
-
const requestedPart = requestedTimeoutMs === void 0 ? "" : ` requestedWaitMs=${requestedTimeoutMs}`;
|
|
212
|
-
const retryHint = action === "poll" ? "; repeated lines usually mean process-poll retry churn, not model progress" : "";
|
|
213
|
-
const responseTarget = action || sessionId ? ` while waiting for process${actionPart}${sessionPart}` : " while waiting for the process tool";
|
|
214
|
-
return {
|
|
215
|
-
responseMessage: `OpenClaw dynamic tool call timed out after ${params.timeoutMs}ms${responseTarget}. This is a tool RPC timeout, not a session idle timeout.`,
|
|
216
|
-
consoleMessage: `codex process tool timeout:${actionPart}${sessionPart} toolTimeoutMs=${params.timeoutMs}${requestedPart}; per-tool-call watchdog, not session idle${retryHint}`,
|
|
217
|
-
meta: {
|
|
218
|
-
...baseMeta,
|
|
219
|
-
processAction: action,
|
|
220
|
-
processSessionId: sessionId,
|
|
221
|
-
processRequestedTimeoutMs: requestedTimeoutMs
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Runs a dynamic tool call with run-abort and per-call timeout handling,
|
|
227
|
-
* returning a Codex protocol response instead of throwing.
|
|
228
|
-
*/
|
|
229
|
-
async function handleDynamicToolCallWithTimeout(params) {
|
|
230
|
-
let didNotifyAgentToolResult = false;
|
|
231
|
-
const conservativeRaceResponses = /* @__PURE__ */ new WeakSet();
|
|
232
|
-
const finalizeTerminal = (response) => {
|
|
233
|
-
const executionSnapshot = params.toolBridge.consumeToolExecutionSnapshot?.(params.call.callId);
|
|
234
|
-
const ownerKey = params.toolBridge.sideEffectOwnerKeyForTool?.(params.call.tool);
|
|
235
|
-
const observedExecutionStarted = executionSnapshot?.executionStarted ?? (conservativeRaceResponses.has(response) ? void 0 : response.executionStarted);
|
|
236
|
-
const terminalResolution = params.observeToolTerminal?.({
|
|
237
|
-
toolCallId: params.call.callId,
|
|
238
|
-
toolName: params.call.tool,
|
|
239
|
-
arguments: response.executedArguments ?? executionSnapshot?.executedArguments ?? params.call.arguments,
|
|
240
|
-
...params.toolMeta ? { meta: params.toolMeta } : {},
|
|
241
|
-
...ownerKey ? { ownerMutation: { ownerKey } } : {},
|
|
242
|
-
...observedExecutionStarted !== void 0 ? { executionStarted: observedExecutionStarted } : {},
|
|
243
|
-
outcome: response.success ? "success" : "failure",
|
|
244
|
-
...!response.success ? { failure: { error: readDynamicToolResponseText(response) } } : {}
|
|
245
|
-
});
|
|
246
|
-
return withDynamicToolTerminalResolution(response, terminalResolution);
|
|
247
|
-
};
|
|
248
|
-
const createFailedAfterPossibleDispatch = (message, terminalReason) => {
|
|
249
|
-
const response = createFailedDynamicToolResponse(message, {
|
|
250
|
-
executionStarted: true,
|
|
251
|
-
sideEffectEvidence: true,
|
|
252
|
-
terminalReason
|
|
253
|
-
});
|
|
254
|
-
conservativeRaceResponses.add(response);
|
|
255
|
-
return response;
|
|
256
|
-
};
|
|
257
|
-
const notifyAgentToolResult = (event) => {
|
|
258
|
-
if (didNotifyAgentToolResult) return;
|
|
259
|
-
didNotifyAgentToolResult = true;
|
|
260
|
-
try {
|
|
261
|
-
params.onAgentToolResult?.(event);
|
|
262
|
-
} catch (error) {
|
|
263
|
-
embeddedAgentLog.warn(`onAgentToolResult handler failed: tool=${params.call.tool} error=${String(error)}`);
|
|
264
|
-
}
|
|
265
|
-
};
|
|
266
|
-
const notifyFailedToolResult = (message, terminalReason = "failed") => {
|
|
267
|
-
notifyAgentToolResult({
|
|
268
|
-
toolName: params.call.tool,
|
|
269
|
-
result: {
|
|
270
|
-
content: [{
|
|
271
|
-
type: "text",
|
|
272
|
-
text: message
|
|
273
|
-
}],
|
|
274
|
-
details: {
|
|
275
|
-
status: terminalReason,
|
|
276
|
-
error: message
|
|
277
|
-
}
|
|
278
|
-
},
|
|
279
|
-
isError: true
|
|
280
|
-
});
|
|
281
|
-
};
|
|
282
|
-
if (params.signal.aborted) {
|
|
283
|
-
const message = "OpenClaw dynamic tool call aborted before execution.";
|
|
284
|
-
const terminalReason = resolveCodexToolAbortTerminalReason(params.signal);
|
|
285
|
-
params.onFallbackSelected?.();
|
|
286
|
-
notifyFailedToolResult(message, terminalReason);
|
|
287
|
-
return finalizeTerminal(createFailedDynamicToolResponse(message, {
|
|
288
|
-
executionStarted: false,
|
|
289
|
-
terminalReason
|
|
290
|
-
}));
|
|
291
|
-
}
|
|
292
|
-
const controller = new AbortController();
|
|
293
|
-
let timeout;
|
|
294
|
-
let timedOut = false;
|
|
295
|
-
let resolveAbort;
|
|
296
|
-
const abortFromRun = () => {
|
|
297
|
-
const message = "OpenClaw dynamic tool call aborted.";
|
|
298
|
-
const terminalReason = resolveCodexToolAbortTerminalReason(params.signal);
|
|
299
|
-
params.onFallbackSelected?.();
|
|
300
|
-
controller.abort(params.signal.reason ?? /* @__PURE__ */ new Error(message));
|
|
301
|
-
notifyFailedToolResult(message, terminalReason);
|
|
302
|
-
resolveAbort?.(createFailedAfterPossibleDispatch(message, terminalReason));
|
|
303
|
-
};
|
|
304
|
-
const abortPromise = new Promise((resolve) => {
|
|
305
|
-
resolveAbort = resolve;
|
|
306
|
-
});
|
|
307
|
-
const timeoutPromise = new Promise((resolve) => {
|
|
308
|
-
const timeoutMs = clampDynamicToolTimeoutMs(params.timeoutMs);
|
|
309
|
-
timeout = setTimeout(() => {
|
|
310
|
-
timedOut = true;
|
|
311
|
-
const timeoutDetails = formatDynamicToolTimeoutDetails({
|
|
312
|
-
call: params.call,
|
|
313
|
-
timeoutMs
|
|
314
|
-
});
|
|
315
|
-
params.onFallbackSelected?.();
|
|
316
|
-
controller.abort(new Error(timeoutDetails.responseMessage));
|
|
317
|
-
params.onTimeout?.();
|
|
318
|
-
embeddedAgentLog.warn("codex dynamic tool call timed out", {
|
|
319
|
-
...timeoutDetails.meta,
|
|
320
|
-
consoleMessage: timeoutDetails.consoleMessage
|
|
321
|
-
});
|
|
322
|
-
notifyFailedToolResult(timeoutDetails.responseMessage, "timed_out");
|
|
323
|
-
resolve(createFailedAfterPossibleDispatch(timeoutDetails.responseMessage, "timed_out"));
|
|
324
|
-
}, timeoutMs);
|
|
325
|
-
timeout.unref?.();
|
|
326
|
-
});
|
|
327
|
-
try {
|
|
328
|
-
params.signal.addEventListener("abort", abortFromRun, { once: true });
|
|
329
|
-
if (params.signal.aborted) abortFromRun();
|
|
330
|
-
const response = await Promise.race([
|
|
331
|
-
params.toolBridge.handleToolCall(params.call, {
|
|
332
|
-
signal: controller.signal,
|
|
333
|
-
onAgentToolResult: notifyAgentToolResult,
|
|
334
|
-
toolCallOrdinal: params.toolCallOrdinal,
|
|
335
|
-
retainExecutionSnapshot: true
|
|
336
|
-
}),
|
|
337
|
-
abortPromise,
|
|
338
|
-
timeoutPromise
|
|
339
|
-
]);
|
|
340
|
-
if (!response.success && !didNotifyAgentToolResult) notifyFailedToolResult(readDynamicToolResponseText(response), response.diagnosticTerminalReason ?? "failed");
|
|
341
|
-
return finalizeTerminal(response);
|
|
342
|
-
} catch (error) {
|
|
343
|
-
const terminalReason = params.signal.aborted ? resolveCodexToolAbortTerminalReason(params.signal) : resolveToolExecutionErrorKind(error);
|
|
344
|
-
const message = formatToolExecutionErrorMessage(error, "OpenClaw dynamic tool call failed.");
|
|
345
|
-
notifyFailedToolResult(message, terminalReason);
|
|
346
|
-
return finalizeTerminal(createFailedAfterPossibleDispatch(message, terminalReason));
|
|
347
|
-
} finally {
|
|
348
|
-
if (timeout) clearTimeout(timeout);
|
|
349
|
-
params.signal.removeEventListener("abort", abortFromRun);
|
|
350
|
-
resolveAbort = void 0;
|
|
351
|
-
if (!timedOut && !controller.signal.aborted) controller.abort(/* @__PURE__ */ new Error("OpenClaw dynamic tool call finished."));
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
function readDynamicToolResponseText(response) {
|
|
355
|
-
return response.contentItems.flatMap((item) => item.type === "inputText" && typeof item.text === "string" ? [item.text] : []).join("\n").trim() || "OpenClaw dynamic tool call failed.";
|
|
356
|
-
}
|
|
357
|
-
/** Strips OpenClaw-only metadata before sending a dynamic tool response to Codex. */
|
|
358
|
-
function toCodexDynamicToolProtocolResponse(response) {
|
|
359
|
-
return {
|
|
360
|
-
contentItems: response.contentItems,
|
|
361
|
-
success: response.success
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
/** Adds async-started progress details when a tool result continues out of band. */
|
|
365
|
-
function toCodexDynamicToolProgressResponse(response, protocolResponse) {
|
|
366
|
-
const transcriptDetails = isJsonObject(response.transcriptDetails) ? response.transcriptDetails : void 0;
|
|
367
|
-
const mcpAppPreview = isJsonObject(transcriptDetails?.mcpAppPreview) ? transcriptDetails.mcpAppPreview : void 0;
|
|
368
|
-
const progressDetails = mcpAppPreview ? { mcpAppPreview } : void 0;
|
|
369
|
-
if (response.asyncStarted !== true && progressDetails === void 0) return protocolResponse;
|
|
370
|
-
return {
|
|
371
|
-
...protocolResponse,
|
|
372
|
-
...progressDetails ? { details: progressDetails } : {},
|
|
373
|
-
...response.asyncStarted === true ? { details: {
|
|
374
|
-
...progressDetails,
|
|
375
|
-
async: true,
|
|
376
|
-
status: "started"
|
|
377
|
-
} } : {}
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
/** Decides whether a terminal dynamic tool response can release the Codex turn. */
|
|
381
|
-
function shouldReleaseTurnAfterTerminalDynamicTool(state) {
|
|
382
|
-
return !state.completed && !state.aborted && state.responseSuccess && !state.currentTurnHadNonTerminalDynamicToolResult && state.activeAppServerTurnRequests === 0 && state.activeTurnItemIdsCount === 0 && state.pendingOpenClawDynamicToolCompletionIdsCount === 0;
|
|
383
|
-
}
|
|
384
|
-
/** Returns true when a non-async result should block terminal-release shortcuts. */
|
|
385
|
-
function shouldBlockTerminalReleaseForNonTerminalDynamicToolResult(response) {
|
|
386
|
-
return response.asyncStarted !== true;
|
|
387
|
-
}
|
|
388
|
-
/** Resolves whether terminal diagnostic state should release, wait, or stay idle. */
|
|
389
|
-
function resolveTerminalDynamicToolBatchAction(state) {
|
|
390
|
-
if (state.activeAppServerTurnRequests > 0 || state.activeTurnItemIdsCount > 0 || state.pendingOpenClawDynamicToolCompletionIdsCount > 0) return "wait";
|
|
391
|
-
if (state.currentTurnHadNonTerminalDynamicToolResult) return "clear-nonterminal-batch";
|
|
392
|
-
if (state.hasPendingTerminalDynamicToolRelease) return "release-pending-terminal";
|
|
393
|
-
return "idle";
|
|
394
|
-
}
|
|
395
|
-
/** Returns true for diagnostic events that terminate a dynamic tool call. */
|
|
396
|
-
function isDynamicToolTerminalDiagnosticEvent(event) {
|
|
397
|
-
return event.type === "tool.execution.completed" || event.type === "tool.execution.error" || event.type === "tool.execution.blocked";
|
|
398
|
-
}
|
|
399
|
-
/** Matches terminal diagnostics to a specific dynamic tool call id/name. */
|
|
400
|
-
function isMatchingDynamicToolTerminalDiagnostic(params) {
|
|
401
|
-
if (params.event.toolCallId !== params.call.callId || params.event.toolName !== params.call.tool) return false;
|
|
402
|
-
if (params.runId !== void 0) return params.event.runId === params.runId;
|
|
403
|
-
if (params.sessionId !== void 0) return params.event.sessionId === params.sessionId;
|
|
404
|
-
if (params.sessionKey !== void 0) return params.event.sessionKey === params.sessionKey;
|
|
405
|
-
return params.event.runId === void 0 && params.event.sessionId === void 0 && params.event.sessionKey === void 0;
|
|
406
|
-
}
|
|
407
|
-
/** Checks pending diagnostics for a terminal event matching a tool call. */
|
|
408
|
-
function hasPendingDynamicToolTerminalDiagnostic(params) {
|
|
409
|
-
return hasPendingInternalDiagnosticEvent((event) => {
|
|
410
|
-
if (!isDynamicToolTerminalDiagnosticEvent(event)) return false;
|
|
411
|
-
return isMatchingDynamicToolTerminalDiagnostic({
|
|
412
|
-
event,
|
|
413
|
-
call: params.call,
|
|
414
|
-
runId: params.runId,
|
|
415
|
-
sessionId: params.sessionId,
|
|
416
|
-
sessionKey: params.sessionKey
|
|
417
|
-
});
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
/** Resolves per-tool timeout, applying media/message defaults and hard caps. */
|
|
421
|
-
function resolveDynamicToolCallTimeoutMs(params) {
|
|
422
|
-
if (params.call.tool === "computer") return clampDynamicToolTimeoutMs(readComputerToolTimeoutMs(params.call.arguments));
|
|
423
|
-
if (params.call.tool === "message") return CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS;
|
|
424
|
-
if (params.call.tool === "agents_wait") {
|
|
425
|
-
const requestedMs = readDynamicToolCallTimeoutMs(params.call.arguments) ?? readConfiguredDynamicToolTimeoutMs(params.call.tool, params.config) ?? CODEX_DYNAMIC_AGENTS_WAIT_TOOL_TIMEOUT_MS;
|
|
426
|
-
return Math.max(1, Math.min(63e4, Math.floor(requestedMs)));
|
|
427
|
-
}
|
|
428
|
-
return clampDynamicToolTimeoutMs(readDynamicToolCallTimeoutMs(params.call.arguments) ?? readConfiguredDynamicToolTimeoutMs(params.call.tool, params.config) ?? CODEX_DYNAMIC_TOOL_TIMEOUT_MS);
|
|
429
|
-
}
|
|
430
|
-
function readComputerToolTimeoutMs(value) {
|
|
431
|
-
const args = isJsonObject(value) ? value : void 0;
|
|
432
|
-
const action = typeof args?.action === "string" ? args.action : void 0;
|
|
433
|
-
const gatewayTimeoutMs = readPositiveFiniteTimeoutMs(args?.timeoutMs) ?? CODEX_DYNAMIC_COMPUTER_GATEWAY_TIMEOUT_MS;
|
|
434
|
-
const gatewayCallCount = action === "screenshot" || action === "wait" ? 3 : 4;
|
|
435
|
-
return (action === "wait" || action === "hold_key" ? Math.max(0, Number(args?.duration) || 0) * 1e3 : 0) + gatewayCallCount * gatewayTimeoutMs + CODEX_DYNAMIC_COMPUTER_COMPLETION_GRACE_MS;
|
|
436
|
-
}
|
|
437
|
-
function readDynamicToolCallTimeoutMs(value) {
|
|
438
|
-
if (!isJsonObject(value)) return;
|
|
439
|
-
const timeoutMs = readPositiveFiniteTimeoutMs(value.timeoutMs);
|
|
440
|
-
if (timeoutMs !== void 0) return timeoutMs;
|
|
441
|
-
const timeoutSecondsMs = readDynamicToolTimeoutSecondsAsMs(value.timeoutSeconds);
|
|
442
|
-
return timeoutSecondsMs === void 0 ? void 0 : addTimerTimeoutGraceMs(timeoutSecondsMs, CODEX_DYNAMIC_TOOL_TIMEOUT_SECONDS_GRACE_MS);
|
|
443
|
-
}
|
|
444
|
-
function readConfiguredDynamicToolTimeoutMs(toolName, config) {
|
|
445
|
-
if (toolName === "image_generate") {
|
|
446
|
-
const imageModel = config?.agents?.defaults?.mediaModels?.image;
|
|
447
|
-
if (!imageModel || typeof imageModel !== "object") return CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS;
|
|
448
|
-
return readPositiveFiniteTimeoutMs(imageModel.timeoutMs) ?? CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS;
|
|
449
|
-
}
|
|
450
|
-
if (toolName === "view_image") {
|
|
451
|
-
const candidates = (config?.tools?.media?.models ?? []).filter((entry) => !entry.capabilities || entry.capabilities.includes("image"));
|
|
452
|
-
const capabilityTimeoutMs = readTimeoutSecondsAsMs(config?.tools?.media?.image?.timeoutSeconds);
|
|
453
|
-
return Math.max(capabilityTimeoutMs ?? CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS, ...candidates.map((entry) => readTimeoutSecondsAsMs(entry.timeoutSeconds) ?? capabilityTimeoutMs ?? CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS));
|
|
454
|
-
}
|
|
455
|
-
if (toolName === "message") return CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS;
|
|
456
|
-
}
|
|
457
|
-
function readTimeoutSecondsAsMs(value) {
|
|
458
|
-
const seconds = readPositiveFiniteTimeoutMs(value);
|
|
459
|
-
return seconds === void 0 ? void 0 : seconds * 1e3;
|
|
460
|
-
}
|
|
461
|
-
function readDynamicToolTimeoutSecondsAsMs(value) {
|
|
462
|
-
if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) return;
|
|
463
|
-
return value * 1e3;
|
|
464
|
-
}
|
|
465
|
-
function readPositiveFiniteTimeoutMs(value) {
|
|
466
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : void 0;
|
|
467
|
-
}
|
|
468
|
-
function clampDynamicToolTimeoutMs(timeoutMs) {
|
|
469
|
-
return Math.max(1, Math.min(CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS, Math.floor(timeoutMs)));
|
|
470
|
-
}
|
|
471
|
-
//#endregion
|
|
472
|
-
//#region extensions/codex/src/app-server/native-hook-relay-state.ts
|
|
473
|
-
const pending = /* @__PURE__ */ new Set();
|
|
474
|
-
/** Owns delayed hook-relay cleanup across runtime scheduling and test teardown. */
|
|
475
|
-
const nativeHookRelayUnregisterQueue = {
|
|
476
|
-
add(entry) {
|
|
477
|
-
pending.add(entry);
|
|
478
|
-
},
|
|
479
|
-
delete(entry) {
|
|
480
|
-
return pending.delete(entry);
|
|
481
|
-
},
|
|
482
|
-
flush() {
|
|
483
|
-
while (pending.size > 0) {
|
|
484
|
-
const entry = pending.values().next().value;
|
|
485
|
-
if (!entry) return;
|
|
486
|
-
clearTimeout(entry.timeout);
|
|
487
|
-
entry.unregister();
|
|
488
|
-
}
|
|
489
|
-
},
|
|
490
|
-
clear() {
|
|
491
|
-
for (const entry of pending) clearTimeout(entry.timeout);
|
|
492
|
-
pending.clear();
|
|
493
|
-
}
|
|
494
|
-
};
|
|
495
|
-
//#endregion
|
|
496
|
-
//#region extensions/codex/src/app-server/native-hook-relay.ts
|
|
497
|
-
/**
|
|
498
|
-
* Bridges Codex native hook callbacks into OpenClaw's native hook relay so
|
|
499
|
-
* app-server tool events can still run OpenClaw policy and diagnostics.
|
|
500
|
-
*/
|
|
501
|
-
/** Codex hook events that can be registered through OpenClaw's native relay. */
|
|
502
|
-
const CODEX_NATIVE_HOOK_RELAY_EVENTS = [
|
|
503
|
-
"pre_tool_use",
|
|
504
|
-
"post_tool_use",
|
|
505
|
-
"permission_request",
|
|
506
|
-
"before_agent_finalize"
|
|
507
|
-
];
|
|
508
|
-
const CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS = CODEX_NATIVE_HOOK_RELAY_EVENTS.filter((event) => event !== "permission_request");
|
|
509
|
-
const CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS = 30 * 6e4;
|
|
510
|
-
/** Extra relay lifetime after the expected turn budget, preventing late hook drops. */
|
|
511
|
-
const CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS = 5 * 6e4;
|
|
512
|
-
const CODEX_NATIVE_HOOK_RELAY_COMMAND_MIN_PARENT_MARGIN_MS = 250;
|
|
513
|
-
const CODEX_NATIVE_HOOK_RELAY_COMMAND_MAX_PARENT_MARGIN_MS = 1e3;
|
|
514
|
-
const CODEX_NATIVE_HOOK_RELAY_DEFAULT_TIMEOUT_SEC = 10;
|
|
515
|
-
const CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS = 1e4;
|
|
516
|
-
const CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS = 5e3;
|
|
517
|
-
const MAX_PENDING_DIRECT_CHILD_ADMISSIONS = 32;
|
|
518
|
-
const CODEX_HOOK_MATCHER_NAMES_BY_TOOL_ID = {
|
|
519
|
-
exec: [
|
|
520
|
-
"Bash",
|
|
521
|
-
"exec",
|
|
522
|
-
"exec_command"
|
|
523
|
-
],
|
|
524
|
-
apply_patch: [
|
|
525
|
-
"apply_patch",
|
|
526
|
-
"Write",
|
|
527
|
-
"Edit"
|
|
528
|
-
],
|
|
529
|
-
spawn_agent: ["spawn_agent", "Agent"]
|
|
530
|
-
};
|
|
531
|
-
/** Defers relay unregister so late native hook subprocesses can still resolve. */
|
|
532
|
-
function scheduleCodexNativeHookRelayUnregister(params) {
|
|
533
|
-
let pending;
|
|
534
|
-
const unregister = () => {
|
|
535
|
-
if (!pending) return;
|
|
536
|
-
const current = pending;
|
|
537
|
-
pending = void 0;
|
|
538
|
-
if (!nativeHookRelayUnregisterQueue.delete(current)) return;
|
|
539
|
-
params.relay.unregister();
|
|
540
|
-
};
|
|
541
|
-
const timeout = setTimeout(unregister, resolveCodexNativeHookRelayUnregisterGraceMs(params.hookTimeoutSec));
|
|
542
|
-
pending = {
|
|
543
|
-
timeout,
|
|
544
|
-
unregister
|
|
545
|
-
};
|
|
546
|
-
nativeHookRelayUnregisterQueue.add(pending);
|
|
547
|
-
timeout.unref();
|
|
548
|
-
}
|
|
549
|
-
/** Computes the delayed unregister window from Codex's hook timeout. */
|
|
550
|
-
function resolveCodexNativeHookRelayUnregisterGraceMs(hookTimeoutSec) {
|
|
551
|
-
const hookTimeoutMs = finiteSecondsToTimerSafeMilliseconds(normalizeHookTimeoutSec(hookTimeoutSec)) ?? 0;
|
|
552
|
-
return Math.max(CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS, addTimerTimeoutGraceMs(hookTimeoutMs, CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS) ?? 0);
|
|
553
|
-
}
|
|
554
|
-
/** Records a native pre-tool failure that Codex does not project as a tool item. */
|
|
555
|
-
function emitCodexNativePreToolUseFailureDiagnostic(params) {
|
|
556
|
-
emitTrustedDiagnosticEvent({
|
|
557
|
-
type: "tool.execution.error",
|
|
558
|
-
...params.agentId ? { agentId: params.agentId } : {},
|
|
559
|
-
sessionId: params.sessionId,
|
|
560
|
-
...params.sessionKey ? { sessionKey: params.sessionKey } : {},
|
|
561
|
-
runId: params.runId,
|
|
562
|
-
toolName: params.failure.toolName,
|
|
563
|
-
toolCallId: params.failure.toolCallId,
|
|
564
|
-
durationMs: params.failure.durationMs,
|
|
565
|
-
errorCategory: "before_tool_call",
|
|
566
|
-
terminalReason: params.terminalReason ?? (params.signal?.aborted ? resolveCodexToolAbortTerminalReason(params.signal) : params.failure.disposition),
|
|
567
|
-
...params.sourceTimestampMs !== void 0 ? { sourceTimestampMs: params.sourceTimestampMs } : {}
|
|
568
|
-
});
|
|
569
|
-
}
|
|
570
|
-
/** Registers an OpenClaw native hook relay for a Codex app-server turn. */
|
|
571
|
-
function createCodexNativeHookRelay(params) {
|
|
572
|
-
if (params.options?.enabled === false) return;
|
|
573
|
-
const directChildClaims = /* @__PURE__ */ new Map();
|
|
574
|
-
const pendingDirectChildAdmissions = /* @__PURE__ */ new Map();
|
|
575
|
-
let foregroundClosed = false;
|
|
576
|
-
let successfulYieldRetentionAuthorized = false;
|
|
577
|
-
const assertClaim = (threadId, claim) => () => directChildClaims.get(threadId) === claim;
|
|
578
|
-
const rejectPendingAdmissions = (reason) => {
|
|
579
|
-
for (const pending of pendingDirectChildAdmissions.values()) pending.reject(new Error(reason));
|
|
580
|
-
pendingDirectChildAdmissions.clear();
|
|
581
|
-
};
|
|
582
|
-
const relay = registerRetainedNativeHookRelayForBundledRuntime({
|
|
583
|
-
provider: "codex",
|
|
584
|
-
relayId: buildCodexNativeHookRelayId({
|
|
585
|
-
agentId: params.agentId,
|
|
586
|
-
sessionId: params.sessionId,
|
|
587
|
-
sessionKey: params.sessionKey
|
|
588
|
-
}),
|
|
589
|
-
...params.generation ? { generation: params.generation } : {},
|
|
590
|
-
...params.generationMismatchGraceMs ? { generationMismatchGraceMs: params.generationMismatchGraceMs } : {},
|
|
591
|
-
...params.agentId ? { agentId: params.agentId } : {},
|
|
592
|
-
sessionId: params.sessionId,
|
|
593
|
-
...params.sessionKey ? { sessionKey: params.sessionKey } : {},
|
|
594
|
-
...params.config ? { config: params.config } : {},
|
|
595
|
-
runId: params.runId,
|
|
596
|
-
...params.channelId ? { channelId: params.channelId } : {},
|
|
597
|
-
...params.requester ? { requester: params.requester } : {},
|
|
598
|
-
...params.approvalContext ? { approvalContext: params.approvalContext } : {},
|
|
599
|
-
allowedEvents: params.events,
|
|
600
|
-
preToolUseLoopDetection: params.loopDetectionPreToolUseRelay,
|
|
601
|
-
ttlMs: resolveCodexNativeHookRelayTtlMs({
|
|
602
|
-
explicitTtlMs: params.options?.ttlMs,
|
|
603
|
-
attemptTimeoutMs: params.attemptTimeoutMs,
|
|
604
|
-
startupTimeoutMs: params.startupTimeoutMs,
|
|
605
|
-
turnStartTimeoutMs: params.turnStartTimeoutMs
|
|
606
|
-
}),
|
|
607
|
-
signal: params.signal,
|
|
608
|
-
runBeforeToolCall: params.hostCapabilities.runBeforeToolCall,
|
|
609
|
-
assertActive: params.hostCapabilities.assertActive,
|
|
610
|
-
retention: {
|
|
611
|
-
readClaim: readCodexNativeChildThreadId,
|
|
612
|
-
shouldRetainAfterForegroundClose: () => successfulYieldRetentionAuthorized && directChildClaims.size > 0,
|
|
613
|
-
allowPreToolUse: (childThreadId) => directChildClaims.has(childThreadId),
|
|
614
|
-
awaitForegroundAdmission: (childThreadId) => {
|
|
615
|
-
if (foregroundClosed) return Promise.reject(/* @__PURE__ */ new Error("native hook relay foreground admission unavailable"));
|
|
616
|
-
const existingClaim = directChildClaims.get(childThreadId);
|
|
617
|
-
if (existingClaim) return Promise.resolve(assertClaim(childThreadId, existingClaim));
|
|
618
|
-
const existingPending = pendingDirectChildAdmissions.get(childThreadId);
|
|
619
|
-
if (existingPending) return existingPending.promise.then((claim) => assertClaim(childThreadId, claim));
|
|
620
|
-
if (pendingDirectChildAdmissions.size >= MAX_PENDING_DIRECT_CHILD_ADMISSIONS) return Promise.reject(/* @__PURE__ */ new Error("native hook relay foreground admission capacity reached"));
|
|
621
|
-
const { promise, resolve, reject } = createDeferred();
|
|
622
|
-
pendingDirectChildAdmissions.set(childThreadId, {
|
|
623
|
-
promise,
|
|
624
|
-
resolve,
|
|
625
|
-
reject
|
|
626
|
-
});
|
|
627
|
-
return promise.then((claim) => assertClaim(childThreadId, claim));
|
|
628
|
-
},
|
|
629
|
-
onDispose: () => {
|
|
630
|
-
foregroundClosed = true;
|
|
631
|
-
rejectPendingAdmissions("native hook relay registration closed");
|
|
632
|
-
}
|
|
633
|
-
},
|
|
634
|
-
onPreToolUseFailure: params.onPreToolUseFailure,
|
|
635
|
-
command: {
|
|
636
|
-
nice: 10,
|
|
637
|
-
timeoutMs: params.options?.gatewayTimeoutMs
|
|
638
|
-
}
|
|
639
|
-
});
|
|
640
|
-
const unregister = () => {
|
|
641
|
-
foregroundClosed = true;
|
|
642
|
-
rejectPendingAdmissions("native hook relay foreground closed");
|
|
643
|
-
relay.unregister();
|
|
644
|
-
};
|
|
645
|
-
return {
|
|
646
|
-
...relay,
|
|
647
|
-
unregister,
|
|
648
|
-
authorizeRetentionAfterSuccessfulYield: () => {
|
|
649
|
-
successfulYieldRetentionAuthorized = true;
|
|
650
|
-
},
|
|
651
|
-
hasClaimedDirectChild: () => directChildClaims.size > 0,
|
|
652
|
-
rejectPendingDirectChild: (threadIdInput, reason) => {
|
|
653
|
-
const threadId = threadIdInput.trim();
|
|
654
|
-
const pending = threadId ? pendingDirectChildAdmissions.get(threadId) : void 0;
|
|
655
|
-
if (!pending) return;
|
|
656
|
-
pendingDirectChildAdmissions.delete(threadId);
|
|
657
|
-
pending.reject(new Error(reason));
|
|
658
|
-
},
|
|
659
|
-
claimDirectChild: (threadIdInput) => {
|
|
660
|
-
const threadId = threadIdInput.trim();
|
|
661
|
-
if (!threadId) return () => void 0;
|
|
662
|
-
if (directChildClaims.get(threadId)) return () => void 0;
|
|
663
|
-
const claim = Symbol(threadId);
|
|
664
|
-
directChildClaims.set(threadId, claim);
|
|
665
|
-
const pending = pendingDirectChildAdmissions.get(threadId);
|
|
666
|
-
pendingDirectChildAdmissions.delete(threadId);
|
|
667
|
-
pending?.resolve(claim);
|
|
668
|
-
let released = false;
|
|
669
|
-
return () => {
|
|
670
|
-
if (released) return;
|
|
671
|
-
released = true;
|
|
672
|
-
if (directChildClaims.get(threadId) !== claim) return;
|
|
673
|
-
directChildClaims.delete(threadId);
|
|
674
|
-
if (foregroundClosed && directChildClaims.size === 0) relay.unregister();
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
};
|
|
678
|
-
}
|
|
679
|
-
function readCodexNativeChildThreadId(rawPayload) {
|
|
680
|
-
if (!isJsonObject(rawPayload) || typeof rawPayload.agent_id !== "string") return;
|
|
681
|
-
return rawPayload.agent_id.trim() || void 0;
|
|
682
|
-
}
|
|
683
|
-
/** Selects the native hook events Codex should install for the current approval mode. */
|
|
684
|
-
function resolveCodexNativeHookRelayEvents(params) {
|
|
685
|
-
if (params.configuredEvents?.length) return params.configuredEvents;
|
|
686
|
-
return params.appServer.approvalPolicy === "never" ? CODEX_NATIVE_HOOK_RELAY_EVENTS : CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS;
|
|
687
|
-
}
|
|
688
|
-
/** Derives the native hook relay TTL from the turn budget unless explicitly configured. */
|
|
689
|
-
function resolveCodexNativeHookRelayTtlMs(params) {
|
|
690
|
-
if (params.explicitTtlMs !== void 0) return params.explicitTtlMs;
|
|
691
|
-
const relayBudgetMs = params.attemptTimeoutMs + params.startupTimeoutMs + params.turnStartTimeoutMs + CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS;
|
|
692
|
-
return Math.max(CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS, Math.floor(relayBudgetMs));
|
|
693
|
-
}
|
|
694
|
-
/** Builds a stable relay id scoped to the agent and session identity. */
|
|
695
|
-
function buildCodexNativeHookRelayId(params) {
|
|
696
|
-
const hash = createHash("sha256");
|
|
697
|
-
hash.update("openclaw:codex:native-hook-relay:v1");
|
|
698
|
-
hash.update("\0");
|
|
699
|
-
hash.update(params.agentId?.trim() || "");
|
|
700
|
-
hash.update("\0");
|
|
701
|
-
hash.update(params.sessionKey?.trim() || params.sessionId);
|
|
702
|
-
return `codex-${hash.digest("hex").slice(0, 40)}`;
|
|
703
|
-
}
|
|
704
|
-
const CODEX_HOOK_EVENT_BY_NATIVE_EVENT = {
|
|
705
|
-
pre_tool_use: "PreToolUse",
|
|
706
|
-
post_tool_use: "PostToolUse",
|
|
707
|
-
permission_request: "PermissionRequest",
|
|
708
|
-
before_agent_finalize: "Stop"
|
|
709
|
-
};
|
|
710
|
-
const CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT = {
|
|
711
|
-
pre_tool_use: "pre_tool_use",
|
|
712
|
-
post_tool_use: "post_tool_use",
|
|
713
|
-
permission_request: "permission_request",
|
|
714
|
-
before_agent_finalize: "stop"
|
|
715
|
-
};
|
|
716
|
-
const CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS = ["/<session-flags>/config.toml", "<session-flags>/config.toml"];
|
|
717
|
-
/** Builds the Codex config overlay that installs trusted command hooks for relay events. */
|
|
718
|
-
function buildCodexNativeHookRelayConfig(params) {
|
|
719
|
-
const events = params.events?.length ? params.events : CODEX_NATIVE_HOOK_RELAY_EVENTS;
|
|
720
|
-
const selectedEvents = new Set(events);
|
|
721
|
-
const config = { "features.hooks": true };
|
|
722
|
-
const hookState = {};
|
|
723
|
-
for (const event of CODEX_NATIVE_HOOK_RELAY_EVENTS) {
|
|
724
|
-
const codexEvent = CODEX_HOOK_EVENT_BY_NATIVE_EVENT[event];
|
|
725
|
-
const selected = selectedEvents.has(event);
|
|
726
|
-
const shouldRelay = params.relay.shouldRelayEvent(event);
|
|
727
|
-
if (!selected || !shouldRelay) {
|
|
728
|
-
if (selected || params.clearOmittedEvents) config[`hooks.${codexEvent}`] = [];
|
|
729
|
-
if (params.clearOmittedEvents) for (const sourcePath of CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS) hookState[`${sourcePath}:${CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[event]}:0:0`] = { enabled: false };
|
|
730
|
-
continue;
|
|
731
|
-
}
|
|
732
|
-
const timeout = normalizeHookTimeoutSec(params.hookTimeoutSec);
|
|
733
|
-
const command = params.relay.commandForEvent(event, { timeoutMs: resolveCodexNativeHookRelayCommandTimeoutMs(timeout) });
|
|
734
|
-
const matcher = buildCodexNativeToolMatcher(params.relay.toolMatcherForEvent(event));
|
|
735
|
-
config[`hooks.${codexEvent}`] = [{
|
|
736
|
-
...matcher ? { matcher } : {},
|
|
737
|
-
hooks: [{
|
|
738
|
-
type: "command",
|
|
739
|
-
command,
|
|
740
|
-
timeout,
|
|
741
|
-
async: false,
|
|
742
|
-
statusMessage: "OpenClaw native hook relay"
|
|
743
|
-
}]
|
|
744
|
-
}];
|
|
745
|
-
const state = {
|
|
746
|
-
enabled: true,
|
|
747
|
-
trusted_hash: codexCommandHookTrustedHash({
|
|
748
|
-
event,
|
|
749
|
-
command,
|
|
750
|
-
matcher,
|
|
751
|
-
timeout,
|
|
752
|
-
statusMessage: "OpenClaw native hook relay"
|
|
753
|
-
})
|
|
754
|
-
};
|
|
755
|
-
for (const sourcePath of CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS) hookState[`${sourcePath}:${CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[event]}:0:0`] = state;
|
|
756
|
-
}
|
|
757
|
-
config["hooks.state"] = hookState;
|
|
758
|
-
return config;
|
|
759
|
-
}
|
|
760
|
-
/** Builds a Codex config overlay that disables native hooks and clears hook arrays. */
|
|
761
|
-
function buildCodexNativeHookRelayDisabledConfig() {
|
|
762
|
-
return {
|
|
763
|
-
"features.hooks": false,
|
|
764
|
-
"hooks.PreToolUse": [],
|
|
765
|
-
"hooks.PostToolUse": [],
|
|
766
|
-
"hooks.PermissionRequest": [],
|
|
767
|
-
"hooks.Stop": []
|
|
768
|
-
};
|
|
769
|
-
}
|
|
770
|
-
function normalizeHookTimeoutSec(value) {
|
|
771
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.ceil(value) : CODEX_NATIVE_HOOK_RELAY_DEFAULT_TIMEOUT_SEC;
|
|
772
|
-
}
|
|
773
|
-
function resolveCodexNativeHookRelayCommandTimeoutMs(hookTimeoutSec) {
|
|
774
|
-
const parentTimeoutMs = finiteSecondsToTimerSafeMilliseconds(normalizeHookTimeoutSec(hookTimeoutSec)) ?? 5e3;
|
|
775
|
-
const parentMarginMs = Math.min(CODEX_NATIVE_HOOK_RELAY_COMMAND_MAX_PARENT_MARGIN_MS, Math.max(CODEX_NATIVE_HOOK_RELAY_COMMAND_MIN_PARENT_MARGIN_MS, Math.floor(parentTimeoutMs / 5)));
|
|
776
|
-
return Math.max(1, parentTimeoutMs - parentMarginMs);
|
|
777
|
-
}
|
|
778
|
-
function buildCodexNativeToolMatcher(toolNames) {
|
|
779
|
-
if (toolNames === void 0) return;
|
|
780
|
-
if (toolNames.length === 0) throw new TypeError("Codex native hook matcher requires at least one tool name");
|
|
781
|
-
const nativeNames = /* @__PURE__ */ new Set();
|
|
782
|
-
let hasCustomToolName = false;
|
|
783
|
-
for (const toolName of toolNames) {
|
|
784
|
-
const canonicalToolName = toolName.trim();
|
|
785
|
-
if (!canonicalToolName || canonicalToolName === "*") throw new TypeError("Codex native hook matcher requires canonical OpenClaw tool ids");
|
|
786
|
-
const nativeAliases = CODEX_HOOK_MATCHER_NAMES_BY_TOOL_ID[canonicalToolName];
|
|
787
|
-
if (!nativeAliases) hasCustomToolName = true;
|
|
788
|
-
for (const nativeName of nativeAliases ?? [canonicalToolName]) nativeNames.add(nativeName);
|
|
789
|
-
}
|
|
790
|
-
const sortedNames = Array.from(nativeNames).toSorted();
|
|
791
|
-
if (!hasCustomToolName && sortedNames.every((toolName) => /^[A-Za-z0-9_]+$/.test(toolName))) return sortedNames.join("|");
|
|
792
|
-
return `(?i)^(?:${sortedNames.map((toolName) => toolName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})$`;
|
|
793
|
-
}
|
|
794
|
-
function codexCommandHookTrustedHash(params) {
|
|
795
|
-
const identity = {
|
|
796
|
-
event_name: CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[params.event],
|
|
797
|
-
...params.matcher ? { matcher: params.matcher } : {},
|
|
798
|
-
hooks: [{
|
|
799
|
-
async: false,
|
|
800
|
-
command: params.command,
|
|
801
|
-
statusMessage: params.statusMessage,
|
|
802
|
-
timeout: params.timeout,
|
|
803
|
-
type: "command"
|
|
804
|
-
}]
|
|
805
|
-
};
|
|
806
|
-
return `sha256:${createHash("sha256").update(JSON.stringify(sortJsonValue(identity))).digest("hex")}`;
|
|
807
|
-
}
|
|
808
|
-
function sortJsonValue(value) {
|
|
809
|
-
if (!value || typeof value !== "object") return value;
|
|
810
|
-
if (Array.isArray(value)) return value.map(sortJsonValue);
|
|
811
|
-
const sorted = {};
|
|
812
|
-
for (const [key, entry] of Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right))) sorted[key] = sortJsonValue(entry);
|
|
813
|
-
return sorted;
|
|
814
|
-
}
|
|
815
|
-
//#endregion
|
|
816
38
|
//#region extensions/codex/src/app-server/event-projector-native-tool-lifecycle.ts
|
|
817
39
|
/** Projects metadata-only lifecycle diagnostics for native tool items. */
|
|
818
40
|
var CodexNativeToolLifecycleProjector = class {
|
|
@@ -1057,10 +279,10 @@ function joinRemoteWorkspacePath(remoteRoot, suffix) {
|
|
|
1057
279
|
//#endregion
|
|
1058
280
|
//#region extensions/codex/src/app-server/remote-workspace-media.ts
|
|
1059
281
|
const REMOTE_WORKSPACE_MEDIA_TIMEOUT_MS = 6e4;
|
|
1060
|
-
const REMOTE_WORKSPACE_MEDIA_MAX_BYTES =
|
|
282
|
+
const REMOTE_WORKSPACE_MEDIA_MAX_BYTES = 67108864;
|
|
1061
283
|
const REMOTE_WORKSPACE_MEDIA_MAX_ATTACHMENTS = 16;
|
|
1062
|
-
const CODEX_REMOTE_MEDIA_CHUNK_BYTES =
|
|
1063
|
-
const CODEX_REMOTE_COMMAND_DEFAULT_OUTPUT_BYTES =
|
|
284
|
+
const CODEX_REMOTE_MEDIA_CHUNK_BYTES = 524288;
|
|
285
|
+
const CODEX_REMOTE_COMMAND_DEFAULT_OUTPUT_BYTES = 1048576;
|
|
1064
286
|
const CODEX_BOUNDED_REMOTE_FILE_READER = [
|
|
1065
287
|
"try{",
|
|
1066
288
|
"const fs=require(\"node:fs\");",
|
|
@@ -1326,83 +548,47 @@ const dynamicToolBuildState = {};
|
|
|
1326
548
|
const CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME = "node_exec";
|
|
1327
549
|
const CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME = "gateway_exec";
|
|
1328
550
|
const CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME = "gateway_process";
|
|
1329
|
-
const CODEX_EXEC_POLICY_PARAMETER_NAMES = /* @__PURE__ */ new Set([
|
|
1330
|
-
"host",
|
|
1331
|
-
"security",
|
|
1332
|
-
"ask"
|
|
1333
|
-
]);
|
|
1334
|
-
const CODEX_NODE_EXEC_PARAMETER_NAMES = /* @__PURE__ */ new Set([
|
|
1335
|
-
"command",
|
|
1336
|
-
"workdir",
|
|
1337
|
-
"env",
|
|
1338
|
-
"timeoutSeconds",
|
|
1339
|
-
"node"
|
|
1340
|
-
]);
|
|
1341
551
|
const PROCESS_FOLLOWUP_TEXT = "Use process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.";
|
|
1342
552
|
/** Returns true when plugin config explicitly removes any named dynamic tool. */
|
|
1343
553
|
function isCodexDynamicToolExcluded(config, names) {
|
|
1344
554
|
const normalizedNames = new Set(names.map((name) => normalizeCodexDynamicToolName(name)));
|
|
1345
555
|
return (config.codexDynamicToolsExclude ?? []).some((name) => normalizedNames.has(normalizeCodexDynamicToolName(name)));
|
|
1346
556
|
}
|
|
1347
|
-
function
|
|
1348
|
-
const pinnedNode =
|
|
1349
|
-
const
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
const
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
execute: async (toolCallId, args, signal, onUpdate) => {
|
|
1360
|
-
const result = await execTool.execute(toolCallId, pinExecDynamicToolArgs(args, params.host, pinnedNode), signal, onUpdate);
|
|
1361
|
-
return {
|
|
1362
|
-
...result,
|
|
1363
|
-
content: result.content.map((item) => item.type === "text" ? Object.assign({}, item, { text: item.text.replace(PROCESS_FOLLOWUP_TEXT, followupText) }) : item)
|
|
1364
|
-
};
|
|
1365
|
-
}
|
|
557
|
+
function createNodeExecAliasDynamicTool(execTool, node) {
|
|
558
|
+
const pinnedNode = node?.trim();
|
|
559
|
+
const pinnedTool = pinExecToolTarget(execTool, {
|
|
560
|
+
host: "node",
|
|
561
|
+
...pinnedNode ? { node: pinnedNode } : {}
|
|
562
|
+
});
|
|
563
|
+
const execute = async (toolCallId, args, signal, onUpdate) => {
|
|
564
|
+
const result = await pinnedTool.execute(toolCallId, args, signal, onUpdate);
|
|
565
|
+
return {
|
|
566
|
+
...result,
|
|
567
|
+
content: result.content.map((item) => item.type === "text" ? Object.assign({}, item, { text: item.text.replace(PROCESS_FOLLOWUP_TEXT, "Remote-node background follow-up is unavailable. Wait for the command to complete.") }) : item)
|
|
568
|
+
};
|
|
1366
569
|
};
|
|
1367
|
-
}
|
|
1368
|
-
function createGatewayProcessAliasDynamicTool(processTool) {
|
|
1369
570
|
return {
|
|
1370
|
-
...
|
|
1371
|
-
name:
|
|
1372
|
-
description: "
|
|
571
|
+
...pinnedTool,
|
|
572
|
+
name: CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME,
|
|
573
|
+
description: pinnedNode ? "Run a shell command to completion on the OpenClaw configured remote node for this session. This tool always uses OpenClaw host=node internally and follows the existing node exec approval and allowlist policy. Remote-node background follow-up is unavailable. Use Codex's native shell for local app-server work." : "Run a shell command to completion on an OpenClaw remote node. Select the node by name or id when multiple nodes are available. This tool always uses OpenClaw host=node internally and follows the existing node exec approval and allowlist policy. Remote-node background follow-up is unavailable. Use Codex's native shell for local app-server work.",
|
|
574
|
+
execute
|
|
1373
575
|
};
|
|
1374
576
|
}
|
|
1375
|
-
function
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
host
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
return {
|
|
1384
|
-
...nodeArgs,
|
|
1385
|
-
host,
|
|
1386
|
-
...node ? { node } : {}
|
|
1387
|
-
};
|
|
577
|
+
function createGatewayExecProjection(createProjection, execTool, params) {
|
|
578
|
+
return createProjection(execTool, {
|
|
579
|
+
kind: "exec",
|
|
580
|
+
name: CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME,
|
|
581
|
+
description: "Run a shell command through OpenClaw on the Gateway host for OpenClaw-managed Gateway environment access, including Secret Store agent-readable environment values and protected egress sentinels. Native Codex shell remains preferred for ordinary local work. This tool always uses OpenClaw host=gateway internally and follows Gateway exec approval and allowlist policy.",
|
|
582
|
+
followupText: params.processAliasAvailable ? "Use gateway_process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up." : "Background session follow-up is unavailable because gateway_process is not exposed. Rerun without background=true and set yieldMs high enough to wait for completion.",
|
|
583
|
+
...params.ask ? { ask: params.ask } : {}
|
|
584
|
+
});
|
|
1388
585
|
}
|
|
1389
|
-
function
|
|
1390
|
-
return
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
const rawProperties = schema.properties;
|
|
1396
|
-
if (!rawProperties || typeof rawProperties !== "object" || Array.isArray(rawProperties)) return parameters;
|
|
1397
|
-
const includeParameter = (name) => nodeOnly ? CODEX_NODE_EXEC_PARAMETER_NAMES.has(name) && !(hideNode && name === "node") : !CODEX_EXEC_POLICY_PARAMETER_NAMES.has(normalizeCodexDynamicToolName(name)) && !(hideNode && normalizeCodexDynamicToolName(name) === "node");
|
|
1398
|
-
const nextProperties = Object.fromEntries(Object.entries(rawProperties).filter(([name]) => includeParameter(name)));
|
|
1399
|
-
const rawRequired = schema.required;
|
|
1400
|
-
const nextRequired = Array.isArray(rawRequired) ? rawRequired.filter((name) => typeof name !== "string" || includeParameter(name)) : rawRequired;
|
|
1401
|
-
return {
|
|
1402
|
-
...schema,
|
|
1403
|
-
properties: nextProperties,
|
|
1404
|
-
...Array.isArray(rawRequired) ? { required: nextRequired } : {}
|
|
1405
|
-
};
|
|
586
|
+
function createGatewayProcessProjection(createProjection, processTool) {
|
|
587
|
+
return createProjection(processTool, {
|
|
588
|
+
kind: "process",
|
|
589
|
+
name: CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME,
|
|
590
|
+
description: "Manage background shell sessions in the existing per-session OpenClaw process scope: list, poll, log, write, send-keys, submit, paste, kill, clear, or remove. Use for gateway_exec follow-up; use native Codex shell session handling for ordinary local work."
|
|
591
|
+
});
|
|
1406
592
|
}
|
|
1407
593
|
//#endregion
|
|
1408
594
|
//#region extensions/codex/src/app-server/vision-tools.ts
|
|
@@ -1430,10 +616,10 @@ const CODEX_NATIVE_SANDBOX_TOOL_REQUIREMENTS = [
|
|
|
1430
616
|
"apply_patch"
|
|
1431
617
|
];
|
|
1432
618
|
const CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW = /* @__PURE__ */ new Set(["read", "write"]);
|
|
1433
|
-
/** Keeps
|
|
619
|
+
/** Keeps node filesystem and process ownership on its native exec-server. */
|
|
1434
620
|
function resolveCodexNodePlacementToolConstructionPlan(sandbox, nativeToolSurfaceEnabled) {
|
|
1435
621
|
if (!isCodexRemoteExecPlacementSandbox(sandbox) || sandbox?.backendId !== "node" || !("placementNodeId" in sandbox) || typeof sandbox.placementNodeId !== "string" || !sandbox.placementNodeId) return;
|
|
1436
|
-
if (!nativeToolSurfaceEnabled) throw new Error("Codex
|
|
622
|
+
if (!nativeToolSurfaceEnabled) throw new Error("Codex node execution requires its native exec-server tool surface; adjust the session tool policy and start a fresh attempt.");
|
|
1437
623
|
return {
|
|
1438
624
|
includeBaseCodingTools: false,
|
|
1439
625
|
includeShellTools: false,
|
|
@@ -1447,13 +633,6 @@ function preserveRingZeroSystemAgentTool(allTools, filteredTools) {
|
|
|
1447
633
|
if (!openclaw) return filteredTools;
|
|
1448
634
|
return [openclaw, ...filteredTools.filter((tool) => tool.name !== "openclaw")];
|
|
1449
635
|
}
|
|
1450
|
-
/** Splits sandbox and run session keys so tool calls can bind to both scopes when needed. */
|
|
1451
|
-
function resolveOpenClawCodingToolsSessionKeys(params, sandboxSessionKey) {
|
|
1452
|
-
return {
|
|
1453
|
-
sessionKey: sandboxSessionKey,
|
|
1454
|
-
runSessionKey: params.sessionKey && params.sessionKey !== sandboxSessionKey ? params.sessionKey : void 0
|
|
1455
|
-
};
|
|
1456
|
-
}
|
|
1457
636
|
/** Returns the canonical channel used for Codex message routing and receipts. */
|
|
1458
637
|
function resolveCodexMessageToolProvider(params) {
|
|
1459
638
|
return params.messageChannel ?? params.messageProvider;
|
|
@@ -1518,6 +697,10 @@ async function buildDynamicTools(input) {
|
|
|
1518
697
|
...params,
|
|
1519
698
|
disableMessageTool: false
|
|
1520
699
|
} : params;
|
|
700
|
+
const toolRunContext = buildEmbeddedAttemptToolRunContext({
|
|
701
|
+
...params,
|
|
702
|
+
forceMessageTool: shouldForceMessageTool(messagePolicyParams)
|
|
703
|
+
});
|
|
1521
704
|
if (params.disableTools) {
|
|
1522
705
|
input.onWebSearchPolicyResolved?.(false);
|
|
1523
706
|
return [];
|
|
@@ -1531,11 +714,11 @@ async function buildDynamicTools(input) {
|
|
|
1531
714
|
const modelHasVision = params.model.input?.includes("image") ?? false;
|
|
1532
715
|
const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, input.sessionAgentId);
|
|
1533
716
|
const injectedOpenClawCodingToolsFactory = dynamicToolBuildState.openClawCodingToolsFactory;
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
717
|
+
const nativeExecutionPolicy = resolveCodexNativeExecutionPolicyForRun(params, {
|
|
718
|
+
agentId: input.policyAgentId,
|
|
719
|
+
runtimeSessionKey: input.sandboxSessionKey,
|
|
720
|
+
sandbox: input.sandbox
|
|
721
|
+
});
|
|
1539
722
|
const webSearchPlan = resolveCodexWebSearchPlan({
|
|
1540
723
|
config: params.config,
|
|
1541
724
|
disableTools: params.disableTools,
|
|
@@ -1547,16 +730,18 @@ async function buildDynamicTools(input) {
|
|
|
1547
730
|
const toolConstructionPlan = resolveCodexNodePlacementToolConstructionPlan(input.sandbox, input.nativeToolSurfaceEnabled);
|
|
1548
731
|
const options = {
|
|
1549
732
|
agentId: input.sessionAgentId,
|
|
1550
|
-
|
|
733
|
+
policyAgentId: input.policyAgentId,
|
|
734
|
+
...toolRunContext,
|
|
1551
735
|
exec: {
|
|
1552
736
|
...params.execOverrides,
|
|
737
|
+
...input.sessionPermissionPolicy ? { mode: input.sessionPermissionPolicy.execMode } : {},
|
|
1553
738
|
...resolveCodexNodeExecToolOverrides(nativeExecutionPolicy),
|
|
1554
739
|
config: params.config,
|
|
1555
740
|
elevated: params.bashElevated
|
|
1556
741
|
},
|
|
1557
|
-
sessionPermissionPolicy:
|
|
1558
|
-
mode:
|
|
1559
|
-
root:
|
|
742
|
+
sessionPermissionPolicy: input.sessionPermissionPolicy ? {
|
|
743
|
+
mode: input.sessionPermissionPolicy.mode,
|
|
744
|
+
root: input.sessionPermissionPolicy.root
|
|
1560
745
|
} : void 0,
|
|
1561
746
|
sandbox: input.sandbox,
|
|
1562
747
|
...toolConstructionPlan ? { toolConstructionPlan } : {},
|
|
@@ -1582,7 +767,8 @@ async function buildDynamicTools(input) {
|
|
|
1582
767
|
trustedInternalHandoff: params.trustedInternalHandoff,
|
|
1583
768
|
scheduledToolPolicy: params.scheduledToolPolicy,
|
|
1584
769
|
allowGatewaySubagentBinding: params.allowGatewaySubagentBinding || isForcedPrivateQaCodexRuntime(),
|
|
1585
|
-
|
|
770
|
+
sessionKey: input.sandboxSessionKey,
|
|
771
|
+
runSessionKey: params.sessionKey && params.sessionKey !== input.sandboxSessionKey ? params.sessionKey : void 0,
|
|
1586
772
|
sessionId: params.sessionId,
|
|
1587
773
|
runId: params.runId,
|
|
1588
774
|
approvalReviewerDeviceId: params.approvalReviewerDeviceId,
|
|
@@ -1595,6 +781,7 @@ async function buildDynamicTools(input) {
|
|
|
1595
781
|
resolvedWorkspace: input.resolvedWorkspace
|
|
1596
782
|
}),
|
|
1597
783
|
config: params.config,
|
|
784
|
+
githubPublicationAvailable: params.githubPublicationAvailable,
|
|
1598
785
|
authProfileStore: params.toolAuthProfileStore ?? params.authProfileStore,
|
|
1599
786
|
abortSignal: input.runAbortController.signal,
|
|
1600
787
|
emitBeforeToolCallDiagnostics: false,
|
|
@@ -1616,6 +803,7 @@ async function buildDynamicTools(input) {
|
|
|
1616
803
|
hasRepliedRef: params.hasRepliedRef,
|
|
1617
804
|
modelHasVision,
|
|
1618
805
|
computerContextEpoch: input.computerContextEpoch,
|
|
806
|
+
registerRunCleanup: input.registerRunCleanup,
|
|
1619
807
|
requireExplicitMessageTarget: params.requireExplicitMessageTarget ?? isSubagentSessionKey(params.sessionKey),
|
|
1620
808
|
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
|
1621
809
|
taskSuggestionDeliveryMode: params.taskSuggestionDeliveryMode,
|
|
@@ -1663,7 +851,7 @@ async function buildDynamicTools(input) {
|
|
|
1663
851
|
const readableAllTools = [...readableAllToolProjection.tools];
|
|
1664
852
|
const normallyProfiledTools = input.nativeToolSurfaceEnabled === false ? filterCodexDynamicToolsForDisabledNativeSurface(readableAllTools, input.pluginConfig, { preserveShell: shouldKeepOpenClawShellDynamicTools(input, nativeExecutionPolicy) }) : filterCodexDynamicTools(readableAllTools, input.pluginConfig);
|
|
1665
853
|
const profileFilteredTools = (input.isHostScopedToolActive?.("openclaw") ?? isHostScopedAgentToolActive("openclaw")) && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow) ? preserveRingZeroSystemAgentTool(readableAllTools, normallyProfiledTools) : normallyProfiledTools;
|
|
1666
|
-
const codexFilteredTools = addNodeShellDynamicToolsIfNeeded(addGatewayShellDynamicToolsIfAvailable(addSandboxShellDynamicToolsIfAvailable(isCodexMemoryFlushRun(params) ? filterCodexMemoryFlushDynamicTools(readableAllTools) : profileFilteredTools, readableAllTools, input), readableAllTools, input, nativeExecutionPolicy), readableAllTools, input, nativeExecutionPolicy);
|
|
854
|
+
const codexFilteredTools = addNodeShellDynamicToolsIfNeeded(addGatewayShellDynamicToolsIfAvailable(addSandboxShellDynamicToolsIfAvailable(isCodexMemoryFlushRun(params) ? filterCodexMemoryFlushDynamicTools(readableAllTools) : profileFilteredTools, readableAllTools, input, nativeExecutionPolicy), readableAllTools, input, nativeExecutionPolicy), readableAllTools, input, nativeExecutionPolicy);
|
|
1667
855
|
toolBuildStages.mark("codex-filtering");
|
|
1668
856
|
const visionFilteredTools = filterCodexVisionTools(codexFilteredTools, {
|
|
1669
857
|
modelHasVision,
|
|
@@ -1672,33 +860,33 @@ async function buildDynamicTools(input) {
|
|
|
1672
860
|
toolBuildStages.mark("vision-filtering");
|
|
1673
861
|
const webSearchPresent = visionFilteredTools.some((tool) => tool.name === "web_search");
|
|
1674
862
|
const persistentCodexWebSearchSurface = params.config?.tools?.web?.search?.enabled !== false && !(input.pluginConfig.codexDynamicToolsExclude ?? []).some((name) => normalizeCodexDynamicToolName(name) === "web_search");
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
input.onPersistentWebSearchPolicyResolved?.(
|
|
1701
|
-
const filteredTools = filterCodexDynamicToolsForAllowlist(visionFilteredTools,
|
|
863
|
+
let persistentWebSearchAllowed = webSearchPresent;
|
|
864
|
+
if (input.onPersistentWebSearchPolicyResolved && !webSearchPresent && persistentCodexWebSearchSurface) {
|
|
865
|
+
const webSearchPolicy = (await import("openclaw/plugin-sdk/agent-harness")).resolveWebSearchToolPolicy({
|
|
866
|
+
config: params.config,
|
|
867
|
+
modelProvider: params.model.provider,
|
|
868
|
+
modelId: params.modelId,
|
|
869
|
+
agentId: input.policyAgentId,
|
|
870
|
+
sessionKey: input.sandboxSessionKey,
|
|
871
|
+
sandboxToolPolicy: input.sandbox?.tools,
|
|
872
|
+
messageProvider: resolveCodexMessageToolProvider(params),
|
|
873
|
+
agentAccountId: params.agentAccountId,
|
|
874
|
+
groupId: params.groupId,
|
|
875
|
+
groupChannel: params.groupChannel,
|
|
876
|
+
groupSpace: params.groupSpace,
|
|
877
|
+
spawnedBy: params.spawnedBy,
|
|
878
|
+
senderId: params.senderId,
|
|
879
|
+
senderName: params.senderName,
|
|
880
|
+
senderUsername: params.senderUsername,
|
|
881
|
+
senderE164: params.senderE164,
|
|
882
|
+
inputProvenance: params.inputProvenance,
|
|
883
|
+
trustedInternalHandoff: params.trustedInternalHandoff,
|
|
884
|
+
scheduledToolPolicy: params.scheduledToolPolicy
|
|
885
|
+
});
|
|
886
|
+
persistentWebSearchAllowed = webSearchPolicy.persistentAllowed && (!webSearchPolicy.allowed || isCodexMemoryFlushRun(params));
|
|
887
|
+
}
|
|
888
|
+
input.onPersistentWebSearchPolicyResolved?.(persistentWebSearchAllowed);
|
|
889
|
+
const filteredTools = filterCodexDynamicToolsForAllowlist(visionFilteredTools, toolRunContext.runtimeToolAllowlist);
|
|
1702
890
|
toolBuildStages.mark("allowlist-filter");
|
|
1703
891
|
const normalizedTools = normalizeAgentRuntimeTools({
|
|
1704
892
|
runtimePlan: input.ignoreRuntimePlan ? void 0 : params.runtimePlan,
|
|
@@ -1759,48 +947,39 @@ function addGatewayShellDynamicToolsIfAvailable(filteredTools, allTools, input,
|
|
|
1759
947
|
if (!execTool || execExcluded || existingNames.has("gateway_exec")) return filteredTools;
|
|
1760
948
|
const processExcluded = isCodexDynamicToolExcluded(input.pluginConfig, ["process", CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME]);
|
|
1761
949
|
const processAliasAvailable = Boolean(processTool && !processExcluded && !existingNames.has("gateway_process"));
|
|
1762
|
-
const
|
|
1763
|
-
|
|
1764
|
-
|
|
950
|
+
const createProjection = resolveCodexScheduledToolProjectionFactory(input.params.hostCapabilities);
|
|
951
|
+
if (!createProjection) return filteredTools;
|
|
952
|
+
const toolsToAppend = [createGatewayExecProjection(createProjection, execTool, {
|
|
953
|
+
processAliasAvailable,
|
|
954
|
+
...input.sessionPermissionPolicy?.mode === "guarded" ? { ask: "always" } : {}
|
|
1765
955
|
})];
|
|
1766
|
-
if (processAliasAvailable && processTool) toolsToAppend.push(
|
|
956
|
+
if (processAliasAvailable && processTool) toolsToAppend.push(createGatewayProcessProjection(createProjection, processTool));
|
|
1767
957
|
return [...filteredTools, ...toolsToAppend];
|
|
1768
958
|
}
|
|
1769
|
-
/** Preserves delivery-critical tools when a narrow allowlist would otherwise hide them. */
|
|
1770
|
-
function includeForcedCodexDynamicToolAllow(toolsAllow, params) {
|
|
1771
|
-
if (toolsAllow === void 0 || hasWildcardCodexToolsAllow(toolsAllow)) return toolsAllow;
|
|
1772
|
-
const forcedToolNames = shouldForceMessageTool(params) ? ["message"] : [];
|
|
1773
|
-
if (forcedToolNames.length === 0) return toolsAllow;
|
|
1774
|
-
if (toolsAllow.length === 0) return forcedToolNames;
|
|
1775
|
-
const normalized = new Set(toolsAllow.map((name) => normalizeCodexDynamicToolName(name)));
|
|
1776
|
-
const missingToolNames = forcedToolNames.filter((toolName) => !normalized.has(normalizeCodexDynamicToolName(toolName)));
|
|
1777
|
-
return missingToolNames.length === 0 ? toolsAllow : [...toolsAllow, ...missingToolNames];
|
|
1778
|
-
}
|
|
1779
959
|
/** Decides whether Codex native code mode can own shell/file tools for this turn. */
|
|
1780
960
|
function shouldEnableCodexAppServerNativeToolSurface(params, sandbox, options = {}) {
|
|
1781
961
|
if (params.pluginHarnessToolPolicyRestricted === true) return false;
|
|
1782
962
|
if (isCodexMemoryFlushRun(params)) return false;
|
|
1783
963
|
if (params.disableTools) return false;
|
|
1784
|
-
if (
|
|
964
|
+
if (!resolveCodexNativeExecutionPolicyForRun(params, {
|
|
1785
965
|
agentId: options.agentId,
|
|
1786
966
|
runtimeSessionKey: options.runtimeSessionKey,
|
|
1787
967
|
sandbox
|
|
1788
|
-
})) return false;
|
|
1789
|
-
const toolsAllow =
|
|
968
|
+
}).nativeToolSurfaceAllowed) return false;
|
|
969
|
+
const toolsAllow = params.toolsAllow;
|
|
1790
970
|
if (toolsAllow === void 0) return canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
|
|
1791
971
|
return hasWildcardCodexToolsAllow(toolsAllow) && canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
|
|
1792
972
|
}
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
return !resolveCodexNativeExecutionPolicy({
|
|
973
|
+
function resolveCodexNativeExecutionPolicyForRun(params, options = {}) {
|
|
974
|
+
return resolveCodexNativeExecutionPolicy({
|
|
1796
975
|
config: params.config,
|
|
1797
976
|
sessionKey: resolveCodexRuntimePolicySessionKey(params, options.runtimeSessionKey),
|
|
1798
977
|
sessionId: params.sessionId,
|
|
1799
978
|
agentId: options.agentId,
|
|
1800
979
|
execOverrides: params.execOverrides,
|
|
1801
|
-
sandboxAvailable: options.sandbox?.enabled,
|
|
980
|
+
sandboxAvailable: options.sandbox === null ? false : options.sandbox?.enabled,
|
|
1802
981
|
readRuntimeSessionEntry: true
|
|
1803
|
-
})
|
|
982
|
+
});
|
|
1804
983
|
}
|
|
1805
984
|
function resolveCodexRuntimePolicySessionKey(params, runtimeSessionKey) {
|
|
1806
985
|
return runtimeSessionKey?.trim() || params.sandboxSessionKey?.trim() || params.sessionKey?.trim() || params.sessionId;
|
|
@@ -1863,8 +1042,8 @@ function disableCodexPluginThreadConfig(pluginConfig) {
|
|
|
1863
1042
|
};
|
|
1864
1043
|
}
|
|
1865
1044
|
/** Adds sandbox_exec/process aliases when native Code Mode cannot directly honor the sandbox. */
|
|
1866
|
-
function addSandboxShellDynamicToolsIfAvailable(filteredTools, allTools, input) {
|
|
1867
|
-
if (
|
|
1045
|
+
function addSandboxShellDynamicToolsIfAvailable(filteredTools, allTools, input, executionPolicy) {
|
|
1046
|
+
if (isCodexMemoryFlushRun(input.params) || !executionPolicy.nativeToolSurfaceAllowed || !input.sandbox?.enabled || !input.sandbox.backendId.trim() || input.nativeToolSurfaceEnabled !== false || isSandboxShellDynamicToolExcluded(input.pluginConfig)) return filteredTools;
|
|
1868
1047
|
const execTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "exec");
|
|
1869
1048
|
const processTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "process");
|
|
1870
1049
|
if (!execTool || !processTool) return filteredTools;
|
|
@@ -1891,16 +1070,6 @@ function addSandboxShellDynamicToolsIfAvailable(filteredTools, allTools, input)
|
|
|
1891
1070
|
sandboxProcessTool
|
|
1892
1071
|
];
|
|
1893
1072
|
}
|
|
1894
|
-
function shouldExposeSandboxExecDynamicTool(input) {
|
|
1895
|
-
if (isCodexMemoryFlushRun(input.params)) return false;
|
|
1896
|
-
if (isCodexNativeExecutionBlockedByNodeExecHost(input.params, {
|
|
1897
|
-
agentId: input.sessionAgentId,
|
|
1898
|
-
runtimeSessionKey: input.sandboxSessionKey,
|
|
1899
|
-
sandbox: input.sandbox
|
|
1900
|
-
})) return false;
|
|
1901
|
-
const backendId = input.sandbox?.enabled ? input.sandbox.backendId.trim().toLowerCase() : "";
|
|
1902
|
-
return Boolean(backendId && input.nativeToolSurfaceEnabled === false);
|
|
1903
|
-
}
|
|
1904
1073
|
function isSandboxShellDynamicToolExcluded(config) {
|
|
1905
1074
|
return isCodexDynamicToolExcluded(config, [
|
|
1906
1075
|
"exec",
|
|
@@ -1916,26 +1085,12 @@ function addNodeShellDynamicToolsIfNeeded(filteredTools, allTools, input, nodePo
|
|
|
1916
1085
|
if (!nodeExecIsDefault && !nodeExecAvailableFromAuto) return filteredTools;
|
|
1917
1086
|
const execTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "exec");
|
|
1918
1087
|
if (!execTool) return filteredTools;
|
|
1919
|
-
if (!isCodexDynamicToolExcluded(input.pluginConfig, ["exec", "node_exec"]) && !filteredTools.some((tool) => normalizeCodexDynamicToolName(tool.name) === "node_exec")) return [...filteredTools,
|
|
1920
|
-
host: "node",
|
|
1921
|
-
node: nodePolicy.node
|
|
1922
|
-
})];
|
|
1088
|
+
if (!isCodexDynamicToolExcluded(input.pluginConfig, ["exec", "node_exec"]) && !filteredTools.some((tool) => normalizeCodexDynamicToolName(tool.name) === "node_exec")) return [...filteredTools, createNodeExecAliasDynamicTool(execTool, nodePolicy.node)];
|
|
1923
1089
|
return filteredTools;
|
|
1924
1090
|
}
|
|
1925
1091
|
function shouldKeepOpenClawShellDynamicTools(input, nodePolicy) {
|
|
1926
1092
|
return !isCodexMemoryFlushRun(input.params) && input.nativeToolSurfaceEnabled === false && input.sandbox?.enabled !== true && nodePolicy.effectiveExecHost !== "node";
|
|
1927
1093
|
}
|
|
1928
|
-
function resolveCodexNativeExecutionPolicyForDynamicTools(input) {
|
|
1929
|
-
return resolveCodexNativeExecutionPolicy({
|
|
1930
|
-
config: input.params.config,
|
|
1931
|
-
sessionKey: resolveCodexRuntimePolicySessionKey(input.params, input.sandboxSessionKey),
|
|
1932
|
-
sessionId: input.params.sessionId,
|
|
1933
|
-
agentId: input.sessionAgentId,
|
|
1934
|
-
execOverrides: input.params.execOverrides,
|
|
1935
|
-
sandboxAvailable: input.sandbox?.enabled,
|
|
1936
|
-
readRuntimeSessionEntry: true
|
|
1937
|
-
});
|
|
1938
|
-
}
|
|
1939
1094
|
/** Applies a normalized tool allowlist while preserving shell aliases for exec/process. */
|
|
1940
1095
|
function filterCodexDynamicToolsForAllowlist(tools, toolsAllow) {
|
|
1941
1096
|
if (!toolsAllow) return tools;
|
|
@@ -1957,9 +1112,9 @@ function shouldForceMessageTool(params) {
|
|
|
1957
1112
|
}
|
|
1958
1113
|
//#endregion
|
|
1959
1114
|
//#region extensions/codex/src/app-server/sandbox-exec-server-node-relay.ts
|
|
1960
|
-
const CODEX_NODE_EXEC_SERVER_MAX_MESSAGE_BYTES$1 =
|
|
1115
|
+
const CODEX_NODE_EXEC_SERVER_MAX_MESSAGE_BYTES$1 = 67108864;
|
|
1961
1116
|
const CODEX_NODE_EXEC_SERVER_MAX_FAILURE_DETAIL_CHARS = 240;
|
|
1962
|
-
const CODEX_NODE_HTTP_CREDENTIAL_BODY_MAX_BYTES =
|
|
1117
|
+
const CODEX_NODE_HTTP_CREDENTIAL_BODY_MAX_BYTES = 1048576;
|
|
1963
1118
|
const CODEX_NODE_HTTP_CREDENTIAL_SCAN_MAX_FIELDS = 256;
|
|
1964
1119
|
const CODEX_NODE_HTTP_CREDENTIAL_SCAN_MAX_DEPTH = 8;
|
|
1965
1120
|
const CODEX_NODE_HTTP_CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -1986,7 +1141,7 @@ const nodeExecServerTextDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
|
1986
1141
|
/** Produces the bounded, redacted terminal failure shared by pending and claimed node leases. */
|
|
1987
1142
|
function createCodexNodeExecServerDisconnectError(reason, cause) {
|
|
1988
1143
|
const detail = cause === void 0 ? "" : `: ${truncateUtf16Safe(redactSensitiveText(formatErrorMessage$1(cause), { mode: "tools" }), CODEX_NODE_EXEC_SERVER_MAX_FAILURE_DETAIL_CHARS)}`;
|
|
1989
|
-
return /* @__PURE__ */ new Error(`Codex
|
|
1144
|
+
return /* @__PURE__ */ new Error(`Codex execution node disconnected; start a fresh attempt. (${reason}${detail})`);
|
|
1990
1145
|
}
|
|
1991
1146
|
/** Relays one authorized, single-use Codex exec-server channel without interpreting its protocol. */
|
|
1992
1147
|
async function startCodexNodeExecServerRelay(params) {
|
|
@@ -2013,7 +1168,7 @@ async function startCodexNodeExecServerRelay(params) {
|
|
|
2013
1168
|
if (!closed && !params.lease.closed) params.lease.onDisconnected?.(createCodexNodeExecServerDisconnectError(reason, cause));
|
|
2014
1169
|
closeBoth(code, reason);
|
|
2015
1170
|
};
|
|
2016
|
-
params.lease.onChannelClosed = ({ failed, error }) => failUnexpectedly(failed ? 1011 : 1001, failed ? "execution
|
|
1171
|
+
params.lease.onChannelClosed = ({ failed, error }) => failUnexpectedly(failed ? 1011 : 1001, failed ? "execution node failed" : "execution node disconnected", error);
|
|
2017
1172
|
socket.once("close", () => failUnexpectedly(1001, "execution socket closed"));
|
|
2018
1173
|
socket.once("error", () => failUnexpectedly(1011, "execution socket failed"));
|
|
2019
1174
|
let toNode = Promise.resolve();
|
|
@@ -2217,7 +1372,7 @@ function createCredentialedCodexNodeHttpRejection(request) {
|
|
|
2217
1372
|
id: request.id,
|
|
2218
1373
|
error: {
|
|
2219
1374
|
code: -32602,
|
|
2220
|
-
message: "Authenticated remote HTTP is unavailable on
|
|
1375
|
+
message: "Authenticated remote HTTP is unavailable on execution nodes; run on Gateway or use an intentionally credential-free endpoint."
|
|
2221
1376
|
}
|
|
2222
1377
|
}));
|
|
2223
1378
|
}
|
|
@@ -2599,10 +1754,10 @@ function joinSandboxChildPath(parent, child) {
|
|
|
2599
1754
|
* Implements filesystem JSON-RPC handlers for the Codex sandbox exec-server
|
|
2600
1755
|
* with OpenClaw sandbox policy checks before every bridge operation.
|
|
2601
1756
|
*/
|
|
2602
|
-
const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES =
|
|
1757
|
+
const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES = 536870912;
|
|
2603
1758
|
const CODEX_SANDBOX_EXEC_SERVER_MAX_OPEN_FILE_READS = 128;
|
|
2604
|
-
const CODEX_SANDBOX_EXEC_SERVER_MAX_BUFFERED_FILE_READ_BYTES =
|
|
2605
|
-
const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_BLOCK_BYTES =
|
|
1759
|
+
const CODEX_SANDBOX_EXEC_SERVER_MAX_BUFFERED_FILE_READ_BYTES = 67108864;
|
|
1760
|
+
const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_BLOCK_BYTES = 1048576;
|
|
2606
1761
|
const CODEX_SANDBOX_EXEC_SERVER_MAX_FILE_READ_HANDLE_ID_BYTES = 32;
|
|
2607
1762
|
/** Opens a policy-checked sandbox file under a bounded, connection-owned handle. */
|
|
2608
1763
|
async function openFile(execServer, handles, params) {
|
|
@@ -3006,12 +2161,14 @@ function delay(ms) {
|
|
|
3006
2161
|
* access through the active OpenClaw sandbox backend.
|
|
3007
2162
|
*/
|
|
3008
2163
|
/** Maximum JSON-line size accepted from the streaming HTTP helper process. */
|
|
3009
|
-
const SANDBOX_HTTP_STREAM_LINE_MAX_CHARS =
|
|
2164
|
+
const SANDBOX_HTTP_STREAM_LINE_MAX_CHARS = 262144;
|
|
3010
2165
|
/** Handles one sandbox HTTP JSON-RPC request, optionally streaming response body deltas. */
|
|
3011
2166
|
async function httpRequest(execServer, notifications, params) {
|
|
3012
2167
|
const record = requireObject(params, "http/request params");
|
|
3013
2168
|
const requestId = requireString(record.requestId, "requestId");
|
|
3014
2169
|
const url = requireString(record.url, "url");
|
|
2170
|
+
const redirectPolicy = record.redirectPolicy ?? "follow";
|
|
2171
|
+
if (redirectPolicy !== "follow" && redirectPolicy !== "stop") throw new Error("http/request redirectPolicy must be follow or stop");
|
|
3015
2172
|
assertSandboxHttpRequestTargetAllowed(url);
|
|
3016
2173
|
const request = {
|
|
3017
2174
|
method: requireString(record.method, "method"),
|
|
@@ -3019,6 +2176,7 @@ async function httpRequest(execServer, notifications, params) {
|
|
|
3019
2176
|
headers: readHttpHeaders(record.headers),
|
|
3020
2177
|
bodyBase64: typeof record.bodyBase64 === "string" ? record.bodyBase64 : void 0,
|
|
3021
2178
|
timeoutMs: typeof record.timeoutMs === "number" && record.timeoutMs > 0 ? Math.floor(record.timeoutMs) : void 0,
|
|
2179
|
+
redirectPolicy,
|
|
3022
2180
|
streamResponse: record.streamResponse === true
|
|
3023
2181
|
};
|
|
3024
2182
|
if (request.streamResponse) return await runStreamingSandboxHttpRequest(execServer, notifications, requestId, request);
|
|
@@ -3315,9 +2473,43 @@ def assert_url_allowed(url):
|
|
|
3315
2473
|
PINNED_ADDRESSES[hostname] = sorted(addresses)
|
|
3316
2474
|
|
|
3317
2475
|
class GuardedRedirectHandler(urllib.request.HTTPRedirectHandler):
|
|
2476
|
+
# Python 3.9 lacks the 308 dispatch alias; use the same guarded redirect path.
|
|
2477
|
+
http_error_308 = urllib.request.HTTPRedirectHandler.http_error_302
|
|
2478
|
+
|
|
2479
|
+
def __init__(self, redirect_policy):
|
|
2480
|
+
self.redirect_policy = redirect_policy
|
|
2481
|
+
|
|
3318
2482
|
def redirect_request(self, req, fp, code, msg, headers, newurl):
|
|
2483
|
+
if self.redirect_policy == "stop":
|
|
2484
|
+
return None
|
|
3319
2485
|
assert_url_allowed(newurl)
|
|
3320
|
-
|
|
2486
|
+
method = req.get_method()
|
|
2487
|
+
drop_body = code == 303 or (code in (301, 302) and method == "POST")
|
|
2488
|
+
next_headers = dict(req.headers)
|
|
2489
|
+
if drop_body:
|
|
2490
|
+
if method != "HEAD":
|
|
2491
|
+
method = "GET"
|
|
2492
|
+
for name in ("content-type", "content-length", "content-encoding", "transfer-encoding"):
|
|
2493
|
+
next_headers.pop(name.capitalize(), None)
|
|
2494
|
+
redirected = urllib.request.Request(
|
|
2495
|
+
newurl,
|
|
2496
|
+
data=None if drop_body else req.data,
|
|
2497
|
+
headers=next_headers,
|
|
2498
|
+
method=method,
|
|
2499
|
+
origin_req_host=req.origin_req_host,
|
|
2500
|
+
unverifiable=True,
|
|
2501
|
+
)
|
|
2502
|
+
previous = urllib.parse.urlsplit(req.full_url)
|
|
2503
|
+
target = urllib.parse.urlsplit(newurl)
|
|
2504
|
+
previous_port = previous.port or (443 if previous.scheme == "https" else 80)
|
|
2505
|
+
target_port = target.port or (443 if target.scheme == "https" else 80)
|
|
2506
|
+
if (previous.scheme, previous.hostname, previous_port) != (
|
|
2507
|
+
target.scheme, target.hostname, target_port
|
|
2508
|
+
):
|
|
2509
|
+
# Match Codex's route-aware client: cross-origin hops never inherit secrets.
|
|
2510
|
+
for name in ("authorization", "cookie", "proxy-authorization", "www-authenticate", "cookie2"):
|
|
2511
|
+
redirected.remove_header(name.capitalize())
|
|
2512
|
+
return redirected
|
|
3321
2513
|
|
|
3322
2514
|
def pinned_getaddrinfo(original_getaddrinfo):
|
|
3323
2515
|
def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
|
|
@@ -3373,7 +2565,8 @@ def main():
|
|
|
3373
2565
|
timeout = None
|
|
3374
2566
|
if isinstance(timeout_ms, (int, float)) and timeout_ms > 0:
|
|
3375
2567
|
timeout = timeout_ms / 1000
|
|
3376
|
-
|
|
2568
|
+
redirect_handler = GuardedRedirectHandler(input_data.get("redirectPolicy", "follow"))
|
|
2569
|
+
opener = urllib.request.build_opener(urllib.request.ProxyHandler({}), redirect_handler)
|
|
3377
2570
|
original_getaddrinfo = socket.getaddrinfo
|
|
3378
2571
|
socket.getaddrinfo = pinned_getaddrinfo(original_getaddrinfo)
|
|
3379
2572
|
try:
|
|
@@ -3396,7 +2589,7 @@ python3 "$tmp"
|
|
|
3396
2589
|
* termination for Codex sandbox exec-server process RPCs.
|
|
3397
2590
|
*/
|
|
3398
2591
|
const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
3399
|
-
const RETAINED_PROCESS_OUTPUT_BYTES =
|
|
2592
|
+
const RETAINED_PROCESS_OUTPUT_BYTES = 1048576;
|
|
3400
2593
|
const CLOSED_PROCESS_EVICTION_MS = 6e4;
|
|
3401
2594
|
/** Starts a sandbox-backed process and registers it in the connection-local process table. */
|
|
3402
2595
|
async function startProcess(execServer, processes, notify, params) {
|
|
@@ -3406,6 +2599,7 @@ async function startProcess(execServer, processes, notify, params) {
|
|
|
3406
2599
|
const argv = requireStringArray(record.argv, "argv");
|
|
3407
2600
|
const cwd = resolveExecServerPath(requireString(record.cwd, "cwd"), "process cwd");
|
|
3408
2601
|
rejectUnsupportedArg0(record.arg0);
|
|
2602
|
+
assertSupportedProcessSandbox(execServer, record);
|
|
3409
2603
|
const env = readProcessEnv(record);
|
|
3410
2604
|
const managed = {
|
|
3411
2605
|
processId,
|
|
@@ -3450,7 +2644,18 @@ async function startProcess(execServer, processes, notify, params) {
|
|
|
3450
2644
|
} finally {
|
|
3451
2645
|
if (managed.startPromise === startPromise) managed.startPromise = void 0;
|
|
3452
2646
|
}
|
|
3453
|
-
return {
|
|
2647
|
+
return {
|
|
2648
|
+
processId,
|
|
2649
|
+
sandboxType: "none"
|
|
2650
|
+
};
|
|
2651
|
+
}
|
|
2652
|
+
function assertSupportedProcessSandbox(execServer, record) {
|
|
2653
|
+
if (record.networkProxy !== void 0 && record.networkProxy !== null) throw new Error("Codex sandbox exec-server network proxy launch is not supported.");
|
|
2654
|
+
if (record.enforceManagedNetwork === true || record.managedNetwork !== void 0 && record.managedNetwork !== null) throw new Error("Codex managed network restrictions cannot be enforced by the sandbox backend.");
|
|
2655
|
+
if (resolveFsSandboxPolicy(execServer, record)?.unrestricted === false) throw new Error("Codex process filesystem sandbox restrictions cannot be enforced by the backend.");
|
|
2656
|
+
if (record.sandbox === void 0 || record.sandbox === null) return;
|
|
2657
|
+
if (requireObject(requireObject(record.sandbox, "process sandbox context").permissions, "process sandbox permissions").network !== "restricted") return;
|
|
2658
|
+
if (!execServer.networkIsolated) throw new Error("Codex network restrictions cannot be enforced by the sandbox backend.");
|
|
3454
2659
|
}
|
|
3455
2660
|
async function runProcess(execServer, managed, params) {
|
|
3456
2661
|
const backend = execServer.backend;
|
|
@@ -3641,10 +2846,11 @@ function readEnv(value) {
|
|
|
3641
2846
|
return env;
|
|
3642
2847
|
}
|
|
3643
2848
|
function readProcessEnv(record) {
|
|
3644
|
-
|
|
2849
|
+
const requestedEnv = {
|
|
3645
2850
|
...buildEnvFromPolicy(record.envPolicy),
|
|
3646
2851
|
...readEnv(record.env)
|
|
3647
|
-
}
|
|
2852
|
+
};
|
|
2853
|
+
return sanitizeEnvVars(requestedEnv).allowed;
|
|
3648
2854
|
}
|
|
3649
2855
|
function buildEnvFromPolicy(value) {
|
|
3650
2856
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
@@ -3759,15 +2965,15 @@ var CodexSandboxExecSession = class {
|
|
|
3759
2965
|
* Hosts the local OpenClaw sandbox exec-server that Codex app-server native
|
|
3760
2966
|
* execution can register as an external environment.
|
|
3761
2967
|
*/
|
|
3762
|
-
const CODEX_SANDBOX_EXEC_SERVER_MAX_INBOUND_MESSAGE_BYTES =
|
|
3763
|
-
const CODEX_NODE_EXEC_SERVER_MAX_MESSAGE_BYTES =
|
|
2968
|
+
const CODEX_SANDBOX_EXEC_SERVER_MAX_INBOUND_MESSAGE_BYTES = 104857600;
|
|
2969
|
+
const CODEX_NODE_EXEC_SERVER_MAX_MESSAGE_BYTES = 67108864;
|
|
3764
2970
|
const codexNodeExecServerLeases = /* @__PURE__ */ new WeakMap();
|
|
3765
2971
|
/** Starts or reuses a sandbox exec-server and registers it with Codex app-server. */
|
|
3766
2972
|
async function ensureCodexSandboxExecServerEnvironment(params) {
|
|
3767
2973
|
if (!params.sandbox?.enabled) return;
|
|
3768
2974
|
const placementNodeId = readCodexPlacementNodeId(params.sandbox);
|
|
3769
2975
|
if (!params.sandbox.backend && !placementNodeId) return;
|
|
3770
|
-
if (placementNodeId && !params.runtime) throw new Error("Codex
|
|
2976
|
+
if (placementNodeId && !params.runtime) throw new Error("Codex node execution requires its active plugin runtime.");
|
|
3771
2977
|
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.");
|
|
3772
2978
|
const { server: execServer, nodeLease } = await acquireOpenClawExecServer({
|
|
3773
2979
|
sandbox: params.sandbox,
|
|
@@ -3833,7 +3039,7 @@ async function acquireOpenClawExecServer(params) {
|
|
|
3833
3039
|
if (!("node" in server)) return { server };
|
|
3834
3040
|
if (!runtime || !signal) {
|
|
3835
3041
|
await releaseOpenClawExecServer(server);
|
|
3836
|
-
throw new Error("Codex
|
|
3042
|
+
throw new Error("Codex node execution requires an active runtime and attempt.");
|
|
3837
3043
|
}
|
|
3838
3044
|
try {
|
|
3839
3045
|
const placementIdentity = readCodexPlacementWorkspaceIdentity(sandbox);
|
|
@@ -3852,7 +3058,7 @@ async function acquireOpenClawExecServer(params) {
|
|
|
3852
3058
|
});
|
|
3853
3059
|
if (signal.aborted || server.closed || sandboxExecServerRegistry.servers.get(key) !== promise) {
|
|
3854
3060
|
channel.close();
|
|
3855
|
-
throw new Error("Codex
|
|
3061
|
+
throw new Error("Codex node execution retired before its channel was ready.");
|
|
3856
3062
|
}
|
|
3857
3063
|
const nodeLease = {
|
|
3858
3064
|
id: randomUUID(),
|
|
@@ -3936,7 +3142,8 @@ async function startOpenClawExecServer(sandbox) {
|
|
|
3936
3142
|
} : {
|
|
3937
3143
|
...common,
|
|
3938
3144
|
backend: connection.backend,
|
|
3939
|
-
fsBridge: connection.fsBridge
|
|
3145
|
+
fsBridge: connection.fsBridge,
|
|
3146
|
+
networkIsolated: (connection.backend.id === "docker" || connection.backend.id === "podman") && sandbox.docker.network.trim().toLowerCase() === "none"
|
|
3940
3147
|
};
|
|
3941
3148
|
server.on("connection", (socket, request) => {
|
|
3942
3149
|
socket.on("error", handleExecServerSocketError);
|
|
@@ -3977,7 +3184,7 @@ function readCodexPlacementNodeId(sandbox) {
|
|
|
3977
3184
|
return sandbox.placementNodeId;
|
|
3978
3185
|
}
|
|
3979
3186
|
function readCodexPlacementWorkspaceIdentity(sandbox) {
|
|
3980
|
-
if (!("placementEnvironmentId" in sandbox) || typeof sandbox.placementEnvironmentId !== "string" || !sandbox.placementEnvironmentId || sandbox.placementEnvironmentId.trim() !== sandbox.placementEnvironmentId || !("placementSessionId" in sandbox) || typeof sandbox.placementSessionId !== "string" || !sandbox.placementSessionId || sandbox.placementSessionId.trim() !== sandbox.placementSessionId || !("placementOwnerEpoch" in sandbox) || typeof sandbox.placementOwnerEpoch !== "number" || !Number.isSafeInteger(sandbox.placementOwnerEpoch) || sandbox.placementOwnerEpoch < 1 || !sandbox.sessionKey || sandbox.sessionKey.trim() !== sandbox.sessionKey) throw new Error("Codex
|
|
3187
|
+
if (!("placementEnvironmentId" in sandbox) || typeof sandbox.placementEnvironmentId !== "string" || !sandbox.placementEnvironmentId || sandbox.placementEnvironmentId.trim() !== sandbox.placementEnvironmentId || !("placementSessionId" in sandbox) || typeof sandbox.placementSessionId !== "string" || !sandbox.placementSessionId || sandbox.placementSessionId.trim() !== sandbox.placementSessionId || !("placementOwnerEpoch" in sandbox) || typeof sandbox.placementOwnerEpoch !== "number" || !Number.isSafeInteger(sandbox.placementOwnerEpoch) || sandbox.placementOwnerEpoch < 1 || !sandbox.sessionKey || sandbox.sessionKey.trim() !== sandbox.sessionKey) throw new Error("Codex node execution requires its exact placement workspace identity.");
|
|
3981
3188
|
return {
|
|
3982
3189
|
environmentId: sandbox.placementEnvironmentId,
|
|
3983
3190
|
sessionId: sandbox.placementSessionId,
|
|
@@ -4018,7 +3225,7 @@ function handleClosedCodexNodeExecServerLease(execServer, lease, result) {
|
|
|
4018
3225
|
return;
|
|
4019
3226
|
}
|
|
4020
3227
|
try {
|
|
4021
|
-
lease.onDisconnected?.(createCodexNodeExecServerDisconnectError(result.failed ? "execution
|
|
3228
|
+
lease.onDisconnected?.(createCodexNodeExecServerDisconnectError(result.failed ? "execution node failed" : "execution node disconnected", result.error));
|
|
4022
3229
|
} finally {
|
|
4023
3230
|
closeCodexNodeExecServerLease(execServer, lease);
|
|
4024
3231
|
}
|
|
@@ -4140,6 +3347,8 @@ async function handleCodexAppServerApprovalRequest(params) {
|
|
|
4140
3347
|
resolvedOutcome = "approved-once";
|
|
4141
3348
|
resolvedMessage = "Codex app-server approval granted for this byte-bound command only.";
|
|
4142
3349
|
}
|
|
3350
|
+
params.signal?.throwIfAborted();
|
|
3351
|
+
if (resolvedOutcome !== "denied") params.paramsForRun.hostCapabilities.assertActive();
|
|
4143
3352
|
emitApprovalEvent(params.paramsForRun, {
|
|
4144
3353
|
phase: "resolved",
|
|
4145
3354
|
kind: context.kind,
|
|
@@ -4156,7 +3365,7 @@ async function handleCodexAppServerApprovalRequest(params) {
|
|
|
4156
3365
|
return buildApprovalResponse(params.method, context.requestParams, resolvedOutcome);
|
|
4157
3366
|
};
|
|
4158
3367
|
try {
|
|
4159
|
-
if (params.method === "item/commandExecution/requestApproval") {
|
|
3368
|
+
if (params.method === "item/commandExecution/requestApproval" && !readNetworkApprovalContext(requestParams)) {
|
|
4160
3369
|
const command = readPolicyCommand(requestParams);
|
|
4161
3370
|
const cwd = readStringField(requestParams, "cwd") ?? params.paramsForRun.workspaceDir;
|
|
4162
3371
|
const prepareMutableFileApproval = params.paramsForRun.hostCapabilities.prepareMutableFileApproval;
|
|
@@ -4178,14 +3387,16 @@ async function handleCodexAppServerApprovalRequest(params) {
|
|
|
4178
3387
|
autoApprove: params.autoApprove,
|
|
4179
3388
|
signal: params.signal
|
|
4180
3389
|
});
|
|
3390
|
+
params.signal?.throwIfAborted();
|
|
4181
3391
|
if (policyOutcome?.outcome === "denied") {
|
|
4182
3392
|
recordNativeToolFailureDisposition(params, context, policyOutcome.failureDisposition);
|
|
4183
3393
|
return await resolvePolicyApproval("denied", policyOutcome.reason);
|
|
4184
3394
|
}
|
|
4185
3395
|
if (policyOutcome?.outcome === "approved-once" || policyOutcome?.outcome === "approved-session") return await resolvePolicyApproval(policyOutcome.outcome);
|
|
4186
|
-
if (CONCRETE_TOOL_AUTO_APPROVAL_METHODS.has(params.method) && params.autoApprove === true) return await resolvePolicyApproval("approved-session", "Codex app-server approval auto-approved by runtime policy.");
|
|
3396
|
+
if (CONCRETE_TOOL_AUTO_APPROVAL_METHODS.has(params.method) && !readNetworkApprovalContext(requestParams) && params.autoApprove === true) return await resolvePolicyApproval("approved-session", "Codex app-server approval auto-approved by runtime policy.");
|
|
4187
3397
|
const requestResult = await requestPluginApproval({
|
|
4188
3398
|
hostCapabilities: params.paramsForRun.hostCapabilities,
|
|
3399
|
+
signal: params.signal,
|
|
4189
3400
|
title: context.title,
|
|
4190
3401
|
description: context.description,
|
|
4191
3402
|
severity: context.severity,
|
|
@@ -4299,18 +3510,19 @@ function buildApprovalContext(params) {
|
|
|
4299
3510
|
const reasonPreview = sanitizeApprovalPreview(readStringPreview(params.requestParams, "reason"), 180);
|
|
4300
3511
|
const command = commandPreview.text;
|
|
4301
3512
|
const reason = reasonPreview.text;
|
|
3513
|
+
const networkApproval = params.method === "item/commandExecution/requestApproval" ? readNetworkApprovalContext(params.requestParams) : void 0;
|
|
4302
3514
|
const approvalKind = params.method.includes("commandExecution") ? "command" : params.method.includes("fileChange") ? "file-change" : params.method.includes("permissions") ? "permissions" : "other";
|
|
4303
3515
|
const kind = approvalKind === "command" ? "exec" : approvalKind === "other" ? "unknown" : "plugin";
|
|
4304
3516
|
const permissionLines = params.method === "item/permissions/requestApproval" ? describeRequestedPermissions(params.requestParams) : [];
|
|
4305
|
-
const title = kind === "exec" ? "Codex app-server command approval" : params.method === "item/permissions/requestApproval" ? "Codex app-server permission approval" : kind === "plugin" ? "Codex app-server file approval" : "Codex app-server approval";
|
|
4306
|
-
const subject = permissionLines[0] ?? (command ? `Command: ${formatApprovalPreviewSubject(command, commandPreview.omitted)}` : commandPreview.omitted ? `Command: ${APPROVAL_PREVIEW_OMITTED}` : reason ? `Reason: ${formatApprovalPreviewSubject(reason, reasonPreview.omitted)}` : reasonPreview.omitted ? `Reason: ${APPROVAL_PREVIEW_OMITTED}` : `Request method: ${params.method}`);
|
|
3517
|
+
const title = networkApproval ? "Codex app-server network approval" : kind === "exec" ? "Codex app-server command approval" : params.method === "item/permissions/requestApproval" ? "Codex app-server permission approval" : kind === "plugin" ? "Codex app-server file approval" : "Codex app-server approval";
|
|
3518
|
+
const subject = (networkApproval ? `Network: ${sanitizePermissionScalar(networkApproval.protocol)}://${sanitizePermissionHostValue(networkApproval.host)}` : void 0) ?? permissionLines[0] ?? (command ? `Command: ${formatApprovalPreviewSubject(command, commandPreview.omitted)}` : commandPreview.omitted ? `Command: ${APPROVAL_PREVIEW_OMITTED}` : reason ? `Reason: ${formatApprovalPreviewSubject(reason, reasonPreview.omitted)}` : reasonPreview.omitted ? `Reason: ${APPROVAL_PREVIEW_OMITTED}` : `Request method: ${params.method}`);
|
|
4307
3519
|
return {
|
|
4308
3520
|
approvalKind,
|
|
4309
3521
|
kind,
|
|
4310
3522
|
title,
|
|
4311
3523
|
description: permissionLines.length > 0 ? joinDescriptionLinesWithinLimit(permissionLines, PERMISSION_DESCRIPTION_MAX_LENGTH) : [subject, ...commandDetailLines].join("\n"),
|
|
4312
3524
|
severity: kind === "exec" ? "warning" : "info",
|
|
4313
|
-
toolName: kind === "exec" ? "codex_command_approval" : params.method === "item/permissions/requestApproval" ? "codex_permission_approval" : "codex_file_approval",
|
|
3525
|
+
toolName: networkApproval ? "codex_network_approval" : kind === "exec" ? "codex_command_approval" : params.method === "item/permissions/requestApproval" ? "codex_permission_approval" : "codex_file_approval",
|
|
4314
3526
|
itemId,
|
|
4315
3527
|
approvalId,
|
|
4316
3528
|
requestParams: params.requestParams,
|
|
@@ -4482,6 +3694,10 @@ function sanitizeRelayDecisionReason(value) {
|
|
|
4482
3694
|
}
|
|
4483
3695
|
function buildOpenClawToolPolicyRequest(method, requestParams) {
|
|
4484
3696
|
if (method === "item/commandExecution/requestApproval") {
|
|
3697
|
+
if (readNetworkApprovalContext(requestParams)) return {
|
|
3698
|
+
toolName: "codex_network_approval",
|
|
3699
|
+
params: { approval: requestParams ?? {} }
|
|
3700
|
+
};
|
|
4485
3701
|
const command = readPolicyCommand(requestParams);
|
|
4486
3702
|
return {
|
|
4487
3703
|
toolName: "exec",
|
|
@@ -4694,7 +3910,8 @@ function summarizeNetworkPolicyAmendments(value) {
|
|
|
4694
3910
|
function sanitizePermissionHostValue(value) {
|
|
4695
3911
|
const withoutScheme = sanitizePermissionScalar(value).toLowerCase().replace(/^[a-z][a-z0-9+.-]*:\/\//, "");
|
|
4696
3912
|
const authority = withoutScheme.split(/[/?#]/, 1)[0] ?? withoutScheme;
|
|
4697
|
-
|
|
3913
|
+
const withoutUserInfo = authority.includes("@") ? authority.slice(authority.lastIndexOf("@") + 1) : authority;
|
|
3914
|
+
return truncateCodexApprovalDisplayText(withoutUserInfo, PERMISSION_VALUE_MAX_LENGTH);
|
|
4698
3915
|
}
|
|
4699
3916
|
function sanitizePermissionPathValue(value) {
|
|
4700
3917
|
return truncateCodexApprovalDisplayText(formatApprovalDisplayPath(sanitizePermissionScalar(value)), PERMISSION_VALUE_MAX_LENGTH);
|
|
@@ -4769,6 +3986,15 @@ function readPolicyCommand(record) {
|
|
|
4769
3986
|
const actionCommands = readCommandActions(record);
|
|
4770
3987
|
if (actionCommands.length > 0) return actionCommands.join(" && ");
|
|
4771
3988
|
}
|
|
3989
|
+
function readNetworkApprovalContext(record) {
|
|
3990
|
+
const context = isJsonObject(record?.networkApprovalContext) ? record.networkApprovalContext : void 0;
|
|
3991
|
+
const host = readStringField(context, "host");
|
|
3992
|
+
const protocol = readStringField(context, "protocol");
|
|
3993
|
+
return host && protocol ? {
|
|
3994
|
+
host,
|
|
3995
|
+
protocol
|
|
3996
|
+
} : void 0;
|
|
3997
|
+
}
|
|
4772
3998
|
function readCommandActions(record) {
|
|
4773
3999
|
const actions = record?.commandActions;
|
|
4774
4000
|
if (!Array.isArray(actions)) return [];
|
|
@@ -4814,7 +4040,8 @@ function appendPreviewPart(source, part, separator) {
|
|
|
4814
4040
|
}
|
|
4815
4041
|
function sanitizeApprovalPreview(source, maxLength) {
|
|
4816
4042
|
if (!source || !source.value) return { omitted: false };
|
|
4817
|
-
const
|
|
4043
|
+
const rawPreview = stripDanglingCodexApprovalTerminalSequence(source.value);
|
|
4044
|
+
const sanitized = sanitizeCodexApprovalVisibleText(rawPreview);
|
|
4818
4045
|
if (!sanitized) return { omitted: true };
|
|
4819
4046
|
return {
|
|
4820
4047
|
text: formatCodexDisplayText(truncateCodexApprovalDisplayText(sanitized, maxLength)),
|
|
@@ -4958,6 +4185,8 @@ async function routeCodexAppServerElicitationRequest(params) {
|
|
|
4958
4185
|
if (!requestParams || readNonBlankStringField(requestParams, "threadId") !== params.threadId) return { kind: "not-mine" };
|
|
4959
4186
|
const requestTurnId = requestParams.turnId;
|
|
4960
4187
|
if (requestTurnId !== null && requestTurnId !== void 0 && requestTurnId !== params.turnId) return { kind: "not-mine" };
|
|
4188
|
+
if (!((isJsonObject(requestParams["_meta"]) ? requestParams["_meta"] : void 0)?.[MCP_TOOL_APPROVAL_KIND_KEY] === MCP_TOOL_APPROVAL_KIND || params.computerUseMcpServerName !== void 0 && readNonBlankStringField(requestParams, "serverName") === params.computerUseMcpServerName)) return { kind: "not-mine" };
|
|
4189
|
+
if (params.signal?.aborted) return handled(createCodexElicitationResponse("cancel"));
|
|
4961
4190
|
const pluginResolution = resolvePluginElicitation({
|
|
4962
4191
|
requestParams,
|
|
4963
4192
|
pluginAppPolicyContext: params.pluginAppPolicyContext
|
|
@@ -4983,7 +4212,7 @@ async function routeCodexAppServerElicitationRequest(params) {
|
|
|
4983
4212
|
}));
|
|
4984
4213
|
}
|
|
4985
4214
|
const approvalPrompt = readComputerUseApprovalElicitation(requestParams, params.computerUseMcpServerName) ?? readBridgeableApprovalElicitation(requestParams);
|
|
4986
|
-
if (!approvalPrompt) return
|
|
4215
|
+
if (!approvalPrompt) return handled(createCodexElicitationResponse("decline"));
|
|
4987
4216
|
return handled(buildElicitationResponse(approvalPrompt, await requestPluginApprovalOutcome({
|
|
4988
4217
|
paramsForRun: params.paramsForRun,
|
|
4989
4218
|
title: approvalPrompt.title,
|
|
@@ -5256,7 +4485,8 @@ function readDisplayParamLines(meta) {
|
|
|
5256
4485
|
return remaining > 0 ? [...lines, `- Additional parameters: ${remaining} more`] : lines;
|
|
5257
4486
|
}
|
|
5258
4487
|
function formatDisplayParamValue(value) {
|
|
5259
|
-
|
|
4488
|
+
const formatted = typeof value === "string" ? value : formatDisplayJsonValue(value ?? null);
|
|
4489
|
+
return truncateCodexApprovalDisplayText(sanitizeDisplayText(formatted), MAX_DISPLAY_PARAM_VALUE_LENGTH);
|
|
5260
4490
|
}
|
|
5261
4491
|
function formatDisplayJsonValue(value, depth = MAX_DISPLAY_VALUE_DEPTH) {
|
|
5262
4492
|
if (value === null) return "null";
|
|
@@ -5304,6 +4534,7 @@ async function requestPluginApprovalOutcome(params) {
|
|
|
5304
4534
|
try {
|
|
5305
4535
|
const requestResult = await requestPluginApproval({
|
|
5306
4536
|
hostCapabilities: params.paramsForRun.hostCapabilities,
|
|
4537
|
+
signal: params.signal,
|
|
5307
4538
|
title: params.title,
|
|
5308
4539
|
description: params.description,
|
|
5309
4540
|
severity: "warning",
|
|
@@ -5490,7 +4721,7 @@ function assertCodexDynamicToolInputMatchesSchema(params) {
|
|
|
5490
4721
|
const visibleErrors = validation.errors.slice(0, MAX_CODEX_DYNAMIC_TOOL_VALIDATION_ERRORS);
|
|
5491
4722
|
const details = visibleErrors.map((error) => {
|
|
5492
4723
|
if (error.text.length <= MAX_CODEX_DYNAMIC_TOOL_VALIDATION_ERROR_CHARS) return error.text;
|
|
5493
|
-
return `${error.text.slice(0,
|
|
4724
|
+
return `${error.text.slice(0, 141)}${CODEX_DYNAMIC_TOOL_VALIDATION_TRUNCATED_SUFFIX}`;
|
|
5494
4725
|
}).join("; ");
|
|
5495
4726
|
const omitted = validation.errors.length - visibleErrors.length;
|
|
5496
4727
|
const omittedSuffix = omitted > 0 ? `; ${omitted} more violation(s) omitted` : "";
|
|
@@ -5699,6 +4930,8 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5699
4930
|
messagingToolSentTargets: [],
|
|
5700
4931
|
messagingToolSourceReplyPayloads: [],
|
|
5701
4932
|
toolMediaUrls: [],
|
|
4933
|
+
toolAutoDeliveryMediaUrls: [],
|
|
4934
|
+
coreTtsToolResults: [],
|
|
5702
4935
|
toolAudioAsVoice: false,
|
|
5703
4936
|
acceptedSessionSpawns: [],
|
|
5704
4937
|
quarantinedTools
|
|
@@ -5912,13 +5145,17 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5912
5145
|
const toolConfirmedSourceReply = params.hookContext?.sourceReplyDeliveryMode === "message_tool_only" && toolName === "message" && !resultIsError && (rawResult.terminate === true || result.terminate === true);
|
|
5913
5146
|
const confirmedSourceReply = params.hookContext?.sourceReplyDeliveryMode === "message_tool_only" && toolName === "message" && (toolConfirmedSourceReply || deliveredSourceReply || receiptConfirmedSourceReply);
|
|
5914
5147
|
const sourceReplyFinal = confirmedSourceReply ? executedArgs.final !== false : void 0;
|
|
5148
|
+
const autoDeliveryTtsMediaUrls = getCoreTtsToolResultMediaUrls(rawResult);
|
|
5915
5149
|
collectToolTelemetry({
|
|
5916
5150
|
toolName,
|
|
5917
5151
|
args: executedArgs,
|
|
5918
5152
|
result,
|
|
5919
5153
|
mediaTrustResult: telemetryRawResult,
|
|
5920
5154
|
telemetry,
|
|
5155
|
+
signal,
|
|
5921
5156
|
isError: resultIsError,
|
|
5157
|
+
autoDeliveryTtsMediaUrls,
|
|
5158
|
+
coreTtsToolResult: autoDeliveryTtsMediaUrls?.length ? rawResult : void 0,
|
|
5922
5159
|
messagingTarget: confirmedMessagingTarget,
|
|
5923
5160
|
sourceReplyFinal
|
|
5924
5161
|
});
|
|
@@ -5950,13 +5187,6 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5950
5187
|
toolCallOrdinal: options?.toolCallOrdinal
|
|
5951
5188
|
});
|
|
5952
5189
|
notifyAgentToolResult(options?.onAgentToolResult, toolName, failedResult, true);
|
|
5953
|
-
collectToolTelemetry({
|
|
5954
|
-
toolName,
|
|
5955
|
-
args: executedArgs,
|
|
5956
|
-
result: void 0,
|
|
5957
|
-
telemetry,
|
|
5958
|
-
isError: true
|
|
5959
|
-
});
|
|
5960
5190
|
runAgentHarnessAfterToolCallHook({
|
|
5961
5191
|
toolName,
|
|
5962
5192
|
toolCallId: call.callId,
|
|
@@ -6281,15 +5511,26 @@ function collectToolTelemetry(params) {
|
|
|
6281
5511
|
const response = normalizeHeartbeatToolResponse(params.result?.details);
|
|
6282
5512
|
if (response) params.telemetry.heartbeatToolResponse = response;
|
|
6283
5513
|
}
|
|
6284
|
-
if (
|
|
5514
|
+
if (params.result && !params.signal.aborted) {
|
|
6285
5515
|
const media = extractToolResultMediaArtifact(params.result);
|
|
6286
5516
|
if (media) {
|
|
6287
5517
|
const mediaUrls = filterToolResultMediaUrls(params.toolName, media.mediaUrls, params.mediaTrustResult ?? params.result);
|
|
6288
5518
|
const seen = new Set(params.telemetry.toolMediaUrls);
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
5519
|
+
const autoDeliveryMediaUrls = new Set(params.telemetry.toolAutoDeliveryMediaUrls);
|
|
5520
|
+
const rawAutoDeliveryMediaUrls = new Set(params.autoDeliveryTtsMediaUrls);
|
|
5521
|
+
let retainsCoreTtsMedia = false;
|
|
5522
|
+
for (const mediaUrl of mediaUrls) {
|
|
5523
|
+
if (!seen.has(mediaUrl)) {
|
|
5524
|
+
seen.add(mediaUrl);
|
|
5525
|
+
params.telemetry.toolMediaUrls.push(mediaUrl);
|
|
5526
|
+
}
|
|
5527
|
+
if (rawAutoDeliveryMediaUrls.has(mediaUrl)) {
|
|
5528
|
+
autoDeliveryMediaUrls.add(mediaUrl);
|
|
5529
|
+
retainsCoreTtsMedia = true;
|
|
5530
|
+
} else autoDeliveryMediaUrls.delete(mediaUrl);
|
|
6292
5531
|
}
|
|
5532
|
+
params.telemetry.toolAutoDeliveryMediaUrls = [...autoDeliveryMediaUrls];
|
|
5533
|
+
if (retainsCoreTtsMedia && params.coreTtsToolResult && !params.telemetry.coreTtsToolResults.includes(params.coreTtsToolResult)) params.telemetry.coreTtsToolResults.push(params.coreTtsToolResult);
|
|
6293
5534
|
if (media.audioAsVoice) params.telemetry.toolAudioAsVoice = true;
|
|
6294
5535
|
}
|
|
6295
5536
|
}
|
|
@@ -6526,4 +5767,4 @@ function isCronAddAction(args) {
|
|
|
6526
5767
|
return typeof action === "string" && action.trim().toLowerCase() === "add";
|
|
6527
5768
|
}
|
|
6528
5769
|
//#endregion
|
|
6529
|
-
export {
|
|
5770
|
+
export { shouldRequireCodexSandboxExecServerEnvironment as C, CodexNativeToolLifecycleProjector as D, readBoundedCodexRemoteWorkspaceFile as E, shouldEnableCodexAppServerNativeToolSurface as S, filterCodexVisionTools as T, resolveCodexAppServerHookChannelId as _, emitDynamicToolStartedDiagnostic as a, resolveCodexNodePlacementToolConstructionPlan as b, resolveCodexProviderWebSearchSupport as c, releaseCodexSandboxExecServerEnvironment as d, buildDynamicTools as f, resolveCodexAppServerExecutionCwd as g, formatCodexDynamicToolBuildStageSummary as h, emitDynamicToolErrorDiagnostic as i, resolveCodexProviderWebSearchSupportForClient as l, disableCodexPluginThreadConfig as m, projectCodexExecutableDynamicTools as n, emitDynamicToolTerminalDiagnostic as o, createCodexDynamicToolBuildStageTracker as p, routeCodexAppServerElicitationRequest as r, handleCodexAppServerApprovalRequest as s, createCodexDynamicToolBridge as t, ensureCodexSandboxExecServerEnvironment as u, resolveCodexExternalSandboxPolicyForOpenClawSandbox as v, shouldWarnCodexDynamicToolBuildStageSummary as w, resolveCodexSandboxEnvironmentSelection as x, resolveCodexMessageToolProvider as y };
|