@openclaw/codex 2026.5.16-beta.4 → 2026.5.16-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{command-handlers-jZV_1Ks9.js → command-handlers-DcoFMn4e.js} +86 -32
- package/dist/harness.js +6 -3
- package/dist/index.js +2 -2
- package/dist/{node-cli-sessions-BKhlcAB9.js → node-cli-sessions-C9rlYMPw.js} +79 -31
- package/dist/{run-attempt-DMKAwtUV.js → run-attempt-D6sdcUE0.js} +425 -119
- package/dist/{side-question-BYYJZq23.js → side-question-BzVnOoBU.js} +103 -16
- package/dist/test-api.js +1 -1
- package/dist/{thread-lifecycle-wcyYqwrl.js → thread-lifecycle-Cc_ljZLZ.js} +243 -21
- package/dist/{vision-tools-Cm_YicZb.js → vision-tools-BX9YuTEK.js} +203 -7
- package/package.json +5 -5
|
@@ -4,17 +4,17 @@ import { t as isJsonObject } from "./protocol-C9UWI98H.js";
|
|
|
4
4
|
import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-6FkrXfaz.js";
|
|
5
5
|
import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-XPjLayGw.js";
|
|
6
6
|
import { d as resolveCodexUsageLimitResetAtMs, f as shouldRefreshCodexRateLimitsForUsageLimitMessage, r as formatCodexDisplayText, u as formatCodexUsageLimitErrorMessage } from "./command-formatters-BRW7_Nu7.js";
|
|
7
|
-
import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, l as resolveCodexAppServerAuthProfileId, s as refreshCodexAppServerAuthTokens, t as clearSharedCodexAppServerClientIfCurrent, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-DlvmoLBJ.js";
|
|
7
|
+
import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, f as resolveCodexAppServerHomeDir, l as resolveCodexAppServerAuthProfileId, s as refreshCodexAppServerAuthTokens, t as clearSharedCodexAppServerClientIfCurrent, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-DlvmoLBJ.js";
|
|
8
8
|
import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-DqApZIgD.js";
|
|
9
9
|
import { a as defaultCodexAppInventoryCache } from "./plugin-activation-B49xb7pI.js";
|
|
10
|
-
import { S as
|
|
10
|
+
import { C as isForcedPrivateQaCodexRuntime, S as filterCodexDynamicTools, T as resolveCodexDynamicToolsLoading, _ as projectContextEngineAssemblyForCodex, b as createCodexDynamicToolBridge, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as shouldBuildCodexPluginThreadConfig, h as mergeCodexThreadConfigs, i as buildDeveloperInstructions, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfigInputFingerprint, p as buildCodexPluginThreadConfig, r as buildContextEngineBinding, s as buildTurnStartParams, t as areCodexDynamicToolFingerprintsCompatible, v as resolveCodexContextEngineProjectionMaxChars, w as normalizeCodexDynamicToolName, x as sanitizeCodexHistoryImagePayloads, y as resolveCodexContextEngineProjectionReserveTokens } from "./thread-lifecycle-Cc_ljZLZ.js";
|
|
11
11
|
import { t as defaultCodexAppServerClientFactory } from "./client-factory-9L6Ie1dC.js";
|
|
12
|
-
import {
|
|
12
|
+
import { a as handleCodexAppServerElicitationRequest, i as buildCodexNativeHookRelayDisabledConfig, n as CODEX_NATIVE_HOOK_RELAY_EVENTS, o as handleCodexAppServerApprovalRequest, r as buildCodexNativeHookRelayConfig, t as filterToolsForVisionInputs } from "./vision-tools-BX9YuTEK.js";
|
|
13
13
|
import { t as ensureCodexComputerUse } from "./computer-use-UJ3dxrXF.js";
|
|
14
14
|
import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-dvhq-4pi.js";
|
|
15
15
|
import { createHash } from "node:crypto";
|
|
16
16
|
import nodeFs from "node:fs";
|
|
17
|
-
import { TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, bootstrapHarnessContextEngine, buildEmbeddedAttemptToolRunContext, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, finalizeHarnessContextEngineTurn, formatErrorMessage, formatToolAggregate, formatToolProgressOutput, hasBeforeToolCallPolicy, inferToolMetaFromArgs, isActiveHarnessContextEngine, isSubagentSessionKey, loadCodexBundleMcpThreadConfig, normalizeAgentRuntimeTools, normalizeUsage, registerNativeHookRelay, resolveAgentHarnessBeforePromptBuildResult, resolveAttemptSpawnWorkspaceDir, resolveBootstrapContextForRun, resolveContextEngineOwnerPluginId, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds,
|
|
17
|
+
import { TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, bootstrapHarnessContextEngine, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, finalizeHarnessContextEngineTurn, formatErrorMessage, formatToolAggregate, formatToolProgressOutput, hasBeforeToolCallPolicy, inferToolMetaFromArgs, isActiveHarnessContextEngine, isSubagentSessionKey, loadCodexBundleMcpThreadConfig, normalizeAgentRuntimeTools, normalizeUsage, registerNativeHookRelay, resolveAgentHarnessBeforePromptBuildResult, resolveAttemptSpawnWorkspaceDir, resolveBootstrapContextForRun, resolveContextEngineOwnerPluginId, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds, resolveSessionWriteLockOptions, resolveUserPath, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessAgentEndHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
18
18
|
import fs from "node:fs/promises";
|
|
19
19
|
import path from "node:path";
|
|
20
20
|
import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
|
|
@@ -324,7 +324,7 @@ async function readCodexMirroredSessionHistoryMessages(sessionFile) {
|
|
|
324
324
|
const firstEntry = entries[0];
|
|
325
325
|
if (firstEntry?.type !== "session" || typeof firstEntry.id !== "string") return;
|
|
326
326
|
migrateSessionEntries(entries);
|
|
327
|
-
return buildSessionContext(entries.filter((entry) => entry.type !== "session")).messages;
|
|
327
|
+
return sanitizeCodexHistoryImagePayloads(buildSessionContext(entries.filter((entry) => entry.type !== "session")).messages, "codex mirrored history");
|
|
328
328
|
} catch (error) {
|
|
329
329
|
if (isMissingFileError(error)) return [];
|
|
330
330
|
return;
|
|
@@ -446,7 +446,7 @@ async function mirrorCodexAppServerTranscript(params) {
|
|
|
446
446
|
if (messages.length === 0) return;
|
|
447
447
|
const lock = await acquireSessionWriteLock({
|
|
448
448
|
sessionFile: params.sessionFile,
|
|
449
|
-
|
|
449
|
+
...resolveSessionWriteLockOptions(params.config)
|
|
450
450
|
});
|
|
451
451
|
try {
|
|
452
452
|
const existingIdempotencyKeys = await readTranscriptIdempotencyKeys(params.sessionFile);
|
|
@@ -535,6 +535,19 @@ const CODEX_PROMPT_TOTAL_INPUT_KEYS = [
|
|
|
535
535
|
];
|
|
536
536
|
const MAX_TOOL_OUTPUT_DELTA_MESSAGES_PER_ITEM = 20;
|
|
537
537
|
const TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS = 12e3;
|
|
538
|
+
const TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES = new Set([
|
|
539
|
+
"message",
|
|
540
|
+
"messages",
|
|
541
|
+
"reply",
|
|
542
|
+
"send",
|
|
543
|
+
"reaction",
|
|
544
|
+
"react",
|
|
545
|
+
"typing"
|
|
546
|
+
]);
|
|
547
|
+
function shouldEmitTranscriptToolProgress(toolName, args) {
|
|
548
|
+
const normalized = typeof toolName === "string" ? toolName.trim().toLowerCase() : "";
|
|
549
|
+
return Boolean(normalized && !TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES.has(normalized) && !isActivityLogCommandProgress(normalized, args));
|
|
550
|
+
}
|
|
538
551
|
var CodexAppServerEventProjector = class {
|
|
539
552
|
constructor(params, threadId, turnId, options = {}) {
|
|
540
553
|
this.params = params;
|
|
@@ -554,11 +567,15 @@ var CodexAppServerEventProjector = class {
|
|
|
554
567
|
this.toolResultSummaryItemIds = /* @__PURE__ */ new Set();
|
|
555
568
|
this.toolResultOutputItemIds = /* @__PURE__ */ new Set();
|
|
556
569
|
this.toolResultOutputStreamedItemIds = /* @__PURE__ */ new Set();
|
|
570
|
+
this.transcriptToolProgressSuppressedIds = /* @__PURE__ */ new Set();
|
|
571
|
+
this.toolTranscriptArgumentsById = /* @__PURE__ */ new Map();
|
|
557
572
|
this.toolResultOutputDeltaState = /* @__PURE__ */ new Map();
|
|
573
|
+
this.toolResultOutputTextByItem = /* @__PURE__ */ new Map();
|
|
558
574
|
this.toolMetas = /* @__PURE__ */ new Map();
|
|
559
575
|
this.toolTranscriptMessages = [];
|
|
560
576
|
this.toolTranscriptCallIds = /* @__PURE__ */ new Set();
|
|
561
577
|
this.toolTranscriptResultIds = /* @__PURE__ */ new Set();
|
|
578
|
+
this.transcriptToolProgressCallIds = /* @__PURE__ */ new Set();
|
|
562
579
|
this.nativeGeneratedMediaUrls = /* @__PURE__ */ new Set();
|
|
563
580
|
this.diagnosticToolStartedAtByItem = /* @__PURE__ */ new Map();
|
|
564
581
|
this.afterToolCallObservedItemIds = /* @__PURE__ */ new Set();
|
|
@@ -990,6 +1007,7 @@ var CodexAppServerEventProjector = class {
|
|
|
990
1007
|
});
|
|
991
1008
|
}
|
|
992
1009
|
this.recordToolMeta(item);
|
|
1010
|
+
this.emitSnapshotOnlyNativeToolProgress(item);
|
|
993
1011
|
this.recordNativeToolTranscriptCall(item);
|
|
994
1012
|
this.recordNativeToolTranscriptResult(item);
|
|
995
1013
|
this.emitAfterToolCallObservation(item);
|
|
@@ -999,10 +1017,40 @@ var CodexAppServerEventProjector = class {
|
|
|
999
1017
|
this.activeCompactionItemIds.clear();
|
|
1000
1018
|
await this.maybeEndReasoning();
|
|
1001
1019
|
}
|
|
1020
|
+
emitSnapshotOnlyNativeToolProgress(item) {
|
|
1021
|
+
if (!shouldSynthesizeToolProgressForItem(item) || !this.isCurrentTurnSnapshotItem(item) || this.completedItemIds.has(item.id) || itemStatus(item) === "running") return;
|
|
1022
|
+
if (!this.activeItemIds.has(item.id)) {
|
|
1023
|
+
this.emitStandardItemEvent({
|
|
1024
|
+
phase: "start",
|
|
1025
|
+
item
|
|
1026
|
+
});
|
|
1027
|
+
this.emitNormalizedToolItemEvent({
|
|
1028
|
+
phase: "start",
|
|
1029
|
+
item
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
this.activeItemIds.delete(item.id);
|
|
1033
|
+
this.emitStandardItemEvent({
|
|
1034
|
+
phase: "end",
|
|
1035
|
+
item
|
|
1036
|
+
});
|
|
1037
|
+
this.emitNormalizedToolItemEvent({
|
|
1038
|
+
phase: "result",
|
|
1039
|
+
item
|
|
1040
|
+
});
|
|
1041
|
+
this.completedItemIds.add(item.id);
|
|
1042
|
+
}
|
|
1043
|
+
isCurrentTurnSnapshotItem(item) {
|
|
1044
|
+
const itemTurnId = readItemString(item, "turnId") ?? readItemString(item, "turn_id");
|
|
1045
|
+
return itemTurnId === void 0 || itemTurnId === this.turnId;
|
|
1046
|
+
}
|
|
1002
1047
|
handleOutputDelta(params, toolName) {
|
|
1003
1048
|
const itemId = readString$2(params, "itemId");
|
|
1004
1049
|
const delta = readString$2(params, "delta");
|
|
1005
|
-
if (!itemId || !delta
|
|
1050
|
+
if (!itemId || !delta) return;
|
|
1051
|
+
appendToolOutputDeltaText(this.toolResultOutputTextByItem, itemId, delta);
|
|
1052
|
+
if (!this.shouldEmitToolOutput()) return;
|
|
1053
|
+
if (this.transcriptToolProgressSuppressedIds.has(itemId) || !shouldEmitTranscriptToolProgress(toolName, this.toolTranscriptArgumentsById.get(itemId))) return;
|
|
1006
1054
|
const state = this.toolResultOutputDeltaState.get(itemId) ?? {
|
|
1007
1055
|
chars: 0,
|
|
1008
1056
|
messages: 0,
|
|
@@ -1125,15 +1173,26 @@ var CodexAppServerEventProjector = class {
|
|
|
1125
1173
|
if (!item || !shouldSynthesizeToolProgressForItem(item)) return;
|
|
1126
1174
|
const name = itemName(item);
|
|
1127
1175
|
if (!name) return;
|
|
1128
|
-
const meta = itemMeta(item, this.toolProgressDetailMode());
|
|
1129
|
-
const args = params.phase === "start" ? itemToolArgs(item) : void 0;
|
|
1130
1176
|
const status = params.phase === "result" ? itemStatus(item) : "running";
|
|
1177
|
+
const args = itemToolArgs(item);
|
|
1178
|
+
this.recordToolTrajectoryEvent({
|
|
1179
|
+
phase: params.phase,
|
|
1180
|
+
item,
|
|
1181
|
+
name,
|
|
1182
|
+
args,
|
|
1183
|
+
status
|
|
1184
|
+
});
|
|
1131
1185
|
this.emitDiagnosticToolExecutionEvent({
|
|
1132
1186
|
phase: params.phase,
|
|
1133
1187
|
item,
|
|
1134
1188
|
name,
|
|
1135
1189
|
status
|
|
1136
1190
|
});
|
|
1191
|
+
if (!shouldEmitTranscriptToolProgress(name, args)) {
|
|
1192
|
+
if (params.phase === "result") this.emitAfterToolCallObservation(item);
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
const meta = itemMeta(item, this.toolProgressDetailMode());
|
|
1137
1196
|
this.emitAgentEvent({
|
|
1138
1197
|
stream: "tool",
|
|
1139
1198
|
data: {
|
|
@@ -1142,7 +1201,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1142
1201
|
itemId: item.id,
|
|
1143
1202
|
toolCallId: item.id,
|
|
1144
1203
|
...meta ? { meta } : {},
|
|
1145
|
-
...args ? { args } : {},
|
|
1204
|
+
...params.phase === "start" && args ? { args } : {},
|
|
1146
1205
|
...params.phase === "result" ? {
|
|
1147
1206
|
status,
|
|
1148
1207
|
isError: isNonSuccessItemStatus(status),
|
|
@@ -1152,6 +1211,32 @@ var CodexAppServerEventProjector = class {
|
|
|
1152
1211
|
});
|
|
1153
1212
|
if (params.phase === "result") this.emitAfterToolCallObservation(item);
|
|
1154
1213
|
}
|
|
1214
|
+
recordToolTrajectoryEvent(params) {
|
|
1215
|
+
if (params.phase === "start") {
|
|
1216
|
+
this.options.trajectoryRecorder?.recordEvent("tool.call", {
|
|
1217
|
+
threadId: this.threadId,
|
|
1218
|
+
turnId: this.turnId,
|
|
1219
|
+
itemId: params.item.id,
|
|
1220
|
+
toolCallId: params.item.id,
|
|
1221
|
+
name: params.name,
|
|
1222
|
+
arguments: params.args
|
|
1223
|
+
});
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
const toolResult = itemToolResult(params.item).result;
|
|
1227
|
+
const output = itemOutputText(params.item, this.toolResultOutputTextByItem);
|
|
1228
|
+
this.options.trajectoryRecorder?.recordEvent("tool.result", {
|
|
1229
|
+
threadId: this.threadId,
|
|
1230
|
+
turnId: this.turnId,
|
|
1231
|
+
itemId: params.item.id,
|
|
1232
|
+
toolCallId: params.item.id,
|
|
1233
|
+
name: params.name,
|
|
1234
|
+
status: params.status,
|
|
1235
|
+
isError: isNonSuccessItemStatus(params.status),
|
|
1236
|
+
...toolResult ? { result: toolResult } : {},
|
|
1237
|
+
...output ? { output } : {}
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1155
1240
|
emitDiagnosticToolExecutionEvent(params) {
|
|
1156
1241
|
const base = {
|
|
1157
1242
|
runId: this.params.runId,
|
|
@@ -1196,7 +1281,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1196
1281
|
if (status === "running") return;
|
|
1197
1282
|
this.afterToolCallObservedItemIds.add(item.id);
|
|
1198
1283
|
const result = itemToolResult(item).result;
|
|
1199
|
-
const error = itemToolError(item, status);
|
|
1284
|
+
const error = itemToolError(item, status, this.toolResultOutputTextByItem);
|
|
1200
1285
|
const startedAt = typeof item.durationMs === "number" ? Date.now() - Math.max(0, item.durationMs) : void 0;
|
|
1201
1286
|
const hookParams = {
|
|
1202
1287
|
toolName: name,
|
|
@@ -1225,6 +1310,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1225
1310
|
if (this.toolResultSummaryItemIds.has(itemId)) return;
|
|
1226
1311
|
const toolName = itemName(item);
|
|
1227
1312
|
if (!toolName) return;
|
|
1313
|
+
if (!shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
|
|
1228
1314
|
this.toolResultSummaryItemIds.add(itemId);
|
|
1229
1315
|
const meta = itemMeta(item, this.toolProgressDetailMode());
|
|
1230
1316
|
this.emitToolResultMessage({
|
|
@@ -1238,8 +1324,9 @@ var CodexAppServerEventProjector = class {
|
|
|
1238
1324
|
if (this.toolResultOutputItemIds.has(itemId)) return;
|
|
1239
1325
|
if (this.toolResultOutputStreamedItemIds.has(itemId)) return;
|
|
1240
1326
|
const toolName = itemName(item);
|
|
1241
|
-
const output = itemOutputText(item);
|
|
1327
|
+
const output = itemOutputText(item, this.toolResultOutputTextByItem);
|
|
1242
1328
|
if (!toolName || !output) return;
|
|
1329
|
+
if (!shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
|
|
1243
1330
|
this.emitToolResultMessage({
|
|
1244
1331
|
itemId,
|
|
1245
1332
|
text: formatToolOutput(toolName, itemMeta(item, this.toolProgressDetailMode()), output),
|
|
@@ -1291,20 +1378,53 @@ var CodexAppServerEventProjector = class {
|
|
|
1291
1378
|
this.recordToolTranscriptResult({
|
|
1292
1379
|
id: item.id,
|
|
1293
1380
|
name,
|
|
1294
|
-
text: itemTranscriptResultText(item),
|
|
1381
|
+
text: itemTranscriptResultText(item, this.toolResultOutputTextByItem),
|
|
1295
1382
|
isError: isNonSuccessItemStatus(itemStatus(item))
|
|
1296
1383
|
});
|
|
1297
1384
|
}
|
|
1298
1385
|
recordToolTranscriptCall(params) {
|
|
1299
1386
|
if (!params.id || !params.name || this.toolTranscriptCallIds.has(params.id)) return;
|
|
1300
1387
|
this.toolTranscriptCallIds.add(params.id);
|
|
1388
|
+
this.toolTranscriptArgumentsById.set(params.id, params.arguments);
|
|
1389
|
+
if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) this.transcriptToolProgressSuppressedIds.add(params.id);
|
|
1390
|
+
else this.transcriptToolProgressSuppressedIds.delete(params.id);
|
|
1391
|
+
this.emitTranscriptToolCallProgress(params);
|
|
1301
1392
|
this.toolTranscriptMessages.push(attachCodexMirrorIdentity(this.createToolCallMessage(params), `${this.turnId}:tool:${params.id}:call`));
|
|
1302
1393
|
}
|
|
1303
1394
|
recordToolTranscriptResult(params) {
|
|
1304
1395
|
if (!params.id || !params.name || this.toolTranscriptResultIds.has(params.id)) return;
|
|
1305
1396
|
this.toolTranscriptResultIds.add(params.id);
|
|
1397
|
+
this.emitTranscriptToolResultProgress(params);
|
|
1306
1398
|
this.toolTranscriptMessages.push(attachCodexMirrorIdentity(this.createToolResultMessage(params), `${this.turnId}:tool:${params.id}:result`));
|
|
1307
1399
|
}
|
|
1400
|
+
emitTranscriptToolCallProgress(params) {
|
|
1401
|
+
if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) return;
|
|
1402
|
+
this.transcriptToolProgressCallIds.add(params.id);
|
|
1403
|
+
const args = normalizeToolTranscriptArguments(params.arguments);
|
|
1404
|
+
const meta = inferToolMetaFromArgs(params.name, args, { detailMode: this.toolProgressDetailMode() });
|
|
1405
|
+
if (!this.params.onToolResult || !this.shouldEmitToolResult() || this.toolResultSummaryItemIds.has(params.id) || this.toolResultOutputStreamedItemIds.has(params.id)) return;
|
|
1406
|
+
this.toolResultSummaryItemIds.add(params.id);
|
|
1407
|
+
this.emitToolResultMessage({
|
|
1408
|
+
itemId: params.id,
|
|
1409
|
+
text: formatToolSummary(params.name, meta)
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
emitTranscriptToolResultProgress(params) {
|
|
1413
|
+
if (this.transcriptToolProgressSuppressedIds.has(params.id) || !shouldEmitTranscriptToolProgress(params.name, this.toolTranscriptArgumentsById.get(params.id))) return;
|
|
1414
|
+
if (!this.transcriptToolProgressCallIds.has(params.id)) this.emitTranscriptToolCallProgress({
|
|
1415
|
+
id: params.id,
|
|
1416
|
+
name: params.name,
|
|
1417
|
+
arguments: {}
|
|
1418
|
+
});
|
|
1419
|
+
if (!this.params.onToolResult || !this.shouldEmitToolOutput() || this.toolResultOutputItemIds.has(params.id) || this.toolResultOutputStreamedItemIds.has(params.id)) return;
|
|
1420
|
+
const text = params.text?.trim();
|
|
1421
|
+
if (!text) return;
|
|
1422
|
+
this.emitToolResultMessage({
|
|
1423
|
+
itemId: params.id,
|
|
1424
|
+
text: formatToolOutput(params.name, void 0, text),
|
|
1425
|
+
finalOutput: true
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1308
1428
|
formatCodexErrorMessage(params) {
|
|
1309
1429
|
const error = isJsonObject(params.error) ? params.error : void 0;
|
|
1310
1430
|
return formatCodexUsageLimitErrorMessage({
|
|
@@ -1654,10 +1774,10 @@ function itemFileChanges(item) {
|
|
|
1654
1774
|
kind: change.kind
|
|
1655
1775
|
})) : [];
|
|
1656
1776
|
}
|
|
1657
|
-
function itemToolError(item, status) {
|
|
1777
|
+
function itemToolError(item, status, outputTextByItem) {
|
|
1658
1778
|
if (status === "blocked") return "codex native tool blocked";
|
|
1659
1779
|
if (status !== "failed") return;
|
|
1660
|
-
return itemOutputText(item) ?? "codex native tool failed";
|
|
1780
|
+
return itemOutputText(item, outputTextByItem) ?? "codex native tool failed";
|
|
1661
1781
|
}
|
|
1662
1782
|
function itemMeta(item, detailMode = "explain") {
|
|
1663
1783
|
if (item.type === "commandExecution" && typeof item.command === "string") return inferToolMetaFromArgs("exec", {
|
|
@@ -1668,24 +1788,50 @@ function itemMeta(item, detailMode = "explain") {
|
|
|
1668
1788
|
const toolName = itemName(item);
|
|
1669
1789
|
if ((item.type === "dynamicToolCall" || item.type === "mcpToolCall") && toolName) return inferToolMetaFromArgs(toolName, item.arguments, { detailMode });
|
|
1670
1790
|
}
|
|
1671
|
-
function itemOutputText(item) {
|
|
1672
|
-
if (item.type === "commandExecution") return item.aggregatedOutput?.trim() || void 0;
|
|
1791
|
+
function itemOutputText(item, outputTextByItem) {
|
|
1792
|
+
if (item.type === "commandExecution") return item.aggregatedOutput?.trim() || outputTextByItem?.get(item.id)?.trim() || void 0;
|
|
1673
1793
|
if (item.type === "dynamicToolCall") return collectDynamicToolContentText(item.contentItems).trim() || void 0;
|
|
1674
1794
|
if (item.type === "mcpToolCall") {
|
|
1675
1795
|
if (item.error) return stringifyJsonValue(item.error);
|
|
1676
1796
|
return item.result ? stringifyJsonValue(item.result) : void 0;
|
|
1677
1797
|
}
|
|
1678
1798
|
}
|
|
1679
|
-
function itemTranscriptResultText(item) {
|
|
1680
|
-
const output = itemOutputText(item);
|
|
1799
|
+
function itemTranscriptResultText(item, outputTextByItem) {
|
|
1800
|
+
const output = itemOutputText(item, outputTextByItem);
|
|
1681
1801
|
if (output) return output;
|
|
1682
1802
|
const result = itemToolResult(item).result;
|
|
1683
1803
|
return result ? stringifyJsonValue(result) : itemStatus(item);
|
|
1684
1804
|
}
|
|
1805
|
+
function appendToolOutputDeltaText(outputTextByItem, itemId, delta) {
|
|
1806
|
+
const current = outputTextByItem.get(itemId) ?? "";
|
|
1807
|
+
if (current.length >= TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS) return;
|
|
1808
|
+
const remaining = TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS - current.length;
|
|
1809
|
+
const next = current + (delta.length > remaining ? delta.slice(0, remaining) : delta);
|
|
1810
|
+
outputTextByItem.set(itemId, next);
|
|
1811
|
+
}
|
|
1685
1812
|
function normalizeToolTranscriptArguments(value) {
|
|
1686
1813
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
1687
1814
|
return value;
|
|
1688
1815
|
}
|
|
1816
|
+
function isActivityLogCommandProgress(toolName, args) {
|
|
1817
|
+
if (toolName !== "bash" && toolName !== "exec" && toolName !== "shell") return false;
|
|
1818
|
+
const command = readToolCommandText(args);
|
|
1819
|
+
return Boolean(command && command.includes("log_activity.sh"));
|
|
1820
|
+
}
|
|
1821
|
+
function readToolCommandText(value) {
|
|
1822
|
+
if (typeof value === "string") return value;
|
|
1823
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
1824
|
+
const record = value;
|
|
1825
|
+
for (const key of [
|
|
1826
|
+
"command",
|
|
1827
|
+
"cmd",
|
|
1828
|
+
"shellCommand",
|
|
1829
|
+
"script"
|
|
1830
|
+
]) {
|
|
1831
|
+
const text = record[key];
|
|
1832
|
+
if (typeof text === "string" && text) return text;
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1689
1835
|
function collectDynamicToolContentText(contentItems) {
|
|
1690
1836
|
if (!Array.isArray(contentItems)) return "";
|
|
1691
1837
|
return contentItems.flatMap((entry) => {
|
|
@@ -1749,88 +1895,6 @@ function readTurn(value) {
|
|
|
1749
1895
|
return readCodexTurn(value);
|
|
1750
1896
|
}
|
|
1751
1897
|
//#endregion
|
|
1752
|
-
//#region extensions/codex/src/app-server/native-hook-relay.ts
|
|
1753
|
-
const CODEX_NATIVE_HOOK_RELAY_EVENTS = [
|
|
1754
|
-
"pre_tool_use",
|
|
1755
|
-
"post_tool_use",
|
|
1756
|
-
"permission_request",
|
|
1757
|
-
"before_agent_finalize"
|
|
1758
|
-
];
|
|
1759
|
-
const CODEX_HOOK_EVENT_BY_NATIVE_EVENT = {
|
|
1760
|
-
pre_tool_use: "PreToolUse",
|
|
1761
|
-
post_tool_use: "PostToolUse",
|
|
1762
|
-
permission_request: "PermissionRequest",
|
|
1763
|
-
before_agent_finalize: "Stop"
|
|
1764
|
-
};
|
|
1765
|
-
const CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT = {
|
|
1766
|
-
pre_tool_use: "pre_tool_use",
|
|
1767
|
-
post_tool_use: "post_tool_use",
|
|
1768
|
-
permission_request: "permission_request",
|
|
1769
|
-
before_agent_finalize: "stop"
|
|
1770
|
-
};
|
|
1771
|
-
const CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS = ["/<session-flags>/config.toml", "<session-flags>/config.toml"];
|
|
1772
|
-
function buildCodexNativeHookRelayConfig(params) {
|
|
1773
|
-
const events = params.events?.length ? params.events : CODEX_NATIVE_HOOK_RELAY_EVENTS;
|
|
1774
|
-
const config = { "features.hooks": true };
|
|
1775
|
-
const hookState = {};
|
|
1776
|
-
for (const event of events) {
|
|
1777
|
-
const codexEvent = CODEX_HOOK_EVENT_BY_NATIVE_EVENT[event];
|
|
1778
|
-
const command = params.relay.commandForEvent(event);
|
|
1779
|
-
const timeout = normalizeHookTimeoutSec(params.hookTimeoutSec);
|
|
1780
|
-
config[`hooks.${codexEvent}`] = [{ hooks: [{
|
|
1781
|
-
type: "command",
|
|
1782
|
-
command,
|
|
1783
|
-
timeout,
|
|
1784
|
-
async: false,
|
|
1785
|
-
statusMessage: "OpenClaw native hook relay"
|
|
1786
|
-
}] }];
|
|
1787
|
-
const state = {
|
|
1788
|
-
enabled: true,
|
|
1789
|
-
trusted_hash: codexCommandHookTrustedHash({
|
|
1790
|
-
event,
|
|
1791
|
-
command,
|
|
1792
|
-
timeout,
|
|
1793
|
-
statusMessage: "OpenClaw native hook relay"
|
|
1794
|
-
})
|
|
1795
|
-
};
|
|
1796
|
-
for (const sourcePath of CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS) hookState[`${sourcePath}:${CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[event]}:0:0`] = state;
|
|
1797
|
-
}
|
|
1798
|
-
config["hooks.state"] = hookState;
|
|
1799
|
-
return config;
|
|
1800
|
-
}
|
|
1801
|
-
function buildCodexNativeHookRelayDisabledConfig() {
|
|
1802
|
-
return {
|
|
1803
|
-
"features.hooks": false,
|
|
1804
|
-
"hooks.PreToolUse": [],
|
|
1805
|
-
"hooks.PostToolUse": [],
|
|
1806
|
-
"hooks.PermissionRequest": [],
|
|
1807
|
-
"hooks.Stop": []
|
|
1808
|
-
};
|
|
1809
|
-
}
|
|
1810
|
-
function normalizeHookTimeoutSec(value) {
|
|
1811
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.ceil(value) : 5;
|
|
1812
|
-
}
|
|
1813
|
-
function codexCommandHookTrustedHash(params) {
|
|
1814
|
-
const identity = {
|
|
1815
|
-
event_name: CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[params.event],
|
|
1816
|
-
hooks: [{
|
|
1817
|
-
async: false,
|
|
1818
|
-
command: params.command,
|
|
1819
|
-
statusMessage: params.statusMessage,
|
|
1820
|
-
timeout: params.timeout,
|
|
1821
|
-
type: "command"
|
|
1822
|
-
}]
|
|
1823
|
-
};
|
|
1824
|
-
return `sha256:${createHash("sha256").update(JSON.stringify(sortJsonValue(identity))).digest("hex")}`;
|
|
1825
|
-
}
|
|
1826
|
-
function sortJsonValue(value) {
|
|
1827
|
-
if (!value || typeof value !== "object") return value;
|
|
1828
|
-
if (Array.isArray(value)) return value.map(sortJsonValue);
|
|
1829
|
-
const sorted = {};
|
|
1830
|
-
for (const key of Object.keys(value).toSorted()) sorted[key] = sortJsonValue(value[key]);
|
|
1831
|
-
return sorted;
|
|
1832
|
-
}
|
|
1833
|
-
//#endregion
|
|
1834
1898
|
//#region extensions/codex/src/app-server/trajectory.ts
|
|
1835
1899
|
const SENSITIVE_FIELD_RE = /(?:authorization|cookie|credential|key|password|passwd|secret|token)/iu;
|
|
1836
1900
|
const PRIVATE_PAYLOAD_FIELD_RE = /(?:image|screenshot|attachment|fileData|dataUri)/iu;
|
|
@@ -2401,6 +2465,169 @@ function isCodexAppServerPolicyMode(value) {
|
|
|
2401
2465
|
function isCodexAppServerApprovalPolicy(value) {
|
|
2402
2466
|
return value === "never" || value === "on-request" || value === "on-failure" || value === "untrusted";
|
|
2403
2467
|
}
|
|
2468
|
+
const CODEX_APP_SERVER_NATIVE_THREAD_MAX_TOKENS = 7e4;
|
|
2469
|
+
const CODEX_APP_SERVER_BYTE_UNITS = {
|
|
2470
|
+
b: 1,
|
|
2471
|
+
k: 1024,
|
|
2472
|
+
kb: 1024,
|
|
2473
|
+
kib: 1024,
|
|
2474
|
+
m: 1024 * 1024,
|
|
2475
|
+
mb: 1024 * 1024,
|
|
2476
|
+
mib: 1024 * 1024,
|
|
2477
|
+
g: 1024 * 1024 * 1024,
|
|
2478
|
+
gb: 1024 * 1024 * 1024,
|
|
2479
|
+
gib: 1024 * 1024 * 1024,
|
|
2480
|
+
t: 1024 * 1024 * 1024 * 1024,
|
|
2481
|
+
tb: 1024 * 1024 * 1024 * 1024,
|
|
2482
|
+
tib: 1024 * 1024 * 1024 * 1024
|
|
2483
|
+
};
|
|
2484
|
+
function parseCodexAppServerByteLimit(value) {
|
|
2485
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.floor(value);
|
|
2486
|
+
if (typeof value !== "string") return;
|
|
2487
|
+
const match = value.trim().match(/^(\d+(?:\.\d+)?)\s*([a-z]+)?$/i);
|
|
2488
|
+
if (!match) return;
|
|
2489
|
+
const amount = Number(match[1]);
|
|
2490
|
+
if (!Number.isFinite(amount) || amount <= 0) return;
|
|
2491
|
+
const multiplier = CODEX_APP_SERVER_BYTE_UNITS[(match[2] ?? "b").toLowerCase()];
|
|
2492
|
+
if (multiplier === void 0) return;
|
|
2493
|
+
return Math.max(1, Math.round(amount * multiplier));
|
|
2494
|
+
}
|
|
2495
|
+
async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codexHome) {
|
|
2496
|
+
const resolvedAgentDir = path.resolve(agentDir);
|
|
2497
|
+
const resolvedCodexHome = codexHome?.trim() ? path.resolve(codexHome) : resolveCodexAppServerHomeDir(resolvedAgentDir);
|
|
2498
|
+
const roots = [
|
|
2499
|
+
path.join(resolvedCodexHome, "sessions"),
|
|
2500
|
+
path.join(resolveCodexAppServerHomeDir(resolvedAgentDir), "sessions"),
|
|
2501
|
+
path.join(resolvedAgentDir, "agent", "codex-home", "sessions"),
|
|
2502
|
+
path.join(path.dirname(resolvedAgentDir), "codex-home", "sessions")
|
|
2503
|
+
];
|
|
2504
|
+
const files = [];
|
|
2505
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2506
|
+
for (const root of roots) {
|
|
2507
|
+
if (visited.has(root)) continue;
|
|
2508
|
+
visited.add(root);
|
|
2509
|
+
const stack = [root];
|
|
2510
|
+
while (stack.length > 0) {
|
|
2511
|
+
const dir = stack.pop();
|
|
2512
|
+
if (!dir) continue;
|
|
2513
|
+
let entries;
|
|
2514
|
+
try {
|
|
2515
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
2516
|
+
} catch {
|
|
2517
|
+
continue;
|
|
2518
|
+
}
|
|
2519
|
+
for (const entry of entries) {
|
|
2520
|
+
const file = path.join(dir, entry.name);
|
|
2521
|
+
if (entry.isDirectory()) {
|
|
2522
|
+
stack.push(file);
|
|
2523
|
+
continue;
|
|
2524
|
+
}
|
|
2525
|
+
if (!entry.isFile() || !entry.name.endsWith(".jsonl") || !entry.name.includes(threadId)) continue;
|
|
2526
|
+
try {
|
|
2527
|
+
files.push({
|
|
2528
|
+
path: file,
|
|
2529
|
+
bytes: (await fs.stat(file)).size
|
|
2530
|
+
});
|
|
2531
|
+
} catch {}
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
return files;
|
|
2536
|
+
}
|
|
2537
|
+
async function readCodexSessionRecordForSessionFile(sessionFile) {
|
|
2538
|
+
const sessionsFile = path.join(path.dirname(sessionFile), "sessions.json");
|
|
2539
|
+
let store;
|
|
2540
|
+
try {
|
|
2541
|
+
store = JSON.parse(await fs.readFile(sessionsFile, "utf8"));
|
|
2542
|
+
} catch {
|
|
2543
|
+
return;
|
|
2544
|
+
}
|
|
2545
|
+
if (!isJsonObject(store)) return;
|
|
2546
|
+
const resolvedSessionFile = path.resolve(sessionFile);
|
|
2547
|
+
for (const [sessionKey, record] of Object.entries(store)) {
|
|
2548
|
+
if (!isJsonObject(record) || typeof record.sessionFile !== "string") continue;
|
|
2549
|
+
if (path.resolve(record.sessionFile) !== resolvedSessionFile) continue;
|
|
2550
|
+
return {
|
|
2551
|
+
sessionKey,
|
|
2552
|
+
...record
|
|
2553
|
+
};
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
async function readCodexAppServerRolloutTokenUsage(file) {
|
|
2557
|
+
let handle;
|
|
2558
|
+
try {
|
|
2559
|
+
handle = await fs.open(file, "r");
|
|
2560
|
+
} catch {
|
|
2561
|
+
return;
|
|
2562
|
+
}
|
|
2563
|
+
let totalTokens;
|
|
2564
|
+
try {
|
|
2565
|
+
for await (const line of handle.readLines()) {
|
|
2566
|
+
const lineTokens = readCodexAppServerRolloutTokenUsageLine(line);
|
|
2567
|
+
if (lineTokens !== void 0) totalTokens = lineTokens;
|
|
2568
|
+
}
|
|
2569
|
+
} finally {
|
|
2570
|
+
await handle.close();
|
|
2571
|
+
}
|
|
2572
|
+
return totalTokens;
|
|
2573
|
+
}
|
|
2574
|
+
function readCodexAppServerRolloutTokenUsageLine(line) {
|
|
2575
|
+
if (!line.trim()) return;
|
|
2576
|
+
try {
|
|
2577
|
+
const parsed = JSON.parse(line);
|
|
2578
|
+
const payload = isJsonObject(parsed) ? parsed.payload : void 0;
|
|
2579
|
+
const info = isJsonObject(payload) && payload.type === "token_count" && isJsonObject(payload.info) ? payload.info : void 0;
|
|
2580
|
+
if (!info) return;
|
|
2581
|
+
const usage = isJsonObject(info.last_token_usage) ? info.last_token_usage : isJsonObject(info.total_token_usage) ? info.total_token_usage : void 0;
|
|
2582
|
+
const value = usage?.total_tokens ?? usage?.totalTokens;
|
|
2583
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
2584
|
+
} catch {
|
|
2585
|
+
return;
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
function maxFiniteNumber(values) {
|
|
2589
|
+
const nums = values.filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
2590
|
+
if (nums.length === 0) return;
|
|
2591
|
+
return Math.max(...nums);
|
|
2592
|
+
}
|
|
2593
|
+
async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
2594
|
+
const binding = params.binding;
|
|
2595
|
+
if (!binding?.threadId) return binding;
|
|
2596
|
+
if (params.config?.agents?.defaults?.compaction?.truncateAfterCompaction !== true) return binding;
|
|
2597
|
+
const sessionRecord = await readCodexSessionRecordForSessionFile(params.sessionFile);
|
|
2598
|
+
const maxBytes = parseCodexAppServerByteLimit(params.config?.agents?.defaults?.compaction?.maxActiveTranscriptBytes);
|
|
2599
|
+
const rolloutFiles = await listCodexAppServerRolloutFilesForThread(params.agentDir, binding.threadId, params.codexHome);
|
|
2600
|
+
if (maxBytes !== void 0) {
|
|
2601
|
+
const oversizedFiles = rolloutFiles.filter((file) => file.bytes >= maxBytes);
|
|
2602
|
+
if (oversizedFiles.length > 0) {
|
|
2603
|
+
embeddedAgentLog.warn("codex app-server native transcript exceeded active byte limit; starting a fresh thread", {
|
|
2604
|
+
threadId: binding.threadId,
|
|
2605
|
+
maxBytes,
|
|
2606
|
+
files: oversizedFiles.map((file) => ({
|
|
2607
|
+
path: file.path,
|
|
2608
|
+
bytes: file.bytes
|
|
2609
|
+
}))
|
|
2610
|
+
});
|
|
2611
|
+
await clearCodexAppServerBinding(params.sessionFile);
|
|
2612
|
+
return;
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
const nativeTokens = maxFiniteNumber(await Promise.all(rolloutFiles.map(async (file) => readCodexAppServerRolloutTokenUsage(file.path))));
|
|
2616
|
+
const sessionTokens = sessionRecord?.totalTokensFresh !== false && typeof sessionRecord?.totalTokens === "number" && Number.isFinite(sessionRecord.totalTokens) ? sessionRecord.totalTokens : void 0;
|
|
2617
|
+
const tokenCount = maxFiniteNumber([sessionTokens, nativeTokens]);
|
|
2618
|
+
if (tokenCount !== void 0 && tokenCount >= CODEX_APP_SERVER_NATIVE_THREAD_MAX_TOKENS) {
|
|
2619
|
+
embeddedAgentLog.warn("codex app-server native transcript exceeded active token limit; starting a fresh thread", {
|
|
2620
|
+
threadId: binding.threadId,
|
|
2621
|
+
maxTokens: CODEX_APP_SERVER_NATIVE_THREAD_MAX_TOKENS,
|
|
2622
|
+
sessionKey: sessionRecord?.sessionKey,
|
|
2623
|
+
sessionTokens,
|
|
2624
|
+
nativeTokens
|
|
2625
|
+
});
|
|
2626
|
+
await clearCodexAppServerBinding(params.sessionFile);
|
|
2627
|
+
return;
|
|
2628
|
+
}
|
|
2629
|
+
return binding;
|
|
2630
|
+
}
|
|
2404
2631
|
async function runCodexAppServerAttempt(params, options = {}) {
|
|
2405
2632
|
const attemptStartedAt = Date.now();
|
|
2406
2633
|
const attemptClientFactory = options.clientFactory ?? defaultCodexAppServerClientFactory;
|
|
@@ -2440,8 +2667,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2440
2667
|
agentId: params.agentId
|
|
2441
2668
|
});
|
|
2442
2669
|
const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId);
|
|
2443
|
-
|
|
2444
|
-
const
|
|
2670
|
+
let startupBinding = await readCodexAppServerBinding(params.sessionFile);
|
|
2671
|
+
const startupBindingAuthProfileId = startupBinding?.authProfileId;
|
|
2672
|
+
startupBinding = await rotateOversizedCodexAppServerStartupBinding({
|
|
2673
|
+
binding: startupBinding,
|
|
2674
|
+
sessionFile: params.sessionFile,
|
|
2675
|
+
agentDir,
|
|
2676
|
+
codexHome: appServer.start.env?.CODEX_HOME,
|
|
2677
|
+
config: params.config
|
|
2678
|
+
});
|
|
2679
|
+
const startupAuthProfileCandidate = params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId ?? startupBindingAuthProfileId;
|
|
2445
2680
|
const startupAuthProfileId = params.authProfileStore ? resolveCodexAppServerAuthProfileId({
|
|
2446
2681
|
authProfileId: startupAuthProfileCandidate,
|
|
2447
2682
|
store: params.authProfileStore,
|
|
@@ -2481,8 +2716,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2481
2716
|
disableTools: params.disableTools,
|
|
2482
2717
|
toolsAllow: params.toolsAllow
|
|
2483
2718
|
});
|
|
2719
|
+
const nativeToolSurfaceEnabled = shouldEnableCodexAppServerNativeToolSurface(params);
|
|
2484
2720
|
for (const diagnostic of bundleMcpThreadConfig.diagnostics) embeddedAgentLog.warn(`bundle-mcp: ${diagnostic.pluginId}: ${diagnostic.message}`);
|
|
2485
2721
|
const activeContextEngine = isActiveHarnessContextEngine(params.contextEngine) ? params.contextEngine : void 0;
|
|
2722
|
+
const hookChannelId = resolveCodexAppServerHookChannelId(params, sandboxSessionKey);
|
|
2486
2723
|
let yieldDetected = false;
|
|
2487
2724
|
const toolBridge = createCodexDynamicToolBridge({
|
|
2488
2725
|
tools: await buildDynamicTools({
|
|
@@ -2499,14 +2736,15 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2499
2736
|
}
|
|
2500
2737
|
}),
|
|
2501
2738
|
signal: runAbortController.signal,
|
|
2502
|
-
loading: pluginConfig
|
|
2739
|
+
loading: resolveCodexDynamicToolsLoading(pluginConfig),
|
|
2503
2740
|
directToolNames: shouldForceMessageTool(params) ? ["message"] : [],
|
|
2504
2741
|
hookContext: {
|
|
2505
2742
|
agentId: sessionAgentId,
|
|
2506
2743
|
config: params.config,
|
|
2507
2744
|
sessionId: params.sessionId,
|
|
2508
2745
|
sessionKey: sandboxSessionKey,
|
|
2509
|
-
runId: params.runId
|
|
2746
|
+
runId: params.runId,
|
|
2747
|
+
channelId: hookChannelId
|
|
2510
2748
|
}
|
|
2511
2749
|
});
|
|
2512
2750
|
const hadSessionFile = await pathExists(activeSessionFile);
|
|
@@ -2524,7 +2762,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2524
2762
|
workspaceDir: params.workspaceDir,
|
|
2525
2763
|
messageProvider: params.messageProvider ?? void 0,
|
|
2526
2764
|
trigger: params.trigger,
|
|
2527
|
-
channelId:
|
|
2765
|
+
channelId: hookChannelId,
|
|
2528
2766
|
...hookContextWindowFields
|
|
2529
2767
|
};
|
|
2530
2768
|
const activeContextEnginePluginId = activeContextEngine ? resolveContextEngineOwnerPluginId(activeContextEngine) : void 0;
|
|
@@ -2688,6 +2926,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2688
2926
|
sessionKey: sandboxSessionKey,
|
|
2689
2927
|
config: params.config,
|
|
2690
2928
|
runId: params.runId,
|
|
2929
|
+
channelId: hookChannelId,
|
|
2691
2930
|
attemptTimeoutMs: params.timeoutMs,
|
|
2692
2931
|
startupTimeoutMs,
|
|
2693
2932
|
turnStartTimeoutMs: params.timeoutMs,
|
|
@@ -2699,7 +2938,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2699
2938
|
hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec
|
|
2700
2939
|
}) : options.nativeHookRelay?.enabled === false ? buildCodexNativeHookRelayDisabledConfig() : void 0;
|
|
2701
2940
|
const threadConfig = mergeCodexThreadConfigs(bundleMcpThreadConfig?.configPatch);
|
|
2702
|
-
const
|
|
2941
|
+
const pluginThreadConfigRequired = !nativeToolSurfaceEnabled || shouldBuildCodexPluginThreadConfig(pluginConfig);
|
|
2942
|
+
const pluginThreadConfigPluginConfig = nativeToolSurfaceEnabled ? pluginConfig : disableCodexPluginThreadConfig(pluginConfig);
|
|
2703
2943
|
const pluginAppCacheKey = buildCodexPluginAppCacheKey({
|
|
2704
2944
|
appServer,
|
|
2705
2945
|
agentDir,
|
|
@@ -2707,11 +2947,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2707
2947
|
accountId: startupAuthAccountCacheKey,
|
|
2708
2948
|
envApiKeyFingerprint: startupEnvApiKeyCacheKey
|
|
2709
2949
|
});
|
|
2710
|
-
const pluginThreadConfigInputFingerprint =
|
|
2711
|
-
pluginConfig,
|
|
2950
|
+
const pluginThreadConfigInputFingerprint = pluginThreadConfigRequired ? buildCodexPluginThreadConfigInputFingerprint({
|
|
2951
|
+
pluginConfig: pluginThreadConfigPluginConfig,
|
|
2712
2952
|
appCacheKey: pluginAppCacheKey
|
|
2713
2953
|
}) : void 0;
|
|
2714
|
-
const resolvedPluginPolicy =
|
|
2954
|
+
const resolvedPluginPolicy = pluginThreadConfigRequired ? resolveCodexPluginsPolicy(pluginThreadConfigPluginConfig) : void 0;
|
|
2715
2955
|
const enabledPluginConfigKeys = resolvedPluginPolicy ? resolvedPluginPolicy.pluginPolicies.filter((plugin) => plugin.enabled).map((plugin) => plugin.configKey).toSorted() : void 0;
|
|
2716
2956
|
pluginAppServer = resolvedPluginPolicy?.enabled === true ? {
|
|
2717
2957
|
...appServer,
|
|
@@ -2742,15 +2982,17 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2742
2982
|
developerInstructions: promptBuild.developerInstructions,
|
|
2743
2983
|
config: threadConfig,
|
|
2744
2984
|
finalConfigPatch: nativeHookRelayConfig,
|
|
2985
|
+
nativeCodeModeEnabled: nativeToolSurfaceEnabled,
|
|
2986
|
+
userMcpServersEnabled: nativeToolSurfaceEnabled,
|
|
2745
2987
|
mcpServersFingerprint: bundleMcpThreadConfig.fingerprint,
|
|
2746
2988
|
mcpServersFingerprintEvaluated: bundleMcpThreadConfig.evaluated,
|
|
2747
2989
|
contextEngineProjection,
|
|
2748
|
-
pluginThreadConfig:
|
|
2990
|
+
pluginThreadConfig: pluginThreadConfigRequired ? {
|
|
2749
2991
|
enabled: true,
|
|
2750
2992
|
inputFingerprint: pluginThreadConfigInputFingerprint,
|
|
2751
2993
|
enabledPluginConfigKeys,
|
|
2752
2994
|
build: () => buildCodexPluginThreadConfig({
|
|
2753
|
-
pluginConfig,
|
|
2995
|
+
pluginConfig: pluginThreadConfigPluginConfig,
|
|
2754
2996
|
request: (method, requestParams) => startupClient.request(method, requestParams, {
|
|
2755
2997
|
timeoutMs: appServer.requestTimeoutMs,
|
|
2756
2998
|
signal: runAbortController.signal
|
|
@@ -3298,6 +3540,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3298
3540
|
paramsForRun: params,
|
|
3299
3541
|
threadId: thread.threadId,
|
|
3300
3542
|
turnId,
|
|
3543
|
+
nativeHookRelay,
|
|
3301
3544
|
signal: runAbortController.signal
|
|
3302
3545
|
});
|
|
3303
3546
|
}
|
|
@@ -3328,7 +3571,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3328
3571
|
});
|
|
3329
3572
|
const toolMeta = inferCodexDynamicToolMeta(call, resolveCodexToolProgressDetailMode(params.toolProgressDetail));
|
|
3330
3573
|
const toolArgs = sanitizeCodexToolArguments(call.arguments);
|
|
3331
|
-
|
|
3574
|
+
const shouldEmitDynamicToolProgress = shouldEmitTranscriptToolProgress(call.tool, toolArgs);
|
|
3575
|
+
if (shouldEmitDynamicToolProgress) emitCodexAppServerEvent(params, {
|
|
3332
3576
|
stream: "tool",
|
|
3333
3577
|
data: {
|
|
3334
3578
|
phase: "start",
|
|
@@ -3371,7 +3615,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3371
3615
|
success: response.success,
|
|
3372
3616
|
contentItems: response.contentItems
|
|
3373
3617
|
});
|
|
3374
|
-
emitCodexAppServerEvent(params, {
|
|
3618
|
+
if (shouldEmitDynamicToolProgress) emitCodexAppServerEvent(params, {
|
|
3375
3619
|
stream: "tool",
|
|
3376
3620
|
data: {
|
|
3377
3621
|
phase: "result",
|
|
@@ -3539,6 +3783,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3539
3783
|
signal: runAbortController.signal
|
|
3540
3784
|
});
|
|
3541
3785
|
const turnStartErrorMessage = usageLimitError?.message ?? formatErrorMessage(turnStartError);
|
|
3786
|
+
if (isInvalidCodexImagePayloadError(turnStartErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(activeSessionFile, {
|
|
3787
|
+
phase: "turn_start",
|
|
3788
|
+
threadId: thread.threadId,
|
|
3789
|
+
error: turnStartErrorMessage
|
|
3790
|
+
});
|
|
3542
3791
|
emitCodexAppServerEvent(params, {
|
|
3543
3792
|
stream: "codex_app_server.lifecycle",
|
|
3544
3793
|
data: {
|
|
@@ -3621,7 +3870,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3621
3870
|
prompt: promptBuild.prompt,
|
|
3622
3871
|
imagesCount: params.images?.length ?? 0
|
|
3623
3872
|
});
|
|
3624
|
-
projector = new CodexAppServerEventProjector(params, thread.threadId, activeTurnId, {
|
|
3873
|
+
projector = new CodexAppServerEventProjector(params, thread.threadId, activeTurnId, {
|
|
3874
|
+
nativePostToolUseRelayEnabled: nativeHookRelay?.allowedEvents.includes("post_tool_use") === true && nativeHookRelay.shouldRelayEvent("post_tool_use"),
|
|
3875
|
+
trajectoryRecorder
|
|
3876
|
+
});
|
|
3625
3877
|
if (isTerminalTurnStatus(turn.turn.status) || pendingNotifications.some((notification) => isTerminalTurnNotificationForTurn(notification, activeTurnId))) terminalTurnNotificationQueued = true;
|
|
3626
3878
|
closeCleanup = client.addCloseHandler?.(() => {
|
|
3627
3879
|
if (completed || terminalTurnNotificationQueued || runAbortController.signal.aborted) return;
|
|
@@ -3698,6 +3950,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3698
3950
|
const finalAborted = result.aborted || runAbortController.signal.aborted && !clientClosedAbort;
|
|
3699
3951
|
let finalPromptError = clientClosedPromptError ?? (turnCompletionIdleTimedOut ? turnCompletionIdleTimeoutMessage : timedOut ? "codex app-server attempt timed out" : result.promptError);
|
|
3700
3952
|
const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
|
|
3953
|
+
if (isInvalidCodexImagePayloadError(finalPromptErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(activeSessionFile, {
|
|
3954
|
+
phase: "turn_completed",
|
|
3955
|
+
threadId: thread.threadId,
|
|
3956
|
+
turnId: activeTurnId,
|
|
3957
|
+
error: finalPromptErrorMessage
|
|
3958
|
+
});
|
|
3701
3959
|
if (shouldRefreshCodexRateLimitsForUsageLimitMessage(finalPromptErrorMessage)) finalPromptError = await refreshCodexUsageLimitErrorMessage({
|
|
3702
3960
|
client,
|
|
3703
3961
|
source: {
|
|
@@ -3997,6 +4255,7 @@ function createCodexNativeHookRelay(params) {
|
|
|
3997
4255
|
...params.sessionKey ? { sessionKey: params.sessionKey } : {},
|
|
3998
4256
|
...params.config ? { config: params.config } : {},
|
|
3999
4257
|
runId: params.runId,
|
|
4258
|
+
...params.channelId ? { channelId: params.channelId } : {},
|
|
4000
4259
|
allowedEvents: params.events,
|
|
4001
4260
|
ttlMs: resolveCodexNativeHookRelayTtlMs({
|
|
4002
4261
|
explicitTtlMs: params.options?.ttlMs,
|
|
@@ -4060,6 +4319,15 @@ function resolveOpenClawCodingToolsSessionKeys(params, sandboxSessionKey) {
|
|
|
4060
4319
|
runSessionKey: params.sessionKey && params.sessionKey !== sandboxSessionKey ? params.sessionKey : void 0
|
|
4061
4320
|
};
|
|
4062
4321
|
}
|
|
4322
|
+
function resolveCodexAppServerHookChannelId(params, sandboxSessionKey) {
|
|
4323
|
+
return buildAgentHookContextChannelFields({
|
|
4324
|
+
sessionKey: sandboxSessionKey,
|
|
4325
|
+
messageChannel: params.messageChannel,
|
|
4326
|
+
messageProvider: params.messageProvider,
|
|
4327
|
+
currentChannelId: params.currentChannelId,
|
|
4328
|
+
messageTo: params.messageTo
|
|
4329
|
+
}).channelId;
|
|
4330
|
+
}
|
|
4063
4331
|
function buildOpenClawCodingToolsOptions(input) {
|
|
4064
4332
|
const { params } = input;
|
|
4065
4333
|
const modelHasVision = params.model.input?.includes("image") ?? false;
|
|
@@ -4086,7 +4354,7 @@ function buildOpenClawCodingToolsOptions(input) {
|
|
|
4086
4354
|
senderUsername: params.senderUsername,
|
|
4087
4355
|
senderE164: params.senderE164,
|
|
4088
4356
|
senderIsOwner: params.senderIsOwner,
|
|
4089
|
-
allowGatewaySubagentBinding: params.allowGatewaySubagentBinding,
|
|
4357
|
+
allowGatewaySubagentBinding: params.allowGatewaySubagentBinding || isForcedPrivateQaCodexRuntime(),
|
|
4090
4358
|
...sessionKeys,
|
|
4091
4359
|
sessionId: params.sessionId,
|
|
4092
4360
|
runId: params.runId,
|
|
@@ -4107,6 +4375,7 @@ function buildOpenClawCodingToolsOptions(input) {
|
|
|
4107
4375
|
modelAuthMode: resolveModelAuthMode(params.model.provider, params.config, void 0, { workspaceDir: input.effectiveWorkspace }),
|
|
4108
4376
|
suppressManagedWebSearch: false,
|
|
4109
4377
|
currentChannelId: params.currentChannelId,
|
|
4378
|
+
hookChannelId: resolveCodexAppServerHookChannelId(params, input.sandboxSessionKey),
|
|
4110
4379
|
currentThreadTs: params.currentThreadTs,
|
|
4111
4380
|
currentMessageId: params.currentMessageId,
|
|
4112
4381
|
replyToMode: params.replyToMode,
|
|
@@ -4153,16 +4422,35 @@ async function buildDynamicTools(input) {
|
|
|
4153
4422
|
});
|
|
4154
4423
|
}
|
|
4155
4424
|
function includeForcedMessageToolAllow(toolsAllow, params) {
|
|
4156
|
-
if (!shouldForceMessageTool(params)) return toolsAllow;
|
|
4157
|
-
if (toolsAllow === void 0) return toolsAllow;
|
|
4425
|
+
if (!shouldForceMessageTool(params) || toolsAllow === void 0 || hasWildcardCodexToolsAllow(toolsAllow)) return toolsAllow;
|
|
4158
4426
|
if (toolsAllow.length === 0) return ["message"];
|
|
4159
4427
|
return new Set(toolsAllow.map((name) => normalizeCodexDynamicToolName(name))).has("message") ? toolsAllow : [...toolsAllow, "message"];
|
|
4160
4428
|
}
|
|
4429
|
+
function shouldEnableCodexAppServerNativeToolSurface(params) {
|
|
4430
|
+
const toolsAllow = includeForcedMessageToolAllow(params.toolsAllow, params);
|
|
4431
|
+
if (toolsAllow === void 0) return true;
|
|
4432
|
+
return hasWildcardCodexToolsAllow(toolsAllow);
|
|
4433
|
+
}
|
|
4434
|
+
function disableCodexPluginThreadConfig(pluginConfig) {
|
|
4435
|
+
const config = readCodexPluginConfig(pluginConfig);
|
|
4436
|
+
return {
|
|
4437
|
+
...config,
|
|
4438
|
+
codexPlugins: {
|
|
4439
|
+
...config.codexPlugins,
|
|
4440
|
+
enabled: false
|
|
4441
|
+
}
|
|
4442
|
+
};
|
|
4443
|
+
}
|
|
4161
4444
|
function filterCodexDynamicToolsForAllowlist(tools, toolsAllow) {
|
|
4162
|
-
if (!toolsAllow
|
|
4445
|
+
if (!toolsAllow) return tools;
|
|
4446
|
+
if (toolsAllow.length === 0) return [];
|
|
4447
|
+
if (hasWildcardCodexToolsAllow(toolsAllow)) return tools;
|
|
4163
4448
|
const allowSet = new Set(toolsAllow.map((name) => normalizeCodexDynamicToolName(name)).filter(Boolean));
|
|
4164
4449
|
return tools.filter((tool) => allowSet.has(normalizeCodexDynamicToolName(tool.name)));
|
|
4165
4450
|
}
|
|
4451
|
+
function hasWildcardCodexToolsAllow(toolsAllow) {
|
|
4452
|
+
return toolsAllow.some((name) => normalizeCodexDynamicToolName(name) === "*");
|
|
4453
|
+
}
|
|
4166
4454
|
function shouldForceMessageTool(params) {
|
|
4167
4455
|
return params.sourceReplyDeliveryMode === "message_tool_only";
|
|
4168
4456
|
}
|
|
@@ -4365,6 +4653,23 @@ function readCodexErrorPayload(error) {
|
|
|
4365
4653
|
rateLimits
|
|
4366
4654
|
};
|
|
4367
4655
|
}
|
|
4656
|
+
function isInvalidCodexImagePayloadError(message) {
|
|
4657
|
+
if (typeof message !== "string" || !message.trim()) return false;
|
|
4658
|
+
const normalizedMessage = message.replace(/[_-]+/gu, " ");
|
|
4659
|
+
return /\b(?:invalid|malformed)\b[\s\S]{0,120}\b(?:image|image url|base64)\b/iu.test(normalizedMessage) || /\b(?:image|image url|base64)\b[\s\S]{0,120}\b(?:invalid|malformed)\b/iu.test(normalizedMessage);
|
|
4660
|
+
}
|
|
4661
|
+
async function clearCodexBindingAfterInvalidImagePayload(sessionFile, fields) {
|
|
4662
|
+
const currentBinding = await readCodexAppServerBinding(sessionFile);
|
|
4663
|
+
if (fields.threadId && currentBinding && currentBinding.threadId !== fields.threadId) {
|
|
4664
|
+
embeddedAgentLog.warn("codex app-server image payload error detected for unbound thread; preserving thread binding", {
|
|
4665
|
+
...fields,
|
|
4666
|
+
boundThreadId: currentBinding.threadId
|
|
4667
|
+
});
|
|
4668
|
+
return;
|
|
4669
|
+
}
|
|
4670
|
+
embeddedAgentLog.warn("codex app-server image payload error detected; clearing thread binding", fields);
|
|
4671
|
+
await clearCodexAppServerBinding(sessionFile);
|
|
4672
|
+
}
|
|
4368
4673
|
function describeNotificationActivity(notification) {
|
|
4369
4674
|
if (!isJsonObject(notification.params)) return { lastNotificationMethod: notification.method };
|
|
4370
4675
|
if (notification.method !== "rawResponseItem/completed") return { lastNotificationMethod: notification.method };
|
|
@@ -4749,6 +5054,7 @@ function handleApprovalRequest(params) {
|
|
|
4749
5054
|
paramsForRun: params.paramsForRun,
|
|
4750
5055
|
threadId: params.threadId,
|
|
4751
5056
|
turnId: params.turnId,
|
|
5057
|
+
nativeHookRelay: params.nativeHookRelay,
|
|
4752
5058
|
signal: params.signal
|
|
4753
5059
|
});
|
|
4754
5060
|
}
|