@openclaw/codex 2026.9.1-beta.1 → 2026.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +5 -6
- package/dist/{attempt-client-cleanup-bfsmcQ6m.js → attempt-client-cleanup-DYHcRQAa.js} +31 -45
- package/dist/attempt-context-DmQUNWwT.js +634 -0
- package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
- package/dist/{binding-connection-BMvPX73o.js → binding-connection-E6uDsPlx.js} +2 -2
- package/dist/{bounded-turn-B7iBUcuP.js → bounded-turn-wzJrwKKe.js} +15 -20
- package/dist/{capabilities-BRMh0aIq.js → capabilities-dIjNVCYH.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-DEsIufkt.js → command-formatters-CLHhEB1Q.js} +5 -4
- package/dist/{command-handlers-D_-1_qRp.js → command-handlers-CTGb2csu.js} +124 -101
- package/dist/{compact-BglNFZrQ.js → compact-_t0HQrUS.js} +38 -29
- package/dist/{config-giW8X0QA.js → config-BhmfC1s6.js} +294 -282
- package/dist/{context-compaction-activity-BOeJf7yo.js → context-compaction-activity-CMla5FPJ.js} +4 -1
- package/dist/{conversation-binding-data-CW2GuupV.js → conversation-binding-data-BiodpIzq.js} +2 -1
- package/dist/doctor-contract-api.js +143 -12
- package/dist/{dynamic-tools-Dnlfa--w.js → dynamic-tools-BU9tmlYm.js} +599 -655
- package/dist/{effective-mcp-catalog-CTeGrnfO.js → effective-mcp-catalog-DzYBW4h1.js} +2 -2
- package/dist/{event-projector-assistant-message-C5-Ds8mA.js → event-projector-assistant-message-DHRFXKbS.js} +4 -4
- package/dist/{event-projector-usage-Bk1I90Bg.js → event-projector-usage-C5mcrGjp.js} +15 -148
- package/dist/{harness-Csz0F-DK.js → harness-DXVZ5II5.js} +42 -52
- package/dist/harness.js +1 -1
- package/dist/index.js +458 -404
- package/dist/{isolated-completion-Cv6FqygM.js → isolated-completion-kg9kv4iH.js} +4 -4
- package/dist/launch-args-RXQwn8zV.js +90 -0
- package/dist/{managed-binary-DFYK4DWq.js → managed-binary-4-Vjz5GH.js} +14 -9
- package/dist/media-understanding-provider.js +1 -1
- package/dist/model-catalog-CUM68Hkl.js +101 -0
- package/dist/{models-TS3HBU-q.js → models-sYnEc0gd.js} +25 -28
- package/dist/{native-subagent-monitor-4Mfq2HDs.js → native-subagent-monitor-CnH147jH.js} +55 -115
- package/dist/{node-exec-server.runtime-BpWqJO1V.js → node-exec-server.runtime-CstNHCmC.js} +9 -6
- package/dist/{plugin-approval-roundtrip-bUm777tR.js → plugin-approval-roundtrip-CNe-Xrjx.js} +30 -3
- package/dist/{plugin-marketplace-discovery-B9DvaAG-.js → plugin-marketplace-discovery-CfFlKqDl.js} +15 -14
- package/dist/{plugin-metadata-cache-CTCT3w5L.js → plugin-metadata-cache-BFrPhb2c.js} +6 -6
- package/dist/provider-capabilities-DW5p4k9w.js +101 -0
- package/dist/{rate-limits-C5_D8Gmb.js → rate-limits-CawQJfUS.js} +3 -2
- package/dist/{sandbox-guard-kuWTn9C5.js → request-DYAI5FQE.js} +195 -2
- package/dist/{run-attempt-DYc0QCBF.js → run-attempt-D1hJO4fX.js} +828 -2100
- package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-C3jVimFn.js} +21 -14
- package/dist/{session-binding-Bcynfd-_.js → session-binding-BHuTCRZQ.js} +198 -127
- package/dist/{session-catalog-DaLKVtpH.js → session-catalog-yyvTWFOw.js} +564 -408
- package/dist/{session-cli-DMc4oS2w.js → session-cli-CmFEXMAM.js} +1 -1
- package/dist/session-history-C5J1AKzG.js +87 -0
- package/dist/session-initialization-BeWzjGiR.js +74 -0
- package/dist/{session-permission-policy-BrNH1bjy.js → session-permission-policy-DeWVTCMj.js} +2 -2
- package/dist/session-retirement-BujDjXVF.js +97 -0
- package/dist/{session-upstream-marker-BIkusb95.js → session-upstream-marker-C351-5Qw.js} +19 -4
- package/dist/settled-turn-context-D3SNWtUn.js +268 -0
- package/dist/settled-turn-finalizer-BVJx4yoc.js +104 -0
- package/dist/{shared-client-DKz23hHY.js → shared-client-DxcfF9KX.js} +3480 -679
- package/dist/{side-question-DjA_jsNe.js → side-question-BTZAII4l.js} +108 -70
- package/dist/{thread-lifecycle-L7oEkTlq.js → thread-lifecycle-DAcEJ_Om.js} +2188 -1915
- package/dist/{thread-ownership-DZeuKH1j.js → thread-ownership-zGokd8i1.js} +25 -14
- package/dist/thread-policy-g4KbJPzp.js +54 -0
- package/dist/{plugin-app-cache-key-C1CAdfcP.js → thread-resume-C7pyVKeW.js} +59 -7
- package/dist/{transcript-mirror-DsCMWBca.js → transcript-mirror-DTUxFWa_.js} +79 -17
- package/dist/transport-stdio-CyPldczm.js +726 -0
- package/dist/{upstream-prompt-provenance-CFmsKwr9.js → upstream-prompt-provenance-LphB8slG.js} +8 -4
- package/dist/upstream-session-fork-CYlBIGVt.js +966 -0
- package/dist/{usage-ROIaW3wo.js → usage-Bj-rrzkR.js} +3 -3
- package/dist/{web-search-provider.runtime-ClaNPV7N.js → web-search-provider.runtime-D2FWSK4w.js} +3 -3
- package/openclaw.plugin.json +1 -30
- package/package.json +6 -6
- package/dist/command-rpc-CCeCkf_v.js +0 -90
- package/dist/incognito-session-ET_ufDH-.js +0 -2
- package/dist/model-catalog-i9rNBthX.js +0 -48
- package/dist/protocol-validators-VeJxxJ0U.js +0 -2421
- package/dist/request-DXXGHko0.js +0 -157
- package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
- package/dist/session-retirement-CcNC3YSY.js +0 -36
- package/dist/settled-turn-finalizer-Dc3ApjU4.js +0 -328
- package/dist/thread-resume-BE9qNEW0.js +0 -30
- package/dist/transport-stdio-DhoGy33Z.js +0 -99
- package/dist/upstream-session-fork-DlaHxSLC.js +0 -326
|
@@ -1,41 +1,45 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { E as itemStatus,
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { $t as isJsonObject, Qt as flattenCodexDynamicToolFunctions, Zt as CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE, _t as resolveCodexToolAbortTerminalReason, bt as withDynamicToolTranscriptDetails, it as readCodexTurn, ot as createCodexElicitationResponse, vt as createFailedDynamicToolResponse, yt as withDynamicToolExecutionState } from "./shared-client-DxcfF9KX.js";
|
|
2
|
+
import { E as readCodexPluginConfig, w as isCodexRemoteExecPlacementSandbox } from "./config-BhmfC1s6.js";
|
|
3
|
+
import { E as itemStatus, I as readItem, b as auditNativeToolUnfinishedStatus, h as isCodexNotificationForTurn, v as auditNativeToolName, y as auditNativeToolTerminalStatus } from "./attempt-client-cleanup-DYHcRQAa.js";
|
|
4
|
+
import { B as emitCodexNativePreToolUseFailureDiagnostic, S as resolveCodexWebSearchPlan, at as filterCodexDynamicTools, lt as isSystemAgentOnlyCodexDynamicToolAllowlist, ot as filterCodexDynamicToolsForDisabledNativeSurface, st as isForcedPrivateQaCodexRuntime, ut as normalizeCodexDynamicToolName } from "./thread-lifecycle-DAcEJ_Om.js";
|
|
5
|
+
import { l as resolveCodexNativeExecutionPolicy, u as resolveCodexNodeExecToolOverrides } from "./request-DYAI5FQE.js";
|
|
6
6
|
import { r as sanitizeInlineImageDataUrl, t as invalidInlineImageText } from "./image-payload-sanitizer-CnfoUPCE.js";
|
|
7
|
-
import {
|
|
8
|
-
import { a as
|
|
9
|
-
import { a as
|
|
7
|
+
import { a as formatCodexDisplayText } from "./command-formatters-CLHhEB1Q.js";
|
|
8
|
+
import { a as requestPluginApprovalOutcome, c as truncateCodexApprovalDisplayText, i as requestPluginApproval, l as waitForPluginApprovalDecision, n as codexApprovalTimeoutText, o as sanitizeCodexApprovalVisibleText, r as mapExecDecisionToOutcome, s as stripDanglingCodexApprovalTerminalSequence, t as approvalRequestExplicitlyUnavailable } from "./plugin-approval-roundtrip-CNe-Xrjx.js";
|
|
9
|
+
import { a as CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME, c as createNodeExecAliasDynamicTool, i as CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME, l as isCodexDynamicToolExcluded, o as createGatewayExecProjection, r as CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME, s as createGatewayProcessProjection } from "./provider-capabilities-DW5p4k9w.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
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
|
+
import { isPathStrictlyInside, root } from "openclaw/plugin-sdk/file-access-runtime";
|
|
16
17
|
import { createHash, randomUUID } from "node:crypto";
|
|
17
18
|
import { resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
|
|
18
19
|
import { formatErrorMessage as formatErrorMessage$1, redactSensitiveText } from "openclaw/plugin-sdk/security-runtime";
|
|
19
20
|
import { killProcessTree } from "openclaw/plugin-sdk/process-runtime";
|
|
20
21
|
import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
21
22
|
import { spawn } from "node:child_process";
|
|
23
|
+
import { once } from "node:events";
|
|
22
24
|
import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
23
25
|
import { DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS, estimateToolResultTextChars, resolveLiveToolResultMaxChars, sliceToolResultTextToBudget, sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
24
|
-
import {
|
|
26
|
+
import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
25
27
|
import { isIP } from "node:net";
|
|
26
28
|
import { WebSocketServer } from "ws";
|
|
27
29
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
28
30
|
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
29
31
|
import { redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
|
|
30
|
-
import {
|
|
31
|
-
import { runWithCronCreatorAuthorityCapabilityResolver } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
32
|
-
import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
32
|
+
import { formatMcpCodexApprovalRemedy, requiresMcpCodexToolApproval, resolveCodexScheduledToolProjectionFactory, resolveProjectedMcpCodexToolApprovalMode, runWithCronCreatorAuthorityCapabilityResolver } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
33
33
|
import { buildRemoteCommand, isToolAllowed, sanitizeEnvVars } from "openclaw/plugin-sdk/sandbox";
|
|
34
34
|
import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
35
35
|
import { getMediaDir } from "openclaw/plugin-sdk/media-runtime";
|
|
36
|
-
import {
|
|
36
|
+
import { consumeTrustedToolNoStartError, getCoreTtsToolResultMediaUrls } from "openclaw/plugin-sdk/agent-harness-tool-runtime";
|
|
37
|
+
import { normalizeOpenAIStrictCompatSchema } from "openclaw/plugin-sdk/provider-tools";
|
|
37
38
|
//#region extensions/codex/src/app-server/event-projector-native-tool-lifecycle.ts
|
|
38
|
-
|
|
39
|
+
function isMcpToolCallItemNotification(method, params) {
|
|
40
|
+
return (method === "item/started" || method === "item/completed") && isJsonObject(params.item) && params.item.type === "mcpToolCall";
|
|
41
|
+
}
|
|
42
|
+
/** Owns native item lifetimes for diagnostics and MCP approval correlation. */
|
|
39
43
|
var CodexNativeToolLifecycleProjector = class {
|
|
40
44
|
constructor(context, threadId, turnId, options = {}) {
|
|
41
45
|
this.context = context;
|
|
@@ -49,13 +53,39 @@ var CodexNativeToolLifecycleProjector = class {
|
|
|
49
53
|
this.approvalFailureDispositionByItem = /* @__PURE__ */ new Map();
|
|
50
54
|
this.preToolUseFailureByItem = /* @__PURE__ */ new Map();
|
|
51
55
|
this.finalized = false;
|
|
56
|
+
this.turnCompleted = false;
|
|
57
|
+
this.pendingMcpNotifications = 0;
|
|
58
|
+
}
|
|
59
|
+
getActiveMcpToolCall(serverName) {
|
|
60
|
+
if (this.finalized || this.turnCompleted || this.pendingMcpNotifications > 0 || this.options.runAbortSignal?.aborted) return;
|
|
61
|
+
let candidate;
|
|
62
|
+
for (const { mcpToolCall } of this.activeItems.values()) {
|
|
63
|
+
if (mcpToolCall?.server !== serverName) continue;
|
|
64
|
+
if (candidate) return;
|
|
65
|
+
candidate = mcpToolCall;
|
|
66
|
+
}
|
|
67
|
+
if (!candidate || candidate.status !== "inProgress" || typeof candidate.server !== "string" || !candidate.server.trim() || typeof candidate.tool !== "string" || !candidate.tool.trim() || candidate.arguments === void 0 || candidate.appContext != null || candidate.pluginId != null) return;
|
|
68
|
+
return {
|
|
69
|
+
id: candidate.id,
|
|
70
|
+
server: candidate.server,
|
|
71
|
+
tool: candidate.tool,
|
|
72
|
+
arguments: candidate.arguments
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
recordMcpToolCallReceipt(notification) {
|
|
76
|
+
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
77
|
+
if (!params || !isCodexNotificationForTurn(params, this.threadId, this.turnId)) return;
|
|
78
|
+
if (isMcpToolCallItemNotification(notification.method, params)) this.pendingMcpNotifications += 1;
|
|
79
|
+
else if (notification.method === "turn/completed" && readCodexTurn(params.turn)?.id === this.turnId) this.turnCompleted = true;
|
|
52
80
|
}
|
|
53
81
|
handleNotification(notification) {
|
|
54
82
|
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
55
83
|
if (!params || !isCodexNotificationForTurn(params, this.threadId, this.turnId)) return;
|
|
84
|
+
if (this.pendingMcpNotifications > 0 && isMcpToolCallItemNotification(notification.method, params)) this.pendingMcpNotifications -= 1;
|
|
56
85
|
if (notification.method === "turn/completed") {
|
|
57
86
|
const turn = readCodexTurn(params.turn);
|
|
58
87
|
if (!turn || turn.id !== this.turnId) return;
|
|
88
|
+
this.turnCompleted = true;
|
|
59
89
|
for (const item of turn.items ?? []) this.recordSnapshotItem(item);
|
|
60
90
|
return;
|
|
61
91
|
}
|
|
@@ -74,10 +104,10 @@ var CodexNativeToolLifecycleProjector = class {
|
|
|
74
104
|
});
|
|
75
105
|
}
|
|
76
106
|
recordItem(params) {
|
|
77
|
-
const toolName = auditNativeToolName(params.item);
|
|
107
|
+
const toolName = auditNativeToolName(params.item) ?? (params.item.type === "mcpToolCall" ? params.item.type : void 0);
|
|
78
108
|
if (!toolName || this.completedItemIds.has(params.item.id)) return;
|
|
79
109
|
if (params.phase === "start") {
|
|
80
|
-
this.recordStarted(params.item.id, toolName, auditNativeToolUnfinishedStatus(params.item), params.sourceTimestampMs);
|
|
110
|
+
this.recordStarted(params.item.id, toolName, auditNativeToolUnfinishedStatus(params.item), params.sourceTimestampMs, params.item.type === "mcpToolCall" ? params.item : void 0);
|
|
81
111
|
return;
|
|
82
112
|
}
|
|
83
113
|
if (params.item.type === "webSearch") {
|
|
@@ -203,12 +233,13 @@ var CodexNativeToolLifecycleProjector = class {
|
|
|
203
233
|
item
|
|
204
234
|
});
|
|
205
235
|
}
|
|
206
|
-
recordStarted(toolCallId, toolName, unfinishedStatus, sourceTimestampMs) {
|
|
236
|
+
recordStarted(toolCallId, toolName, unfinishedStatus, sourceTimestampMs, mcpToolCall) {
|
|
207
237
|
if (this.activeItems.has(toolCallId)) return;
|
|
208
238
|
this.startedAtByItem.set(toolCallId, sourceTimestampMs ?? Date.now());
|
|
209
239
|
this.activeItems.set(toolCallId, {
|
|
210
240
|
toolName,
|
|
211
|
-
unfinishedStatus
|
|
241
|
+
unfinishedStatus,
|
|
242
|
+
mcpToolCall
|
|
212
243
|
});
|
|
213
244
|
emitTrustedDiagnosticEvent({
|
|
214
245
|
type: "tool.execution.started",
|
|
@@ -278,10 +309,10 @@ function joinRemoteWorkspacePath(remoteRoot, suffix) {
|
|
|
278
309
|
//#endregion
|
|
279
310
|
//#region extensions/codex/src/app-server/remote-workspace-media.ts
|
|
280
311
|
const REMOTE_WORKSPACE_MEDIA_TIMEOUT_MS = 6e4;
|
|
281
|
-
const REMOTE_WORKSPACE_MEDIA_MAX_BYTES =
|
|
312
|
+
const REMOTE_WORKSPACE_MEDIA_MAX_BYTES = 67108864;
|
|
282
313
|
const REMOTE_WORKSPACE_MEDIA_MAX_ATTACHMENTS = 16;
|
|
283
|
-
const CODEX_REMOTE_MEDIA_CHUNK_BYTES =
|
|
284
|
-
const CODEX_REMOTE_COMMAND_DEFAULT_OUTPUT_BYTES =
|
|
314
|
+
const CODEX_REMOTE_MEDIA_CHUNK_BYTES = 524288;
|
|
315
|
+
const CODEX_REMOTE_COMMAND_DEFAULT_OUTPUT_BYTES = 1048576;
|
|
285
316
|
const CODEX_BOUNDED_REMOTE_FILE_READER = [
|
|
286
317
|
"try{",
|
|
287
318
|
"const fs=require(\"node:fs\");",
|
|
@@ -543,90 +574,6 @@ function mapMessageMediaValues(args, mapValue) {
|
|
|
543
574
|
/** Mutable dependency seam shared by dynamic-tool construction and its behavioral tests. */
|
|
544
575
|
const dynamicToolBuildState = {};
|
|
545
576
|
//#endregion
|
|
546
|
-
//#region extensions/codex/src/app-server/shell-dynamic-tools.ts
|
|
547
|
-
const CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME = "node_exec";
|
|
548
|
-
const CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME = "gateway_exec";
|
|
549
|
-
const CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME = "gateway_process";
|
|
550
|
-
const CODEX_EXEC_POLICY_PARAMETER_NAMES = /* @__PURE__ */ new Set([
|
|
551
|
-
"host",
|
|
552
|
-
"security",
|
|
553
|
-
"ask"
|
|
554
|
-
]);
|
|
555
|
-
const CODEX_NODE_EXEC_PARAMETER_NAMES = /* @__PURE__ */ new Set([
|
|
556
|
-
"command",
|
|
557
|
-
"workdir",
|
|
558
|
-
"env",
|
|
559
|
-
"timeoutSeconds",
|
|
560
|
-
"node"
|
|
561
|
-
]);
|
|
562
|
-
const PROCESS_FOLLOWUP_TEXT = "Use process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.";
|
|
563
|
-
/** Returns true when plugin config explicitly removes any named dynamic tool. */
|
|
564
|
-
function isCodexDynamicToolExcluded(config, names) {
|
|
565
|
-
const normalizedNames = new Set(names.map((name) => normalizeCodexDynamicToolName(name)));
|
|
566
|
-
return (config.codexDynamicToolsExclude ?? []).some((name) => normalizedNames.has(normalizeCodexDynamicToolName(name)));
|
|
567
|
-
}
|
|
568
|
-
function createExecAliasDynamicTool(execTool, params) {
|
|
569
|
-
const pinnedNode = params.host === "node" ? params.node?.trim() : void 0;
|
|
570
|
-
const nodeAlias = params.host === "node";
|
|
571
|
-
const gatewayProcessAliasAvailable = params.host === "gateway" && params.processAliasAvailable;
|
|
572
|
-
const name = nodeAlias ? CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME : CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME;
|
|
573
|
-
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.";
|
|
574
|
-
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.";
|
|
575
|
-
return {
|
|
576
|
-
...execTool,
|
|
577
|
-
name,
|
|
578
|
-
description,
|
|
579
|
-
parameters: hideExecDynamicToolParameters(execTool.parameters, !nodeAlias || Boolean(pinnedNode), nodeAlias),
|
|
580
|
-
execute: async (toolCallId, args, signal, onUpdate) => {
|
|
581
|
-
const result = await execTool.execute(toolCallId, pinExecDynamicToolArgs(args, params, pinnedNode), signal, onUpdate);
|
|
582
|
-
return {
|
|
583
|
-
...result,
|
|
584
|
-
content: result.content.map((item) => item.type === "text" ? Object.assign({}, item, { text: item.text.replace(PROCESS_FOLLOWUP_TEXT, followupText) }) : item)
|
|
585
|
-
};
|
|
586
|
-
}
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
function createGatewayProcessAliasDynamicTool(processTool) {
|
|
590
|
-
return {
|
|
591
|
-
...processTool,
|
|
592
|
-
name: CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME,
|
|
593
|
-
description: "Manage background shell sessions in the existing per-session OpenClaw process scope: list, poll, log, write, send-keys, submit, paste, kill, clear, or remove. Use for gateway_exec follow-up; use native Codex shell session handling for ordinary local work."
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
function pinExecDynamicToolArgs(args, params, configuredNode) {
|
|
597
|
-
const { host: _host, security: _security, ask: _ask, node: requestedNode, ...rest } = normalizeExecDynamicToolArgs(args);
|
|
598
|
-
if (params.host === "gateway") return {
|
|
599
|
-
...rest,
|
|
600
|
-
host: params.host,
|
|
601
|
-
...params.ask ? { ask: params.ask } : {}
|
|
602
|
-
};
|
|
603
|
-
const nodeArgs = Object.fromEntries(Object.entries(rest).filter(([name]) => CODEX_NODE_EXEC_PARAMETER_NAMES.has(name)));
|
|
604
|
-
const node = configuredNode ?? (typeof requestedNode === "string" ? requestedNode.trim() : "");
|
|
605
|
-
return {
|
|
606
|
-
...nodeArgs,
|
|
607
|
-
host: params.host,
|
|
608
|
-
...node ? { node } : {}
|
|
609
|
-
};
|
|
610
|
-
}
|
|
611
|
-
function normalizeExecDynamicToolArgs(args) {
|
|
612
|
-
return args && typeof args === "object" && !Array.isArray(args) ? args : {};
|
|
613
|
-
}
|
|
614
|
-
function hideExecDynamicToolParameters(parameters, hideNode, nodeOnly) {
|
|
615
|
-
if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) return parameters;
|
|
616
|
-
const schema = parameters;
|
|
617
|
-
const rawProperties = schema.properties;
|
|
618
|
-
if (!rawProperties || typeof rawProperties !== "object" || Array.isArray(rawProperties)) return parameters;
|
|
619
|
-
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");
|
|
620
|
-
const nextProperties = Object.fromEntries(Object.entries(rawProperties).filter(([name]) => includeParameter(name)));
|
|
621
|
-
const rawRequired = schema.required;
|
|
622
|
-
const nextRequired = Array.isArray(rawRequired) ? rawRequired.filter((name) => typeof name !== "string" || includeParameter(name)) : rawRequired;
|
|
623
|
-
return {
|
|
624
|
-
...schema,
|
|
625
|
-
properties: nextProperties,
|
|
626
|
-
...Array.isArray(rawRequired) ? { required: nextRequired } : {}
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
//#endregion
|
|
630
577
|
//#region extensions/codex/src/app-server/vision-tools.ts
|
|
631
578
|
/**
|
|
632
579
|
* Codex's enabled native surface includes its stable view_image loader. Keep
|
|
@@ -652,6 +599,15 @@ const CODEX_NATIVE_SANDBOX_TOOL_REQUIREMENTS = [
|
|
|
652
599
|
"apply_patch"
|
|
653
600
|
];
|
|
654
601
|
const CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW = /* @__PURE__ */ new Set(["read", "write"]);
|
|
602
|
+
const CODEX_DISABLED_NATIVE_SHELL_DYNAMIC_TOOLS = /* @__PURE__ */ new Set([
|
|
603
|
+
"exec",
|
|
604
|
+
"process",
|
|
605
|
+
"sandbox_exec",
|
|
606
|
+
"sandbox_process",
|
|
607
|
+
CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME,
|
|
608
|
+
CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME,
|
|
609
|
+
CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME
|
|
610
|
+
]);
|
|
655
611
|
/** Keeps node filesystem and process ownership on its native exec-server. */
|
|
656
612
|
function resolveCodexNodePlacementToolConstructionPlan(sandbox, nativeToolSurfaceEnabled) {
|
|
657
613
|
if (!isCodexRemoteExecPlacementSandbox(sandbox) || sandbox?.backendId !== "node" || !("placementNodeId" in sandbox) || typeof sandbox.placementNodeId !== "string" || !sandbox.placementNodeId) return;
|
|
@@ -669,13 +625,6 @@ function preserveRingZeroSystemAgentTool(allTools, filteredTools) {
|
|
|
669
625
|
if (!openclaw) return filteredTools;
|
|
670
626
|
return [openclaw, ...filteredTools.filter((tool) => tool.name !== "openclaw")];
|
|
671
627
|
}
|
|
672
|
-
/** Splits sandbox and run session keys so tool calls can bind to both scopes when needed. */
|
|
673
|
-
function resolveOpenClawCodingToolsSessionKeys(params, sandboxSessionKey) {
|
|
674
|
-
return {
|
|
675
|
-
sessionKey: sandboxSessionKey,
|
|
676
|
-
runSessionKey: params.sessionKey && params.sessionKey !== sandboxSessionKey ? params.sessionKey : void 0
|
|
677
|
-
};
|
|
678
|
-
}
|
|
679
628
|
/** Returns the canonical channel used for Codex message routing and receipts. */
|
|
680
629
|
function resolveCodexMessageToolProvider(params) {
|
|
681
630
|
return params.messageChannel ?? params.messageProvider;
|
|
@@ -740,6 +689,10 @@ async function buildDynamicTools(input) {
|
|
|
740
689
|
...params,
|
|
741
690
|
disableMessageTool: false
|
|
742
691
|
} : params;
|
|
692
|
+
const toolRunContext = buildEmbeddedAttemptToolRunContext({
|
|
693
|
+
...params,
|
|
694
|
+
forceMessageTool: shouldForceMessageTool(messagePolicyParams)
|
|
695
|
+
});
|
|
743
696
|
if (params.disableTools) {
|
|
744
697
|
input.onWebSearchPolicyResolved?.(false);
|
|
745
698
|
return [];
|
|
@@ -753,11 +706,11 @@ async function buildDynamicTools(input) {
|
|
|
753
706
|
const modelHasVision = params.model.input?.includes("image") ?? false;
|
|
754
707
|
const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, input.sessionAgentId);
|
|
755
708
|
const injectedOpenClawCodingToolsFactory = dynamicToolBuildState.openClawCodingToolsFactory;
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
709
|
+
const nativeExecutionPolicy = resolveCodexNativeExecutionPolicyForRun(params, {
|
|
710
|
+
agentId: input.policyAgentId,
|
|
711
|
+
runtimeSessionKey: input.sandboxSessionKey,
|
|
712
|
+
sandbox: input.sandbox
|
|
713
|
+
});
|
|
761
714
|
const webSearchPlan = resolveCodexWebSearchPlan({
|
|
762
715
|
config: params.config,
|
|
763
716
|
disableTools: params.disableTools,
|
|
@@ -765,109 +718,114 @@ async function buildDynamicTools(input) {
|
|
|
765
718
|
nativeProviderWebSearchSupport: input.nativeProviderWebSearchSupport
|
|
766
719
|
});
|
|
767
720
|
const webFetchHostnameAllowlistRef = {};
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
config: params.config,
|
|
778
|
-
elevated: params.bashElevated
|
|
779
|
-
},
|
|
780
|
-
sessionPermissionPolicy: input.sessionPermissionPolicy ? {
|
|
781
|
-
mode: input.sessionPermissionPolicy.mode,
|
|
782
|
-
root: input.sessionPermissionPolicy.root
|
|
783
|
-
} : void 0,
|
|
784
|
-
sandbox: input.sandbox,
|
|
785
|
-
...toolConstructionPlan ? { toolConstructionPlan } : {},
|
|
786
|
-
messageProvider: resolveCodexMessageToolProvider(params),
|
|
787
|
-
toolPolicyMessageProvider: params.messageProvider ?? params.messageChannel,
|
|
788
|
-
clientCaps: params.clientCaps,
|
|
789
|
-
chatType: params.chatType,
|
|
790
|
-
agentAccountId: params.agentAccountId,
|
|
791
|
-
messageTo: params.messageTo,
|
|
792
|
-
messageThreadId: params.messageThreadId,
|
|
793
|
-
nativeChannelId: params.chatId,
|
|
794
|
-
messageActionTurnCapability: params.messageActionTurnCapability,
|
|
795
|
-
groupId: params.groupId,
|
|
796
|
-
groupChannel: params.groupChannel,
|
|
797
|
-
groupSpace: params.groupSpace,
|
|
798
|
-
spawnedBy: params.spawnedBy,
|
|
799
|
-
senderId: params.senderId,
|
|
800
|
-
senderName: params.senderName,
|
|
801
|
-
senderUsername: params.senderUsername,
|
|
802
|
-
senderE164: params.senderE164,
|
|
803
|
-
senderIsOwner: params.senderIsOwner,
|
|
804
|
-
inputProvenance: params.inputProvenance,
|
|
805
|
-
trustedInternalHandoff: params.trustedInternalHandoff,
|
|
806
|
-
scheduledToolPolicy: params.scheduledToolPolicy,
|
|
807
|
-
allowGatewaySubagentBinding: params.allowGatewaySubagentBinding || isForcedPrivateQaCodexRuntime(),
|
|
808
|
-
...sessionKeys,
|
|
809
|
-
sessionId: params.sessionId,
|
|
810
|
-
runId: params.runId,
|
|
811
|
-
approvalReviewerDeviceId: params.approvalReviewerDeviceId,
|
|
812
|
-
agentDir,
|
|
813
|
-
preparedModelRuntime: params.preparedModelRuntime,
|
|
814
|
-
cwd: input.effectiveCwd ?? input.effectiveWorkspace,
|
|
815
|
-
workspaceDir: input.effectiveWorkspace,
|
|
816
|
-
spawnWorkspaceDir: input.effectiveCwd && input.effectiveCwd !== input.effectiveWorkspace ? input.resolvedWorkspace : resolveAttemptSpawnWorkspaceDir({
|
|
817
|
-
sandbox: input.sandbox,
|
|
818
|
-
resolvedWorkspace: input.resolvedWorkspace
|
|
819
|
-
}),
|
|
721
|
+
const toolConstructionPlan = resolveCodexNodePlacementToolConstructionPlan(input.sandbox, input.nativeToolSurfaceEnabled);
|
|
722
|
+
const options = {
|
|
723
|
+
agentId: input.sessionAgentId,
|
|
724
|
+
policyAgentId: input.policyAgentId,
|
|
725
|
+
...toolRunContext,
|
|
726
|
+
exec: {
|
|
727
|
+
...params.execOverrides,
|
|
728
|
+
...input.sessionPermissionPolicy ? { mode: input.sessionPermissionPolicy.execMode } : {},
|
|
729
|
+
...resolveCodexNodeExecToolOverrides(nativeExecutionPolicy),
|
|
820
730
|
config: params.config,
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
731
|
+
elevated: params.bashElevated
|
|
732
|
+
},
|
|
733
|
+
sessionPermissionPolicy: input.sessionPermissionPolicy ? {
|
|
734
|
+
mode: input.sessionPermissionPolicy.mode,
|
|
735
|
+
root: input.sessionPermissionPolicy.root
|
|
736
|
+
} : void 0,
|
|
737
|
+
sandbox: input.sandbox,
|
|
738
|
+
...toolConstructionPlan ? { toolConstructionPlan } : {},
|
|
739
|
+
messageProvider: resolveCodexMessageToolProvider(params),
|
|
740
|
+
toolPolicyMessageProvider: params.messageProvider ?? params.messageChannel,
|
|
741
|
+
clientCaps: params.clientCaps,
|
|
742
|
+
chatType: params.chatType,
|
|
743
|
+
agentAccountId: params.agentAccountId,
|
|
744
|
+
messageTo: params.messageTo,
|
|
745
|
+
messageThreadId: params.messageThreadId,
|
|
746
|
+
nativeChannelId: params.chatId,
|
|
747
|
+
messageActionTurnCapability: params.messageActionTurnCapability,
|
|
748
|
+
groupId: params.groupId,
|
|
749
|
+
groupChannel: params.groupChannel,
|
|
750
|
+
groupSpace: params.groupSpace,
|
|
751
|
+
spawnedBy: params.spawnedBy,
|
|
752
|
+
senderId: params.senderId,
|
|
753
|
+
senderName: params.senderName,
|
|
754
|
+
senderUsername: params.senderUsername,
|
|
755
|
+
senderE164: params.senderE164,
|
|
756
|
+
senderIsOwner: params.senderIsOwner,
|
|
757
|
+
inputProvenance: params.inputProvenance,
|
|
758
|
+
trustedInternalHandoff: params.trustedInternalHandoff,
|
|
759
|
+
scheduledToolPolicy: params.scheduledToolPolicy,
|
|
760
|
+
allowGatewaySubagentBinding: params.allowGatewaySubagentBinding || isForcedPrivateQaCodexRuntime(),
|
|
761
|
+
sessionKey: input.sandboxSessionKey,
|
|
762
|
+
runSessionKey: params.sessionKey && params.sessionKey !== input.sandboxSessionKey ? params.sessionKey : void 0,
|
|
763
|
+
sessionId: params.sessionId,
|
|
764
|
+
runId: params.runId,
|
|
765
|
+
approvalReviewerDeviceId: params.approvalReviewerDeviceId,
|
|
766
|
+
agentDir,
|
|
767
|
+
preparedModelRuntime: params.preparedModelRuntime,
|
|
768
|
+
cwd: input.effectiveCwd ?? input.effectiveWorkspace,
|
|
769
|
+
workspaceDir: input.effectiveWorkspace,
|
|
770
|
+
spawnWorkspaceDir: input.effectiveCwd && input.effectiveCwd !== input.effectiveWorkspace ? input.resolvedWorkspace : resolveAttemptSpawnWorkspaceDir({
|
|
771
|
+
sandbox: input.sandbox,
|
|
772
|
+
resolvedWorkspace: input.resolvedWorkspace
|
|
773
|
+
}),
|
|
774
|
+
config: params.config,
|
|
775
|
+
skillsSnapshot: params.skillsSnapshot,
|
|
776
|
+
...params.skillLibraryAuthoring ? { skillWorkshop: { libraryAuthoring: params.skillLibraryAuthoring } } : {},
|
|
777
|
+
githubPublicationAvailable: params.githubPublicationAvailable,
|
|
778
|
+
authProfileStore: params.toolAuthProfileStore ?? params.authProfileStore,
|
|
779
|
+
abortSignal: input.runAbortController.signal,
|
|
780
|
+
emitBeforeToolCallDiagnostics: false,
|
|
781
|
+
modelProvider: params.model.provider,
|
|
782
|
+
modelId: params.modelId,
|
|
783
|
+
modelCompat: params.model.compat && typeof params.model.compat === "object" ? params.model.compat : void 0,
|
|
784
|
+
modelApi: params.model.api,
|
|
785
|
+
modelContextWindowTokens: params.model.contextWindow,
|
|
786
|
+
delegationCapability: params.delegationCapability,
|
|
787
|
+
modelAuthMode: resolveModelAuthMode(params.model.provider, params.config, params.toolAuthProfileStore ?? params.authProfileStore, { workspaceDir: input.effectiveWorkspace }),
|
|
788
|
+
suppressManagedWebSearch: false,
|
|
789
|
+
webFetchHostnameAllowlistRef,
|
|
790
|
+
currentChannelId: params.currentChannelId,
|
|
791
|
+
currentMessagingTarget: params.currentMessagingTarget,
|
|
792
|
+
hookChannelId: resolveCodexAppServerHookChannelId(params, input.sandboxSessionKey),
|
|
793
|
+
currentThreadTs: params.currentThreadTs,
|
|
794
|
+
currentMessageId: params.currentMessageId,
|
|
795
|
+
replyToMode: params.replyToMode,
|
|
796
|
+
hasRepliedRef: params.hasRepliedRef,
|
|
797
|
+
modelHasVision,
|
|
798
|
+
computerContextEpoch: input.computerContextEpoch,
|
|
799
|
+
registerRunCleanup: input.registerRunCleanup,
|
|
800
|
+
requireExplicitMessageTarget: params.requireExplicitMessageTarget ?? isSubagentSessionKey(params.sessionKey),
|
|
801
|
+
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
|
802
|
+
taskSuggestionDeliveryMode: params.taskSuggestionDeliveryMode,
|
|
803
|
+
disableMessageTool: input.ignoreDisableMessageTool ? false : params.disableMessageTool,
|
|
804
|
+
forceMessageTool: shouldForceMessageTool(messagePolicyParams),
|
|
805
|
+
enableHeartbeatTool: params.trigger === "heartbeat" || input.forceHeartbeatTool === true,
|
|
806
|
+
forceHeartbeatTool: params.trigger === "heartbeat" || input.forceHeartbeatTool === true,
|
|
807
|
+
onYield: (message, acknowledgment) => {
|
|
808
|
+
input.onYieldDetected(acknowledgment);
|
|
809
|
+
input.onCodexAppServerEvent?.({
|
|
810
|
+
stream: "codex_app_server.tool",
|
|
811
|
+
data: {
|
|
812
|
+
name: "sessions_yield",
|
|
813
|
+
message
|
|
814
|
+
}
|
|
815
|
+
});
|
|
816
|
+
},
|
|
817
|
+
claimYieldCompletion: input.claimYieldCompletion,
|
|
818
|
+
recordToolPrepStage: (name) => {
|
|
819
|
+
toolBuildStages.mark(name);
|
|
820
|
+
},
|
|
821
|
+
onToolOutcome: params.onToolOutcome,
|
|
822
|
+
isTurnTainted: params.isTurnTainted,
|
|
823
|
+
allocateToolOutcomeOrdinal: params.allocateToolOutcomeOrdinal,
|
|
824
|
+
cronCreatorToolAllowlistRef: input.cronCreatorToolAllowlistRef,
|
|
825
|
+
cronCreatorToolAllowlistCaptureRef: input.cronCreatorToolAllowlistCaptureRef,
|
|
826
|
+
cronCreatorAuthorityUnavailableReason: input.cronCreatorAuthorityUnavailableReason
|
|
827
|
+
};
|
|
828
|
+
const buildOpenClawCodingTools = () => {
|
|
871
829
|
const bindingOptions = { cwd: input.effectiveCwd ?? input.effectiveWorkspace };
|
|
872
830
|
if (injectedOpenClawCodingToolsFactory) return params.hostCapabilities.bindToolSurface(injectedOpenClawCodingToolsFactory(options), bindingOptions);
|
|
873
831
|
const createToolSurface = params.hostCapabilities.createToolSurface;
|
|
@@ -887,7 +845,7 @@ async function buildDynamicTools(input) {
|
|
|
887
845
|
const readableAllTools = [...readableAllToolProjection.tools];
|
|
888
846
|
const normallyProfiledTools = input.nativeToolSurfaceEnabled === false ? filterCodexDynamicToolsForDisabledNativeSurface(readableAllTools, input.pluginConfig, { preserveShell: shouldKeepOpenClawShellDynamicTools(input, nativeExecutionPolicy) }) : filterCodexDynamicTools(readableAllTools, input.pluginConfig);
|
|
889
847
|
const profileFilteredTools = (input.isHostScopedToolActive?.("openclaw") ?? isHostScopedAgentToolActive("openclaw")) && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow) ? preserveRingZeroSystemAgentTool(readableAllTools, normallyProfiledTools) : normallyProfiledTools;
|
|
890
|
-
const codexFilteredTools = addNodeShellDynamicToolsIfNeeded(addGatewayShellDynamicToolsIfAvailable(addSandboxShellDynamicToolsIfAvailable(isCodexMemoryFlushRun(params) ? filterCodexMemoryFlushDynamicTools(readableAllTools) : profileFilteredTools, readableAllTools, input), readableAllTools, input, nativeExecutionPolicy), readableAllTools, input, nativeExecutionPolicy);
|
|
848
|
+
const codexFilteredTools = await addNodeShellDynamicToolsIfNeeded(addGatewayShellDynamicToolsIfAvailable(addSandboxShellDynamicToolsIfAvailable(isCodexMemoryFlushRun(params) ? filterCodexMemoryFlushDynamicTools(readableAllTools) : profileFilteredTools, readableAllTools, input, nativeExecutionPolicy), readableAllTools, input, nativeExecutionPolicy), readableAllTools, input, nativeExecutionPolicy);
|
|
891
849
|
toolBuildStages.mark("codex-filtering");
|
|
892
850
|
const visionFilteredTools = filterCodexVisionTools(codexFilteredTools, {
|
|
893
851
|
modelHasVision,
|
|
@@ -896,33 +854,33 @@ async function buildDynamicTools(input) {
|
|
|
896
854
|
toolBuildStages.mark("vision-filtering");
|
|
897
855
|
const webSearchPresent = visionFilteredTools.some((tool) => tool.name === "web_search");
|
|
898
856
|
const persistentCodexWebSearchSurface = params.config?.tools?.web?.search?.enabled !== false && !(input.pluginConfig.codexDynamicToolsExclude ?? []).some((name) => normalizeCodexDynamicToolName(name) === "web_search");
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
input.onPersistentWebSearchPolicyResolved?.(
|
|
925
|
-
const filteredTools = filterCodexDynamicToolsForAllowlist(visionFilteredTools,
|
|
857
|
+
let persistentWebSearchAllowed = webSearchPresent;
|
|
858
|
+
if (input.onPersistentWebSearchPolicyResolved && !webSearchPresent && persistentCodexWebSearchSurface) {
|
|
859
|
+
const webSearchPolicy = (await import("openclaw/plugin-sdk/agent-harness")).resolveWebSearchToolPolicy({
|
|
860
|
+
config: params.config,
|
|
861
|
+
modelProvider: params.model.provider,
|
|
862
|
+
modelId: params.modelId,
|
|
863
|
+
agentId: input.policyAgentId,
|
|
864
|
+
sessionKey: input.sandboxSessionKey,
|
|
865
|
+
sandboxToolPolicy: input.sandbox?.tools,
|
|
866
|
+
messageProvider: resolveCodexMessageToolProvider(params),
|
|
867
|
+
agentAccountId: params.agentAccountId,
|
|
868
|
+
groupId: params.groupId,
|
|
869
|
+
groupChannel: params.groupChannel,
|
|
870
|
+
groupSpace: params.groupSpace,
|
|
871
|
+
spawnedBy: params.spawnedBy,
|
|
872
|
+
senderId: params.senderId,
|
|
873
|
+
senderName: params.senderName,
|
|
874
|
+
senderUsername: params.senderUsername,
|
|
875
|
+
senderE164: params.senderE164,
|
|
876
|
+
inputProvenance: params.inputProvenance,
|
|
877
|
+
trustedInternalHandoff: params.trustedInternalHandoff,
|
|
878
|
+
scheduledToolPolicy: params.scheduledToolPolicy
|
|
879
|
+
});
|
|
880
|
+
persistentWebSearchAllowed = webSearchPolicy.persistentAllowed && (!webSearchPolicy.allowed || isCodexMemoryFlushRun(params));
|
|
881
|
+
}
|
|
882
|
+
input.onPersistentWebSearchPolicyResolved?.(persistentWebSearchAllowed);
|
|
883
|
+
const filteredTools = filterCodexDynamicToolsForAllowlist(visionFilteredTools, toolRunContext.runtimeToolAllowlist);
|
|
926
884
|
toolBuildStages.mark("allowlist-filter");
|
|
927
885
|
const normalizedTools = normalizeAgentRuntimeTools({
|
|
928
886
|
runtimePlan: input.ignoreRuntimePlan ? void 0 : params.runtimePlan,
|
|
@@ -941,7 +899,7 @@ async function buildDynamicTools(input) {
|
|
|
941
899
|
const webSearchAllowed = normalizedTools.some((tool) => tool.name === "web_search");
|
|
942
900
|
webFetchHostnameAllowlistRef.value = webSearchAllowed ? webSearchPlan.webFetchHostnameAllowlist : void 0;
|
|
943
901
|
input.onWebSearchPolicyResolved?.(webSearchAllowed);
|
|
944
|
-
const exposedTools = webSearchPlan.suppressManagedWebSearch ? normalizedTools.filter((tool) => tool.name !== "web_search") : normalizedTools;
|
|
902
|
+
const exposedTools = placeDisabledNativeShellToolsInDirectNamespace(webSearchPlan.suppressManagedWebSearch ? normalizedTools.filter((tool) => tool.name !== "web_search") : normalizedTools, input.nativeToolSurfaceEnabled);
|
|
945
903
|
if (preNormalizationDiagnostics.length > 0) embeddedAgentLog.warn(`codex app-server quarantined ${preNormalizationDiagnostics.length} unsupported runtime tool schema${preNormalizationDiagnostics.length === 1 ? "" : "s"} before dynamic tool registration`, {
|
|
946
904
|
runId: params.runId,
|
|
947
905
|
sessionId: params.sessionId,
|
|
@@ -983,49 +941,39 @@ function addGatewayShellDynamicToolsIfAvailable(filteredTools, allTools, input,
|
|
|
983
941
|
if (!execTool || execExcluded || existingNames.has("gateway_exec")) return filteredTools;
|
|
984
942
|
const processExcluded = isCodexDynamicToolExcluded(input.pluginConfig, ["process", CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME]);
|
|
985
943
|
const processAliasAvailable = Boolean(processTool && !processExcluded && !existingNames.has("gateway_process"));
|
|
986
|
-
const
|
|
987
|
-
|
|
944
|
+
const createProjection = resolveCodexScheduledToolProjectionFactory(input.params.hostCapabilities);
|
|
945
|
+
if (!createProjection) return filteredTools;
|
|
946
|
+
const toolsToAppend = [createGatewayExecProjection(createProjection, execTool, {
|
|
988
947
|
processAliasAvailable,
|
|
989
948
|
...input.sessionPermissionPolicy?.mode === "guarded" ? { ask: "always" } : {}
|
|
990
949
|
})];
|
|
991
|
-
if (processAliasAvailable && processTool) toolsToAppend.push(
|
|
950
|
+
if (processAliasAvailable && processTool) toolsToAppend.push(createGatewayProcessProjection(createProjection, processTool));
|
|
992
951
|
return [...filteredTools, ...toolsToAppend];
|
|
993
952
|
}
|
|
994
|
-
/** Preserves delivery-critical tools when a narrow allowlist would otherwise hide them. */
|
|
995
|
-
function includeForcedCodexDynamicToolAllow(toolsAllow, params) {
|
|
996
|
-
if (toolsAllow === void 0 || hasWildcardCodexToolsAllow(toolsAllow)) return toolsAllow;
|
|
997
|
-
const forcedToolNames = shouldForceMessageTool(params) ? ["message"] : [];
|
|
998
|
-
if (forcedToolNames.length === 0) return toolsAllow;
|
|
999
|
-
if (toolsAllow.length === 0) return forcedToolNames;
|
|
1000
|
-
const normalized = new Set(toolsAllow.map((name) => normalizeCodexDynamicToolName(name)));
|
|
1001
|
-
const missingToolNames = forcedToolNames.filter((toolName) => !normalized.has(normalizeCodexDynamicToolName(toolName)));
|
|
1002
|
-
return missingToolNames.length === 0 ? toolsAllow : [...toolsAllow, ...missingToolNames];
|
|
1003
|
-
}
|
|
1004
953
|
/** Decides whether Codex native code mode can own shell/file tools for this turn. */
|
|
1005
954
|
function shouldEnableCodexAppServerNativeToolSurface(params, sandbox, options = {}) {
|
|
1006
955
|
if (params.pluginHarnessToolPolicyRestricted === true) return false;
|
|
1007
956
|
if (isCodexMemoryFlushRun(params)) return false;
|
|
1008
957
|
if (params.disableTools) return false;
|
|
1009
|
-
if (
|
|
958
|
+
if (!resolveCodexNativeExecutionPolicyForRun(params, {
|
|
1010
959
|
agentId: options.agentId,
|
|
1011
960
|
runtimeSessionKey: options.runtimeSessionKey,
|
|
1012
961
|
sandbox
|
|
1013
|
-
})) return false;
|
|
1014
|
-
const toolsAllow =
|
|
962
|
+
}).nativeToolSurfaceAllowed) return false;
|
|
963
|
+
const toolsAllow = params.toolsAllow;
|
|
1015
964
|
if (toolsAllow === void 0) return canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
|
|
1016
965
|
return hasWildcardCodexToolsAllow(toolsAllow) && canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
|
|
1017
966
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
return !resolveCodexNativeExecutionPolicy({
|
|
967
|
+
function resolveCodexNativeExecutionPolicyForRun(params, options = {}) {
|
|
968
|
+
return resolveCodexNativeExecutionPolicy({
|
|
1021
969
|
config: params.config,
|
|
1022
970
|
sessionKey: resolveCodexRuntimePolicySessionKey(params, options.runtimeSessionKey),
|
|
1023
971
|
sessionId: params.sessionId,
|
|
1024
972
|
agentId: options.agentId,
|
|
1025
973
|
execOverrides: params.execOverrides,
|
|
1026
|
-
sandboxAvailable: options.sandbox?.enabled,
|
|
974
|
+
sandboxAvailable: options.sandbox === null ? false : options.sandbox?.enabled,
|
|
1027
975
|
readRuntimeSessionEntry: true
|
|
1028
|
-
})
|
|
976
|
+
});
|
|
1029
977
|
}
|
|
1030
978
|
function resolveCodexRuntimePolicySessionKey(params, runtimeSessionKey) {
|
|
1031
979
|
return runtimeSessionKey?.trim() || params.sandboxSessionKey?.trim() || params.sessionKey?.trim() || params.sessionId;
|
|
@@ -1088,8 +1036,8 @@ function disableCodexPluginThreadConfig(pluginConfig) {
|
|
|
1088
1036
|
};
|
|
1089
1037
|
}
|
|
1090
1038
|
/** Adds sandbox_exec/process aliases when native Code Mode cannot directly honor the sandbox. */
|
|
1091
|
-
function addSandboxShellDynamicToolsIfAvailable(filteredTools, allTools, input) {
|
|
1092
|
-
if (
|
|
1039
|
+
function addSandboxShellDynamicToolsIfAvailable(filteredTools, allTools, input, executionPolicy) {
|
|
1040
|
+
if (isCodexMemoryFlushRun(input.params) || !executionPolicy.nativeToolSurfaceAllowed || !input.sandbox?.enabled || !input.sandbox.backendId.trim() || input.nativeToolSurfaceEnabled !== false || isSandboxShellDynamicToolExcluded(input.pluginConfig)) return filteredTools;
|
|
1093
1041
|
const execTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "exec");
|
|
1094
1042
|
const processTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "process");
|
|
1095
1043
|
if (!execTool || !processTool) return filteredTools;
|
|
@@ -1116,16 +1064,6 @@ function addSandboxShellDynamicToolsIfAvailable(filteredTools, allTools, input)
|
|
|
1116
1064
|
sandboxProcessTool
|
|
1117
1065
|
];
|
|
1118
1066
|
}
|
|
1119
|
-
function shouldExposeSandboxExecDynamicTool(input) {
|
|
1120
|
-
if (isCodexMemoryFlushRun(input.params)) return false;
|
|
1121
|
-
if (isCodexNativeExecutionBlockedByNodeExecHost(input.params, {
|
|
1122
|
-
agentId: input.sessionAgentId,
|
|
1123
|
-
runtimeSessionKey: input.sandboxSessionKey,
|
|
1124
|
-
sandbox: input.sandbox
|
|
1125
|
-
})) return false;
|
|
1126
|
-
const backendId = input.sandbox?.enabled ? input.sandbox.backendId.trim().toLowerCase() : "";
|
|
1127
|
-
return Boolean(backendId && input.nativeToolSurfaceEnabled === false);
|
|
1128
|
-
}
|
|
1129
1067
|
function isSandboxShellDynamicToolExcluded(config) {
|
|
1130
1068
|
return isCodexDynamicToolExcluded(config, [
|
|
1131
1069
|
"exec",
|
|
@@ -1134,32 +1072,24 @@ function isSandboxShellDynamicToolExcluded(config) {
|
|
|
1134
1072
|
"sandbox_process"
|
|
1135
1073
|
]);
|
|
1136
1074
|
}
|
|
1137
|
-
function addNodeShellDynamicToolsIfNeeded(filteredTools, allTools, input, nodePolicy) {
|
|
1075
|
+
async function addNodeShellDynamicToolsIfNeeded(filteredTools, allTools, input, nodePolicy) {
|
|
1138
1076
|
if (isCodexMemoryFlushRun(input.params)) return filteredTools;
|
|
1139
1077
|
const nodeExecIsDefault = nodePolicy.effectiveExecHost === "node";
|
|
1140
1078
|
const nodeExecAvailableFromAuto = nodePolicy.requestedExecHost === "auto" && nodePolicy.effectiveExecHost === "gateway";
|
|
1141
1079
|
if (!nodeExecIsDefault && !nodeExecAvailableFromAuto) return filteredTools;
|
|
1142
1080
|
const execTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "exec");
|
|
1143
|
-
if (!execTool) return filteredTools;
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
node: nodePolicy.node
|
|
1147
|
-
})];
|
|
1148
|
-
return filteredTools;
|
|
1081
|
+
if (!execTool || isCodexDynamicToolExcluded(input.pluginConfig, ["exec", "node_exec"]) || filteredTools.some((tool) => normalizeCodexDynamicToolName(tool.name) === "node_exec")) return filteredTools;
|
|
1082
|
+
const nodeExec = await createNodeExecAliasDynamicTool(execTool, nodePolicy.node, input.runAbortController.signal, input.nodeExecAvailability);
|
|
1083
|
+
return nodeExec ? [...filteredTools, nodeExec] : filteredTools;
|
|
1149
1084
|
}
|
|
1150
1085
|
function shouldKeepOpenClawShellDynamicTools(input, nodePolicy) {
|
|
1151
1086
|
return !isCodexMemoryFlushRun(input.params) && input.nativeToolSurfaceEnabled === false && input.sandbox?.enabled !== true && nodePolicy.effectiveExecHost !== "node";
|
|
1152
1087
|
}
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
agentId: input.sessionAgentId,
|
|
1159
|
-
execOverrides: input.params.execOverrides,
|
|
1160
|
-
sandboxAvailable: input.sandbox?.enabled,
|
|
1161
|
-
readRuntimeSessionEntry: true
|
|
1162
|
-
});
|
|
1088
|
+
/** Keeps replacement shell tools direct even when model metadata mandates Codex Code Mode. */
|
|
1089
|
+
function placeDisabledNativeShellToolsInDirectNamespace(tools, nativeToolSurfaceEnabled) {
|
|
1090
|
+
if (nativeToolSurfaceEnabled !== false) return tools;
|
|
1091
|
+
for (const tool of tools) if (CODEX_DISABLED_NATIVE_SHELL_DYNAMIC_TOOLS.has(normalizeCodexDynamicToolName(tool.name))) tool.catalogMode = "direct-only";
|
|
1092
|
+
return tools;
|
|
1163
1093
|
}
|
|
1164
1094
|
/** Applies a normalized tool allowlist while preserving shell aliases for exec/process. */
|
|
1165
1095
|
function filterCodexDynamicToolsForAllowlist(tools, toolsAllow) {
|
|
@@ -1182,9 +1112,9 @@ function shouldForceMessageTool(params) {
|
|
|
1182
1112
|
}
|
|
1183
1113
|
//#endregion
|
|
1184
1114
|
//#region extensions/codex/src/app-server/sandbox-exec-server-node-relay.ts
|
|
1185
|
-
const CODEX_NODE_EXEC_SERVER_MAX_MESSAGE_BYTES$1 =
|
|
1115
|
+
const CODEX_NODE_EXEC_SERVER_MAX_MESSAGE_BYTES$1 = 67108864;
|
|
1186
1116
|
const CODEX_NODE_EXEC_SERVER_MAX_FAILURE_DETAIL_CHARS = 240;
|
|
1187
|
-
const CODEX_NODE_HTTP_CREDENTIAL_BODY_MAX_BYTES =
|
|
1117
|
+
const CODEX_NODE_HTTP_CREDENTIAL_BODY_MAX_BYTES = 1048576;
|
|
1188
1118
|
const CODEX_NODE_HTTP_CREDENTIAL_SCAN_MAX_FIELDS = 256;
|
|
1189
1119
|
const CODEX_NODE_HTTP_CREDENTIAL_SCAN_MAX_DEPTH = 8;
|
|
1190
1120
|
const CODEX_NODE_HTTP_CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -1824,10 +1754,10 @@ function joinSandboxChildPath(parent, child) {
|
|
|
1824
1754
|
* Implements filesystem JSON-RPC handlers for the Codex sandbox exec-server
|
|
1825
1755
|
* with OpenClaw sandbox policy checks before every bridge operation.
|
|
1826
1756
|
*/
|
|
1827
|
-
const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES =
|
|
1757
|
+
const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES = 536870912;
|
|
1828
1758
|
const CODEX_SANDBOX_EXEC_SERVER_MAX_OPEN_FILE_READS = 128;
|
|
1829
|
-
const CODEX_SANDBOX_EXEC_SERVER_MAX_BUFFERED_FILE_READ_BYTES =
|
|
1830
|
-
const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_BLOCK_BYTES =
|
|
1759
|
+
const CODEX_SANDBOX_EXEC_SERVER_MAX_BUFFERED_FILE_READ_BYTES = 67108864;
|
|
1760
|
+
const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_BLOCK_BYTES = 1048576;
|
|
1831
1761
|
const CODEX_SANDBOX_EXEC_SERVER_MAX_FILE_READ_HANDLE_ID_BYTES = 32;
|
|
1832
1762
|
/** Opens a policy-checked sandbox file under a bounded, connection-owned handle. */
|
|
1833
1763
|
async function openFile(execServer, handles, params) {
|
|
@@ -2231,7 +2161,7 @@ function delay(ms) {
|
|
|
2231
2161
|
* access through the active OpenClaw sandbox backend.
|
|
2232
2162
|
*/
|
|
2233
2163
|
/** Maximum JSON-line size accepted from the streaming HTTP helper process. */
|
|
2234
|
-
const SANDBOX_HTTP_STREAM_LINE_MAX_CHARS =
|
|
2164
|
+
const SANDBOX_HTTP_STREAM_LINE_MAX_CHARS = 262144;
|
|
2235
2165
|
/** Handles one sandbox HTTP JSON-RPC request, optionally streaming response body deltas. */
|
|
2236
2166
|
async function httpRequest(execServer, notifications, params) {
|
|
2237
2167
|
const record = requireObject(params, "http/request params");
|
|
@@ -2543,6 +2473,9 @@ def assert_url_allowed(url):
|
|
|
2543
2473
|
PINNED_ADDRESSES[hostname] = sorted(addresses)
|
|
2544
2474
|
|
|
2545
2475
|
class GuardedRedirectHandler(urllib.request.HTTPRedirectHandler):
|
|
2476
|
+
# Python 3.9 lacks the 308 dispatch alias; use the same guarded redirect path.
|
|
2477
|
+
http_error_308 = urllib.request.HTTPRedirectHandler.http_error_302
|
|
2478
|
+
|
|
2546
2479
|
def __init__(self, redirect_policy):
|
|
2547
2480
|
self.redirect_policy = redirect_policy
|
|
2548
2481
|
|
|
@@ -2656,7 +2589,7 @@ python3 "$tmp"
|
|
|
2656
2589
|
* termination for Codex sandbox exec-server process RPCs.
|
|
2657
2590
|
*/
|
|
2658
2591
|
const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
2659
|
-
const RETAINED_PROCESS_OUTPUT_BYTES =
|
|
2592
|
+
const RETAINED_PROCESS_OUTPUT_BYTES = 1048576;
|
|
2660
2593
|
const CLOSED_PROCESS_EVICTION_MS = 6e4;
|
|
2661
2594
|
/** Starts a sandbox-backed process and registers it in the connection-local process table. */
|
|
2662
2595
|
async function startProcess(execServer, processes, notify, params) {
|
|
@@ -2913,10 +2846,11 @@ function readEnv(value) {
|
|
|
2913
2846
|
return env;
|
|
2914
2847
|
}
|
|
2915
2848
|
function readProcessEnv(record) {
|
|
2916
|
-
|
|
2849
|
+
const requestedEnv = {
|
|
2917
2850
|
...buildEnvFromPolicy(record.envPolicy),
|
|
2918
2851
|
...readEnv(record.env)
|
|
2919
|
-
}
|
|
2852
|
+
};
|
|
2853
|
+
return sanitizeEnvVars(requestedEnv).allowed;
|
|
2920
2854
|
}
|
|
2921
2855
|
function buildEnvFromPolicy(value) {
|
|
2922
2856
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
@@ -3031,8 +2965,8 @@ var CodexSandboxExecSession = class {
|
|
|
3031
2965
|
* Hosts the local OpenClaw sandbox exec-server that Codex app-server native
|
|
3032
2966
|
* execution can register as an external environment.
|
|
3033
2967
|
*/
|
|
3034
|
-
const CODEX_SANDBOX_EXEC_SERVER_MAX_INBOUND_MESSAGE_BYTES =
|
|
3035
|
-
const CODEX_NODE_EXEC_SERVER_MAX_MESSAGE_BYTES =
|
|
2968
|
+
const CODEX_SANDBOX_EXEC_SERVER_MAX_INBOUND_MESSAGE_BYTES = 104857600;
|
|
2969
|
+
const CODEX_NODE_EXEC_SERVER_MAX_MESSAGE_BYTES = 67108864;
|
|
3036
2970
|
const codexNodeExecServerLeases = /* @__PURE__ */ new WeakMap();
|
|
3037
2971
|
/** Starts or reuses a sandbox exec-server and registers it with Codex app-server. */
|
|
3038
2972
|
async function ensureCodexSandboxExecServerEnvironment(params) {
|
|
@@ -3323,52 +3257,6 @@ async function handleMessage(session, data) {
|
|
|
3323
3257
|
await session.handleRequest(parseRequest(buffer.toString("utf8")));
|
|
3324
3258
|
}
|
|
3325
3259
|
//#endregion
|
|
3326
|
-
//#region extensions/codex/src/app-server/provider-capabilities.ts
|
|
3327
|
-
function resolveOverriddenProviderWebSearchSupport(modelProviderOverride) {
|
|
3328
|
-
const provider = modelProviderOverride?.trim().toLowerCase();
|
|
3329
|
-
if (!provider) return;
|
|
3330
|
-
return provider === "openai" ? "supported" : "unsupported";
|
|
3331
|
-
}
|
|
3332
|
-
async function readConfiguredProviderWebSearchSupport(params) {
|
|
3333
|
-
return (await params.client.request("modelProvider/capabilities/read", {}, {
|
|
3334
|
-
timeoutMs: params.timeoutMs,
|
|
3335
|
-
signal: params.signal
|
|
3336
|
-
})).webSearch ? "supported" : "unsupported";
|
|
3337
|
-
}
|
|
3338
|
-
async function resolveCodexProviderWebSearchSupportForClient(params) {
|
|
3339
|
-
const overrideSupport = resolveOverriddenProviderWebSearchSupport(params.modelProviderOverride);
|
|
3340
|
-
if (overrideSupport) return overrideSupport;
|
|
3341
|
-
try {
|
|
3342
|
-
return await readConfiguredProviderWebSearchSupport(params);
|
|
3343
|
-
} catch {
|
|
3344
|
-
return "unknown";
|
|
3345
|
-
}
|
|
3346
|
-
}
|
|
3347
|
-
async function resolveCodexProviderWebSearchSupport(params) {
|
|
3348
|
-
const overrideSupport = resolveOverriddenProviderWebSearchSupport(params.modelProviderOverride);
|
|
3349
|
-
if (overrideSupport) return overrideSupport;
|
|
3350
|
-
let client;
|
|
3351
|
-
try {
|
|
3352
|
-
client = await params.clientFactory({
|
|
3353
|
-
startOptions: params.appServer.start,
|
|
3354
|
-
...params.preparedAuth ? { preparedAuth: params.preparedAuth } : { authProfileId: params.authProfileId },
|
|
3355
|
-
agentDir: params.agentDir,
|
|
3356
|
-
config: params.config,
|
|
3357
|
-
timeoutMs: params.appServer.requestTimeoutMs
|
|
3358
|
-
});
|
|
3359
|
-
return await resolveCodexProviderWebSearchSupportForClient({
|
|
3360
|
-
client,
|
|
3361
|
-
timeoutMs: params.appServer.requestTimeoutMs,
|
|
3362
|
-
modelProviderOverride: params.modelProviderOverride,
|
|
3363
|
-
signal: params.signal
|
|
3364
|
-
});
|
|
3365
|
-
} catch {
|
|
3366
|
-
return "unknown";
|
|
3367
|
-
} finally {
|
|
3368
|
-
if (client) releaseLeasedSharedCodexAppServerClient(client);
|
|
3369
|
-
}
|
|
3370
|
-
}
|
|
3371
|
-
//#endregion
|
|
3372
3260
|
//#region extensions/codex/src/app-server/approval-bridge.ts
|
|
3373
3261
|
/**
|
|
3374
3262
|
* Bridges Codex app-server approval requests into OpenClaw policy hooks and
|
|
@@ -3413,6 +3301,8 @@ async function handleCodexAppServerApprovalRequest(params) {
|
|
|
3413
3301
|
resolvedOutcome = "approved-once";
|
|
3414
3302
|
resolvedMessage = "Codex app-server approval granted for this byte-bound command only.";
|
|
3415
3303
|
}
|
|
3304
|
+
params.signal?.throwIfAborted();
|
|
3305
|
+
if (resolvedOutcome !== "denied") params.paramsForRun.hostCapabilities.assertActive();
|
|
3416
3306
|
emitApprovalEvent(params.paramsForRun, {
|
|
3417
3307
|
phase: "resolved",
|
|
3418
3308
|
kind: context.kind,
|
|
@@ -3451,6 +3341,7 @@ async function handleCodexAppServerApprovalRequest(params) {
|
|
|
3451
3341
|
autoApprove: params.autoApprove,
|
|
3452
3342
|
signal: params.signal
|
|
3453
3343
|
});
|
|
3344
|
+
params.signal?.throwIfAborted();
|
|
3454
3345
|
if (policyOutcome?.outcome === "denied") {
|
|
3455
3346
|
recordNativeToolFailureDisposition(params, context, policyOutcome.failureDisposition);
|
|
3456
3347
|
return await resolvePolicyApproval("denied", policyOutcome.reason);
|
|
@@ -3459,6 +3350,7 @@ async function handleCodexAppServerApprovalRequest(params) {
|
|
|
3459
3350
|
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.");
|
|
3460
3351
|
const requestResult = await requestPluginApproval({
|
|
3461
3352
|
hostCapabilities: params.paramsForRun.hostCapabilities,
|
|
3353
|
+
signal: params.signal,
|
|
3462
3354
|
title: context.title,
|
|
3463
3355
|
description: context.description,
|
|
3464
3356
|
severity: context.severity,
|
|
@@ -3972,7 +3864,8 @@ function summarizeNetworkPolicyAmendments(value) {
|
|
|
3972
3864
|
function sanitizePermissionHostValue(value) {
|
|
3973
3865
|
const withoutScheme = sanitizePermissionScalar(value).toLowerCase().replace(/^[a-z][a-z0-9+.-]*:\/\//, "");
|
|
3974
3866
|
const authority = withoutScheme.split(/[/?#]/, 1)[0] ?? withoutScheme;
|
|
3975
|
-
|
|
3867
|
+
const withoutUserInfo = authority.includes("@") ? authority.slice(authority.lastIndexOf("@") + 1) : authority;
|
|
3868
|
+
return truncateCodexApprovalDisplayText(withoutUserInfo, PERMISSION_VALUE_MAX_LENGTH);
|
|
3976
3869
|
}
|
|
3977
3870
|
function sanitizePermissionPathValue(value) {
|
|
3978
3871
|
return truncateCodexApprovalDisplayText(formatApprovalDisplayPath(sanitizePermissionScalar(value)), PERMISSION_VALUE_MAX_LENGTH);
|
|
@@ -4101,7 +3994,8 @@ function appendPreviewPart(source, part, separator) {
|
|
|
4101
3994
|
}
|
|
4102
3995
|
function sanitizeApprovalPreview(source, maxLength) {
|
|
4103
3996
|
if (!source || !source.value) return { omitted: false };
|
|
4104
|
-
const
|
|
3997
|
+
const rawPreview = stripDanglingCodexApprovalTerminalSequence(source.value);
|
|
3998
|
+
const sanitized = sanitizeCodexApprovalVisibleText(rawPreview);
|
|
4105
3999
|
if (!sanitized) return { omitted: true };
|
|
4106
4000
|
return {
|
|
4107
4001
|
text: formatCodexDisplayText(truncateCodexApprovalDisplayText(sanitized, maxLength)),
|
|
@@ -4246,6 +4140,7 @@ async function routeCodexAppServerElicitationRequest(params) {
|
|
|
4246
4140
|
const requestTurnId = requestParams.turnId;
|
|
4247
4141
|
if (requestTurnId !== null && requestTurnId !== void 0 && requestTurnId !== params.turnId) return { kind: "not-mine" };
|
|
4248
4142
|
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" };
|
|
4143
|
+
if (params.signal?.aborted) return handled(createCodexElicitationResponse("cancel"));
|
|
4249
4144
|
const pluginResolution = resolvePluginElicitation({
|
|
4250
4145
|
requestParams,
|
|
4251
4146
|
pluginAppPolicyContext: params.pluginAppPolicyContext
|
|
@@ -4270,16 +4165,63 @@ async function routeCodexAppServerElicitationRequest(params) {
|
|
|
4270
4165
|
signal: params.signal
|
|
4271
4166
|
}));
|
|
4272
4167
|
}
|
|
4273
|
-
const
|
|
4168
|
+
const computerUsePrompt = readComputerUseApprovalElicitation(requestParams, params.computerUseMcpServerName);
|
|
4169
|
+
const approvalPrompt = computerUsePrompt ?? readBridgeableApprovalElicitation(requestParams);
|
|
4274
4170
|
if (!approvalPrompt) return handled(createCodexElicitationResponse("decline"));
|
|
4171
|
+
let persistence;
|
|
4172
|
+
if (!computerUsePrompt) {
|
|
4173
|
+
const serverName = readNonBlankStringField(requestParams, "serverName");
|
|
4174
|
+
const server = serverName ? params.paramsForRun.config?.mcp?.servers?.[serverName] : void 0;
|
|
4175
|
+
const mode = serverName ? resolveProjectedMcpCodexToolApprovalMode(serverName, server ?? {}, params.projectedMcpServers?.[serverName]) : void 0;
|
|
4176
|
+
if (!requiresMcpCodexToolApproval({
|
|
4177
|
+
mode,
|
|
4178
|
+
fullPermission: params.autoApproveMcpTools
|
|
4179
|
+
})) {
|
|
4180
|
+
params.paramsForRun.hostCapabilities.assertActive();
|
|
4181
|
+
return handled(buildElicitationResponse(approvalPrompt, "approved-once"));
|
|
4182
|
+
}
|
|
4183
|
+
if (mode === "prompt") approvalPrompt.allowedDecisions = ["allow-once", "deny"];
|
|
4184
|
+
else if (serverName && serverName !== CODEX_APPS_SERVER_NAME && Object.hasOwn(params.paramsForRun.config?.mcp?.servers ?? {}, serverName) && requestTurnId === params.turnId && readPersistHints(approvalPrompt.meta, "explicit").includes("always")) {
|
|
4185
|
+
const resolveItem = () => {
|
|
4186
|
+
const item = params.getActiveMcpToolCall?.(serverName);
|
|
4187
|
+
return item?.server === serverName && matchesMcpApprovalDisplay(item, approvalPrompt.meta) ? item : void 0;
|
|
4188
|
+
};
|
|
4189
|
+
const item = resolveItem();
|
|
4190
|
+
if (item) persistence = {
|
|
4191
|
+
mcpTool: {
|
|
4192
|
+
server: serverName,
|
|
4193
|
+
tool: item.tool
|
|
4194
|
+
},
|
|
4195
|
+
toolCallId: item.id,
|
|
4196
|
+
isMcpToolApprovalActive: () => {
|
|
4197
|
+
const current = resolveItem();
|
|
4198
|
+
return current?.id === item.id && current.tool === item.tool;
|
|
4199
|
+
}
|
|
4200
|
+
};
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4275
4203
|
return handled(buildElicitationResponse(approvalPrompt, await requestPluginApprovalOutcome({
|
|
4276
|
-
|
|
4204
|
+
hostCapabilities: params.paramsForRun.hostCapabilities,
|
|
4277
4205
|
title: approvalPrompt.title,
|
|
4278
4206
|
description: approvalPrompt.description,
|
|
4279
4207
|
allowedDecisions: approvalPrompt.allowedDecisions,
|
|
4208
|
+
toolName: "codex_mcp_tool_approval",
|
|
4209
|
+
...persistence,
|
|
4280
4210
|
signal: params.signal
|
|
4281
4211
|
})));
|
|
4282
4212
|
}
|
|
4213
|
+
function matchesMcpApprovalDisplay(item, meta) {
|
|
4214
|
+
if (!Object.hasOwn(meta, MCP_TOOL_APPROVAL_TOOL_PARAMS_DISPLAY_KEY)) return true;
|
|
4215
|
+
const display = meta[MCP_TOOL_APPROVAL_TOOL_PARAMS_DISPLAY_KEY];
|
|
4216
|
+
if (!Array.isArray(display)) return false;
|
|
4217
|
+
const args = item.arguments;
|
|
4218
|
+
return display.every((param) => {
|
|
4219
|
+
if (!isJsonObject(param) || typeof param.name !== "string" || !isJsonObject(args)) return false;
|
|
4220
|
+
if (!Object.hasOwn(args, param.name)) return false;
|
|
4221
|
+
const value = args[param.name];
|
|
4222
|
+
return typeof param.value !== "string" || param.value === (typeof value === "string" ? value : JSON.stringify(value));
|
|
4223
|
+
});
|
|
4224
|
+
}
|
|
4283
4225
|
function handled(response) {
|
|
4284
4226
|
return {
|
|
4285
4227
|
kind: "handled",
|
|
@@ -4395,14 +4337,14 @@ async function buildPluginPolicyElicitationResponse(params) {
|
|
|
4395
4337
|
const response = buildElicitationResponse(approvalPrompt, "approved-once");
|
|
4396
4338
|
if (response.action === "accept") {
|
|
4397
4339
|
if (mode === "allow") return response;
|
|
4398
|
-
|
|
4399
|
-
|
|
4340
|
+
return buildElicitationResponse(approvalPrompt, await requestPluginApprovalOutcome({
|
|
4341
|
+
hostCapabilities: params.paramsForRun.hostCapabilities,
|
|
4400
4342
|
title: approvalPrompt.title,
|
|
4401
4343
|
description: approvalPrompt.description,
|
|
4402
4344
|
allowedDecisions: allowedPluginPolicyApprovalDecisions(mode, approvalPrompt),
|
|
4345
|
+
toolName: "codex_mcp_tool_approval",
|
|
4403
4346
|
signal: params.signal
|
|
4404
|
-
});
|
|
4405
|
-
return buildElicitationResponse(approvalPrompt, mode === "ask" && outcome === "approved-session" ? "approved-once" : outcome);
|
|
4347
|
+
}));
|
|
4406
4348
|
}
|
|
4407
4349
|
logPluginElicitationDecline("unmappable_schema", params.requestParams);
|
|
4408
4350
|
return createCodexElicitationResponse("decline");
|
|
@@ -4437,15 +4379,16 @@ function readPluginApprovalElicitation(entry, requestParams) {
|
|
|
4437
4379
|
allowedDecisions: buildApprovalAllowedDecisions(requestedSchema, meta)
|
|
4438
4380
|
};
|
|
4439
4381
|
}
|
|
4440
|
-
function buildApprovalAllowedDecisions(requestedSchema, meta) {
|
|
4441
|
-
return canMapPersistentApproval(requestedSchema, meta) ? [
|
|
4382
|
+
function buildApprovalAllowedDecisions(requestedSchema, meta, allowSession = false) {
|
|
4383
|
+
return canMapPersistentApproval(requestedSchema, meta, allowSession) ? [
|
|
4442
4384
|
"allow-once",
|
|
4443
4385
|
"allow-always",
|
|
4444
4386
|
"deny"
|
|
4445
4387
|
] : ["allow-once", "deny"];
|
|
4446
4388
|
}
|
|
4447
|
-
function canMapPersistentApproval(requestedSchema, meta) {
|
|
4389
|
+
function canMapPersistentApproval(requestedSchema, meta, allowSession) {
|
|
4448
4390
|
const persistHints = readPersistHints(meta, "explicit");
|
|
4391
|
+
if (allowSession) return choosePersistHint(persistHints) !== void 0;
|
|
4449
4392
|
if (persistHints.length > 0) return persistHints.includes("always");
|
|
4450
4393
|
const properties = isJsonObject(requestedSchema.properties) ? requestedSchema.properties : {};
|
|
4451
4394
|
return Object.entries(properties).some(([name, value]) => {
|
|
@@ -4470,16 +4413,20 @@ function readBridgeableApprovalElicitation(requestParams) {
|
|
|
4470
4413
|
const requestedSchema = requestParams.requestedSchema;
|
|
4471
4414
|
if (readNonBlankStringField(requestedSchema, "type") !== "object" || !isJsonObject(requestedSchema.properties)) return;
|
|
4472
4415
|
const title = sanitizeDisplayText(readNonBlankStringField(requestParams, "message") ?? "") || "Codex MCP tool approval";
|
|
4416
|
+
const serverName = readNonBlankStringField(requestParams, "serverName");
|
|
4473
4417
|
return {
|
|
4474
4418
|
title,
|
|
4475
4419
|
description: buildApprovalDescription({
|
|
4476
4420
|
title,
|
|
4477
4421
|
meta: requestParams["_meta"],
|
|
4478
4422
|
requestedSchema,
|
|
4479
|
-
serverName: sanitizeOptionalDisplayText(
|
|
4423
|
+
serverName: sanitizeOptionalDisplayText(serverName),
|
|
4424
|
+
remedy: serverName ? formatMcpCodexApprovalRemedy(serverName) : void 0
|
|
4480
4425
|
}),
|
|
4481
4426
|
requestedSchema,
|
|
4482
|
-
meta: requestParams["_meta"]
|
|
4427
|
+
meta: requestParams["_meta"],
|
|
4428
|
+
persistHintsMode: "explicit",
|
|
4429
|
+
allowedDecisions: buildApprovalAllowedDecisions(requestedSchema, requestParams["_meta"], true)
|
|
4483
4430
|
};
|
|
4484
4431
|
}
|
|
4485
4432
|
function readComputerUseApprovalElicitation(requestParams, expectedServerName) {
|
|
@@ -4509,6 +4456,7 @@ function buildApprovalDescription(params) {
|
|
|
4509
4456
|
connectorName && `App: ${connectorName}`,
|
|
4510
4457
|
toolTitle && `Tool: ${toolTitle}`,
|
|
4511
4458
|
params.serverName && `MCP server: ${params.serverName}`,
|
|
4459
|
+
params.remedy,
|
|
4512
4460
|
toolDescription
|
|
4513
4461
|
].filter((line) => Boolean(line));
|
|
4514
4462
|
const paramLines = readDisplayParamLines(params.meta);
|
|
@@ -4544,7 +4492,8 @@ function readDisplayParamLines(meta) {
|
|
|
4544
4492
|
return remaining > 0 ? [...lines, `- Additional parameters: ${remaining} more`] : lines;
|
|
4545
4493
|
}
|
|
4546
4494
|
function formatDisplayParamValue(value) {
|
|
4547
|
-
|
|
4495
|
+
const formatted = typeof value === "string" ? value : formatDisplayJsonValue(value ?? null);
|
|
4496
|
+
return truncateCodexApprovalDisplayText(sanitizeDisplayText(formatted), MAX_DISPLAY_PARAM_VALUE_LENGTH);
|
|
4548
4497
|
}
|
|
4549
4498
|
function formatDisplayJsonValue(value, depth = MAX_DISPLAY_VALUE_DEPTH) {
|
|
4550
4499
|
if (value === null) return "null";
|
|
@@ -4588,35 +4537,10 @@ function sanitizeDisplayText(value) {
|
|
|
4588
4537
|
const escaped = sanitized ? formatCodexDisplayText(sanitized) : "";
|
|
4589
4538
|
return clipped && escaped ? `${escaped}...` : escaped;
|
|
4590
4539
|
}
|
|
4591
|
-
async function requestPluginApprovalOutcome(params) {
|
|
4592
|
-
try {
|
|
4593
|
-
const requestResult = await requestPluginApproval({
|
|
4594
|
-
hostCapabilities: params.paramsForRun.hostCapabilities,
|
|
4595
|
-
title: params.title,
|
|
4596
|
-
description: params.description,
|
|
4597
|
-
severity: "warning",
|
|
4598
|
-
toolName: "codex_mcp_tool_approval",
|
|
4599
|
-
allowedDecisions: params.allowedDecisions
|
|
4600
|
-
});
|
|
4601
|
-
const approvalId = requestResult?.id;
|
|
4602
|
-
if (!approvalId) return "unavailable";
|
|
4603
|
-
const approvalResult = approvalRequestExplicitlyUnavailable(requestResult) ? void 0 : await waitForPluginApprovalDecision({
|
|
4604
|
-
hostCapabilities: params.paramsForRun.hostCapabilities,
|
|
4605
|
-
approvalId,
|
|
4606
|
-
signal: params.signal
|
|
4607
|
-
});
|
|
4608
|
-
if (params.signal?.aborted) return "cancelled";
|
|
4609
|
-
if (approvalResult?.terminalReason === "timeout") return "timed-out";
|
|
4610
|
-
return mapExecDecisionToOutcome(approvalResult?.decision);
|
|
4611
|
-
} catch {
|
|
4612
|
-
return params.signal?.aborted ? "cancelled" : "denied";
|
|
4613
|
-
}
|
|
4614
|
-
}
|
|
4615
4540
|
function buildElicitationResponse(approvalPrompt, outcome) {
|
|
4616
4541
|
const { requestedSchema, meta } = approvalPrompt;
|
|
4617
4542
|
if (outcome === "cancelled") return createCodexElicitationResponse("cancel");
|
|
4618
|
-
if (outcome === "timed-out"
|
|
4619
|
-
if (outcome === "denied" || outcome === "unavailable") return createCodexElicitationResponse("decline");
|
|
4543
|
+
if (outcome === "timed-out" || outcome === "denied" || outcome === "unavailable") return createCodexElicitationResponse("decline");
|
|
4620
4544
|
const content = buildAcceptedContent(approvalPrompt, outcome);
|
|
4621
4545
|
if (!content && !hasNoSchemaProperties(requestedSchema)) {
|
|
4622
4546
|
embeddedAgentLog.warn("codex MCP approval elicitation approved without a mappable response", {
|
|
@@ -4643,7 +4567,7 @@ function buildAcceptedContent(approvalPrompt, outcome) {
|
|
|
4643
4567
|
schema,
|
|
4644
4568
|
required: required.has(name)
|
|
4645
4569
|
};
|
|
4646
|
-
const next = readApprovalFieldValue(property, outcome) ?? readPersistFieldValue(property, meta, outcome, approvalPrompt.persistHintsMode ?? "legacy") ?? readFallbackFieldValue(property, outcome);
|
|
4570
|
+
const next = readApprovalFieldValue(property, outcome, choosePersistHint(readPersistHints(meta, approvalPrompt.persistHintsMode))) ?? readPersistFieldValue(property, meta, outcome, approvalPrompt.persistHintsMode ?? "legacy") ?? readFallbackFieldValue(property, outcome);
|
|
4647
4571
|
if (next === void 0) {
|
|
4648
4572
|
if (isApprovalField(property)) sawApprovalField = true;
|
|
4649
4573
|
if (property.required) return;
|
|
@@ -4654,15 +4578,14 @@ function buildAcceptedContent(approvalPrompt, outcome) {
|
|
|
4654
4578
|
}
|
|
4655
4579
|
return sawApprovalField ? content : void 0;
|
|
4656
4580
|
}
|
|
4657
|
-
function readApprovalFieldValue(property, outcome) {
|
|
4581
|
+
function readApprovalFieldValue(property, outcome, persist) {
|
|
4658
4582
|
if (!isApprovalField(property)) return;
|
|
4659
4583
|
if (readNonBlankStringField(property.schema, "type") === "boolean") return true;
|
|
4660
4584
|
const options = readEnumOptions(property.schema);
|
|
4661
4585
|
if (options.length === 0) return;
|
|
4662
|
-
const sessionChoice = options.find((option) => isSessionApprovalOption(option));
|
|
4663
4586
|
const acceptChoice = options.find((option) => isPositiveApprovalOption(option));
|
|
4664
|
-
if (outcome === "approved-session") return
|
|
4665
|
-
return acceptChoice?.value
|
|
4587
|
+
if (outcome === "approved-session") return options.find((option) => isPersistentApprovalOption(option, persist))?.value ?? acceptChoice?.value;
|
|
4588
|
+
return acceptChoice?.value;
|
|
4666
4589
|
}
|
|
4667
4590
|
function readPersistFieldValue(property, meta, outcome, persistHintsMode) {
|
|
4668
4591
|
if (!isPersistField(property) || outcome !== "approved-session") return;
|
|
@@ -4741,9 +4664,9 @@ function isPositiveApprovalOption(option) {
|
|
|
4741
4664
|
const haystack = `${option.value} ${option.label}`.toLowerCase();
|
|
4742
4665
|
return /\b(allow|approve|accept|yes|continue|proceed|true)\b/.test(haystack);
|
|
4743
4666
|
}
|
|
4744
|
-
function
|
|
4667
|
+
function isPersistentApprovalOption(option, persist) {
|
|
4745
4668
|
const haystack = `${option.value} ${option.label}`.toLowerCase();
|
|
4746
|
-
return /\b(
|
|
4669
|
+
return (persist === "always" ? /\b(always|persistent)\b|\bdon't ask me again\b/.test(haystack) : persist === "session" && /\bsession\b/.test(haystack)) && /\b(allow|approve|accept)\b/.test(haystack);
|
|
4747
4670
|
}
|
|
4748
4671
|
function readNonBlankStringField(record, key) {
|
|
4749
4672
|
const value = record?.[key];
|
|
@@ -4756,57 +4679,242 @@ function readFirstString$1(record, keys) {
|
|
|
4756
4679
|
}
|
|
4757
4680
|
}
|
|
4758
4681
|
//#endregion
|
|
4759
|
-
//#region extensions/codex/src/app-server/dynamic-
|
|
4760
|
-
/**
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
const
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
const
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
}
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4682
|
+
//#region extensions/codex/src/app-server/dynamic-tool-catalog.ts
|
|
4683
|
+
/** Namespace attached to OpenClaw-owned dynamic tools exposed to Codex. */
|
|
4684
|
+
const CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE = "openclaw";
|
|
4685
|
+
const CODEX_DYNAMIC_TOOL_NAME_MAX_CHARS = 128;
|
|
4686
|
+
const CODEX_DYNAMIC_TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/u;
|
|
4687
|
+
const ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
4688
|
+
"agents_list",
|
|
4689
|
+
"progress_card",
|
|
4690
|
+
"sessions_spawn",
|
|
4691
|
+
"sessions_yield"
|
|
4692
|
+
]);
|
|
4693
|
+
function createCodexDynamicToolSpecs(params) {
|
|
4694
|
+
const directToolNames = /* @__PURE__ */ new Set([...ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES, ...params.directToolNames ?? []]);
|
|
4695
|
+
const specs = [];
|
|
4696
|
+
const namespaceTools = [];
|
|
4697
|
+
const directOnlyNamespaceTools = [];
|
|
4698
|
+
const entries = params.loading === "direct" ? params.entries : params.entries.toSorted((left, right) => left.name.localeCompare(right.name));
|
|
4699
|
+
for (const entry of entries) {
|
|
4700
|
+
const functionSpec = createCodexDynamicToolFunctionSpec({ entry });
|
|
4701
|
+
if (entry.name === "openclaw" && directToolNames.has(entry.name)) {
|
|
4702
|
+
specs.push(functionSpec);
|
|
4703
|
+
continue;
|
|
4704
|
+
}
|
|
4705
|
+
if (entry.tool.catalogMode === "direct-only") {
|
|
4706
|
+
directOnlyNamespaceTools.push(functionSpec);
|
|
4707
|
+
continue;
|
|
4708
|
+
}
|
|
4709
|
+
if (params.loading === "direct" || directToolNames.has(entry.name)) {
|
|
4710
|
+
specs.push(functionSpec);
|
|
4711
|
+
continue;
|
|
4712
|
+
}
|
|
4713
|
+
namespaceTools.push({
|
|
4714
|
+
...functionSpec,
|
|
4715
|
+
deferLoading: true
|
|
4716
|
+
});
|
|
4717
|
+
}
|
|
4718
|
+
if (namespaceTools.length > 0) specs.push({
|
|
4719
|
+
type: "namespace",
|
|
4720
|
+
name: CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE,
|
|
4721
|
+
description: "",
|
|
4722
|
+
tools: namespaceTools
|
|
4723
|
+
});
|
|
4724
|
+
if (directOnlyNamespaceTools.length > 0) specs.push({
|
|
4725
|
+
type: "namespace",
|
|
4726
|
+
name: CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE,
|
|
4727
|
+
description: "",
|
|
4728
|
+
tools: directOnlyNamespaceTools
|
|
4729
|
+
});
|
|
4730
|
+
return specs;
|
|
4731
|
+
}
|
|
4732
|
+
function createCodexDynamicToolFunctionSpec(params) {
|
|
4733
|
+
return {
|
|
4734
|
+
type: "function",
|
|
4735
|
+
name: params.entry.name,
|
|
4736
|
+
description: params.entry.description,
|
|
4737
|
+
inputSchema: params.entry.inputSchema
|
|
4738
|
+
};
|
|
4739
|
+
}
|
|
4740
|
+
function projectCodexDynamicTools(tools) {
|
|
4741
|
+
const projectedTools = [];
|
|
4742
|
+
const quarantinedTools = [];
|
|
4743
|
+
let length;
|
|
4744
|
+
try {
|
|
4745
|
+
length = tools.length;
|
|
4746
|
+
} catch {
|
|
4747
|
+
return {
|
|
4748
|
+
tools: [],
|
|
4749
|
+
quarantinedTools: [{
|
|
4750
|
+
tool: "tool[0]",
|
|
4751
|
+
violations: ["tool[0] is unreadable"]
|
|
4752
|
+
}]
|
|
4753
|
+
};
|
|
4754
|
+
}
|
|
4755
|
+
for (let toolIndex = 0; toolIndex < length; toolIndex += 1) {
|
|
4756
|
+
let tool;
|
|
4757
|
+
try {
|
|
4758
|
+
tool = tools[toolIndex];
|
|
4759
|
+
} catch {
|
|
4760
|
+
quarantinedTools.push({
|
|
4761
|
+
tool: `tool[${toolIndex}]`,
|
|
4762
|
+
violations: [`tool[${toolIndex}] is unreadable`]
|
|
4763
|
+
});
|
|
4764
|
+
continue;
|
|
4765
|
+
}
|
|
4766
|
+
const descriptor = readCodexDynamicToolDescriptor(tool, toolIndex);
|
|
4767
|
+
if (!descriptor.ok) {
|
|
4768
|
+
quarantinedTools.push(descriptor.diagnostic);
|
|
4769
|
+
continue;
|
|
4770
|
+
}
|
|
4771
|
+
const normalizedParameters = normalizeOpenAIStrictCompatSchema(descriptor.parameters);
|
|
4772
|
+
const projection = projectRuntimeToolInputSchema(normalizedParameters ?? descriptor.parameters, `${descriptor.name}.inputSchema`);
|
|
4773
|
+
if (projection.violations.length > 0) {
|
|
4774
|
+
quarantinedTools.push({
|
|
4775
|
+
tool: descriptor.name,
|
|
4776
|
+
violations: projection.violations
|
|
4777
|
+
});
|
|
4778
|
+
continue;
|
|
4779
|
+
}
|
|
4780
|
+
if (!isRecord(projection.schema)) {
|
|
4781
|
+
quarantinedTools.push({
|
|
4782
|
+
tool: descriptor.name,
|
|
4783
|
+
violations: [`${descriptor.name}.inputSchema must be a JSON object schema`]
|
|
4784
|
+
});
|
|
4785
|
+
continue;
|
|
4786
|
+
}
|
|
4787
|
+
projectedTools.push({
|
|
4788
|
+
tool,
|
|
4789
|
+
name: descriptor.name,
|
|
4790
|
+
description: descriptor.description,
|
|
4791
|
+
inputSchema: projection.schema
|
|
4792
|
+
});
|
|
4793
|
+
}
|
|
4794
|
+
return {
|
|
4795
|
+
tools: projectedTools,
|
|
4796
|
+
quarantinedTools
|
|
4797
|
+
};
|
|
4798
|
+
}
|
|
4799
|
+
function readCodexDynamicToolDescriptor(tool, toolIndex) {
|
|
4800
|
+
const fallbackName = `tool[${toolIndex}]`;
|
|
4801
|
+
let name;
|
|
4802
|
+
try {
|
|
4803
|
+
const rawName = tool.name;
|
|
4804
|
+
if (typeof rawName !== "string" || !rawName) return {
|
|
4805
|
+
ok: false,
|
|
4806
|
+
diagnostic: {
|
|
4807
|
+
tool: fallbackName,
|
|
4808
|
+
violations: [`${fallbackName}.name must be a non-empty string`]
|
|
4809
|
+
}
|
|
4810
|
+
};
|
|
4811
|
+
const trimmedName = rawName.trim();
|
|
4812
|
+
let nameViolation;
|
|
4813
|
+
if (!trimmedName) nameViolation = `${rawName}.name must not be empty`;
|
|
4814
|
+
else if (trimmedName !== rawName) nameViolation = `${rawName}.name must not have leading or trailing whitespace`;
|
|
4815
|
+
else if (!CODEX_DYNAMIC_TOOL_NAME_PATTERN.test(rawName)) nameViolation = `${rawName}.name must match ^[a-zA-Z0-9_-]+$`;
|
|
4816
|
+
else if (rawName.length > CODEX_DYNAMIC_TOOL_NAME_MAX_CHARS) nameViolation = `${rawName}.name must be at most ${CODEX_DYNAMIC_TOOL_NAME_MAX_CHARS} characters`;
|
|
4817
|
+
else if (rawName === "mcp" || rawName.startsWith("mcp__")) nameViolation = `${rawName}.name is reserved by Codex app-server`;
|
|
4818
|
+
if (nameViolation) return {
|
|
4819
|
+
ok: false,
|
|
4820
|
+
diagnostic: {
|
|
4821
|
+
tool: rawName,
|
|
4822
|
+
violations: [nameViolation]
|
|
4823
|
+
}
|
|
4824
|
+
};
|
|
4825
|
+
name = rawName;
|
|
4826
|
+
} catch {
|
|
4827
|
+
return {
|
|
4828
|
+
ok: false,
|
|
4829
|
+
diagnostic: {
|
|
4830
|
+
tool: fallbackName,
|
|
4831
|
+
violations: [`${fallbackName}.name is unreadable`]
|
|
4832
|
+
}
|
|
4833
|
+
};
|
|
4834
|
+
}
|
|
4835
|
+
let description;
|
|
4836
|
+
try {
|
|
4837
|
+
description = typeof tool.description === "string" ? tool.description : "";
|
|
4838
|
+
} catch {
|
|
4839
|
+
return {
|
|
4840
|
+
ok: false,
|
|
4841
|
+
diagnostic: {
|
|
4842
|
+
tool: name,
|
|
4843
|
+
violations: [`${name}.description is unreadable`]
|
|
4844
|
+
}
|
|
4845
|
+
};
|
|
4846
|
+
}
|
|
4847
|
+
let parameters;
|
|
4848
|
+
try {
|
|
4849
|
+
parameters = tool.parameters;
|
|
4850
|
+
} catch {
|
|
4851
|
+
return {
|
|
4852
|
+
ok: false,
|
|
4853
|
+
diagnostic: {
|
|
4854
|
+
tool: name,
|
|
4855
|
+
violations: [`${name}.inputSchema is unreadable`]
|
|
4856
|
+
}
|
|
4857
|
+
};
|
|
4858
|
+
}
|
|
4859
|
+
return {
|
|
4860
|
+
ok: true,
|
|
4861
|
+
name,
|
|
4862
|
+
description,
|
|
4863
|
+
parameters
|
|
4864
|
+
};
|
|
4865
|
+
}
|
|
4866
|
+
//#endregion
|
|
4867
|
+
//#region extensions/codex/src/app-server/dynamic-tools.ts
|
|
4868
|
+
/**
|
|
4869
|
+
* Bridges OpenClaw runtime tools into Codex app-server dynamic tool specs and
|
|
4870
|
+
* tool-call responses.
|
|
4871
|
+
*/
|
|
4872
|
+
const INTERNAL_TOOL_EXECUTION_VALIDATION = Symbol.for("openclaw.internalToolExecutionValidation");
|
|
4873
|
+
const MAX_CODEX_DYNAMIC_TOOL_VALIDATION_ERRORS = 4;
|
|
4874
|
+
const MAX_CODEX_DYNAMIC_TOOL_VALIDATION_ERROR_CHARS = 160;
|
|
4875
|
+
const CODEX_DYNAMIC_TOOL_VALIDATION_TRUNCATED_SUFFIX = " [detail truncated]";
|
|
4876
|
+
function shouldValidateCodexDynamicToolInput(tool) {
|
|
4877
|
+
return getPluginToolMeta(tool)?.mcp?.operation !== "tool";
|
|
4878
|
+
}
|
|
4879
|
+
function assertCodexDynamicToolInputMatchesSchema(params) {
|
|
4880
|
+
const validation = validateJsonSchemaValue({
|
|
4881
|
+
schema: params.schema,
|
|
4882
|
+
cacheKey: `codex-dynamic-tool-input:${params.toolName}:${JSON.stringify(params.schema)}`,
|
|
4883
|
+
value: params.value
|
|
4884
|
+
});
|
|
4885
|
+
if (validation.ok) return;
|
|
4886
|
+
const visibleErrors = validation.errors.slice(0, MAX_CODEX_DYNAMIC_TOOL_VALIDATION_ERRORS);
|
|
4887
|
+
const details = visibleErrors.map((error) => {
|
|
4888
|
+
if (error.text.length <= MAX_CODEX_DYNAMIC_TOOL_VALIDATION_ERROR_CHARS) return error.text;
|
|
4889
|
+
return `${error.text.slice(0, 141)}${CODEX_DYNAMIC_TOOL_VALIDATION_TRUNCATED_SUFFIX}`;
|
|
4890
|
+
}).join("; ");
|
|
4891
|
+
const omitted = validation.errors.length - visibleErrors.length;
|
|
4892
|
+
const omittedSuffix = omitted > 0 ? `; ${omitted} more violation(s) omitted` : "";
|
|
4893
|
+
throw new Error(`Invalid arguments for tool "${params.toolName}": ${details}${omittedSuffix}.`);
|
|
4894
|
+
}
|
|
4895
|
+
function createCodexDynamicToolValidationControl(params) {
|
|
4896
|
+
return {
|
|
4897
|
+
[INTERNAL_TOOL_EXECUTION_VALIDATION]: true,
|
|
4898
|
+
toolCallId: params.toolCallId,
|
|
4899
|
+
validate: params.validate
|
|
4900
|
+
};
|
|
4901
|
+
}
|
|
4902
|
+
function applyCurrentMessageProvider(toolName, args, currentProvider) {
|
|
4903
|
+
const hasProvider = typeof args.provider === "string" && args.provider.trim().length > 0 ? true : typeof args.channel === "string" && args.channel.trim().length > 0;
|
|
4904
|
+
const provider = currentProvider?.trim();
|
|
4905
|
+
if (toolName !== "message" || hasProvider || !provider) return args;
|
|
4906
|
+
return {
|
|
4907
|
+
...args,
|
|
4908
|
+
provider
|
|
4909
|
+
};
|
|
4910
|
+
}
|
|
4911
|
+
function normalizeRouteToken(value) {
|
|
4912
|
+
if (typeof value === "number") return Number.isFinite(value) ? String(value) : void 0;
|
|
4913
|
+
const normalized = value?.trim().toLowerCase();
|
|
4914
|
+
return normalized ? normalized : void 0;
|
|
4915
|
+
}
|
|
4916
|
+
function sourceRouteTokens(hookContext) {
|
|
4917
|
+
const tokens = /* @__PURE__ */ new Set();
|
|
4810
4918
|
const currentTarget = normalizeRouteToken(hookContext?.currentMessagingTarget);
|
|
4811
4919
|
const currentChannel = normalizeRouteToken(hookContext?.currentChannelId);
|
|
4812
4920
|
const currentProvider = normalizeRouteToken(hookContext?.currentChannelProvider);
|
|
@@ -4919,15 +5027,6 @@ function normalizeAcceptedSessionSpawn(result) {
|
|
|
4919
5027
|
childSessionKey
|
|
4920
5028
|
} : null;
|
|
4921
5029
|
}
|
|
4922
|
-
/** Namespace attached to OpenClaw-owned dynamic tools exposed to Codex. */
|
|
4923
|
-
const CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE = "openclaw";
|
|
4924
|
-
const CODEX_DYNAMIC_TOOL_NAME_MAX_CHARS = 128;
|
|
4925
|
-
const CODEX_DYNAMIC_TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/u;
|
|
4926
|
-
const ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
4927
|
-
"agents_list",
|
|
4928
|
-
"sessions_spawn",
|
|
4929
|
-
"sessions_yield"
|
|
4930
|
-
]);
|
|
4931
5030
|
const EXPLICIT_MESSAGE_PROVIDER_KEYS = ["channel", "provider"];
|
|
4932
5031
|
const EXPLICIT_MESSAGE_TARGET_KEYS = [
|
|
4933
5032
|
"target",
|
|
@@ -4967,11 +5066,13 @@ function createCodexDynamicToolBridge(params) {
|
|
|
4967
5066
|
const toolResultMaxChars = typeof contextWindowTokens === "number" && Number.isFinite(contextWindowTokens) && contextWindowTokens > 0 ? Math.max(1, resolveLiveToolResultMaxChars({ contextWindowTokens })) : DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS;
|
|
4968
5067
|
const availableProjection = projectCodexExecutableDynamicToolSurface(params.tools, params.hookContext);
|
|
4969
5068
|
const registeredProjection = params.registeredTools ? projectCodexDynamicTools(params.registeredTools) : availableProjection;
|
|
4970
|
-
const
|
|
5069
|
+
const inheritedSpecs = params.registeredSpecs ? structuredClone([...params.registeredSpecs]) : void 0;
|
|
5070
|
+
const inheritedNames = inheritedSpecs ? new Set(flattenCodexDynamicToolFunctions(inheritedSpecs).map((tool) => tool.name)) : void 0;
|
|
5071
|
+
const availableTools = availableProjection.tools.filter((entry) => !inheritedNames || inheritedNames.has(entry.name));
|
|
4971
5072
|
const quarantinedAvailableToolNames = new Set(availableProjection.quarantinedTools.map((tool) => tool.tool));
|
|
4972
5073
|
const registeredSpecTools = (params.registeredTools ? registeredProjection.tools : availableTools).filter((entry) => !quarantinedAvailableToolNames.has(entry.name));
|
|
4973
5074
|
const toolMap = new Map(availableTools.map((entry) => [entry.name, entry]));
|
|
4974
|
-
const registeredToolNames = new Set(registeredSpecTools.map((entry) => entry.name));
|
|
5075
|
+
const registeredToolNames = inheritedNames ?? new Set(registeredSpecTools.map((entry) => entry.name));
|
|
4975
5076
|
const quarantinedTools = dedupeQuarantinedDynamicTools([...availableProjection.quarantinedTools, ...registeredProjection.quarantinedTools]);
|
|
4976
5077
|
warnQuarantinedDynamicTools({
|
|
4977
5078
|
tools: quarantinedTools,
|
|
@@ -4987,6 +5088,8 @@ function createCodexDynamicToolBridge(params) {
|
|
|
4987
5088
|
messagingToolSentTargets: [],
|
|
4988
5089
|
messagingToolSourceReplyPayloads: [],
|
|
4989
5090
|
toolMediaUrls: [],
|
|
5091
|
+
toolAutoDeliveryMediaUrls: [],
|
|
5092
|
+
coreTtsToolResults: [],
|
|
4990
5093
|
toolAudioAsVoice: false,
|
|
4991
5094
|
acceptedSessionSpawns: [],
|
|
4992
5095
|
quarantinedTools
|
|
@@ -5002,16 +5105,23 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5002
5105
|
};
|
|
5003
5106
|
const legacyExtensionRunner = createCodexAppServerToolResultExtensionRunner(toolResultHookContext);
|
|
5004
5107
|
const executionSnapshotStates = /* @__PURE__ */ new Map();
|
|
5005
|
-
const directToolNames =
|
|
5108
|
+
const directToolNames = params.directToolNames;
|
|
5006
5109
|
let readRemoteWorkspaceFile;
|
|
5007
5110
|
return {
|
|
5008
5111
|
availableTools: availableTools.map((entry) => entry.tool),
|
|
5009
|
-
availableSpecs:
|
|
5112
|
+
availableSpecs: inheritedSpecs ? inheritedSpecs.flatMap((spec) => {
|
|
5113
|
+
if (spec.type === "function") return toolMap.has(spec.name) ? [spec] : [];
|
|
5114
|
+
const tools = spec.tools.filter((tool) => toolMap.has(tool.name));
|
|
5115
|
+
return tools.length ? [{
|
|
5116
|
+
...spec,
|
|
5117
|
+
tools
|
|
5118
|
+
}] : [];
|
|
5119
|
+
}) : createCodexDynamicToolSpecs({
|
|
5010
5120
|
entries: availableTools,
|
|
5011
5121
|
loading: params.loading ?? "searchable",
|
|
5012
5122
|
directToolNames
|
|
5013
5123
|
}),
|
|
5014
|
-
specs: createCodexDynamicToolSpecs({
|
|
5124
|
+
specs: inheritedSpecs ?? createCodexDynamicToolSpecs({
|
|
5015
5125
|
entries: registeredSpecTools,
|
|
5016
5126
|
loading: params.loading ?? "searchable",
|
|
5017
5127
|
directToolNames
|
|
@@ -5200,13 +5310,17 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5200
5310
|
const toolConfirmedSourceReply = params.hookContext?.sourceReplyDeliveryMode === "message_tool_only" && toolName === "message" && !resultIsError && (rawResult.terminate === true || result.terminate === true);
|
|
5201
5311
|
const confirmedSourceReply = params.hookContext?.sourceReplyDeliveryMode === "message_tool_only" && toolName === "message" && (toolConfirmedSourceReply || deliveredSourceReply || receiptConfirmedSourceReply);
|
|
5202
5312
|
const sourceReplyFinal = confirmedSourceReply ? executedArgs.final !== false : void 0;
|
|
5313
|
+
const autoDeliveryTtsMediaUrls = getCoreTtsToolResultMediaUrls(rawResult);
|
|
5203
5314
|
collectToolTelemetry({
|
|
5204
5315
|
toolName,
|
|
5205
5316
|
args: executedArgs,
|
|
5206
5317
|
result,
|
|
5207
5318
|
mediaTrustResult: telemetryRawResult,
|
|
5208
5319
|
telemetry,
|
|
5320
|
+
signal,
|
|
5209
5321
|
isError: resultIsError,
|
|
5322
|
+
autoDeliveryTtsMediaUrls,
|
|
5323
|
+
coreTtsToolResult: autoDeliveryTtsMediaUrls?.length ? rawResult : void 0,
|
|
5210
5324
|
messagingTarget: confirmedMessagingTarget,
|
|
5211
5325
|
sourceReplyFinal
|
|
5212
5326
|
});
|
|
@@ -5222,6 +5336,8 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5222
5336
|
sideEffectEvidence: !replaySafe
|
|
5223
5337
|
});
|
|
5224
5338
|
} catch (error) {
|
|
5339
|
+
const trustedNoStart = consumeTrustedToolNoStartError(error);
|
|
5340
|
+
executionPrevented ||= trustedNoStart;
|
|
5225
5341
|
captureExecutionBoundary();
|
|
5226
5342
|
if (toolName === "computer" && params.computerContextEpoch?.frameToolCallId === call.callId) invalidateComputerFrame(params.computerContextEpoch);
|
|
5227
5343
|
const executionDisposition = getBeforeToolCallFailureDisposition(error) ?? (signal.aborted ? resolveCodexToolAbortTerminalReason(signal) : resolveToolExecutionErrorKind(error));
|
|
@@ -5238,13 +5354,6 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5238
5354
|
toolCallOrdinal: options?.toolCallOrdinal
|
|
5239
5355
|
});
|
|
5240
5356
|
notifyAgentToolResult(options?.onAgentToolResult, toolName, failedResult, true);
|
|
5241
|
-
collectToolTelemetry({
|
|
5242
|
-
toolName,
|
|
5243
|
-
args: executedArgs,
|
|
5244
|
-
result: void 0,
|
|
5245
|
-
telemetry,
|
|
5246
|
-
isError: true
|
|
5247
|
-
});
|
|
5248
5357
|
runAgentHarnessAfterToolCallHook({
|
|
5249
5358
|
toolName,
|
|
5250
5359
|
toolCallId: call.callId,
|
|
@@ -5339,182 +5448,6 @@ function wrapProjectedCodexDynamicTools(tools, hookContext) {
|
|
|
5339
5448
|
quarantinedTools
|
|
5340
5449
|
};
|
|
5341
5450
|
}
|
|
5342
|
-
function createCodexDynamicToolSpecs(params) {
|
|
5343
|
-
const specs = [];
|
|
5344
|
-
const namespaceTools = [];
|
|
5345
|
-
const directOnlyNamespaceTools = [];
|
|
5346
|
-
const entries = params.loading === "direct" ? params.entries : params.entries.toSorted((left, right) => left.name.localeCompare(right.name));
|
|
5347
|
-
for (const entry of entries) {
|
|
5348
|
-
const functionSpec = createCodexDynamicToolFunctionSpec({ entry });
|
|
5349
|
-
if (entry.name === "openclaw" && params.directToolNames.has(entry.name)) {
|
|
5350
|
-
specs.push(functionSpec);
|
|
5351
|
-
continue;
|
|
5352
|
-
}
|
|
5353
|
-
if (entry.tool.catalogMode === "direct-only") {
|
|
5354
|
-
directOnlyNamespaceTools.push(functionSpec);
|
|
5355
|
-
continue;
|
|
5356
|
-
}
|
|
5357
|
-
if (params.loading === "direct" || params.directToolNames.has(entry.name)) {
|
|
5358
|
-
specs.push(functionSpec);
|
|
5359
|
-
continue;
|
|
5360
|
-
}
|
|
5361
|
-
namespaceTools.push({
|
|
5362
|
-
...functionSpec,
|
|
5363
|
-
deferLoading: true
|
|
5364
|
-
});
|
|
5365
|
-
}
|
|
5366
|
-
if (namespaceTools.length > 0) specs.push({
|
|
5367
|
-
type: "namespace",
|
|
5368
|
-
name: CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE,
|
|
5369
|
-
description: "",
|
|
5370
|
-
tools: namespaceTools
|
|
5371
|
-
});
|
|
5372
|
-
if (directOnlyNamespaceTools.length > 0) specs.push({
|
|
5373
|
-
type: "namespace",
|
|
5374
|
-
name: CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE,
|
|
5375
|
-
description: "",
|
|
5376
|
-
tools: directOnlyNamespaceTools
|
|
5377
|
-
});
|
|
5378
|
-
return specs;
|
|
5379
|
-
}
|
|
5380
|
-
function createCodexDynamicToolFunctionSpec(params) {
|
|
5381
|
-
return {
|
|
5382
|
-
type: "function",
|
|
5383
|
-
name: params.entry.name,
|
|
5384
|
-
description: params.entry.description,
|
|
5385
|
-
inputSchema: params.entry.inputSchema
|
|
5386
|
-
};
|
|
5387
|
-
}
|
|
5388
|
-
function projectCodexDynamicTools(tools) {
|
|
5389
|
-
const projectedTools = [];
|
|
5390
|
-
const quarantinedTools = [];
|
|
5391
|
-
let length;
|
|
5392
|
-
try {
|
|
5393
|
-
length = tools.length;
|
|
5394
|
-
} catch {
|
|
5395
|
-
return {
|
|
5396
|
-
tools: [],
|
|
5397
|
-
quarantinedTools: [{
|
|
5398
|
-
tool: "tool[0]",
|
|
5399
|
-
violations: ["tool[0] is unreadable"]
|
|
5400
|
-
}]
|
|
5401
|
-
};
|
|
5402
|
-
}
|
|
5403
|
-
for (let toolIndex = 0; toolIndex < length; toolIndex += 1) {
|
|
5404
|
-
let tool;
|
|
5405
|
-
try {
|
|
5406
|
-
tool = tools[toolIndex];
|
|
5407
|
-
} catch {
|
|
5408
|
-
quarantinedTools.push({
|
|
5409
|
-
tool: `tool[${toolIndex}]`,
|
|
5410
|
-
violations: [`tool[${toolIndex}] is unreadable`]
|
|
5411
|
-
});
|
|
5412
|
-
continue;
|
|
5413
|
-
}
|
|
5414
|
-
const descriptor = readCodexDynamicToolDescriptor(tool, toolIndex);
|
|
5415
|
-
if (!descriptor.ok) {
|
|
5416
|
-
quarantinedTools.push(descriptor.diagnostic);
|
|
5417
|
-
continue;
|
|
5418
|
-
}
|
|
5419
|
-
const normalizedParameters = normalizeOpenAIToolSchemas({
|
|
5420
|
-
provider: "openai",
|
|
5421
|
-
modelApi: "openai-chatgpt-responses",
|
|
5422
|
-
tools: [{ parameters: descriptor.parameters }]
|
|
5423
|
-
})[0]?.parameters;
|
|
5424
|
-
const projection = projectRuntimeToolInputSchema(normalizedParameters ?? descriptor.parameters, `${descriptor.name}.inputSchema`);
|
|
5425
|
-
if (projection.violations.length > 0) {
|
|
5426
|
-
quarantinedTools.push({
|
|
5427
|
-
tool: descriptor.name,
|
|
5428
|
-
violations: projection.violations
|
|
5429
|
-
});
|
|
5430
|
-
continue;
|
|
5431
|
-
}
|
|
5432
|
-
if (!isRecord(projection.schema)) {
|
|
5433
|
-
quarantinedTools.push({
|
|
5434
|
-
tool: descriptor.name,
|
|
5435
|
-
violations: [`${descriptor.name}.inputSchema must be a JSON object schema`]
|
|
5436
|
-
});
|
|
5437
|
-
continue;
|
|
5438
|
-
}
|
|
5439
|
-
projectedTools.push({
|
|
5440
|
-
tool,
|
|
5441
|
-
name: descriptor.name,
|
|
5442
|
-
description: descriptor.description,
|
|
5443
|
-
inputSchema: projection.schema
|
|
5444
|
-
});
|
|
5445
|
-
}
|
|
5446
|
-
return {
|
|
5447
|
-
tools: projectedTools,
|
|
5448
|
-
quarantinedTools
|
|
5449
|
-
};
|
|
5450
|
-
}
|
|
5451
|
-
function readCodexDynamicToolDescriptor(tool, toolIndex) {
|
|
5452
|
-
const fallbackName = `tool[${toolIndex}]`;
|
|
5453
|
-
let name;
|
|
5454
|
-
try {
|
|
5455
|
-
const rawName = tool.name;
|
|
5456
|
-
if (typeof rawName !== "string" || !rawName) return {
|
|
5457
|
-
ok: false,
|
|
5458
|
-
diagnostic: {
|
|
5459
|
-
tool: fallbackName,
|
|
5460
|
-
violations: [`${fallbackName}.name must be a non-empty string`]
|
|
5461
|
-
}
|
|
5462
|
-
};
|
|
5463
|
-
const trimmedName = rawName.trim();
|
|
5464
|
-
let nameViolation;
|
|
5465
|
-
if (!trimmedName) nameViolation = `${rawName}.name must not be empty`;
|
|
5466
|
-
else if (trimmedName !== rawName) nameViolation = `${rawName}.name must not have leading or trailing whitespace`;
|
|
5467
|
-
else if (!CODEX_DYNAMIC_TOOL_NAME_PATTERN.test(rawName)) nameViolation = `${rawName}.name must match ^[a-zA-Z0-9_-]+$`;
|
|
5468
|
-
else if (rawName.length > CODEX_DYNAMIC_TOOL_NAME_MAX_CHARS) nameViolation = `${rawName}.name must be at most ${CODEX_DYNAMIC_TOOL_NAME_MAX_CHARS} characters`;
|
|
5469
|
-
else if (rawName === "mcp" || rawName.startsWith("mcp__")) nameViolation = `${rawName}.name is reserved by Codex app-server`;
|
|
5470
|
-
if (nameViolation) return {
|
|
5471
|
-
ok: false,
|
|
5472
|
-
diagnostic: {
|
|
5473
|
-
tool: rawName,
|
|
5474
|
-
violations: [nameViolation]
|
|
5475
|
-
}
|
|
5476
|
-
};
|
|
5477
|
-
name = rawName;
|
|
5478
|
-
} catch {
|
|
5479
|
-
return {
|
|
5480
|
-
ok: false,
|
|
5481
|
-
diagnostic: {
|
|
5482
|
-
tool: fallbackName,
|
|
5483
|
-
violations: [`${fallbackName}.name is unreadable`]
|
|
5484
|
-
}
|
|
5485
|
-
};
|
|
5486
|
-
}
|
|
5487
|
-
let description;
|
|
5488
|
-
try {
|
|
5489
|
-
description = typeof tool.description === "string" ? tool.description : "";
|
|
5490
|
-
} catch {
|
|
5491
|
-
return {
|
|
5492
|
-
ok: false,
|
|
5493
|
-
diagnostic: {
|
|
5494
|
-
tool: name,
|
|
5495
|
-
violations: [`${name}.description is unreadable`]
|
|
5496
|
-
}
|
|
5497
|
-
};
|
|
5498
|
-
}
|
|
5499
|
-
let parameters;
|
|
5500
|
-
try {
|
|
5501
|
-
parameters = tool.parameters;
|
|
5502
|
-
} catch {
|
|
5503
|
-
return {
|
|
5504
|
-
ok: false,
|
|
5505
|
-
diagnostic: {
|
|
5506
|
-
tool: name,
|
|
5507
|
-
violations: [`${name}.inputSchema is unreadable`]
|
|
5508
|
-
}
|
|
5509
|
-
};
|
|
5510
|
-
}
|
|
5511
|
-
return {
|
|
5512
|
-
ok: true,
|
|
5513
|
-
name,
|
|
5514
|
-
description,
|
|
5515
|
-
parameters
|
|
5516
|
-
};
|
|
5517
|
-
}
|
|
5518
5451
|
function warnQuarantinedDynamicTools(params) {
|
|
5519
5452
|
if (params.tools.length === 0) return;
|
|
5520
5453
|
const unique = /* @__PURE__ */ new Map();
|
|
@@ -5569,15 +5502,26 @@ function collectToolTelemetry(params) {
|
|
|
5569
5502
|
const response = normalizeHeartbeatToolResponse(params.result?.details);
|
|
5570
5503
|
if (response) params.telemetry.heartbeatToolResponse = response;
|
|
5571
5504
|
}
|
|
5572
|
-
if (
|
|
5505
|
+
if (params.result && !params.signal.aborted) {
|
|
5573
5506
|
const media = extractToolResultMediaArtifact(params.result);
|
|
5574
5507
|
if (media) {
|
|
5575
5508
|
const mediaUrls = filterToolResultMediaUrls(params.toolName, media.mediaUrls, params.mediaTrustResult ?? params.result);
|
|
5576
5509
|
const seen = new Set(params.telemetry.toolMediaUrls);
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5510
|
+
const autoDeliveryMediaUrls = new Set(params.telemetry.toolAutoDeliveryMediaUrls);
|
|
5511
|
+
const rawAutoDeliveryMediaUrls = new Set(params.autoDeliveryTtsMediaUrls);
|
|
5512
|
+
let retainsCoreTtsMedia = false;
|
|
5513
|
+
for (const mediaUrl of mediaUrls) {
|
|
5514
|
+
if (!seen.has(mediaUrl)) {
|
|
5515
|
+
seen.add(mediaUrl);
|
|
5516
|
+
params.telemetry.toolMediaUrls.push(mediaUrl);
|
|
5517
|
+
}
|
|
5518
|
+
if (rawAutoDeliveryMediaUrls.has(mediaUrl)) {
|
|
5519
|
+
autoDeliveryMediaUrls.add(mediaUrl);
|
|
5520
|
+
retainsCoreTtsMedia = true;
|
|
5521
|
+
} else autoDeliveryMediaUrls.delete(mediaUrl);
|
|
5580
5522
|
}
|
|
5523
|
+
params.telemetry.toolAutoDeliveryMediaUrls = [...autoDeliveryMediaUrls];
|
|
5524
|
+
if (retainsCoreTtsMedia && params.coreTtsToolResult && !params.telemetry.coreTtsToolResults.includes(params.coreTtsToolResult)) params.telemetry.coreTtsToolResults.push(params.coreTtsToolResult);
|
|
5581
5525
|
if (media.audioAsVoice) params.telemetry.toolAudioAsVoice = true;
|
|
5582
5526
|
}
|
|
5583
5527
|
}
|
|
@@ -5814,4 +5758,4 @@ function isCronAddAction(args) {
|
|
|
5814
5758
|
return typeof action === "string" && action.trim().toLowerCase() === "add";
|
|
5815
5759
|
}
|
|
5816
5760
|
//#endregion
|
|
5817
|
-
export {
|
|
5761
|
+
export { filterCodexVisionTools as C, shouldWarnCodexDynamicToolBuildStageSummary as S, CodexNativeToolLifecycleProjector as T, resolveCodexMessageToolProvider as _, emitDynamicToolStartedDiagnostic as a, shouldEnableCodexAppServerNativeToolSurface as b, ensureCodexSandboxExecServerEnvironment as c, createCodexDynamicToolBuildStageTracker as d, disableCodexPluginThreadConfig as f, resolveCodexExternalSandboxPolicyForOpenClawSandbox as g, resolveCodexAppServerHookChannelId as h, emitDynamicToolErrorDiagnostic as i, releaseCodexSandboxExecServerEnvironment as l, resolveCodexAppServerExecutionCwd as m, projectCodexExecutableDynamicTools as n, emitDynamicToolTerminalDiagnostic as o, formatCodexDynamicToolBuildStageSummary as p, routeCodexAppServerElicitationRequest as r, handleCodexAppServerApprovalRequest as s, createCodexDynamicToolBridge as t, buildDynamicTools as u, resolveCodexNodePlacementToolConstructionPlan as v, readBoundedCodexRemoteWorkspaceFile as w, shouldRequireCodexSandboxExecServerEnvironment as x, resolveCodexSandboxEnvironmentSelection as y };
|