@openclaw/codex 2026.6.8 → 2026.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/{notification-correlation-BGoG0N90.js → app-server-policy-BPTiVNsW.js} +15 -74
  2. package/dist/attempt-notifications-7oZeRa71.js +249 -0
  3. package/dist/{client-DovmVtbr.js → client-CLrtWgrD.js} +24 -2
  4. package/dist/{client-factory-C71Xdb6z.js → client-factory-Bm6HsGob.js} +3 -2
  5. package/dist/{command-handlers-DHecBkuc.js → command-handlers-BaqM9s9b.js} +17 -13
  6. package/dist/{compact-GEKusemL.js → compact-aQJ0ZKhe.js} +5 -5
  7. package/dist/{computer-use-D1qxvTE_.js → computer-use-BmuwYrW6.js} +3 -3
  8. package/dist/{config-DJXpBkGf.js → config-CszD0vP3.js} +176 -25
  9. package/dist/{conversation-binding-CbnMilVW.js → conversation-binding-DbG2ZJQY.js} +166 -58
  10. package/dist/doctor-contract-api.js +37 -3
  11. package/dist/harness.js +6 -6
  12. package/dist/index.js +108 -27
  13. package/dist/media-understanding-provider-Dmfg4tH_.js +463 -0
  14. package/dist/media-understanding-provider.js +1 -355
  15. package/dist/{models-DRKnOpzF.js → models-CAmfBWRl.js} +2 -2
  16. package/dist/{plugin-app-cache-key-kIqpGTQj.js → plugin-app-cache-key-vaZ_8Usz.js} +17 -6
  17. package/dist/prompt-overlay.js +2 -6
  18. package/dist/{protocol-oeJQu4rs.js → protocol-dh-ETiNd.js} +4 -1
  19. package/dist/{protocol-validators-B48C6S9O.js → protocol-validators-B19q5BIX.js} +210 -16
  20. package/dist/{provider-C5P6352f.js → provider-B-OHpbD3.js} +4 -4
  21. package/dist/{native-hook-relay-C3i3FYtc.js → provider-capabilities-ByR82ytL.js} +803 -78
  22. package/dist/provider.js +1 -1
  23. package/dist/{request-BxZ40QKY.js → request-Dcd452Nk.js} +2 -2
  24. package/dist/{run-attempt-D_q-VrpR.js → run-attempt-DYt00Jxz.js} +519 -789
  25. package/dist/{sandbox-guard-C-Yv9uwY.js → sandbox-guard-3tnjhjFb.js} +37 -10
  26. package/dist/{session-binding-ElbcSq2o.js → session-binding-HOuPt-E0.js} +27 -8
  27. package/dist/{shared-client-jFMumCOe.js → shared-client-Dtx5i7Ez.js} +4 -4
  28. package/dist/{side-question-DqKLfWMB.js → side-question-h01W1aCe.js} +106 -42
  29. package/dist/{thread-lifecycle-cban34w3.js → thread-lifecycle-DQyii5vp.js} +948 -616
  30. package/dist/web-search-contract-api.js +10 -0
  31. package/dist/web-search-provider.runtime-BWG_oqLf.js +74 -0
  32. package/dist/web-search-provider.shared-BrZmlqyR.js +32 -0
  33. package/npm-shrinkwrap.json +2 -2
  34. package/openclaw.plugin.json +140 -6
  35. package/package.json +4 -4
