@openclaw/codex 2026.5.24-beta.2 → 2026.5.26-beta.1

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.
Files changed (27) hide show
  1. package/dist/{client-1sSy4p3z.js → client-BVK_jmHW.js} +10 -3
  2. package/dist/{client-factory-Bk6i4FnW.js → client-factory-CaOpX89B.js} +1 -1
  3. package/dist/{command-handlers-CcTABuem.js → command-handlers-D4C2y46B.js} +10 -23
  4. package/dist/compact-CRI0BEc_.js +155 -0
  5. package/dist/{computer-use-Hdq1WgTA.js → computer-use-CDDlIBhY.js} +2 -2
  6. package/dist/{config-DDMrwfJl.js → config-0-UN67Qg.js} +8 -4
  7. package/dist/{node-cli-sessions-9CAqnIaA.js → conversation-binding-BnnjOmgs.js} +426 -434
  8. package/dist/{dynamic-tools-Bq717oJR.js → dynamic-tools-BG9ICyU4.js} +20 -11
  9. package/dist/harness.js +5 -5
  10. package/dist/index.js +452 -18
  11. package/dist/media-understanding-provider.js +8 -6
  12. package/dist/{models-DtGLkqMP.js → models-ASKu9eOY.js} +4 -4
  13. package/dist/{notification-correlation-qKY_sgga.js → notification-correlation-YINts3PA.js} +26 -11
  14. package/dist/{protocol-validators-_gKDcd0x.js → protocol-validators-CSuFMLvY.js} +138 -29
  15. package/dist/provider.js +3 -3
  16. package/dist/{request-D93E78SA.js → request-DmBkYLPy.js} +3 -3
  17. package/dist/{run-attempt-CT1N__qp.js → run-attempt-CFBsGx1T.js} +488 -280
  18. package/dist/{session-binding-Bw_mfIW2.js → session-binding-UFjjws4k.js} +1 -1
  19. package/dist/{shared-client-CFCUGEVs.js → shared-client-Fou5nAyt.js} +66 -11
  20. package/dist/{side-question-CYFMTA1O.js → side-question-fq_T2d_x.js} +17 -12
  21. package/dist/test-api.js +3 -3
  22. package/dist/{thread-lifecycle-DGoaguJh.js → thread-lifecycle-BapIT9Qs.js} +113 -28
  23. package/dist/{vision-tools-DOnxzH2y.js → vision-tools-B30YCKRK.js} +16 -4
  24. package/npm-shrinkwrap.json +222 -305
  25. package/package.json +8 -8
  26. package/dist/compact-DnTgL6UT.js +0 -475
  27. package/dist/protocol-oeJQu4rs.js +0 -9
