@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.
@@ -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 normalizeCodexDynamicToolName, _ 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, x as filterCodexDynamicTools, y as resolveCodexContextEngineProjectionReserveTokens } from "./thread-lifecycle-wcyYqwrl.js";
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 { n as handleCodexAppServerElicitationRequest, r as handleCodexAppServerApprovalRequest, t as filterToolsForVisionInputs } from "./vision-tools-Cm_YicZb.js";
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, resolveSessionWriteLockAcquireTimeoutMs, resolveUserPath, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessAgentEndHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
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
- timeoutMs: resolveSessionWriteLockAcquireTimeoutMs(params.config)
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
- const startupBinding = await readCodexAppServerBinding(params.sessionFile);
2444
- const startupAuthProfileCandidate = params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId;
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.codexDynamicToolsLoading ?? "searchable",
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: params.messageChannel ?? params.messageProvider ?? void 0,
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, { nativePostToolUseRelayEnabled: nativeHookRelay?.allowedEvents.includes("post_tool_use") === true });
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
  }