@openclaw/codex 2026.8.1-beta.3 → 2026.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/api.js +4 -5
  2. package/dist/{attempt-client-cleanup-URjUlCHg.js → attempt-client-cleanup-CVPvp9dL.js} +47 -5
  3. package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
  4. package/dist/{binding-connection-DAvZwp96.js → binding-connection-CCQFs8lf.js} +2 -2
  5. package/dist/{bounded-turn-4BjrZEwW.js → bounded-turn-rq5tiSXk.js} +13 -18
  6. package/dist/{capabilities-CH3K57v4.js → capabilities-CGm_94eL.js} +1 -1
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-D0nZ3qtd.js → command-formatters-C54Yg3eA.js} +2 -2
  9. package/dist/{command-handlers-DC86lgT4.js → command-handlers-BvOAHTrA.js} +89 -62
  10. package/dist/{compact-COqgBRny.js → compact-Hd7SAc0N.js} +8 -9
  11. package/dist/{config-CpNeo5AE.js → config-Cxw3Cl3k.js} +346 -286
  12. package/dist/doctor-contract-api.js +115 -14
  13. package/dist/{dynamic-tools-fJZhl4CE.js → dynamic-tools-BFoUcRdx.js} +147 -903
  14. package/dist/{effective-mcp-catalog-4YKn51aG.js → effective-mcp-catalog-BTJHnDSx.js} +2 -2
  15. package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
  16. package/dist/{event-projector-usage-CLwNEJqW.js → event-projector-usage-D3PHFFXh.js} +3 -3
  17. package/dist/{harness-DoKQcF8n.js → harness-DVfUQBlQ.js} +42 -52
  18. package/dist/harness.js +1 -1
  19. package/dist/index.js +278 -295
  20. package/dist/{isolated-completion-DPMtlH9r.js → isolated-completion-Cbbx_5Ed.js} +4 -4
  21. package/dist/launch-args-sXOAg0SX.js +84 -0
  22. package/dist/{managed-binary-By4FZC6i.js → managed-binary-ZkGodW19.js} +43 -7
  23. package/dist/media-understanding-provider.js +1 -1
  24. package/dist/model-catalog-o6Cgjoss.js +101 -0
  25. package/dist/{models-CZw1wClT.js → models-DgFWSuxA.js} +25 -28
  26. package/dist/{native-subagent-monitor-GGq3RnOo.js → native-subagent-monitor-CwFyoylz.js} +207 -30
  27. package/dist/{node-exec-server.runtime-Bsu1LdFZ.js → node-exec-server.runtime-DXrqpw1c.js} +8 -5
  28. package/dist/{plugin-approval-roundtrip-C75Yiiwc.js → plugin-approval-roundtrip-D80UZiJ_.js} +1 -1
  29. package/dist/{plugin-marketplace-discovery-CSWDkMrP.js → plugin-marketplace-discovery-mdmScYOj.js} +30 -39
  30. package/dist/{plugin-metadata-cache-BXH5NF-4.js → plugin-metadata-cache-CulOABwu.js} +162 -135
  31. package/dist/{protocol-validators-VAVyEnDp.js → protocol-validators-Bg5rpNxk.js} +148 -5
  32. package/dist/{rate-limits-BI1dMHDG.js → rate-limits-hFtzt2Up.js} +1 -1
  33. package/dist/{sandbox-guard-C1qEeZ5C.js → request-CCm4LaED.js} +183 -2
  34. package/dist/{run-attempt-BV3HzuCf.js → run-attempt-BwNQDH2u.js} +599 -361
  35. package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-DeBvleJw.js} +1 -1
  36. package/dist/{session-binding-BTrLf9Qm.js → session-binding-q2WSTVmC.js} +195 -122
  37. package/dist/{session-catalog-ezP_UcRM.js → session-catalog-C2Tae4rI.js} +229 -122
  38. package/dist/session-catalog-home-id-DAKUrm3C.js +112 -0
  39. package/dist/{session-cli-B1hKvfkI.js → session-cli-BuDjm5Ou.js} +1 -1
  40. package/dist/session-permission-policy-gLm40Vtq.js +160 -0
  41. package/dist/session-retirement-CdkI0bvb.js +90 -0
  42. package/dist/{session-upstream-marker-D_2npHlA.js → session-upstream-marker-Bcy33kam.js} +2 -3
  43. package/dist/{settled-turn-finalizer-Dx1onIqg.js → settled-turn-finalizer-B8JJcxCi.js} +7 -6
  44. package/dist/{shared-client-Dw-rzii0.js → shared-client-kNkljY-R.js} +1720 -786
  45. package/dist/{side-question-DbXkJZzg.js → side-question-GwD73tX6.js} +69 -39
  46. package/dist/{thread-lifecycle-DKdrnTMX.js → thread-lifecycle-Ss-uwnC4.js} +852 -359
  47. package/dist/{thread-ownership-i2NBwDUL.js → thread-ownership-CeYBqg_4.js} +18 -8
  48. package/dist/{plugin-app-cache-key-DMNQ8Zi8.js → thread-resume-DF54hagX.js} +52 -6
  49. package/dist/{transcript-mirror-BU0_LKAL.js → transcript-mirror-CkEQIna-.js} +112 -13
  50. package/dist/transport-stdio-C7-s9TLG.js +708 -0
  51. package/dist/{upstream-session-fork-BDVJCLAD.js → upstream-session-fork-BACGlOFa.js} +78 -86
  52. package/dist/{usage-9dKJCgcy.js → usage-C2l8Mils.js} +3 -3
  53. package/dist/{web-search-provider.runtime-DCdx4DGu.js → web-search-provider.runtime-B2XgRdFv.js} +3 -3
  54. package/openclaw.plugin.json +19 -1
  55. package/package.json +8 -8
  56. package/dist/app-server-policy-bg5QPSVP.js +0 -25
  57. package/dist/command-rpc-xUIIonsO.js +0 -90
  58. package/dist/incognito-session-ET_ufDH-.js +0 -2
  59. package/dist/model-catalog-CmGoqVKB.js +0 -48
  60. package/dist/request-DSK0W6YI.js +0 -157
  61. package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
  62. package/dist/session-retirement-CE4iMiLh.js +0 -36
  63. package/dist/thread-resume-CdJk2Ehf.js +0 -30
  64. package/dist/transport-stdio-DhoGy33Z.js +0 -99
