@openclaw/codex 2026.5.27-beta.1 → 2026.5.28-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/dist/{client-BVK_jmHW.js → client-TfDda-h3.js} +1 -1
  2. package/dist/{client-factory-fW4Hh9q_.js → client-factory-BPBvbguy.js} +2 -2
  3. package/dist/{command-handlers-YXjMla3v.js → command-handlers-B8MXR7fh.js} +11 -11
  4. package/dist/{compact-DIXx9K0Q.js → compact-Dyz0rQLl.js} +10 -8
  5. package/dist/{computer-use-CakwWGCR.js → computer-use-BRIifWhE.js} +2 -2
  6. package/dist/{config-0-UN67Qg.js → config-BW7NPdAQ.js} +10 -3
  7. package/dist/{conversation-binding-CWaG0k5A.js → conversation-binding-D8OO0S9R.js} +7 -7
  8. package/dist/harness.js +5 -5
  9. package/dist/index.js +13 -12
  10. package/dist/media-understanding-provider.js +6 -6
  11. package/dist/{models-_XwpqjR8.js → models-Dnasi6LR.js} +1 -1
  12. package/dist/{vision-tools-DqpLmF5H.js → native-hook-relay-DYOYE3qb.js} +691 -14
  13. package/dist/{notification-correlation-YINts3PA.js → notification-correlation-BVB6XFQM.js} +44 -3
  14. package/dist/provider.js +2 -2
  15. package/dist/{request-Dtg0vQrE.js → request-Cj95iOk6.js} +3 -3
  16. package/dist/{run-attempt-BIbGYJog.js → run-attempt-D9i99EqV.js} +8098 -7879
  17. package/dist/{session-binding-4fRldGaa.js → session-binding-DuJisBZB.js} +1 -1
  18. package/dist/{shared-client-8kIrP817.js → shared-client-DICbgRn5.js} +21 -3
  19. package/dist/{side-question-v4nixmAs.js → side-question-280VWjeH.js} +7 -8
  20. package/dist/{thread-lifecycle-DZAfY4d6.js → thread-lifecycle-1u5ogKG_.js} +4 -4
  21. package/npm-shrinkwrap.json +96 -1771
  22. package/package.json +4 -5
  23. package/dist/dynamic-tools-BSZIYzfP.js +0 -560
  24. package/dist/test-api.js +0 -51
@@ -1,9 +1,11 @@
1
- import { l as isJsonObject } from "./client-BVK_jmHW.js";
2
- import { s as formatCodexDisplayText } from "./notification-correlation-YINts3PA.js";
1
+ import { l as isJsonObject } from "./client-TfDda-h3.js";
2
+ import { S as invalidInlineImageText, w as sanitizeInlineImageDataUrl } from "./thread-lifecycle-1u5ogKG_.js";
3
+ import { s as formatCodexDisplayText } from "./notification-correlation-BVB6XFQM.js";
3
4
  import { createHash } from "node:crypto";