@@ -1,13 +1,17 @@
1
- import { c as isTrustedCodexModelBackedOpenAIProvider } from "./config-DJXpBkGf.js";
2
- import { t as isJsonObject } from "./protocol-oeJQu4rs.js";
3
- import { E as sanitizeInlineImageDataUrl, w as invalidInlineImageText } from "./thread-lifecycle-cban34w3.js";
4
- import { l as formatCodexDisplayText } from "./notification-correlation-BGoG0N90.js";
1
+ import { n as isJsonObject } from "./protocol-dh-ETiNd.js";
2
+ import { C as isForcedPrivateQaCodexRuntime, S as filterCodexDynamicTools, _ as resolveCodexWebSearchPlan, w as normalizeCodexDynamicToolName, x as sanitizeInlineImageDataUrl, y as invalidInlineImageText } from "./thread-lifecycle-DQyii5vp.js";
3
+ import { c as isTrustedCodexModelBackedOpenAIProvider, u as readCodexPluginConfig } from "./config-CszD0vP3.js";
4
+ import { a as formatCodexDisplayText } from "./app-server-policy-BPTiVNsW.js";
5
+ import { o as releaseLeasedSharedCodexAppServerClient } from "./shared-client-Dtx5i7Ez.js";
6
+ import { i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-3tnjhjFb.js";
5
7
  import { addTimerTimeoutGraceMs, finiteSecondsToTimerSafeMilliseconds, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
8
+ import { asOptionalRecord, isRecord, normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
6
9
  import { createHash } from "node:crypto";
10
+ import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime";
7
11
  import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
8
- import { asOptionalRecord, isRecord, normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
9
- import { HEARTBEAT_RESPONSE_TOOL_NAME, buildAgentHookContextChannelFields, callGatewayTool, createAgentToolResultMiddlewareRunner, createCodexAppServerToolResultExtensionRunner, embeddedAgentLog, extractToolResultMediaArtifact, filterToolResultMediaUrls, formatApprovalDisplayPath, hasNativeHookRelayInvocation, invokeNativeHookRelay, isMessagingTool, isMessagingToolSendAction, isToolResultError, isToolWrappedWithBeforeToolCallHook, normalizeHeartbeatToolResponse, projectRuntimeToolInputSchema, registerNativeHookRelay, resolveNativeHookRelayDeferredToolApproval, runAgentHarnessAfterToolCallHook, runBeforeToolCallHook, sanitizeToolResult, setBeforeToolCallDiagnosticsEnabled, wrapToolWithBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
12
+ import { HEARTBEAT_RESPONSE_TOOL_NAME, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, callGatewayTool, consumeAdjustedParamsForToolCall, consumePreExecutionBlockedToolCall, createAgentToolResultMiddlewareRunner, createCodexAppServerToolResultExtensionRunner, embeddedAgentLog, extractMessagingToolSend, extractMessagingToolSendResult, extractToolResultMediaArtifact, filterProviderNormalizableTools, filterToolResultMediaUrls, finalizeToolTerminalPresentation, formatApprovalDisplayPath, getChannelAgentToolMeta, getPluginToolMeta, hasNativeHookRelayInvocation, invokeNativeHookRelay, isMessagingTool, isMessagingToolSendAction, isReplaySafeToolCall, isSubagentSessionKey, isToolResultError, isToolWrappedWithBeforeToolCallHook, normalizeAgentRuntimeTools, normalizeHeartbeatToolResponse, projectRuntimeToolInputSchema, registerNativeHookRelay, resolveAttemptSpawnWorkspaceDir, resolveModelAuthMode, resolveNativeHookRelayDeferredToolApproval, runAgentHarnessAfterToolCallHook, runBeforeToolCallHook, sanitizeToolResult, setBeforeToolCallDiagnosticsEnabled, supportsModelTools, wrapToolWithBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
10
13
  import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
14
+ import { isToolAllowed } from "openclaw/plugin-sdk/sandbox";
11
15
  import { buildExecAutoReviewInputForShellCommand, reviewExecRequestWithConfiguredModel } from "openclaw/plugin-sdk/agent-harness-exec-review-runtime";
12
16
  /** Default idle timeout while waiting for app-server turn completion. */
13
17
  const CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS = 6e4;
@@ -112,7 +116,8 @@ async function requestPluginApproval(params) {
112
116
  turnSourceAccountId: params.paramsForRun.agentAccountId,
113
117
  turnSourceThreadId: params.paramsForRun.currentThreadTs,
114
118
  timeoutMs,
115
- twoPhase: true
119
+ twoPhase: true,
120
+ ...params.allowedDecisions ? { allowedDecisions: params.allowedDecisions } : {}
116
121
  }, { expectFinal: false });
117
122
  }
118
123
  /** Detects the gateway's explicit null-decision marker for unavailable approvals. */
@@ -1068,6 +1073,535 @@ function filterToolsForVisionInputs(tools, params) {
1068
1073
  return tools.filter((tool) => tool.name !== "image");
1069
1074
  }
1070
1075
  //#endregion
1076
+ //#region extensions/codex/src/app-server/dynamic-tool-build.ts
1077
+ /**
1078
+ * Builds the Codex app-server dynamic tool list for one turn, including
1079
+ * OpenClaw-owned tools, Codex native-tool fallback rules, sandbox shell shims,
1080
+ * and provider allowlist normalization.
1081
+ */
1082
+ const CODEX_NATIVE_SANDBOX_TOOL_REQUIREMENTS = [
1083
+ "exec",
1084
+ "process",
1085
+ "read",
1086
+ "write",
1087
+ "edit",
1088
+ "apply_patch"
1089
+ ];
1090
+ const CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW = new Set(["read", "write"]);
1091
+ const CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME = "node_exec";
1092
+ const CODEX_NODE_PROCESS_DYNAMIC_TOOL_NAME = "node_process";
1093
+ const CODEX_NODE_EXEC_HIDDEN_PARAMETER_NAMES = new Set([
1094
+ "host",
1095
+ "security",
1096
+ "ask",
1097
+ "node"
1098
+ ]);
1099
+ /** Splits sandbox and run session keys so tool calls can bind to both scopes when needed. */
1100
+ function resolveOpenClawCodingToolsSessionKeys(params, sandboxSessionKey) {
1101
+ return {
1102
+ sessionKey: sandboxSessionKey,
1103
+ runSessionKey: params.sessionKey && params.sessionKey !== sandboxSessionKey ? params.sessionKey : void 0
1104
+ };
1105
+ }
1106
+ /** Returns the canonical channel used for Codex message routing and receipts. */
1107
+ function resolveCodexMessageToolProvider(params) {
1108
+ return params.messageChannel ?? params.messageProvider;
1109
+ }
1110
+ /** Resolves the channel id that hook events should target for this Codex app-server turn. */
1111
+ function resolveCodexAppServerHookChannelId(params, sandboxSessionKey) {
1112
+ return buildAgentHookContextChannelFields({
1113
+ sessionKey: sandboxSessionKey,
1114
+ messageChannel: params.messageChannel,
1115
+ messageProvider: params.messageProvider,
1116
+ currentChannelId: params.currentChannelId,
1117
+ messageTo: params.messageTo
1118
+ }).channelId;
1119
+ }
1120
+ const CODEX_DYNAMIC_TOOL_BUILD_WARN_TOTAL_MS = 1e3;
1121
+ const CODEX_DYNAMIC_TOOL_BUILD_WARN_STAGE_MS = 500;
1122
+ /** Creates cheap optional timing instrumentation for the dynamic-tool hot path. */
1123
+ function createCodexDynamicToolBuildStageTracker(options = {}) {
1124
+ if (!options.enabled) return {
1125
+ mark() {},
1126
+ snapshot() {
1127
+ return {
1128
+ totalMs: 0,
1129
+ stages: []
1130
+ };
1131
+ }
1132
+ };
1133
+ const startedAt = Date.now();
1134
+ let previousAt = startedAt;
1135
+ const stages = [];
1136
+ const toMs = (value) => Math.max(0, Math.round(value));
1137
+ return {
1138
+ mark(name) {
1139
+ const currentAt = Date.now();
1140
+ stages.push({
1141
+ name,
1142
+ durationMs: toMs(currentAt - previousAt),
1143
+ elapsedMs: toMs(currentAt - startedAt)
1144
+ });
1145
+ previousAt = currentAt;
1146
+ },
1147
+ snapshot() {
1148
+ return {
1149
+ totalMs: toMs(Date.now() - startedAt),
1150
+ stages: stages.slice()
1151
+ };
1152
+ }
1153
+ };
1154
+ }
1155
+ /** Returns true when dynamic-tool construction is slow enough to warrant a warning log. */
1156
+ function shouldWarnCodexDynamicToolBuildStageSummary(summary) {
1157
+ return summary.totalMs >= CODEX_DYNAMIC_TOOL_BUILD_WARN_TOTAL_MS || summary.stages.some((stage) => stage.durationMs >= CODEX_DYNAMIC_TOOL_BUILD_WARN_STAGE_MS);
1158
+ }
1159
+ /** Formats per-stage timings into the compact form used by Codex app-server logs. */
1160
+ function formatCodexDynamicToolBuildStageSummary(summary) {
1161
+ return summary.stages.length > 0 ? summary.stages.map((stage) => `${stage.name}:${stage.durationMs}ms@${stage.elapsedMs}ms`).join(",") : "none";
1162
+ }
1163
+ /** Builds, filters, and normalizes Codex-compatible runtime tools for a single turn. */
1164
+ async function buildDynamicTools(input) {
1165
+ const { params } = input;
1166
+ const messagePolicyParams = input.ignoreDisableMessageTool ? {
1167
+ ...params,
1168
+ disableMessageTool: false
1169
+ } : params;
1170
+ if (params.disableTools) {
1171
+ input.onWebSearchPolicyResolved?.(false);
1172
+ return [];
1173
+ }
1174
+ if (!supportsModelTools(params.model)) {
1175
+ input.onPersistentWebSearchPolicyResolved?.(false);
1176
+ input.onWebSearchPolicyResolved?.(false);
1177
+ return [];
1178
+ }
1179
+ const toolBuildStages = createCodexDynamicToolBuildStageTracker({ enabled: input.profilerEnabled });
1180
+ const modelHasVision = params.model.input?.includes("image") ?? false;
1181
+ const agentDir = params.agentDir ?? resolveAgentDir(params.config ?? {}, input.sessionAgentId);
1182
+ const agentHarness = await import("openclaw/plugin-sdk/agent-harness");
1183
+ const createOpenClawCodingTools = agentHarness.createOpenClawCodingTools;
1184
+ toolBuildStages.mark("load-agent-harness-tools");
1185
+ const sessionKeys = resolveOpenClawCodingToolsSessionKeys(params, input.sandboxSessionKey);
1186
+ const nativeExecutionPolicy = resolveCodexNativeExecutionPolicyForDynamicTools(input);
1187
+ const allTools = createOpenClawCodingTools({
1188
+ agentId: input.sessionAgentId,
1189
+ ...buildEmbeddedAttemptToolRunContext(params),
1190
+ exec: {
1191
+ ...params.execOverrides,
1192
+ ...resolveNodeExecToolOverrides(nativeExecutionPolicy),
1193
+ config: params.config,
1194
+ elevated: params.bashElevated
1195
+ },
1196
+ sandbox: input.sandbox,
1197
+ messageProvider: resolveCodexMessageToolProvider(params),
1198
+ toolPolicyMessageProvider: params.messageProvider ?? params.messageChannel,
1199
+ agentAccountId: params.agentAccountId,
1200
+ messageTo: params.messageTo,
1201
+ messageThreadId: params.messageThreadId,
1202
+ groupId: params.groupId,
1203
+ groupChannel: params.groupChannel,
1204
+ groupSpace: params.groupSpace,
1205
+ spawnedBy: params.spawnedBy,
1206
+ senderId: params.senderId,
1207
+ senderName: params.senderName,
1208
+ senderUsername: params.senderUsername,
1209
+ senderE164: params.senderE164,
1210
+ allowGatewaySubagentBinding: params.allowGatewaySubagentBinding || isForcedPrivateQaCodexRuntime(),
1211
+ ...sessionKeys,
1212
+ sessionId: params.sessionId,
1213
+ runId: params.runId,
1214
+ agentDir,
1215
+ cwd: input.effectiveCwd ?? input.effectiveWorkspace,
1216
+ workspaceDir: input.effectiveWorkspace,
1217
+ spawnWorkspaceDir: input.effectiveCwd && input.effectiveCwd !== input.effectiveWorkspace ? input.resolvedWorkspace : resolveAttemptSpawnWorkspaceDir({
1218
+ sandbox: input.sandbox,
1219
+ resolvedWorkspace: input.resolvedWorkspace
1220
+ }),
1221
+ config: params.config,
1222
+ authProfileStore: params.toolAuthProfileStore ?? params.authProfileStore,
1223
+ abortSignal: input.runAbortController.signal,
1224
+ emitBeforeToolCallDiagnostics: false,
1225
+ modelProvider: params.model.provider,
1226
+ modelId: params.modelId,
1227
+ modelCompat: params.model.compat && typeof params.model.compat === "object" ? params.model.compat : void 0,
1228
+ modelApi: params.model.api,
1229
+ modelContextWindowTokens: params.model.contextWindow,
1230
+ modelAuthMode: resolveModelAuthMode(params.model.provider, params.config, params.toolAuthProfileStore ?? params.authProfileStore, { workspaceDir: input.effectiveWorkspace }),
1231
+ suppressManagedWebSearch: false,
1232
+ currentChannelId: params.currentChannelId,
1233
+ currentMessagingTarget: params.currentMessagingTarget,
1234
+ hookChannelId: resolveCodexAppServerHookChannelId(params, input.sandboxSessionKey),
1235
+ currentThreadTs: params.currentThreadTs,
1236
+ currentMessageId: params.currentMessageId,
1237
+ replyToMode: params.replyToMode,
1238
+ hasRepliedRef: params.hasRepliedRef,
1239
+ modelHasVision,
1240
+ requireExplicitMessageTarget: params.requireExplicitMessageTarget ?? isSubagentSessionKey(params.sessionKey),
1241
+ sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
1242
+ disableMessageTool: input.ignoreDisableMessageTool ? false : params.disableMessageTool,
1243
+ forceMessageTool: shouldForceMessageTool(messagePolicyParams),
1244
+ enableHeartbeatTool: params.trigger === "heartbeat" || input.forceHeartbeatTool === true,
1245
+ forceHeartbeatTool: params.trigger === "heartbeat" || input.forceHeartbeatTool === true,
1246
+ onYield: (message) => {
1247
+ input.onYieldDetected();
1248
+ input.onCodexAppServerEvent?.({
1249
+ stream: "codex_app_server.tool",
1250
+ data: {
1251
+ name: "sessions_yield",
1252
+ message
1253
+ }
1254
+ });
1255
+ },
1256
+ recordToolPrepStage: (name) => {
1257
+ toolBuildStages.mark(name);
1258
+ },
1259
+ onToolOutcome: params.onToolOutcome,
1260
+ allocateToolOutcomeOrdinal: params.allocateToolOutcomeOrdinal
1261
+ });
1262
+ toolBuildStages.mark("create-openclaw-coding-tools");
1263
+ const preNormalizationDiagnostics = [];
1264
+ const readableAllToolProjection = filterProviderNormalizableTools(allTools);
1265
+ preNormalizationDiagnostics.push(...readableAllToolProjection.diagnostics);
1266
+ const webSearchPlan = resolveCodexWebSearchPlan({
1267
+ config: params.config,
1268
+ disableTools: params.disableTools,
1269
+ nativeToolSurfaceEnabled: input.nativeToolSurfaceEnabled,
1270
+ nativeProviderWebSearchSupport: input.nativeProviderWebSearchSupport
1271
+ });
1272
+ const readableAllTools = [...readableAllToolProjection.tools];
1273
+ const codexFilteredTools = addNodeShellDynamicToolsIfNeeded(addSandboxShellDynamicToolsIfAvailable(isCodexMemoryFlushRun(params) ? filterCodexMemoryFlushDynamicTools(readableAllTools) : filterCodexDynamicTools(readableAllTools, input.pluginConfig), readableAllTools, input), readableAllTools, input, nativeExecutionPolicy);
1274
+ toolBuildStages.mark("codex-filtering");
1275
+ const visionFilteredTools = filterToolsForVisionInputs(codexFilteredTools, {
1276
+ modelHasVision,
1277
+ hasInboundImages: (params.images?.length ?? 0) > 0
1278
+ });
1279
+ toolBuildStages.mark("vision-filtering");
1280
+ const webSearchPresent = visionFilteredTools.some((tool) => tool.name === "web_search");
1281
+ const webSearchPolicy = agentHarness.resolveWebSearchToolPolicy({
1282
+ config: params.config,
1283
+ modelProvider: params.model.provider,
1284
+ modelId: params.modelId,
1285
+ agentId: input.sessionAgentId,
1286
+ sessionKey: input.sandboxSessionKey,
1287
+ sandboxToolPolicy: input.sandbox?.tools,
1288
+ messageProvider: resolveCodexMessageToolProvider(params),
1289
+ agentAccountId: params.agentAccountId,
1290
+ groupId: params.groupId,
1291
+ groupChannel: params.groupChannel,
1292
+ groupSpace: params.groupSpace,
1293
+ spawnedBy: params.spawnedBy,
1294
+ senderId: params.senderId,
1295
+ senderName: params.senderName,
1296
+ senderUsername: params.senderUsername,
1297
+ senderE164: params.senderE164
1298
+ });
1299
+ const transientWebSearchRestriction = !webSearchPolicy.allowed && webSearchPolicy.persistentAllowed || isCodexMemoryFlushRun(params);
1300
+ const persistentCodexWebSearchSurface = params.config?.tools?.web?.search?.enabled !== false && !(input.pluginConfig.codexDynamicToolsExclude ?? []).some((name) => normalizeCodexDynamicToolName(name) === "web_search");
1301
+ input.onPersistentWebSearchPolicyResolved?.(webSearchPresent || persistentCodexWebSearchSurface && transientWebSearchRestriction && webSearchPolicy.persistentAllowed);
1302
+ const filteredTools = filterCodexDynamicToolsForAllowlist(visionFilteredTools, includeForcedCodexDynamicToolAllow(params.toolsAllow, messagePolicyParams));
1303
+ toolBuildStages.mark("allowlist-filter");
1304
+ const normalizedTools = normalizeAgentRuntimeTools({
1305
+ runtimePlan: input.ignoreRuntimePlan ? void 0 : params.runtimePlan,
1306
+ tools: filteredTools,
1307
+ provider: params.provider,
1308
+ config: params.config,
1309
+ workspaceDir: input.effectiveWorkspace,
1310
+ env: process.env,
1311
+ modelId: params.modelId,
1312
+ modelApi: params.model.api,
1313
+ model: params.model,
1314
+ onPreNormalizationSchemaDiagnostics: (diagnostics) => preNormalizationDiagnostics.push(...diagnostics)
1315
+ });
1316
+ toolBuildStages.mark("runtime-normalization");
1317
+ input.onWebSearchPolicyResolved?.(normalizedTools.some((tool) => tool.name === "web_search"));
1318
+ const exposedTools = webSearchPlan.suppressManagedWebSearch ? normalizedTools.filter((tool) => tool.name !== "web_search") : normalizedTools;
1319
+ if (preNormalizationDiagnostics.length > 0) embeddedAgentLog.warn(`codex app-server quarantined ${preNormalizationDiagnostics.length} unsupported runtime tool schema${preNormalizationDiagnostics.length === 1 ? "" : "s"} before dynamic tool registration`, {
1320
+ runId: params.runId,
1321
+ sessionId: params.sessionId,
1322
+ diagnostics: preNormalizationDiagnostics.map((diagnostic) => ({
1323
+ index: diagnostic.toolIndex,
1324
+ tool: diagnostic.toolName,
1325
+ violations: diagnostic.violations.slice(0, 12),
1326
+ violationCount: diagnostic.violations.length
1327
+ }))
1328
+ });
1329
+ const summary = toolBuildStages.snapshot();
1330
+ if (shouldWarnCodexDynamicToolBuildStageSummary(summary)) {
1331
+ const phase = input.forceHeartbeatTool ? "registered-tools" : "runtime-tools";
1332
+ embeddedAgentLog.warn(`codex app-server dynamic tool build timings runId=${params.runId} sessionId=${params.sessionId} phase=${phase} totalMs=${summary.totalMs} stages=${formatCodexDynamicToolBuildStageSummary(summary)}`, {
1333
+ runId: params.runId,
1334
+ sessionId: params.sessionId,
1335
+ phase,
1336
+ totalMs: summary.totalMs,
1337
+ stages: summary.stages,
1338
+ allToolCount: readableAllTools.length,
1339
+ codexFilteredToolCount: codexFilteredTools.length,
1340
+ visionFilteredToolCount: visionFilteredTools.length,
1341
+ filteredToolCount: filteredTools.length,
1342
+ normalizedToolCount: exposedTools.length,
1343
+ forceHeartbeatTool: input.forceHeartbeatTool === true,
1344
+ ignoreRuntimePlan: input.ignoreRuntimePlan === true,
1345
+ nativeToolSurfaceEnabled: input.nativeToolSurfaceEnabled === true
1346
+ });
1347
+ }
1348
+ return exposedTools;
1349
+ }
1350
+ /** Preserves delivery-critical tools when a narrow allowlist would otherwise hide them. */
1351
+ function includeForcedCodexDynamicToolAllow(toolsAllow, params) {
1352
+ if (toolsAllow === void 0 || hasWildcardCodexToolsAllow(toolsAllow)) return toolsAllow;
1353
+ const forcedToolNames = shouldForceMessageTool(params) ? ["message"] : [];
1354
+ if (forcedToolNames.length === 0) return toolsAllow;
1355
+ if (toolsAllow.length === 0) return forcedToolNames;
1356
+ const normalized = new Set(toolsAllow.map((name) => normalizeCodexDynamicToolName(name)));
1357
+ const missingToolNames = forcedToolNames.filter((toolName) => !normalized.has(normalizeCodexDynamicToolName(toolName)));
1358
+ return missingToolNames.length === 0 ? toolsAllow : [...toolsAllow, ...missingToolNames];
1359
+ }
1360
+ /** Decides whether Codex native code mode can own shell/file tools for this turn. */
1361
+ function shouldEnableCodexAppServerNativeToolSurface(params, sandbox, options = {}) {
1362
+ if (isCodexMemoryFlushRun(params)) return false;
1363
+ const toolsAllow = includeForcedCodexDynamicToolAllow(params.toolsAllow, params);
1364
+ if (toolsAllow === void 0) return canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
1365
+ return hasWildcardCodexToolsAllow(toolsAllow) && canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
1366
+ }
1367
+ /** Returns true when OpenClaw policy requires the Node-owned exec/process tools instead. */
1368
+ function isCodexNativeExecutionBlockedByNodeExecHost(params, options = {}) {
1369
+ return !resolveCodexNativeExecutionPolicy({
1370
+ config: params.config,
1371
+ sessionKey: resolveCodexRuntimePolicySessionKey(params, options.runtimeSessionKey),
1372
+ sessionId: params.sessionId,
1373
+ agentId: options.agentId,
1374
+ execOverrides: params.execOverrides,
1375
+ sandboxAvailable: options.sandbox?.enabled,
1376
+ readRuntimeSessionEntry: true
1377
+ }).nativeToolSurfaceAllowed;
1378
+ }
1379
+ function resolveCodexRuntimePolicySessionKey(params, runtimeSessionKey) {
1380
+ return runtimeSessionKey?.trim() || params.sandboxSessionKey?.trim() || params.sessionKey?.trim() || params.sessionId;
1381
+ }
1382
+ function canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options = {}) {
1383
+ if (!sandbox?.enabled) return true;
1384
+ if (options.sandboxExecServerEnabled === true && sandbox.backend && canSandboxToolPolicyExposeCodexNativeToolSurface(sandbox)) return true;
1385
+ return false;
1386
+ }
1387
+ function canSandboxToolPolicyExposeCodexNativeToolSurface(sandbox) {
1388
+ return CODEX_NATIVE_SANDBOX_TOOL_REQUIREMENTS.every((toolName) => isToolAllowed(sandbox.tools, toolName));
1389
+ }
1390
+ function isCodexMemoryFlushRun(params) {
1391
+ return params?.trigger === "memory" && Boolean(params.memoryFlushWritePath?.trim());
1392
+ }
1393
+ function filterCodexMemoryFlushDynamicTools(tools) {
1394
+ return tools.filter((tool) => CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW.has(normalizeCodexDynamicToolName(tool.name)));
1395
+ }
1396
+ /** Requires a Codex sandbox environment only when native tools must run inside OpenClaw sandboxing. */
1397
+ function shouldRequireCodexSandboxExecServerEnvironment(params) {
1398
+ return Boolean(params.sandbox?.enabled && params.nativeToolSurfaceEnabled && params.sandboxExecServerEnabled);
1399
+ }
1400
+ /** Selects the sandbox exec-server environment passed through the Codex app-server protocol. */
1401
+ function resolveCodexSandboxEnvironmentSelection(environment, nativeToolSurfaceEnabled) {
1402
+ return environment && nativeToolSurfaceEnabled ? [environment] : void 0;
1403
+ }
1404
+ /** Chooses the cwd visible to Codex native execution after sandbox exec-server setup. */
1405
+ function resolveCodexAppServerExecutionCwd(params) {
1406
+ return mapCodexAppServerRemoteWorkspacePath({
1407
+ value: params.environment && params.nativeToolSurfaceEnabled ? params.environment.cwd : params.effectiveCwd,
1408
+ localWorkspaceRoot: params.localWorkspaceRoot,
1409
+ remoteWorkspaceRoot: params.remoteWorkspaceRoot
1410
+ });
1411
+ }
1412
+ /** Projects a local OpenClaw workspace cwd into the remote Codex app-server workspace root. */
1413
+ function mapCodexAppServerRemoteWorkspacePath(params) {
1414
+ if (!params.remoteWorkspaceRoot) return params.value;
1415
+ const localRoot = normalizeRemoteWorkspaceMatchPath(params.localWorkspaceRoot);
1416
+ const remoteRoot = normalizeRemoteWorkspaceMatchPath(params.remoteWorkspaceRoot);
1417
+ const normalizedValue = normalizeRemoteWorkspaceMatchPath(params.value);
1418
+ if (!localRoot || !remoteRoot) throw new Error("Codex remoteWorkspaceRoot requires non-empty workspace roots.");
1419
+ if (normalizedValue === localRoot) return remoteRoot;
1420
+ const prefix = `${localRoot}/`;
1421
+ if (!normalizedValue.startsWith(prefix)) throw new Error(`Codex remoteWorkspaceRoot is configured but cwd ${params.value} is outside OpenClaw workspace root ${params.localWorkspaceRoot}; refusing to send a gateway-local cwd to the remote Codex app-server.`);
1422
+ return joinRemoteWorkspacePath(remoteRoot, normalizedValue.slice(prefix.length));
1423
+ }
1424
+ function normalizeRemoteWorkspaceMatchPath(value) {
1425
+ return trimTrailingPathSeparator(value.replace(/\\/gu, "/"));
1426
+ }
1427
+ function trimTrailingPathSeparator(value) {
1428
+ return value.length > 1 ? value.replace(/[\\/]+$/u, "") : value;
1429
+ }
1430
+ function joinRemoteWorkspacePath(remoteRoot, suffix) {
1431
+ return remoteRoot === "/" ? `/${suffix}` : `${remoteRoot}/${suffix}`;
1432
+ }
1433
+ /** Converts OpenClaw sandbox networking into Codex's external-sandbox policy shape. */
1434
+ function resolveCodexExternalSandboxPolicyForOpenClawSandbox(sandbox) {
1435
+ return {
1436
+ type: "externalSandbox",
1437
+ networkAccess: codexNetworkAccessForOpenClawSandbox(sandbox) ? "enabled" : "restricted"
1438
+ };
1439
+ }
1440
+ function codexNetworkAccessForOpenClawSandbox(sandbox) {
1441
+ if (sandbox?.backendId !== "docker") return true;
1442
+ const network = sandbox?.docker?.network?.trim().toLowerCase();
1443
+ return Boolean(network && network !== "none");
1444
+ }
1445
+ /** Returns a Codex config copy with app-server Codex plugin loading disabled for thread tools. */
1446
+ function disableCodexPluginThreadConfig(pluginConfig) {
1447
+ const config = readCodexPluginConfig(pluginConfig);
1448
+ return {
1449
+ ...config,
1450
+ codexPlugins: {
1451
+ ...config.codexPlugins,
1452
+ enabled: false
1453
+ }
1454
+ };
1455
+ }
1456
+ /** Adds sandbox_exec/process aliases when native Code Mode cannot directly honor the sandbox. */
1457
+ function addSandboxShellDynamicToolsIfAvailable(filteredTools, allTools, input) {
1458
+ if (!shouldExposeSandboxExecDynamicTool(input) || isSandboxShellDynamicToolExcluded(input.pluginConfig)) return filteredTools;
1459
+ const execTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "exec");
1460
+ const processTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "process");
1461
+ if (!execTool || !processTool) return filteredTools;
1462
+ const sandboxExecTool = {
1463
+ ...execTool,
1464
+ name: "sandbox_exec",
1465
+ description: "Run a shell command through OpenClaw's configured sandbox backend for this session. Use when OpenClaw sandboxing is active or when a command must execute in the sandbox backend, such as an SSH-backed sandbox or Docker container-path bind layout. Use Codex's native shell only when no OpenClaw sandbox is active and native Code Mode is available.",
1466
+ execute: async (toolCallId, args, signal, onUpdate) => {
1467
+ const result = await execTool.execute(toolCallId, args, signal, onUpdate);
1468
+ return {
1469
+ ...result,
1470
+ content: result.content.map((item) => item.type === "text" ? Object.assign({}, item, { text: item.text.replace("Use process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.", "Use sandbox_process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.") }) : item)
1471
+ };
1472
+ }
1473
+ };
1474
+ const sandboxProcessTool = {
1475
+ ...processTool,
1476
+ name: "sandbox_process",
1477
+ description: "Manage sandbox_exec sessions that were started through OpenClaw's configured sandbox backend for this session: list, poll, log, write, send-keys, submit, paste, kill, clear, or remove. Use only for sandbox_exec follow-up; use Codex's native shell session handling only when no OpenClaw sandbox is active and native Code Mode is available."
1478
+ };
1479
+ return [
1480
+ ...filteredTools,
1481
+ sandboxExecTool,
1482
+ sandboxProcessTool
1483
+ ];
1484
+ }
1485
+ function shouldExposeSandboxExecDynamicTool(input) {
1486
+ if (isCodexMemoryFlushRun(input.params)) return false;
1487
+ if (isCodexNativeExecutionBlockedByNodeExecHost(input.params, {
1488
+ agentId: input.sessionAgentId,
1489
+ runtimeSessionKey: input.sandboxSessionKey,
1490
+ sandbox: input.sandbox
1491
+ })) return false;
1492
+ const backendId = input.sandbox?.enabled ? input.sandbox.backendId.trim().toLowerCase() : "";
1493
+ return Boolean(backendId && input.nativeToolSurfaceEnabled === false);
1494
+ }
1495
+ function isCodexDynamicToolExcluded(config, names) {
1496
+ const normalizedNames = new Set(names.map((name) => normalizeCodexDynamicToolName(name)));
1497
+ return (config.codexDynamicToolsExclude ?? []).some((name) => {
1498
+ const normalized = normalizeCodexDynamicToolName(name);
1499
+ return normalizedNames.has(normalized);
1500
+ });
1501
+ }
1502
+ function isSandboxShellDynamicToolExcluded(config) {
1503
+ return isCodexDynamicToolExcluded(config, [
1504
+ "exec",
1505
+ "sandbox_exec",
1506
+ "process",
1507
+ "sandbox_process"
1508
+ ]);
1509
+ }
1510
+ function addNodeShellDynamicToolsIfNeeded(filteredTools, allTools, input, nodePolicy) {
1511
+ if (isCodexMemoryFlushRun(input.params)) return filteredTools;
1512
+ if (nodePolicy.effectiveExecHost !== "node") return filteredTools;
1513
+ const execTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "exec");
1514
+ const processTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "process");
1515
+ if (!execTool || !processTool) return filteredTools;
1516
+ const toolsToAppend = [];
1517
+ if (!isCodexDynamicToolExcluded(input.pluginConfig, ["exec", CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME]) && !filteredTools.some((tool) => normalizeCodexDynamicToolName(tool.name) === CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME)) toolsToAppend.push(createNodeExecDynamicTool(execTool, nodePolicy.node));
1518
+ if (!isCodexDynamicToolExcluded(input.pluginConfig, ["process", CODEX_NODE_PROCESS_DYNAMIC_TOOL_NAME]) && !filteredTools.some((tool) => normalizeCodexDynamicToolName(tool.name) === CODEX_NODE_PROCESS_DYNAMIC_TOOL_NAME)) toolsToAppend.push(createNodeProcessDynamicTool(processTool));
1519
+ return toolsToAppend.length > 0 ? [...filteredTools, ...toolsToAppend] : filteredTools;
1520
+ }
1521
+ function createNodeExecDynamicTool(execTool, configuredNode) {
1522
+ return {
1523
+ ...execTool,
1524
+ name: CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME,
1525
+ description: "Run a shell command 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. Use node_process for follow-up on backgrounded node_exec sessions. Use Codex's native shell for local app-server work.",
1526
+ parameters: hideNodeExecDynamicToolParameters(execTool.parameters),
1527
+ execute: async (toolCallId, args, signal, onUpdate) => {
1528
+ const result = await execTool.execute(toolCallId, pinNodeExecDynamicToolArgs(args, configuredNode), signal, onUpdate);
1529
+ return {
1530
+ ...result,
1531
+ content: result.content.map((item) => item.type === "text" ? Object.assign({}, item, { text: item.text.replace("Use process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.", "Use node_process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.") }) : item)
1532
+ };
1533
+ }
1534
+ };
1535
+ }
1536
+ function createNodeProcessDynamicTool(processTool) {
1537
+ return {
1538
+ ...processTool,
1539
+ name: CODEX_NODE_PROCESS_DYNAMIC_TOOL_NAME,
1540
+ description: "Manage node_exec sessions that were started on the OpenClaw configured remote node for this session: list, poll, log, write, send-keys, submit, paste, kill, clear, or remove. Use only for node_exec follow-up; use Codex's native shell session handling for local app-server work."
1541
+ };
1542
+ }
1543
+ function pinNodeExecDynamicToolArgs(args, configuredNode) {
1544
+ const { host: _host, security: _security, ask: _ask, node: _node, ...rest } = args && typeof args === "object" && !Array.isArray(args) ? args : {};
1545
+ const node = configuredNode?.trim();
1546
+ return {
1547
+ ...rest,
1548
+ host: "node",
1549
+ ...node ? { node } : {}
1550
+ };
1551
+ }
1552
+ function hideNodeExecDynamicToolParameters(parameters) {
1553
+ if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) return parameters;
1554
+ const schema = parameters;
1555
+ const rawProperties = schema.properties;
1556
+ if (!rawProperties || typeof rawProperties !== "object" || Array.isArray(rawProperties)) return parameters;
1557
+ const nextProperties = Object.fromEntries(Object.entries(rawProperties).filter(([name]) => !CODEX_NODE_EXEC_HIDDEN_PARAMETER_NAMES.has(normalizeCodexDynamicToolName(name))));
1558
+ const rawRequired = schema.required;
1559
+ const nextRequired = Array.isArray(rawRequired) ? rawRequired.filter((name) => typeof name !== "string" || !CODEX_NODE_EXEC_HIDDEN_PARAMETER_NAMES.has(normalizeCodexDynamicToolName(name))) : rawRequired;
1560
+ return {
1561
+ ...schema,
1562
+ properties: nextProperties,
1563
+ ...Array.isArray(rawRequired) ? { required: nextRequired } : {}
1564
+ };
1565
+ }
1566
+ function resolveCodexNativeExecutionPolicyForDynamicTools(input) {
1567
+ return resolveCodexNativeExecutionPolicy({
1568
+ config: input.params.config,
1569
+ sessionKey: resolveCodexRuntimePolicySessionKey(input.params, input.sandboxSessionKey),
1570
+ sessionId: input.params.sessionId,
1571
+ agentId: input.sessionAgentId,
1572
+ execOverrides: input.params.execOverrides,
1573
+ sandboxAvailable: input.sandbox?.enabled,
1574
+ readRuntimeSessionEntry: true
1575
+ });
1576
+ }
1577
+ function resolveNodeExecToolOverrides(policy) {
1578
+ if (policy.effectiveExecHost !== "node") return;
1579
+ const node = policy.node?.trim();
1580
+ return {
1581
+ host: "node",
1582
+ ...node ? { node } : {}
1583
+ };
1584
+ }
1585
+ /** Applies a normalized tool allowlist while preserving shell aliases for exec/process. */
1586
+ function filterCodexDynamicToolsForAllowlist(tools, toolsAllow) {
1587
+ if (!toolsAllow) return tools;
1588
+ if (toolsAllow.length === 0) return [];
1589
+ if (hasWildcardCodexToolsAllow(toolsAllow)) return tools;
1590
+ const allowSet = new Set(toolsAllow.map((name) => normalizeCodexDynamicToolName(name)).filter(Boolean));
1591
+ return tools.filter((tool) => {
1592
+ const normalized = normalizeCodexDynamicToolName(tool.name);
1593
+ return allowSet.has(normalized) || normalized === "sandbox_exec" && allowSet.has("exec") || normalized === "sandbox_process" && (allowSet.has("exec") || allowSet.has("process")) || normalized === CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME && allowSet.has("exec") || normalized === CODEX_NODE_PROCESS_DYNAMIC_TOOL_NAME && (allowSet.has("exec") || allowSet.has("process"));
1594
+ });
1595
+ }
1596
+ /** Detects the wildcard allowlist marker after Codex tool-name normalization. */
1597
+ function hasWildcardCodexToolsAllow(toolsAllow) {
1598
+ return toolsAllow.some((name) => normalizeCodexDynamicToolName(name) === "*");
1599
+ }
1600
+ /** Forces message delivery through the message tool when the source channel requires it. */
1601
+ function shouldForceMessageTool(params) {
1602
+ return params.disableMessageTool !== true && params.sourceReplyDeliveryMode === "message_tool_only";
1603
+ }
1604
+ //#endregion
1071
1605
  //#region extensions/codex/src/app-server/dynamic-tool-diagnostics.ts