@@ -1,818 +1,39 @@
1
- import { h as readCodexPluginConfig, p as isCodexRemoteExecPlacementSandbox } from "./config-CpNeo5AE.js";
2
- import { V as createCodexElicitationResponse, ct as CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE, l as releaseLeasedSharedCodexAppServerClient, ut as isJsonObject } from "./shared-client-Dw-rzii0.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-URjUlCHg.js";
4
- import { l as readCodexTurn } from "./protocol-validators-VAVyEnDp.js";
5
- import { A as isForcedPrivateQaCodexRuntime, M as isSystemAgentOnlyCodexDynamicToolAllowlist, N as normalizeCodexDynamicToolName, O as filterCodexDynamicTools, f as resolveCodexWebSearchPlan, k as filterCodexDynamicToolsForDisabledNativeSurface } from "./thread-lifecycle-DKdrnTMX.js";
1
+ import { C as isCodexRemoteExecPlacementSandbox, T as readCodexPluginConfig } from "./config-Cxw3Cl3k.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-kNkljY-R.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-CVPvp9dL.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-Ss-uwnC4.js";
6
+ import { l as resolveCodexNativeExecutionPolicy, u as resolveCodexNodeExecToolOverrides } from "./request-CCm4LaED.js";
6
7
  import { r as sanitizeInlineImageDataUrl, t as invalidInlineImageText } from "./image-payload-sanitizer-CnfoUPCE.js";
