@openclaw/codex 2026.5.16-beta.4 → 2026.5.16-beta.5
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-Bssnu2uw.js} +292 -95
- package/dist/{side-question-BYYJZq23.js → side-question-DgVgwmjR.js} +103 -16
- package/dist/test-api.js +1 -1
- package/dist/{thread-lifecycle-wcyYqwrl.js → thread-lifecycle-BbriKhTq.js} +209 -11
- 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-BbriKhTq.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);
|
|
@@ -990,6 +990,7 @@ var CodexAppServerEventProjector = class {
|
|
|
990
990
|
});
|
|
991
991
|
}
|
|
992
992
|
this.recordToolMeta(item);
|
|
993
|
+
this.emitSnapshotOnlyNativeToolProgress(item);
|
|
993
994
|
this.recordNativeToolTranscriptCall(item);
|
|
994
995
|
this.recordNativeToolTranscriptResult(item);
|
|
995
996
|
this.emitAfterToolCallObservation(item);
|
|
@@ -999,6 +1000,33 @@ var CodexAppServerEventProjector = class {
|
|
|
999
1000
|
this.activeCompactionItemIds.clear();
|
|
1000
1001
|
await this.maybeEndReasoning();
|
|
1001
1002
|
}
|
|
1003
|
+
emitSnapshotOnlyNativeToolProgress(item) {
|
|
1004
|
+
if (!shouldSynthesizeToolProgressForItem(item) || !this.isCurrentTurnSnapshotItem(item) || this.completedItemIds.has(item.id) || itemStatus(item) === "running") return;
|
|
1005
|
+
if (!this.activeItemIds.has(item.id)) {
|
|
1006
|
+
this.emitStandardItemEvent({
|
|
1007
|
+
phase: "start",
|
|
1008
|
+
item
|
|
1009
|
+
});
|
|
1010
|
+
this.emitNormalizedToolItemEvent({
|
|
1011
|
+
phase: "start",
|
|
1012
|
+
item
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
this.activeItemIds.delete(item.id);
|
|
1016
|
+
this.emitStandardItemEvent({
|
|
1017
|
+
phase: "end",
|
|
1018
|
+
item
|
|
1019
|
+
});
|
|
1020
|
+
this.emitNormalizedToolItemEvent({
|
|
1021
|
+
phase: "result",
|
|
1022
|
+
item
|
|
1023
|
+
});
|
|
1024
|
+
this.completedItemIds.add(item.id);
|
|
1025
|
+
}
|
|
1026
|
+
isCurrentTurnSnapshotItem(item) {
|
|
1027
|
+
const itemTurnId = readItemString(item, "turnId") ?? readItemString(item, "turn_id");
|
|
1028
|
+
return itemTurnId === void 0 || itemTurnId === this.turnId;
|
|
1029
|
+
}
|
|
1002
1030
|
handleOutputDelta(params, toolName) {
|
|
1003
1031
|
const itemId = readString$2(params, "itemId");
|
|
1004
1032
|
const delta = readString$2(params, "delta");
|
|
@@ -1128,6 +1156,13 @@ var CodexAppServerEventProjector = class {
|
|
|
1128
1156
|
const meta = itemMeta(item, this.toolProgressDetailMode());
|
|
1129
1157
|
const args = params.phase === "start" ? itemToolArgs(item) : void 0;
|
|
1130
1158
|
const status = params.phase === "result" ? itemStatus(item) : "running";
|
|
1159
|
+
this.recordToolTrajectoryEvent({
|
|
1160
|
+
phase: params.phase,
|
|
1161
|
+
item,
|
|
1162
|
+
name,
|
|
1163
|
+
args,
|
|
1164
|
+
status
|
|
1165
|
+
});
|
|
1131
1166
|
this.emitDiagnosticToolExecutionEvent({
|
|
1132
1167
|
phase: params.phase,
|
|
1133
1168
|
item,
|
|
@@ -1152,6 +1187,32 @@ var CodexAppServerEventProjector = class {
|
|
|
1152
1187
|
});
|
|
1153
1188
|
if (params.phase === "result") this.emitAfterToolCallObservation(item);
|
|
1154
1189
|
}
|
|
1190
|
+
recordToolTrajectoryEvent(params) {
|
|
1191
|
+
if (params.phase === "start") {
|
|
1192
|
+
this.options.trajectoryRecorder?.recordEvent("tool.call", {
|
|
1193
|
+
threadId: this.threadId,
|
|
1194
|
+
turnId: this.turnId,
|
|
1195
|
+
itemId: params.item.id,
|
|
1196
|
+
toolCallId: params.item.id,
|
|
1197
|
+
name: params.name,
|
|
1198
|
+
arguments: params.args
|
|
1199
|
+
});
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
const toolResult = itemToolResult(params.item).result;
|
|
1203
|
+
const output = itemOutputText(params.item);
|
|
1204
|
+
this.options.trajectoryRecorder?.recordEvent("tool.result", {
|
|
1205
|
+
threadId: this.threadId,
|
|
1206
|
+
turnId: this.turnId,
|
|
1207
|
+
itemId: params.item.id,
|
|
1208
|
+
toolCallId: params.item.id,
|
|
1209
|
+
name: params.name,
|
|
1210
|
+
status: params.status,
|
|
1211
|
+
isError: isNonSuccessItemStatus(params.status),
|
|
1212
|
+
...toolResult ? { result: toolResult } : {},
|
|
1213
|
+
...output ? { output } : {}
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1155
1216
|
emitDiagnosticToolExecutionEvent(params) {
|
|
1156
1217
|
const base = {
|
|
1157
1218
|
runId: this.params.runId,
|
|
@@ -1749,88 +1810,6 @@ function readTurn(value) {
|
|
|
1749
1810
|
return readCodexTurn(value);
|
|
1750
1811
|
}
|
|
1751
1812
|
//#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
1813
|
//#region extensions/codex/src/app-server/trajectory.ts
|
|
1835
1814
|
const SENSITIVE_FIELD_RE = /(?:authorization|cookie|credential|key|password|passwd|secret|token)/iu;
|
|
1836
1815
|
const PRIVATE_PAYLOAD_FIELD_RE = /(?:image|screenshot|attachment|fileData|dataUri)/iu;
|
|
@@ -2401,6 +2380,169 @@ function isCodexAppServerPolicyMode(value) {
|
|
|
2401
2380
|
function isCodexAppServerApprovalPolicy(value) {
|
|
2402
2381
|
return value === "never" || value === "on-request" || value === "on-failure" || value === "untrusted";
|
|
2403
2382
|
}
|
|
2383
|
+
const CODEX_APP_SERVER_NATIVE_THREAD_MAX_TOKENS = 7e4;
|
|
2384
|
+
const CODEX_APP_SERVER_BYTE_UNITS = {
|
|
2385
|
+
b: 1,
|
|
2386
|
+
k: 1024,
|
|
2387
|
+
kb: 1024,
|
|
2388
|
+
kib: 1024,
|
|
2389
|
+
m: 1024 * 1024,
|
|
2390
|
+
mb: 1024 * 1024,
|
|
2391
|
+
mib: 1024 * 1024,
|
|
2392
|
+
g: 1024 * 1024 * 1024,
|
|
2393
|
+
gb: 1024 * 1024 * 1024,
|
|
2394
|
+
gib: 1024 * 1024 * 1024,
|
|
2395
|
+
t: 1024 * 1024 * 1024 * 1024,
|
|
2396
|
+
tb: 1024 * 1024 * 1024 * 1024,
|
|
2397
|
+
tib: 1024 * 1024 * 1024 * 1024
|
|
2398
|
+
};
|
|
2399
|
+
function parseCodexAppServerByteLimit(value) {
|
|
2400
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.floor(value);
|
|
2401
|
+
if (typeof value !== "string") return;
|
|
2402
|
+
const match = value.trim().match(/^(\d+(?:\.\d+)?)\s*([a-z]+)?$/i);
|
|
2403
|
+
if (!match) return;
|
|
2404
|
+
const amount = Number(match[1]);
|
|
2405
|
+
if (!Number.isFinite(amount) || amount <= 0) return;
|
|
2406
|
+
const multiplier = CODEX_APP_SERVER_BYTE_UNITS[(match[2] ?? "b").toLowerCase()];
|
|
2407
|
+
if (multiplier === void 0) return;
|
|
2408
|
+
return Math.max(1, Math.round(amount * multiplier));
|
|
2409
|
+
}
|
|
2410
|
+
async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codexHome) {
|
|
2411
|
+
const resolvedAgentDir = path.resolve(agentDir);
|
|
2412
|
+
const resolvedCodexHome = codexHome?.trim() ? path.resolve(codexHome) : resolveCodexAppServerHomeDir(resolvedAgentDir);
|
|
2413
|
+
const roots = [
|
|
2414
|
+
path.join(resolvedCodexHome, "sessions"),
|
|
2415
|
+
path.join(resolveCodexAppServerHomeDir(resolvedAgentDir), "sessions"),
|
|
2416
|
+
path.join(resolvedAgentDir, "agent", "codex-home", "sessions"),
|
|
2417
|
+
path.join(path.dirname(resolvedAgentDir), "codex-home", "sessions")
|
|
2418
|
+
];
|
|
2419
|
+
const files = [];
|
|
2420
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2421
|
+
for (const root of roots) {
|
|
2422
|
+
if (visited.has(root)) continue;
|
|
2423
|
+
visited.add(root);
|
|
2424
|
+
const stack = [root];
|
|
2425
|
+
while (stack.length > 0) {
|
|
2426
|
+
const dir = stack.pop();
|
|
2427
|
+
if (!dir) continue;
|
|
2428
|
+
let entries;
|
|
2429
|
+
try {
|
|
2430
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
2431
|
+
} catch {
|
|
2432
|
+
continue;
|
|
2433
|
+
}
|
|
2434
|
+
for (const entry of entries) {
|
|
2435
|
+
const file = path.join(dir, entry.name);
|
|
2436
|
+
if (entry.isDirectory()) {
|
|
2437
|
+
stack.push(file);
|
|
2438
|
+
continue;
|
|
2439
|
+
}
|
|
2440
|
+
if (!entry.isFile() || !entry.name.endsWith(".jsonl") || !entry.name.includes(threadId)) continue;
|
|
2441
|
+
try {
|
|
2442
|
+
files.push({
|
|
2443
|
+
path: file,
|
|
2444
|
+
bytes: (await fs.stat(file)).size
|
|
2445
|
+
});
|
|
2446
|
+
} catch {}
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
return files;
|
|
2451
|
+
}
|
|
2452
|
+
async function readCodexSessionRecordForSessionFile(sessionFile) {
|
|
2453
|
+
const sessionsFile = path.join(path.dirname(sessionFile), "sessions.json");
|
|
2454
|
+
let store;
|
|
2455
|
+
try {
|
|
2456
|
+
store = JSON.parse(await fs.readFile(sessionsFile, "utf8"));
|
|
2457
|
+
} catch {
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2460
|
+
if (!isJsonObject(store)) return;
|
|
2461
|
+
const resolvedSessionFile = path.resolve(sessionFile);
|
|
2462
|
+
for (const [sessionKey, record] of Object.entries(store)) {
|
|
2463
|
+
if (!isJsonObject(record) || typeof record.sessionFile !== "string") continue;
|
|
2464
|
+
if (path.resolve(record.sessionFile) !== resolvedSessionFile) continue;
|
|
2465
|
+
return {
|
|
2466
|
+
sessionKey,
|
|
2467
|
+
...record
|
|
2468
|
+
};
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
async function readCodexAppServerRolloutTokenUsage(file) {
|
|
2472
|
+
let handle;
|
|
2473
|
+
try {
|
|
2474
|
+
handle = await fs.open(file, "r");
|
|
2475
|
+
} catch {
|
|
2476
|
+
return;
|
|
2477
|
+
}
|
|
2478
|
+
let totalTokens;
|
|
2479
|
+
try {
|
|
2480
|
+
for await (const line of handle.readLines()) {
|
|
2481
|
+
const lineTokens = readCodexAppServerRolloutTokenUsageLine(line);
|
|
2482
|
+
if (lineTokens !== void 0) totalTokens = lineTokens;
|
|
2483
|
+
}
|
|
2484
|
+
} finally {
|
|
2485
|
+
await handle.close();
|
|
2486
|
+
}
|
|
2487
|
+
return totalTokens;
|
|
2488
|
+
}
|
|
2489
|
+
function readCodexAppServerRolloutTokenUsageLine(line) {
|
|
2490
|
+
if (!line.trim()) return;
|
|
2491
|
+
try {
|
|
2492
|
+
const parsed = JSON.parse(line);
|
|
2493
|
+
const payload = isJsonObject(parsed) ? parsed.payload : void 0;
|
|
2494
|
+
const info = isJsonObject(payload) && payload.type === "token_count" && isJsonObject(payload.info) ? payload.info : void 0;
|
|
2495
|
+
if (!info) return;
|
|
2496
|
+
const usage = isJsonObject(info.last_token_usage) ? info.last_token_usage : isJsonObject(info.total_token_usage) ? info.total_token_usage : void 0;
|
|
2497
|
+
const value = usage?.total_tokens ?? usage?.totalTokens;
|
|
2498
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
2499
|
+
} catch {
|
|
2500
|
+
return;
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
function maxFiniteNumber(values) {
|
|
2504
|
+
const nums = values.filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
2505
|
+
if (nums.length === 0) return;
|
|
2506
|
+
return Math.max(...nums);
|
|
2507
|
+
}
|
|
2508
|
+
async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
2509
|
+
const binding = params.binding;
|
|
2510
|
+
if (!binding?.threadId) return binding;
|
|
2511
|
+
if (params.config?.agents?.defaults?.compaction?.truncateAfterCompaction !== true) return binding;
|
|
2512
|
+
const sessionRecord = await readCodexSessionRecordForSessionFile(params.sessionFile);
|
|
2513
|
+
const maxBytes = parseCodexAppServerByteLimit(params.config?.agents?.defaults?.compaction?.maxActiveTranscriptBytes);
|
|
2514
|
+
const rolloutFiles = await listCodexAppServerRolloutFilesForThread(params.agentDir, binding.threadId, params.codexHome);
|
|
2515
|
+
if (maxBytes !== void 0) {
|
|
2516
|
+
const oversizedFiles = rolloutFiles.filter((file) => file.bytes >= maxBytes);
|
|
2517
|
+
if (oversizedFiles.length > 0) {
|
|
2518
|
+
embeddedAgentLog.warn("codex app-server native transcript exceeded active byte limit; starting a fresh thread", {
|
|
2519
|
+
threadId: binding.threadId,
|
|
2520
|
+
maxBytes,
|
|
2521
|
+
files: oversizedFiles.map((file) => ({
|
|
2522
|
+
path: file.path,
|
|
2523
|
+
bytes: file.bytes
|
|
2524
|
+
}))
|
|
2525
|
+
});
|
|
2526
|
+
await clearCodexAppServerBinding(params.sessionFile);
|
|
2527
|
+
return;
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
const nativeTokens = maxFiniteNumber(await Promise.all(rolloutFiles.map(async (file) => readCodexAppServerRolloutTokenUsage(file.path))));
|
|
2531
|
+
const sessionTokens = sessionRecord?.totalTokensFresh !== false && typeof sessionRecord?.totalTokens === "number" && Number.isFinite(sessionRecord.totalTokens) ? sessionRecord.totalTokens : void 0;
|
|
2532
|
+
const tokenCount = maxFiniteNumber([sessionTokens, nativeTokens]);
|
|
2533
|
+
if (tokenCount !== void 0 && tokenCount >= CODEX_APP_SERVER_NATIVE_THREAD_MAX_TOKENS) {
|
|
2534
|
+
embeddedAgentLog.warn("codex app-server native transcript exceeded active token limit; starting a fresh thread", {
|
|
2535
|
+
threadId: binding.threadId,
|
|
2536
|
+
maxTokens: CODEX_APP_SERVER_NATIVE_THREAD_MAX_TOKENS,
|
|
2537
|
+
sessionKey: sessionRecord?.sessionKey,
|
|
2538
|
+
sessionTokens,
|
|
2539
|
+
nativeTokens
|
|
2540
|
+
});
|
|
2541
|
+
await clearCodexAppServerBinding(params.sessionFile);
|
|
2542
|
+
return;
|
|
2543
|
+
}
|
|
2544
|
+
return binding;
|
|
2545
|
+
}
|
|
2404
2546
|
async function runCodexAppServerAttempt(params, options = {}) {
|
|
2405
2547
|
const attemptStartedAt = Date.now();
|
|
2406
2548
|
const attemptClientFactory = options.clientFactory ?? defaultCodexAppServerClientFactory;
|
|
@@ -2440,8 +2582,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2440
2582
|
agentId: params.agentId
|
|
2441
2583
|
});
|
|
2442
2584
|
const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId);
|
|
2443
|
-
|
|
2444
|
-
const
|
|
2585
|
+
let startupBinding = await readCodexAppServerBinding(params.sessionFile);
|
|
2586
|
+
const startupBindingAuthProfileId = startupBinding?.authProfileId;
|
|
2587
|
+
startupBinding = await rotateOversizedCodexAppServerStartupBinding({
|
|
2588
|
+
binding: startupBinding,
|
|
2589
|
+
sessionFile: params.sessionFile,
|
|
2590
|
+
agentDir,
|
|
2591
|
+
codexHome: appServer.start.env?.CODEX_HOME,
|
|
2592
|
+
config: params.config
|
|
2593
|
+
});
|
|
2594
|
+
const startupAuthProfileCandidate = params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId ?? startupBindingAuthProfileId;
|
|
2445
2595
|
const startupAuthProfileId = params.authProfileStore ? resolveCodexAppServerAuthProfileId({
|
|
2446
2596
|
authProfileId: startupAuthProfileCandidate,
|
|
2447
2597
|
store: params.authProfileStore,
|
|
@@ -2483,6 +2633,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2483
2633
|
});
|
|
2484
2634
|
for (const diagnostic of bundleMcpThreadConfig.diagnostics) embeddedAgentLog.warn(`bundle-mcp: ${diagnostic.pluginId}: ${diagnostic.message}`);
|
|
2485
2635
|
const activeContextEngine = isActiveHarnessContextEngine(params.contextEngine) ? params.contextEngine : void 0;
|
|
2636
|
+
const hookChannelId = resolveCodexAppServerHookChannelId(params, sandboxSessionKey);
|
|
2486
2637
|
let yieldDetected = false;
|
|
2487
2638
|
const toolBridge = createCodexDynamicToolBridge({
|
|
2488
2639
|
tools: await buildDynamicTools({
|
|
@@ -2499,14 +2650,15 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2499
2650
|
}
|
|
2500
2651
|
}),
|
|
2501
2652
|
signal: runAbortController.signal,
|
|
2502
|
-
loading: pluginConfig
|
|
2653
|
+
loading: resolveCodexDynamicToolsLoading(pluginConfig),
|
|
2503
2654
|
directToolNames: shouldForceMessageTool(params) ? ["message"] : [],
|
|
2504
2655
|
hookContext: {
|
|
2505
2656
|
agentId: sessionAgentId,
|
|
2506
2657
|
config: params.config,
|
|
2507
2658
|
sessionId: params.sessionId,
|
|
2508
2659
|
sessionKey: sandboxSessionKey,
|
|
2509
|
-
runId: params.runId
|
|
2660
|
+
runId: params.runId,
|
|
2661
|
+
channelId: hookChannelId
|
|
2510
2662
|
}
|
|
2511
2663
|
});
|
|
2512
2664
|
const hadSessionFile = await pathExists(activeSessionFile);
|
|
@@ -2524,7 +2676,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2524
2676
|
workspaceDir: params.workspaceDir,
|
|
2525
2677
|
messageProvider: params.messageProvider ?? void 0,
|
|
2526
2678
|
trigger: params.trigger,
|
|
2527
|
-
channelId:
|
|
2679
|
+
channelId: hookChannelId,
|
|
2528
2680
|
...hookContextWindowFields
|
|
2529
2681
|
};
|
|
2530
2682
|
const activeContextEnginePluginId = activeContextEngine ? resolveContextEngineOwnerPluginId(activeContextEngine) : void 0;
|
|
@@ -2688,6 +2840,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2688
2840
|
sessionKey: sandboxSessionKey,
|
|
2689
2841
|
config: params.config,
|
|
2690
2842
|
runId: params.runId,
|
|
2843
|
+
channelId: hookChannelId,
|
|
2691
2844
|
attemptTimeoutMs: params.timeoutMs,
|
|
2692
2845
|
startupTimeoutMs,
|
|
2693
2846
|
turnStartTimeoutMs: params.timeoutMs,
|
|
@@ -3298,6 +3451,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3298
3451
|
paramsForRun: params,
|
|
3299
3452
|
threadId: thread.threadId,
|
|
3300
3453
|
turnId,
|
|
3454
|
+
nativeHookRelay,
|
|
3301
3455
|
signal: runAbortController.signal
|
|
3302
3456
|
});
|
|
3303
3457
|
}
|
|
@@ -3539,6 +3693,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3539
3693
|
signal: runAbortController.signal
|
|
3540
3694
|
});
|
|
3541
3695
|
const turnStartErrorMessage = usageLimitError?.message ?? formatErrorMessage(turnStartError);
|
|
3696
|
+
if (isInvalidCodexImagePayloadError(turnStartErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(activeSessionFile, {
|
|
3697
|
+
phase: "turn_start",
|
|
3698
|
+
threadId: thread.threadId,
|
|
3699
|
+
error: turnStartErrorMessage
|
|
3700
|
+
});
|
|
3542
3701
|
emitCodexAppServerEvent(params, {
|
|
3543
3702
|
stream: "codex_app_server.lifecycle",
|
|
3544
3703
|
data: {
|
|
@@ -3621,7 +3780,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3621
3780
|
prompt: promptBuild.prompt,
|
|
3622
3781
|
imagesCount: params.images?.length ?? 0
|
|
3623
3782
|
});
|
|
3624
|
-
projector = new CodexAppServerEventProjector(params, thread.threadId, activeTurnId, {
|
|
3783
|
+
projector = new CodexAppServerEventProjector(params, thread.threadId, activeTurnId, {
|
|
3784
|
+
nativePostToolUseRelayEnabled: nativeHookRelay?.allowedEvents.includes("post_tool_use") === true && nativeHookRelay.shouldRelayEvent("post_tool_use"),
|
|
3785
|
+
trajectoryRecorder
|
|
3786
|
+
});
|
|
3625
3787
|
if (isTerminalTurnStatus(turn.turn.status) || pendingNotifications.some((notification) => isTerminalTurnNotificationForTurn(notification, activeTurnId))) terminalTurnNotificationQueued = true;
|
|
3626
3788
|
closeCleanup = client.addCloseHandler?.(() => {
|
|
3627
3789
|
if (completed || terminalTurnNotificationQueued || runAbortController.signal.aborted) return;
|
|
@@ -3698,6 +3860,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3698
3860
|
const finalAborted = result.aborted || runAbortController.signal.aborted && !clientClosedAbort;
|
|
3699
3861
|
let finalPromptError = clientClosedPromptError ?? (turnCompletionIdleTimedOut ? turnCompletionIdleTimeoutMessage : timedOut ? "codex app-server attempt timed out" : result.promptError);
|
|
3700
3862
|
const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
|
|
3863
|
+
if (isInvalidCodexImagePayloadError(finalPromptErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(activeSessionFile, {
|
|
3864
|
+
phase: "turn_completed",
|
|
3865
|
+
threadId: thread.threadId,
|
|
3866
|
+
turnId: activeTurnId,
|
|
3867
|
+
error: finalPromptErrorMessage
|
|
3868
|
+
});
|
|
3701
3869
|
if (shouldRefreshCodexRateLimitsForUsageLimitMessage(finalPromptErrorMessage)) finalPromptError = await refreshCodexUsageLimitErrorMessage({
|
|
3702
3870
|
client,
|
|
3703
3871
|
source: {
|
|
@@ -3997,6 +4165,7 @@ function createCodexNativeHookRelay(params) {
|
|
|
3997
4165
|
...params.sessionKey ? { sessionKey: params.sessionKey } : {},
|
|
3998
4166
|
...params.config ? { config: params.config } : {},
|
|
3999
4167
|
runId: params.runId,
|
|
4168
|
+
...params.channelId ? { channelId: params.channelId } : {},
|
|
4000
4169
|
allowedEvents: params.events,
|
|
4001
4170
|
ttlMs: resolveCodexNativeHookRelayTtlMs({
|
|
4002
4171
|
explicitTtlMs: params.options?.ttlMs,
|
|
@@ -4060,6 +4229,15 @@ function resolveOpenClawCodingToolsSessionKeys(params, sandboxSessionKey) {
|
|
|
4060
4229
|
runSessionKey: params.sessionKey && params.sessionKey !== sandboxSessionKey ? params.sessionKey : void 0
|
|
4061
4230
|
};
|
|
4062
4231
|
}
|
|
4232
|
+
function resolveCodexAppServerHookChannelId(params, sandboxSessionKey) {
|
|
4233
|
+
return buildAgentHookContextChannelFields({
|
|
4234
|
+
sessionKey: sandboxSessionKey,
|
|
4235
|
+
messageChannel: params.messageChannel,
|
|
4236
|
+
messageProvider: params.messageProvider,
|
|
4237
|
+
currentChannelId: params.currentChannelId,
|
|
4238
|
+
messageTo: params.messageTo
|
|
4239
|
+
}).channelId;
|
|
4240
|
+
}
|
|
4063
4241
|
function buildOpenClawCodingToolsOptions(input) {
|
|
4064
4242
|
const { params } = input;
|
|
4065
4243
|
const modelHasVision = params.model.input?.includes("image") ?? false;
|
|
@@ -4086,7 +4264,7 @@ function buildOpenClawCodingToolsOptions(input) {
|
|
|
4086
4264
|
senderUsername: params.senderUsername,
|
|
4087
4265
|
senderE164: params.senderE164,
|
|
4088
4266
|
senderIsOwner: params.senderIsOwner,
|
|
4089
|
-
allowGatewaySubagentBinding: params.allowGatewaySubagentBinding,
|
|
4267
|
+
allowGatewaySubagentBinding: params.allowGatewaySubagentBinding || isForcedPrivateQaCodexRuntime(),
|
|
4090
4268
|
...sessionKeys,
|
|
4091
4269
|
sessionId: params.sessionId,
|
|
4092
4270
|
runId: params.runId,
|
|
@@ -4107,6 +4285,7 @@ function buildOpenClawCodingToolsOptions(input) {
|
|
|
4107
4285
|
modelAuthMode: resolveModelAuthMode(params.model.provider, params.config, void 0, { workspaceDir: input.effectiveWorkspace }),
|
|
4108
4286
|
suppressManagedWebSearch: false,
|
|
4109
4287
|
currentChannelId: params.currentChannelId,
|
|
4288
|
+
hookChannelId: resolveCodexAppServerHookChannelId(params, input.sandboxSessionKey),
|
|
4110
4289
|
currentThreadTs: params.currentThreadTs,
|
|
4111
4290
|
currentMessageId: params.currentMessageId,
|
|
4112
4291
|
replyToMode: params.replyToMode,
|
|
@@ -4365,6 +4544,23 @@ function readCodexErrorPayload(error) {
|
|
|
4365
4544
|
rateLimits
|
|
4366
4545
|
};
|
|
4367
4546
|
}
|
|
4547
|
+
function isInvalidCodexImagePayloadError(message) {
|
|
4548
|
+
if (typeof message !== "string" || !message.trim()) return false;
|
|
4549
|
+
const normalizedMessage = message.replace(/[_-]+/gu, " ");
|
|
4550
|
+
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);
|
|
4551
|
+
}
|
|
4552
|
+
async function clearCodexBindingAfterInvalidImagePayload(sessionFile, fields) {
|
|
4553
|
+
const currentBinding = await readCodexAppServerBinding(sessionFile);
|
|
4554
|
+
if (fields.threadId && currentBinding && currentBinding.threadId !== fields.threadId) {
|
|
4555
|
+
embeddedAgentLog.warn("codex app-server image payload error detected for unbound thread; preserving thread binding", {
|
|
4556
|
+
...fields,
|
|
4557
|
+
boundThreadId: currentBinding.threadId
|
|
4558
|
+
});
|
|
4559
|
+
return;
|
|
4560
|
+
}
|
|
4561
|
+
embeddedAgentLog.warn("codex app-server image payload error detected; clearing thread binding", fields);
|
|
4562
|
+
await clearCodexAppServerBinding(sessionFile);
|
|
4563
|
+
}
|
|
4368
4564
|
function describeNotificationActivity(notification) {
|
|
4369
4565
|
if (!isJsonObject(notification.params)) return { lastNotificationMethod: notification.method };
|
|
4370
4566
|
if (notification.method !== "rawResponseItem/completed") return { lastNotificationMethod: notification.method };
|
|
@@ -4749,6 +4945,7 @@ function handleApprovalRequest(params) {
|
|
|
4749
4945
|
paramsForRun: params.paramsForRun,
|
|
4750
4946
|
threadId: params.threadId,
|
|
4751
4947
|
turnId: params.turnId,
|
|
4948
|
+
nativeHookRelay: params.nativeHookRelay,
|
|
4752
4949
|
signal: params.signal
|
|
4753
4950
|
});
|
|
4754
4951
|
}
|