@@ -1,31 +1,31 @@
1
- import { c as readCodexPluginConfig, d as resolveCodexPluginsPolicy, f as withMcpElicitationsApprovalPolicy, i as isCodexAppServerApprovalPolicyAllowedByRequirements, l as resolveCodexAppServerRuntimeOptions, o as isCodexSandboxExecServerEnabled, u as resolveCodexComputerUseConfig } from "./config-DDMrwfJl.js";
2
- import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-_gKDcd0x.js";
3
- import { t as isJsonObject } from "./protocol-oeJQu4rs.js";
4
- import { a as isCodexAppServerConnectionClosedError, i as isCodexAppServerApprovalRequest, r as compareCodexAppServerVersions, s as MIN_CODEX_SANDBOX_EXEC_SERVER_APP_SERVER_VERSION } from "./client-1sSy4p3z.js";
5
- import { C as sanitizeCodexHistoryImagePayloads, D as resolveCodexContextEngineProjectionMaxChars, E as projectContextEngineAssemblyForCodex, O as resolveCodexContextEngineProjectionReserveTokens, _ as shouldBuildCodexPluginThreadConfig, c as buildTurnStartParams, g as mergeCodexThreadConfigs, h as buildCodexPluginThreadConfigInputFingerprint, i as buildDeveloperInstructions, l as codexDynamicToolsFingerprint, m as buildCodexPluginThreadConfig, p as startOrResumeThread, r as buildContextEngineBinding, s as buildTurnCollaborationMode, t as areCodexDynamicToolFingerprintsCompatible, u as isContextEngineBindingCompatible, x as defaultCodexAppInventoryCache } from "./thread-lifecycle-DGoaguJh.js";
6
- import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-Bw_mfIW2.js";
7
- import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-D93E78SA.js";
8
- import { g as shouldRefreshCodexRateLimitsForUsageLimitMessage, h as resolveCodexUsageLimitResetAtMs, i as readCodexNotificationTurnId, m as formatCodexUsageLimitErrorMessage, n as isCodexNotificationForTurn, r as readCodexNotificationThreadId, s as formatCodexDisplayText, t as describeCodexNotificationCorrelation } from "./notification-correlation-qKY_sgga.js";
9
- 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-CFCUGEVs.js";
1
+ import { t as defaultCodexAppServerClientFactory } from "./client-factory-CaOpX89B.js";
2
+ import { c as readCodexPluginConfig, d as resolveCodexPluginsPolicy, f as shouldAutoApproveCodexAppServerApprovals, i as isCodexAppServerApprovalPolicyAllowedByRequirements, l as resolveCodexAppServerRuntimeOptions, o as isCodexSandboxExecServerEnabled, p as withMcpElicitationsApprovalPolicy, u as resolveCodexComputerUseConfig } from "./config-0-UN67Qg.js";
3
+ import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-CSuFMLvY.js";
4
+ import { a as isCodexAppServerConnectionClosedError, i as isCodexAppServerApprovalRequest, l as isJsonObject, r as compareCodexAppServerVersions, s as MIN_CODEX_SANDBOX_EXEC_SERVER_APP_SERVER_VERSION } from "./client-BVK_jmHW.js";
5
+ import { C as defaultCodexAppInventoryCache, D as projectContextEngineAssemblyForCodex, O as resolveCodexContextEngineProjectionMaxChars, T as sanitizeCodexHistoryImagePayloads, _ as buildCodexPluginThreadConfigInputFingerprint, a as buildDeveloperInstructions, c as buildTurnCollaborationMode, d as isContextEngineBindingCompatible, g as buildCodexPluginThreadConfig, h as isCodexAppServerProfilerEnabled, i as buildContextEngineBinding, k as resolveCodexContextEngineProjectionReserveTokens, l as buildTurnStartParams, m as startOrResumeThread, n as areCodexDynamicToolFingerprintsCompatible, u as codexDynamicToolsFingerprint, v as mergeCodexThreadConfigs, y as shouldBuildCodexPluginThreadConfig } from "./thread-lifecycle-BapIT9Qs.js";
6
+ import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-UFjjws4k.js";
7
+ import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-DmBkYLPy.js";
8
+ import { g as shouldRefreshCodexRateLimitsForUsageLimitMessage, h as resolveCodexUsageLimitResetAtMs, i as readCodexNotificationTurnId, m as formatCodexUsageLimitErrorMessage, n as isCodexNotificationForTurn, r as readCodexNotificationThreadId, s as formatCodexDisplayText, t as describeCodexNotificationCorrelation } from "./notification-correlation-YINts3PA.js";
9
+ import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerFallbackApiKeyCacheKey, f as resolveCodexAppServerHomeDir, l as resolveCodexAppServerAuthProfileId, s as refreshCodexAppServerAuthTokens, t as clearSharedCodexAppServerClientIfCurrent, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-Fou5nAyt.js";
10
10
  import { i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-CTnEWuor.js";
11
- import { a as resolveCodexDynamicToolsLoading, i as normalizeCodexDynamicToolName, n as filterCodexDynamicTools, r as isForcedPrivateQaCodexRuntime, t as createCodexDynamicToolBridge } from "./dynamic-tools-Bq717oJR.js";
12
- import { t as defaultCodexAppServerClientFactory } from "./client-factory-Bk6i4FnW.js";
13
- import { a as handleCodexAppServerElicitationRequest, c as emitDynamicToolTerminalDiagnostic, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerApprovalRequest, n as CODEX_NATIVE_HOOK_RELAY_EVENTS, o as emitDynamicToolErrorDiagnostic, r as buildCodexNativeHookRelayConfig, s as emitDynamicToolStartedDiagnostic, t as filterToolsForVisionInputs } from "./vision-tools-DOnxzH2y.js";
14
- import { t as ensureCodexComputerUse } from "./computer-use-Hdq1WgTA.js";
11
+ import { a as resolveCodexDynamicToolsLoading, i as normalizeCodexDynamicToolName, n as filterCodexDynamicTools, r as isForcedPrivateQaCodexRuntime, t as createCodexDynamicToolBridge } from "./dynamic-tools-BG9ICyU4.js";
12
+ import { a as handleCodexAppServerElicitationRequest, c as emitDynamicToolTerminalDiagnostic, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerApprovalRequest, n as CODEX_NATIVE_HOOK_RELAY_EVENTS, o as emitDynamicToolErrorDiagnostic, r as buildCodexNativeHookRelayConfig, s as emitDynamicToolStartedDiagnostic, t as filterToolsForVisionInputs } from "./vision-tools-B30YCKRK.js";
13
+ import { t as ensureCodexComputerUse } from "./computer-use-CDDlIBhY.js";
15
14
  import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-N66I-Rd7.js";
16
15
  import { createHash, randomUUID } from "node:crypto";
17
- import nodeFs from "node:fs";
18
- import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, PREEMPTIVE_OVERFLOW_ERROR_TEXT, TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentHarnessAgentEndHook, bootstrapHarnessContextEngine, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, compactContextEngineWithSafetyTimeout, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, estimateRenderedLlmBoundaryTokenPressure, finalizeHarnessContextEngineTurn, formatErrorMessage, formatPrePromptPrecheckLog, formatToolAggregate, formatToolProgressOutput, hasBeforeToolCallPolicy, inferToolMetaFromArgs, isActiveHarnessContextEngine, isSubagentSessionKey, loadCodexBundleMcpThreadConfig, normalizeAgentRuntimeTools, normalizeUsage, registerNativeHookRelay, resolveAgentHarnessBeforePromptBuildResult, resolveAttemptSpawnWorkspaceDir, resolveBootstrapContextForRun, resolveCompactionTimeoutMs, resolveContextEngineOwnerPluginId, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds, resolveSessionWriteLockOptions, resolveUserPath, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessAgentEndHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, shouldPreemptivelyCompactBeforePrompt, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
16
+ import fsSync from "node:fs";
17
+ import { asBoolean, asFiniteNumber, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
18
+ import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentHarnessAgentEndHook, bootstrapHarnessContextEngine, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, finalizeHarnessContextEngineTurn, formatErrorMessage, formatToolAggregate, formatToolProgressOutput, getBeforeToolCallPolicyDiagnosticState, 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";
19
19
  import { spawn } from "node:child_process";
20
20
  import { once } from "node:events";
21
21
  import { WebSocketServer } from "ws";
22
22
  import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
23
23
  import fs from "node:fs/promises";
24
24
  import path, { posix } from "node:path";
25
+ import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, hasPendingInternalDiagnosticEvent, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
25
26
  import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
26
27
  import { isToolAllowed } from "openclaw/plugin-sdk/sandbox";
27
28
  import { appendRegularFile, pathExists } from "openclaw/plugin-sdk/security-runtime";
28
- import { emitTrustedDiagnosticEvent, hasPendingInternalDiagnosticEvent, onInternalDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
29
29
  import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "@earendil-works/pi-coding-agent";
30
30
  import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
31
31
  import { isIP } from "node:net";
@@ -102,10 +102,6 @@ function inferCodexDynamicToolMeta(call, detailMode) {
102
102
  //#endregion
103
103
  //#region extensions/codex/src/app-server/transcript-mirror.ts
104
104
  const MIRROR_IDENTITY_META_KEY = "mirrorIdentity";
105
- function normalizeOptionalString$1(value) {
106
- const normalized = value?.trim();
107
- return normalized ? normalized : void 0;
108
- }
109
105
  function buildSenderLabel(params) {
110
106
  const label = params.senderName ?? params.senderUsername ?? params.senderE164 ?? params.senderId;
111
107
  if (!label) return;
@@ -113,17 +109,17 @@ function buildSenderLabel(params) {
113
109
  return `${label} (${params.senderId})`;
114
110
  }
115
111
  function buildCodexUserPromptMessage(params) {
116
- const senderId = normalizeOptionalString$1(params.senderId);
117
- const senderName = normalizeOptionalString$1(params.senderName);
118
- const senderUsername = normalizeOptionalString$1(params.senderUsername);
119
- const senderE164 = normalizeOptionalString$1(params.senderE164);
112
+ const senderId = normalizeOptionalString(params.senderId);
113
+ const senderName = normalizeOptionalString(params.senderName);
114
+ const senderUsername = normalizeOptionalString(params.senderUsername);
115
+ const senderE164 = normalizeOptionalString(params.senderE164);
120
116
  const senderLabel = buildSenderLabel({
121
117
  senderId,
122
118
  senderName,
123
119
  senderUsername,
124
120
  senderE164
125
121
  });
126
- const sourceChannel = normalizeOptionalString$1(params.inputProvenance?.sourceChannel ?? params.messageChannel ?? params.messageProvider);
122
+ const sourceChannel = normalizeOptionalString(params.inputProvenance?.sourceChannel ?? params.messageChannel ?? params.messageProvider);
127
123
  return {
128
124
  role: "user",
129
125
  content: params.prompt,
@@ -183,12 +179,14 @@ async function mirrorCodexAppServerTranscript(params) {
183
179
  sessionFile: params.sessionFile,
184
180
  ...resolveSessionWriteLockOptions(params.config)
185
181
  });
182
+ const appendedUpdates = [];
186
183
  try {
187
- const existingIdempotencyKeys = await readTranscriptIdempotencyKeys(params.sessionFile);
184
+ const mirrorState = await readTranscriptMirrorState(params.sessionFile);
185
+ let nextMessageSeq = mirrorState.messageCount;
188
186
  for (const message of messages) {
189
187
  const dedupeIdentity = buildMirrorDedupeIdentity(message);
190
188
  const idempotencyKey = params.idempotencyScope ? `${params.idempotencyScope}:${dedupeIdentity}` : void 0;
191
- if (idempotencyKey && existingIdempotencyKeys.has(idempotencyKey)) continue;
189
+ if (idempotencyKey && mirrorState.idempotencyKeys.has(idempotencyKey)) continue;
192
190
  const nextMessage = runAgentHarnessBeforeMessageWriteHook({
193
191
  message: {
194
192
  ...message,
@@ -202,41 +200,57 @@ async function mirrorCodexAppServerTranscript(params) {
202
200
  ...nextMessage,
203
201
  idempotencyKey
204
202
  } : nextMessage;
205
- await appendSessionTranscriptMessage({
203
+ const { messageId, message: appendedMessage } = await appendSessionTranscriptMessage({
206
204
  transcriptPath: params.sessionFile,
207
205
  message: messageToAppend,
208
206
  config: params.config
209
207
  });
210
- if (idempotencyKey) existingIdempotencyKeys.add(idempotencyKey);
208
+ nextMessageSeq += 1;
209
+ appendedUpdates.push({
210
+ messageId,
211
+ message: appendedMessage,
212
+ messageSeq: nextMessageSeq
213
+ });
214
+ if (idempotencyKey) mirrorState.idempotencyKeys.add(idempotencyKey);
211
215
  }
212
216
  } finally {
213
217
  await lock.release();
214
218
  }
215
- if (params.sessionKey) emitSessionTranscriptUpdate({
219
+ for (const update of appendedUpdates) emitSessionTranscriptUpdate({
216
220
  sessionFile: params.sessionFile,
217
- sessionKey: params.sessionKey
221
+ ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
222
+ message: update.message,
223
+ messageId: update.messageId,
224
+ messageSeq: update.messageSeq
218
225
  });
219
- else emitSessionTranscriptUpdate(params.sessionFile);
220
226
  }
221
- async function readTranscriptIdempotencyKeys(sessionFile) {
222
- const keys = /* @__PURE__ */ new Set();
227
+ async function readTranscriptMirrorState(sessionFile) {
228
+ const idempotencyKeys = /* @__PURE__ */ new Set();
229
+ let messageCount = 0;
223
230
  let raw;
224
231
  try {
225
232
  raw = await fs.readFile(sessionFile, "utf8");
226
233
  } catch (error) {
227
234
  if (error.code !== "ENOENT") throw error;
228
- return keys;
235
+ return {
236
+ idempotencyKeys,
237
+ messageCount
238
+ };
229
239
  }
230
240
  for (const line of raw.split(/\r?\n/)) {
231
241
  if (!line.trim()) continue;
232
242
  try {
233
243
  const parsed = JSON.parse(line);
234
- if (typeof parsed.message?.idempotencyKey === "string") keys.add(parsed.message.idempotencyKey);
244
+ if (parsed.type === "message") messageCount += 1;
245
+ if (typeof parsed.message?.idempotencyKey === "string") idempotencyKeys.add(parsed.message.idempotencyKey);
235
246
  } catch {
236
247
  continue;
237
248
  }
238
249
  }
239
- return keys;
250
+ return {
251
+ idempotencyKeys,
252
+ messageCount
253
+ };
240
254
  }
241
255
  //#endregion
242
256
  //#region extensions/codex/src/app-server/event-projector.ts
@@ -463,6 +477,12 @@ var CodexAppServerEventProjector = class {
463
477
  });
464
478
  }
465
479
  recordDynamicToolResult(params) {
480
+ const existingMeta = this.toolMetas.get(params.callId);
481
+ this.toolMetas.set(params.callId, {
482
+ toolName: params.tool,
483
+ ...existingMeta?.meta ? { meta: existingMeta.meta } : {},
484
+ ...existingMeta?.asyncStarted === true || params.asyncStarted === true ? { asyncStarted: true } : {}
485
+ });
466
486
  this.recordToolTranscriptResult({
467
487
  id: params.callId,
468
488
  name: params.tool,
@@ -832,7 +852,7 @@ var CodexAppServerEventProjector = class {
832
852
  if (savedPath) this.nativeGeneratedMediaUrls.add(savedPath);
833
853
  }
834
854
  buildToolMediaUrls(toolTelemetry) {
835
- const mediaUrls = new Set(toolTelemetry.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []);
855
+ const mediaUrls = new Set(normalizeStringEntries(toolTelemetry.toolMediaUrls ?? []));
836
856
  if ((toolTelemetry.messagingToolSentMediaUrls?.length ?? 0) === 0) for (const mediaUrl of this.nativeGeneratedMediaUrls) mediaUrls.add(mediaUrl);
837
857
  return mediaUrls.size > 0 ? [...mediaUrls] : toolTelemetry.toolMediaUrls;
838
858
  }
@@ -1118,9 +1138,11 @@ var CodexAppServerEventProjector = class {
1118
1138
  const toolName = itemName(item);
1119
1139
  if (!toolName) return;
1120
1140
  const meta = itemMeta(item, this.toolProgressDetailMode());
1141
+ const existingMeta = this.toolMetas.get(item.id);
1121
1142
  this.toolMetas.set(item.id, {
1122
1143
  toolName,
1123
- ...meta ? { meta } : {}
1144
+ ...meta ? { meta } : {},
1145
+ ...existingMeta?.asyncStarted === true ? { asyncStarted: true } : {}
1124
1146
  });
1125
1147
  if (isSideEffectingNativeToolItem(item)) this.sideEffectingToolItemIds.add(item.id);
1126
1148
  else this.sideEffectingToolItemIds.delete(item.id);
@@ -1364,12 +1386,10 @@ function readNullableString$1(record, key) {
1364
1386
  return typeof value === "string" ? value : void 0;
1365
1387
  }
1366
1388
  function readNumber$1(record, key) {
1367
- const value = record[key];
1368
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1389
+ return asFiniteNumber(record[key]);
1369
1390
  }
1370
1391
  function readBoolean$1(record, key) {
1371
- const value = record[key];
1372
- return typeof value === "boolean" ? value : void 0;
1392
+ return asBoolean(record[key]);
1373
1393
  }
1374
1394
  function readBooleanAlias(record, keys) {
1375
1395
  for (const key of keys) {
@@ -2616,9 +2636,6 @@ function readString$2(record, key) {
2616
2636
  const value = record?.[key];
2617
2637
  return typeof value === "string" ? value : void 0;
2618
2638
  }
2619
- function normalizeOptionalString(value) {
2620
- return value?.trim() || void 0;
2621
- }
2622
2639
  function readStringArray(value) {
2623
2640
  if (!Array.isArray(value)) return [];
2624
2641
  return value.filter((entry) => typeof entry === "string" && entry.trim() !== "");
@@ -2741,8 +2758,7 @@ function readTranscriptParentThreadId(payload) {
2741
2758
  return readString$2(isJsonObject(subagent?.thread_spawn) ? subagent.thread_spawn : void 0, "parent_thread_id")?.trim();
2742
2759
  }
2743
2760
  function readNumber(record, key) {
2744
- const value = record[key];
2745
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
2761
+ return asFiniteNumber(record[key]);
2746
2762
  }
2747
2763
  function secondsToMillis(value) {
2748
2764
  return value === void 0 ? void 0 : Math.round(value * 1e3);
@@ -3930,7 +3946,7 @@ const JWT_VALUE_RE = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]
3930
3946
  const COOKIE_PAIR_RE = /\b([A-Za-z][A-Za-z0-9_.-]{1,64})=([A-Za-z0-9+/._~%=-]{16,})(?=;|\s|$)/gu;
3931
3947
  const TRAJECTORY_RUNTIME_FILE_MAX_BYTES = 50 * 1024 * 1024;
3932
3948
  const TRAJECTORY_RUNTIME_EVENT_MAX_BYTES = 256 * 1024;
3933
- function resolveCodexTrajectoryPointerFlags(constants = nodeFs.constants) {
3949
+ function resolveCodexTrajectoryPointerFlags(constants = fsSync.constants) {
3934
3950
  const noFollow = constants.O_NOFOLLOW;
3935
3951
  return constants.O_CREAT | constants.O_TRUNC | constants.O_WRONLY | (typeof noFollow === "number" ? noFollow : 0);
3936
3952
  }
@@ -3964,23 +3980,23 @@ function writeTrajectoryPointerBestEffort(params) {
3964
3980
  const pointerPath = resolveTrajectoryPointerFilePath(params.sessionFile);
3965
3981
  try {
3966
3982
  const pointerDir = path.resolve(path.dirname(pointerPath));
3967
- if (nodeFs.lstatSync(pointerDir).isSymbolicLink()) return;
3983
+ if (fsSync.lstatSync(pointerDir).isSymbolicLink()) return;
3968
3984
  try {
3969
- if (nodeFs.lstatSync(pointerPath).isSymbolicLink()) return;
3985
+ if (fsSync.lstatSync(pointerPath).isSymbolicLink()) return;
3970
3986
  } catch (error) {
3971
3987
  if (error.code !== "ENOENT") return;
3972
3988
  }
3973
- const fd = nodeFs.openSync(pointerPath, resolveCodexTrajectoryPointerFlags(), 384);
3989
+ const fd = fsSync.openSync(pointerPath, resolveCodexTrajectoryPointerFlags(), 384);
3974
3990
  try {
3975
- nodeFs.writeFileSync(fd, `${JSON.stringify({
3991
+ fsSync.writeFileSync(fd, `${JSON.stringify({
3976
3992
  traceSchema: "openclaw-trajectory-pointer",
3977
3993
  schemaVersion: 1,
3978
3994
  sessionId: params.sessionId,
3979
3995
  runtimeFile: params.filePath
3980
3996
  }, null, 2)}\n`, "utf8");
3981
- nodeFs.fchmodSync(fd, 384);
3997
+ fsSync.fchmodSync(fd, 384);
3982
3998
  } finally {
3983
- nodeFs.closeSync(fd);
3999
+ fsSync.closeSync(fd);
3984
4000
  }
3985
4001
  } catch {}
3986
4002
  }
@@ -4345,6 +4361,7 @@ const CODEX_BOOTSTRAP_CONTEXT_ORDER = new Map([
4345
4361
  ["memory.md", 60],
4346
4362
  ["heartbeat.md", 70]
4347
4363
  ]);
4364
+ const ensuredCodexWorkspaceDirs = /* @__PURE__ */ new Set();
4348
4365
  const pendingCodexNativeHookRelayUnregisters = /* @__PURE__ */ new Set();
4349
4366
  function scheduleCodexNativeHookRelayUnregister(params) {
4350
4367
  let pending;
@@ -4367,6 +4384,19 @@ function resolveCodexNativeHookRelayUnregisterGraceMs(hookTimeoutSec) {
4367
4384
  const hookTimeoutMs = typeof hookTimeoutSec === "number" && Number.isFinite(hookTimeoutSec) && hookTimeoutSec > 0 ? Math.ceil(hookTimeoutSec) * 1e3 : 0;
4368
4385
  return Math.max(CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS, hookTimeoutMs + CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS);
4369
4386
  }
4387
+ async function ensureCodexWorkspaceDirOnce(workspaceDir) {
4388
+ const normalized = path.resolve(workspaceDir);
4389
+ if (ensuredCodexWorkspaceDirs.has(normalized)) {
4390
+ try {
4391
+ if ((await fs.stat(normalized)).isDirectory()) return;
4392
+ } catch (error) {
4393
+ if ((typeof error === "object" && error ? error.code : void 0) !== "ENOENT") throw error;
4394
+ }
4395
+ ensuredCodexWorkspaceDirs.delete(normalized);
4396
+ }
4397
+ await fs.mkdir(normalized, { recursive: true });
4398
+ ensuredCodexWorkspaceDirs.add(normalized);
4399
+ }
4370
4400
  function emitCodexAppServerEvent(params, event) {
4371
4401
  try {
4372
4402
  emitAgentEvent({
@@ -4549,7 +4579,7 @@ function isCodexAppServerPolicyMode(value) {
4549
4579
  function isCodexAppServerApprovalPolicy(value) {
4550
4580
  return value === "never" || value === "on-request" || value === "on-failure" || value === "untrusted";
4551
4581
  }
4552
- const CODEX_APP_SERVER_NATIVE_THREAD_MAX_TOKENS = 7e4;
4582
+ const CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS = 3e5;
4553
4583
  const CODEX_APP_SERVER_BYTE_UNITS = {
4554
4584
  b: 1,
4555
4585
  k: 1024,
@@ -4637,25 +4667,29 @@ async function readCodexSessionRecordForSessionFile(sessionFile) {
4637
4667
  };
4638
4668
  }
4639
4669
  }
4640
- async function readCodexAppServerRolloutTokenUsage(file) {
4670
+ async function readCodexAppServerRolloutTokenSnapshot(file) {
4641
4671
  let handle;
4642
4672
  try {
4643
4673
  handle = await fs.open(file, "r");
4644
4674
  } catch {
4645
4675
  return;
4646
4676
  }
4647
- let totalTokens;
4677
+ let snapshot;
4648
4678
  try {
4649
4679
  for await (const line of handle.readLines()) {
4650
- const lineTokens = readCodexAppServerRolloutTokenUsageLine(line);
4651
- if (lineTokens !== void 0) totalTokens = lineTokens;
4680
+ const lineSnapshot = readCodexAppServerRolloutTokenSnapshotLine(line);
4681
+ if (lineSnapshot !== void 0) {
4682
+ snapshot ??= {};
4683
+ if (lineSnapshot.totalTokens !== void 0) snapshot.totalTokens = lineSnapshot.totalTokens;
4684
+ if (lineSnapshot.modelContextWindow !== void 0) snapshot.modelContextWindow = lineSnapshot.modelContextWindow;
4685
+ }
4652
4686
  }
4653
4687
  } finally {
4654
4688
  await handle.close();
4655
4689
  }
4656
- return totalTokens;
4690
+ return snapshot;
4657
4691
  }
4658
- function readCodexAppServerRolloutTokenUsageLine(line) {
4692
+ function readCodexAppServerRolloutTokenSnapshotLine(line) {
4659
4693
  if (!line.trim()) return;
4660
4694
  try {
4661
4695
  const parsed = JSON.parse(line);
@@ -4664,7 +4698,23 @@ function readCodexAppServerRolloutTokenUsageLine(line) {
4664
4698
  if (!info) return;
4665
4699
  const usage = isJsonObject(info.last_token_usage) ? info.last_token_usage : isJsonObject(info.total_token_usage) ? info.total_token_usage : void 0;
4666
4700
  const value = usage?.total_tokens ?? usage?.totalTokens;
4667
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
4701
+ const totalTokens = typeof value === "number" && Number.isFinite(value) ? value : void 0;
4702
+ const windowValue = info.model_context_window ?? info.modelContextWindow;
4703
+ const modelContextWindow = typeof windowValue === "number" && Number.isFinite(windowValue) && windowValue > 0 ? Math.floor(windowValue) : void 0;
4704
+ const snapshot = {};
4705
+ if (totalTokens !== void 0) snapshot.totalTokens = totalTokens;
4706
+ if (modelContextWindow !== void 0) snapshot.modelContextWindow = modelContextWindow;
4707
+ return snapshot.totalTokens !== void 0 || snapshot.modelContextWindow !== void 0 ? snapshot : void 0;
4708
+ } catch {
4709
+ return;
4710
+ }
4711
+ }
4712
+ function resolveCodexAppServerNativeThreadTokenFuse(modelContextWindow) {
4713
+ return modelContextWindow ?? CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS;
4714
+ }
4715
+ function utf8JsonByteLength(value) {
4716
+ try {
4717
+ return Buffer.byteLength(JSON.stringify(value), "utf8");
4668
4718
  } catch {
4669
4719
  return;
4670
4720
  }
@@ -4674,10 +4724,22 @@ function maxFiniteNumber(values) {
4674
4724
  if (nums.length === 0) return;
4675
4725
  return Math.max(...nums);
4676
4726
  }
4727
+ function hasContextEngineThreadBootstrapProjection(binding) {
4728
+ return binding.contextEngine?.projection?.mode === "thread_bootstrap";
4729
+ }
4677
4730
  async function rotateOversizedCodexAppServerStartupBinding(params) {
4678
4731
  const binding = params.binding;
4679
4732
  if (!binding?.threadId) return binding;
4680
4733
  if (params.config?.agents?.defaults?.compaction?.truncateAfterCompaction !== true) return binding;
4734
+ if (params.contextEngineActive === true && hasContextEngineThreadBootstrapProjection(binding)) {
4735
+ embeddedAgentLog.debug("codex app-server deferring native transcript size guard for context-engine thread bootstrap", {
4736
+ threadId: binding.threadId,
4737
+ engineId: binding.contextEngine?.engineId,
4738
+ epoch: binding.contextEngine?.projection?.epoch,
4739
+ fingerprint: binding.contextEngine?.projection?.fingerprint
4740
+ });
4741
+ return binding;
4742
+ }
4681
4743
  const sessionRecord = await readCodexSessionRecordForSessionFile(params.sessionFile);
4682
4744
  const maxBytes = parseCodexAppServerByteLimit(params.config?.agents?.defaults?.compaction?.maxActiveTranscriptBytes);
4683
4745
  const rolloutFiles = await listCodexAppServerRolloutFilesForThread(params.agentDir, binding.threadId, params.codexHome);
@@ -4696,16 +4758,20 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
4696
4758
  return;
4697
4759
  }
4698
4760
  }
4699
- const nativeTokens = maxFiniteNumber(await Promise.all(rolloutFiles.map(async (file) => readCodexAppServerRolloutTokenUsage(file.path))));
4761
+ const nativeTokenSnapshots = await Promise.all(rolloutFiles.map(async (file) => readCodexAppServerRolloutTokenSnapshot(file.path)));
4762
+ const nativeTokens = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.totalTokens));
4763
+ const nativeModelContextWindow = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.modelContextWindow));
4764
+ const maxTokens = resolveCodexAppServerNativeThreadTokenFuse(nativeModelContextWindow);
4700
4765
  const sessionTokens = sessionRecord?.totalTokensFresh !== false && typeof sessionRecord?.totalTokens === "number" && Number.isFinite(sessionRecord.totalTokens) ? sessionRecord.totalTokens : void 0;
4701
4766
  const tokenCount = maxFiniteNumber([sessionTokens, nativeTokens]);
4702
- if (tokenCount !== void 0 && tokenCount >= CODEX_APP_SERVER_NATIVE_THREAD_MAX_TOKENS) {
4767
+ if (tokenCount !== void 0 && tokenCount >= maxTokens) {
4703
4768
  embeddedAgentLog.warn("codex app-server native transcript exceeded active token limit; starting a fresh thread", {
4704
4769
  threadId: binding.threadId,
4705
- maxTokens: CODEX_APP_SERVER_NATIVE_THREAD_MAX_TOKENS,
4770
+ maxTokens,
4706
4771
  sessionKey: sessionRecord?.sessionKey,
4707
4772
  sessionTokens,
4708
- nativeTokens
4773
+ nativeTokens,
4774
+ nativeModelContextWindow
4709
4775
  });
4710
4776
  await clearCodexAppServerBinding(params.sessionFile);
4711
4777
  return;
@@ -4724,12 +4790,24 @@ async function runCodexAgentEndHook(params, hookParams) {
4724
4790
  }
4725
4791
  async function runCodexAppServerAttempt(params, options = {}) {
4726
4792
  const attemptStartedAt = Date.now();
4793
+ const profilerEnabled = isCodexAppServerProfilerEnabled(params.config);
4794
+ const codexModelCallTrace = freezeDiagnosticTraceContext(createDiagnosticTraceContextFromActiveScope());
4795
+ const codexModelContentCapture = resolveDiagnosticModelContentCapturePolicy(params.config);
4796
+ const codexModelCallId = `${params.runId}:codex-model:1`;
4797
+ let codexModelCallStartedAt = attemptStartedAt;
4798
+ let codexModelCallStarted = false;
4799
+ let codexModelCallTerminalEmitted = false;
4800
+ let codexModelCallRequestPayloadBytes;
4801
+ const preDynamicStartupStages = createCodexDynamicToolBuildStageTracker({ enabled: profilerEnabled });
4727
4802
  const attemptClientFactory = options.clientFactory ?? defaultCodexAppServerClientFactory;
4728
4803
  const pluginConfig = readCodexPluginConfig(options.pluginConfig);
4729
4804
  const computerUseConfig = resolveCodexComputerUseConfig({ pluginConfig });
4730
4805
  const configuredAppServer = resolveCodexAppServerRuntimeOptions({ pluginConfig });
4806
+ const beforeToolCallPolicy = getBeforeToolCallPolicyDiagnosticState();
4807
+ preDynamicStartupStages.mark("config");
4731
4808
  const resolvedWorkspace = resolveUserPath(params.workspaceDir);
4732
- await fs.mkdir(resolvedWorkspace, { recursive: true });
4809
+ await ensureCodexWorkspaceDirOnce(resolvedWorkspace);
4810
+ preDynamicStartupStages.mark("workspace");
4733
4811
  const sandboxSessionKey = params.sandboxSessionKey?.trim() || params.sessionKey?.trim() || params.sessionId;
4734
4812
  const contextSessionKey = params.sessionKey?.trim() || sandboxSessionKey;
4735
4813
  const sandbox = await resolveSandboxContext({
@@ -4737,20 +4815,30 @@ async function runCodexAppServerAttempt(params, options = {}) {
4737
4815
  sessionKey: sandboxSessionKey,
4738
4816
  workspaceDir: resolvedWorkspace
4739
4817
  });
4818
+ preDynamicStartupStages.mark("sandbox");
4740
4819
  const effectiveWorkspace = sandbox?.enabled ? sandbox.workspaceAccess === "rw" ? resolvedWorkspace : sandbox.workspaceDir : resolvedWorkspace;
4741
- await fs.mkdir(effectiveWorkspace, { recursive: true });
4820
+ await ensureCodexWorkspaceDirOnce(effectiveWorkspace);
4821
+ preDynamicStartupStages.mark("effective-workspace");
4742
4822
  const appServer = resolveCodexAppServerForOpenClawToolPolicy({
4743
4823
  appServer: configuredAppServer,
4744
4824
  pluginConfig,
4745
4825
  env: process.env,
4746
- shouldPromote: hasBeforeToolCallPolicy(),
4826
+ shouldPromote: beforeToolCallPolicy.hasBeforeToolCallHook || beforeToolCallPolicy.trustedToolPolicies.length > 0,
4747
4827
  canUseUntrustedApprovalPolicy: configuredAppServer.start.transport !== "stdio" || isCodexAppServerApprovalPolicyAllowedByRequirements("untrusted")
4748
4828
  });
4829
+ if (configuredAppServer.approvalPolicy === "never" && appServer.approvalPolicy === "untrusted") embeddedAgentLog.info("codex app-server approval policy promoted for OpenClaw tool policy", {
4830
+ from: "never",
4831
+ to: "untrusted",
4832
+ beforeToolCallHook: beforeToolCallPolicy.hasBeforeToolCallHook,
4833
+ trustedToolPolicies: beforeToolCallPolicy.trustedToolPolicies
4834
+ });
4835
+ preDynamicStartupStages.mark("app-server-policy");
4749
4836
  let pluginAppServer = appServer;
4750
4837
  const nativeHookRelayEvents = resolveCodexNativeHookRelayEvents({
4751
4838
  configuredEvents: options.nativeHookRelay?.events,
4752
4839
  appServer
4753
4840
  });
4841
+ preDynamicStartupStages.mark("native-hook-relay");
4754
4842
  const runAbortController = new AbortController();
4755
4843
  const abortFromUpstream = () => {
4756
4844
  runAbortController.abort(params.abortSignal?.reason ?? "upstream_abort");
@@ -4763,15 +4851,19 @@ async function runCodexAppServerAttempt(params, options = {}) {
4763
4851
  agentId: params.agentId
4764
4852
  });
4765
4853
  const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId);
4854
+ preDynamicStartupStages.mark("session-agent");
4766
4855
  let startupBinding = await readCodexAppServerBinding(params.sessionFile);
4856
+ preDynamicStartupStages.mark("read-binding");
4767
4857
  const startupBindingAuthProfileId = startupBinding?.authProfileId;
4768
4858
  startupBinding = await rotateOversizedCodexAppServerStartupBinding({
4769
4859
  binding: startupBinding,
4770
4860
  sessionFile: params.sessionFile,
4771
4861
  agentDir,
4772
4862
  codexHome: appServer.start.env?.CODEX_HOME,
4773
- config: params.config
4863
+ config: params.config,
4864
+ contextEngineActive: isActiveHarnessContextEngine(params.contextEngine)
4774
4865
  });
4866
+ preDynamicStartupStages.mark("rotate-binding");
4775
4867
  const startupAuthProfileCandidate = params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId ?? startupBindingAuthProfileId;
4776
4868
  const startupAuthProfileId = params.authProfileStore ? resolveCodexAppServerAuthProfileId({
4777
4869
  authProfileId: startupAuthProfileCandidate,
@@ -4782,6 +4874,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
4782
4874
  agentDir,
4783
4875
  config: params.config
4784
4876
  });
4877
+ preDynamicStartupStages.mark("auth-profile");
4785
4878
  const runtimeParams = {
4786
4879
  ...params,
4787
4880
  sessionKey: contextSessionKey,
@@ -4794,22 +4887,20 @@ async function runCodexAppServerAttempt(params, options = {}) {
4794
4887
  sessionId: activeSessionId,
4795
4888
  sessionFile: activeSessionFile
4796
4889
  });
4797
- const adoptContextEngineCompactionTranscript = (compactResult) => {
4798
- if (compactResult.result?.sessionId) activeSessionId = compactResult.result.sessionId;
4799
- if (compactResult.result?.sessionFile) activeSessionFile = compactResult.result.sessionFile;
4800
- };
4801
4890
  const startupAuthAccountCacheKey = await resolveCodexAppServerAuthAccountCacheKey({
4802
4891
  authProfileId: startupAuthProfileId,
4803
4892
  authProfileStore: params.authProfileStore,
4804
4893
  agentDir,
4805
4894
  config: params.config
4806
4895
  });
4807
- const startupEnvApiKeyCacheKey = startupAuthProfileId ? void 0 : resolveCodexAppServerEnvApiKeyCacheKey({ startOptions: appServer.start });
4896
+ const startupEnvApiKeyCacheKey = startupAuthProfileId ? void 0 : resolveCodexAppServerFallbackApiKeyCacheKey({ startOptions: appServer.start });
4897
+ preDynamicStartupStages.mark("auth-cache");
4808
4898
  const nodeExecBlocksNativeExecution = isCodexNativeExecutionBlockedByNodeExecHost(params, {
4809
4899
  agentId: sessionAgentId,
4810
4900
  runtimeSessionKey: sandboxSessionKey,
4811
4901
  sandbox
4812
4902
  });
4903
+ preDynamicStartupStages.mark("native-exec-policy");
4813
4904
  const bundleMcpThreadConfig = await loadCodexBundleMcpThreadConfig({
4814
4905
  workspaceDir: effectiveWorkspace,
4815
4906
  cfg: params.config,
@@ -4817,12 +4908,14 @@ async function runCodexAppServerAttempt(params, options = {}) {
4817
4908
  disableTools: params.disableTools,
4818
4909
  toolsAllow: nodeExecBlocksNativeExecution ? [] : params.toolsAllow
4819
4910
  });
4911
+ preDynamicStartupStages.mark("bundle-mcp");
4820
4912
  const sandboxExecServerEnabled = isCodexSandboxExecServerEnabled(pluginConfig);
4821
4913
  const nativeToolSurfaceEnabled = shouldEnableCodexAppServerNativeToolSurface(params, sandbox, {
4822
4914
  agentId: sessionAgentId,
4823
4915
  runtimeSessionKey: sandboxSessionKey,
4824
4916
  sandboxExecServerEnabled
4825
4917
  });
4918
+ preDynamicStartupStages.mark("native-tool-surface");
4826
4919
  for (const diagnostic of bundleMcpThreadConfig.diagnostics) embeddedAgentLog.warn(`bundle-mcp: ${diagnostic.pluginId}: ${diagnostic.message}`);
4827
4920
  const activeContextEngine = isActiveHarnessContextEngine(params.contextEngine) ? params.contextEngine : void 0;
4828
4921
  if (activeContextEngine) assertContextEngineHostSupport({
@@ -4831,22 +4924,36 @@ async function runCodexAppServerAttempt(params, options = {}) {
4831
4924
  host: CODEX_APP_SERVER_CONTEXT_ENGINE_HOST
4832
4925
  });
4833
4926
  const hookChannelId = resolveCodexAppServerHookChannelId(params, sandboxSessionKey);
4927
+ preDynamicStartupStages.mark("context-engine-support");
4928
+ const preDynamicSummary = preDynamicStartupStages.snapshot();
4929
+ if (shouldWarnCodexDynamicToolBuildStageSummary(preDynamicSummary)) embeddedAgentLog.warn(`codex app-server pre-dynamic startup timings runId=${params.runId} sessionId=${params.sessionId} totalMs=${preDynamicSummary.totalMs} stages=${formatCodexDynamicToolBuildStageSummary(preDynamicSummary)}`, {
4930
+ runId: params.runId,
4931
+ sessionId: params.sessionId,
4932
+ totalMs: preDynamicSummary.totalMs,
4933
+ stages: preDynamicSummary.stages,
4934
+ hasStartupBinding: Boolean(startupBinding?.threadId),
4935
+ startupAuthProfileId: startupAuthProfileId ?? null,
4936
+ bundleMcpDiagnosticCount: bundleMcpThreadConfig.diagnostics.length,
4937
+ nativeToolSurfaceEnabled
4938
+ });
4834
4939
  let yieldDetected = false;
4940
+ const tools = await buildDynamicTools({
4941
+ params,
4942
+ resolvedWorkspace,
4943
+ effectiveWorkspace,
4944
+ sandboxSessionKey,
4945
+ sandbox,
4946
+ nativeToolSurfaceEnabled,
4947
+ runAbortController,
4948
+ sessionAgentId,
4949
+ pluginConfig,
4950
+ profilerEnabled,
4951
+ onYieldDetected: () => {
4952
+ yieldDetected = true;
4953
+ }
4954
+ });
4835
4955
  const toolBridge = createCodexDynamicToolBridge({
4836
- tools: await buildDynamicTools({
4837
- params,
4838
- resolvedWorkspace,
4839
- effectiveWorkspace,
4840
- sandboxSessionKey,
4841
- sandbox,
4842
- nativeToolSurfaceEnabled,
4843
- runAbortController,
4844
- sessionAgentId,
4845
- pluginConfig,
4846
- onYieldDetected: () => {
4847
- yieldDetected = true;
4848
- }
4849
- }),
4956
+ tools,
4850
4957
  registeredTools: await buildDynamicTools({
4851
4958
  params,
4852
4959
  resolvedWorkspace,
@@ -4857,6 +4964,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
4857
4964
  runAbortController,
4858
4965
  sessionAgentId,
4859
4966
  pluginConfig,
4967
+ profilerEnabled,
4860
4968
  forceHeartbeatTool: true,
4861
4969
  ignoreRuntimePlan: true,
4862
4970
  onYieldDetected: () => {
@@ -4902,65 +5010,6 @@ async function runCodexAppServerAttempt(params, options = {}) {
4902
5010
  contextEnginePluginId: activeContextEnginePluginId,
4903
5011
  tokenBudget: params.contextTokenBudget
4904
5012
  });
4905
- const forceContextEngineCompactionForCodexOverflow = async (error, options = {}) => {
4906
- if (!activeContextEngine?.info.ownsCompaction) return false;
4907
- embeddedAgentLog.warn("codex app-server context-engine prompt overflowed; forcing context-engine compaction", {
4908
- sessionId: activeSessionId,
4909
- sessionKey: contextSessionKey,
4910
- ...options.threadId ? { threadId: options.threadId } : {},
4911
- engineId: activeContextEngine.info.id,
4912
- tokenBudget: params.contextTokenBudget,
4913
- error: formatErrorMessage(error)
4914
- });
4915
- try {
4916
- const runtimeContext = buildActiveContextEngineRuntimeContext();
4917
- const overflowTokenCount = params.contextTokenBudget ?? params.contextWindowInfo?.tokens;
4918
- const compactResult = await compactContextEngineWithSafetyTimeout(activeContextEngine, {
4919
- sessionId: activeSessionId,
4920
- sessionKey: contextSessionKey,
4921
- sessionFile: activeSessionFile,
4922
- tokenBudget: params.contextTokenBudget,
4923
- force: true,
4924
- ...overflowTokenCount ? { currentTokenCount: overflowTokenCount } : {},
4925
- compactionTarget: "threshold",
4926
- runtimeContext: overflowTokenCount ? {
4927
- ...runtimeContext,
4928
- currentTokenCount: overflowTokenCount
4929
- } : runtimeContext
4930
- }, resolveCompactionTimeoutMs(params.config), runAbortController.signal);
4931
- embeddedAgentLog.info("codex app-server context-engine forced compaction result", {
4932
- sessionId: activeSessionId,
4933
- sessionKey: contextSessionKey,
4934
- engineId: activeContextEngine.info.id,
4935
- ok: compactResult.ok,
4936
- compacted: compactResult.compacted,
4937
- reason: compactResult.reason,
4938
- tokensBefore: compactResult.result?.tokensBefore,
4939
- tokensAfter: compactResult.result?.tokensAfter
4940
- });
4941
- if (!compactResult.ok || !compactResult.compacted) return false;
4942
- adoptContextEngineCompactionTranscript(compactResult);
4943
- const maintenanceRuntimeContext = buildActiveContextEngineRuntimeContext();
4944
- await runHarnessContextEngineMaintenance({
4945
- contextEngine: activeContextEngine,
4946
- sessionId: activeSessionId,
4947
- sessionKey: contextSessionKey,
4948
- sessionFile: activeSessionFile,
4949
- reason: "compaction",
4950
- runtimeContext: maintenanceRuntimeContext,
4951
- config: params.config
4952
- });
4953
- return true;
4954
- } catch (compactErr) {
4955
- embeddedAgentLog.warn("codex app-server context-engine forced compaction failed", {
4956
- sessionId: params.sessionId,
4957
- sessionKey: contextSessionKey,
4958
- engineId: activeContextEngine.info.id,
4959
- error: formatErrorMessage(compactErr)
4960
- });
4961
- return false;
4962
- }
4963
- };
4964
5013
  if (activeContextEngine) {
4965
5014
  await bootstrapHarnessContextEngine({
4966
5015
  hadSessionFile,
@@ -4992,12 +5041,6 @@ async function runCodexAppServerAttempt(params, options = {}) {
4992
5041
  let developerInstructions = baseDeveloperInstructions;
4993
5042
  let prePromptMessageCount = historyMessages.length;
4994
5043
  let contextEngineProjection;
4995
- const resetCodexPromptInputs = () => {
4996
- promptText = params.prompt;
4997
- developerInstructions = baseDeveloperInstructions;
4998
- prePromptMessageCount = historyMessages.length;
4999
- contextEngineProjection = void 0;
5000
- };
5001
5044
  const applyActiveContextEngineProjection = async (decisionStartupBinding) => {
5002
5045
  if (!activeContextEngine) return;
5003
5046
  const assembled = await assembleHarnessContextEngine({
@@ -5082,78 +5125,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
5082
5125
  let promptBuild = await buildPromptFromCurrentInputs();
5083
5126
  const decorateCodexTurnPromptText = (prompt) => prependCodexOpenClawPromptContext(prompt, openClawPromptContext);
5084
5127
  let codexTurnPromptText = decorateCodexTurnPromptText(promptBuild.prompt);
5085
- const refreshCodexTurnPromptText = () => {
5086
- codexTurnPromptText = decorateCodexTurnPromptText(promptBuild.prompt);
5087
- };
5088
5128
  const buildCodexTurnCollaborationDeveloperInstructions = () => buildTurnCollaborationMode(params, {
5089
5129
  turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
5090
5130
  heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
5091
5131
  }).settings.developer_instructions ?? void 0;
5092
5132
  const buildRenderedCodexDeveloperInstructions = () => joinPresentSections(promptBuild.developerInstructions, buildCodexTurnCollaborationDeveloperInstructions());
5093
- const rebuildPromptAfterContextEngineCompaction = async () => {
5094
- historyMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? historyMessages;
5095
- resetCodexPromptInputs();
5096
- try {
5097
- await applyActiveContextEngineProjection(void 0);
5098
- } catch (assembleErr) {
5099
- embeddedAgentLog.warn("context engine assemble failed after forced compaction; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
5100
- }
5101
- promptBuild = await buildPromptFromCurrentInputs();
5102
- refreshCodexTurnPromptText();
5103
- };
5104
- const buildCodexProviderBoundaryPrecheck = () => {
5105
- const contextTokenBudget = typeof params.contextTokenBudget === "number" && Number.isFinite(params.contextTokenBudget) ? Math.floor(params.contextTokenBudget) : typeof params.contextWindowInfo?.tokens === "number" && Number.isFinite(params.contextWindowInfo.tokens) ? Math.floor(params.contextWindowInfo.tokens) : void 0;
5106
- if (!contextTokenBudget || contextTokenBudget <= 0) return;
5107
- const reserveTokens = resolveCodexContextEngineProjectionReserveTokens({ config: params.config }) ?? 2e4;
5108
- const renderedDeveloperInstructions = buildRenderedCodexDeveloperInstructions();
5109
- const renderedChars = codexTurnPromptText.length + renderedDeveloperInstructions.length;
5110
- return shouldPreemptivelyCompactBeforePrompt({
5111
- messages: historyMessages,
5112
- systemPrompt: renderedDeveloperInstructions,
5113
- prompt: codexTurnPromptText,
5114
- contextTokenBudget,
5115
- reserveTokens,
5116
- llmBoundaryTokenPressure: {
5117
- estimatedPromptTokens: estimateRenderedLlmBoundaryTokenPressure({
5118
- systemPrompt: renderedDeveloperInstructions,
5119
- prompt: codexTurnPromptText
5120
- }),
5121
- source: "codex_app_server_rendered_prompt",
5122
- renderedChars
5123
- }
5124
- });
5125
- };
5126
- const maybeCompactContextEngineForProviderBoundaryPrecheck = async () => {
5127
- if (!activeContextEngine?.info.ownsCompaction || !contextEngineProjection) return;
5128
- const precheck = buildCodexProviderBoundaryPrecheck();
5129
- if (!precheck) return;
5130
- embeddedAgentLog.debug(formatPrePromptPrecheckLog({
5131
- result: precheck,
5132
- provider: params.provider,
5133
- modelId: params.modelId,
5134
- messageCount: historyMessages.length,
5135
- contextTokenBudget: typeof params.contextTokenBudget === "number" ? params.contextTokenBudget : params.contextWindowInfo?.tokens ?? 0,
5136
- reserveTokens: resolveCodexContextEngineProjectionReserveTokens({ config: params.config }) ?? 2e4,
5137
- ...contextSessionKey ? { sessionKey: contextSessionKey } : {},
5138
- ...activeSessionId ? { sessionId: activeSessionId } : {},
5139
- ...activeSessionFile ? { sessionFile: activeSessionFile } : {}
5140
- }));
5141
- if (precheck.route === "fits") return;
5142
- if (!await forceContextEngineCompactionForCodexOverflow(PREEMPTIVE_OVERFLOW_ERROR_TEXT)) throw new Error(PREEMPTIVE_OVERFLOW_ERROR_TEXT);
5143
- await rebuildPromptAfterContextEngineCompaction();
5144
- const afterCompactionPrecheck = buildCodexProviderBoundaryPrecheck();
5145
- if (!afterCompactionPrecheck || afterCompactionPrecheck.route === "fits") return;
5146
- embeddedAgentLog.warn("codex app-server provider-boundary precheck still overflowed after compaction", {
5147
- sessionId: activeSessionId,
5148
- sessionKey: contextSessionKey,
5149
- route: afterCompactionPrecheck.route,
5150
- estimatedPromptTokens: afterCompactionPrecheck.estimatedPromptTokens,
5151
- promptBudgetBeforeReserve: afterCompactionPrecheck.promptBudgetBeforeReserve,
5152
- overflowTokens: afterCompactionPrecheck.overflowTokens
5153
- });
5154
- throw new Error(PREEMPTIVE_OVERFLOW_ERROR_TEXT);
5155
- };
5156
- await maybeCompactContextEngineForProviderBoundaryPrecheck();
5157
5133
  const systemPromptReport = buildCodexSystemPromptReport({
5158
5134
  attempt: params,
5159
5135
  sessionKey: contextSessionKey,
@@ -5916,7 +5892,9 @@ async function runCodexAppServerAttempt(params, options = {}) {
5916
5892
  ...turnId ? { turnId } : {}
5917
5893
  });
5918
5894
  embeddedAgentLog.debug("codex app-server raw notification received", correlation);
5919
- if (notification.method === "turn/completed" && correlation.matchesActiveTurn === false) embeddedAgentLog.warn("codex app-server turn/completed did not match active turn", correlation);
5895
+ if (notification.method === "turn/completed" && correlation.matchesActiveTurn === false) if (correlation.matchesActiveThread) embeddedAgentLog.warn("codex app-server turn/completed did not match active turn", correlation);
5896
+ else embeddedAgentLog.debug("codex app-server turn/completed ignored for other subscribed thread", correlation);
5897
+ if (isCodexNotificationOutsideActiveRun(correlation)) return Promise.resolve();
5920
5898
  if (!projector || !turnId) {
5921
5899
  userInputBridge?.handleNotification(notification);
5922
5900
  pendingNotifications.push(notification);
@@ -5990,6 +5968,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
5990
5968
  threadId: thread.threadId,
5991
5969
  turnId,
5992
5970
  nativeHookRelay,
5971
+ autoApprove: shouldAutoApproveCodexAppServerApprovals(appServer),
5993
5972
  signal: runAbortController.signal
5994
5973
  });
5995
5974
  }
@@ -6083,22 +6062,26 @@ async function runCodexAppServerAttempt(params, options = {}) {
6083
6062
  projector?.recordDynamicToolResult({
6084
6063
  callId: call.callId,
6085
6064
  tool: call.tool,
6065
+ asyncStarted: response.asyncStarted === true,
6086
6066
  success: protocolResponse.success,
6087
6067
  terminalType: response.diagnosticTerminalType ?? (protocolResponse.success ? "completed" : "error"),
6088
6068
  sideEffectEvidence: response.sideEffectEvidence === true,
6089
6069
  contentItems: protocolResponse.contentItems
6090
6070
  });
6091
- if (shouldEmitDynamicToolProgress) emitCodexAppServerEvent(params, {
6092
- stream: "tool",
6093
- data: {
6094
- phase: "result",
6095
- name: call.tool,
6096
- toolCallId: call.callId,
6097
- ...toolMeta ? { meta: toolMeta } : {},
6098
- isError: !protocolResponse.success,
6099
- result: sanitizeCodexToolResponse(protocolResponse)
6100
- }
6101
- });
6071
+ if (shouldEmitDynamicToolProgress) {
6072
+ const progressResponse = toCodexDynamicToolProgressResponse(response, protocolResponse);
6073
+ emitCodexAppServerEvent(params, {
6074
+ stream: "tool",
6075
+ data: {
6076
+ phase: "result",
6077
+ name: call.tool,
6078
+ toolCallId: call.callId,
6079
+ ...toolMeta ? { meta: toolMeta } : {},
6080
+ isError: !protocolResponse.success,
6081
+ result: sanitizeCodexToolResponse(progressResponse)
6082
+ }
6083
+ });
6084
+ }
6102
6085
  if (!terminalDiagnosticObserved && !hasPendingDynamicToolTerminalDiagnostic({
6103
6086
  call,
6104
6087
  runId: params.runId,
@@ -6161,27 +6144,99 @@ async function runCodexAppServerAttempt(params, options = {}) {
6161
6144
  systemPrompt: buildRenderedCodexDeveloperInstructions(),
6162
6145
  prompt: codexTurnPromptText,
6163
6146
  historyMessages,
6164
- imagesCount: params.images?.length ?? 0
6147
+ imagesCount: params.images?.length ?? 0,
6148
+ tools
6165
6149
  });
6166
6150
  const buildTurnStartFailureMessages = () => [...historyMessages, buildCodexUserPromptMessage({
6167
6151
  ...params,
6168
6152
  prompt: codexTurnPromptText
6169
6153
  })];
6154
+ const codexModelCallBaseFields = {
6155
+ runId: params.runId,
6156
+ callId: codexModelCallId,
6157
+ ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
6158
+ sessionId: params.sessionId,
6159
+ provider: params.provider,
6160
+ model: params.modelId,
6161
+ api: params.model.api,
6162
+ transport: appServer.start.transport,
6163
+ ...hookContextWindowFields,
6164
+ trace: codexModelCallTrace
6165
+ };
6166
+ const codexDiagnosticToolDefinitions = codexModelContentCapture.toolDefinitions ? buildCodexDiagnosticToolDefinitions(tools) : void 0;
6167
+ const codexModelContentPrivateData = (modelContent) => modelContent && Object.keys(modelContent).length > 0 ? { modelContent } : void 0;
6168
+ const buildCodexModelCallDiagnosticContent = () => {
6169
+ const modelContent = {
6170
+ ...codexModelContentCapture.inputMessages ? { inputMessages: buildTurnStartFailureMessages() } : {},
6171
+ ...codexModelContentCapture.systemPrompt ? { systemPrompt: buildRenderedCodexDeveloperInstructions() } : {},
6172
+ ...codexDiagnosticToolDefinitions ? { toolDefinitions: codexDiagnosticToolDefinitions } : {}
6173
+ };
6174
+ return Object.keys(modelContent).length > 0 ? modelContent : void 0;
6175
+ };
6176
+ const emitCodexModelCallStarted = () => {
6177
+ codexModelCallStartedAt = Date.now();
6178
+ codexModelCallStarted = true;
6179
+ emitTrustedDiagnosticEventWithPrivateData({
6180
+ type: "model.call.started",
6181
+ ...codexModelCallBaseFields
6182
+ }, codexModelContentPrivateData(buildCodexModelCallDiagnosticContent()));
6183
+ };
6184
+ const emitCodexModelCallCompleted = (result) => {
6185
+ if (!codexModelCallStarted || codexModelCallTerminalEmitted) return;
6186
+ codexModelCallTerminalEmitted = true;
6187
+ emitTrustedDiagnosticEventWithPrivateData({
6188
+ type: "model.call.completed",
6189
+ ...codexModelCallBaseFields,
6190
+ durationMs: Math.max(0, Date.now() - codexModelCallStartedAt),
6191
+ ...codexModelCallRequestPayloadBytes !== void 0 ? { requestPayloadBytes: codexModelCallRequestPayloadBytes } : {}
6192
+ }, codexModelContentPrivateData({
6193
+ ...buildCodexModelCallDiagnosticContent(),
6194
+ ...codexModelContentCapture.outputMessages ? { outputMessages: result.lastAssistant ? [result.lastAssistant] : result.assistantTexts } : {}
6195
+ }));
6196
+ };
6197
+ const emitCodexModelCallError = (error, fields = {}) => {
6198
+ if (!codexModelCallStarted || codexModelCallTerminalEmitted) return;
6199
+ codexModelCallTerminalEmitted = true;
6200
+ emitTrustedDiagnosticEventWithPrivateData({
6201
+ type: "model.call.error",
6202
+ ...codexModelCallBaseFields,
6203
+ durationMs: Math.max(0, Date.now() - codexModelCallStartedAt),
6204
+ errorCategory: fields.failureKind ?? "error",
6205
+ ...fields.failureKind ? { failureKind: fields.failureKind } : {},
6206
+ ...codexModelCallRequestPayloadBytes !== void 0 ? { requestPayloadBytes: codexModelCallRequestPayloadBytes } : {}
6207
+ }, codexModelContentPrivateData({
6208
+ ...buildCodexModelCallDiagnosticContent(),
6209
+ ...codexModelContentCapture.outputMessages ? { outputMessages: [] } : {}
6210
+ }));
6211
+ embeddedAgentLog.debug("codex app-server model call diagnostic ended with error", { error: formatErrorMessage(error) });
6212
+ };
6213
+ const classifyCodexModelCallFailureKind = (error) => {
6214
+ if (timedOut || turnCompletionIdleTimedOut) return "timeout";
6215
+ const errorMessage = error ? formatErrorMessage(error).toLowerCase() : "";
6216
+ if (errorMessage.includes("timed out") || errorMessage.includes("timeout")) return "timeout";
6217
+ if (runAbortController.signal.aborted && !clientClosedAbort) return String(runAbortController.signal.reason ?? "").toLowerCase().includes("timeout") ? "timeout" : "aborted";
6218
+ return errorMessage.includes("aborted") ? "aborted" : void 0;
6219
+ };
6170
6220
  let turn;
6171
- const startCodexTurn = async () => assertCodexTurnStartResponse(await client.request("turn/start", buildTurnStartParams(params, {
6172
- threadId: thread.threadId,
6173
- cwd: codexExecutionCwd,
6174
- appServer: pluginAppServer,
6175
- promptText: codexTurnPromptText,
6176
- sandboxPolicy: codexSandboxPolicy,
6177
- environmentSelection: codexEnvironmentSelection,
6178
- turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
6179
- heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
6180
- }), {
6181
- timeoutMs: params.timeoutMs,
6182
- signal: runAbortController.signal
6183
- }));
6221
+ const startCodexTurn = async () => {
6222
+ const turnStartParams = buildTurnStartParams(params, {
6223
+ threadId: thread.threadId,
6224
+ cwd: codexExecutionCwd,
6225
+ appServer: pluginAppServer,
6226
+ promptText: codexTurnPromptText,
6227
+ sandboxPolicy: codexSandboxPolicy,
6228
+ environmentSelection: codexEnvironmentSelection,
6229
+ turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
6230
+ heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
6231
+ });
6232
+ codexModelCallRequestPayloadBytes = utf8JsonByteLength(turnStartParams);
6233
+ return assertCodexTurnStartResponse(await client.request("turn/start", turnStartParams, {
6234
+ timeoutMs: params.timeoutMs,
6235
+ signal: runAbortController.signal
6236
+ }));
6237
+ };
6184
6238
  try {
6239
+ emitCodexModelCallStarted();
6185
6240
  runAgentHarnessLlmInputHook({
6186
6241
  event: buildLlmInputEvent(),
6187
6242
  ctx: hookContext
@@ -6207,10 +6262,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
6207
6262
  });
6208
6263
  try {
6209
6264
  const preRetrySessionFile = activeSessionFile;
6210
- const compactedForRetry = await forceContextEngineCompactionForCodexOverflow(turnStartError, { threadId: thread.threadId });
6211
6265
  await clearCodexAppServerBinding(preRetrySessionFile);
6212
6266
  if (activeSessionFile !== preRetrySessionFile) await clearCodexAppServerBinding(activeSessionFile);
6213
- if (compactedForRetry) await rebuildPromptAfterContextEngineCompaction();
6214
6267
  thread = await restartContextEngineCodexThread();
6215
6268
  emitCodexAppServerEvent(params, {
6216
6269
  stream: "codex_app_server.lifecycle",
@@ -6270,6 +6323,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
6270
6323
  },
6271
6324
  ctx: hookContext
6272
6325
  });
6326
+ const turnStartFailureKind = classifyCodexModelCallFailureKind(turnStartError);
6327
+ emitCodexModelCallError(turnStartErrorMessage, turnStartFailureKind ? { failureKind: turnStartFailureKind } : {});
6273
6328
  await runCodexAgentEndHook(params, {
6274
6329
  event: {
6275
6330
  messages: buildTurnStartFailureMessages(),
@@ -6303,12 +6358,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
6303
6358
  authProfileId: startupAuthProfileId,
6304
6359
  rateLimits: usageLimitError.rateLimitsForProfile
6305
6360
  });
6306
- return buildCodexTurnStartFailureResult({
6361
+ return { ...buildCodexTurnStartFailureResult({
6307
6362
  params,
6308
6363
  message: usageLimitError.message,
6309
6364
  messagesSnapshot: buildTurnStartFailureMessages(),
6310
6365
  systemPromptReport
6311
- });
6366
+ }) };
6312
6367
  }
6313
6368
  throw turnStartError;
6314
6369
  }
@@ -6380,24 +6435,26 @@ async function runCodexAppServerAttempt(params, options = {}) {
6380
6435
  queueMessage: async (text, options) => activeSteeringQueue.queue(text, options),
6381
6436
  isStreaming: () => !completed,
6382
6437
  isCompacting: () => projector?.isCompacting() ?? false,
6438
+ sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
6383
6439
  cancel: () => runAbortController.abort("cancelled"),
6384
6440
  abort: () => runAbortController.abort("aborted")
6385
6441
  };
6386
6442
  setActiveEmbeddedRun(params.sessionId, handle, params.sessionKey);
6443
+ mirrorPromptAtTurnStartBestEffort({
6444
+ params,
6445
+ agentId: sessionAgentId,
6446
+ sessionKey: sandboxSessionKey,
6447
+ threadId: thread.threadId,
6448
+ turnId: activeTurnId
6449
+ });
6387
6450
  turnAttemptIdleWatchArmed = true;
6388
6451
  turnTerminalIdleWatchArmed = true;
6389
6452
  touchTurnCompletionActivity("turn:start", { attemptProgress: true });
6390
6453
  const abortListener = () => {
6391
- const shouldRetireClient = timedOut;
6392
6454
  interruptCodexTurnBestEffort(client, {
6393
6455
  threadId: thread.threadId,
6394
6456
  turnId: activeTurnId,
6395
- timeoutMs: shouldRetireClient ? CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS : void 0
6396
- });
6397
- if (shouldRetireClient) retireCodexAppServerClientAfterTimedOutTurn(client, {
6398
- threadId: thread.threadId,
6399
- turnId: activeTurnId,
6400
- reason: String(runAbortController.signal.reason ?? "timeout")
6457
+ timeoutMs: timedOut ? CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS : void 0
6401
6458
  });
6402
6459
  resolveCompletion?.();
6403
6460
  };
@@ -6432,6 +6489,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
6432
6489
  result,
6433
6490
  turnCompletionIdleTimedOut
6434
6491
  });
6492
+ const modelCallFailureKind = classifyCodexModelCallFailureKind(finalPromptError) ?? (finalAborted ? "aborted" : void 0);
6493
+ if (modelCallFailureKind) emitCodexModelCallError(finalPromptError ?? "codex app-server attempt interrupted", { failureKind: modelCallFailureKind });
6494
+ else if (finalPromptError) emitCodexModelCallError(finalPromptError);
6495
+ else emitCodexModelCallCompleted(result);
6435
6496
  recordCodexTrajectoryCompletion(trajectoryRecorder, {
6436
6497
  attempt: params,
6437
6498
  result,
@@ -6542,6 +6603,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
6542
6603
  systemPromptReport
6543
6604
  };
6544
6605
  } finally {
6606
+ emitCodexModelCallError("codex app-server run completed without model-call terminal event");
6545
6607
  emitLifecycleTerminal({
6546
6608
  phase: "error",
6547
6609
  error: "codex app-server run completed without lifecycle terminal event"
@@ -6717,6 +6779,16 @@ function toCodexDynamicToolProtocolResponse(response) {
6717
6779
  success: response.success
6718
6780
  };
6719
6781
  }
6782
+ function toCodexDynamicToolProgressResponse(response, protocolResponse) {
6783
+ if (response.asyncStarted !== true) return protocolResponse;
6784
+ return {
6785
+ ...protocolResponse,
6786
+ details: {
6787
+ async: true,
6788
+ status: "started"
6789
+ }
6790
+ };
6791
+ }
6720
6792
  function shouldReleaseTurnAfterTerminalDynamicTool(state) {
6721
6793
  return !state.completed && !state.aborted && state.responseSuccess && !state.currentTurnHadNonTerminalDynamicToolResult && state.activeAppServerTurnRequests === 0 && state.activeTurnItemIdsCount === 0 && state.pendingOpenClawDynamicToolCompletionIdsCount === 0;
6722
6794
  }
@@ -6797,7 +6869,10 @@ function createCodexNativeHookRelay(params) {
6797
6869
  turnStartTimeoutMs: params.turnStartTimeoutMs
6798
6870
  }),
6799
6871
  signal: params.signal,
6800
- command: { timeoutMs: params.options?.gatewayTimeoutMs }
6872
+ command: {
6873
+ nice: 10,
6874
+ timeoutMs: params.options?.gatewayTimeoutMs
6875
+ }
6801
6876
  });
6802
6877
  }
6803
6878
  function resolveCodexNativeHookRelayEvents(params) {
@@ -6865,19 +6940,6 @@ async function unsubscribeCodexThreadBestEffort(client, params) {
6865
6940
  });
6866
6941
  }
6867
6942
  }
6868
- function retireCodexAppServerClientAfterTimedOutTurn(client, params) {
6869
- const clearedSharedClient = clearSharedCodexAppServerClientIfCurrent(client);
6870
- if (!clearedSharedClient) {
6871
- const close = client.close;
6872
- if (typeof close === "function") close.call(client);
6873
- }
6874
- embeddedAgentLog.warn("codex app-server client retired after timed-out turn", {
6875
- threadId: params.threadId,
6876
- turnId: params.turnId,
6877
- reason: params.reason,
6878
- clearedSharedClient
6879
- });
6880
- }
6881
6943
  function resolveOpenClawCodingToolsSessionKeys(params, sandboxSessionKey) {
6882
6944
  return {
6883
6945
  sessionKey: sandboxSessionKey,
@@ -6893,12 +6955,54 @@ function resolveCodexAppServerHookChannelId(params, sandboxSessionKey) {
6893
6955
  messageTo: params.messageTo
6894
6956
  }).channelId;
6895
6957
  }
6958
+ const CODEX_DYNAMIC_TOOL_BUILD_WARN_TOTAL_MS = 1e3;
6959
+ const CODEX_DYNAMIC_TOOL_BUILD_WARN_STAGE_MS = 500;
6960
+ function createCodexDynamicToolBuildStageTracker(options = {}) {
6961
+ if (!options.enabled) return {
6962
+ mark() {},
6963
+ snapshot() {
6964
+ return {
6965
+ totalMs: 0,
6966
+ stages: []
6967
+ };
6968
+ }
6969
+ };
6970
+ const startedAt = Date.now();
6971
+ let previousAt = startedAt;
6972
+ const stages = [];
6973
+ const toMs = (value) => Math.max(0, Math.round(value));
6974
+ return {
6975
+ mark(name) {
6976
+ const currentAt = Date.now();
6977
+ stages.push({
6978
+ name,
6979
+ durationMs: toMs(currentAt - previousAt),
6980
+ elapsedMs: toMs(currentAt - startedAt)
6981
+ });
6982
+ previousAt = currentAt;
6983
+ },
6984
+ snapshot() {
6985
+ return {
6986
+ totalMs: toMs(Date.now() - startedAt),
6987
+ stages: stages.slice()
6988
+ };
6989
+ }
6990
+ };
6991
+ }
6992
+ function shouldWarnCodexDynamicToolBuildStageSummary(summary) {
6993
+ return summary.totalMs >= CODEX_DYNAMIC_TOOL_BUILD_WARN_TOTAL_MS || summary.stages.some((stage) => stage.durationMs >= CODEX_DYNAMIC_TOOL_BUILD_WARN_STAGE_MS);
6994
+ }
6995
+ function formatCodexDynamicToolBuildStageSummary(summary) {
6996
+ return summary.stages.length > 0 ? summary.stages.map((stage) => `${stage.name}:${stage.durationMs}ms@${stage.elapsedMs}ms`).join(",") : "none";
6997
+ }
6896
6998
  async function buildDynamicTools(input) {
6897
6999
  const { params } = input;
6898
7000
  if (params.disableTools || !supportsModelTools(params.model)) return [];
7001
+ const toolBuildStages = createCodexDynamicToolBuildStageTracker({ enabled: input.profilerEnabled });
6899
7002
  const modelHasVision = params.model.input?.includes("image") ?? false;
6900
7003
  const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, input.sessionAgentId);
6901
7004
  const createOpenClawCodingTools = (await import("openclaw/plugin-sdk/agent-harness")).createOpenClawCodingTools;
7005
+ toolBuildStages.mark("load-agent-harness-tools");
6902
7006
  const sessionKeys = resolveOpenClawCodingToolsSessionKeys(params, input.sandboxSessionKey);
6903
7007
  const allTools = createOpenClawCodingTools({
6904
7008
  agentId: input.sessionAgentId,
@@ -6963,13 +7067,22 @@ async function buildDynamicTools(input) {
6963
7067
  message
6964
7068
  }
6965
7069
  });
7070
+ },
7071
+ recordToolPrepStage: (name) => {
7072
+ toolBuildStages.mark(name);
6966
7073
  }
6967
7074
  });
6968
- const filteredTools = filterCodexDynamicToolsForAllowlist(filterToolsForVisionInputs(addNodeShellDynamicToolsIfNeeded(addSandboxShellDynamicToolsIfAvailable(isCodexMemoryFlushRun(params) ? filterCodexMemoryFlushDynamicTools(allTools) : filterCodexDynamicTools(allTools, input.pluginConfig), allTools, input), allTools, input), {
7075
+ toolBuildStages.mark("create-openclaw-coding-tools");
7076
+ const codexFilteredTools = addNodeShellDynamicToolsIfNeeded(addSandboxShellDynamicToolsIfAvailable(isCodexMemoryFlushRun(params) ? filterCodexMemoryFlushDynamicTools(allTools) : filterCodexDynamicTools(allTools, input.pluginConfig), allTools, input), allTools, input);
7077
+ toolBuildStages.mark("codex-filtering");
7078
+ const visionFilteredTools = filterToolsForVisionInputs(codexFilteredTools, {
6969
7079
  modelHasVision,
6970
7080
  hasInboundImages: (params.images?.length ?? 0) > 0
6971
- }), includeForcedCodexDynamicToolAllow(params.toolsAllow, params));
6972
- return normalizeAgentRuntimeTools({
7081
+ });
7082
+ toolBuildStages.mark("vision-filtering");
7083
+ const filteredTools = filterCodexDynamicToolsForAllowlist(visionFilteredTools, includeForcedCodexDynamicToolAllow(params.toolsAllow, params));
7084
+ toolBuildStages.mark("allowlist-filter");
7085
+ const normalizedTools = normalizeAgentRuntimeTools({
6973
7086
  runtimePlan: input.ignoreRuntimePlan ? void 0 : params.runtimePlan,
6974
7087
  tools: filteredTools,
6975
7088
  provider: params.provider,
@@ -6980,6 +7093,27 @@ async function buildDynamicTools(input) {
6980
7093
  modelApi: params.model.api,
6981
7094
  model: params.model
6982
7095
  });
7096
+ toolBuildStages.mark("runtime-normalization");
7097
+ const summary = toolBuildStages.snapshot();
7098
+ if (shouldWarnCodexDynamicToolBuildStageSummary(summary)) {
7099
+ const phase = input.forceHeartbeatTool ? "registered-tools" : "runtime-tools";
7100
+ embeddedAgentLog.warn(`codex app-server dynamic tool build timings runId=${params.runId} sessionId=${params.sessionId} phase=${phase} totalMs=${summary.totalMs} stages=${formatCodexDynamicToolBuildStageSummary(summary)}`, {
7101
+ runId: params.runId,
7102
+ sessionId: params.sessionId,
7103
+ phase,
7104
+ totalMs: summary.totalMs,
7105
+ stages: summary.stages,
7106
+ allToolCount: allTools.length,
7107
+ codexFilteredToolCount: codexFilteredTools.length,
7108
+ visionFilteredToolCount: visionFilteredTools.length,
7109
+ filteredToolCount: filteredTools.length,
7110
+ normalizedToolCount: normalizedTools.length,
7111
+ forceHeartbeatTool: input.forceHeartbeatTool === true,
7112
+ ignoreRuntimePlan: input.ignoreRuntimePlan === true,
7113
+ nativeToolSurfaceEnabled: input.nativeToolSurfaceEnabled === true
7114
+ });
7115
+ }
7116
+ return normalizedTools;
6983
7117
  }
6984
7118
  function includeForcedCodexDynamicToolAllow(toolsAllow, params) {
6985
7119
  if (toolsAllow === void 0 || hasWildcardCodexToolsAllow(toolsAllow)) return toolsAllow;
@@ -7149,11 +7283,33 @@ function shouldProjectMirroredHistoryForCodexStart(params) {
7149
7283
  if (!params.historyMessages.some((message) => message.role === "user")) return false;
7150
7284
  if (params.forceProject) return true;
7151
7285
  if (!params.startupBinding?.threadId) return true;
7286
+ if (hasUserVisibleHistoryAfterCodexBinding({
7287
+ startupBinding: params.startupBinding,
7288
+ historyMessages: params.historyMessages
7289
+ })) return true;
7152
7290
  return !areCodexDynamicToolFingerprintsCompatible({
7153
7291
  previous: params.startupBinding.dynamicToolsFingerprint,
7154
7292
  next: params.dynamicToolsFingerprint
7155
7293
  });
7156
7294
  }
7295
+ function hasUserVisibleHistoryAfterCodexBinding(params) {
7296
+ const bindingUpdatedAt = Date.parse(params.startupBinding.updatedAt);
7297
+ if (!Number.isFinite(bindingUpdatedAt)) return false;
7298
+ return params.historyMessages.some((message) => {
7299
+ if (message.role !== "user" && message.role !== "assistant") return false;
7300
+ if (isCodexAppServerMirroredTranscriptMessage(message)) return false;
7301
+ const timestamp = typeof message.timestamp === "number" ? message.timestamp : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
7302
+ return Number.isFinite(timestamp) && timestamp > bindingUpdatedAt;
7303
+ });
7304
+ }
7305
+ function isCodexAppServerMirroredTranscriptMessage(message) {
7306
+ const record = message;
7307
+ const idempotencyKey = record.idempotencyKey;
7308
+ if (typeof idempotencyKey === "string" && idempotencyKey.startsWith("codex-app-server:")) return true;
7309
+ const meta = record["__openclaw"];
7310
+ if (!meta || typeof meta !== "object" || Array.isArray(meta)) return false;
7311
+ return typeof meta.mirrorIdentity === "string";
7312
+ }
7157
7313
  function readContextEngineThreadBootstrapProjection(projection) {
7158
7314
  if (projection?.mode !== "thread_bootstrap") return;
7159
7315
  const epoch = projection.epoch?.trim();
@@ -7471,6 +7627,11 @@ function readRawAssistantTextPreview(item) {
7471
7627
  function isTurnNotification(value, threadId, turnId) {
7472
7628
  return isCodexNotificationForTurn(value, threadId, turnId);
7473
7629
  }
7630
+ function isCodexNotificationOutsideActiveRun(correlation) {
7631
+ if (!Boolean(correlation.threadId || correlation.nestedTurnThreadId)) return false;
7632
+ if (!correlation.matchesActiveThread) return true;
7633
+ return Boolean(correlation.turnId || correlation.nestedTurnId) && correlation.matchesActiveTurn === false;
7634
+ }
7474
7635
  function isCurrentThreadTurnRequestParams(value, threadId, turnId) {
7475
7636
  if (!isJsonObject(value)) return false;
7476
7637
  return readString(value, "threadId") === threadId && readString(value, "turnId") === turnId;
@@ -7528,8 +7689,7 @@ function readString(record, key) {
7528
7689
  return typeof value === "string" ? value : void 0;
7529
7690
  }
7530
7691
  function readBoolean(record, key) {
7531
- const value = record[key];
7532
- return typeof value === "boolean" ? value : void 0;
7692
+ return asBoolean(record[key]);
7533
7693
  }
7534
7694
  async function readMirroredSessionHistoryMessages(sessionFile) {
7535
7695
  const messages = await readCodexMirroredSessionHistoryMessages(sessionFile);
@@ -7596,7 +7756,8 @@ function buildCodexSystemPromptReport(params) {
7596
7756
  systemPrompt: {
7597
7757
  chars: params.developerInstructions.length,
7598
7758
  projectContextChars: 0,
7599
- nonProjectContextChars: params.developerInstructions.length
7759
+ nonProjectContextChars: params.developerInstructions.length,
7760
+ hash: sha256Text(params.developerInstructions)
7600
7761
  },
7601
7762
  injectedWorkspaceFiles: buildCodexBootstrapInjectionStats({
7602
7763
  bootstrapFiles: params.workspaceBootstrapContext.bootstrapFiles,
@@ -7605,6 +7766,7 @@ function buildCodexSystemPromptReport(params) {
7605
7766
  }),
7606
7767
  skills: {
7607
7768
  promptChars: skillsPrompt.length,
7769
+ hash: sha256Text(skillsPrompt),
7608
7770
  entries: buildCodexSkillReportEntries(skillsPrompt)
7609
7771
  },
7610
7772
  tools: {
@@ -7621,17 +7783,30 @@ function buildCodexSkillReportEntries(skillsPrompt) {
7621
7783
  blockChars: block.length
7622
7784
  })).filter((entry) => entry.blockChars > 0);
7623
7785
  }
7786
+ function readCodexDiagnosticToolParameters(tool) {
7787
+ return tool.inputSchema ?? tool.parameters;
7788
+ }
7789
+ function buildCodexDiagnosticToolDefinitions(tools) {
7790
+ return tools.map((tool) => ({
7791
+ name: tool.name,
7792
+ description: tool.description,
7793
+ parameters: readCodexDiagnosticToolParameters(tool)
7794
+ }));
7795
+ }
7624
7796
  function buildCodexToolReportEntry(tool) {
7625
7797
  const summary = tool.description.trim();
7626
7798
  if (tool.deferLoading === true) return {
7627
7799
  name: tool.name,
7628
7800
  summaryChars: summary.length,
7801
+ summaryHash: sha256Text(summary),
7629
7802
  schemaChars: 0,
7803
+ schemaHash: stableJsonHash(null),
7630
7804
  propertiesCount: null
7631
7805
  };
7632
7806
  return {
7633
7807
  name: tool.name,
7634
7808
  summaryChars: summary.length,
7809
+ summaryHash: sha256Text(summary),
7635
7810
  ...buildCodexToolSchemaStats(tool.inputSchema)
7636
7811
  };
7637
7812
  }
@@ -7646,9 +7821,24 @@ function buildCodexToolSchemaStats(schema) {
7646
7821
  const properties = isJsonObject(schema) && isJsonObject(schema.properties) ? schema.properties : null;
7647
7822
  return {
7648
7823
  schemaChars,
7824
+ schemaHash: stableJsonHash(schema),
7649
7825
  propertiesCount: properties ? Object.keys(properties).length : null
7650
7826
  };
7651
7827
  }
7828
+ function sha256Text(value) {
7829
+ return createHash("sha256").update(value).digest("hex");
7830
+ }
7831
+ function normalizeForStableHash(value) {
7832
+ if (Array.isArray(value)) return value.map((entry) => normalizeForStableHash(entry));
7833
+ if (value && typeof value === "object") {
7834
+ const record = value;
7835
+ return Object.fromEntries(Object.keys(record).toSorted((left, right) => left.localeCompare(right)).map((key) => [key, normalizeForStableHash(record[key])]));
7836
+ }
7837
+ return value;
7838
+ }
7839
+ function stableJsonHash(value) {
7840
+ return sha256Text(JSON.stringify(normalizeForStableHash(value)) ?? "null");
7841
+ }
7652
7842
  function buildCodexBootstrapInjectionStats(params) {
7653
7843
  const injectedIndex = indexCodexContextFileContent(params.injectedFiles);
7654
7844
  const developerInstructionIndex = indexCodexContextFileContent(params.developerInstructionFiles ?? []);
@@ -7822,9 +8012,11 @@ function isMissingCodexBootstrapContextFile(file) {
7822
8012
  function remapCodexContextFilePath(params) {
7823
8013
  const relativePath = path.relative(params.sourceWorkspaceDir, params.file.path);
7824
8014
  if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath) || params.sourceWorkspaceDir === params.targetWorkspaceDir) return params.file;
8015
+ const targetUsesPosixSeparators = params.targetWorkspaceDir.includes("/") && !params.targetWorkspaceDir.includes("\\");
8016
+ const normalizedRelativePath = targetUsesPosixSeparators ? relativePath.replaceAll("\\", "/") : relativePath.replaceAll("/", "\\");
7825
8017
  return {
7826
8018
  ...params.file,
7827
- path: path.join(params.targetWorkspaceDir, relativePath)
8019
+ path: targetUsesPosixSeparators ? path.posix.join(params.targetWorkspaceDir, normalizedRelativePath) : path.win32.join(params.targetWorkspaceDir, normalizedRelativePath)
7828
8020
  };
7829
8021
  }
7830
8022
  function compareCodexContextFiles(left, right) {
@@ -7861,6 +8053,21 @@ async function mirrorTranscriptBestEffort(params) {
7861
8053
  embeddedAgentLog.warn("failed to mirror codex app-server transcript", { error });
7862
8054
  }
7863
8055
  }
8056
+ async function mirrorPromptAtTurnStartBestEffort(params) {
8057
+ if (params.params.suppressNextUserMessagePersistence) return;
8058
+ try {
8059
+ await mirrorCodexAppServerTranscript({
8060
+ sessionFile: params.params.sessionFile,
8061
+ agentId: params.agentId,
8062
+ sessionKey: params.sessionKey,
8063
+ messages: [attachCodexMirrorIdentity(buildCodexUserPromptMessage(params.params), `${params.turnId}:prompt`)],
8064
+ idempotencyScope: `codex-app-server:${params.threadId}`,
8065
+ config: params.params.config
8066
+ });
8067
+ } catch (error) {
8068
+ embeddedAgentLog.warn("failed to mirror codex app-server prompt at turn start", { error });
8069
+ }
8070
+ }
7864
8071
  function isNonEmptyString(value) {
7865
8072
  return typeof value === "string" && value.length > 0;
7866
8073
  }
@@ -7907,6 +8114,7 @@ function handleApprovalRequest(params) {
7907
8114
  threadId: params.threadId,
7908
8115
  turnId: params.turnId,
7909
8116
  nativeHookRelay: params.nativeHookRelay,
8117
+ autoApprove: params.autoApprove,
7910
8118
  signal: params.signal
7911
8119
  });
7912
8120
  }