7
- import { r as formatCodexDisplayText } from "./command-formatters-D0nZ3qtd.js";
8
- import { a as resolveCodexNodeExecToolOverrides, i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-C1qEeZ5C.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-C75Yiiwc.js";
8
+ import { r as formatCodexDisplayText } from "./command-formatters-C54Yg3eA.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-D80UZiJ_.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 { addTimerTimeoutGraceMs, asDateTimestampMs, finiteSecondsToTimerSafeMilliseconds, parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
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 { once } from "node:events";
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";
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 {
@@ -1326,83 +547,47 @@ const dynamicToolBuildState = {};
1326
547
  const CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME = "node_exec";
1327
548
  const CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME = "gateway_exec";
1328
549
  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
550
  const PROCESS_FOLLOWUP_TEXT = "Use process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.";
1342
551
  /** Returns true when plugin config explicitly removes any named dynamic tool. */
1343
552
  function isCodexDynamicToolExcluded(config, names) {
1344
553
  const normalizedNames = new Set(names.map((name) => normalizeCodexDynamicToolName(name)));
1345
554
  return (config.codexDynamicToolsExclude ?? []).some((name) => normalizedNames.has(normalizeCodexDynamicToolName(name)));
1346
555
  }
1347
- function createExecAliasDynamicTool(execTool, params) {
1348
- const pinnedNode = params.host === "node" ? params.node?.trim() : void 0;
1349
- const nodeAlias = params.host === "node";
1350
- const gatewayProcessAliasAvailable = params.host === "gateway" && params.processAliasAvailable;
1351
- const name = nodeAlias ? CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME : CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME;
1352
- const description = nodeAlias ? 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." : "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.";
1353
- const followupText = nodeAlias ? "Remote-node background follow-up is unavailable. Wait for the command to complete." : gatewayProcessAliasAvailable ? "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.";
1354
- return {
1355
- ...execTool,
1356
- name,
1357
- description,
1358
- parameters: hideExecDynamicToolParameters(execTool.parameters, !nodeAlias || Boolean(pinnedNode), nodeAlias),
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
- }
556
+ function createNodeExecAliasDynamicTool(execTool, node) {
557
+ const pinnedNode = node?.trim();
558
+ const pinnedTool = pinExecToolTarget(execTool, {
559
+ host: "node",
560
+ ...pinnedNode ? { node: pinnedNode } : {}
561
+ });
562
+ const execute = async (toolCallId, args, signal, onUpdate) => {
563
+ const result = await pinnedTool.execute(toolCallId, args, signal, onUpdate);
564
+ return {
565
+ ...result,
566
+ 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)
567
+ };
1366
568
  };
1367
- }
1368
- function createGatewayProcessAliasDynamicTool(processTool) {
1369
569
  return {
1370
- ...processTool,
1371
- name: CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME,
1372
- 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."
570
+ ...pinnedTool,
571
+ name: CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME,
572
+ 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.",
573
+ execute
1373
574
  };
1374
575
  }
1375
- function pinExecDynamicToolArgs(args, host, configuredNode) {
1376
- const { host: _host, security: _security, ask: _ask, node: requestedNode, ...rest } = normalizeExecDynamicToolArgs(args);
1377
- if (host === "gateway") return {
1378
- ...rest,
1379
- host
1380
- };
1381
- const nodeArgs = Object.fromEntries(Object.entries(rest).filter(([name]) => CODEX_NODE_EXEC_PARAMETER_NAMES.has(name)));
1382
- const node = configuredNode ?? (typeof requestedNode === "string" ? requestedNode.trim() : "");
1383
- return {
1384
- ...nodeArgs,
1385
- host,
1386
- ...node ? { node } : {}
1387
- };
576
+ function createGatewayExecProjection(createProjection, execTool, params) {
577
+ return createProjection(execTool, {
578
+ kind: "exec",
579
+ name: CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME,
580
+ 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.",
581
+ 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.",
582
+ ...params.ask ? { ask: params.ask } : {}
583
+ });
1388
584
  }
1389
- function normalizeExecDynamicToolArgs(args) {
1390
- return args && typeof args === "object" && !Array.isArray(args) ? args : {};
1391
- }
1392
- function hideExecDynamicToolParameters(parameters, hideNode, nodeOnly) {
1393
- if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) return parameters;
1394
- const schema = parameters;
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
- };
585
+ function createGatewayProcessProjection(createProjection, processTool) {
586
+ return createProjection(processTool, {
587
+ kind: "process",
588
+ name: CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME,
589
+ 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."
590
+ });
1406
591
  }
1407
592
  //#endregion
1408
593
  //#region extensions/codex/src/app-server/vision-tools.ts
@@ -1430,10 +615,10 @@ const CODEX_NATIVE_SANDBOX_TOOL_REQUIREMENTS = [
1430
615
  "apply_patch"
1431
616
  ];
1432
617
  const CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW = /* @__PURE__ */ new Set(["read", "write"]);
1433
- /** Keeps paired-device filesystem and process ownership on its native exec-server. */
618
+ /** Keeps node filesystem and process ownership on its native exec-server. */
1434
619
  function resolveCodexNodePlacementToolConstructionPlan(sandbox, nativeToolSurfaceEnabled) {
1435
620
  if (!isCodexRemoteExecPlacementSandbox(sandbox) || sandbox?.backendId !== "node" || !("placementNodeId" in sandbox) || typeof sandbox.placementNodeId !== "string" || !sandbox.placementNodeId) return;
1436
- if (!nativeToolSurfaceEnabled) throw new Error("Codex paired-device remote execution requires its native exec-server tool surface; adjust the session tool policy and start a fresh attempt.");
621
+ 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
622
  return {
1438
623
  includeBaseCodingTools: false,
1439
624
  includeShellTools: false,
@@ -1518,6 +703,10 @@ async function buildDynamicTools(input) {
1518
703
  ...params,
1519
704
  disableMessageTool: false
1520
705
  } : params;
706
+ const toolRunContext = buildEmbeddedAttemptToolRunContext({
707
+ ...params,
708
+ forceMessageTool: shouldForceMessageTool(messagePolicyParams)
709
+ });
1521
710
  if (params.disableTools) {
1522
711
  input.onWebSearchPolicyResolved?.(false);
1523
712
  return [];
@@ -1547,16 +736,17 @@ async function buildDynamicTools(input) {
1547
736
  const toolConstructionPlan = resolveCodexNodePlacementToolConstructionPlan(input.sandbox, input.nativeToolSurfaceEnabled);
1548
737
  const options = {
1549
738
  agentId: input.sessionAgentId,
1550
- ...buildEmbeddedAttemptToolRunContext(params),
739
+ ...toolRunContext,
1551
740
  exec: {
1552
741
  ...params.execOverrides,
742
+ ...input.sessionPermissionPolicy ? { mode: input.sessionPermissionPolicy.execMode } : {},
1553
743
  ...resolveCodexNodeExecToolOverrides(nativeExecutionPolicy),
1554
744
  config: params.config,
1555
745
  elevated: params.bashElevated
1556
746
  },
1557
- sessionPermissionPolicy: params.permissionMode && params.sessionRoot ? {
1558
- mode: params.permissionMode,
1559
- root: params.sessionRoot
747
+ sessionPermissionPolicy: input.sessionPermissionPolicy ? {
748
+ mode: input.sessionPermissionPolicy.mode,
749
+ root: input.sessionPermissionPolicy.root
1560
750
  } : void 0,
1561
751
  sandbox: input.sandbox,
1562
752
  ...toolConstructionPlan ? { toolConstructionPlan } : {},
@@ -1595,6 +785,7 @@ async function buildDynamicTools(input) {
1595
785
  resolvedWorkspace: input.resolvedWorkspace
1596
786
  }),
1597
787
  config: params.config,
788
+ githubPublicationAvailable: params.githubPublicationAvailable,
1598
789
  authProfileStore: params.toolAuthProfileStore ?? params.authProfileStore,
1599
790
  abortSignal: input.runAbortController.signal,
1600
791
  emitBeforeToolCallDiagnostics: false,
@@ -1616,6 +807,7 @@ async function buildDynamicTools(input) {
1616
807
  hasRepliedRef: params.hasRepliedRef,
1617
808
  modelHasVision,
1618
809
  computerContextEpoch: input.computerContextEpoch,
810
+ registerRunCleanup: input.registerRunCleanup,
1619
811
  requireExplicitMessageTarget: params.requireExplicitMessageTarget ?? isSubagentSessionKey(params.sessionKey),
1620
812
  sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
1621
813
  taskSuggestionDeliveryMode: params.taskSuggestionDeliveryMode,
@@ -1698,7 +890,7 @@ async function buildDynamicTools(input) {
1698
890
  };
1699
891
  const transientWebSearchRestriction = !webSearchPolicy.allowed && webSearchPolicy.persistentAllowed || isCodexMemoryFlushRun(params);
1700
892
  input.onPersistentWebSearchPolicyResolved?.(webSearchPresent || persistentCodexWebSearchSurface && transientWebSearchRestriction && webSearchPolicy.persistentAllowed);
1701
- const filteredTools = filterCodexDynamicToolsForAllowlist(visionFilteredTools, includeForcedCodexDynamicToolAllow(params.toolsAllow, messagePolicyParams));
893
+ const filteredTools = filterCodexDynamicToolsForAllowlist(visionFilteredTools, toolRunContext.runtimeToolAllowlist);
1702
894
  toolBuildStages.mark("allowlist-filter");
1703
895
  const normalizedTools = normalizeAgentRuntimeTools({
1704
896
  runtimePlan: input.ignoreRuntimePlan ? void 0 : params.runtimePlan,
@@ -1759,23 +951,15 @@ function addGatewayShellDynamicToolsIfAvailable(filteredTools, allTools, input,
1759
951
  if (!execTool || execExcluded || existingNames.has("gateway_exec")) return filteredTools;
1760
952
  const processExcluded = isCodexDynamicToolExcluded(input.pluginConfig, ["process", CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME]);
1761
953
  const processAliasAvailable = Boolean(processTool && !processExcluded && !existingNames.has("gateway_process"));
1762
- const toolsToAppend = [createExecAliasDynamicTool(execTool, {
1763
- host: "gateway",
1764
- processAliasAvailable
954
+ const createProjection = resolveCodexScheduledToolProjectionFactory(input.params.hostCapabilities);
955
+ if (!createProjection) return filteredTools;
956
+ const toolsToAppend = [createGatewayExecProjection(createProjection, execTool, {
957
+ processAliasAvailable,
958
+ ...input.sessionPermissionPolicy?.mode === "guarded" ? { ask: "always" } : {}
1765
959
  })];
1766
- if (processAliasAvailable && processTool) toolsToAppend.push(createGatewayProcessAliasDynamicTool(processTool));
960
+ if (processAliasAvailable && processTool) toolsToAppend.push(createGatewayProcessProjection(createProjection, processTool));
1767
961
  return [...filteredTools, ...toolsToAppend];
1768
962
  }
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
963
  /** Decides whether Codex native code mode can own shell/file tools for this turn. */
1780
964
  function shouldEnableCodexAppServerNativeToolSurface(params, sandbox, options = {}) {
1781
965
  if (params.pluginHarnessToolPolicyRestricted === true) return false;
@@ -1786,7 +970,7 @@ function shouldEnableCodexAppServerNativeToolSurface(params, sandbox, options =
1786
970
  runtimeSessionKey: options.runtimeSessionKey,
1787
971
  sandbox
1788
972
  })) return false;
1789
- const toolsAllow = includeForcedCodexDynamicToolAllow(params.toolsAllow, params);
973
+ const toolsAllow = params.toolsAllow;
1790
974
  if (toolsAllow === void 0) return canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
1791
975
  return hasWildcardCodexToolsAllow(toolsAllow) && canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
1792
976
  }
@@ -1916,10 +1100,7 @@ function addNodeShellDynamicToolsIfNeeded(filteredTools, allTools, input, nodePo
1916
1100
  if (!nodeExecIsDefault && !nodeExecAvailableFromAuto) return filteredTools;
1917
1101
  const execTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "exec");
1918
1102
  if (!execTool) return filteredTools;
1919
- if (!isCodexDynamicToolExcluded(input.pluginConfig, ["exec", "node_exec"]) && !filteredTools.some((tool) => normalizeCodexDynamicToolName(tool.name) === "node_exec")) return [...filteredTools, createExecAliasDynamicTool(execTool, {
1920
- host: "node",
1921
- node: nodePolicy.node
1922
- })];
1103
+ if (!isCodexDynamicToolExcluded(input.pluginConfig, ["exec", "node_exec"]) && !filteredTools.some((tool) => normalizeCodexDynamicToolName(tool.name) === "node_exec")) return [...filteredTools, createNodeExecAliasDynamicTool(execTool, nodePolicy.node)];
1923
1104
  return filteredTools;
1924
1105
  }
1925
1106
  function shouldKeepOpenClawShellDynamicTools(input, nodePolicy) {
@@ -1986,7 +1167,7 @@ const nodeExecServerTextDecoder = new TextDecoder("utf-8", { fatal: true });
1986
1167
  /** Produces the bounded, redacted terminal failure shared by pending and claimed node leases. */
1987
1168
  function createCodexNodeExecServerDisconnectError(reason, cause) {
1988
1169
  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 paired execution device disconnected; start a fresh attempt. (${reason}${detail})`);
1170
+ return /* @__PURE__ */ new Error(`Codex execution node disconnected; start a fresh attempt. (${reason}${detail})`);
1990
1171
  }
1991
1172
  /** Relays one authorized, single-use Codex exec-server channel without interpreting its protocol. */
1992
1173
  async function startCodexNodeExecServerRelay(params) {
@@ -2013,7 +1194,7 @@ async function startCodexNodeExecServerRelay(params) {
2013
1194
  if (!closed && !params.lease.closed) params.lease.onDisconnected?.(createCodexNodeExecServerDisconnectError(reason, cause));
2014
1195
  closeBoth(code, reason);
2015
1196
  };
2016
- params.lease.onChannelClosed = ({ failed, error }) => failUnexpectedly(failed ? 1011 : 1001, failed ? "execution device failed" : "execution device disconnected", error);
1197
+ params.lease.onChannelClosed = ({ failed, error }) => failUnexpectedly(failed ? 1011 : 1001, failed ? "execution node failed" : "execution node disconnected", error);
2017
1198
  socket.once("close", () => failUnexpectedly(1001, "execution socket closed"));
2018
1199
  socket.once("error", () => failUnexpectedly(1011, "execution socket failed"));
2019
1200
  let toNode = Promise.resolve();
@@ -2217,7 +1398,7 @@ function createCredentialedCodexNodeHttpRejection(request) {
2217
1398
  id: request.id,
2218
1399
  error: {
2219
1400
  code: -32602,
2220
- message: "Authenticated remote HTTP is unavailable on paired devices; run on Gateway or use an intentionally credential-free endpoint."
1401
+ message: "Authenticated remote HTTP is unavailable on execution nodes; run on Gateway or use an intentionally credential-free endpoint."
2221
1402
  }
2222
1403
  }));
2223
1404
  }
@@ -3012,6 +2193,8 @@ async function httpRequest(execServer, notifications, params) {
3012
2193
  const record = requireObject(params, "http/request params");
3013
2194
  const requestId = requireString(record.requestId, "requestId");
3014
2195
  const url = requireString(record.url, "url");
2196
+ const redirectPolicy = record.redirectPolicy ?? "follow";
2197
+ if (redirectPolicy !== "follow" && redirectPolicy !== "stop") throw new Error("http/request redirectPolicy must be follow or stop");
3015
2198
  assertSandboxHttpRequestTargetAllowed(url);
3016
2199
  const request = {
3017
2200
  method: requireString(record.method, "method"),
@@ -3019,6 +2202,7 @@ async function httpRequest(execServer, notifications, params) {
3019
2202
  headers: readHttpHeaders(record.headers),
3020
2203
  bodyBase64: typeof record.bodyBase64 === "string" ? record.bodyBase64 : void 0,
3021
2204
  timeoutMs: typeof record.timeoutMs === "number" && record.timeoutMs > 0 ? Math.floor(record.timeoutMs) : void 0,
2205
+ redirectPolicy,
3022
2206
  streamResponse: record.streamResponse === true
3023
2207
  };
3024
2208
  if (request.streamResponse) return await runStreamingSandboxHttpRequest(execServer, notifications, requestId, request);
@@ -3315,9 +2499,40 @@ def assert_url_allowed(url):
3315
2499
  PINNED_ADDRESSES[hostname] = sorted(addresses)
3316
2500
 
3317
2501
  class GuardedRedirectHandler(urllib.request.HTTPRedirectHandler):
2502
+ def __init__(self, redirect_policy):
2503
+ self.redirect_policy = redirect_policy
2504
+
3318
2505
  def redirect_request(self, req, fp, code, msg, headers, newurl):
2506
+ if self.redirect_policy == "stop":
2507
+ return None
3319
2508
  assert_url_allowed(newurl)
3320
- return super().redirect_request(req, fp, code, msg, headers, newurl)
2509
+ method = req.get_method()
2510
+ drop_body = code == 303 or (code in (301, 302) and method == "POST")
2511
+ next_headers = dict(req.headers)
2512
+ if drop_body:
2513
+ if method != "HEAD":
2514
+ method = "GET"
2515
+ for name in ("content-type", "content-length", "content-encoding", "transfer-encoding"):
2516
+ next_headers.pop(name.capitalize(), None)
2517
+ redirected = urllib.request.Request(
2518
+ newurl,
2519
+ data=None if drop_body else req.data,
2520
+ headers=next_headers,
2521
+ method=method,
2522
+ origin_req_host=req.origin_req_host,
2523
+ unverifiable=True,
2524
+ )
2525
+ previous = urllib.parse.urlsplit(req.full_url)
2526
+ target = urllib.parse.urlsplit(newurl)
2527
+ previous_port = previous.port or (443 if previous.scheme == "https" else 80)
2528
+ target_port = target.port or (443 if target.scheme == "https" else 80)
2529
+ if (previous.scheme, previous.hostname, previous_port) != (
2530
+ target.scheme, target.hostname, target_port
2531
+ ):
2532
+ # Match Codex's route-aware client: cross-origin hops never inherit secrets.
2533
+ for name in ("authorization", "cookie", "proxy-authorization", "www-authenticate", "cookie2"):
2534
+ redirected.remove_header(name.capitalize())
2535
+ return redirected
3321
2536
 
3322
2537
  def pinned_getaddrinfo(original_getaddrinfo):
3323
2538
  def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
@@ -3373,7 +2588,8 @@ def main():
3373
2588
  timeout = None
3374
2589
  if isinstance(timeout_ms, (int, float)) and timeout_ms > 0:
3375
2590
  timeout = timeout_ms / 1000
3376
- opener = urllib.request.build_opener(urllib.request.ProxyHandler({}), GuardedRedirectHandler)
2591
+ redirect_handler = GuardedRedirectHandler(input_data.get("redirectPolicy", "follow"))
2592
+ opener = urllib.request.build_opener(urllib.request.ProxyHandler({}), redirect_handler)
3377
2593
  original_getaddrinfo = socket.getaddrinfo
3378
2594
  socket.getaddrinfo = pinned_getaddrinfo(original_getaddrinfo)
3379
2595
  try:
@@ -3406,6 +2622,7 @@ async function startProcess(execServer, processes, notify, params) {
3406
2622
  const argv = requireStringArray(record.argv, "argv");
3407
2623
  const cwd = resolveExecServerPath(requireString(record.cwd, "cwd"), "process cwd");
3408
2624
  rejectUnsupportedArg0(record.arg0);
2625
+ assertSupportedProcessSandbox(execServer, record);
3409
2626
  const env = readProcessEnv(record);
3410
2627
  const managed = {
3411
2628
  processId,
@@ -3450,7 +2667,18 @@ async function startProcess(execServer, processes, notify, params) {
3450
2667
  } finally {
3451
2668
  if (managed.startPromise === startPromise) managed.startPromise = void 0;
3452
2669
  }
3453
- return { processId };
2670
+ return {
2671
+ processId,
2672
+ sandboxType: "none"
2673
+ };
2674
+ }
2675
+ function assertSupportedProcessSandbox(execServer, record) {
2676
+ if (record.networkProxy !== void 0 && record.networkProxy !== null) throw new Error("Codex sandbox exec-server network proxy launch is not supported.");
2677
+ 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.");
2678
+ if (resolveFsSandboxPolicy(execServer, record)?.unrestricted === false) throw new Error("Codex process filesystem sandbox restrictions cannot be enforced by the backend.");
2679
+ if (record.sandbox === void 0 || record.sandbox === null) return;
2680
+ if (requireObject(requireObject(record.sandbox, "process sandbox context").permissions, "process sandbox permissions").network !== "restricted") return;
2681
+ if (!execServer.networkIsolated) throw new Error("Codex network restrictions cannot be enforced by the sandbox backend.");
3454
2682
  }
3455
2683
  async function runProcess(execServer, managed, params) {
3456
2684
  const backend = execServer.backend;
@@ -3767,7 +2995,7 @@ async function ensureCodexSandboxExecServerEnvironment(params) {
3767
2995
  if (!params.sandbox?.enabled) return;
3768
2996
  const placementNodeId = readCodexPlacementNodeId(params.sandbox);
3769
2997
  if (!params.sandbox.backend && !placementNodeId) return;
3770
- if (placementNodeId && !params.runtime) throw new Error("Codex paired-device execution requires its active plugin runtime.");
2998
+ if (placementNodeId && !params.runtime) throw new Error("Codex node execution requires its active plugin runtime.");
3771
2999
  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
3000
  const { server: execServer, nodeLease } = await acquireOpenClawExecServer({
3773
3001
  sandbox: params.sandbox,
@@ -3833,7 +3061,7 @@ async function acquireOpenClawExecServer(params) {
3833
3061
  if (!("node" in server)) return { server };
3834
3062
  if (!runtime || !signal) {
3835
3063
  await releaseOpenClawExecServer(server);
3836
- throw new Error("Codex paired-device execution requires an active runtime and attempt.");
3064
+ throw new Error("Codex node execution requires an active runtime and attempt.");
3837
3065
  }
3838
3066
  try {
3839
3067
  const placementIdentity = readCodexPlacementWorkspaceIdentity(sandbox);
@@ -3852,7 +3080,7 @@ async function acquireOpenClawExecServer(params) {
3852
3080
  });
3853
3081
  if (signal.aborted || server.closed || sandboxExecServerRegistry.servers.get(key) !== promise) {
3854
3082
  channel.close();
3855
- throw new Error("Codex paired-device execution retired before its channel was ready.");
3083
+ throw new Error("Codex node execution retired before its channel was ready.");
3856
3084
  }
3857
3085
  const nodeLease = {
3858
3086
  id: randomUUID(),
@@ -3936,7 +3164,8 @@ async function startOpenClawExecServer(sandbox) {
3936
3164
  } : {
3937
3165
  ...common,
3938
3166
  backend: connection.backend,
3939
- fsBridge: connection.fsBridge
3167
+ fsBridge: connection.fsBridge,
3168
+ networkIsolated: (connection.backend.id === "docker" || connection.backend.id === "podman") && sandbox.docker.network.trim().toLowerCase() === "none"
3940
3169
  };
3941
3170
  server.on("connection", (socket, request) => {
3942
3171
  socket.on("error", handleExecServerSocketError);
@@ -3977,7 +3206,7 @@ function readCodexPlacementNodeId(sandbox) {
3977
3206
  return sandbox.placementNodeId;
3978
3207
  }
3979
3208
  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 paired-device execution requires its exact placement workspace identity.");
3209
+ 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
3210
  return {
3982
3211
  environmentId: sandbox.placementEnvironmentId,
3983
3212
  sessionId: sandbox.placementSessionId,
@@ -4018,7 +3247,7 @@ function handleClosedCodexNodeExecServerLease(execServer, lease, result) {
4018
3247
  return;
4019
3248
  }
4020
3249
  try {
4021
- lease.onDisconnected?.(createCodexNodeExecServerDisconnectError(result.failed ? "execution device failed" : "execution device disconnected", result.error));
3250
+ lease.onDisconnected?.(createCodexNodeExecServerDisconnectError(result.failed ? "execution node failed" : "execution node disconnected", result.error));
4022
3251
  } finally {
4023
3252
  closeCodexNodeExecServerLease(execServer, lease);
4024
3253
  }
@@ -4156,7 +3385,7 @@ async function handleCodexAppServerApprovalRequest(params) {
4156
3385
  return buildApprovalResponse(params.method, context.requestParams, resolvedOutcome);
4157
3386
  };
4158
3387
  try {
4159
- if (params.method === "item/commandExecution/requestApproval") {
3388
+ if (params.method === "item/commandExecution/requestApproval" && !readNetworkApprovalContext(requestParams)) {
4160
3389
  const command = readPolicyCommand(requestParams);
4161
3390
  const cwd = readStringField(requestParams, "cwd") ?? params.paramsForRun.workspaceDir;
4162
3391
  const prepareMutableFileApproval = params.paramsForRun.hostCapabilities.prepareMutableFileApproval;
@@ -4183,7 +3412,7 @@ async function handleCodexAppServerApprovalRequest(params) {
4183
3412
  return await resolvePolicyApproval("denied", policyOutcome.reason);
4184
3413
  }
4185
3414
  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.");
3415
+ 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
3416
  const requestResult = await requestPluginApproval({
4188
3417
  hostCapabilities: params.paramsForRun.hostCapabilities,
4189
3418
  title: context.title,
@@ -4299,18 +3528,19 @@ function buildApprovalContext(params) {
4299
3528
  const reasonPreview = sanitizeApprovalPreview(readStringPreview(params.requestParams, "reason"), 180);
4300
3529
  const command = commandPreview.text;
4301
3530
  const reason = reasonPreview.text;
3531
+ const networkApproval = params.method === "item/commandExecution/requestApproval" ? readNetworkApprovalContext(params.requestParams) : void 0;
4302
3532
  const approvalKind = params.method.includes("commandExecution") ? "command" : params.method.includes("fileChange") ? "file-change" : params.method.includes("permissions") ? "permissions" : "other";
4303
3533
  const kind = approvalKind === "command" ? "exec" : approvalKind === "other" ? "unknown" : "plugin";
4304
3534
  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}`);
3535
+ 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";
3536
+ 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
3537
  return {
4308
3538
  approvalKind,
4309
3539
  kind,
4310
3540
  title,
4311
3541
  description: permissionLines.length > 0 ? joinDescriptionLinesWithinLimit(permissionLines, PERMISSION_DESCRIPTION_MAX_LENGTH) : [subject, ...commandDetailLines].join("\n"),
4312
3542
  severity: kind === "exec" ? "warning" : "info",
4313
- toolName: kind === "exec" ? "codex_command_approval" : params.method === "item/permissions/requestApproval" ? "codex_permission_approval" : "codex_file_approval",
3543
+ toolName: networkApproval ? "codex_network_approval" : kind === "exec" ? "codex_command_approval" : params.method === "item/permissions/requestApproval" ? "codex_permission_approval" : "codex_file_approval",
4314
3544
  itemId,
4315
3545
  approvalId,
4316
3546
  requestParams: params.requestParams,
@@ -4482,6 +3712,10 @@ function sanitizeRelayDecisionReason(value) {
4482
3712
  }
4483
3713
  function buildOpenClawToolPolicyRequest(method, requestParams) {
4484
3714
  if (method === "item/commandExecution/requestApproval") {
3715
+ if (readNetworkApprovalContext(requestParams)) return {
3716
+ toolName: "codex_network_approval",
3717
+ params: { approval: requestParams ?? {} }
3718
+ };
4485
3719
  const command = readPolicyCommand(requestParams);
4486
3720
  return {
4487
3721
  toolName: "exec",
@@ -4769,6 +4003,15 @@ function readPolicyCommand(record) {
4769
4003
  const actionCommands = readCommandActions(record);
4770
4004
  if (actionCommands.length > 0) return actionCommands.join(" && ");
4771
4005
  }
4006
+ function readNetworkApprovalContext(record) {
4007
+ const context = isJsonObject(record?.networkApprovalContext) ? record.networkApprovalContext : void 0;
4008
+ const host = readStringField(context, "host");
4009
+ const protocol = readStringField(context, "protocol");
4010
+ return host && protocol ? {
4011
+ host,
4012
+ protocol
4013
+ } : void 0;
4014
+ }
4772
4015
  function readCommandActions(record) {
4773
4016
  const actions = record?.commandActions;
4774
4017
  if (!Array.isArray(actions)) return [];
@@ -4958,6 +4201,7 @@ async function routeCodexAppServerElicitationRequest(params) {
4958
4201
  if (!requestParams || readNonBlankStringField(requestParams, "threadId") !== params.threadId) return { kind: "not-mine" };
4959
4202
  const requestTurnId = requestParams.turnId;
4960
4203
  if (requestTurnId !== null && requestTurnId !== void 0 && requestTurnId !== params.turnId) return { kind: "not-mine" };
4204
+ 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
4205
  const pluginResolution = resolvePluginElicitation({
4962
4206
  requestParams,
4963
4207
  pluginAppPolicyContext: params.pluginAppPolicyContext
@@ -4983,7 +4227,7 @@ async function routeCodexAppServerElicitationRequest(params) {
4983
4227
  }));
4984
4228
  }
4985
4229
  const approvalPrompt = readComputerUseApprovalElicitation(requestParams, params.computerUseMcpServerName) ?? readBridgeableApprovalElicitation(requestParams);
4986
- if (!approvalPrompt) return (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 ? handled(createCodexElicitationResponse("decline")) : { kind: "not-mine" };
4230
+ if (!approvalPrompt) return handled(createCodexElicitationResponse("decline"));
4987
4231
  return handled(buildElicitationResponse(approvalPrompt, await requestPluginApprovalOutcome({
4988
4232
  paramsForRun: params.paramsForRun,
4989
4233
  title: approvalPrompt.title,
@@ -6526,4 +5770,4 @@ function isCronAddAction(args) {
6526
5770
  return typeof action === "string" && action.trim().toLowerCase() === "add";
6527
5771
  }
6528
5772
  //#endregion
6529
- export { buildCodexNativeHookRelayConfig as A, isMatchingDynamicToolTerminalDiagnostic as B, shouldRequireCodexSandboxExecServerEnvironment as C, CodexNativeToolLifecycleProjector as D, readBoundedCodexRemoteWorkspaceFile as E, resolveCodexNativeHookRelayTtlMs as F, toCodexDynamicToolProgressResponse as G, resolveTerminalDynamicToolBatchAction as H, scheduleCodexNativeHookRelayUnregister as I, toCodexDynamicToolProtocolResponse as K, handleDynamicToolCallWithTimeout as L, createCodexNativeHookRelay as M, emitCodexNativePreToolUseFailureDiagnostic as N, CODEX_NATIVE_HOOK_RELAY_EVENTS as O, resolveCodexNativeHookRelayEvents as P, hasPendingDynamicToolTerminalDiagnostic as R, shouldEnableCodexAppServerNativeToolSurface as S, filterCodexVisionTools as T, shouldBlockTerminalReleaseForNonTerminalDynamicToolResult as U, resolveDynamicToolCallTimeoutMs as V, shouldReleaseTurnAfterTerminalDynamicTool as W, 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, buildCodexNativeHookRelayDisabledConfig as j, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as k, resolveCodexProviderWebSearchSupportForClient as l, disableCodexPluginThreadConfig as m, projectCodexExecutableDynamicTools as n, emitDynamicToolTerminalDiagnostic as o, createCodexDynamicToolBuildStageTracker as p, resolveCodexToolAbortTerminalReason as q, routeCodexAppServerElicitationRequest as r, handleCodexAppServerApprovalRequest as s, createCodexDynamicToolBridge as t, ensureCodexSandboxExecServerEnvironment as u, resolveCodexExternalSandboxPolicyForOpenClawSandbox as v, shouldWarnCodexDynamicToolBuildStageSummary as w, resolveCodexSandboxEnvironmentSelection as x, resolveCodexMessageToolProvider as y, isDynamicToolTerminalDiagnosticEvent as z };
5773
+ 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 };