@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.
@@ -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-Cc_ljZLZ.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);
@@ -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 || !this.shouldEmitToolOutput()) return;
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
- const startupBinding = await readCodexAppServerBinding(params.sessionFile);
2444
- const startupAuthProfileCandidate = params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId;
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.codexDynamicToolsLoading ?? "searchable",
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: params.messageChannel ?? params.messageProvider ?? void 0,
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 pluginThreadConfigEnabled = shouldBuildCodexPluginThreadConfig(pluginConfig);
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 = pluginThreadConfigEnabled ? buildCodexPluginThreadConfigInputFingerprint({
2711
- pluginConfig,
2950
+ const pluginThreadConfigInputFingerprint = pluginThreadConfigRequired ? buildCodexPluginThreadConfigInputFingerprint({
2951
+ pluginConfig: pluginThreadConfigPluginConfig,
2712
2952
  appCacheKey: pluginAppCacheKey
2713
2953
  }) : void 0;
2714
- const resolvedPluginPolicy = pluginThreadConfigEnabled ? resolveCodexPluginsPolicy(pluginConfig) : void 0;
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: pluginThreadConfigEnabled ? {
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
- emitCodexAppServerEvent(params, {
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, { nativePostToolUseRelayEnabled: nativeHookRelay?.allowedEvents.includes("post_tool_use") === true });
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 || toolsAllow.length === 0) return tools;
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
  }