@openclaw/codex 2026.7.2-beta.1 → 2026.7.2-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{app-server-policy-DVcxdse_.js → app-server-policy-Scc-Wevo.js} +1 -1
- package/dist/{attempt-notifications-DEv9h7iC.js → attempt-notifications-BFmNhqFl.js} +3 -6
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-D6ZlGNmb.js → command-formatters-Dq9InZUK.js} +34 -3
- package/dist/{command-handlers-Cpl9fUWv.js → command-handlers-IgqmL_kv.js} +10 -13
- package/dist/{compact-FnJmiPNA.js → compact-DCTmg3id.js} +4 -5
- package/dist/{computer-use-DVzr8OP1.js → computer-use-CPcU8TjG.js} +4 -4
- package/dist/{conversation-control-DtQ-E7mr.js → conversation-control-CGkBlfc5.js} +5 -7
- package/dist/doctor-contract-api.js +1 -1
- package/dist/{dynamic-tools-BMLoaTeG.js → dynamic-tools-C_1tEs34.js} +608 -330
- package/dist/harness.js +9 -5
- package/dist/index.js +52 -31
- package/dist/{media-understanding-provider-D580L0P8.js → media-understanding-provider-D31dOJwb.js} +11 -12
- package/dist/media-understanding-provider.js +1 -1
- package/dist/{models-DuKzZA6G.js → models-uh26C8QU.js} +5 -9
- package/dist/{notification-correlation-DfaCm0mx.js → notification-correlation-KmfV4EkP.js} +3 -3
- package/dist/{plugin-app-cache-key-BKNjHMEs.js → plugin-app-cache-key-Ceb-lm2c.js} +2 -2
- package/dist/{rate-limits-Dhp04Rqo.js → rate-limits-DyXaYAxU.js} +7 -6
- package/dist/{request-DborTWgw.js → request-B_oQsCXy.js} +54 -8
- package/dist/{run-attempt-VPVJoYDP.js → run-attempt-MLzoMe_m.js} +499 -295
- package/dist/{config-c48K5HP9.js → session-binding-h1mmCGnl.js} +786 -3
- package/dist/{session-catalog-7H112Tr_.js → session-catalog-CEvoXWHA.js} +45 -29
- package/dist/{session-cli-B28RhCyp.js → session-cli-XsEuWb_C.js} +1 -1
- package/dist/{shared-client-D4mFI9al.js → shared-client-JiAnW6pc.js} +255 -81
- package/dist/{side-question-CgJBz52s.js → side-question-DqDvIwSU.js} +15 -13
- package/dist/{thread-lifecycle-BgLXzjvV.js → thread-lifecycle-CN_pPtPh.js} +1787 -1579
- package/dist/{protocol-validators-dZQ-UTOa.js → transcript-mirror-D9rTxx2P.js} +485 -2
- package/dist/usage-D5Rohxoc.js +25 -0
- package/dist/{web-search-provider.runtime-Bs-eTn5U.js → web-search-provider.runtime-CKVBn3fP.js} +3 -3
- package/npm-shrinkwrap.json +30 -30
- package/openclaw.plugin.json +10 -5
- package/package.json +6 -6
- package/dist/capabilities-42Dfn2TV.js +0 -33
- package/dist/prompt-overlay.js +0 -15
- package/dist/protocol-BMifTfdW.js +0 -15
- package/dist/provider-catalog.js +0 -118
- package/dist/provider-discovery.js +0 -34
- package/dist/provider.js +0 -307
- package/dist/session-binding-BMfX1OX-.js +0 -786
- package/dist/transcript-mirror-DhLwFIL4.js +0 -485
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { c as readCodexTurn } from "./
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { n as formatCodexUsageLimitErrorMessage } from "./rate-limits-
|
|
7
|
-
import { c as attachCodexMirrorIdentity, s as promptSnapshot } from "./transcript-mirror-DhLwFIL4.js";
|
|
8
|
-
import { r as formatCodexDisplayText } from "./command-formatters-D6ZlGNmb.js";
|
|
1
|
+
import { Y as CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE, Z as isJsonObject, _ as readCodexRateLimitsRevision, c as releaseLeasedSharedCodexAppServerClient, j as resolveCodexGatewayTimeoutWithGraceMs, v as readRecentCodexRateLimits, y as rememberCodexRateLimitsRead } from "./shared-client-JiAnW6pc.js";
|
|
2
|
+
import { y as readCodexPluginConfig } from "./session-binding-h1mmCGnl.js";
|
|
3
|
+
import { c as attachCodexMirrorIdentity, g as readCodexTurn, s as promptSnapshot } from "./transcript-mirror-D9rTxx2P.js";
|
|
4
|
+
import { C as isForcedPrivateQaCodexRuntime, S as filterCodexDynamicToolsWithOpenClawShell, T as normalizeCodexDynamicToolName, a as sanitizeCodexHistoryImagePayloads, d as resolveCodexWebSearchPlan, i as invalidInlineImageText, o as sanitizeInlineImageDataUrl, w as isSystemAgentOnlyCodexDynamicToolAllowlist, x as filterCodexDynamicTools } from "./thread-lifecycle-CN_pPtPh.js";
|
|
5
|
+
import { d as CODEX_CONTROL_METHODS, r as formatCodexDisplayText } from "./command-formatters-Dq9InZUK.js";
|
|
6
|
+
import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-DyXaYAxU.js";
|
|
9
7
|
import { a as resolveCodexNodeExecToolOverrides, i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-D1Wky__S.js";
|
|
10
|
-
import { n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-
|
|
8
|
+
import { n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-KmfV4EkP.js";
|
|
11
9
|
import fs from "node:fs/promises";
|
|
12
|
-
import { addTimerTimeoutGraceMs, asDateTimestampMs, finiteSecondsToTimerSafeMilliseconds, parseStrictNonNegativeInteger
|
|
10
|
+
import { addTimerTimeoutGraceMs, asDateTimestampMs, finiteSecondsToTimerSafeMilliseconds, parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
13
11
|
import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
14
12
|
import { createHash } from "node:crypto";
|
|
15
|
-
import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime";
|
|
13
|
+
import { markAuthProfileBlockedUntil, resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime";
|
|
16
14
|
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
|
|
17
15
|
import { asOptionalRecord, isRecord, normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
18
16
|
import { HEARTBEAT_RESPONSE_TOOL_NAME, TOOL_PROGRESS_OUTPUT_MAX_CHARS, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, callGatewayTool, classifyAgentHarnessTerminalOutcome, consumeAdjustedParamsForToolCall, consumePreExecutionBlockedToolCall, createAgentToolResultMiddlewareRunner, createCodexAppServerToolResultExtensionRunner, embeddedAgentLog, emitAgentEvent, extractMessagingToolSend, extractMessagingToolSendResult, extractToolResultMediaArtifact, filterProviderNormalizableTools, filterToolResultMediaUrls, finalizeToolTerminalPresentation, formatApprovalDisplayPath, formatErrorMessage, formatToolAggregate, formatToolExecutionErrorMessage, formatToolProgressOutput, getBeforeToolCallFailureDisposition, getChannelAgentToolMeta, getPluginToolMeta, hasNativeHookRelayInvocation, inferToolMetaFromArgs, invokeNativeHookRelay, isDeliveredMessageToolOnlySourceReplyResult, isDeliveredMessagingToolResult, isHostScopedAgentToolActive, isMessagingTool, isMessagingToolSendAction, isReplaySafeToolCall, isSubagentSessionKey, isToolResultError, isToolWrappedWithBeforeToolCallHook, normalizeAgentRuntimeTools, normalizeHeartbeatToolResponse, normalizeUsage, projectRuntimeToolInputSchema, registerNativeHookRelay, resolveAttemptSpawnWorkspaceDir, resolveModelAuthMode, resolveNativeHookRelayDeferredToolApproval, resolveToolExecutionErrorKind, resolveToolResultFailureKind, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessBeforeCompactionHook, runBeforeToolCallHook, sanitizeToolResult, setBeforeToolCallDiagnosticsEnabled, supportsModelTools, wrapToolWithBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
@@ -25,6 +23,7 @@ import { isToolAllowed } from "openclaw/plugin-sdk/sandbox";
|
|
|
25
23
|
import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "openclaw/plugin-sdk/agent-sessions";
|
|
26
24
|
import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
|
|
27
25
|
import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
26
|
+
import { normalizeOpenAIToolSchemas } from "openclaw/plugin-sdk/provider-tools";
|
|
28
27
|
//#region extensions/codex/src/app-server/local-runtime-attribution.ts
|
|
29
28
|
const OPENAI_PROVIDER_ID = "openai";
|
|
30
29
|
const OPENAI_RESPONSES_API = "openai-responses";
|
|
@@ -67,6 +66,7 @@ function createAssistantMessage(params, text, options) {
|
|
|
67
66
|
output: options.tokenUsage.output ?? 0,
|
|
68
67
|
cacheRead: options.tokenUsage.cacheRead ?? 0,
|
|
69
68
|
cacheWrite: options.tokenUsage.cacheWrite ?? 0,
|
|
69
|
+
...options.tokenUsage.contextUsage ? { contextUsage: options.tokenUsage.contextUsage } : {},
|
|
70
70
|
totalTokens: options.tokenUsage.total ?? (options.tokenUsage.input ?? 0) + (options.tokenUsage.output ?? 0) + (options.tokenUsage.cacheRead ?? 0) + (options.tokenUsage.cacheWrite ?? 0),
|
|
71
71
|
cost: ZERO_USAGE$1.cost
|
|
72
72
|
} : ZERO_USAGE$1;
|
|
@@ -103,7 +103,7 @@ function createAssistantMirrorMessage(params, title, text) {
|
|
|
103
103
|
}
|
|
104
104
|
//#endregion
|
|
105
105
|
//#region extensions/codex/src/app-server/event-projector-values.ts
|
|
106
|
-
function readString$
|
|
106
|
+
function readString$3(record, key) {
|
|
107
107
|
const value = record[key];
|
|
108
108
|
return typeof value === "string" ? value : void 0;
|
|
109
109
|
}
|
|
@@ -139,15 +139,15 @@ function readNonNegativeInteger(record, key) {
|
|
|
139
139
|
}
|
|
140
140
|
function readCodexErrorNotificationMessage(record) {
|
|
141
141
|
const error = record.error;
|
|
142
|
-
return isJsonObject(error) ? readString$
|
|
142
|
+
return isJsonObject(error) ? readString$3(error, "message") : void 0;
|
|
143
143
|
}
|
|
144
144
|
function readHookOutputEntries(value) {
|
|
145
145
|
if (!Array.isArray(value)) return [];
|
|
146
146
|
return value.flatMap((entry) => {
|
|
147
147
|
if (!isJsonObject(entry)) return [];
|
|
148
|
-
const text = readString$
|
|
148
|
+
const text = readString$3(entry, "text");
|
|
149
149
|
if (!text) return [];
|
|
150
|
-
const kind = readString$
|
|
150
|
+
const kind = readString$3(entry, "kind");
|
|
151
151
|
return [{
|
|
152
152
|
...kind ? { kind } : {},
|
|
153
153
|
text
|
|
@@ -160,9 +160,9 @@ function splitPlanText(text) {
|
|
|
160
160
|
function extractRawAssistantText(item) {
|
|
161
161
|
return (Array.isArray(item.content) ? item.content : []).flatMap((entry) => {
|
|
162
162
|
if (!isJsonObject(entry)) return [];
|
|
163
|
-
const type = readString$
|
|
163
|
+
const type = readString$3(entry, "type");
|
|
164
164
|
if (type !== "output_text" && type !== "text") return [];
|
|
165
|
-
const value = readString$
|
|
165
|
+
const value = readString$3(entry, "text");
|
|
166
166
|
return value ? [value] : [];
|
|
167
167
|
}).join("").trim() || void 0;
|
|
168
168
|
}
|
|
@@ -218,8 +218,8 @@ var CodexAssistantProjection = class {
|
|
|
218
218
|
return this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff && this.hasLatestTerminalAssistantCandidateText();
|
|
219
219
|
}
|
|
220
220
|
async handleAssistantDelta(params) {
|
|
221
|
-
const itemId = readString$
|
|
222
|
-
const delta = readString$
|
|
221
|
+
const itemId = readString$3(params, "itemId") ?? "assistant";
|
|
222
|
+
const delta = readString$3(params, "delta") ?? "";
|
|
223
223
|
if (!delta) return;
|
|
224
224
|
if (itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
225
225
|
const isCommentary = this.isCommentaryAssistantItem(itemId);
|
|
@@ -299,9 +299,9 @@ var CodexAssistantProjection = class {
|
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
301
|
handleRawResponseItemCompleted(item, activeItemIds) {
|
|
302
|
-
const role = readString$
|
|
303
|
-
const phase = readString$
|
|
304
|
-
const rawItemId = readString$
|
|
302
|
+
const role = readString$3(item, "role");
|
|
303
|
+
const phase = readString$3(item, "phase");
|
|
304
|
+
const rawItemId = readString$3(item, "id");
|
|
305
305
|
const candidateWasSupersededBeforeRaw = this.latestTerminalAssistantCandidateSuperseded;
|
|
306
306
|
const pendingTerminalAssistantEchoItemId = this.pendingRawTerminalAssistantEchoItemId;
|
|
307
307
|
const isPendingTerminalAssistantEcho = role === "assistant" && phase !== "commentary" && pendingTerminalAssistantEchoItemId !== void 0 && (rawItemId === void 0 || rawItemId === pendingTerminalAssistantEchoItemId);
|
|
@@ -607,7 +607,7 @@ function collectDynamicToolContentText(contentItems) {
|
|
|
607
607
|
if (!Array.isArray(contentItems)) return "";
|
|
608
608
|
return contentItems.flatMap((entry) => {
|
|
609
609
|
if (!isJsonObject(entry)) return [];
|
|
610
|
-
const text = readString$
|
|
610
|
+
const text = readString$3(entry, "text");
|
|
611
611
|
return text ? [text] : [];
|
|
612
612
|
}).join("\n");
|
|
613
613
|
}
|
|
@@ -956,7 +956,29 @@ var CodexToolProgressProjection = class {
|
|
|
956
956
|
return this.sideEffectingNativeIds.size > 0 || this.sideEffectingDynamicIds.size > 0;
|
|
957
957
|
}
|
|
958
958
|
setLastToolError(error) {
|
|
959
|
-
|
|
959
|
+
if (!error) {
|
|
960
|
+
this.lastNativeToolError = void 0;
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
const terminalResolution = this.params.observeToolTerminal?.({
|
|
964
|
+
toolName: error.toolName,
|
|
965
|
+
...error.meta ? { meta: error.meta } : {},
|
|
966
|
+
outcome: "failure",
|
|
967
|
+
failure: {
|
|
968
|
+
...error.errorCode ? { errorCode: error.errorCode } : {},
|
|
969
|
+
...error.error ? { error: error.error } : {},
|
|
970
|
+
...error.validationErrorSummary ? { validationErrorSummary: error.validationErrorSummary } : {},
|
|
971
|
+
...error.timedOut ? { timedOut: true } : {},
|
|
972
|
+
...error.middlewareError ? { middlewareError: true } : {}
|
|
973
|
+
},
|
|
974
|
+
nativeMutation: {
|
|
975
|
+
mutatingAction: error.mutatingAction === true,
|
|
976
|
+
replaySafe: error.mutatingAction !== true,
|
|
977
|
+
...error.actionFingerprint ? { actionFingerprint: error.actionFingerprint } : {},
|
|
978
|
+
...error.fileTarget ? { fileTarget: error.fileTarget } : {}
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
this.lastNativeToolError = terminalResolution?.lastToolError ?? (this.lastNativeToolError?.mutatingAction && error.mutatingAction !== true ? this.lastNativeToolError : error);
|
|
960
982
|
}
|
|
961
983
|
recordDynamicToolResult(params) {
|
|
962
984
|
const resultText = collectDynamicToolContentText(params.contentItems);
|
|
@@ -967,16 +989,17 @@ var CodexToolProgressProjection = class {
|
|
|
967
989
|
...params.asyncStarted === true ? { asyncStarted: true } : {},
|
|
968
990
|
...!params.success ? { isError: true } : {}
|
|
969
991
|
});
|
|
970
|
-
if (
|
|
992
|
+
if (params.terminalResolution) this.lastNativeToolError = params.terminalResolution.lastToolError;
|
|
993
|
+
else if (!params.success) this.lastNativeToolError = {
|
|
971
994
|
toolName: params.tool,
|
|
972
|
-
error: resultText || "codex dynamic tool blocked"
|
|
995
|
+
error: resultText || (params.terminalType === "blocked" ? "codex dynamic tool blocked" : "codex dynamic tool failed")
|
|
973
996
|
};
|
|
974
|
-
else if (
|
|
997
|
+
else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
|
|
975
998
|
if (params.sideEffectEvidence === true) this.sideEffectingDynamicIds.add(params.callId);
|
|
976
999
|
}
|
|
977
1000
|
handleOutputDelta(params, toolName) {
|
|
978
|
-
const itemId = readString$
|
|
979
|
-
const delta = readString$
|
|
1001
|
+
const itemId = readString$3(params, "itemId");
|
|
1002
|
+
const delta = readString$3(params, "delta");
|
|
980
1003
|
if (!itemId || !delta) return;
|
|
981
1004
|
const storedOutput = this.output.append(itemId, delta);
|
|
982
1005
|
this.rememberEcho(itemId, {
|
|
@@ -1017,25 +1040,37 @@ var CodexToolProgressProjection = class {
|
|
|
1017
1040
|
});
|
|
1018
1041
|
}
|
|
1019
1042
|
recordNativeToolError(params) {
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1043
|
+
const executionStarted = params.status !== "blocked";
|
|
1044
|
+
const mutatingAction = executionStarted && isMutatingNativeToolItem(params.item);
|
|
1045
|
+
const actionFingerprint = mutatingAction ? nativeToolActionFingerprint(params.item) : void 0;
|
|
1046
|
+
const isFailure = isNonSuccessItemStatus(params.status);
|
|
1047
|
+
const error = isFailure ? itemToolError(params.item, params.status, this.output.textByItem) : void 0;
|
|
1048
|
+
const terminalResolution = this.params.observeToolTerminal?.({
|
|
1049
|
+
toolCallId: params.item.id,
|
|
1050
|
+
toolName: params.name,
|
|
1051
|
+
arguments: itemToolArgs(params.item),
|
|
1052
|
+
...params.meta ? { meta: params.meta } : {},
|
|
1053
|
+
executionStarted,
|
|
1054
|
+
outcome: isFailure ? "failure" : "success",
|
|
1055
|
+
...isFailure ? { failure: error ? { error } : {} } : {},
|
|
1056
|
+
nativeMutation: {
|
|
1057
|
+
mutatingAction,
|
|
1058
|
+
replaySafe: !mutatingAction,
|
|
1059
|
+
...actionFingerprint ? { actionFingerprint } : {}
|
|
1025
1060
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1061
|
+
});
|
|
1062
|
+
if (terminalResolution) {
|
|
1063
|
+
this.lastNativeToolError = terminalResolution.lastToolError;
|
|
1028
1064
|
return;
|
|
1029
1065
|
}
|
|
1030
|
-
|
|
1031
|
-
const actionFingerprint = nativeToolActionFingerprint(params.item);
|
|
1032
|
-
this.lastNativeToolError = {
|
|
1066
|
+
if (isFailure) this.lastNativeToolError = {
|
|
1033
1067
|
toolName: params.name,
|
|
1034
1068
|
...params.meta ? { meta: params.meta } : {},
|
|
1035
1069
|
...error ? { error } : {},
|
|
1036
|
-
...
|
|
1070
|
+
...mutatingAction ? { mutatingAction: true } : {},
|
|
1037
1071
|
...actionFingerprint ? { actionFingerprint } : {}
|
|
1038
1072
|
};
|
|
1073
|
+
else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
|
|
1039
1074
|
}
|
|
1040
1075
|
emitToolResultSummary(item) {
|
|
1041
1076
|
if (!item || !this.params.onToolResult || !this.shouldEmitToolResult()) return;
|
|
@@ -1202,7 +1237,8 @@ async function readCodexMirroredSessionHistoryMessages(target) {
|
|
|
1202
1237
|
const entries = await readCodexMirroredSessionEntries(target);
|
|
1203
1238
|
if (entries.length === 0) return [];
|
|
1204
1239
|
const firstEntry = entries[0];
|
|
1205
|
-
if (firstEntry?.type !== "session"
|
|
1240
|
+
if (firstEntry?.type !== "session") return [];
|
|
1241
|
+
if (typeof firstEntry.id !== "string") return;
|
|
1206
1242
|
migrateSessionEntries(entries);
|
|
1207
1243
|
return sanitizeCodexHistoryImagePayloads(buildSessionContext(entries.filter((entry) => {
|
|
1208
1244
|
return entry !== null && typeof entry === "object" && !Array.isArray(entry) && entry.type !== "session";
|
|
@@ -1533,14 +1569,14 @@ var CodexEventProjection = class {
|
|
|
1533
1569
|
data: {
|
|
1534
1570
|
method,
|
|
1535
1571
|
phase: method.endsWith("/started") ? "started" : "completed",
|
|
1536
|
-
reviewId: readString$
|
|
1572
|
+
reviewId: readString$3(params, "reviewId"),
|
|
1537
1573
|
targetItemId: readNullableString(params, "targetItemId"),
|
|
1538
|
-
decisionSource: readString$
|
|
1539
|
-
status: review ? readString$
|
|
1540
|
-
riskLevel: review ? readString$
|
|
1541
|
-
userAuthorization: review ? readString$
|
|
1574
|
+
decisionSource: readString$3(params, "decisionSource"),
|
|
1575
|
+
status: review ? readString$3(review, "status") : void 0,
|
|
1576
|
+
riskLevel: review ? readString$3(review, "riskLevel") : void 0,
|
|
1577
|
+
userAuthorization: review ? readString$3(review, "userAuthorization") : void 0,
|
|
1542
1578
|
rationale: review ? readNullableString(review, "rationale") : void 0,
|
|
1543
|
-
actionType: action ? readString$
|
|
1579
|
+
actionType: action ? readString$3(action, "type") : void 0
|
|
1544
1580
|
}
|
|
1545
1581
|
});
|
|
1546
1582
|
}
|
|
@@ -1549,7 +1585,7 @@ var CodexEventProjection = class {
|
|
|
1549
1585
|
stream: "codex_app_server.guardian",
|
|
1550
1586
|
data: {
|
|
1551
1587
|
phase: "warning",
|
|
1552
|
-
message: readString$
|
|
1588
|
+
message: readString$3(params, "message")
|
|
1553
1589
|
}
|
|
1554
1590
|
});
|
|
1555
1591
|
}
|
|
@@ -1565,14 +1601,14 @@ var CodexEventProjection = class {
|
|
|
1565
1601
|
phase: method === "hook/started" ? "started" : "completed",
|
|
1566
1602
|
threadId: this.threadId,
|
|
1567
1603
|
turnId: hookTurnId === void 0 ? this.turnId : hookTurnId,
|
|
1568
|
-
hookRunId: readString$
|
|
1569
|
-
eventName: readString$
|
|
1570
|
-
handlerType: readString$
|
|
1571
|
-
executionMode: readString$
|
|
1572
|
-
scope: readString$
|
|
1573
|
-
source: readString$
|
|
1574
|
-
sourcePath: readString$
|
|
1575
|
-
status: readString$
|
|
1604
|
+
hookRunId: readString$3(run, "id"),
|
|
1605
|
+
eventName: readString$3(run, "eventName"),
|
|
1606
|
+
handlerType: readString$3(run, "handlerType"),
|
|
1607
|
+
executionMode: readString$3(run, "executionMode"),
|
|
1608
|
+
scope: readString$3(run, "scope"),
|
|
1609
|
+
source: readString$3(run, "source"),
|
|
1610
|
+
sourcePath: readString$3(run, "sourcePath"),
|
|
1611
|
+
status: readString$3(run, "status"),
|
|
1576
1612
|
statusMessage: readNullableString(run, "statusMessage"),
|
|
1577
1613
|
...durationMs !== void 0 ? { durationMs } : {},
|
|
1578
1614
|
...entries.length > 0 ? { entries } : {}
|
|
@@ -1673,10 +1709,10 @@ var CodexGeneratedMediaProjection = class {
|
|
|
1673
1709
|
});
|
|
1674
1710
|
}
|
|
1675
1711
|
async recordRaw(item) {
|
|
1676
|
-
if (readString$
|
|
1677
|
-
const result = readString$
|
|
1712
|
+
if (readString$3(item, "type") !== "image_generation_call") return;
|
|
1713
|
+
const result = readString$3(item, "result");
|
|
1678
1714
|
if (!result) return;
|
|
1679
|
-
const itemId = readString$
|
|
1715
|
+
const itemId = readString$3(item, "id") ?? `raw-image-${this.itemIds.size}`;
|
|
1680
1716
|
this.itemIds.add(itemId);
|
|
1681
1717
|
const maxBytes = resolveGeneratedImageMaxBytes(this.config);
|
|
1682
1718
|
const estimatedDecodedBytes = estimateBase64DecodedBytes(result);
|
|
@@ -1691,7 +1727,7 @@ var CodexGeneratedMediaProjection = class {
|
|
|
1691
1727
|
const asset = generatedImageAssetFromBase64({
|
|
1692
1728
|
base64: result,
|
|
1693
1729
|
index: this.itemIds.size,
|
|
1694
|
-
revisedPrompt: readString$
|
|
1730
|
+
revisedPrompt: readString$3(item, "revised_prompt") ?? readString$3(item, "revisedPrompt"),
|
|
1695
1731
|
fileNamePrefix: "codex-image-generation",
|
|
1696
1732
|
sniffMimeType: true
|
|
1697
1733
|
});
|
|
@@ -1749,6 +1785,90 @@ function resolveGeneratedImageMaxBytes(config) {
|
|
|
1749
1785
|
return DEFAULT_GENERATED_IMAGE_MAX_BYTES;
|
|
1750
1786
|
}
|
|
1751
1787
|
//#endregion
|
|
1788
|
+
//#region extensions/codex/src/app-server/dynamic-tool-response-state.ts
|
|
1789
|
+
function withDynamicToolTerminalResolution(response, terminalResolution) {
|
|
1790
|
+
if (terminalResolution) {
|
|
1791
|
+
Object.defineProperties(response, {
|
|
1792
|
+
terminalResolution: {
|
|
1793
|
+
configurable: true,
|
|
1794
|
+
enumerable: false,
|
|
1795
|
+
value: terminalResolution
|
|
1796
|
+
},
|
|
1797
|
+
executionStarted: {
|
|
1798
|
+
configurable: true,
|
|
1799
|
+
enumerable: false,
|
|
1800
|
+
value: terminalResolution.executionStarted
|
|
1801
|
+
},
|
|
1802
|
+
...terminalResolution.executedArguments ? { executedArguments: {
|
|
1803
|
+
configurable: true,
|
|
1804
|
+
enumerable: false,
|
|
1805
|
+
value: terminalResolution.executedArguments
|
|
1806
|
+
} } : {}
|
|
1807
|
+
});
|
|
1808
|
+
withDynamicToolSideEffectEvidence(response, terminalResolution.sideEffectEvidence);
|
|
1809
|
+
}
|
|
1810
|
+
return response;
|
|
1811
|
+
}
|
|
1812
|
+
function withDynamicToolExecutionState(response, state) {
|
|
1813
|
+
Object.defineProperties(response, {
|
|
1814
|
+
executedArguments: {
|
|
1815
|
+
configurable: true,
|
|
1816
|
+
enumerable: false,
|
|
1817
|
+
value: state.executedArguments
|
|
1818
|
+
},
|
|
1819
|
+
executionStarted: {
|
|
1820
|
+
configurable: true,
|
|
1821
|
+
enumerable: false,
|
|
1822
|
+
value: state.executionStarted
|
|
1823
|
+
}
|
|
1824
|
+
});
|
|
1825
|
+
return withDynamicToolSideEffectEvidence(response, state.sideEffectEvidence === true);
|
|
1826
|
+
}
|
|
1827
|
+
function withDynamicToolSideEffectEvidence(response, sideEffectEvidence) {
|
|
1828
|
+
if (!sideEffectEvidence) {
|
|
1829
|
+
delete response.sideEffectEvidence;
|
|
1830
|
+
return response;
|
|
1831
|
+
}
|
|
1832
|
+
Object.defineProperty(response, "sideEffectEvidence", {
|
|
1833
|
+
configurable: true,
|
|
1834
|
+
enumerable: false,
|
|
1835
|
+
value: true
|
|
1836
|
+
});
|
|
1837
|
+
return response;
|
|
1838
|
+
}
|
|
1839
|
+
function createFailedDynamicToolResponse(message, options) {
|
|
1840
|
+
const response = {
|
|
1841
|
+
contentItems: [{
|
|
1842
|
+
type: "inputText",
|
|
1843
|
+
text: message
|
|
1844
|
+
}],
|
|
1845
|
+
success: false
|
|
1846
|
+
};
|
|
1847
|
+
Object.defineProperties(response, {
|
|
1848
|
+
diagnosticTerminalReason: {
|
|
1849
|
+
configurable: true,
|
|
1850
|
+
enumerable: false,
|
|
1851
|
+
value: options?.terminalReason ?? "failed"
|
|
1852
|
+
},
|
|
1853
|
+
diagnosticTerminalType: {
|
|
1854
|
+
configurable: true,
|
|
1855
|
+
enumerable: false,
|
|
1856
|
+
value: "error"
|
|
1857
|
+
}
|
|
1858
|
+
});
|
|
1859
|
+
if (options?.executionStarted !== void 0) Object.defineProperty(response, "executionStarted", {
|
|
1860
|
+
configurable: true,
|
|
1861
|
+
enumerable: false,
|
|
1862
|
+
value: options.executionStarted
|
|
1863
|
+
});
|
|
1864
|
+
if (options?.executedArguments !== void 0) Object.defineProperty(response, "executedArguments", {
|
|
1865
|
+
configurable: true,
|
|
1866
|
+
enumerable: false,
|
|
1867
|
+
value: options.executedArguments
|
|
1868
|
+
});
|
|
1869
|
+
return withDynamicToolSideEffectEvidence(response, options?.sideEffectEvidence === true);
|
|
1870
|
+
}
|
|
1871
|
+
//#endregion
|
|
1752
1872
|
//#region extensions/codex/src/app-server/tool-abort-terminal-reason.ts
|
|
1753
1873
|
/** Leaf helper shared by native and dynamic tool diagnostics. */
|
|
1754
1874
|
const CODEX_TIMEOUT_ABORT_REASONS = /* @__PURE__ */ new Set([
|
|
@@ -1846,6 +1966,30 @@ function formatDynamicToolTimeoutDetails(params) {
|
|
|
1846
1966
|
*/
|
|
1847
1967
|
async function handleDynamicToolCallWithTimeout(params) {
|
|
1848
1968
|
let didNotifyAgentToolResult = false;
|
|
1969
|
+
const conservativeRaceResponses = /* @__PURE__ */ new WeakSet();
|
|
1970
|
+
const finalizeTerminal = (response) => {
|
|
1971
|
+
const executionSnapshot = params.toolBridge.consumeToolExecutionSnapshot?.(params.call.callId);
|
|
1972
|
+
const observedExecutionStarted = executionSnapshot?.executionStarted ?? (conservativeRaceResponses.has(response) ? void 0 : response.executionStarted);
|
|
1973
|
+
const terminalResolution = params.observeToolTerminal?.({
|
|
1974
|
+
toolCallId: params.call.callId,
|
|
1975
|
+
toolName: params.call.tool,
|
|
1976
|
+
arguments: response.executedArguments ?? executionSnapshot?.executedArguments ?? params.call.arguments,
|
|
1977
|
+
...params.toolMeta ? { meta: params.toolMeta } : {},
|
|
1978
|
+
...observedExecutionStarted !== void 0 ? { executionStarted: observedExecutionStarted } : {},
|
|
1979
|
+
outcome: response.success ? "success" : "failure",
|
|
1980
|
+
...!response.success ? { failure: { error: readDynamicToolResponseText(response) } } : {}
|
|
1981
|
+
});
|
|
1982
|
+
return withDynamicToolTerminalResolution(response, terminalResolution);
|
|
1983
|
+
};
|
|
1984
|
+
const createFailedAfterPossibleDispatch = (message, terminalReason) => {
|
|
1985
|
+
const response = createFailedDynamicToolResponse(message, {
|
|
1986
|
+
executionStarted: true,
|
|
1987
|
+
sideEffectEvidence: true,
|
|
1988
|
+
terminalReason
|
|
1989
|
+
});
|
|
1990
|
+
conservativeRaceResponses.add(response);
|
|
1991
|
+
return response;
|
|
1992
|
+
};
|
|
1849
1993
|
const notifyAgentToolResult = (event) => {
|
|
1850
1994
|
if (didNotifyAgentToolResult) return;
|
|
1851
1995
|
didNotifyAgentToolResult = true;
|
|
@@ -1876,7 +2020,10 @@ async function handleDynamicToolCallWithTimeout(params) {
|
|
|
1876
2020
|
const terminalReason = resolveCodexToolAbortTerminalReason(params.signal);
|
|
1877
2021
|
params.onFallbackSelected?.();
|
|
1878
2022
|
notifyFailedToolResult(message, terminalReason);
|
|
1879
|
-
return
|
|
2023
|
+
return finalizeTerminal(createFailedDynamicToolResponse(message, {
|
|
2024
|
+
executionStarted: false,
|
|
2025
|
+
terminalReason
|
|
2026
|
+
}));
|
|
1880
2027
|
}
|
|
1881
2028
|
const controller = new AbortController();
|
|
1882
2029
|
let timeout;
|
|
@@ -1888,10 +2035,7 @@ async function handleDynamicToolCallWithTimeout(params) {
|
|
|
1888
2035
|
params.onFallbackSelected?.();
|
|
1889
2036
|
controller.abort(params.signal.reason ?? /* @__PURE__ */ new Error(message));
|
|
1890
2037
|
notifyFailedToolResult(message, terminalReason);
|
|
1891
|
-
resolveAbort?.(
|
|
1892
|
-
sideEffectEvidence: true,
|
|
1893
|
-
terminalReason
|
|
1894
|
-
}));
|
|
2038
|
+
resolveAbort?.(createFailedAfterPossibleDispatch(message, terminalReason));
|
|
1895
2039
|
};
|
|
1896
2040
|
const abortPromise = new Promise((resolve) => {
|
|
1897
2041
|
resolveAbort = resolve;
|
|
@@ -1912,10 +2056,7 @@ async function handleDynamicToolCallWithTimeout(params) {
|
|
|
1912
2056
|
consoleMessage: timeoutDetails.consoleMessage
|
|
1913
2057
|
});
|
|
1914
2058
|
notifyFailedToolResult(timeoutDetails.responseMessage, "timed_out");
|
|
1915
|
-
resolve(
|
|
1916
|
-
sideEffectEvidence: true,
|
|
1917
|
-
terminalReason: "timed_out"
|
|
1918
|
-
}));
|
|
2059
|
+
resolve(createFailedAfterPossibleDispatch(timeoutDetails.responseMessage, "timed_out"));
|
|
1919
2060
|
}, timeoutMs);
|
|
1920
2061
|
timeout.unref?.();
|
|
1921
2062
|
});
|
|
@@ -1926,21 +2067,19 @@ async function handleDynamicToolCallWithTimeout(params) {
|
|
|
1926
2067
|
params.toolBridge.handleToolCall(params.call, {
|
|
1927
2068
|
signal: controller.signal,
|
|
1928
2069
|
onAgentToolResult: notifyAgentToolResult,
|
|
1929
|
-
toolCallOrdinal: params.toolCallOrdinal
|
|
2070
|
+
toolCallOrdinal: params.toolCallOrdinal,
|
|
2071
|
+
retainExecutionSnapshot: true
|
|
1930
2072
|
}),
|
|
1931
2073
|
abortPromise,
|
|
1932
2074
|
timeoutPromise
|
|
1933
2075
|
]);
|
|
1934
2076
|
if (!response.success && !didNotifyAgentToolResult) notifyFailedToolResult(readDynamicToolResponseText(response), response.diagnosticTerminalReason ?? "failed");
|
|
1935
|
-
return response;
|
|
2077
|
+
return finalizeTerminal(response);
|
|
1936
2078
|
} catch (error) {
|
|
1937
2079
|
const terminalReason = params.signal.aborted ? resolveCodexToolAbortTerminalReason(params.signal) : resolveToolExecutionErrorKind(error);
|
|
1938
2080
|
const message = formatToolExecutionErrorMessage(error, "OpenClaw dynamic tool call failed.");
|
|
1939
2081
|
notifyFailedToolResult(message, terminalReason);
|
|
1940
|
-
return
|
|
1941
|
-
sideEffectEvidence: true,
|
|
1942
|
-
terminalReason
|
|
1943
|
-
});
|
|
2082
|
+
return finalizeTerminal(createFailedAfterPossibleDispatch(message, terminalReason));
|
|
1944
2083
|
} finally {
|
|
1945
2084
|
if (timeout) clearTimeout(timeout);
|
|
1946
2085
|
params.signal.removeEventListener("abort", abortFromRun);
|
|
@@ -1951,31 +2090,6 @@ async function handleDynamicToolCallWithTimeout(params) {
|
|
|
1951
2090
|
function readDynamicToolResponseText(response) {
|
|
1952
2091
|
return response.contentItems.flatMap((item) => item.type === "inputText" && typeof item.text === "string" ? [item.text] : []).join("\n").trim() || "OpenClaw dynamic tool call failed.";
|
|
1953
2092
|
}
|
|
1954
|
-
function failedDynamicToolResponse(message, options) {
|
|
1955
|
-
const response = {
|
|
1956
|
-
contentItems: [{
|
|
1957
|
-
type: "inputText",
|
|
1958
|
-
text: message
|
|
1959
|
-
}],
|
|
1960
|
-
success: false
|
|
1961
|
-
};
|
|
1962
|
-
Object.defineProperty(response, "diagnosticTerminalType", {
|
|
1963
|
-
configurable: true,
|
|
1964
|
-
enumerable: false,
|
|
1965
|
-
value: "error"
|
|
1966
|
-
});
|
|
1967
|
-
Object.defineProperty(response, "diagnosticTerminalReason", {
|
|
1968
|
-
configurable: true,
|
|
1969
|
-
enumerable: false,
|
|
1970
|
-
value: options?.terminalReason ?? "failed"
|
|
1971
|
-
});
|
|
1972
|
-
if (options?.sideEffectEvidence === true) Object.defineProperty(response, "sideEffectEvidence", {
|
|
1973
|
-
configurable: true,
|
|
1974
|
-
enumerable: false,
|
|
1975
|
-
value: true
|
|
1976
|
-
});
|
|
1977
|
-
return response;
|
|
1978
|
-
}
|
|
1979
2093
|
/** Strips OpenClaw-only metadata before sending a dynamic tool response to Codex. */
|
|
1980
2094
|
function toCodexDynamicToolProtocolResponse(response) {
|
|
1981
2095
|
return {
|
|
@@ -2181,6 +2295,7 @@ function createCodexNativeHookRelay(params) {
|
|
|
2181
2295
|
runId: params.runId,
|
|
2182
2296
|
...params.channelId ? { channelId: params.channelId } : {},
|
|
2183
2297
|
allowedEvents: params.events,
|
|
2298
|
+
preToolUseLoopDetection: params.loopDetectionPreToolUseRelay,
|
|
2184
2299
|
ttlMs: resolveCodexNativeHookRelayTtlMs({
|
|
2185
2300
|
explicitTtlMs: params.options?.ttlMs,
|
|
2186
2301
|
attemptTimeoutMs: params.attemptTimeoutMs,
|
|
@@ -2239,7 +2354,8 @@ function buildCodexNativeHookRelayConfig(params) {
|
|
|
2239
2354
|
const codexEvent = CODEX_HOOK_EVENT_BY_NATIVE_EVENT[event];
|
|
2240
2355
|
const selected = selectedEvents.has(event);
|
|
2241
2356
|
const shouldRelay = params.relay.shouldRelayEvent(event);
|
|
2242
|
-
|
|
2357
|
+
const selectedNoopPreToolUse = selected && event === "pre_tool_use" && !shouldRelay && params.loopDetectionPreToolUseRelay;
|
|
2358
|
+
if (!selected || !shouldRelay && !selectedNoopPreToolUse) {
|
|
2243
2359
|
if (selected || params.clearOmittedEvents) config[`hooks.${codexEvent}`] = [];
|
|
2244
2360
|
if (params.clearOmittedEvents) for (const sourcePath of CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS) hookState[`${sourcePath}:${CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[event]}:0:0`] = { enabled: false };
|
|
2245
2361
|
continue;
|
|
@@ -2382,12 +2498,12 @@ var CodexNativeToolLifecycleProjector = class {
|
|
|
2382
2498
|
this.preToolUseFailureByItem.set(failure.toolCallId, record);
|
|
2383
2499
|
}
|
|
2384
2500
|
recordRawWebSearchResult(item) {
|
|
2385
|
-
if (readString$
|
|
2386
|
-
const toolCallId = readString$
|
|
2501
|
+
if (readString$3(item, "type") !== "web_search_call") return;
|
|
2502
|
+
const toolCallId = readString$3(item, "id");
|
|
2387
2503
|
if (!toolCallId || this.completedItemIds.has(toolCallId)) return;
|
|
2388
2504
|
const toolName = "web_search";
|
|
2389
2505
|
this.recordStarted(toolCallId, toolName, "unknown");
|
|
2390
|
-
const rawStatus = readString$
|
|
2506
|
+
const rawStatus = readString$3(item, "status");
|
|
2391
2507
|
if (rawStatus === "in_progress" || rawStatus === "running") return;
|
|
2392
2508
|
const status = rawStatus === "completed" ? "completed" : rawStatus === "cancelled" ? "cancelled" : rawStatus === "failed" || rawStatus === "error" || rawStatus === "incomplete" ? "failed" : "unknown";
|
|
2393
2509
|
this.recordTerminal(toolCallId, toolName, status, { sourceTimestampMs: this.webSearchCompletionByItem.get(toolCallId)?.sourceTimestampMs });
|
|
@@ -2512,8 +2628,8 @@ var CodexReasoningProjection = class {
|
|
|
2512
2628
|
this.reasoningEnded = false;
|
|
2513
2629
|
}
|
|
2514
2630
|
async handleReasoningDelta(method, params) {
|
|
2515
|
-
const itemId = readString$
|
|
2516
|
-
const delta = readString$
|
|
2631
|
+
const itemId = readString$3(params, "itemId") ?? "reasoning";
|
|
2632
|
+
const delta = readString$3(params, "delta") ?? "";
|
|
2517
2633
|
if (!delta) return;
|
|
2518
2634
|
this.reasoningStarted = true;
|
|
2519
2635
|
if (!this.reasoningItemOrder.has(itemId)) this.reasoningItemOrder.set(itemId, this.reasoningItemOrder.size);
|
|
@@ -2532,24 +2648,29 @@ var CodexReasoningProjection = class {
|
|
|
2532
2648
|
});
|
|
2533
2649
|
}
|
|
2534
2650
|
handlePlanDelta(params) {
|
|
2535
|
-
const itemId = readString$
|
|
2536
|
-
const delta = readString$
|
|
2651
|
+
const itemId = readString$3(params, "itemId") ?? "plan";
|
|
2652
|
+
const delta = readString$3(params, "delta") ?? "";
|
|
2537
2653
|
if (!delta) return;
|
|
2538
2654
|
const text = `${this.planTextByItem.get(itemId) ?? ""}${delta}`;
|
|
2539
2655
|
this.planTextByItem.set(itemId, text);
|
|
2540
2656
|
this.emitPlanUpdate({
|
|
2541
2657
|
explanation: void 0,
|
|
2542
|
-
steps: splitPlanText(text)
|
|
2658
|
+
steps: splitPlanText(text).map((step) => ({
|
|
2659
|
+
step,
|
|
2660
|
+
status: "pending"
|
|
2661
|
+
}))
|
|
2543
2662
|
});
|
|
2544
2663
|
}
|
|
2545
2664
|
handleTurnPlanUpdated(params) {
|
|
2546
2665
|
const plan = Array.isArray(params.plan) ? params.plan.flatMap((entry) => {
|
|
2547
2666
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [];
|
|
2548
2667
|
const record = entry;
|
|
2549
|
-
const step = readString$
|
|
2550
|
-
const status = readString$2(record, "status");
|
|
2668
|
+
const step = readString$3(record, "step");
|
|
2551
2669
|
if (!step) return [];
|
|
2552
|
-
return
|
|
2670
|
+
return [{
|
|
2671
|
+
step,
|
|
2672
|
+
status: normalizePlanStepStatus(readString$3(record, "status"))
|
|
2673
|
+
}];
|
|
2553
2674
|
}) : void 0;
|
|
2554
2675
|
this.emitPlanUpdate({
|
|
2555
2676
|
explanation: readNullableString(params, "explanation"),
|
|
@@ -2561,7 +2682,10 @@ var CodexReasoningProjection = class {
|
|
|
2561
2682
|
this.planTextByItem.set(item.id, item.text);
|
|
2562
2683
|
this.emitPlanUpdate({
|
|
2563
2684
|
explanation: void 0,
|
|
2564
|
-
steps: splitPlanText(item.text)
|
|
2685
|
+
steps: splitPlanText(item.text).map((step) => ({
|
|
2686
|
+
step,
|
|
2687
|
+
status: "pending"
|
|
2688
|
+
}))
|
|
2565
2689
|
});
|
|
2566
2690
|
}
|
|
2567
2691
|
}
|
|
@@ -2590,6 +2714,10 @@ var CodexReasoningProjection = class {
|
|
|
2590
2714
|
});
|
|
2591
2715
|
}
|
|
2592
2716
|
};
|
|
2717
|
+
function normalizePlanStepStatus(status) {
|
|
2718
|
+
if (status === "inProgress" || status === "in_progress") return "in_progress";
|
|
2719
|
+
return status === "completed" ? "completed" : "pending";
|
|
2720
|
+
}
|
|
2593
2721
|
function collectReasoningTextValues(groups, itemOrder) {
|
|
2594
2722
|
return [...groups.values()].toSorted((left, right) => {
|
|
2595
2723
|
const itemDelta = (itemOrder.get(left.itemId) ?? Number.MAX_SAFE_INTEGER) - (itemOrder.get(right.itemId) ?? Number.MAX_SAFE_INTEGER);
|
|
@@ -2603,15 +2731,187 @@ function reasoningMethodOrder(method) {
|
|
|
2603
2731
|
}
|
|
2604
2732
|
//#endregion
|
|
2605
2733
|
//#region extensions/codex/src/app-server/event-projector-usage.ts
|
|
2606
|
-
function
|
|
2734
|
+
function readTokenCount(record, key) {
|
|
2735
|
+
const value = readNonNegativeInteger(record, key);
|
|
2736
|
+
return value !== void 0 && Number.isSafeInteger(value) ? value : void 0;
|
|
2737
|
+
}
|
|
2738
|
+
function normalizeCodexThreadTokenUsage(record) {
|
|
2607
2739
|
const inputTokens = readNumber(record, "inputTokens");
|
|
2608
2740
|
const cacheRead = readNumber(record, "cachedInputTokens");
|
|
2609
|
-
|
|
2741
|
+
const usage = normalizeUsage({
|
|
2610
2742
|
input: inputTokens !== void 0 && cacheRead !== void 0 ? Math.max(0, inputTokens - cacheRead) : inputTokens,
|
|
2611
2743
|
output: readNumber(record, "outputTokens"),
|
|
2612
2744
|
cacheRead,
|
|
2613
2745
|
total: readNumber(record, "totalTokens")
|
|
2614
2746
|
});
|
|
2747
|
+
return usage ? {
|
|
2748
|
+
...usage,
|
|
2749
|
+
contextUsage: { state: "unavailable" }
|
|
2750
|
+
} : void 0;
|
|
2751
|
+
}
|
|
2752
|
+
function normalizeCodexResponseTokenUsage(record) {
|
|
2753
|
+
const totalTokens = readTokenCount(record, "totalTokens");
|
|
2754
|
+
const inputTokens = readTokenCount(record, "inputTokens");
|
|
2755
|
+
const cacheRead = readTokenCount(record, "cachedInputTokens");
|
|
2756
|
+
const output = readTokenCount(record, "outputTokens");
|
|
2757
|
+
const reasoningOutput = readTokenCount(record, "reasoningOutputTokens");
|
|
2758
|
+
const cacheWrite = record.cacheWriteInputTokens === void 0 ? 0 : readTokenCount(record, "cacheWriteInputTokens");
|
|
2759
|
+
if (totalTokens === void 0 || inputTokens === void 0 || cacheRead === void 0 || cacheWrite === void 0 || output === void 0 || reasoningOutput === void 0 || cacheRead + cacheWrite > inputTokens || totalTokens !== inputTokens + output) return;
|
|
2760
|
+
const usage = normalizeUsage({
|
|
2761
|
+
input: inputTokens - cacheRead - cacheWrite,
|
|
2762
|
+
output,
|
|
2763
|
+
cacheRead,
|
|
2764
|
+
cacheWrite,
|
|
2765
|
+
total: totalTokens
|
|
2766
|
+
});
|
|
2767
|
+
if (!usage) return;
|
|
2768
|
+
return {
|
|
2769
|
+
...usage,
|
|
2770
|
+
contextUsage: {
|
|
2771
|
+
state: "available",
|
|
2772
|
+
promptTokens: inputTokens,
|
|
2773
|
+
totalTokens
|
|
2774
|
+
}
|
|
2775
|
+
};
|
|
2776
|
+
}
|
|
2777
|
+
//#endregion
|
|
2778
|
+
//#region extensions/codex/src/app-server/usage-limit-error.ts
|
|
2779
|
+
/**
|
|
2780
|
+
* Enriches Codex usage-limit failures with current rate-limit information and
|
|
2781
|
+
* marks blocked auth profiles when Codex exposes a reset time.
|
|
2782
|
+
*/
|
|
2783
|
+
const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
|
|
2784
|
+
function createCodexUsageLimitPromptError(message) {
|
|
2785
|
+
return Object.assign(new Error(message), { status: 429 });
|
|
2786
|
+
}
|
|
2787
|
+
function isCodexUsageLimitPromptError(error) {
|
|
2788
|
+
return error instanceof Error && "status" in error && error.status === 429;
|
|
2789
|
+
}
|
|
2790
|
+
/** Marks a Codex auth profile blocked until the reset time advertised by rate limits. */
|
|
2791
|
+
async function markCodexAuthProfileBlockedFromRateLimits(params) {
|
|
2792
|
+
const authProfileId = params.authProfileId?.trim();
|
|
2793
|
+
if (!authProfileId || !params.params.authProfileStore) return;
|
|
2794
|
+
const blockedUntil = resolveCodexUsageLimitResetAtMs(params.rateLimits);
|
|
2795
|
+
if (!blockedUntil) return;
|
|
2796
|
+
try {
|
|
2797
|
+
await markAuthProfileBlockedUntil({
|
|
2798
|
+
store: params.params.authProfileStore,
|
|
2799
|
+
profileId: authProfileId,
|
|
2800
|
+
blockedUntil,
|
|
2801
|
+
source: "codex_rate_limits",
|
|
2802
|
+
agentDir: params.params.agentDir,
|
|
2803
|
+
runId: params.params.runId,
|
|
2804
|
+
modelId: params.params.modelId
|
|
2805
|
+
});
|
|
2806
|
+
} catch (error) {
|
|
2807
|
+
embeddedAgentLog.debug("failed to mark Codex auth profile blocked from app-server limits", {
|
|
2808
|
+
authProfileId,
|
|
2809
|
+
error: formatErrorMessage(error)
|
|
2810
|
+
});
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
/** Formats a turn-start usage-limit error, refreshing rate limits when needed. */
|
|
2814
|
+
async function formatCodexTurnStartUsageLimitError(params) {
|
|
2815
|
+
return refreshCodexUsageLimitError({
|
|
2816
|
+
client: params.client,
|
|
2817
|
+
source: readCodexTurnStartUsageLimitErrorSource(params.client, params.error, params.errorNotification, params.rateLimitsRevisionBeforeTurnStart),
|
|
2818
|
+
timeoutMs: params.timeoutMs,
|
|
2819
|
+
signal: params.signal
|
|
2820
|
+
});
|
|
2821
|
+
}
|
|
2822
|
+
/** Refreshes a generic prompt usage-limit message into a reset-aware message. */
|
|
2823
|
+
async function refreshCodexUsageLimitPromptError(params) {
|
|
2824
|
+
if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(params.message)) return;
|
|
2825
|
+
return refreshCodexUsageLimitError({
|
|
2826
|
+
client: params.client,
|
|
2827
|
+
source: {
|
|
2828
|
+
message: params.message,
|
|
2829
|
+
codexErrorInfo: "usageLimitExceeded",
|
|
2830
|
+
rateLimits: readRecentCodexRateLimits(params.client)
|
|
2831
|
+
},
|
|
2832
|
+
timeoutMs: params.timeoutMs,
|
|
2833
|
+
signal: params.signal
|
|
2834
|
+
});
|
|
2835
|
+
}
|
|
2836
|
+
async function refreshCodexUsageLimitError(params) {
|
|
2837
|
+
const initialMessage = formatCodexUsageLimitErrorMessage(params.source);
|
|
2838
|
+
if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(initialMessage)) return initialMessage ? {
|
|
2839
|
+
message: initialMessage,
|
|
2840
|
+
...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
|
|
2841
|
+
} : void 0;
|
|
2842
|
+
const rateLimits = await readCodexRateLimitsFromAppServerForUsageLimitError({
|
|
2843
|
+
client: params.client,
|
|
2844
|
+
timeoutMs: params.timeoutMs,
|
|
2845
|
+
signal: params.signal
|
|
2846
|
+
});
|
|
2847
|
+
if (!rateLimits) return initialMessage ? {
|
|
2848
|
+
message: initialMessage,
|
|
2849
|
+
...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
|
|
2850
|
+
} : void 0;
|
|
2851
|
+
const message = formatCodexUsageLimitErrorMessage({
|
|
2852
|
+
message: params.source.message,
|
|
2853
|
+
codexErrorInfo: params.source.codexErrorInfo,
|
|
2854
|
+
rateLimits
|
|
2855
|
+
}) ?? initialMessage;
|
|
2856
|
+
return message ? {
|
|
2857
|
+
message,
|
|
2858
|
+
rateLimitsForProfile: rateLimits
|
|
2859
|
+
} : void 0;
|
|
2860
|
+
}
|
|
2861
|
+
async function readCodexRateLimitsFromAppServerForUsageLimitError(params) {
|
|
2862
|
+
if (params.signal?.aborted) return;
|
|
2863
|
+
try {
|
|
2864
|
+
const rateLimits = await params.client.request(CODEX_CONTROL_METHODS.rateLimits, void 0, {
|
|
2865
|
+
timeoutMs: resolveCodexUsageLimitRateLimitRefreshTimeoutMs(params.timeoutMs),
|
|
2866
|
+
signal: params.signal
|
|
2867
|
+
});
|
|
2868
|
+
rememberCodexRateLimitsRead(params.client, rateLimits);
|
|
2869
|
+
return rateLimits;
|
|
2870
|
+
} catch (error) {
|
|
2871
|
+
embeddedAgentLog.debug("codex app-server rate-limit refresh failed after usage-limit error", { error: formatErrorMessage(error) });
|
|
2872
|
+
return;
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
function resolveCodexUsageLimitRateLimitRefreshTimeoutMs(timeoutMs) {
|
|
2876
|
+
if (timeoutMs === void 0 || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS;
|
|
2877
|
+
return Math.max(100, Math.min(timeoutMs, CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS));
|
|
2878
|
+
}
|
|
2879
|
+
function readCodexTurnStartUsageLimitErrorSource(client, error, errorNotification, rateLimitsRevisionBeforeTurnStart) {
|
|
2880
|
+
const notificationError = readCodexErrorNotification(errorNotification);
|
|
2881
|
+
const errorPayload = readCodexErrorPayload(error);
|
|
2882
|
+
const rateLimits = errorPayload.rateLimits ?? readRecentCodexRateLimits(client);
|
|
2883
|
+
const cacheUpdatedDuringTurnStart = rateLimitsRevisionBeforeTurnStart !== void 0 && readCodexRateLimitsRevision(client) > rateLimitsRevisionBeforeTurnStart;
|
|
2884
|
+
return {
|
|
2885
|
+
message: notificationError?.message ?? errorPayload.message ?? formatErrorMessage(error),
|
|
2886
|
+
codexErrorInfo: notificationError?.codexErrorInfo ?? errorPayload.codexErrorInfo,
|
|
2887
|
+
rateLimits,
|
|
2888
|
+
rateLimitsTrustedForProfile: errorPayload.rateLimits !== void 0 || cacheUpdatedDuringTurnStart
|
|
2889
|
+
};
|
|
2890
|
+
}
|
|
2891
|
+
function readCodexErrorNotification(notification) {
|
|
2892
|
+
if (notification?.method !== "error" || !isJsonObject(notification.params)) return;
|
|
2893
|
+
const error = notification.params.error;
|
|
2894
|
+
return isJsonObject(error) ? {
|
|
2895
|
+
message: readString$2(error, "message"),
|
|
2896
|
+
codexErrorInfo: error.codexErrorInfo
|
|
2897
|
+
} : void 0;
|
|
2898
|
+
}
|
|
2899
|
+
function readCodexErrorPayload(error) {
|
|
2900
|
+
const message = error instanceof Error ? error.message : void 0;
|
|
2901
|
+
if (!error || typeof error !== "object" || !("data" in error)) return { message };
|
|
2902
|
+
const data = error.data;
|
|
2903
|
+
if (!isJsonObject(data)) return { message };
|
|
2904
|
+
const nestedError = isJsonObject(data.error) ? data.error : data;
|
|
2905
|
+
const rateLimits = nestedError.rateLimits ?? data.rateLimits;
|
|
2906
|
+
return {
|
|
2907
|
+
message: readString$2(nestedError, "message") ?? message,
|
|
2908
|
+
codexErrorInfo: nestedError.codexErrorInfo,
|
|
2909
|
+
rateLimits
|
|
2910
|
+
};
|
|
2911
|
+
}
|
|
2912
|
+
function readString$2(record, key) {
|
|
2913
|
+
const value = record[key];
|
|
2914
|
+
return typeof value === "string" ? value : void 0;
|
|
2615
2915
|
}
|
|
2616
2916
|
//#endregion
|
|
2617
2917
|
//#region extensions/codex/src/app-server/event-projector.ts
|
|
@@ -2725,10 +3025,14 @@ var CodexAppServerEventProjector = class {
|
|
|
2725
3025
|
case "turn/completed":
|
|
2726
3026
|
await this.handleTurnCompleted(params);
|
|
2727
3027
|
break;
|
|
3028
|
+
case "rawResponse/completed":
|
|
3029
|
+
this.handleRawResponseCompleted(params);
|
|
3030
|
+
break;
|
|
2728
3031
|
case "rawResponseItem/completed":
|
|
2729
3032
|
await this.handleRawResponseItemCompleted(params);
|
|
2730
3033
|
break;
|
|
2731
3034
|
case "error":
|
|
3035
|
+
this.responseUsage = void 0;
|
|
2732
3036
|
if (params.willRetry === true) break;
|
|
2733
3037
|
this.promptError = this.formatCodexErrorMessage(params) ?? "codex app-server error";
|
|
2734
3038
|
this.promptErrorSource = "prompt";
|
|
@@ -2741,6 +3045,7 @@ var CodexAppServerEventProjector = class {
|
|
|
2741
3045
|
const assistantTexts = this.assistantProjection.collectAssistantTexts();
|
|
2742
3046
|
const reasoningText = this.reasoningProjection.reasoningText();
|
|
2743
3047
|
const planText = this.reasoningProjection.planText();
|
|
3048
|
+
const projectedUsage = this.aborted ? this.tokenUsage : this.responseUsage ?? this.tokenUsage;
|
|
2744
3049
|
const hasAssistantItemText = this.assistantProjection.hasAssistantItemTextForSynthesis();
|
|
2745
3050
|
const legacyFailClosed = !this.completedTurn || this.completedTurn.status !== "completed" || hasAssistantItemText;
|
|
2746
3051
|
const hasDeliverableAssistantOnCompletedTurn = this.completedTurn?.status === "completed" && assistantTexts.some((text) => text.trim().length > 0);
|
|
@@ -2753,7 +3058,7 @@ var CodexAppServerEventProjector = class {
|
|
|
2753
3058
|
this.promptErrorSource = this.promptErrorSource ?? "prompt";
|
|
2754
3059
|
}
|
|
2755
3060
|
const assistantMessageOptions = {
|
|
2756
|
-
tokenUsage:
|
|
3061
|
+
tokenUsage: projectedUsage,
|
|
2757
3062
|
aborted: this.aborted,
|
|
2758
3063
|
promptError: this.promptError
|
|
2759
3064
|
};
|
|
@@ -2806,7 +3111,7 @@ var CodexAppServerEventProjector = class {
|
|
|
2806
3111
|
toolAudioAsVoice: toolTelemetry.toolAudioAsVoice,
|
|
2807
3112
|
successfulCronAdds: toolTelemetry.successfulCronAdds,
|
|
2808
3113
|
cloudCodeAssistFormatError: false,
|
|
2809
|
-
attemptUsage:
|
|
3114
|
+
attemptUsage: projectedUsage,
|
|
2810
3115
|
replayMetadata: {
|
|
2811
3116
|
hadPotentialSideEffects,
|
|
2812
3117
|
replaySafe: !hadPotentialSideEffects
|
|
@@ -2835,13 +3140,14 @@ var CodexAppServerEventProjector = class {
|
|
|
2835
3140
|
}
|
|
2836
3141
|
markAborted() {
|
|
2837
3142
|
this.aborted = true;
|
|
3143
|
+
this.responseUsage = void 0;
|
|
2838
3144
|
}
|
|
2839
3145
|
isCompacting() {
|
|
2840
3146
|
return this.activeCompactionItemIds.size > 0;
|
|
2841
3147
|
}
|
|
2842
3148
|
async handleItemStarted(params) {
|
|
2843
3149
|
const item = readItem(params.item);
|
|
2844
|
-
const itemId = item?.id ?? readString$
|
|
3150
|
+
const itemId = item?.id ?? readString$3(params, "itemId");
|
|
2845
3151
|
this.assistantProjection.recordItemStarted(item, itemId);
|
|
2846
3152
|
if (itemId) this.activeItemIds.add(itemId);
|
|
2847
3153
|
this.recordNativeToolOutcome(item);
|
|
@@ -2896,7 +3202,7 @@ var CodexAppServerEventProjector = class {
|
|
|
2896
3202
|
const item = readItem(params.item);
|
|
2897
3203
|
this.recordNativeToolOutcome(item);
|
|
2898
3204
|
this.clearTerminalPresentationForNativeItem(item);
|
|
2899
|
-
const itemId = item?.id ?? readString$
|
|
3205
|
+
const itemId = item?.id ?? readString$3(params, "itemId");
|
|
2900
3206
|
if (itemId) {
|
|
2901
3207
|
this.activeItemIds.delete(itemId);
|
|
2902
3208
|
this.completedItemIds.add(itemId);
|
|
@@ -2962,19 +3268,25 @@ var CodexAppServerEventProjector = class {
|
|
|
2962
3268
|
const tokenUsage = isJsonObject(params.tokenUsage) ? params.tokenUsage : void 0;
|
|
2963
3269
|
const last = tokenUsage && isJsonObject(tokenUsage.last) ? tokenUsage.last : void 0;
|
|
2964
3270
|
if (!last) return;
|
|
2965
|
-
const usage =
|
|
3271
|
+
const usage = normalizeCodexThreadTokenUsage(last);
|
|
2966
3272
|
if (usage) this.tokenUsage = usage;
|
|
2967
3273
|
}
|
|
3274
|
+
handleRawResponseCompleted(params) {
|
|
3275
|
+
const usage = isJsonObject(params.usage) ? params.usage : void 0;
|
|
3276
|
+
this.responseUsage = usage ? normalizeCodexResponseTokenUsage(usage) : void 0;
|
|
3277
|
+
}
|
|
2968
3278
|
async handleTurnCompleted(params) {
|
|
2969
3279
|
const turn = readCodexTurn(params.turn);
|
|
2970
3280
|
if (!turn || turn.id !== this.turnId) return;
|
|
2971
3281
|
this.completedTurn = turn;
|
|
3282
|
+
if (turn.status !== "completed") this.responseUsage = void 0;
|
|
2972
3283
|
if (turn.status === "failed") {
|
|
2973
|
-
|
|
3284
|
+
const usageLimitMessage = formatCodexUsageLimitErrorMessage({
|
|
2974
3285
|
message: turn.error?.message,
|
|
2975
3286
|
codexErrorInfo: turn.error?.codexErrorInfo,
|
|
2976
3287
|
rateLimits: this.options.readRecentRateLimits?.()
|
|
2977
|
-
})
|
|
3288
|
+
});
|
|
3289
|
+
this.promptError = usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : turn.error?.message ?? "codex app-server turn failed";
|
|
2978
3290
|
this.promptErrorSource = "prompt";
|
|
2979
3291
|
}
|
|
2980
3292
|
const turnItems = turn.items ?? [];
|
|
@@ -3051,11 +3363,12 @@ var CodexAppServerEventProjector = class {
|
|
|
3051
3363
|
}
|
|
3052
3364
|
formatCodexErrorMessage(params) {
|
|
3053
3365
|
const error = isJsonObject(params.error) ? params.error : void 0;
|
|
3054
|
-
|
|
3055
|
-
message: error ? readString$
|
|
3366
|
+
const usageLimitMessage = formatCodexUsageLimitErrorMessage({
|
|
3367
|
+
message: error ? readString$3(error, "message") : void 0,
|
|
3056
3368
|
codexErrorInfo: error?.codexErrorInfo,
|
|
3057
3369
|
rateLimits: this.options.readRecentRateLimits?.()
|
|
3058
|
-
})
|
|
3370
|
+
});
|
|
3371
|
+
return usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : readCodexErrorNotificationMessage(params);
|
|
3059
3372
|
}
|
|
3060
3373
|
emitAgentEvent(event) {
|
|
3061
3374
|
try {
|
|
@@ -3083,7 +3396,7 @@ var CodexAppServerEventProjector = class {
|
|
|
3083
3396
|
return threadId === this.threadId && turnId === this.turnId;
|
|
3084
3397
|
}
|
|
3085
3398
|
isHookNotificationForCurrentThread(params) {
|
|
3086
|
-
const threadId = readString$
|
|
3399
|
+
const threadId = readString$3(params, "threadId");
|
|
3087
3400
|
const turnId = params.turnId;
|
|
3088
3401
|
return threadId === this.threadId && (turnId === this.turnId || turnId === null);
|
|
3089
3402
|
}
|
|
@@ -3121,12 +3434,72 @@ function addCodexMessageToolOnlyFinalParameter(parameters) {
|
|
|
3121
3434
|
...rawProperties,
|
|
3122
3435
|
final: {
|
|
3123
3436
|
type: "boolean",
|
|
3124
|
-
description: "Set
|
|
3437
|
+
description: "Set false for progress or true to complete the current source reply. If omitted, OpenClaw continues and resolves the latest omitted source reply when the turn ends."
|
|
3125
3438
|
}
|
|
3126
3439
|
}
|
|
3127
3440
|
};
|
|
3128
3441
|
}
|
|
3129
3442
|
//#endregion
|
|
3443
|
+
//#region extensions/codex/src/app-server/shell-dynamic-tools.ts
|
|
3444
|
+
const CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME = "node_exec";
|
|
3445
|
+
const CODEX_NODE_PROCESS_DYNAMIC_TOOL_NAME = "node_process";
|
|
3446
|
+
const CODEX_NODE_EXEC_POLICY_PARAMETER_NAMES = /* @__PURE__ */ new Set([
|
|
3447
|
+
"host",
|
|
3448
|
+
"security",
|
|
3449
|
+
"ask"
|
|
3450
|
+
]);
|
|
3451
|
+
/** Returns true when plugin config explicitly removes any named dynamic tool. */
|
|
3452
|
+
function isCodexDynamicToolExcluded(config, names) {
|
|
3453
|
+
const normalizedNames = new Set(names.map((name) => normalizeCodexDynamicToolName(name)));
|
|
3454
|
+
return (config.codexDynamicToolsExclude ?? []).some((name) => normalizedNames.has(normalizeCodexDynamicToolName(name)));
|
|
3455
|
+
}
|
|
3456
|
+
function createNodeExecDynamicTool(execTool, configuredNode) {
|
|
3457
|
+
const pinnedNode = configuredNode?.trim();
|
|
3458
|
+
return {
|
|
3459
|
+
...execTool,
|
|
3460
|
+
name: CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME,
|
|
3461
|
+
description: pinnedNode ? "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." : "Run a shell command on an OpenClaw remote node. Select the node by name or id when multiple nodes are available. This tool always uses OpenClaw host=node internally and follows the existing node exec approval and allowlist policy. Use node_process for follow-up on backgrounded node_exec sessions. Use Codex's native shell for local app-server work.",
|
|
3462
|
+
parameters: hideNodeExecDynamicToolParameters(execTool.parameters, { hideNode: Boolean(pinnedNode) }),
|
|
3463
|
+
execute: async (toolCallId, args, signal, onUpdate) => {
|
|
3464
|
+
const result = await execTool.execute(toolCallId, pinNodeExecDynamicToolArgs(args, pinnedNode), signal, onUpdate);
|
|
3465
|
+
return {
|
|
3466
|
+
...result,
|
|
3467
|
+
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)
|
|
3468
|
+
};
|
|
3469
|
+
}
|
|
3470
|
+
};
|
|
3471
|
+
}
|
|
3472
|
+
function createNodeProcessDynamicTool(processTool) {
|
|
3473
|
+
return {
|
|
3474
|
+
...processTool,
|
|
3475
|
+
name: CODEX_NODE_PROCESS_DYNAMIC_TOOL_NAME,
|
|
3476
|
+
description: "Manage node_exec sessions that were started on OpenClaw remote nodes: 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."
|
|
3477
|
+
};
|
|
3478
|
+
}
|
|
3479
|
+
function pinNodeExecDynamicToolArgs(args, configuredNode) {
|
|
3480
|
+
const { host: _host, security: _security, ask: _ask, node: requestedNode, ...rest } = args && typeof args === "object" && !Array.isArray(args) ? args : {};
|
|
3481
|
+
const node = configuredNode ?? (typeof requestedNode === "string" ? requestedNode.trim() : "");
|
|
3482
|
+
return {
|
|
3483
|
+
...rest,
|
|
3484
|
+
host: "node",
|
|
3485
|
+
...node ? { node } : {}
|
|
3486
|
+
};
|
|
3487
|
+
}
|
|
3488
|
+
function hideNodeExecDynamicToolParameters(parameters, options) {
|
|
3489
|
+
if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) return parameters;
|
|
3490
|
+
const schema = parameters;
|
|
3491
|
+
const rawProperties = schema.properties;
|
|
3492
|
+
if (!rawProperties || typeof rawProperties !== "object" || Array.isArray(rawProperties)) return parameters;
|
|
3493
|
+
const nextProperties = Object.fromEntries(Object.entries(rawProperties).filter(([name]) => !CODEX_NODE_EXEC_POLICY_PARAMETER_NAMES.has(normalizeCodexDynamicToolName(name)) && !(options.hideNode && normalizeCodexDynamicToolName(name) === "node")));
|
|
3494
|
+
const rawRequired = schema.required;
|
|
3495
|
+
const nextRequired = Array.isArray(rawRequired) ? rawRequired.filter((name) => typeof name !== "string" || !CODEX_NODE_EXEC_POLICY_PARAMETER_NAMES.has(normalizeCodexDynamicToolName(name)) && !(options.hideNode && normalizeCodexDynamicToolName(name) === "node")) : rawRequired;
|
|
3496
|
+
return {
|
|
3497
|
+
...schema,
|
|
3498
|
+
properties: nextProperties,
|
|
3499
|
+
...Array.isArray(rawRequired) ? { required: nextRequired } : {}
|
|
3500
|
+
};
|
|
3501
|
+
}
|
|
3502
|
+
//#endregion
|
|
3130
3503
|
//#region extensions/codex/src/app-server/vision-tools.ts
|
|
3131
3504
|
/**
|
|
3132
3505
|
* Filters Codex dynamic tools for turns that already contain image inputs so
|
|
@@ -3153,13 +3526,6 @@ const CODEX_NATIVE_SANDBOX_TOOL_REQUIREMENTS = [
|
|
|
3153
3526
|
"apply_patch"
|
|
3154
3527
|
];
|
|
3155
3528
|
const CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW = /* @__PURE__ */ new Set(["read", "write"]);
|
|
3156
|
-
const CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME = "node_exec";
|
|
3157
|
-
const CODEX_NODE_PROCESS_DYNAMIC_TOOL_NAME = "node_process";
|
|
3158
|
-
const CODEX_NODE_EXEC_POLICY_PARAMETER_NAMES = /* @__PURE__ */ new Set([
|
|
3159
|
-
"host",
|
|
3160
|
-
"security",
|
|
3161
|
-
"ask"
|
|
3162
|
-
]);
|
|
3163
3529
|
function preserveRingZeroSystemAgentTool(allTools, filteredTools) {
|
|
3164
3530
|
const openclaw = allTools.find((tool) => tool.name === "openclaw" && tool.catalogMode === "direct-only");
|
|
3165
3531
|
if (!openclaw) return filteredTools;
|
|
@@ -3248,8 +3614,8 @@ async function buildDynamicTools(input) {
|
|
|
3248
3614
|
const toolBuildStages = createCodexDynamicToolBuildStageTracker({ enabled: input.profilerEnabled });
|
|
3249
3615
|
const modelHasVision = params.model.input?.includes("image") ?? false;
|
|
3250
3616
|
const agentDir = params.agentDir ?? resolveAgentDir(params.config ?? {}, input.sessionAgentId);
|
|
3251
|
-
const
|
|
3252
|
-
const createOpenClawCodingTools = dynamicToolBuildState.openClawCodingToolsFactory ??
|
|
3617
|
+
const { createOpenClawCodingTools: defaultCreateOpenClawCodingTools, resolveWebSearchToolPolicy } = await import("openclaw/plugin-sdk/agent-harness");
|
|
3618
|
+
const createOpenClawCodingTools = dynamicToolBuildState.openClawCodingToolsFactory ?? defaultCreateOpenClawCodingTools;
|
|
3253
3619
|
toolBuildStages.mark("load-agent-harness-tools");
|
|
3254
3620
|
const sessionKeys = resolveOpenClawCodingToolsSessionKeys(params, input.sandboxSessionKey);
|
|
3255
3621
|
const nativeExecutionPolicy = resolveCodexNativeExecutionPolicyForDynamicTools(input);
|
|
@@ -3346,7 +3712,7 @@ async function buildDynamicTools(input) {
|
|
|
3346
3712
|
nativeProviderWebSearchSupport: input.nativeProviderWebSearchSupport
|
|
3347
3713
|
});
|
|
3348
3714
|
const readableAllTools = [...readableAllToolProjection.tools];
|
|
3349
|
-
const normallyProfiledTools = filterCodexDynamicTools(readableAllTools, input.pluginConfig);
|
|
3715
|
+
const normallyProfiledTools = shouldKeepOpenClawShellDynamicTools(input, nativeExecutionPolicy) ? filterCodexDynamicToolsWithOpenClawShell(readableAllTools, input.pluginConfig) : filterCodexDynamicTools(readableAllTools, input.pluginConfig);
|
|
3350
3716
|
const profileFilteredTools = (input.isHostScopedToolActive?.("openclaw") ?? isHostScopedAgentToolActive("openclaw")) && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow) ? preserveRingZeroSystemAgentTool(readableAllTools, normallyProfiledTools) : normallyProfiledTools;
|
|
3351
3717
|
const codexFilteredTools = addNodeShellDynamicToolsIfNeeded(addSandboxShellDynamicToolsIfAvailable(isCodexMemoryFlushRun(params) ? filterCodexMemoryFlushDynamicTools(readableAllTools) : profileFilteredTools, readableAllTools, input), readableAllTools, input, nativeExecutionPolicy);
|
|
3352
3718
|
toolBuildStages.mark("codex-filtering");
|
|
@@ -3356,7 +3722,7 @@ async function buildDynamicTools(input) {
|
|
|
3356
3722
|
});
|
|
3357
3723
|
toolBuildStages.mark("vision-filtering");
|
|
3358
3724
|
const webSearchPresent = visionFilteredTools.some((tool) => tool.name === "web_search");
|
|
3359
|
-
const webSearchPolicy =
|
|
3725
|
+
const webSearchPolicy = resolveWebSearchToolPolicy({
|
|
3360
3726
|
config: params.config,
|
|
3361
3727
|
modelProvider: params.model.provider,
|
|
3362
3728
|
modelId: params.modelId,
|
|
@@ -3570,13 +3936,6 @@ function shouldExposeSandboxExecDynamicTool(input) {
|
|
|
3570
3936
|
const backendId = input.sandbox?.enabled ? input.sandbox.backendId.trim().toLowerCase() : "";
|
|
3571
3937
|
return Boolean(backendId && input.nativeToolSurfaceEnabled === false);
|
|
3572
3938
|
}
|
|
3573
|
-
function isCodexDynamicToolExcluded(config, names) {
|
|
3574
|
-
const normalizedNames = new Set(names.map((name) => normalizeCodexDynamicToolName(name)));
|
|
3575
|
-
return (config.codexDynamicToolsExclude ?? []).some((name) => {
|
|
3576
|
-
const normalized = normalizeCodexDynamicToolName(name);
|
|
3577
|
-
return normalizedNames.has(normalized);
|
|
3578
|
-
});
|
|
3579
|
-
}
|
|
3580
3939
|
function isSandboxShellDynamicToolExcluded(config) {
|
|
3581
3940
|
return isCodexDynamicToolExcluded(config, [
|
|
3582
3941
|
"exec",
|
|
@@ -3594,55 +3953,12 @@ function addNodeShellDynamicToolsIfNeeded(filteredTools, allTools, input, nodePo
|
|
|
3594
3953
|
const processTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "process");
|
|
3595
3954
|
if (!execTool || !processTool) return filteredTools;
|
|
3596
3955
|
const toolsToAppend = [];
|
|
3597
|
-
if (!isCodexDynamicToolExcluded(input.pluginConfig, ["exec",
|
|
3598
|
-
if (!isCodexDynamicToolExcluded(input.pluginConfig, ["process",
|
|
3956
|
+
if (!isCodexDynamicToolExcluded(input.pluginConfig, ["exec", "node_exec"]) && !filteredTools.some((tool) => normalizeCodexDynamicToolName(tool.name) === "node_exec")) toolsToAppend.push(createNodeExecDynamicTool(execTool, nodePolicy.node));
|
|
3957
|
+
if (!isCodexDynamicToolExcluded(input.pluginConfig, ["process", "node_process"]) && !filteredTools.some((tool) => normalizeCodexDynamicToolName(tool.name) === "node_process")) toolsToAppend.push(createNodeProcessDynamicTool(processTool));
|
|
3599
3958
|
return toolsToAppend.length > 0 ? [...filteredTools, ...toolsToAppend] : filteredTools;
|
|
3600
3959
|
}
|
|
3601
|
-
function
|
|
3602
|
-
|
|
3603
|
-
return {
|
|
3604
|
-
...execTool,
|
|
3605
|
-
name: CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME,
|
|
3606
|
-
description: pinnedNode ? "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." : "Run a shell command on an OpenClaw remote node. Select the node by name or id when multiple nodes are available. This tool always uses OpenClaw host=node internally and follows the existing node exec approval and allowlist policy. Use node_process for follow-up on backgrounded node_exec sessions. Use Codex's native shell for local app-server work.",
|
|
3607
|
-
parameters: hideNodeExecDynamicToolParameters(execTool.parameters, { hideNode: Boolean(pinnedNode) }),
|
|
3608
|
-
execute: async (toolCallId, args, signal, onUpdate) => {
|
|
3609
|
-
const result = await execTool.execute(toolCallId, pinNodeExecDynamicToolArgs(args, pinnedNode), signal, onUpdate);
|
|
3610
|
-
return {
|
|
3611
|
-
...result,
|
|
3612
|
-
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)
|
|
3613
|
-
};
|
|
3614
|
-
}
|
|
3615
|
-
};
|
|
3616
|
-
}
|
|
3617
|
-
function createNodeProcessDynamicTool(processTool) {
|
|
3618
|
-
return {
|
|
3619
|
-
...processTool,
|
|
3620
|
-
name: CODEX_NODE_PROCESS_DYNAMIC_TOOL_NAME,
|
|
3621
|
-
description: "Manage node_exec sessions that were started on OpenClaw remote nodes: 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."
|
|
3622
|
-
};
|
|
3623
|
-
}
|
|
3624
|
-
function pinNodeExecDynamicToolArgs(args, configuredNode) {
|
|
3625
|
-
const { host: _host, security: _security, ask: _ask, node: requestedNode, ...rest } = args && typeof args === "object" && !Array.isArray(args) ? args : {};
|
|
3626
|
-
const node = configuredNode ?? (typeof requestedNode === "string" ? requestedNode.trim() : "");
|
|
3627
|
-
return {
|
|
3628
|
-
...rest,
|
|
3629
|
-
host: "node",
|
|
3630
|
-
...node ? { node } : {}
|
|
3631
|
-
};
|
|
3632
|
-
}
|
|
3633
|
-
function hideNodeExecDynamicToolParameters(parameters, options) {
|
|
3634
|
-
if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) return parameters;
|
|
3635
|
-
const schema = parameters;
|
|
3636
|
-
const rawProperties = schema.properties;
|
|
3637
|
-
if (!rawProperties || typeof rawProperties !== "object" || Array.isArray(rawProperties)) return parameters;
|
|
3638
|
-
const nextProperties = Object.fromEntries(Object.entries(rawProperties).filter(([name]) => !CODEX_NODE_EXEC_POLICY_PARAMETER_NAMES.has(normalizeCodexDynamicToolName(name)) && !(options.hideNode && normalizeCodexDynamicToolName(name) === "node")));
|
|
3639
|
-
const rawRequired = schema.required;
|
|
3640
|
-
const nextRequired = Array.isArray(rawRequired) ? rawRequired.filter((name) => typeof name !== "string" || !CODEX_NODE_EXEC_POLICY_PARAMETER_NAMES.has(normalizeCodexDynamicToolName(name)) && !(options.hideNode && normalizeCodexDynamicToolName(name) === "node")) : rawRequired;
|
|
3641
|
-
return {
|
|
3642
|
-
...schema,
|
|
3643
|
-
properties: nextProperties,
|
|
3644
|
-
...Array.isArray(rawRequired) ? { required: nextRequired } : {}
|
|
3645
|
-
};
|
|
3960
|
+
function shouldKeepOpenClawShellDynamicTools(input, nodePolicy) {
|
|
3961
|
+
return !isCodexMemoryFlushRun(input.params) && input.nativeToolSurfaceEnabled === false && input.sandbox?.enabled !== true && nodePolicy.effectiveExecHost !== "node";
|
|
3646
3962
|
}
|
|
3647
3963
|
function resolveCodexNativeExecutionPolicyForDynamicTools(input) {
|
|
3648
3964
|
return resolveCodexNativeExecutionPolicy({
|
|
@@ -3663,7 +3979,7 @@ function filterCodexDynamicToolsForAllowlist(tools, toolsAllow) {
|
|
|
3663
3979
|
const allowSet = new Set(toolsAllow.map((name) => normalizeCodexDynamicToolName(name)).filter(Boolean));
|
|
3664
3980
|
return tools.filter((tool) => {
|
|
3665
3981
|
const normalized = normalizeCodexDynamicToolName(tool.name);
|
|
3666
|
-
return allowSet.has(normalized) || normalized === "sandbox_exec" && allowSet.has("exec") || normalized === "sandbox_process" && (allowSet.has("exec") || allowSet.has("process")) || normalized ===
|
|
3982
|
+
return allowSet.has(normalized) || normalized === "sandbox_exec" && allowSet.has("exec") || normalized === "sandbox_process" && (allowSet.has("exec") || allowSet.has("process")) || normalized === "node_exec" && allowSet.has("exec") || normalized === "node_process" && (allowSet.has("exec") || allowSet.has("process"));
|
|
3667
3983
|
});
|
|
3668
3984
|
}
|
|
3669
3985
|
/** Detects the wildcard allowlist marker after Codex tool-name normalization. */
|
|
@@ -3675,90 +3991,28 @@ function shouldForceMessageTool(params) {
|
|
|
3675
3991
|
return params.disableMessageTool !== true && params.sourceReplyDeliveryMode === "message_tool_only";
|
|
3676
3992
|
}
|
|
3677
3993
|
//#endregion
|
|
3678
|
-
//#region extensions/codex/src/app-server/
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
const CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS = 6e4;
|
|
3687
|
-
/** Short guard after apparent assistant completion. */
|
|
3688
|
-
const CODEX_TURN_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS = 1e4;
|
|
3689
|
-
const CODEX_POST_TOOL_RAW_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS = 5 * 6e4;
|
|
3690
|
-
/** Guard after reasoning/commentary progress when no tool handoff occurred. */
|
|
3691
|
-
const CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS = 5 * 6e4;
|
|
3692
|
-
/** Long terminal idle watch for app-server turns that never send completion. */
|
|
3693
|
-
const CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS = 30 * 6e4;
|
|
3694
|
-
function resolvePositiveIntegerTimeoutMs(value, fallbackMs) {
|
|
3695
|
-
return resolveTimerTimeoutMs(value, resolveTimerTimeoutMs(fallbackMs, 1));
|
|
3696
|
-
}
|
|
3697
|
-
/** Runs startup work with abort and timeout handling plus optional cleanup. */
|
|
3698
|
-
async function withCodexStartupTimeout(params) {
|
|
3699
|
-
if (params.signal.aborted) throw new Error("codex app-server startup aborted");
|
|
3700
|
-
let timeout;
|
|
3701
|
-
let abortCleanup;
|
|
3702
|
-
let timeoutError;
|
|
3703
|
-
let timeoutCleanup;
|
|
3704
|
-
try {
|
|
3705
|
-
return await Promise.race([params.operation(), new Promise((_, reject) => {
|
|
3706
|
-
const rejectOnce = (error) => {
|
|
3707
|
-
if (timeout) {
|
|
3708
|
-
clearTimeout(timeout);
|
|
3709
|
-
timeout = void 0;
|
|
3710
|
-
}
|
|
3711
|
-
reject(error);
|
|
3712
|
-
};
|
|
3713
|
-
timeout = setTimeout(() => {
|
|
3714
|
-
timeoutError = /* @__PURE__ */ new Error("codex app-server startup timed out");
|
|
3715
|
-
timeoutCleanup = Promise.resolve(params.onTimeout?.()).then(() => void 0, () => void 0);
|
|
3716
|
-
timeoutCleanup.finally(() => {
|
|
3717
|
-
rejectOnce(timeoutError);
|
|
3718
|
-
});
|
|
3719
|
-
}, params.timeoutMs);
|
|
3720
|
-
const abortListener = () => rejectOnce(/* @__PURE__ */ new Error("codex app-server startup aborted"));
|
|
3721
|
-
params.signal.addEventListener("abort", abortListener, { once: true });
|
|
3722
|
-
abortCleanup = () => params.signal.removeEventListener("abort", abortListener);
|
|
3723
|
-
})]);
|
|
3724
|
-
} catch (error) {
|
|
3725
|
-
if (timeoutError) {
|
|
3726
|
-
await timeoutCleanup;
|
|
3727
|
-
throw timeoutError;
|
|
3728
|
-
}
|
|
3729
|
-
throw error;
|
|
3730
|
-
} finally {
|
|
3731
|
-
if (timeout) clearTimeout(timeout);
|
|
3732
|
-
abortCleanup?.();
|
|
3994
|
+
//#region extensions/codex/src/app-server/source-reply-finality.ts
|
|
3995
|
+
const sourceReplyDeliveryIntents = /* @__PURE__ */ new WeakMap();
|
|
3996
|
+
/** Retain source-reply intent until the owning Codex turn has an authoritative outcome. */
|
|
3997
|
+
function recordCodexSourceReplyDeliveryIntent(owner, intent) {
|
|
3998
|
+
const intents = sourceReplyDeliveryIntents.get(owner);
|
|
3999
|
+
if (intents) {
|
|
4000
|
+
intents.push(intent);
|
|
4001
|
+
return;
|
|
3733
4002
|
}
|
|
4003
|
+
sourceReplyDeliveryIntents.set(owner, [intent]);
|
|
3734
4004
|
}
|
|
3735
|
-
/**
|
|
3736
|
-
function
|
|
3737
|
-
const
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
function resolveCodexTurnAssistantCompletionIdleTimeoutMs(value) {
|
|
3747
|
-
return resolvePositiveIntegerTimeoutMs(value, CODEX_TURN_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS);
|
|
3748
|
-
}
|
|
3749
|
-
/** Resolves the conservative post-tool raw assistant guard timeout. */
|
|
3750
|
-
function resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs(value, fallbackMs) {
|
|
3751
|
-
return resolvePositiveIntegerTimeoutMs(value, Math.max(resolvePositiveIntegerTimeoutMs(void 0, fallbackMs), CODEX_POST_TOOL_RAW_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS));
|
|
3752
|
-
}
|
|
3753
|
-
/** Resolves the long terminal turn idle timeout. */
|
|
3754
|
-
function resolveCodexTurnTerminalIdleTimeoutMs(value, runTimeoutOverrideMs) {
|
|
3755
|
-
const explicitRunBudgetMs = resolvePositiveIntegerTimeoutMs(runTimeoutOverrideMs, CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS);
|
|
3756
|
-
return resolvePositiveIntegerTimeoutMs(value, Math.max(CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS, explicitRunBudgetMs));
|
|
3757
|
-
}
|
|
3758
|
-
/** Adds gateway grace time to a caller timeout without overflowing invalid values. */
|
|
3759
|
-
function resolveCodexGatewayTimeoutWithGraceMs(timeoutMs, graceMs = 1e4) {
|
|
3760
|
-
const timeout = resolvePositiveIntegerTimeoutMs(timeoutMs, 1);
|
|
3761
|
-
return addTimerTimeoutGraceMs(timeout, resolveTimerTimeoutMs(graceMs, 0, 0)) ?? timeout;
|
|
4005
|
+
/** Resolve omitted finality without changing explicit progress or final markers. */
|
|
4006
|
+
function settleCodexSourceReplyFinality(owner, turnSucceeded) {
|
|
4007
|
+
const intents = sourceReplyDeliveryIntents.get(owner);
|
|
4008
|
+
if (!intents) return false;
|
|
4009
|
+
const lastIntent = intents.at(-1);
|
|
4010
|
+
for (const intent of intents) {
|
|
4011
|
+
if (intent.final !== void 0) continue;
|
|
4012
|
+
intent.record.sourceReplyFinal = turnSucceeded && intent === lastIntent;
|
|
4013
|
+
}
|
|
4014
|
+
sourceReplyDeliveryIntents.delete(owner);
|
|
4015
|
+
return turnSucceeded && intents.some((intent) => intent.record.sourceReplyFinal === true);
|
|
3762
4016
|
}
|
|
3763
4017
|
//#endregion
|
|
3764
4018
|
//#region extensions/codex/src/app-server/provider-capabilities.ts
|
|
@@ -4580,6 +4834,7 @@ async function handleCodexAppServerApprovalRequest(params) {
|
|
|
4580
4834
|
paramsForRun: params.paramsForRun,
|
|
4581
4835
|
context,
|
|
4582
4836
|
nativeHookRelay: params.nativeHookRelay,
|
|
4837
|
+
autoApprove: params.autoApprove,
|
|
4583
4838
|
signal: params.signal
|
|
4584
4839
|
});
|
|
4585
4840
|
if (policyOutcome?.outcome === "denied") {
|
|
@@ -4759,6 +5014,7 @@ async function runOpenClawToolPolicyForApprovalRequest(params) {
|
|
|
4759
5014
|
context: params.context,
|
|
4760
5015
|
policyRequest,
|
|
4761
5016
|
nativeHookRelay: params.nativeHookRelay,
|
|
5017
|
+
autoApprove: params.autoApprove,
|
|
4762
5018
|
cwd,
|
|
4763
5019
|
signal: params.signal
|
|
4764
5020
|
});
|
|
@@ -4867,6 +5123,11 @@ async function runNativeRelayToolPolicyForApprovalRequest(params) {
|
|
|
4867
5123
|
};
|
|
4868
5124
|
return { handled: true };
|
|
4869
5125
|
} catch (error) {
|
|
5126
|
+
if (params.autoApprove === true && !hasNativeHookRelayInvocation({
|
|
5127
|
+
relayId: params.nativeHookRelay.relayId,
|
|
5128
|
+
event: "pre_tool_use",
|
|
5129
|
+
toolUseId: params.context.approvalId
|
|
5130
|
+
})) return;
|
|
4870
5131
|
return {
|
|
4871
5132
|
handled: true,
|
|
4872
5133
|
blocked: true,
|
|
@@ -5539,6 +5800,7 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5539
5800
|
return getChannelAgentToolMeta(tool) === void 0;
|
|
5540
5801
|
};
|
|
5541
5802
|
const legacyExtensionRunner = createCodexAppServerToolResultExtensionRunner(toolResultHookContext);
|
|
5803
|
+
const executionSnapshotStates = /* @__PURE__ */ new Map();
|
|
5542
5804
|
const directToolNames = /* @__PURE__ */ new Set([...ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES, ...params.directToolNames ?? []]);
|
|
5543
5805
|
return {
|
|
5544
5806
|
availableSpecs: createCodexDynamicToolSpecs({
|
|
@@ -5552,9 +5814,16 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5552
5814
|
directToolNames
|
|
5553
5815
|
}),
|
|
5554
5816
|
telemetry,
|
|
5817
|
+
consumeToolExecutionSnapshot: (toolCallId) => {
|
|
5818
|
+
const state = executionSnapshotStates.get(toolCallId);
|
|
5819
|
+
executionSnapshotStates.delete(toolCallId);
|
|
5820
|
+
if (state) state.consumed = true;
|
|
5821
|
+
return state?.snapshot;
|
|
5822
|
+
},
|
|
5555
5823
|
handleToolCall: async (call, options) => {
|
|
5556
5824
|
const toolEntry = toolMap.get(call.tool);
|
|
5557
5825
|
if (!toolEntry) {
|
|
5826
|
+
const executedArguments = jsonObjectToRecord(call.arguments);
|
|
5558
5827
|
const message = registeredToolNames.has(call.tool) ? `OpenClaw tool is not available for this turn: ${call.tool}` : `Unknown OpenClaw tool: ${call.tool}`;
|
|
5559
5828
|
finalizeToolTerminalPresentation({
|
|
5560
5829
|
toolCallId: call.callId,
|
|
@@ -5566,28 +5835,34 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5566
5835
|
toolCallOrdinal: options?.toolCallOrdinal
|
|
5567
5836
|
});
|
|
5568
5837
|
notifyAgentToolResult(options?.onAgentToolResult, call.tool, failedToolResult(message), true);
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
}],
|
|
5574
|
-
success: false
|
|
5575
|
-
};
|
|
5576
|
-
return {
|
|
5577
|
-
contentItems: [{
|
|
5578
|
-
type: "inputText",
|
|
5579
|
-
text: message
|
|
5580
|
-
}],
|
|
5581
|
-
success: false
|
|
5582
|
-
};
|
|
5838
|
+
return createFailedDynamicToolResponse(message, {
|
|
5839
|
+
executedArguments,
|
|
5840
|
+
executionStarted: false
|
|
5841
|
+
});
|
|
5583
5842
|
}
|
|
5584
5843
|
const { tool, name: toolName } = toolEntry;
|
|
5585
5844
|
const args = jsonObjectToRecord(call.arguments);
|
|
5586
5845
|
const startedAt = Date.now();
|
|
5587
5846
|
const signal = composeAbortSignals(params.signal, options?.signal);
|
|
5588
5847
|
let didStartExecution = false;
|
|
5848
|
+
let didDispatchExecution = false;
|
|
5589
5849
|
let executionPrevented = false;
|
|
5590
5850
|
let executedArgs = structuredClone(args);
|
|
5851
|
+
const executionSnapshotState = {
|
|
5852
|
+
consumed: false,
|
|
5853
|
+
retainAfterCompletion: options?.retainExecutionSnapshot === true
|
|
5854
|
+
};
|
|
5855
|
+
executionSnapshotStates.set(call.callId, executionSnapshotState);
|
|
5856
|
+
const captureExecutionBoundary = () => {
|
|
5857
|
+
didStartExecution ||= didDispatchExecution;
|
|
5858
|
+
executionPrevented = executionPrevented || consumePreExecutionBlockedToolCall(call.callId, toolResultHookContext.runId);
|
|
5859
|
+
const adjustedExecutedArgs = consumeAdjustedParamsForToolCall(call.callId, toolResultHookContext.runId);
|
|
5860
|
+
if (isRecord(adjustedExecutedArgs)) executedArgs = adjustedExecutedArgs;
|
|
5861
|
+
if (!executionSnapshotState.consumed) executionSnapshotState.snapshot = {
|
|
5862
|
+
executedArguments: structuredClone(executedArgs),
|
|
5863
|
+
executionStarted: didStartExecution && !executionPrevented
|
|
5864
|
+
};
|
|
5865
|
+
};
|
|
5591
5866
|
try {
|
|
5592
5867
|
const preparedArgs = tool.prepareArguments ? tool.prepareArguments(args) : args;
|
|
5593
5868
|
const telemetryArgs = isRecord(preparedArgs) ? preparedArgs : args;
|
|
@@ -5600,13 +5875,11 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5600
5875
|
replyToMode: params.hookContext?.replyToMode,
|
|
5601
5876
|
hasRepliedRef: params.hookContext?.hasRepliedRef ? { value: params.hookContext.hasRepliedRef.value } : void 0
|
|
5602
5877
|
};
|
|
5603
|
-
|
|
5878
|
+
didDispatchExecution = true;
|
|
5604
5879
|
const rawResult = await tool.execute(call.callId, preparedArgs, signal);
|
|
5605
|
-
|
|
5606
|
-
if (isRecord(adjustedExecutedArgs)) executedArgs = structuredClone(adjustedExecutedArgs);
|
|
5607
|
-
executionPrevented = consumePreExecutionBlockedToolCall(call.callId, toolResultHookContext.runId);
|
|
5880
|
+
captureExecutionBoundary();
|
|
5608
5881
|
const telemetryRawResult = sanitizeToolResult(rawResult);
|
|
5609
|
-
const rawIsError =
|
|
5882
|
+
const rawIsError = isToolResultError(rawResult);
|
|
5610
5883
|
const rawResultFailureKind = resolveToolResultFailureKind(rawResult);
|
|
5611
5884
|
const middlewareResult = await middlewareRunner.applyToolResultMiddleware({
|
|
5612
5885
|
threadId: call.threadId,
|
|
@@ -5625,7 +5898,7 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5625
5898
|
args: structuredClone(executedArgs),
|
|
5626
5899
|
result: middlewareResult
|
|
5627
5900
|
});
|
|
5628
|
-
const resultIsError = rawIsError ||
|
|
5901
|
+
const resultIsError = rawIsError || isToolResultError(result);
|
|
5629
5902
|
const finalResultFailureKind = resolveToolResultFailureKind(result);
|
|
5630
5903
|
const resultFailureKind = rawResultFailureKind ?? finalResultFailureKind;
|
|
5631
5904
|
const observerResult = rawResultFailureKind && finalResultFailureKind !== rawResultFailureKind ? {
|
|
@@ -5689,8 +5962,9 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5689
5962
|
}) && (replyReceiptMatchesCurrentMessage(rawResult, params.hookContext) || replyReceiptMatchesCurrentMessage(result, params.hookContext));
|
|
5690
5963
|
const toolConfirmedSourceReply = params.hookContext?.sourceReplyDeliveryMode === "message_tool_only" && toolName === "message" && !resultIsError && (rawResult.terminate === true || result.terminate === true);
|
|
5691
5964
|
const hasExplicitFinalControl = typeof executedArgs.final === "boolean";
|
|
5692
|
-
const
|
|
5693
|
-
|
|
5965
|
+
const confirmedSourceReply = params.hookContext?.sourceReplyDeliveryMode === "message_tool_only" && toolName === "message" && (toolConfirmedSourceReply || deliveredSourceReply || receiptConfirmedSourceReply);
|
|
5966
|
+
const sourceReplyFinal = confirmedSourceReply ? hasExplicitFinalControl ? executedArgs.final === true : void 0 : void 0;
|
|
5967
|
+
const sourceReplyRecord = collectToolTelemetry({
|
|
5694
5968
|
toolName,
|
|
5695
5969
|
args: executedArgs,
|
|
5696
5970
|
result,
|
|
@@ -5700,17 +5974,26 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5700
5974
|
messagingTarget: confirmedMessagingTarget,
|
|
5701
5975
|
sourceReplyFinal
|
|
5702
5976
|
});
|
|
5977
|
+
if (confirmedSourceReply && sourceReplyRecord) recordCodexSourceReplyDeliveryIntent(telemetry, {
|
|
5978
|
+
record: sourceReplyRecord,
|
|
5979
|
+
final: sourceReplyFinal
|
|
5980
|
+
});
|
|
5703
5981
|
if (deliveredSourceReply || receiptConfirmedSourceReply || toolConfirmedSourceReply) telemetry.didDeliverSourceReplyViaMessageTool = true;
|
|
5704
|
-
|
|
5982
|
+
const defersInferredSourceReplyTermination = confirmedSourceReply && executedArgs.final !== true;
|
|
5983
|
+
withDynamicToolTermination(response, (rawResult.terminate === true || result.terminate === true) && !defersInferredSourceReplyTermination || isToolResultYield(rawResult) || isToolResultYield(result) || confirmedSourceReply && executedArgs.final === true);
|
|
5705
5984
|
const asyncStarted = isAsyncStartedToolResult(rawResult) || isAsyncStartedToolResult(result);
|
|
5706
5985
|
withDynamicToolAsyncStarted(response, asyncStarted);
|
|
5707
|
-
|
|
5986
|
+
const replaySafe = executionPrevented || !asyncStarted && isReplaySafeToolInstance(toolEntry.tool) && isReplaySafeToolCall(toolName, executedArgs);
|
|
5987
|
+
return withDynamicToolExecutionState(response, {
|
|
5988
|
+
executedArguments: executedArgs,
|
|
5989
|
+
executionStarted: didStartExecution && !executionPrevented,
|
|
5990
|
+
sideEffectEvidence: !replaySafe
|
|
5991
|
+
});
|
|
5708
5992
|
} catch (error) {
|
|
5993
|
+
captureExecutionBoundary();
|
|
5709
5994
|
if (toolName === "computer" && params.computerContextEpoch?.frameToolCallId === call.callId) invalidateComputerFrame(params.computerContextEpoch);
|
|
5710
5995
|
const executionDisposition = getBeforeToolCallFailureDisposition(error) ?? (signal.aborted ? resolveCodexToolAbortTerminalReason(signal) : resolveToolExecutionErrorKind(error));
|
|
5711
5996
|
const errorMessage = formatToolExecutionErrorMessage(error, "OpenClaw dynamic tool call failed.");
|
|
5712
|
-
const adjustedExecutedArgs = consumeAdjustedParamsForToolCall(call.callId, toolResultHookContext.runId);
|
|
5713
|
-
if (isRecord(adjustedExecutedArgs)) executedArgs = structuredClone(adjustedExecutedArgs);
|
|
5714
5997
|
executionPrevented = executionPrevented || consumePreExecutionBlockedToolCall(call.callId, toolResultHookContext.runId);
|
|
5715
5998
|
const failedResult = failedToolResult(errorMessage, executionDisposition);
|
|
5716
5999
|
finalizeToolTerminalPresentation({
|
|
@@ -5743,13 +6026,20 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5743
6026
|
startedAt
|
|
5744
6027
|
});
|
|
5745
6028
|
const replaySafe = !didStartExecution || executionPrevented || isReplaySafeToolInstance(toolEntry.tool) && isReplaySafeToolCall(toolName, executedArgs);
|
|
5746
|
-
return
|
|
6029
|
+
return withDynamicToolExecutionState(withDiagnosticFailureDisposition({
|
|
5747
6030
|
contentItems: [{
|
|
5748
6031
|
type: "inputText",
|
|
5749
6032
|
text: errorMessage
|
|
5750
6033
|
}],
|
|
5751
6034
|
success: false
|
|
5752
|
-
}, executionDisposition),
|
|
6035
|
+
}, executionDisposition), {
|
|
6036
|
+
executedArguments: executedArgs,
|
|
6037
|
+
executionStarted: didStartExecution && !executionPrevented,
|
|
6038
|
+
sideEffectEvidence: didStartExecution && !replaySafe
|
|
6039
|
+
});
|
|
6040
|
+
} finally {
|
|
6041
|
+
if (executionSnapshotStates.get(call.callId) === executionSnapshotState && (executionSnapshotState.consumed || !executionSnapshotState.retainAfterCompletion)) executionSnapshotStates.delete(call.callId);
|
|
6042
|
+
consumeAdjustedParamsForToolCall(call.callId, toolResultHookContext.runId);
|
|
5753
6043
|
}
|
|
5754
6044
|
}
|
|
5755
6045
|
};
|
|
@@ -5877,7 +6167,12 @@ function projectCodexDynamicTools(tools) {
|
|
|
5877
6167
|
quarantinedTools.push(descriptor.diagnostic);
|
|
5878
6168
|
continue;
|
|
5879
6169
|
}
|
|
5880
|
-
const
|
|
6170
|
+
const normalizedParameters = normalizeOpenAIToolSchemas({
|
|
6171
|
+
provider: "openai",
|
|
6172
|
+
modelApi: "openai-chatgpt-responses",
|
|
6173
|
+
tools: [{ parameters: descriptor.parameters }]
|
|
6174
|
+
})[0]?.parameters;
|
|
6175
|
+
const projection = projectRuntimeToolInputSchema(normalizedParameters ?? descriptor.parameters, `${descriptor.name}.inputSchema`);
|
|
5881
6176
|
if (projection.violations.length > 0) {
|
|
5882
6177
|
quarantinedTools.push({
|
|
5883
6178
|
tool: descriptor.name,
|
|
@@ -6032,11 +6327,12 @@ function collectToolTelemetry(params) {
|
|
|
6032
6327
|
params.telemetry.didSendViaMessagingTool = true;
|
|
6033
6328
|
const sourceReplyPayload = extractInternalSourceReplyPayload(params.result?.details);
|
|
6034
6329
|
if (sourceReplyPayload) {
|
|
6035
|
-
|
|
6330
|
+
const record = {
|
|
6036
6331
|
...sourceReplyPayload,
|
|
6037
6332
|
...params.sourceReplyFinal !== void 0 ? { sourceReplyFinal: params.sourceReplyFinal } : {}
|
|
6038
|
-
}
|
|
6039
|
-
|
|
6333
|
+
};
|
|
6334
|
+
params.telemetry.messagingToolSourceReplyPayloads.push(record);
|
|
6335
|
+
return record;
|
|
6040
6336
|
}
|
|
6041
6337
|
const text = readFirstString(params.args, [
|
|
6042
6338
|
"text",
|
|
@@ -6047,7 +6343,7 @@ function collectToolTelemetry(params) {
|
|
|
6047
6343
|
if (text) params.telemetry.messagingToolSentTexts.push(text);
|
|
6048
6344
|
const mediaUrls = collectMediaUrls(params.args);
|
|
6049
6345
|
params.telemetry.messagingToolSentMediaUrls.push(...mediaUrls);
|
|
6050
|
-
|
|
6346
|
+
const record = {
|
|
6051
6347
|
...params.messagingTarget ?? {
|
|
6052
6348
|
tool: params.toolName,
|
|
6053
6349
|
provider: readFirstString(params.args, ["provider", "channel"]) ?? params.toolName,
|
|
@@ -6066,7 +6362,9 @@ function collectToolTelemetry(params) {
|
|
|
6066
6362
|
...text ? { text } : {},
|
|
6067
6363
|
...mediaUrls.length > 0 ? { mediaUrls } : {},
|
|
6068
6364
|
...params.sourceReplyFinal !== void 0 ? { sourceReplyFinal: params.sourceReplyFinal } : {}
|
|
6069
|
-
}
|
|
6365
|
+
};
|
|
6366
|
+
params.telemetry.messagingToolSentTargets.push(record);
|
|
6367
|
+
return record;
|
|
6070
6368
|
}
|
|
6071
6369
|
function extractInternalSourceReplyPayload(details) {
|
|
6072
6370
|
if (!isRecord(details) || details.sourceReplySink !== "internal-ui") return;
|
|
@@ -6087,17 +6385,6 @@ function extractInternalSourceReplyPayload(details) {
|
|
|
6087
6385
|
};
|
|
6088
6386
|
return text || mediaUrls.length > 0 || payload.presentation || payload.interactive ? payload : void 0;
|
|
6089
6387
|
}
|
|
6090
|
-
function isCodexToolResultError(result) {
|
|
6091
|
-
if (isToolResultError(result)) return true;
|
|
6092
|
-
const details = result.details;
|
|
6093
|
-
if (!isRecord(details)) return false;
|
|
6094
|
-
if (details.ok === true || details.success === true) return false;
|
|
6095
|
-
if (details.timedOut === true) return true;
|
|
6096
|
-
if (typeof details.exitCode === "number" && details.exitCode !== 0) return true;
|
|
6097
|
-
if (typeof details.status !== "string") return false;
|
|
6098
|
-
const status = details.status.trim().toLowerCase();
|
|
6099
|
-
return status !== "" && status !== "0" && status !== "ok" && status !== "success" && status !== "completed" && status !== "recorded" && status !== "created" && status !== "updated" && status !== "accepted" && status !== "found" && status !== "missing" && status !== "pending" && status !== "started" && status !== "running" && status !== "yielded";
|
|
6100
|
-
}
|
|
6101
6388
|
function isToolResultYield(result) {
|
|
6102
6389
|
const details = result.details;
|
|
6103
6390
|
if (!isRecord(details) || typeof details.status !== "string") return false;
|
|
@@ -6125,15 +6412,6 @@ function withDiagnosticFailureDisposition(response, disposition) {
|
|
|
6125
6412
|
});
|
|
6126
6413
|
return response;
|
|
6127
6414
|
}
|
|
6128
|
-
function withSideEffectEvidence(response, sideEffectEvidence) {
|
|
6129
|
-
if (!sideEffectEvidence) return response;
|
|
6130
|
-
Object.defineProperty(response, "sideEffectEvidence", {
|
|
6131
|
-
configurable: true,
|
|
6132
|
-
enumerable: false,
|
|
6133
|
-
value: true
|
|
6134
|
-
});
|
|
6135
|
-
return response;
|
|
6136
|
-
}
|
|
6137
6415
|
function withDynamicToolTermination(response, terminate) {
|
|
6138
6416
|
if (!terminate) return response;
|
|
6139
6417
|
Object.defineProperty(response, "terminate", {
|
|
@@ -6274,4 +6552,4 @@ function isCronAddAction(args) {
|
|
|
6274
6552
|
return typeof action === "string" && action.trim().toLowerCase() === "add";
|
|
6275
6553
|
}
|
|
6276
6554
|
//#endregion
|
|
6277
|
-
export {
|
|
6555
|
+
export { resolveCodexToolProgressDetailMode as $, CODEX_NATIVE_HOOK_RELAY_EVENTS as A, hasPendingDynamicToolTerminalDiagnostic as B, CodexAppServerEventProjector as C, markCodexAuthProfileBlockedFromRateLimits as D, isCodexUsageLimitPromptError as E, emitCodexNativePreToolUseFailureDiagnostic as F, shouldBlockTerminalReleaseForNonTerminalDynamicToolResult as G, isMatchingDynamicToolTerminalDiagnostic as H, resolveCodexNativeHookRelayEvents as I, toCodexDynamicToolProtocolResponse as J, shouldReleaseTurnAfterTerminalDynamicTool as K, resolveCodexNativeHookRelayTtlMs as L, buildCodexNativeHookRelayConfig as M, buildCodexNativeHookRelayDisabledConfig as N, refreshCodexUsageLimitPromptError as O, createCodexNativeHookRelay as P, inferCodexDynamicToolMeta as Q, scheduleCodexNativeHookRelayUnregister as R, filterToolsForVisionInputs as S, formatCodexTurnStartUsageLimitError as T, resolveDynamicToolCallTimeoutMs as U, isDynamicToolTerminalDiagnosticEvent as V, resolveTerminalDynamicToolBatchAction as W, readCodexMirroredSessionHistoryMessages as X, resolveCodexToolAbortTerminalReason as Y, shouldEmitTranscriptToolProgress as Z, resolveCodexMessageToolProvider as _, emitDynamicToolStartedDiagnostic as a, shouldRequireCodexSandboxExecServerEnvironment as b, resolveCodexProviderWebSearchSupportForClient as c, createCodexDynamicToolBuildStageTracker as d, sanitizeCodexToolArguments as et, disableCodexPluginThreadConfig as f, resolveCodexExternalSandboxPolicyForOpenClawSandbox as g, resolveCodexAppServerHookChannelId as h, emitDynamicToolErrorDiagnostic as i, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as j, CodexNativeToolLifecycleProjector as k, settleCodexSourceReplyFinality as l, resolveCodexAppServerExecutionCwd as m, handleCodexAppServerApprovalRequest as n, resolveCodexLocalRuntimeAttribution as nt, emitDynamicToolTerminalDiagnostic as o, formatCodexDynamicToolBuildStageSummary as p, toCodexDynamicToolProgressResponse as q, handleCodexAppServerElicitationRequest as r, resolveCodexProviderWebSearchSupport as s, createCodexDynamicToolBridge as t, sanitizeCodexToolResponse as tt, buildDynamicTools as u, resolveCodexSandboxEnvironmentSelection as v, createCodexUsageLimitPromptError as w, shouldWarnCodexDynamicToolBuildStageSummary as x, shouldEnableCodexAppServerNativeToolSurface as y, handleDynamicToolCallWithTimeout as z };
|