1072
1606
  /**
1073
1607
  * Trusted diagnostics emitted around Codex dynamic tool execution lifecycle.
@@ -1128,6 +1662,15 @@ function emitDynamicToolTerminalDiagnostic(params) {
1128
1662
  }
1129
1663
  //#endregion
1130
1664
  //#region extensions/codex/src/app-server/dynamic-tools.ts
1665
+ function applyCurrentMessageProvider(toolName, args, currentProvider) {
1666
+ const hasProvider = typeof args.provider === "string" && args.provider.trim().length > 0 ? true : typeof args.channel === "string" && args.channel.trim().length > 0;
1667
+ const provider = currentProvider?.trim();
1668
+ if (toolName !== "message" || hasProvider || !provider) return args;
1669
+ return {
1670
+ ...args,
1671
+ provider
1672
+ };
1673
+ }
1131
1674
  /** Namespace attached to OpenClaw-owned dynamic tools exposed to Codex. */
1132
1675
  const CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE = "openclaw";
1133
1676
  const ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES = new Set(["sessions_yield"]);
@@ -1168,24 +1711,38 @@ function createCodexDynamicToolBridge(params) {
1168
1711
  runtime: "codex",
1169
1712
  ...toolResultHookContext
1170
1713
  });
1714
+ const isReplaySafeToolInstance = (tool) => {
1715
+ const pluginMeta = getPluginToolMeta(tool);
1716
+ if (pluginMeta) return pluginMeta.replaySafe === true;
1717
+ return getChannelAgentToolMeta(tool) === void 0;
1718
+ };
1171
1719
  const legacyExtensionRunner = createCodexAppServerToolResultExtensionRunner(toolResultHookContext);