4
- import { normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
5
- import { buildAgentHookContextChannelFields, callGatewayTool, embeddedAgentLog, formatApprovalDisplayPath, hasNativeHookRelayInvocation, invokeNativeHookRelay, runBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
5
+ import { asOptionalRecord, isRecord, normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
6
+ import { HEARTBEAT_RESPONSE_TOOL_NAME, buildAgentHookContextChannelFields, callGatewayTool, createAgentToolResultMiddlewareRunner, createCodexAppServerToolResultExtensionRunner, embeddedAgentLog, extractToolResultMediaArtifact, filterToolResultMediaUrls, formatApprovalDisplayPath, hasNativeHookRelayInvocation, invokeNativeHookRelay, isMessagingTool, isMessagingToolSendAction, isToolWrappedWithBeforeToolCallHook, normalizeHeartbeatToolResponse, projectRuntimeToolInputSchema, registerNativeHookRelay, resolveNativeHookRelayDeferredToolApproval, runAgentHarnessAfterToolCallHook, runBeforeToolCallHook, setBeforeToolCallDiagnosticsEnabled, wrapToolWithBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
6
7
  import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
8
+ import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
7
9
  //#region extensions/codex/src/app-server/plugin-approval-roundtrip.ts
8
10
  const DEFAULT_CODEX_APPROVAL_TIMEOUT_MS = 12e4;
9
11
  const MAX_PLUGIN_APPROVAL_TITLE_LENGTH = 80;
@@ -107,6 +109,18 @@ async function handleCodexAppServerApprovalRequest(params) {
107
109
  });
108
110
  return buildApprovalResponse(params.method, context.requestParams, "denied");
109
111
  }
112
+ if (policyOutcome?.outcome === "approved-once" || policyOutcome?.outcome === "approved-session") {
113
+ emitApprovalEvent(params.paramsForRun, {
114
+ phase: "resolved",
115
+ kind: context.kind,
116
+ status: "approved",
117
+ title: context.title,
118
+ ...context.eventDetails,
119
+ ...approvalEventScope(params.method, policyOutcome.outcome),
120
+ message: approvalResolutionMessage(policyOutcome.outcome)
121
+ });
122
+ return buildApprovalResponse(params.method, context.requestParams, policyOutcome.outcome);
123
+ }
110
124
  if (params.autoApprove === true) {
111
125
  emitApprovalEvent(params.paramsForRun, {
112
126
  phase: "resolved",
@@ -243,12 +257,14 @@ async function runOpenClawToolPolicyForApprovalRequest(params) {
243
257
  context: params.context,
244
258
  policyRequest,
245
259
  nativeHookRelay: params.nativeHookRelay,
246
- cwd
260
+ cwd,
261
+ signal: params.signal
247
262
  });
248
263
  if (nativeRelayOutcome?.blocked) return {
249
264
  outcome: "denied",
250
265
  reason: nativeRelayOutcome.reason
251
266
  };
267
+ if (nativeRelayOutcome?.outcome === "approved-once" || nativeRelayOutcome?.outcome === "approved-session") return { outcome: nativeRelayOutcome.outcome };
252
268
  if (nativeRelayOutcome?.handled) return { outcome: "no-decision" };
253
269
  const hookChannelId = buildAgentHookContextChannelFields({
254
270
  sessionKey: params.paramsForRun.sessionKey,
@@ -261,7 +277,7 @@ async function runOpenClawToolPolicyForApprovalRequest(params) {
261
277
  toolName: policyRequest.toolName,
262
278
  params: policyRequest.params,
263
279
  ...params.context.itemId ? { toolCallId: params.context.itemId } : {},
264
- approvalMode: "report",
280
+ approvalMode: "request",
265
281
  signal: params.signal,
266
282
  ctx: {
267
283
  ...params.paramsForRun.agentId ? { agentId: params.paramsForRun.agentId } : {},
@@ -281,6 +297,7 @@ async function runOpenClawToolPolicyForApprovalRequest(params) {
281
297
  outcome: "denied",
282
298
  reason: "OpenClaw tool policy rewrote Codex app-server approval params; refusing original request."
283
299
  };
300
+ if (outcome.approvalResolution) return { outcome: "approved-once" };
284
301
  }
285
302
  async function runNativeRelayToolPolicyForApprovalRequest(params) {
286
303
  if (params.method !== "item/commandExecution/requestApproval" || !params.nativeHookRelay?.allowedEvents.includes("pre_tool_use")) return;
@@ -295,7 +312,23 @@ async function runNativeRelayToolPolicyForApprovalRequest(params) {
295
312
  relayId: params.nativeHookRelay.relayId,
296
313
  event: "pre_tool_use",
297
314
  toolUseId: params.context.itemId
298
- })) return { handled: true };
315
+ })) {
316
+ const approvalOutcome = await resolveNativeHookRelayDeferredToolApproval({
317
+ relayId: params.nativeHookRelay.relayId,
318
+ toolUseId: params.context.itemId,
319
+ signal: params.signal
320
+ });
321
+ if (approvalOutcome?.outcome === "denied") return {
322
+ handled: true,
323
+ blocked: true,
324
+ reason: approvalOutcome.reason
325
+ };
326
+ if (approvalOutcome?.outcome === "approved-once") return {
327
+ handled: true,
328
+ outcome: approvalOutcome.outcome
329
+ };
330
+ return { handled: true };
331
+ }
299
332
  try {
300
333
  const decision = readNativeRelayPreToolUseDecision(await invokeNativeHookRelay({
301
334
  provider: "codex",
@@ -310,6 +343,20 @@ async function runNativeRelayToolPolicyForApprovalRequest(params) {
310
343
  blocked: true,
311
344
  reason: decision.reason
312
345
  };
346
+ const approvalOutcome = await resolveNativeHookRelayDeferredToolApproval({
347
+ relayId: params.nativeHookRelay.relayId,
348
+ toolUseId: params.context.itemId,
349
+ signal: params.signal
350
+ });
351
+ if (approvalOutcome?.outcome === "denied") return {
352
+ handled: true,
353
+ blocked: true,
354
+ reason: approvalOutcome.reason
355
+ };
356
+ if (approvalOutcome?.outcome === "approved-once") return {
357
+ handled: true,
358
+ outcome: approvalOutcome.outcome
359
+ };
313
360
  return { handled: true };
314
361
  } catch (error) {
315
362
  return {
@@ -758,6 +805,50 @@ function formatErrorMessage$1(error) {
758
805
  return error instanceof Error ? error.message : String(error);
759
806
  }
760
807
  //#endregion
808
+ //#region extensions/codex/src/app-server/dynamic-tool-profile.ts
809
+ const CODEX_APP_SERVER_OWNED_DYNAMIC_TOOL_EXCLUDES = [
810
+ "read",
811
+ "write",
812
+ "edit",
813
+ "apply_patch",
814
+ "exec",
815
+ "process",
816
+ "update_plan",
817
+ "tool_call",
818
+ "tool_describe",
819
+ "tool_search",
820
+ "tool_search_code"
821
+ ];
822
+ const DYNAMIC_TOOL_NAME_ALIASES = {
823
+ bash: "exec",
824
+ "apply-patch": "apply_patch"
825
+ };
826
+ function normalizeCodexDynamicToolName(name) {
827
+ const normalized = name.trim().toLowerCase();
828
+ return DYNAMIC_TOOL_NAME_ALIASES[normalized] ?? normalized;
829
+ }
830
+ function isForcedPrivateQaCodexRuntime(env = process.env) {
831
+ return env.OPENCLAW_BUILD_PRIVATE_QA === "1" && env.OPENCLAW_QA_FORCE_RUNTIME?.trim().toLowerCase() === "codex";
832
+ }
833
+ function resolveCodexDynamicToolsLoading(config, env = process.env) {
834
+ return isForcedPrivateQaCodexRuntime(env) ? "direct" : config.codexDynamicToolsLoading ?? "searchable";
835
+ }
836
+ function filterCodexDynamicTools(tools, config, env = process.env) {
837
+ const excludes = /* @__PURE__ */ new Set();
838
+ if (!isForcedPrivateQaCodexRuntime(env)) for (const name of CODEX_APP_SERVER_OWNED_DYNAMIC_TOOL_EXCLUDES) excludes.add(name);
839
+ for (const name of config.codexDynamicToolsExclude ?? []) {
840
+ const trimmed = normalizeCodexDynamicToolName(name);
841
+ if (trimmed) excludes.add(trimmed);
842
+ }
843
+ return excludes.size === 0 ? tools : tools.filter((tool) => !excludes.has(normalizeCodexDynamicToolName(tool.name)));
844
+ }
845
+ //#endregion
846
+ //#region extensions/codex/src/app-server/vision-tools.ts
847
+ function filterToolsForVisionInputs(tools, params) {
848
+ if (!params.modelHasVision || !params.hasInboundImages) return tools;
849
+ return tools.filter((tool) => tool.name !== "image");
850
+ }
851
+ //#endregion
761
852
  //#region extensions/codex/src/app-server/dynamic-tool-diagnostics.ts
762
853
  function emitDynamicToolStartedDiagnostic(params) {
763
854
  emitTrustedDiagnosticEvent({
@@ -811,6 +902,522 @@ function emitDynamicToolTerminalDiagnostic(params) {
811
902
  emitDynamicToolErrorDiagnostic(params);
812
903
  }
813
904
  //#endregion
905
+ //#region extensions/codex/src/app-server/dynamic-tools.ts
906
+ const CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE = "openclaw";
907
+ const ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES = new Set(["sessions_yield"]);
908
+ const DEFAULT_CODEX_DYNAMIC_TOOL_RESULT_MAX_CHARS = 16e3;
909
+ function createCodexDynamicToolBridge(params) {
910
+ const toolResultHookContext = toToolResultHookContext(params.hookContext);
911
+ const toolResultMaxChars = resolveCodexDynamicToolResultMaxChars(params.hookContext);
912
+ const availableProjection = projectCodexDynamicTools(params.tools);
913
+ const registeredProjection = params.registeredTools ? projectCodexDynamicTools(params.registeredTools) : availableProjection;
914
+ const availableTools = availableProjection.tools.map(({ tool, inputSchema }) => {
915
+ if (isToolWrappedWithBeforeToolCallHook(tool)) {
916
+ setBeforeToolCallDiagnosticsEnabled(tool, false);
917
+ return {
918
+ tool,
919
+ inputSchema
920
+ };
921
+ }
922
+ return {
923
+ tool: wrapToolWithBeforeToolCallHook(tool, params.hookContext, { emitDiagnostics: false }),
924
+ inputSchema
925
+ };
926
+ });
927
+ const toolMap = new Map(availableTools.map(({ tool }) => [tool.name, tool]));
928
+ const registeredTools = registeredProjection.tools.map(({ tool }) => tool);
929
+ const registeredToolNames = new Set(registeredTools.map((tool) => tool.name));
930
+ const quarantinedTools = dedupeQuarantinedDynamicTools([...availableProjection.quarantinedTools, ...registeredProjection.quarantinedTools]);
931
+ warnQuarantinedDynamicTools(quarantinedTools);
932
+ emitQuarantinedDynamicToolDiagnostics(quarantinedTools, params.hookContext);
933
+ const telemetry = {
934
+ didSendViaMessagingTool: false,
935
+ messagingToolSentTexts: [],
936
+ messagingToolSentMediaUrls: [],
937
+ messagingToolSentTargets: [],
938
+ messagingToolSourceReplyPayloads: [],
939
+ toolMediaUrls: [],
940
+ toolAudioAsVoice: false,
941
+ quarantinedTools
942
+ };
943
+ const middlewareRunner = createAgentToolResultMiddlewareRunner({
944
+ runtime: "codex",
945
+ ...toolResultHookContext
946
+ });
947
+ const legacyExtensionRunner = createCodexAppServerToolResultExtensionRunner(toolResultHookContext);
948
+ const directToolNames = new Set([...ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES, ...params.directToolNames ?? []]);
949
+ return {
950
+ availableSpecs: availableTools.map(({ tool, inputSchema }) => createCodexDynamicToolSpec({
951
+ tool,
952
+ inputSchema,
953
+ loading: params.loading ?? "searchable",
954
+ directToolNames
955
+ })),
956
+ specs: registeredProjection.tools.map(({ tool, inputSchema }) => createCodexDynamicToolSpec({
957
+ tool,
958
+ inputSchema,
959
+ loading: params.loading ?? "searchable",
960
+ directToolNames
961
+ })),
962
+ telemetry,
963
+ handleToolCall: async (call, options) => {
964
+ const tool = toolMap.get(call.tool);
965
+ if (!tool) {
966
+ if (registeredToolNames.has(call.tool)) return {
967
+ contentItems: [{
968
+ type: "inputText",
969
+ text: `OpenClaw tool is not available for this turn: ${call.tool}`
970
+ }],
971
+ success: false
972
+ };
973
+ return {
974
+ contentItems: [{
975
+ type: "inputText",
976
+ text: `Unknown OpenClaw tool: ${call.tool}`
977
+ }],
978
+ success: false
979
+ };
980
+ }
981
+ const args = jsonObjectToRecord(call.arguments);
982
+ const startedAt = Date.now();
983
+ const signal = composeAbortSignals(params.signal, options?.signal);
984
+ let didStartExecution = false;
985
+ try {
986
+ const preparedArgs = tool.prepareArguments ? tool.prepareArguments(args) : args;
987
+ didStartExecution = true;
988
+ const rawResult = await tool.execute(call.callId, preparedArgs, signal);
989
+ const rawIsError = isToolResultError(rawResult);
990
+ const middlewareResult = await middlewareRunner.applyToolResultMiddleware({
991
+ threadId: call.threadId,
992
+ turnId: call.turnId,
993
+ toolCallId: call.callId,
994
+ toolName: tool.name,
995
+ args,
996
+ isError: rawIsError,
997
+ result: rawResult
998
+ });
999
+ const result = await legacyExtensionRunner.applyToolResultExtensions({
1000
+ threadId: call.threadId,
1001
+ turnId: call.turnId,
1002
+ toolCallId: call.callId,
1003
+ toolName: tool.name,
1004
+ args,
1005
+ result: middlewareResult
1006
+ });
1007
+ const resultIsError = rawIsError || isToolResultError(result);
1008
+ collectToolTelemetry({
1009
+ toolName: tool.name,
1010
+ args,
1011
+ result,
1012
+ mediaTrustResult: rawResult,
1013
+ telemetry,
1014
+ isError: resultIsError
1015
+ });
1016
+ runAgentHarnessAfterToolCallHook({
1017
+ toolName: tool.name,
1018
+ toolCallId: call.callId,
1019
+ runId: toolResultHookContext.runId,
1020
+ agentId: toolResultHookContext.agentId,
1021
+ sessionId: toolResultHookContext.sessionId,
1022
+ sessionKey: toolResultHookContext.sessionKey,
1023
+ channelId: toolResultHookContext.channelId,
1024
+ startArgs: args,
1025
+ result,
1026
+ startedAt
1027
+ });
1028
+ const terminalType = inferToolResultDiagnosticTerminalType(result, resultIsError);
1029
+ const response = withDiagnosticTerminalType({
1030
+ contentItems: convertToolContents(result.content, toolResultMaxChars),
1031
+ success: !resultIsError
1032
+ }, terminalType);
1033
+ withDynamicToolTermination(response, rawResult.terminate === true || result.terminate === true || isToolResultYield(rawResult) || isToolResultYield(result));
1034
+ withDynamicToolAsyncStarted(response, isAsyncStartedToolResult(rawResult) || isAsyncStartedToolResult(result));
1035
+ return withSideEffectEvidence(response, terminalType !== "blocked");
1036
+ } catch (error) {
1037
+ collectToolTelemetry({
1038
+ toolName: tool.name,
1039
+ args,
1040
+ result: void 0,
1041
+ telemetry,
1042
+ isError: true
1043
+ });
1044
+ runAgentHarnessAfterToolCallHook({
1045
+ toolName: tool.name,
1046
+ toolCallId: call.callId,
1047
+ runId: toolResultHookContext.runId,
1048
+ agentId: toolResultHookContext.agentId,
1049
+ sessionId: toolResultHookContext.sessionId,
1050
+ sessionKey: toolResultHookContext.sessionKey,
1051
+ channelId: toolResultHookContext.channelId,
1052
+ startArgs: args,
1053
+ error: error instanceof Error ? error.message : String(error),
1054
+ startedAt
1055
+ });
1056
+ return withSideEffectEvidence(withDiagnosticTerminalType({
1057
+ contentItems: [{
1058
+ type: "inputText",
1059
+ text: error instanceof Error ? error.message : String(error)
1060
+ }],
1061
+ success: false
1062
+ }, "error"), didStartExecution);
1063
+ }
1064
+ }
1065
+ };
1066
+ }
1067
+ function createCodexDynamicToolSpec(params) {
1068
+ const base = {
1069
+ name: params.tool.name,
1070
+ description: params.tool.description,
1071
+ inputSchema: params.inputSchema
1072
+ };
1073
+ if (params.loading === "direct" || params.directToolNames.has(params.tool.name)) return base;
1074
+ return {
1075
+ ...base,
1076
+ namespace: CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE,
1077
+ deferLoading: true
1078
+ };
1079
+ }
1080
+ function projectCodexDynamicTools(tools) {
1081
+ const projectedTools = [];
1082
+ const quarantinedTools = [];
1083
+ for (const tool of tools) {
1084
+ const projection = projectRuntimeToolInputSchema(tool.parameters, `${tool.name}.inputSchema`);
1085
+ if (projection.violations.length > 0) {
1086
+ quarantinedTools.push({
1087
+ tool: tool.name,
1088
+ violations: projection.violations
1089
+ });
1090
+ continue;
1091
+ }
1092
+ projectedTools.push({
1093
+ tool,
1094
+ inputSchema: projection.schema
1095
+ });
1096
+ }
1097
+ return {
1098
+ tools: projectedTools,
1099
+ quarantinedTools
1100
+ };
1101
+ }
1102
+ function warnQuarantinedDynamicTools(tools) {
1103
+ if (tools.length === 0) return;
1104
+ const unique = /* @__PURE__ */ new Map();
1105
+ for (const tool of tools) unique.set(tool.tool, tool.violations);
1106
+ embeddedAgentLog.warn(`codex app-server quarantined ${unique.size} dynamic ${unique.size === 1 ? "tool" : "tools"} with unsupported input schemas: ${[...unique.keys()].join(", ")}`, { tools: [...unique.entries()].map(([tool, violations]) => ({
1107
+ tool,
1108
+ violations
1109
+ })) });
1110
+ }
1111
+ function emitQuarantinedDynamicToolDiagnostics(tools, ctx) {
1112
+ for (const tool of tools) emitTrustedDiagnosticEvent({
1113
+ type: "tool.execution.blocked",
1114
+ runId: ctx?.runId,
1115
+ sessionId: ctx?.sessionId,
1116
+ sessionKey: ctx?.sessionKey,
1117
+ toolName: tool.tool,
1118
+ deniedReason: "unsupported_tool_schema",
1119
+ reason: tool.violations.join(", ")
1120
+ });
1121
+ }
1122
+ function dedupeQuarantinedDynamicTools(tools) {
1123
+ return [...new Map(tools.map((tool) => [tool.tool, {
1124
+ tool: tool.tool,
1125
+ violations: tool.violations
1126
+ }])).values()];
1127
+ }
1128
+ function toToolResultHookContext(ctx) {
1129
+ const { agentId, sessionId, sessionKey, runId, channelId } = ctx ?? {};
1130
+ return {
1131
+ ...agentId && { agentId },
1132
+ ...sessionId && { sessionId },
1133
+ ...sessionKey && { sessionKey },
1134
+ ...runId && { runId },
1135
+ ...channelId && { channelId }
1136
+ };
1137
+ }
1138
+ function resolveCodexDynamicToolResultMaxChars(ctx) {
1139
+ return resolveAgentContextLimitValue({
1140
+ config: ctx?.config,
1141
+ agentId: ctx?.agentId,
1142
+ key: "toolResultMaxChars"
1143
+ }) ?? DEFAULT_CODEX_DYNAMIC_TOOL_RESULT_MAX_CHARS;
1144
+ }
1145
+ function resolveAgentContextLimitValue(params) {
1146
+ const agents = asOptionalRecord(params.config?.agents);
1147
+ const defaultValue = readPositiveInteger(asOptionalRecord(asOptionalRecord(agents?.defaults)?.contextLimits)?.[params.key]);
1148
+ if (!params.agentId) return defaultValue;
1149
+ const list = agents?.list;
1150
+ if (!Array.isArray(list)) return defaultValue;
1151
+ const normalizedAgentId = normalizeAgentId(params.agentId);
1152
+ return readPositiveInteger(asOptionalRecord(asOptionalRecord(list.find((entry) => {
1153
+ const entryId = asOptionalRecord(entry)?.id;
1154
+ return typeof entryId === "string" && normalizeAgentId(entryId) === normalizedAgentId;
1155
+ }))?.contextLimits)?.[params.key]) ?? defaultValue;
1156
+ }
1157
+ function composeAbortSignals(...signals) {
1158
+ const activeSignals = signals.filter((signal) => Boolean(signal));
1159
+ if (activeSignals.length === 0) return new AbortController().signal;
1160
+ if (activeSignals.length === 1) return activeSignals[0];
1161
+ return AbortSignal.any(activeSignals);
1162
+ }
1163
+ function collectToolTelemetry(params) {
1164
+ if (params.isError) return;
1165
+ if (!params.isError && params.toolName === "cron" && isCronAddAction(params.args)) params.telemetry.successfulCronAdds = (params.telemetry.successfulCronAdds ?? 0) + 1;
1166
+ if (!params.isError && params.toolName === HEARTBEAT_RESPONSE_TOOL_NAME) {
1167
+ const response = normalizeHeartbeatToolResponse(params.result?.details);
1168
+ if (response) params.telemetry.heartbeatToolResponse = response;
1169
+ }
1170
+ if (!params.isError && params.result) {
1171
+ const media = extractToolResultMediaArtifact(params.result);
1172
+ if (media) {
1173
+ const mediaUrls = filterToolResultMediaUrls(params.toolName, media.mediaUrls, params.mediaTrustResult ?? params.result);
1174
+ const seen = new Set(params.telemetry.toolMediaUrls);
1175
+ for (const mediaUrl of mediaUrls) if (!seen.has(mediaUrl)) {
1176
+ seen.add(mediaUrl);
1177
+ params.telemetry.toolMediaUrls.push(mediaUrl);
1178
+ }
1179
+ if (media.audioAsVoice) params.telemetry.toolAudioAsVoice = true;
1180
+ }
1181
+ }
1182
+ if (!isMessagingTool(params.toolName) || !isMessagingToolSendAction(params.toolName, params.args)) return;
1183
+ params.telemetry.didSendViaMessagingTool = true;
1184
+ const sourceReplyPayload = extractInternalSourceReplyPayload(params.result?.details);
1185
+ if (sourceReplyPayload) {
1186
+ params.telemetry.messagingToolSourceReplyPayloads.push(sourceReplyPayload);
1187
+ return;
1188
+ }
1189
+ const text = readFirstString$1(params.args, [
1190
+ "text",
1191
+ "message",
1192
+ "body",
1193
+ "content"
1194
+ ]);
1195
+ if (text) params.telemetry.messagingToolSentTexts.push(text);
1196
+ const mediaUrls = collectMediaUrls(params.args);
1197
+ params.telemetry.messagingToolSentMediaUrls.push(...mediaUrls);
1198
+ params.telemetry.messagingToolSentTargets.push({
1199
+ tool: params.toolName,
1200
+ provider: readFirstString$1(params.args, ["provider", "channel"]) ?? params.toolName,
1201
+ accountId: readFirstString$1(params.args, ["accountId", "account_id"]),
1202
+ to: readFirstString$1(params.args, [
1203
+ "to",
1204
+ "target",
1205
+ "recipient"
1206
+ ]),
1207
+ threadId: readFirstString$1(params.args, [
1208
+ "threadId",
1209
+ "thread_id",
1210
+ "messageThreadId"
1211
+ ]),
1212
+ ...text ? { text } : {},
1213
+ ...mediaUrls.length > 0 ? { mediaUrls } : {}
1214
+ });
1215
+ }
1216
+ function extractInternalSourceReplyPayload(details) {
1217
+ if (!isRecord(details) || details.sourceReplySink !== "internal-ui") return;
1218
+ const rawPayload = details.sourceReply;
1219
+ if (!isRecord(rawPayload)) return;
1220
+ const text = readFirstString$1(rawPayload, ["text", "message"]);
1221
+ const mediaUrls = collectMediaUrls(rawPayload);
1222
+ const mediaUrl = typeof rawPayload.mediaUrl === "string" && rawPayload.mediaUrl.trim() ? rawPayload.mediaUrl.trim() : mediaUrls[0];
1223
+ const payload = {
1224
+ ...text ? { text } : {},
1225
+ ...mediaUrl ? { mediaUrl } : {},
1226
+ ...mediaUrls.length > 0 ? { mediaUrls } : {},
1227
+ ...rawPayload.audioAsVoice === true ? { audioAsVoice: true } : {},
1228
+ ...isRecord(rawPayload.presentation) ? { presentation: rawPayload.presentation } : {},
1229
+ ...isRecord(rawPayload.interactive) ? { interactive: rawPayload.interactive } : {},
1230
+ ...isRecord(rawPayload.channelData) ? { channelData: rawPayload.channelData } : {},
1231
+ ...typeof details.idempotencyKey === "string" && details.idempotencyKey.trim() ? { idempotencyKey: details.idempotencyKey.trim() } : {}
1232
+ };
1233
+ return text || mediaUrls.length > 0 || payload.presentation || payload.interactive ? payload : void 0;
1234
+ }
1235
+ function readPositiveInteger(value) {
1236
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return;
1237
+ return Math.floor(value);
1238
+ }
1239
+ function isToolResultError(result) {
1240
+ const details = result.details;
1241
+ if (!isRecord(details)) return false;
1242
+ if (details.timedOut === true) return true;
1243
+ if (typeof details.exitCode === "number" && details.exitCode !== 0) return true;
1244
+ if (typeof details.status !== "string") return false;
1245
+ const status = details.status.trim().toLowerCase();
1246
+ return status !== "" && status !== "0" && status !== "ok" && status !== "success" && status !== "completed" && status !== "recorded" && status !== "pending" && status !== "started" && status !== "running" && status !== "yielded";
1247
+ }
1248
+ function isToolResultYield(result) {
1249
+ const details = result.details;
1250
+ if (!isRecord(details) || typeof details.status !== "string") return false;
1251
+ return details.status.trim().toLowerCase() === "yielded";
1252
+ }
1253
+ function isAsyncStartedToolResult(result) {
1254
+ const details = result.details;
1255
+ return isRecord(details) && details.async === true && details.status === "started";
1256
+ }
1257
+ function inferToolResultDiagnosticTerminalType(result, isError) {
1258
+ const details = result.details;
1259
+ if (isRecord(details) && typeof details.status === "string") {
1260
+ if (details.status.trim().toLowerCase() === "blocked") return "blocked";
1261
+ }
1262
+ return isError ? "error" : "completed";
1263
+ }
1264
+ function withDiagnosticTerminalType(response, terminalType) {
1265
+ Object.defineProperty(response, "diagnosticTerminalType", {
1266
+ configurable: true,
1267
+ enumerable: false,
1268
+ value: terminalType
1269
+ });
1270
+ return response;
1271
+ }
1272
+ function withSideEffectEvidence(response, sideEffectEvidence) {
1273
+ if (!sideEffectEvidence) return response;
1274
+ Object.defineProperty(response, "sideEffectEvidence", {
1275
+ configurable: true,
1276
+ enumerable: false,
1277
+ value: true
1278
+ });
1279
+ return response;
1280
+ }
1281
+ function withDynamicToolTermination(response, terminate) {
1282
+ if (!terminate) return response;
1283
+ Object.defineProperty(response, "terminate", {
1284
+ configurable: true,
1285
+ enumerable: false,
1286
+ value: true
1287
+ });
1288
+ return response;
1289
+ }
1290
+ function withDynamicToolAsyncStarted(response, asyncStarted) {
1291
+ if (!asyncStarted) return response;
1292
+ Object.defineProperty(response, "asyncStarted", {
1293
+ configurable: true,
1294
+ enumerable: false,
1295
+ value: true
1296
+ });
1297
+ return response;
1298
+ }
1299
+ function normalizeToolResultMaxChars(maxChars) {
1300
+ return typeof maxChars === "number" && Number.isFinite(maxChars) && maxChars > 0 ? Math.floor(maxChars) : DEFAULT_CODEX_DYNAMIC_TOOL_RESULT_MAX_CHARS;
1301
+ }
1302
+ function convertToolContents(content, toolResultMaxChars = DEFAULT_CODEX_DYNAMIC_TOOL_RESULT_MAX_CHARS) {
1303
+ const maxChars = normalizeToolResultMaxChars(toolResultMaxChars);
1304
+ const totalTextChars = content.reduce((total, item) => total + (item.type === "text" ? item.text.length : 0), 0);
1305
+ if (totalTextChars <= maxChars) return content.flatMap(convertToolContent);
1306
+ const noticeText = `...(OpenClaw truncated dynamic tool result: original ${totalTextChars} chars, showing ${maxChars}; rerun with narrower args.)`;
1307
+ const notice = `\n${noticeText}`;
1308
+ let remainingTextBudget = Math.max(0, maxChars - notice.length);
1309
+ let appendedNotice = false;
1310
+ const output = [];
1311
+ for (const item of content) {
1312
+ if (item.type !== "text") {
1313
+ output.push(...convertToolContent(item));
1314
+ continue;
1315
+ }
1316
+ if (appendedNotice) continue;
1317
+ if (notice.length >= maxChars) {
1318
+ output.push({
1319
+ type: "inputText",
1320
+ text: noticeText.slice(0, maxChars)
1321
+ });
1322
+ appendedNotice = true;
1323
+ continue;
1324
+ }
1325
+ const sliceLength = Math.min(item.text.length, remainingTextBudget);
1326
+ remainingTextBudget -= sliceLength;
1327
+ const shouldAppendNotice = remainingTextBudget <= 0;
1328
+ const text = item.text.slice(0, sliceLength);
1329
+ if (shouldAppendNotice) {
1330
+ output.push({
1331
+ type: "inputText",
1332
+ text: `${text.trimEnd()}${notice}`.slice(0, maxChars)
1333
+ });
1334
+ appendedNotice = true;
1335
+ } else if (text.length > 0) output.push({
1336
+ type: "inputText",
1337
+ text
1338
+ });
1339
+ }
1340
+ if (!appendedNotice) output.push({
1341
+ type: "inputText",
1342
+ text: noticeText.slice(0, maxChars)
1343
+ });
1344
+ return output;
1345
+ }
1346
+ function convertToolContent(content) {
1347
+ if (content.type === "text") return [{
1348
+ type: "inputText",
1349
+ text: content.text
1350
+ }];
1351
+ const imageUrl = sanitizeInlineImageDataUrl(`data:${content.mimeType};base64,${content.data}`);
1352
+ if (!imageUrl) return [{
1353
+ type: "inputText",
1354
+ text: invalidInlineImageText("codex dynamic tool")
1355
+ }];
1356
+ return [{
1357
+ type: "inputImage",
1358
+ imageUrl
1359
+ }];
1360
+ }
1361
+ function jsonObjectToRecord(value) {
1362
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
1363
+ return value;
1364
+ }
1365
+ function readFirstString$1(record, keys) {
1366
+ for (const key of keys) {
1367
+ const value = record[key];
1368
+ if (typeof value === "string" && value.trim()) return value.trim();
1369
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
1370
+ }
1371
+ }
1372
+ function collectMediaUrls(record) {
1373
+ const urls = [];
1374
+ const pushMediaUrl = (value) => {
1375
+ if (typeof value === "string" && value.trim()) urls.push(value.trim());
1376
+ };
1377
+ const pushAttachment = (value) => {
1378
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
1379
+ const attachment = value;
1380
+ for (const key of [
1381
+ "media",
1382
+ "mediaUrl",
1383
+ "path",
1384
+ "filePath",
1385
+ "fileUrl",
1386
+ "url"
1387
+ ]) pushMediaUrl(attachment[key]);
1388
+ };
1389
+ for (const key of [
1390
+ "media",
1391
+ "mediaUrl",
1392
+ "media_url",
1393
+ "path",
1394
+ "filePath",
1395
+ "fileUrl",
1396
+ "imageUrl",
1397
+ "image_url"
1398
+ ]) {
1399
+ const value = record[key];
1400
+ pushMediaUrl(value);
1401
+ }
1402
+ for (const key of [
1403
+ "mediaUrls",
1404
+ "media_urls",
1405
+ "imageUrls",
1406
+ "image_urls"
1407
+ ]) {
1408
+ const value = record[key];
1409
+ if (!Array.isArray(value)) continue;
1410
+ for (const entry of value) pushMediaUrl(entry);
1411
+ }
1412
+ const attachments = record.attachments;
1413
+ if (Array.isArray(attachments)) for (const attachment of attachments) pushAttachment(attachment);
1414
+ return urls;
1415
+ }
1416
+ function isCronAddAction(args) {
1417
+ const action = args.action;
1418
+ return typeof action === "string" && action.trim().toLowerCase() === "add";
1419
+ }
1420
+ //#endregion
814
1421
  //#region extensions/codex/src/app-server/elicitation-bridge.ts
815
1422
  const MCP_TOOL_APPROVAL_KIND = "mcp_tool_call";
816
1423
  const MCP_TOOL_APPROVAL_KIND_KEY = "codex_approval_kind";
@@ -1326,6 +1933,82 @@ const CODEX_NATIVE_HOOK_RELAY_EVENTS = [
1326
1933
  "permission_request",
1327
1934
  "before_agent_finalize"
1328
1935
  ];
1936
+ const CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS = CODEX_NATIVE_HOOK_RELAY_EVENTS.filter((event) => event !== "permission_request");
1937
+ const CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS = 30 * 6e4;
1938
+ const CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS = 5 * 6e4;
1939
+ const CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS = 1e4;
1940
+ const CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS = 5e3;
1941
+ const pendingCodexNativeHookRelayUnregisters = /* @__PURE__ */ new Set();
1942
+ function scheduleCodexNativeHookRelayUnregister(params) {
1943
+ let pending;
1944
+ const unregister = () => {
1945
+ if (!pending) return;
1946
+ const current = pending;
1947
+ pending = void 0;
1948
+ if (!pendingCodexNativeHookRelayUnregisters.delete(current)) return;
1949
+ params.relay.unregister();
1950
+ };
1951
+ const timeout = setTimeout(unregister, resolveCodexNativeHookRelayUnregisterGraceMs(params.hookTimeoutSec));
1952
+ pending = {
1953
+ timeout,
1954
+ unregister
1955
+ };
1956
+ pendingCodexNativeHookRelayUnregisters.add(pending);
1957
+ timeout.unref();
1958
+ }
1959
+ function resolveCodexNativeHookRelayUnregisterGraceMs(hookTimeoutSec) {
1960
+ const hookTimeoutMs = typeof hookTimeoutSec === "number" && Number.isFinite(hookTimeoutSec) && hookTimeoutSec > 0 ? Math.ceil(hookTimeoutSec) * 1e3 : 0;
1961
+ return Math.max(CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS, hookTimeoutMs + CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS);
1962
+ }
1963
+ function createCodexNativeHookRelay(params) {
1964
+ if (params.options?.enabled === false) return;
1965
+ return registerNativeHookRelay({
1966
+ provider: "codex",
1967
+ relayId: buildCodexNativeHookRelayId({
1968
+ agentId: params.agentId,
1969
+ sessionId: params.sessionId,
1970
+ sessionKey: params.sessionKey
1971
+ }),
1972
+ ...params.generation ? { generation: params.generation } : {},
1973
+ ...params.generationMismatchGraceMs ? { generationMismatchGraceMs: params.generationMismatchGraceMs } : {},
1974
+ ...params.agentId ? { agentId: params.agentId } : {},
1975
+ sessionId: params.sessionId,
1976
+ ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
1977
+ ...params.config ? { config: params.config } : {},
1978
+ runId: params.runId,
1979
+ ...params.channelId ? { channelId: params.channelId } : {},
1980
+ allowedEvents: params.events,
1981
+ ttlMs: resolveCodexNativeHookRelayTtlMs({
1982
+ explicitTtlMs: params.options?.ttlMs,
1983
+ attemptTimeoutMs: params.attemptTimeoutMs,
1984
+ startupTimeoutMs: params.startupTimeoutMs,
1985
+ turnStartTimeoutMs: params.turnStartTimeoutMs
1986
+ }),
1987
+ signal: params.signal,
1988
+ command: {
1989
+ nice: 10,
1990
+ timeoutMs: params.options?.gatewayTimeoutMs
1991
+ }
1992
+ });
1993
+ }
1994
+ function resolveCodexNativeHookRelayEvents(params) {
1995
+ if (params.configuredEvents?.length) return params.configuredEvents;
1996
+ return params.appServer.approvalPolicy === "never" ? CODEX_NATIVE_HOOK_RELAY_EVENTS : CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS;
1997
+ }
1998
+ function resolveCodexNativeHookRelayTtlMs(params) {
1999
+ if (params.explicitTtlMs !== void 0) return params.explicitTtlMs;
2000
+ const relayBudgetMs = params.attemptTimeoutMs + params.startupTimeoutMs + params.turnStartTimeoutMs + CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS;
2001
+ return Math.max(CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS, Math.floor(relayBudgetMs));
2002
+ }
2003
+ function buildCodexNativeHookRelayId(params) {
2004
+ const hash = createHash("sha256");
2005
+ hash.update("openclaw:codex:native-hook-relay:v1");
2006
+ hash.update("\0");
2007
+ hash.update(params.agentId?.trim() || "");
2008
+ hash.update("\0");
2009
+ hash.update(params.sessionKey?.trim() || params.sessionId);
2010
+ return `codex-${hash.digest("hex").slice(0, 40)}`;
2011
+ }
1329
2012
  const CODEX_HOOK_EVENT_BY_NATIVE_EVENT = {
1330
2013
  pre_tool_use: "PreToolUse",
1331
2014
  post_tool_use: "PostToolUse",
@@ -1408,10 +2091,4 @@ function sortJsonValue(value) {
1408
2091
  return sorted;
1409
2092
  }
1410
2093
  //#endregion
1411
- //#region extensions/codex/src/app-server/vision-tools.ts
1412
- function filterToolsForVisionInputs(tools, params) {
1413
- if (!params.modelHasVision || !params.hasInboundImages) return tools;
1414
- return tools.filter((tool) => tool.name !== "image");
1415
- }
1416
- //#endregion
1417
- export { handleCodexAppServerElicitationRequest as a, emitDynamicToolTerminalDiagnostic as c, buildCodexNativeHookRelayDisabledConfig as i, handleCodexAppServerApprovalRequest as l, CODEX_NATIVE_HOOK_RELAY_EVENTS as n, emitDynamicToolErrorDiagnostic as o, buildCodexNativeHookRelayConfig as r, emitDynamicToolStartedDiagnostic as s, filterToolsForVisionInputs as t };
2094
+ export { normalizeCodexDynamicToolName as _, createCodexNativeHookRelay as a, scheduleCodexNativeHookRelayUnregister as c, emitDynamicToolErrorDiagnostic as d, emitDynamicToolStartedDiagnostic as f, isForcedPrivateQaCodexRuntime as g, filterCodexDynamicTools 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, resolveCodexDynamicToolsLoading as v, handleCodexAppServerApprovalRequest as y };