@openclaw/codex 2026.8.1-beta.3 → 2026.9.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +3 -3
- package/dist/{attempt-client-cleanup-URjUlCHg.js → attempt-client-cleanup-bfsmcQ6m.js} +21 -2
- package/dist/{binding-connection-DAvZwp96.js → binding-connection-BMvPX73o.js} +2 -2
- package/dist/{bounded-turn-4BjrZEwW.js → bounded-turn-B7iBUcuP.js} +8 -8
- package/dist/{capabilities-CH3K57v4.js → capabilities-BRMh0aIq.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-D0nZ3qtd.js → command-formatters-DEsIufkt.js} +2 -2
- package/dist/{command-handlers-DC86lgT4.js → command-handlers-D_-1_qRp.js} +43 -32
- package/dist/{command-rpc-xUIIonsO.js → command-rpc-CCeCkf_v.js} +4 -4
- package/dist/{compact-COqgBRny.js → compact-BglNFZrQ.js} +8 -8
- package/dist/{config-CpNeo5AE.js → config-giW8X0QA.js} +82 -28
- package/dist/doctor-contract-api.js +9 -8
- package/dist/{dynamic-tools-fJZhl4CE.js → dynamic-tools-Dnlfa--w.js} +108 -820
- package/dist/{effective-mcp-catalog-4YKn51aG.js → effective-mcp-catalog-CTeGrnfO.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-Bk1I90Bg.js} +3 -3
- package/dist/{harness-DoKQcF8n.js → harness-Csz0F-DK.js} +11 -11
- package/dist/harness.js +1 -1
- package/dist/index.js +130 -172
- package/dist/{isolated-completion-DPMtlH9r.js → isolated-completion-Cv6FqygM.js} +4 -4
- package/dist/{managed-binary-By4FZC6i.js → managed-binary-DFYK4DWq.js} +43 -7
- package/dist/media-understanding-provider.js +1 -1
- package/dist/{model-catalog-CmGoqVKB.js → model-catalog-i9rNBthX.js} +4 -4
- package/dist/{models-CZw1wClT.js → models-TS3HBU-q.js} +4 -3
- package/dist/{native-subagent-monitor-GGq3RnOo.js → native-subagent-monitor-4Mfq2HDs.js} +176 -19
- package/dist/{node-exec-server.runtime-Bsu1LdFZ.js → node-exec-server.runtime-BpWqJO1V.js} +2 -2
- package/dist/{plugin-app-cache-key-DMNQ8Zi8.js → plugin-app-cache-key-C1CAdfcP.js} +6 -3
- package/dist/{plugin-approval-roundtrip-C75Yiiwc.js → plugin-approval-roundtrip-bUm777tR.js} +1 -1
- package/dist/{plugin-marketplace-discovery-CSWDkMrP.js → plugin-marketplace-discovery-B9DvaAG-.js} +29 -38
- package/dist/{plugin-metadata-cache-BXH5NF-4.js → plugin-metadata-cache-CTCT3w5L.js} +162 -135
- package/dist/{protocol-validators-VAVyEnDp.js → protocol-validators-VeJxxJ0U.js} +25 -3
- package/dist/{rate-limits-BI1dMHDG.js → rate-limits-C5_D8Gmb.js} +1 -1
- package/dist/{request-DSK0W6YI.js → request-DXXGHko0.js} +2 -2
- package/dist/{run-attempt-BV3HzuCf.js → run-attempt-DYc0QCBF.js} +346 -267
- package/dist/{sandbox-guard-C1qEeZ5C.js → sandbox-guard-kuWTn9C5.js} +1 -1
- package/dist/{session-binding-BTrLf9Qm.js → session-binding-Bcynfd-_.js} +1 -1
- package/dist/{session-catalog-ezP_UcRM.js → session-catalog-DaLKVtpH.js} +17 -16
- package/dist/{session-cli-B1hKvfkI.js → session-cli-DMc4oS2w.js} +1 -1
- package/dist/session-permission-policy-BrNH1bjy.js +160 -0
- package/dist/{session-retirement-CE4iMiLh.js → session-retirement-CcNC3YSY.js} +3 -3
- package/dist/{session-upstream-marker-D_2npHlA.js → session-upstream-marker-BIkusb95.js} +1 -1
- package/dist/{settled-turn-finalizer-Dx1onIqg.js → settled-turn-finalizer-Dc3ApjU4.js} +4 -4
- package/dist/{shared-client-Dw-rzii0.js → shared-client-DKz23hHY.js} +1026 -248
- package/dist/{side-question-DbXkJZzg.js → side-question-DjA_jsNe.js} +65 -36
- package/dist/{thread-lifecycle-DKdrnTMX.js → thread-lifecycle-L7oEkTlq.js} +850 -35
- package/dist/{thread-ownership-i2NBwDUL.js → thread-ownership-DZeuKH1j.js} +2 -2
- package/dist/{thread-resume-CdJk2Ehf.js → thread-resume-BE9qNEW0.js} +3 -3
- package/dist/{transcript-mirror-BU0_LKAL.js → transcript-mirror-DsCMWBca.js} +91 -10
- package/dist/{upstream-session-fork-BDVJCLAD.js → upstream-session-fork-DlaHxSLC.js} +3 -3
- package/dist/{usage-9dKJCgcy.js → usage-ROIaW3wo.js} +3 -3
- package/dist/{web-search-provider.runtime-DCdx4DGu.js → web-search-provider.runtime-ClaNPV7N.js} +3 -3
- package/openclaw.plugin.json +18 -1
- package/package.json +8 -8
- package/dist/app-server-policy-bg5QPSVP.js +0 -25
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { h as readCodexPluginConfig, p as isCodexRemoteExecPlacementSandbox } from "./config-
|
|
2
|
-
import {
|
|
3
|
-
import { E as itemStatus, F as readItem, b as auditNativeToolUnfinishedStatus, h as isCodexNotificationForTurn, v as auditNativeToolName, y as auditNativeToolTerminalStatus } from "./attempt-client-cleanup-
|
|
4
|
-
import { l as readCodexTurn } from "./protocol-validators-
|
|
5
|
-
import {
|
|
1
|
+
import { h as readCodexPluginConfig, p as isCodexRemoteExecPlacementSandbox } from "./config-giW8X0QA.js";
|
|
2
|
+
import { K as createCodexElicitationResponse, gt as CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE, p as releaseLeasedSharedCodexAppServerClient, vt as isJsonObject } from "./shared-client-DKz23hHY.js";
|
|
3
|
+
import { E as itemStatus, F as readItem, b as auditNativeToolUnfinishedStatus, h as isCodexNotificationForTurn, v as auditNativeToolName, y as auditNativeToolTerminalStatus } from "./attempt-client-cleanup-bfsmcQ6m.js";
|
|
4
|
+
import { l as readCodexTurn } from "./protocol-validators-VeJxxJ0U.js";
|
|
5
|
+
import { $ as isForcedPrivateQaCodexRuntime, D as withDynamicToolExecutionState, E as createFailedDynamicToolResponse, F as resolveCodexWebSearchPlan, O as withDynamicToolTranscriptDetails, Q as filterCodexDynamicToolsForDisabledNativeSurface, T as resolveCodexToolAbortTerminalReason, Z as filterCodexDynamicTools, d as emitCodexNativePreToolUseFailureDiagnostic, nt as normalizeCodexDynamicToolName, tt as isSystemAgentOnlyCodexDynamicToolAllowlist } from "./thread-lifecycle-L7oEkTlq.js";
|
|
6
6
|
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 resolveCodexNodeExecToolOverrides, i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-
|
|
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-
|
|
7
|
+
import { r as formatCodexDisplayText } from "./command-formatters-DEsIufkt.js";
|
|
8
|
+
import { a as resolveCodexNodeExecToolOverrides, i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-kuWTn9C5.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-bUm777tR.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
22
|
import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
@@ -29,790 +29,11 @@ import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
|
29
29
|
import { redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
|
|
30
30
|
import { isPathStrictlyInside, root } from "openclaw/plugin-sdk/file-access-runtime";
|
|
31
31
|
import { runWithCronCreatorAuthorityCapabilityResolver } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
32
|
-
import { emitTrustedDiagnosticEvent
|
|
32
|
+
import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
33
33
|
import { buildRemoteCommand, isToolAllowed, sanitizeEnvVars } from "openclaw/plugin-sdk/sandbox";
|
|
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";
|
|
37
36
|
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
37
|
//#region extensions/codex/src/app-server/event-projector-native-tool-lifecycle.ts
|
|
817
38
|
/** Projects metadata-only lifecycle diagnostics for native tool items. */
|
|
818
39
|
var CodexNativeToolLifecycleProjector = class {
|
|
@@ -1357,7 +578,7 @@ function createExecAliasDynamicTool(execTool, params) {
|
|
|
1357
578
|
description,
|
|
1358
579
|
parameters: hideExecDynamicToolParameters(execTool.parameters, !nodeAlias || Boolean(pinnedNode), nodeAlias),
|
|
1359
580
|
execute: async (toolCallId, args, signal, onUpdate) => {
|
|
1360
|
-
const result = await execTool.execute(toolCallId, pinExecDynamicToolArgs(args, params
|
|
581
|
+
const result = await execTool.execute(toolCallId, pinExecDynamicToolArgs(args, params, pinnedNode), signal, onUpdate);
|
|
1361
582
|
return {
|
|
1362
583
|
...result,
|
|
1363
584
|
content: result.content.map((item) => item.type === "text" ? Object.assign({}, item, { text: item.text.replace(PROCESS_FOLLOWUP_TEXT, followupText) }) : item)
|
|
@@ -1372,17 +593,18 @@ function createGatewayProcessAliasDynamicTool(processTool) {
|
|
|
1372
593
|
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."
|
|
1373
594
|
};
|
|
1374
595
|
}
|
|
1375
|
-
function pinExecDynamicToolArgs(args,
|
|
596
|
+
function pinExecDynamicToolArgs(args, params, configuredNode) {
|
|
1376
597
|
const { host: _host, security: _security, ask: _ask, node: requestedNode, ...rest } = normalizeExecDynamicToolArgs(args);
|
|
1377
|
-
if (host === "gateway") return {
|
|
598
|
+
if (params.host === "gateway") return {
|
|
1378
599
|
...rest,
|
|
1379
|
-
host
|
|
600
|
+
host: params.host,
|
|
601
|
+
...params.ask ? { ask: params.ask } : {}
|
|
1380
602
|
};
|
|
1381
603
|
const nodeArgs = Object.fromEntries(Object.entries(rest).filter(([name]) => CODEX_NODE_EXEC_PARAMETER_NAMES.has(name)));
|
|
1382
604
|
const node = configuredNode ?? (typeof requestedNode === "string" ? requestedNode.trim() : "");
|
|
1383
605
|
return {
|
|
1384
606
|
...nodeArgs,
|
|
1385
|
-
host,
|
|
607
|
+
host: params.host,
|
|
1386
608
|
...node ? { node } : {}
|
|
1387
609
|
};
|
|
1388
610
|
}
|
|
@@ -1430,10 +652,10 @@ const CODEX_NATIVE_SANDBOX_TOOL_REQUIREMENTS = [
|
|
|
1430
652
|
"apply_patch"
|
|
1431
653
|
];
|
|
1432
654
|
const CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW = /* @__PURE__ */ new Set(["read", "write"]);
|
|
1433
|
-
/** Keeps
|
|
655
|
+
/** Keeps node filesystem and process ownership on its native exec-server. */
|
|
1434
656
|
function resolveCodexNodePlacementToolConstructionPlan(sandbox, nativeToolSurfaceEnabled) {
|
|
1435
657
|
if (!isCodexRemoteExecPlacementSandbox(sandbox) || sandbox?.backendId !== "node" || !("placementNodeId" in sandbox) || typeof sandbox.placementNodeId !== "string" || !sandbox.placementNodeId) return;
|
|
1436
|
-
if (!nativeToolSurfaceEnabled) throw new Error("Codex
|
|
658
|
+
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
659
|
return {
|
|
1438
660
|
includeBaseCodingTools: false,
|
|
1439
661
|
includeShellTools: false,
|
|
@@ -1550,13 +772,14 @@ async function buildDynamicTools(input) {
|
|
|
1550
772
|
...buildEmbeddedAttemptToolRunContext(params),
|
|
1551
773
|
exec: {
|
|
1552
774
|
...params.execOverrides,
|
|
775
|
+
...input.sessionPermissionPolicy ? { mode: input.sessionPermissionPolicy.execMode } : {},
|
|
1553
776
|
...resolveCodexNodeExecToolOverrides(nativeExecutionPolicy),
|
|
1554
777
|
config: params.config,
|
|
1555
778
|
elevated: params.bashElevated
|
|
1556
779
|
},
|
|
1557
|
-
sessionPermissionPolicy:
|
|
1558
|
-
mode:
|
|
1559
|
-
root:
|
|
780
|
+
sessionPermissionPolicy: input.sessionPermissionPolicy ? {
|
|
781
|
+
mode: input.sessionPermissionPolicy.mode,
|
|
782
|
+
root: input.sessionPermissionPolicy.root
|
|
1560
783
|
} : void 0,
|
|
1561
784
|
sandbox: input.sandbox,
|
|
1562
785
|
...toolConstructionPlan ? { toolConstructionPlan } : {},
|
|
@@ -1595,6 +818,7 @@ async function buildDynamicTools(input) {
|
|
|
1595
818
|
resolvedWorkspace: input.resolvedWorkspace
|
|
1596
819
|
}),
|
|
1597
820
|
config: params.config,
|
|
821
|
+
githubPublicationAvailable: params.githubPublicationAvailable,
|
|
1598
822
|
authProfileStore: params.toolAuthProfileStore ?? params.authProfileStore,
|
|
1599
823
|
abortSignal: input.runAbortController.signal,
|
|
1600
824
|
emitBeforeToolCallDiagnostics: false,
|
|
@@ -1761,7 +985,8 @@ function addGatewayShellDynamicToolsIfAvailable(filteredTools, allTools, input,
|
|
|
1761
985
|
const processAliasAvailable = Boolean(processTool && !processExcluded && !existingNames.has("gateway_process"));
|
|
1762
986
|
const toolsToAppend = [createExecAliasDynamicTool(execTool, {
|
|
1763
987
|
host: "gateway",
|
|
1764
|
-
processAliasAvailable
|
|
988
|
+
processAliasAvailable,
|
|
989
|
+
...input.sessionPermissionPolicy?.mode === "guarded" ? { ask: "always" } : {}
|
|
1765
990
|
})];
|
|
1766
991
|
if (processAliasAvailable && processTool) toolsToAppend.push(createGatewayProcessAliasDynamicTool(processTool));
|
|
1767
992
|
return [...filteredTools, ...toolsToAppend];
|
|
@@ -1986,7 +1211,7 @@ const nodeExecServerTextDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
|
1986
1211
|
/** Produces the bounded, redacted terminal failure shared by pending and claimed node leases. */
|
|
1987
1212
|
function createCodexNodeExecServerDisconnectError(reason, cause) {
|
|
1988
1213
|
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
|
|
1214
|
+
return /* @__PURE__ */ new Error(`Codex execution node disconnected; start a fresh attempt. (${reason}${detail})`);
|
|
1990
1215
|
}
|
|
1991
1216
|
/** Relays one authorized, single-use Codex exec-server channel without interpreting its protocol. */
|
|
1992
1217
|
async function startCodexNodeExecServerRelay(params) {
|
|
@@ -2013,7 +1238,7 @@ async function startCodexNodeExecServerRelay(params) {
|
|
|
2013
1238
|
if (!closed && !params.lease.closed) params.lease.onDisconnected?.(createCodexNodeExecServerDisconnectError(reason, cause));
|
|
2014
1239
|
closeBoth(code, reason);
|
|
2015
1240
|
};
|
|
2016
|
-
params.lease.onChannelClosed = ({ failed, error }) => failUnexpectedly(failed ? 1011 : 1001, failed ? "execution
|
|
1241
|
+
params.lease.onChannelClosed = ({ failed, error }) => failUnexpectedly(failed ? 1011 : 1001, failed ? "execution node failed" : "execution node disconnected", error);
|
|
2017
1242
|
socket.once("close", () => failUnexpectedly(1001, "execution socket closed"));
|
|
2018
1243
|
socket.once("error", () => failUnexpectedly(1011, "execution socket failed"));
|
|
2019
1244
|
let toNode = Promise.resolve();
|
|
@@ -2217,7 +1442,7 @@ function createCredentialedCodexNodeHttpRejection(request) {
|
|
|
2217
1442
|
id: request.id,
|
|
2218
1443
|
error: {
|
|
2219
1444
|
code: -32602,
|
|
2220
|
-
message: "Authenticated remote HTTP is unavailable on
|
|
1445
|
+
message: "Authenticated remote HTTP is unavailable on execution nodes; run on Gateway or use an intentionally credential-free endpoint."
|
|
2221
1446
|
}
|
|
2222
1447
|
}));
|
|
2223
1448
|
}
|
|
@@ -3012,6 +2237,8 @@ async function httpRequest(execServer, notifications, params) {
|
|
|
3012
2237
|
const record = requireObject(params, "http/request params");
|
|
3013
2238
|
const requestId = requireString(record.requestId, "requestId");
|
|
3014
2239
|
const url = requireString(record.url, "url");
|
|
2240
|
+
const redirectPolicy = record.redirectPolicy ?? "follow";
|
|
2241
|
+
if (redirectPolicy !== "follow" && redirectPolicy !== "stop") throw new Error("http/request redirectPolicy must be follow or stop");
|
|
3015
2242
|
assertSandboxHttpRequestTargetAllowed(url);
|
|
3016
2243
|
const request = {
|
|
3017
2244
|
method: requireString(record.method, "method"),
|
|
@@ -3019,6 +2246,7 @@ async function httpRequest(execServer, notifications, params) {
|
|
|
3019
2246
|
headers: readHttpHeaders(record.headers),
|
|
3020
2247
|
bodyBase64: typeof record.bodyBase64 === "string" ? record.bodyBase64 : void 0,
|
|
3021
2248
|
timeoutMs: typeof record.timeoutMs === "number" && record.timeoutMs > 0 ? Math.floor(record.timeoutMs) : void 0,
|
|
2249
|
+
redirectPolicy,
|
|
3022
2250
|
streamResponse: record.streamResponse === true
|
|
3023
2251
|
};
|
|
3024
2252
|
if (request.streamResponse) return await runStreamingSandboxHttpRequest(execServer, notifications, requestId, request);
|
|
@@ -3315,9 +2543,40 @@ def assert_url_allowed(url):
|
|
|
3315
2543
|
PINNED_ADDRESSES[hostname] = sorted(addresses)
|
|
3316
2544
|
|
|
3317
2545
|
class GuardedRedirectHandler(urllib.request.HTTPRedirectHandler):
|
|
2546
|
+
def __init__(self, redirect_policy):
|
|
2547
|
+
self.redirect_policy = redirect_policy
|
|
2548
|
+
|
|
3318
2549
|
def redirect_request(self, req, fp, code, msg, headers, newurl):
|
|
2550
|
+
if self.redirect_policy == "stop":
|
|
2551
|
+
return None
|
|
3319
2552
|
assert_url_allowed(newurl)
|
|
3320
|
-
|
|
2553
|
+
method = req.get_method()
|
|
2554
|
+
drop_body = code == 303 or (code in (301, 302) and method == "POST")
|
|
2555
|
+
next_headers = dict(req.headers)
|
|
2556
|
+
if drop_body:
|
|
2557
|
+
if method != "HEAD":
|
|
2558
|
+
method = "GET"
|
|
2559
|
+
for name in ("content-type", "content-length", "content-encoding", "transfer-encoding"):
|
|
2560
|
+
next_headers.pop(name.capitalize(), None)
|
|
2561
|
+
redirected = urllib.request.Request(
|
|
2562
|
+
newurl,
|
|
2563
|
+
data=None if drop_body else req.data,
|
|
2564
|
+
headers=next_headers,
|
|
2565
|
+
method=method,
|
|
2566
|
+
origin_req_host=req.origin_req_host,
|
|
2567
|
+
unverifiable=True,
|
|
2568
|
+
)
|
|
2569
|
+
previous = urllib.parse.urlsplit(req.full_url)
|
|
2570
|
+
target = urllib.parse.urlsplit(newurl)
|
|
2571
|
+
previous_port = previous.port or (443 if previous.scheme == "https" else 80)
|
|
2572
|
+
target_port = target.port or (443 if target.scheme == "https" else 80)
|
|
2573
|
+
if (previous.scheme, previous.hostname, previous_port) != (
|
|
2574
|
+
target.scheme, target.hostname, target_port
|
|
2575
|
+
):
|
|
2576
|
+
# Match Codex's route-aware client: cross-origin hops never inherit secrets.
|
|
2577
|
+
for name in ("authorization", "cookie", "proxy-authorization", "www-authenticate", "cookie2"):
|
|
2578
|
+
redirected.remove_header(name.capitalize())
|
|
2579
|
+
return redirected
|
|
3321
2580
|
|
|
3322
2581
|
def pinned_getaddrinfo(original_getaddrinfo):
|
|
3323
2582
|
def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
|
|
@@ -3373,7 +2632,8 @@ def main():
|
|
|
3373
2632
|
timeout = None
|
|
3374
2633
|
if isinstance(timeout_ms, (int, float)) and timeout_ms > 0:
|
|
3375
2634
|
timeout = timeout_ms / 1000
|
|
3376
|
-
|
|
2635
|
+
redirect_handler = GuardedRedirectHandler(input_data.get("redirectPolicy", "follow"))
|
|
2636
|
+
opener = urllib.request.build_opener(urllib.request.ProxyHandler({}), redirect_handler)
|
|
3377
2637
|
original_getaddrinfo = socket.getaddrinfo
|
|
3378
2638
|
socket.getaddrinfo = pinned_getaddrinfo(original_getaddrinfo)
|
|
3379
2639
|
try:
|
|
@@ -3406,6 +2666,7 @@ async function startProcess(execServer, processes, notify, params) {
|
|
|
3406
2666
|
const argv = requireStringArray(record.argv, "argv");
|
|
3407
2667
|
const cwd = resolveExecServerPath(requireString(record.cwd, "cwd"), "process cwd");
|
|
3408
2668
|
rejectUnsupportedArg0(record.arg0);
|
|
2669
|
+
assertSupportedProcessSandbox(execServer, record);
|
|
3409
2670
|
const env = readProcessEnv(record);
|
|
3410
2671
|
const managed = {
|
|
3411
2672
|
processId,
|
|
@@ -3450,7 +2711,18 @@ async function startProcess(execServer, processes, notify, params) {
|
|
|
3450
2711
|
} finally {
|
|
3451
2712
|
if (managed.startPromise === startPromise) managed.startPromise = void 0;
|
|
3452
2713
|
}
|
|
3453
|
-
return {
|
|
2714
|
+
return {
|
|
2715
|
+
processId,
|
|
2716
|
+
sandboxType: "none"
|
|
2717
|
+
};
|
|
2718
|
+
}
|
|
2719
|
+
function assertSupportedProcessSandbox(execServer, record) {
|
|
2720
|
+
if (record.networkProxy !== void 0 && record.networkProxy !== null) throw new Error("Codex sandbox exec-server network proxy launch is not supported.");
|
|
2721
|
+
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.");
|
|
2722
|
+
if (resolveFsSandboxPolicy(execServer, record)?.unrestricted === false) throw new Error("Codex process filesystem sandbox restrictions cannot be enforced by the backend.");
|
|
2723
|
+
if (record.sandbox === void 0 || record.sandbox === null) return;
|
|
2724
|
+
if (requireObject(requireObject(record.sandbox, "process sandbox context").permissions, "process sandbox permissions").network !== "restricted") return;
|
|
2725
|
+
if (!execServer.networkIsolated) throw new Error("Codex network restrictions cannot be enforced by the sandbox backend.");
|
|
3454
2726
|
}
|
|
3455
2727
|
async function runProcess(execServer, managed, params) {
|
|
3456
2728
|
const backend = execServer.backend;
|
|
@@ -3767,7 +3039,7 @@ async function ensureCodexSandboxExecServerEnvironment(params) {
|
|
|
3767
3039
|
if (!params.sandbox?.enabled) return;
|
|
3768
3040
|
const placementNodeId = readCodexPlacementNodeId(params.sandbox);
|
|
3769
3041
|
if (!params.sandbox.backend && !placementNodeId) return;
|
|
3770
|
-
if (placementNodeId && !params.runtime) throw new Error("Codex
|
|
3042
|
+
if (placementNodeId && !params.runtime) throw new Error("Codex node execution requires its active plugin runtime.");
|
|
3771
3043
|
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
3044
|
const { server: execServer, nodeLease } = await acquireOpenClawExecServer({
|
|
3773
3045
|
sandbox: params.sandbox,
|
|
@@ -3833,7 +3105,7 @@ async function acquireOpenClawExecServer(params) {
|
|
|
3833
3105
|
if (!("node" in server)) return { server };
|
|
3834
3106
|
if (!runtime || !signal) {
|
|
3835
3107
|
await releaseOpenClawExecServer(server);
|
|
3836
|
-
throw new Error("Codex
|
|
3108
|
+
throw new Error("Codex node execution requires an active runtime and attempt.");
|
|
3837
3109
|
}
|
|
3838
3110
|
try {
|
|
3839
3111
|
const placementIdentity = readCodexPlacementWorkspaceIdentity(sandbox);
|
|
@@ -3852,7 +3124,7 @@ async function acquireOpenClawExecServer(params) {
|
|
|
3852
3124
|
});
|
|
3853
3125
|
if (signal.aborted || server.closed || sandboxExecServerRegistry.servers.get(key) !== promise) {
|
|
3854
3126
|
channel.close();
|
|
3855
|
-
throw new Error("Codex
|
|
3127
|
+
throw new Error("Codex node execution retired before its channel was ready.");
|
|
3856
3128
|
}
|
|
3857
3129
|
const nodeLease = {
|
|
3858
3130
|
id: randomUUID(),
|
|
@@ -3936,7 +3208,8 @@ async function startOpenClawExecServer(sandbox) {
|
|
|
3936
3208
|
} : {
|
|
3937
3209
|
...common,
|
|
3938
3210
|
backend: connection.backend,
|
|
3939
|
-
fsBridge: connection.fsBridge
|
|
3211
|
+
fsBridge: connection.fsBridge,
|
|
3212
|
+
networkIsolated: (connection.backend.id === "docker" || connection.backend.id === "podman") && sandbox.docker.network.trim().toLowerCase() === "none"
|
|
3940
3213
|
};
|
|
3941
3214
|
server.on("connection", (socket, request) => {
|
|
3942
3215
|
socket.on("error", handleExecServerSocketError);
|
|
@@ -3977,7 +3250,7 @@ function readCodexPlacementNodeId(sandbox) {
|
|
|
3977
3250
|
return sandbox.placementNodeId;
|
|
3978
3251
|
}
|
|
3979
3252
|
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
|
|
3253
|
+
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
3254
|
return {
|
|
3982
3255
|
environmentId: sandbox.placementEnvironmentId,
|
|
3983
3256
|
sessionId: sandbox.placementSessionId,
|
|
@@ -4018,7 +3291,7 @@ function handleClosedCodexNodeExecServerLease(execServer, lease, result) {
|
|
|
4018
3291
|
return;
|
|
4019
3292
|
}
|
|
4020
3293
|
try {
|
|
4021
|
-
lease.onDisconnected?.(createCodexNodeExecServerDisconnectError(result.failed ? "execution
|
|
3294
|
+
lease.onDisconnected?.(createCodexNodeExecServerDisconnectError(result.failed ? "execution node failed" : "execution node disconnected", result.error));
|
|
4022
3295
|
} finally {
|
|
4023
3296
|
closeCodexNodeExecServerLease(execServer, lease);
|
|
4024
3297
|
}
|
|
@@ -4156,7 +3429,7 @@ async function handleCodexAppServerApprovalRequest(params) {
|
|
|
4156
3429
|
return buildApprovalResponse(params.method, context.requestParams, resolvedOutcome);
|
|
4157
3430
|
};
|
|
4158
3431
|
try {
|
|
4159
|
-
if (params.method === "item/commandExecution/requestApproval") {
|
|
3432
|
+
if (params.method === "item/commandExecution/requestApproval" && !readNetworkApprovalContext(requestParams)) {
|
|
4160
3433
|
const command = readPolicyCommand(requestParams);
|
|
4161
3434
|
const cwd = readStringField(requestParams, "cwd") ?? params.paramsForRun.workspaceDir;
|
|
4162
3435
|
const prepareMutableFileApproval = params.paramsForRun.hostCapabilities.prepareMutableFileApproval;
|
|
@@ -4183,7 +3456,7 @@ async function handleCodexAppServerApprovalRequest(params) {
|
|
|
4183
3456
|
return await resolvePolicyApproval("denied", policyOutcome.reason);
|
|
4184
3457
|
}
|
|
4185
3458
|
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.");
|
|
3459
|
+
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
3460
|
const requestResult = await requestPluginApproval({
|
|
4188
3461
|
hostCapabilities: params.paramsForRun.hostCapabilities,
|
|
4189
3462
|
title: context.title,
|
|
@@ -4299,18 +3572,19 @@ function buildApprovalContext(params) {
|
|
|
4299
3572
|
const reasonPreview = sanitizeApprovalPreview(readStringPreview(params.requestParams, "reason"), 180);
|
|
4300
3573
|
const command = commandPreview.text;
|
|
4301
3574
|
const reason = reasonPreview.text;
|
|
3575
|
+
const networkApproval = params.method === "item/commandExecution/requestApproval" ? readNetworkApprovalContext(params.requestParams) : void 0;
|
|
4302
3576
|
const approvalKind = params.method.includes("commandExecution") ? "command" : params.method.includes("fileChange") ? "file-change" : params.method.includes("permissions") ? "permissions" : "other";
|
|
4303
3577
|
const kind = approvalKind === "command" ? "exec" : approvalKind === "other" ? "unknown" : "plugin";
|
|
4304
3578
|
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}`);
|
|
3579
|
+
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";
|
|
3580
|
+
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
3581
|
return {
|
|
4308
3582
|
approvalKind,
|
|
4309
3583
|
kind,
|
|
4310
3584
|
title,
|
|
4311
3585
|
description: permissionLines.length > 0 ? joinDescriptionLinesWithinLimit(permissionLines, PERMISSION_DESCRIPTION_MAX_LENGTH) : [subject, ...commandDetailLines].join("\n"),
|
|
4312
3586
|
severity: kind === "exec" ? "warning" : "info",
|
|
4313
|
-
toolName: kind === "exec" ? "codex_command_approval" : params.method === "item/permissions/requestApproval" ? "codex_permission_approval" : "codex_file_approval",
|
|
3587
|
+
toolName: networkApproval ? "codex_network_approval" : kind === "exec" ? "codex_command_approval" : params.method === "item/permissions/requestApproval" ? "codex_permission_approval" : "codex_file_approval",
|
|
4314
3588
|
itemId,
|
|
4315
3589
|
approvalId,
|
|
4316
3590
|
requestParams: params.requestParams,
|
|
@@ -4482,6 +3756,10 @@ function sanitizeRelayDecisionReason(value) {
|
|
|
4482
3756
|
}
|
|
4483
3757
|
function buildOpenClawToolPolicyRequest(method, requestParams) {
|
|
4484
3758
|
if (method === "item/commandExecution/requestApproval") {
|
|
3759
|
+
if (readNetworkApprovalContext(requestParams)) return {
|
|
3760
|
+
toolName: "codex_network_approval",
|
|
3761
|
+
params: { approval: requestParams ?? {} }
|
|
3762
|
+
};
|
|
4485
3763
|
const command = readPolicyCommand(requestParams);
|
|
4486
3764
|
return {
|
|
4487
3765
|
toolName: "exec",
|
|
@@ -4769,6 +4047,15 @@ function readPolicyCommand(record) {
|
|
|
4769
4047
|
const actionCommands = readCommandActions(record);
|
|
4770
4048
|
if (actionCommands.length > 0) return actionCommands.join(" && ");
|
|
4771
4049
|
}
|
|
4050
|
+
function readNetworkApprovalContext(record) {
|
|
4051
|
+
const context = isJsonObject(record?.networkApprovalContext) ? record.networkApprovalContext : void 0;
|
|
4052
|
+
const host = readStringField(context, "host");
|
|
4053
|
+
const protocol = readStringField(context, "protocol");
|
|
4054
|
+
return host && protocol ? {
|
|
4055
|
+
host,
|
|
4056
|
+
protocol
|
|
4057
|
+
} : void 0;
|
|
4058
|
+
}
|
|
4772
4059
|
function readCommandActions(record) {
|
|
4773
4060
|
const actions = record?.commandActions;
|
|
4774
4061
|
if (!Array.isArray(actions)) return [];
|
|
@@ -4958,6 +4245,7 @@ async function routeCodexAppServerElicitationRequest(params) {
|
|
|
4958
4245
|
if (!requestParams || readNonBlankStringField(requestParams, "threadId") !== params.threadId) return { kind: "not-mine" };
|
|
4959
4246
|
const requestTurnId = requestParams.turnId;
|
|
4960
4247
|
if (requestTurnId !== null && requestTurnId !== void 0 && requestTurnId !== params.turnId) return { kind: "not-mine" };
|
|
4248
|
+
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" };
|
|
4961
4249
|
const pluginResolution = resolvePluginElicitation({
|
|
4962
4250
|
requestParams,
|
|
4963
4251
|
pluginAppPolicyContext: params.pluginAppPolicyContext
|
|
@@ -4983,7 +4271,7 @@ async function routeCodexAppServerElicitationRequest(params) {
|
|
|
4983
4271
|
}));
|
|
4984
4272
|
}
|
|
4985
4273
|
const approvalPrompt = readComputerUseApprovalElicitation(requestParams, params.computerUseMcpServerName) ?? readBridgeableApprovalElicitation(requestParams);
|
|
4986
|
-
if (!approvalPrompt) return
|
|
4274
|
+
if (!approvalPrompt) return handled(createCodexElicitationResponse("decline"));
|
|
4987
4275
|
return handled(buildElicitationResponse(approvalPrompt, await requestPluginApprovalOutcome({
|
|
4988
4276
|
paramsForRun: params.paramsForRun,
|
|
4989
4277
|
title: approvalPrompt.title,
|
|
@@ -6526,4 +5814,4 @@ function isCronAddAction(args) {
|
|
|
6526
5814
|
return typeof action === "string" && action.trim().toLowerCase() === "add";
|
|
6527
5815
|
}
|
|
6528
5816
|
//#endregion
|
|
6529
|
-
export {
|
|
5817
|
+
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 };
|