1172
1720
  const directToolNames = new Set([...ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES, ...params.directToolNames ?? []]);
1173
1721
  return {
1174
- availableSpecs: availableTools.map((entry) => createCodexDynamicToolSpec({
1175
- entry,
1722
+ availableSpecs: createCodexDynamicToolSpecs({
1723
+ entries: availableTools,
1176
1724
  loading: params.loading ?? "searchable",
1177
1725
  directToolNames
1178
- })),
1179
- specs: registeredSpecTools.map((entry) => createCodexDynamicToolSpec({
1180
- entry,
1726
+ }),
1727
+ specs: createCodexDynamicToolSpecs({
1728
+ entries: registeredSpecTools,
1181
1729
  loading: params.loading ?? "searchable",
1182
1730
  directToolNames
1183
- })),
1731
+ }),
1184
1732
  telemetry,
1185
1733
  handleToolCall: async (call, options) => {
1186
1734
  const toolEntry = toolMap.get(call.tool);
1187
1735
  if (!toolEntry) {
1188
1736
  const message = registeredToolNames.has(call.tool) ? `OpenClaw tool is not available for this turn: ${call.tool}` : `Unknown OpenClaw tool: ${call.tool}`;
1737
+ finalizeToolTerminalPresentation({
1738
+ toolCallId: call.callId,
1739
+ runId: toolResultHookContext.runId,
1740
+ result: failedToolResult(message),
1741
+ isError: true,
1742
+ observer: params.hookContext?.onToolOutcome,
1743
+ toolName: call.tool,
1744
+ toolCallOrdinal: options?.toolCallOrdinal
1745
+ });
1189
1746
  notifyAgentToolResult(options?.onAgentToolResult, call.tool, failedToolResult(message), true);
1190
1747
  if (registeredToolNames.has(call.tool)) return {
1191
1748
  contentItems: [{
@@ -1207,17 +1764,33 @@ function createCodexDynamicToolBridge(params) {
1207
1764
  const startedAt = Date.now();
1208
1765
  const signal = composeAbortSignals(params.signal, options?.signal);
1209
1766
  let didStartExecution = false;
1767
+ let executionPrevented = false;
1768
+ let executedArgs = structuredClone(args);
1210
1769
  try {
1211
1770
  const preparedArgs = tool.prepareArguments ? tool.prepareArguments(args) : args;
1771
+ const telemetryArgs = isRecord(preparedArgs) ? preparedArgs : args;
1772
+ executedArgs = structuredClone(telemetryArgs);
1773
+ const messagingContext = {
1774
+ config: params.hookContext?.config,
1775
+ currentChannelId: params.hookContext?.currentChannelId,
1776
+ currentMessagingTarget: params.hookContext?.currentMessagingTarget,
1777
+ currentThreadId: params.hookContext?.currentThreadId,
1778
+ replyToMode: params.hookContext?.replyToMode,
1779
+ hasRepliedRef: params.hookContext?.hasRepliedRef ? { value: params.hookContext.hasRepliedRef.value } : void 0
1780
+ };
1212
1781
  didStartExecution = true;
1213
1782
  const rawResult = await tool.execute(call.callId, preparedArgs, signal);
1783
+ const adjustedExecutedArgs = consumeAdjustedParamsForToolCall(call.callId, toolResultHookContext.runId);
1784
+ if (isRecord(adjustedExecutedArgs)) executedArgs = structuredClone(adjustedExecutedArgs);
1785
+ executionPrevented = consumePreExecutionBlockedToolCall(call.callId, toolResultHookContext.runId);
1786
+ const telemetryRawResult = sanitizeToolResult(rawResult);
1214
1787
  const rawIsError = isCodexToolResultError(rawResult);
1215
1788
  const middlewareResult = await middlewareRunner.applyToolResultMiddleware({
1216
1789
  threadId: call.threadId,
1217
1790
  turnId: call.turnId,
1218
1791
  toolCallId: call.callId,
1219
1792
  toolName,
1220
- args,
1793
+ args: structuredClone(executedArgs),
1221
1794
  isError: rawIsError,
1222
1795
  result: rawResult
1223
1796
  });
@@ -1226,19 +1799,11 @@ function createCodexDynamicToolBridge(params) {
1226
1799
  turnId: call.turnId,
1227
1800
  toolCallId: call.callId,
1228
1801
  toolName,
1229
- args,
1802
+ args: structuredClone(executedArgs),
1230
1803
  result: middlewareResult
1231
1804
  });
1232
1805
  const resultIsError = rawIsError || isCodexToolResultError(result);
1233
1806
  notifyAgentToolResult(options?.onAgentToolResult, toolName, result, resultIsError);
1234
- collectToolTelemetry({
1235
- toolName,
1236
- args,
1237
- result,
1238
- mediaTrustResult: rawResult,
1239
- telemetry,
1240
- isError: resultIsError
1241
- });
1242
1807
  runAgentHarnessAfterToolCallHook({
1243
1808
  toolName,
1244
1809
  toolCallId: call.callId,
@@ -1247,24 +1812,59 @@ function createCodexDynamicToolBridge(params) {
1247
1812
  sessionId: toolResultHookContext.sessionId,
1248
1813
  sessionKey: toolResultHookContext.sessionKey,
1249
1814
  channelId: toolResultHookContext.channelId,
1250
- startArgs: args,
1815
+ startArgs: executedArgs,
1251
1816
  result,
1252
1817
  startedAt
1253
1818
  });
1819
+ finalizeToolTerminalPresentation({
1820
+ toolCallId: call.callId,
1821
+ runId: toolResultHookContext.runId,
1822
+ result,
1823
+ isError: resultIsError,
1824
+ observer: params.hookContext?.onToolOutcome,
1825
+ toolName,
1826
+ toolCallOrdinal: options?.toolCallOrdinal
1827
+ });
1828
+ const messagingTelemetryArgs = applyCurrentMessageProvider(toolName, executedArgs, params.hookContext?.currentChannelProvider);
1829
+ const messagingTarget = isMessagingTool(toolName) && isMessagingToolSendAction(toolName, executedArgs) ? extractMessagingToolSend(toolName, messagingTelemetryArgs, messagingContext) : void 0;
1830
+ const confirmedMessagingTarget = !rawIsError && messagingTarget ? extractMessagingToolSendResult(messagingTarget, telemetryRawResult) : messagingTarget;
1831
+ collectToolTelemetry({
1832
+ toolName,
1833
+ args: executedArgs,
1834
+ result,
1835
+ mediaTrustResult: telemetryRawResult,
1836
+ telemetry,
1837
+ isError: resultIsError,
1838
+ messagingTarget: confirmedMessagingTarget
1839
+ });
1254
1840
  const terminalType = inferToolResultDiagnosticTerminalType(result, resultIsError);
1255
1841
  const response = withDiagnosticTerminalType({
1256
1842
  contentItems: convertToolContents(result.content, toolResultMaxChars),
1257
1843
  success: !resultIsError
1258
1844
  }, terminalType);
1259
1845
  withDynamicToolTermination(response, rawResult.terminate === true || result.terminate === true || isToolResultYield(rawResult) || isToolResultYield(result));
1260
- withDynamicToolAsyncStarted(response, isAsyncStartedToolResult(rawResult) || isAsyncStartedToolResult(result));
1261
- return withSideEffectEvidence(response, terminalType !== "blocked");
1846
+ const asyncStarted = isAsyncStartedToolResult(rawResult) || isAsyncStartedToolResult(result);
1847
+ withDynamicToolAsyncStarted(response, asyncStarted);
1848
+ return withSideEffectEvidence(response, !(executionPrevented || !asyncStarted && isReplaySafeToolInstance(toolEntry.tool) && isReplaySafeToolCall(toolName, executedArgs)));
1262
1849
  } catch (error) {
1263
1850
  const errorMessage = error instanceof Error ? error.message : String(error);
1264
- notifyAgentToolResult(options?.onAgentToolResult, toolName, failedToolResult(errorMessage), true);
1851
+ const adjustedExecutedArgs = consumeAdjustedParamsForToolCall(call.callId, toolResultHookContext.runId);
1852
+ if (isRecord(adjustedExecutedArgs)) executedArgs = structuredClone(adjustedExecutedArgs);
1853
+ executionPrevented = executionPrevented || consumePreExecutionBlockedToolCall(call.callId, toolResultHookContext.runId);
1854
+ const failedResult = failedToolResult(errorMessage);
1855
+ finalizeToolTerminalPresentation({
1856
+ toolCallId: call.callId,
1857
+ runId: toolResultHookContext.runId,
1858
+ result: failedResult,
1859
+ isError: true,
1860
+ observer: params.hookContext?.onToolOutcome,
1861
+ toolName,
1862
+ toolCallOrdinal: options?.toolCallOrdinal
1863
+ });
1864
+ notifyAgentToolResult(options?.onAgentToolResult, toolName, failedResult, true);
1265
1865
  collectToolTelemetry({
1266
1866
  toolName,
1267
- args,
1867
+ args: executedArgs,
1268
1868
  result: void 0,
1269
1869
  telemetry,
1270
1870
  isError: true
@@ -1277,17 +1877,18 @@ function createCodexDynamicToolBridge(params) {
1277
1877
  sessionId: toolResultHookContext.sessionId,
1278
1878
  sessionKey: toolResultHookContext.sessionKey,
1279
1879
  channelId: toolResultHookContext.channelId,
1280
- startArgs: args,
1880
+ startArgs: executedArgs,
1281
1881
  error: errorMessage,
1282
1882
  startedAt
1283
1883
  });
1884
+ const replaySafe = !didStartExecution || executionPrevented || isReplaySafeToolInstance(toolEntry.tool) && isReplaySafeToolCall(toolName, executedArgs);
1284
1885
  return withSideEffectEvidence(withDiagnosticTerminalType({
1285
1886
  contentItems: [{
1286
1887
  type: "inputText",
1287
1888
  text: errorMessage
1288
1889
  }],
1289
1890
  success: false
1290
- }, "error"), didStartExecution);
1891
+ }, "error"), didStartExecution && !replaySafe);
1291
1892
  }
1292
1893
  }
1293
1894
  };
@@ -1339,18 +1940,35 @@ function wrapProjectedCodexDynamicTools(tools, hookContext) {
1339
1940
  quarantinedTools
1340
1941
  };
1341
1942
  }
1342
- function createCodexDynamicToolSpec(params) {
1343
- const base = {
1943
+ function createCodexDynamicToolSpecs(params) {
1944
+ const specs = [];
1945
+ const namespaceTools = [];
1946
+ for (const entry of params.entries) {
1947
+ const functionSpec = createCodexDynamicToolFunctionSpec({ entry });
1948
+ if (params.loading === "direct" || params.directToolNames.has(entry.name)) {
1949
+ specs.push(functionSpec);
1950
+ continue;
1951
+ }
1952
+ namespaceTools.push({
1953
+ ...functionSpec,
1954
+ deferLoading: true
1955
+ });
1956
+ }
1957
+ if (namespaceTools.length > 0) specs.push({
1958
+ type: "namespace",
1959
+ name: CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE,
1960
+ description: "",
1961
+ tools: namespaceTools
1962
+ });
1963
+ return specs;
1964
+ }
1965
+ function createCodexDynamicToolFunctionSpec(params) {
1966
+ return {
1967
+ type: "function",
1344
1968
  name: params.entry.name,
1345
1969
  description: params.entry.description,
1346
1970
  inputSchema: params.entry.inputSchema
1347
1971
  };
1348
- if (params.loading === "direct" || params.directToolNames.has(params.entry.name)) return base;
1349
- return {
1350
- ...base,
1351
- namespace: CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE,
1352
- deferLoading: true
1353
- };
1354
1972
  }
1355
1973
  function projectCodexDynamicTools(tools) {
1356
1974
  const projectedTools = [];
@@ -1553,19 +2171,21 @@ function collectToolTelemetry(params) {
1553
2171
  const mediaUrls = collectMediaUrls(params.args);
1554
2172
  params.telemetry.messagingToolSentMediaUrls.push(...mediaUrls);
1555
2173
  params.telemetry.messagingToolSentTargets.push({
1556
- tool: params.toolName,
1557
- provider: readFirstString$1(params.args, ["provider", "channel"]) ?? params.toolName,
1558
- accountId: readFirstString$1(params.args, ["accountId", "account_id"]),
1559
- to: readFirstString$1(params.args, [
1560
- "to",
1561
- "target",
1562
- "recipient"
1563
- ]),
1564
- threadId: readFirstString$1(params.args, [
1565
- "threadId",
1566
- "thread_id",
1567
- "messageThreadId"
1568
- ]),
2174
+ ...params.messagingTarget ?? {
2175
+ tool: params.toolName,
2176
+ provider: readFirstString$1(params.args, ["provider", "channel"]) ?? params.toolName,
2177
+ accountId: readFirstString$1(params.args, ["accountId", "account_id"]),
2178
+ to: readFirstString$1(params.args, [
2179
+ "to",
2180
+ "target",
2181
+ "recipient"
2182
+ ]),
2183
+ threadId: readFirstString$1(params.args, [
2184
+ "threadId",
2185
+ "thread_id",
2186
+ "messageThreadId"
2187
+ ])
2188
+ },
1569
2189
  ...text ? { text } : {},
1570
2190
  ...mediaUrls.length > 0 ? { mediaUrls } : {}
1571
2191
  });
@@ -1845,17 +2465,22 @@ async function handleCodexAppServerElicitationRequest(params) {
1845
2465
  logPluginElicitationDecline("missing_active_turn", requestParams);
1846
2466
  return declineElicitationResponse();
1847
2467
  }
1848
- return buildPluginPolicyElicitationResponse(pluginResolution.entry, requestParams);
2468
+ return await buildPluginPolicyElicitationResponse({
2469
+ entry: pluginResolution.entry,
2470
+ requestParams,
2471
+ paramsForRun: params.paramsForRun,
2472
+ signal: params.signal
2473
+ });
1849
2474
  }
1850
2475
  const approvalPrompt = readComputerUseApprovalElicitation(requestParams, params.computerUseMcpServerName) ?? readBridgeableApprovalElicitation(requestParams);
1851
2476
  if (!approvalPrompt) return;
1852
- const outcome = await requestPluginApprovalOutcome({
2477
+ return buildElicitationResponse(approvalPrompt, await requestPluginApprovalOutcome({
1853
2478
  paramsForRun: params.paramsForRun,
1854
2479
  title: approvalPrompt.title,
1855
2480
  description: approvalPrompt.description,
2481
+ allowedDecisions: approvalPrompt.allowedDecisions,
1856
2482
  signal: params.signal
1857
- });
1858
- return buildElicitationResponse(approvalPrompt.requestedSchema, approvalPrompt.meta, outcome);
2483
+ }));
1859
2484
  }
1860
2485
  function matchesCurrentThread(requestParams, threadId) {
1861
2486
  if (!requestParams) return false;
@@ -1953,21 +2578,77 @@ function hasDisplayNameOnlyPluginMatch(meta, entries) {
1953
2578
  function normalizePluginIdentityText(value) {
1954
2579
  return value.toLowerCase().replace(/[^a-z0-9]+/g, "");
1955
2580
  }
1956
- function buildPluginPolicyElicitationResponse(entry, requestParams) {
1957
- if (!entry.allowDestructiveActions) {
1958
- logPluginElicitationDecline("destructive_actions_disabled", requestParams);
2581
+ async function buildPluginPolicyElicitationResponse(params) {
2582
+ const mode = resolvePluginDestructiveApprovalMode(params.entry);
2583
+ if (mode === "deny") {
2584
+ logPluginElicitationDecline("destructive_actions_disabled", params.requestParams);
1959
2585
  return declineElicitationResponse();
1960
2586
  }
1961
- if (readString(requestParams, "mode") !== "form" || !isJsonObject(requestParams.requestedSchema)) {
1962
- logPluginElicitationDecline("unsupported_schema", requestParams);
2587
+ const approvalPrompt = readPluginApprovalElicitation(params.entry, params.requestParams);
2588
+ if (!approvalPrompt) {
2589
+ logPluginElicitationDecline("unsupported_schema", params.requestParams);
1963
2590
  return declineElicitationResponse();
1964
2591
  }
1965
- const meta = isJsonObject(requestParams["_meta"]) ? requestParams["_meta"] : {};
1966
- const response = buildElicitationResponse(requestParams.requestedSchema, meta, "approved-once");
1967
- if (isJsonObject(response) && response.action === "accept") return response;
1968
- logPluginElicitationDecline("unmappable_schema", requestParams);
2592
+ const response = buildElicitationResponse(approvalPrompt, "approved-once");
2593
+ if (isJsonObject(response) && response.action === "accept") {
2594
+ if (mode === "allow") return response;
2595
+ return buildElicitationResponse(approvalPrompt, await requestPluginApprovalOutcome({
2596
+ paramsForRun: params.paramsForRun,
2597
+ title: approvalPrompt.title,
2598
+ description: approvalPrompt.description,
2599
+ allowedDecisions: approvalPrompt.allowedDecisions,
2600
+ signal: params.signal
2601
+ }));
2602
+ }
2603
+ logPluginElicitationDecline("unmappable_schema", params.requestParams);
1969
2604
  return declineElicitationResponse();
1970
2605
  }
2606
+ function resolvePluginDestructiveApprovalMode(entry) {
2607
+ return entry.destructiveApprovalMode ?? (entry.allowDestructiveActions ? "allow" : "deny");
2608
+ }
2609
+ function readPluginApprovalElicitation(entry, requestParams) {
2610
+ if (readString(requestParams, "mode") !== "form" || !isJsonObject(requestParams.requestedSchema)) return;
2611
+ const requestedSchema = requestParams.requestedSchema;
2612
+ if (readString(requestedSchema, "type") !== "object" || !isJsonObject(requestedSchema.properties)) return;
2613
+ const meta = isJsonObject(requestParams["_meta"]) ? requestParams["_meta"] : {};
2614
+ const title = sanitizeDisplayText(readString(requestParams, "message") ?? "") || "Codex plugin approval";
2615
+ const descriptionMeta = { ...meta };
2616
+ if (!readString(descriptionMeta, MCP_TOOL_APPROVAL_CONNECTOR_NAME_KEY)) descriptionMeta[MCP_TOOL_APPROVAL_CONNECTOR_NAME_KEY] = entry.pluginName;
2617
+ return {
2618
+ title,
2619
+ description: buildApprovalDescription({
2620
+ title,
2621
+ meta: descriptionMeta,
2622
+ requestedSchema,
2623
+ serverName: sanitizeOptionalDisplayText(readString(requestParams, "serverName"))
2624
+ }),
2625
+ requestedSchema,
2626
+ meta,
2627
+ persistHintsMode: "explicit",
2628
+ allowedDecisions: buildApprovalAllowedDecisions(requestedSchema, meta)
2629
+ };
2630
+ }
2631
+ function buildApprovalAllowedDecisions(requestedSchema, meta) {
2632
+ return canMapPersistentApproval(requestedSchema, meta) ? [
2633
+ "allow-once",
2634
+ "allow-always",
2635
+ "deny"
2636
+ ] : ["allow-once", "deny"];
2637
+ }
2638
+ function canMapPersistentApproval(requestedSchema, meta) {
2639
+ const persistHints = readPersistHints(meta, "explicit");
2640
+ if (persistHints.length > 0) return persistHints.includes("always");
2641
+ const properties = isJsonObject(requestedSchema.properties) ? requestedSchema.properties : {};
2642
+ return Object.entries(properties).some(([name, value]) => {
2643
+ const schema = isJsonObject(value) ? value : void 0;
2644
+ if (!schema) return false;
2645
+ return isPersistField({
2646
+ name,
2647
+ schema,
2648
+ required: false
2649
+ }) && chooseAlwaysPersistOptionValue(readEnumOptions(schema)) !== void 0;
2650
+ });
2651
+ }
1971
2652
  function declineElicitationResponse() {
1972
2653
  return {
1973
2654
  action: "decline",
@@ -2115,7 +2796,8 @@ async function requestPluginApprovalOutcome(params) {
2115
2796
  title: params.title,
2116
2797
  description: params.description,
2117
2798
  severity: "warning",
2118
- toolName: "codex_mcp_tool_approval"
2799
+ toolName: "codex_mcp_tool_approval",
2800
+ allowedDecisions: params.allowedDecisions
2119
2801
  });
2120
2802
  const approvalId = requestResult?.id;
2121
2803
  if (!approvalId) return "unavailable";
@@ -2127,7 +2809,8 @@ async function requestPluginApprovalOutcome(params) {
2127
2809
  return params.signal?.aborted ? "cancelled" : "denied";
2128
2810
  }
2129
2811
  }
2130
- function buildElicitationResponse(requestedSchema, meta, outcome) {
2812
+ function buildElicitationResponse(approvalPrompt, outcome) {
2813
+ const { requestedSchema, meta } = approvalPrompt;
2131
2814
  if (outcome === "cancelled") return {
2132
2815
  action: "cancel",
2133
2816
  content: null,
@@ -2138,12 +2821,12 @@ function buildElicitationResponse(requestedSchema, meta, outcome) {
2138
2821
  content: null,
2139
2822
  _meta: null
2140
2823
  };
2141
- const content = buildAcceptedContent(requestedSchema, meta, outcome);
2824
+ const content = buildAcceptedContent(approvalPrompt, outcome);
2142
2825
  if (!content) {
2143
2826
  if (hasNoSchemaProperties(requestedSchema)) return {
2144
2827
  action: "accept",
2145
2828
  content: null,
2146
- _meta: buildAcceptedMeta(meta, outcome)
2829
+ _meta: buildAcceptedMeta(meta, outcome, approvalPrompt.persistHintsMode ?? "legacy")
2147
2830
  };
2148
2831
  embeddedAgentLog.warn("codex MCP approval elicitation approved without a mappable response", {
2149
2832
  approvalKind: meta[MCP_TOOL_APPROVAL_KIND_KEY],
@@ -2159,10 +2842,11 @@ function buildElicitationResponse(requestedSchema, meta, outcome) {
2159
2842
  return {
2160
2843
  action: "accept",
2161
2844
  content,
2162
- _meta: buildAcceptedMeta(meta, outcome)
2845
+ _meta: buildAcceptedMeta(meta, outcome, approvalPrompt.persistHintsMode ?? "legacy")
2163
2846
  };
2164
2847
  }
2165
- function buildAcceptedContent(requestedSchema, meta, outcome) {
2848
+ function buildAcceptedContent(approvalPrompt, outcome) {
2849
+ const { requestedSchema, meta } = approvalPrompt;
2166
2850
  const properties = isJsonObject(requestedSchema.properties) ? requestedSchema.properties : void 0;
2167
2851
  if (!properties) return;
2168
2852
  const required = Array.isArray(requestedSchema.required) ? new Set(requestedSchema.required.filter((entry) => typeof entry === "string")) : /* @__PURE__ */ new Set();
@@ -2176,7 +2860,7 @@ function buildAcceptedContent(requestedSchema, meta, outcome) {
2176
2860
  schema,
2177
2861
  required: required.has(name)
2178
2862
  };
2179
- const next = readApprovalFieldValue(property, outcome) ?? readPersistFieldValue(property, meta, outcome) ?? readFallbackFieldValue(property, outcome);
2863
+ const next = readApprovalFieldValue(property, outcome) ?? readPersistFieldValue(property, meta, outcome, approvalPrompt.persistHintsMode ?? "legacy") ?? readFallbackFieldValue(property, outcome);
2180
2864
  if (next === void 0) {
2181
2865
  if (isApprovalField(property)) sawApprovalField = true;
2182
2866
  if (property.required) return;
@@ -2197,13 +2881,14 @@ function readApprovalFieldValue(property, outcome) {
2197
2881
  if (outcome === "approved-session") return sessionChoice?.value ?? acceptChoice?.value;
2198
2882
  return acceptChoice?.value ?? sessionChoice?.value;
2199
2883
  }
2200
- function readPersistFieldValue(property, meta, outcome) {
2884
+ function readPersistFieldValue(property, meta, outcome, persistHintsMode) {
2201
2885
  if (!isPersistField(property) || outcome !== "approved-session") return;
2202
- const persistHints = readPersistHints(meta);
2886
+ const persistHints = readPersistHints(meta, persistHintsMode);
2203
2887
  const options = readEnumOptions(property.schema);
2204
2888
  if (options.length === 0) return;
2205
2889
  const preferred = choosePersistHint(persistHints);
2206
2890
  if (preferred) return options.find((option) => option.value === preferred || option.label === preferred)?.value;
2891
+ if (persistHintsMode === "explicit") return chooseAlwaysPersistOptionValue(options);
2207
2892
  }
2208
2893
  function readDefaultValue(schema) {
2209
2894
  return schema.default;
@@ -2227,21 +2912,27 @@ function propertyText(property) {
2227
2912
  readString(property.schema, "description")
2228
2913
  ].filter(Boolean).join(" ");
2229
2914
  }
2230
- function readPersistHints(meta) {
2915
+ function readPersistHints(meta, mode = "legacy") {
2231
2916
  const raw = meta.persist;
2232
2917
  if (typeof raw === "string") return [raw];
2233
2918
  if (Array.isArray(raw)) return raw.filter((entry) => typeof entry === "string");
2234
- return ["session", "always"];
2919
+ return mode === "legacy" ? ["session", "always"] : [];
2235
2920
  }
2236
- function buildAcceptedMeta(meta, outcome) {
2921
+ function buildAcceptedMeta(meta, outcome, persistHintsMode) {
2237
2922
  if (outcome !== "approved-session") return null;
2238
- const persist = choosePersistHint(readPersistHints(meta));
2923
+ const persist = choosePersistHint(readPersistHints(meta, persistHintsMode));
2239
2924
  return persist ? { persist } : null;
2240
2925
  }
2241
2926
  function choosePersistHint(persistHints) {
2242
2927
  if (persistHints.includes("always")) return "always";
2243
2928
  if (persistHints.includes("session")) return "session";
2244
2929
  }
2930
+ function chooseAlwaysPersistOptionValue(options) {
2931
+ return options.find((option) => optionMatchesPersist(option, "always"))?.value;
2932
+ }
2933
+ function optionMatchesPersist(option, persist) {
2934
+ return option.value.toLowerCase() === persist || option.label.toLowerCase() === persist;
2935
+ }
2245
2936
  function hasNoSchemaProperties(requestedSchema) {
2246
2937
  const properties = isJsonObject(requestedSchema.properties) ? requestedSchema.properties : {};
2247
2938
  return Object.keys(properties).length === 0;
@@ -2472,4 +3163,38 @@ function sortJsonValue(value) {
2472
3163
  return sorted;
2473
3164
  }
2474
3165
  //#endregion
2475
- export { withCodexStartupTimeout as S, resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs as _, createCodexNativeHookRelay as a, resolveCodexTurnCompletionIdleTimeoutMs as b, scheduleCodexNativeHookRelayUnregister as c, emitDynamicToolErrorDiagnostic as d, emitDynamicToolStartedDiagnostic as f, CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS as g, handleCodexAppServerApprovalRequest as h, buildCodexNativeHookRelayDisabledConfig as i, handleCodexAppServerElicitationRequest as l, filterToolsForVisionInputs as m, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as n, resolveCodexNativeHookRelayEvents as o, emitDynamicToolTerminalDiagnostic as p, buildCodexNativeHookRelayConfig as r, resolveCodexNativeHookRelayTtlMs as s, CODEX_NATIVE_HOOK_RELAY_EVENTS as t, createCodexDynamicToolBridge as u, resolveCodexStartupTimeoutMs as v, resolveCodexTurnTerminalIdleTimeoutMs as x, resolveCodexTurnAssistantCompletionIdleTimeoutMs as y };
3166
+ //#region extensions/codex/src/app-server/provider-capabilities.ts
3167
+ async function readConfiguredProviderWebSearchSupport(params) {
3168
+ return (await params.client.request("modelProvider/capabilities/read", {}, {
3169
+ timeoutMs: params.timeoutMs,
3170
+ signal: params.signal
3171
+ })).webSearch ? "supported" : "unsupported";
3172
+ }
3173
+ async function resolveCodexProviderWebSearchSupportForClient(params) {
3174
+ const modelProviderOverride = params.modelProviderOverride?.trim().toLowerCase();
3175
+ if (modelProviderOverride === "openai") return "supported";
3176
+ if (modelProviderOverride) return "unsupported";
3177
+ try {
3178
+ return await readConfiguredProviderWebSearchSupport(params);
3179
+ } catch {
3180
+ return "unknown";
3181
+ }
3182
+ }
3183
+ async function resolveCodexProviderWebSearchSupport(params) {
3184
+ let client;
3185
+ try {
3186
+ client = await params.clientFactory(params.appServer.start, params.authProfileId, params.agentDir, params.config, { timeoutMs: params.appServer.requestTimeoutMs });
3187
+ return await resolveCodexProviderWebSearchSupportForClient({
3188
+ client,
3189
+ timeoutMs: params.appServer.requestTimeoutMs,
3190
+ modelProviderOverride: params.modelProviderOverride,
3191
+ signal: params.signal
3192
+ });
3193
+ } catch {
3194
+ return "unknown";
3195
+ } finally {
3196
+ if (client) releaseLeasedSharedCodexAppServerClient(client);
3197
+ }
3198
+ }
3199
+ //#endregion
3200
+ export { CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS as A, resolveCodexMessageToolProvider as C, shouldWarnCodexDynamicToolBuildStageSummary as D, shouldRequireCodexSandboxExecServerEnvironment as E, resolveCodexTurnTerminalIdleTimeoutMs as F, withCodexStartupTimeout as I, resolveCodexStartupTimeoutMs as M, resolveCodexTurnAssistantCompletionIdleTimeoutMs as N, filterToolsForVisionInputs as O, resolveCodexTurnCompletionIdleTimeoutMs as P, resolveCodexExternalSandboxPolicyForOpenClawSandbox as S, shouldEnableCodexAppServerNativeToolSurface as T, createCodexDynamicToolBuildStageTracker as _, buildCodexNativeHookRelayConfig as a, resolveCodexAppServerExecutionCwd as b, resolveCodexNativeHookRelayEvents as c, handleCodexAppServerElicitationRequest as d, createCodexDynamicToolBridge as f, buildDynamicTools as g, emitDynamicToolTerminalDiagnostic as h, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as i, resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs as j, handleCodexAppServerApprovalRequest as k, resolveCodexNativeHookRelayTtlMs as l, emitDynamicToolStartedDiagnostic as m, resolveCodexProviderWebSearchSupportForClient as n, buildCodexNativeHookRelayDisabledConfig as o, emitDynamicToolErrorDiagnostic as p, CODEX_NATIVE_HOOK_RELAY_EVENTS as r, createCodexNativeHookRelay as s, resolveCodexProviderWebSearchSupport as t, scheduleCodexNativeHookRelayUnregister as u, disableCodexPluginThreadConfig as v, resolveCodexSandboxEnvironmentSelection as w, resolveCodexAppServerHookChannelId as x, formatCodexDynamicToolBuildStageSummary as y };