@openclaw/codex 2026.5.14-beta.2 → 2026.5.16-beta.2

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 (25) hide show
  1. package/dist/{client-CoctX13d.js → client-CA7amCZ8.js} +1 -1
  2. package/dist/{client-factory-Be6RD28K.js → client-factory-DwzPofwS.js} +1 -1
  3. package/dist/{command-formatters-DRJaVHhN.js → command-formatters-BRW7_Nu7.js} +10 -2
  4. package/dist/{command-handlers-CXxykxjq.js → command-handlers-D6UDzndR.js} +7 -7
  5. package/dist/compact-96QPqIAu.js +329 -0
  6. package/dist/{computer-use-DsJxRRtm.js → computer-use-BX02ojP4.js} +2 -2
  7. package/dist/{config-0rd3LnKg.js → config-3ATInASk.js} +7 -1
  8. package/dist/harness.js +9 -6
  9. package/dist/index.js +7 -7
  10. package/dist/media-understanding-provider.js +3 -3
  11. package/dist/{models-GCYf5s8J.js → models-BHS-8DS_.js} +1 -1
  12. package/dist/{node-cli-sessions-CiexDHeV.js → node-cli-sessions-BLDFnUEF.js} +5 -5
  13. package/dist/{plugin-activation-aQOmRQwA.js → plugin-activation-BDU4e-NA.js} +1 -1
  14. package/dist/provider.js +2 -2
  15. package/dist/{request-CKYiRqsN.js → request-Czoa60Nt.js} +3 -3
  16. package/dist/{run-attempt-DG9NQab2.js → run-attempt-B6gN6CrO.js} +364 -77
  17. package/dist/{session-binding-CMTXuyoz.js → session-binding-DbdVqMzW.js} +14 -2
  18. package/dist/{shared-client-BwUqd3lh.js → shared-client-CnbrvEfV.js} +2 -2
  19. package/dist/{side-question-CVWPOkY-.js → side-question-CFcVH8fj.js} +7 -7
  20. package/dist/test-api.js +2 -2
  21. package/dist/{thread-lifecycle-DrbViNpf.js → thread-lifecycle-BMK4m_PL.js} +159 -34
  22. package/dist/{vision-tools-CzTdigBu.js → vision-tools-Cm_YicZb.js} +107 -7
  23. package/openclaw.plugin.json +1 -1
  24. package/package.json +4 -4
  25. package/dist/compact-DWa8cylR.js +0 -256
@@ -1,28 +1,28 @@
1
- import { l as resolveCodexPluginsPolicy, o as readCodexPluginConfig, s as resolveCodexAppServerRuntimeOptions, u as withMcpElicitationsApprovalPolicy } from "./config-0rd3LnKg.js";
1
+ import { c as resolveCodexAppServerRuntimeOptions, d as withMcpElicitationsApprovalPolicy, i as isCodexAppServerApprovalPolicyAllowedByRequirements, s as readCodexPluginConfig, u as resolveCodexPluginsPolicy } from "./config-3ATInASk.js";
2
2
  import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-CSY0BFBo.js";
3
3
  import { t as isJsonObject } from "./protocol-C9UWI98H.js";
4
- import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-CoctX13d.js";
5
- import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-CKYiRqsN.js";
6
- import { d as resolveCodexUsageLimitResetAtMs, f as shouldRefreshCodexRateLimitsForUsageLimitMessage, r as formatCodexDisplayText, u as formatCodexUsageLimitErrorMessage } from "./command-formatters-DRJaVHhN.js";
7
- import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, l as resolveCodexAppServerAuthProfileId, n as clearSharedCodexAppServerClientIfCurrent, s as refreshCodexAppServerAuthTokens, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-BwUqd3lh.js";
8
- import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-CMTXuyoz.js";
9
- import { a as defaultCodexAppInventoryCache } from "./plugin-activation-aQOmRQwA.js";
10
- import { _ as resolveCodexContextEngineProjectionReserveTokens, b as normalizeCodexDynamicToolName, d as buildCodexPluginThreadConfig, f as buildCodexPluginThreadConfigInputFingerprint, g as resolveCodexContextEngineProjectionMaxChars, h as projectContextEngineAssemblyForCodex, m as shouldBuildCodexPluginThreadConfig, o as buildTurnStartParams, p as mergeCodexThreadConfigs, r as buildDeveloperInstructions, s as codexDynamicToolsFingerprint, t as areCodexDynamicToolFingerprintsCompatible, u as startOrResumeThread, v as createCodexDynamicToolBridge, y as filterCodexDynamicTools } from "./thread-lifecycle-DrbViNpf.js";
11
- import { t as defaultCodexAppServerClientFactory } from "./client-factory-Be6RD28K.js";
12
- import { n as handleCodexAppServerElicitationRequest, r as handleCodexAppServerApprovalRequest, t as filterToolsForVisionInputs } from "./vision-tools-CzTdigBu.js";
13
- import { t as ensureCodexComputerUse } from "./computer-use-DsJxRRtm.js";
4
+ import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-CA7amCZ8.js";
5
+ import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-Czoa60Nt.js";
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, n as clearSharedCodexAppServerClientIfCurrent, s as refreshCodexAppServerAuthTokens, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-CnbrvEfV.js";
8
+ import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-DbdVqMzW.js";
9
+ import { a as defaultCodexAppInventoryCache } from "./plugin-activation-BDU4e-NA.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-BMK4m_PL.js";
11
+ import { t as defaultCodexAppServerClientFactory } from "./client-factory-DwzPofwS.js";
12
+ import { n as handleCodexAppServerElicitationRequest, r as handleCodexAppServerApprovalRequest, t as filterToolsForVisionInputs } from "./vision-tools-Cm_YicZb.js";
13
+ import { t as ensureCodexComputerUse } from "./computer-use-BX02ojP4.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, inferToolMetaFromArgs, isActiveHarnessContextEngine, isSubagentSessionKey, loadCodexBundleMcpThreadConfig, normalizeAgentRuntimeTools, normalizeUsage, registerNativeHookRelay, resolveAgentHarnessBeforePromptBuildResult, resolveAttemptSpawnWorkspaceDir, resolveBootstrapContextForRun, 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, 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";
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";
21
21
  import { appendRegularFile, pathExists } from "openclaw/plugin-sdk/security-runtime";
22
+ import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
22
23
  import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
23
24
  import { createRunningTaskRun, finalizeTaskRunByRunId, recordTaskRunProgressByRunId } from "openclaw/plugin-sdk/codex-native-task-runtime";
24
25
  import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "@earendil-works/pi-coding-agent";
25
- import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
26
26
  //#region extensions/codex/src/app-server/native-subagent-task-mirror.ts
27
27
  const CODEX_NATIVE_SUBAGENT_RUNTIME = "subagent";
28
28
  const CODEX_NATIVE_SUBAGENT_TASK_KIND = "codex-native";
@@ -347,6 +347,41 @@ function inferCodexDynamicToolMeta(call, detailMode) {
347
347
  //#endregion
348
348
  //#region extensions/codex/src/app-server/transcript-mirror.ts
349
349
  const MIRROR_IDENTITY_META_KEY = "mirrorIdentity";
350
+ function normalizeOptionalString(value) {
351
+ const normalized = value?.trim();
352
+ return normalized ? normalized : void 0;
353
+ }
354
+ function buildSenderLabel(params) {
355
+ const label = params.senderName ?? params.senderUsername ?? params.senderE164 ?? params.senderId;
356
+ if (!label) return;
357
+ if (!params.senderId || label.includes(params.senderId)) return label;
358
+ return `${label} (${params.senderId})`;
359
+ }
360
+ function buildCodexUserPromptMessage(params) {
361
+ const senderId = normalizeOptionalString(params.senderId);
362
+ const senderName = normalizeOptionalString(params.senderName);
363
+ const senderUsername = normalizeOptionalString(params.senderUsername);
364
+ const senderE164 = normalizeOptionalString(params.senderE164);
365
+ const senderLabel = buildSenderLabel({
366
+ senderId,
367
+ senderName,
368
+ senderUsername,
369
+ senderE164
370
+ });
371
+ const sourceChannel = normalizeOptionalString(params.inputProvenance?.sourceChannel ?? params.messageChannel ?? params.messageProvider);
372
+ return {
373
+ role: "user",
374
+ content: params.prompt,
375
+ timestamp: Date.now(),
376
+ ...params.inputProvenance ? { provenance: params.inputProvenance } : {},
377
+ ...sourceChannel ? { sourceChannel } : {},
378
+ ...senderId ? { senderId } : {},
379
+ ...senderName ? { senderName } : {},
380
+ ...senderUsername ? { senderUsername } : {},
381
+ ...senderE164 ? { senderE164 } : {},
382
+ ...senderLabel ? { senderLabel } : {}
383
+ };
384
+ }
350
385
  /**
351
386
  * Tag a message with a stable logical identity for mirror dedupe. Callers
352
387
  * should use a value that is invariant for the same logical message across
@@ -596,11 +631,7 @@ var CodexAppServerEventProjector = class {
596
631
  const planText = collectTextValues(this.planTextByItem).join("\n\n");
597
632
  const lastAssistant = assistantTexts.length > 0 ? this.createAssistantMessage(assistantTexts.join("\n\n")) : void 0;
598
633
  const turnId = this.turnId;
599
- const messagesSnapshot = [attachCodexMirrorIdentity({
600
- role: "user",
601
- content: this.params.prompt,
602
- timestamp: Date.now()
603
- }, `${turnId}:prompt`)];
634
+ const messagesSnapshot = [attachCodexMirrorIdentity(buildCodexUserPromptMessage(this.params), `${turnId}:prompt`)];
604
635
  if (reasoningText) messagesSnapshot.push(attachCodexMirrorIdentity(this.createAssistantMirrorMessage("Codex reasoning", reasoningText), `${turnId}:reasoning`));
605
636
  if (planText) messagesSnapshot.push(attachCodexMirrorIdentity(this.createAssistantMirrorMessage("Codex plan", planText), `${turnId}:plan`));
606
637
  messagesSnapshot.push(...this.toolTranscriptMessages);
@@ -1701,27 +1732,45 @@ const CODEX_HOOK_EVENT_BY_NATIVE_EVENT = {
1701
1732
  permission_request: "PermissionRequest",
1702
1733
  before_agent_finalize: "Stop"
1703
1734
  };
1735
+ const CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT = {
1736
+ pre_tool_use: "pre_tool_use",
1737
+ post_tool_use: "post_tool_use",
1738
+ permission_request: "permission_request",
1739
+ before_agent_finalize: "stop"
1740
+ };
1741
+ const CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS = ["/<session-flags>/config.toml", "<session-flags>/config.toml"];
1704
1742
  function buildCodexNativeHookRelayConfig(params) {
1705
1743
  const events = params.events?.length ? params.events : CODEX_NATIVE_HOOK_RELAY_EVENTS;
1706
- const config = { "features.codex_hooks": true };
1744
+ const config = { "features.hooks": true };
1745
+ const hookState = {};
1707
1746
  for (const event of events) {
1708
1747
  const codexEvent = CODEX_HOOK_EVENT_BY_NATIVE_EVENT[event];
1709
- config[`hooks.${codexEvent}`] = [{
1710
- matcher: null,
1711
- hooks: [{
1712
- type: "command",
1713
- command: params.relay.commandForEvent(event),
1714
- timeout: normalizeHookTimeoutSec(params.hookTimeoutSec),
1715
- async: false,
1748
+ const command = params.relay.commandForEvent(event);
1749
+ const timeout = normalizeHookTimeoutSec(params.hookTimeoutSec);
1750
+ config[`hooks.${codexEvent}`] = [{ hooks: [{
1751
+ type: "command",
1752
+ command,
1753
+ timeout,
1754
+ async: false,
1755
+ statusMessage: "OpenClaw native hook relay"
1756
+ }] }];
1757
+ const state = {
1758
+ enabled: true,
1759
+ trusted_hash: codexCommandHookTrustedHash({
1760
+ event,
1761
+ command,
1762
+ timeout,
1716
1763
  statusMessage: "OpenClaw native hook relay"
1717
- }]
1718
- }];
1764
+ })
1765
+ };
1766
+ for (const sourcePath of CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS) hookState[`${sourcePath}:${CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[event]}:0:0`] = state;
1719
1767
  }
1768
+ config["hooks.state"] = hookState;
1720
1769
  return config;
1721
1770
  }
1722
1771
  function buildCodexNativeHookRelayDisabledConfig() {
1723
1772
  return {
1724
- "features.codex_hooks": false,
1773
+ "features.hooks": false,
1725
1774
  "hooks.PreToolUse": [],
1726
1775
  "hooks.PostToolUse": [],
1727
1776
  "hooks.PermissionRequest": [],
@@ -1731,6 +1780,26 @@ function buildCodexNativeHookRelayDisabledConfig() {
1731
1780
  function normalizeHookTimeoutSec(value) {
1732
1781
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.ceil(value) : 5;
1733
1782
  }
1783
+ function codexCommandHookTrustedHash(params) {
1784
+ const identity = {
1785
+ event_name: CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[params.event],
1786
+ hooks: [{
1787
+ async: false,
1788
+ command: params.command,
1789
+ statusMessage: params.statusMessage,
1790
+ timeout: params.timeout,
1791
+ type: "command"
1792
+ }]
1793
+ };
1794
+ return `sha256:${createHash("sha256").update(JSON.stringify(sortJsonValue(identity))).digest("hex")}`;
1795
+ }
1796
+ function sortJsonValue(value) {
1797
+ if (!value || typeof value !== "object") return value;
1798
+ if (Array.isArray(value)) return value.map(sortJsonValue);
1799
+ const sorted = {};
1800
+ for (const key of Object.keys(value).toSorted()) sorted[key] = sortJsonValue(value[key]);
1801
+ return sorted;
1802
+ }
1734
1803
  //#endregion
1735
1804
  //#region extensions/codex/src/app-server/trajectory.ts
1736
1805
  const SENSITIVE_FIELD_RE = /(?:authorization|cookie|credential|key|password|passwd|secret|token)/iu;
@@ -2284,6 +2353,22 @@ function restrictCodexAppServerSandboxForOpenClawSandbox(appServer, sandbox) {
2284
2353
  sandbox: "workspace-write"
2285
2354
  };
2286
2355
  }
2356
+ function resolveCodexAppServerForOpenClawToolPolicy(params) {
2357
+ if (!params.shouldPromote || !params.canUseUntrustedApprovalPolicy || params.appServer.approvalPolicy !== "never") return params.appServer;
2358
+ const explicitMode = params.pluginConfig.appServer?.mode !== void 0 || isCodexAppServerPolicyMode(params.env.OPENCLAW_CODEX_APP_SERVER_MODE);
2359
+ const explicitApprovalPolicy = params.pluginConfig.appServer?.approvalPolicy !== void 0 || isCodexAppServerApprovalPolicy(params.env.OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY);
2360
+ if (explicitMode || explicitApprovalPolicy) return params.appServer;
2361
+ return {
2362
+ ...params.appServer,
2363
+ approvalPolicy: "untrusted"
2364
+ };
2365
+ }
2366
+ function isCodexAppServerPolicyMode(value) {
2367
+ return value === "guardian" || value === "yolo";
2368
+ }
2369
+ function isCodexAppServerApprovalPolicy(value) {
2370
+ return value === "never" || value === "on-request" || value === "on-failure" || value === "untrusted";
2371
+ }
2287
2372
  async function runCodexAppServerAttempt(params, options = {}) {
2288
2373
  const attemptStartedAt = Date.now();
2289
2374
  const attemptClientFactory = options.clientFactory ?? defaultCodexAppServerClientFactory;
@@ -2299,7 +2384,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
2299
2384
  });
2300
2385
  const effectiveWorkspace = sandbox?.enabled ? sandbox.workspaceAccess === "rw" ? resolvedWorkspace : sandbox.workspaceDir : resolvedWorkspace;
2301
2386
  await fs.mkdir(effectiveWorkspace, { recursive: true });
2302
- const appServer = restrictCodexAppServerSandboxForOpenClawSandbox(configuredAppServer, sandbox);
2387
+ const appServer = resolveCodexAppServerForOpenClawToolPolicy({
2388
+ appServer: restrictCodexAppServerSandboxForOpenClawSandbox(configuredAppServer, sandbox),
2389
+ pluginConfig,
2390
+ env: process.env,
2391
+ shouldPromote: hasBeforeToolCallPolicy(),
2392
+ canUseUntrustedApprovalPolicy: configuredAppServer.start.transport !== "stdio" || isCodexAppServerApprovalPolicyAllowedByRequirements("untrusted")
2393
+ });
2303
2394
  let pluginAppServer = appServer;
2304
2395
  const nativeHookRelayEvents = resolveCodexNativeHookRelayEvents({
2305
2396
  configuredEvents: options.nativeHookRelay?.events,
@@ -2333,6 +2424,17 @@ async function runCodexAppServerAttempt(params, options = {}) {
2333
2424
  sessionKey: sandboxSessionKey,
2334
2425
  ...startupAuthProfileId ? { authProfileId: startupAuthProfileId } : {}
2335
2426
  };
2427
+ let activeSessionId = params.sessionId;
2428
+ let activeSessionFile = params.sessionFile;
2429
+ const buildActiveRunAttemptParams = () => ({
2430
+ ...runtimeParams,
2431
+ sessionId: activeSessionId,
2432
+ sessionFile: activeSessionFile
2433
+ });
2434
+ const adoptContextEngineCompactionTranscript = (compactResult) => {
2435
+ if (compactResult.result?.sessionId) activeSessionId = compactResult.result.sessionId;
2436
+ if (compactResult.result?.sessionFile) activeSessionFile = compactResult.result.sessionFile;
2437
+ };
2336
2438
  const startupAuthAccountCacheKey = await resolveCodexAppServerAuthAccountCacheKey({
2337
2439
  authProfileId: startupAuthProfileId,
2338
2440
  authProfileStore: params.authProfileStore,
@@ -2375,8 +2477,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
2375
2477
  runId: params.runId
2376
2478
  }
2377
2479
  });
2378
- const hadSessionFile = await pathExists(params.sessionFile);
2379
- let historyMessages = await readMirroredSessionHistoryMessages(params.sessionFile) ?? [];
2480
+ const hadSessionFile = await pathExists(activeSessionFile);
2481
+ let historyMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? [];
2380
2482
  const hookContextWindowFields = {
2381
2483
  ...params.contextWindowInfo?.tokens ? { contextTokenBudget: params.contextWindowInfo.tokens } : params.contextTokenBudget ? { contextTokenBudget: params.contextTokenBudget } : {},
2382
2484
  ...params.contextWindowInfo?.source ? { contextWindowSource: params.contextWindowInfo.source } : {},
@@ -2393,24 +2495,28 @@ async function runCodexAppServerAttempt(params, options = {}) {
2393
2495
  channelId: params.messageChannel ?? params.messageProvider ?? void 0,
2394
2496
  ...hookContextWindowFields
2395
2497
  };
2498
+ const activeContextEnginePluginId = activeContextEngine ? resolveContextEngineOwnerPluginId(activeContextEngine) : void 0;
2499
+ const buildActiveContextEngineRuntimeContext = () => buildHarnessContextEngineRuntimeContext({
2500
+ attempt: buildActiveRunAttemptParams(),
2501
+ workspaceDir: effectiveWorkspace,
2502
+ agentDir,
2503
+ activeAgentId: sessionAgentId,
2504
+ contextEnginePluginId: activeContextEnginePluginId,
2505
+ tokenBudget: params.contextTokenBudget
2506
+ });
2396
2507
  if (activeContextEngine) {
2397
2508
  await bootstrapHarnessContextEngine({
2398
2509
  hadSessionFile,
2399
2510
  contextEngine: activeContextEngine,
2400
- sessionId: params.sessionId,
2511
+ sessionId: activeSessionId,
2401
2512
  sessionKey: sandboxSessionKey,
2402
- sessionFile: params.sessionFile,
2403
- runtimeContext: buildHarnessContextEngineRuntimeContext({
2404
- attempt: runtimeParams,
2405
- workspaceDir: effectiveWorkspace,
2406
- agentDir,
2407
- tokenBudget: params.contextTokenBudget
2408
- }),
2513
+ sessionFile: activeSessionFile,
2514
+ runtimeContext: buildActiveContextEngineRuntimeContext(),
2409
2515
  runMaintenance: runHarnessContextEngineMaintenance,
2410
2516
  config: params.config,
2411
2517
  warn: (message) => embeddedAgentLog.warn(message)
2412
2518
  });
2413
- historyMessages = await readMirroredSessionHistoryMessages(params.sessionFile) ?? historyMessages;
2519
+ historyMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? historyMessages;
2414
2520
  }
2415
2521
  const baseDeveloperInstructions = buildDeveloperInstructions(params);
2416
2522
  const workspaceBootstrapContext = await buildCodexWorkspaceBootstrapContext({
@@ -2424,10 +2530,18 @@ async function runCodexAppServerAttempt(params, options = {}) {
2424
2530
  let promptText = params.prompt;
2425
2531
  let developerInstructions = joinPresentSections(baseDeveloperInstructions, workspaceBootstrapInstructions);
2426
2532
  let prePromptMessageCount = historyMessages.length;
2427
- if (activeContextEngine) try {
2533
+ let contextEngineProjection;
2534
+ const resetCodexPromptInputs = () => {
2535
+ promptText = params.prompt;
2536
+ developerInstructions = joinPresentSections(baseDeveloperInstructions, workspaceBootstrapInstructions);
2537
+ prePromptMessageCount = historyMessages.length;
2538
+ contextEngineProjection = void 0;
2539
+ };
2540
+ const applyActiveContextEngineProjection = async (decisionStartupBinding) => {
2541
+ if (!activeContextEngine) return;
2428
2542
  const assembled = await assembleHarnessContextEngine({
2429
2543
  contextEngine: activeContextEngine,
2430
- sessionId: params.sessionId,
2544
+ sessionId: activeSessionId,
2431
2545
  sessionKey: sandboxSessionKey,
2432
2546
  messages: historyMessages,
2433
2547
  tokenBudget: params.contextTokenBudget,
@@ -2437,6 +2551,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
2437
2551
  prompt: params.prompt
2438
2552
  });
2439
2553
  if (!assembled) throw new Error("context engine assemble returned no result");
2554
+ contextEngineProjection = readContextEngineThreadBootstrapProjection(assembled.contextProjection);
2440
2555
  const projection = projectContextEngineAssemblyForCodex({
2441
2556
  assembledMessages: assembled.messages,
2442
2557
  originalHistoryMessages: historyMessages,
@@ -2445,11 +2560,41 @@ async function runCodexAppServerAttempt(params, options = {}) {
2445
2560
  maxRenderedContextChars: resolveCodexContextEngineProjectionMaxChars({
2446
2561
  contextTokenBudget: params.contextTokenBudget,
2447
2562
  reserveTokens: resolveCodexContextEngineProjectionReserveTokens({ config: params.config })
2448
- })
2563
+ }),
2564
+ toolPayloadMode: contextEngineProjection ? "preserve" : "elide"
2449
2565
  });
2450
- promptText = projection.promptText;
2566
+ const projectionDecision = contextEngineProjection ? resolveContextEngineBootstrapProjectionDecision({
2567
+ startupBinding: decisionStartupBinding,
2568
+ expectedBinding: buildContextEngineBinding(buildActiveRunAttemptParams(), contextEngineProjection),
2569
+ projection: contextEngineProjection,
2570
+ dynamicToolsFingerprint: codexDynamicToolsFingerprint(toolBridge.specs)
2571
+ }) : {
2572
+ project: true,
2573
+ reason: "per-turn-projection"
2574
+ };
2575
+ embeddedAgentLog.info("codex app-server context-engine projection decision", {
2576
+ sessionId: params.sessionId,
2577
+ sessionKey: sandboxSessionKey,
2578
+ engineId: activeContextEngine.info.id,
2579
+ mode: contextEngineProjection?.mode ?? assembled.contextProjection?.mode ?? "per_turn",
2580
+ epoch: contextEngineProjection?.epoch,
2581
+ fingerprint: contextEngineProjection?.fingerprint,
2582
+ previousThreadId: decisionStartupBinding?.threadId,
2583
+ previousEpoch: decisionStartupBinding?.contextEngine?.projection?.epoch,
2584
+ previousFingerprint: decisionStartupBinding?.contextEngine?.projection?.fingerprint,
2585
+ projected: projectionDecision.project,
2586
+ reason: projectionDecision.reason,
2587
+ assembledMessages: assembled.messages.length,
2588
+ originalHistoryMessages: historyMessages.length,
2589
+ projectedPromptChars: projection.promptText.length,
2590
+ developerInstructionAdditionChars: projection.developerInstructionAddition?.length ?? 0
2591
+ });
2592
+ promptText = projectionDecision.project ? projection.promptText : params.prompt;
2451
2593
  developerInstructions = joinPresentSections(baseDeveloperInstructions, workspaceBootstrapInstructions, projection.developerInstructionAddition);
2452
2594
  prePromptMessageCount = projection.prePromptMessageCount;
2595
+ };
2596
+ if (activeContextEngine) try {
2597
+ await applyActiveContextEngineProjection(startupBinding);
2453
2598
  } catch (assembleErr) {
2454
2599
  embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
2455
2600
  }
@@ -2466,13 +2611,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
2466
2611
  promptText = projection.promptText;
2467
2612
  prePromptMessageCount = projection.prePromptMessageCount;
2468
2613
  }
2469
- promptText = prependCurrentTurnContext(promptText, params.currentTurnContext);
2470
- const promptBuild = await resolveAgentHarnessBeforePromptBuildResult({
2471
- prompt: promptText,
2614
+ const buildPromptFromCurrentInputs = () => resolveAgentHarnessBeforePromptBuildResult({
2615
+ prompt: prependCurrentTurnContext(promptText, params.currentTurnContext),
2472
2616
  developerInstructions,
2473
2617
  messages: historyMessages,
2474
2618
  ctx: hookContext
2475
2619
  });
2620
+ let promptBuild = await buildPromptFromCurrentInputs();
2476
2621
  const systemPromptReport = buildCodexSystemPromptReport({
2477
2622
  attempt: params,
2478
2623
  sessionKey: sandboxSessionKey,
@@ -2554,9 +2699,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
2554
2699
  timeoutMs: appServer.requestTimeoutMs,
2555
2700
  signal: runAbortController.signal
2556
2701
  });
2557
- const threadLifecycleParams = {
2702
+ const buildThreadLifecycleParams = () => ({
2558
2703
  client: startupClient,
2559
- params: runtimeParams,
2704
+ params: buildActiveRunAttemptParams(),
2705
+ agentId: sessionAgentId,
2560
2706
  cwd: effectiveWorkspace,
2561
2707
  dynamicTools: toolBridge.specs,
2562
2708
  appServer: pluginAppServer,
@@ -2564,6 +2710,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
2564
2710
  config: threadConfig,
2565
2711
  mcpServersFingerprint: bundleMcpThreadConfig.fingerprint,
2566
2712
  mcpServersFingerprintEvaluated: bundleMcpThreadConfig.evaluated,
2713
+ contextEngineProjection,
2567
2714
  pluginThreadConfig: pluginThreadConfigEnabled ? {
2568
2715
  enabled: true,
2569
2716
  inputFingerprint: pluginThreadConfigInputFingerprint,
@@ -2578,11 +2725,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
2578
2725
  appCacheKey: pluginAppCacheKey
2579
2726
  })
2580
2727
  } : void 0
2581
- };
2582
- restartContextEngineCodexThread = () => startOrResumeThread(threadLifecycleParams);
2728
+ });
2729
+ restartContextEngineCodexThread = () => startOrResumeThread(buildThreadLifecycleParams());
2583
2730
  return {
2584
2731
  client: startupClient,
2585
- thread: await startOrResumeThread(threadLifecycleParams)
2732
+ thread: await startOrResumeThread(buildThreadLifecycleParams())
2586
2733
  };
2587
2734
  };
2588
2735
  for (let attempt = 1; attempt <= CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS; attempt += 1) try {
@@ -2916,6 +3063,9 @@ async function runCodexAppServerAttempt(params, options = {}) {
2916
3063
  }
2917
3064
  if (isCurrentTurnNotification) updateActiveTurnItemIds(notification, activeTurnItemIds);
2918
3065
  const unblockedAssistantCompletionRelease = isCurrentTurnNotification && turnAssistantCompletionIdleWatchArmed && notification.method === "item/completed" && activeTurnItemIds.size === 0;
3066
+ const trackedDynamicToolCompletion = isTrackedOpenClawDynamicToolCompletionNotification(notification, activeOpenClawDynamicToolCallIds);
3067
+ const rawToolOutputCompletion = isRawToolOutputCompletionNotification(notification);
3068
+ const shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem = isCurrentTurnNotification && notification.method === "item/completed" && activeTurnItemIds.size === 0 && !trackedDynamicToolCompletion && !isCompletedAssistantNotification(notification);
2919
3069
  if (isCurrentTurnNotification && notification.method === "error") {
2920
3070
  if (isRetryableErrorNotification(notification.params)) disarmTurnCompletionIdleWatch();
2921
3071
  else armTurnCompletionIdleWatch({ pinnedByTerminalError: true });
@@ -2923,11 +3073,14 @@ async function runCodexAppServerAttempt(params, options = {}) {
2923
3073
  } else if (isTurnCompletion) disarmTurnAssistantCompletionIdleWatch();
2924
3074
  else if (isCurrentTurnNotification && isCompletedAssistantNotification(notification)) armTurnAssistantCompletionIdleWatch(describeNotificationActivity(notification));
2925
3075
  else if (unblockedAssistantCompletionRelease) armTurnAssistantCompletionIdleWatch(describeNotificationActivity(notification));
3076
+ else if (shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) armTurnCompletionIdleWatch();
3077
+ else if (isCurrentTurnNotification && rawToolOutputCompletion) armTurnCompletionIdleWatch();
2926
3078
  else if (isCurrentTurnNotification && shouldDisarmAssistantCompletionIdleWatch(notification)) disarmTurnAssistantCompletionIdleWatch();
2927
- if (turnCompletionIdleWatchArmed && !turnCompletionIdleWatchPinnedByTerminalError && notification.method !== "turn/completed" && isCurrentTurnNotification && !isTrackedOpenClawDynamicToolCompletionNotification(notification, activeOpenClawDynamicToolCallIds)) disarmTurnCompletionIdleWatch();
3079
+ if (turnCompletionIdleWatchArmed && !turnCompletionIdleWatchPinnedByTerminalError && notification.method !== "turn/completed" && isCurrentTurnNotification && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) disarmTurnCompletionIdleWatch();
2928
3080
  const isTurnAbortMarker = isCurrentTurnNotification && isCodexTurnAbortMarkerNotification(notification, { currentPromptText: promptBuild.prompt });
2929
3081
  const isTurnTerminal = isTurnCompletion || isTurnAbortMarker;
2930
3082
  try {
3083
+ await waitForCodexNotificationDispatchTurn();
2931
3084
  await projector.handleNotification(notification);
2932
3085
  } catch (error) {
2933
3086
  embeddedAgentLog.debug("codex app-server projector notification threw", {
@@ -2947,6 +3100,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
2947
3100
  }
2948
3101
  };
2949
3102
  const enqueueNotification = (notification) => {
3103
+ if (!projector || !turnId) {
3104
+ userInputBridge?.handleNotification(notification);
3105
+ pendingNotifications.push(notification);
3106
+ return Promise.resolve();
3107
+ }
2950
3108
  notificationQueue = notificationQueue.then(() => handleNotification(notification), () => handleNotification(notification));
2951
3109
  return notificationQueue;
2952
3110
  };
@@ -3079,7 +3237,76 @@ async function runCodexAppServerAttempt(params, options = {}) {
3079
3237
  touchTurnCompletionActivity(`request:${request.method}:response`, { arm: armCompletionWatchOnResponse });
3080
3238
  }
3081
3239
  });
3082
- const llmInputEvent = {
3240
+ const forceContextEngineCompactionForCodexOverflow = async (error) => {
3241
+ if (!activeContextEngine?.info.ownsCompaction) return false;
3242
+ embeddedAgentLog.warn("codex app-server context-engine turn overflowed; forcing context-engine compaction", {
3243
+ sessionId: activeSessionId,
3244
+ sessionKey: sandboxSessionKey,
3245
+ threadId: thread.threadId,
3246
+ engineId: activeContextEngine.info.id,
3247
+ tokenBudget: params.contextTokenBudget,
3248
+ error: formatErrorMessage(error)
3249
+ });
3250
+ try {
3251
+ const runtimeContext = buildActiveContextEngineRuntimeContext();
3252
+ const overflowTokenCount = params.contextTokenBudget ?? params.contextWindowInfo?.tokens;
3253
+ const compactResult = await activeContextEngine.compact({
3254
+ sessionId: activeSessionId,
3255
+ sessionKey: sandboxSessionKey,
3256
+ sessionFile: activeSessionFile,
3257
+ tokenBudget: params.contextTokenBudget,
3258
+ force: true,
3259
+ ...overflowTokenCount ? { currentTokenCount: overflowTokenCount } : {},
3260
+ compactionTarget: "threshold",
3261
+ runtimeContext: overflowTokenCount ? {
3262
+ ...runtimeContext,
3263
+ currentTokenCount: overflowTokenCount
3264
+ } : runtimeContext
3265
+ });
3266
+ embeddedAgentLog.info("codex app-server context-engine forced compaction result", {
3267
+ sessionId: activeSessionId,
3268
+ sessionKey: sandboxSessionKey,
3269
+ engineId: activeContextEngine.info.id,
3270
+ ok: compactResult.ok,
3271
+ compacted: compactResult.compacted,
3272
+ reason: compactResult.reason,
3273
+ tokensBefore: compactResult.result?.tokensBefore,
3274
+ tokensAfter: compactResult.result?.tokensAfter
3275
+ });
3276
+ if (!compactResult.ok || !compactResult.compacted) return false;
3277
+ adoptContextEngineCompactionTranscript(compactResult);
3278
+ const maintenanceRuntimeContext = buildActiveContextEngineRuntimeContext();
3279
+ await runHarnessContextEngineMaintenance({
3280
+ contextEngine: activeContextEngine,
3281
+ sessionId: activeSessionId,
3282
+ sessionKey: sandboxSessionKey,
3283
+ sessionFile: activeSessionFile,
3284
+ reason: "compaction",
3285
+ runtimeContext: maintenanceRuntimeContext,
3286
+ config: params.config
3287
+ });
3288
+ return true;
3289
+ } catch (compactErr) {
3290
+ embeddedAgentLog.warn("codex app-server context-engine forced compaction failed", {
3291
+ sessionId: params.sessionId,
3292
+ sessionKey: sandboxSessionKey,
3293
+ engineId: activeContextEngine.info.id,
3294
+ error: formatErrorMessage(compactErr)
3295
+ });
3296
+ return false;
3297
+ }
3298
+ };
3299
+ const rebuildPromptAfterContextEngineCompaction = async () => {
3300
+ historyMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? historyMessages;
3301
+ resetCodexPromptInputs();
3302
+ try {
3303
+ await applyActiveContextEngineProjection(void 0);
3304
+ } catch (assembleErr) {
3305
+ embeddedAgentLog.warn("context engine assemble failed after forced compaction; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
3306
+ }
3307
+ promptBuild = await buildPromptFromCurrentInputs();
3308
+ };
3309
+ const buildLlmInputEvent = () => ({
3083
3310
  runId: params.runId,
3084
3311
  sessionId: params.sessionId,
3085
3312
  provider: params.provider,
@@ -3088,12 +3315,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
3088
3315
  prompt: promptBuild.prompt,
3089
3316
  historyMessages,
3090
3317
  imagesCount: params.images?.length ?? 0
3091
- };
3092
- const turnStartFailureMessages = [...historyMessages, {
3093
- role: "user",
3094
- content: promptBuild.prompt,
3095
- timestamp: Date.now()
3096
- }];
3318
+ });
3319
+ const buildTurnStartFailureMessages = () => [...historyMessages, buildCodexUserPromptMessage({
3320
+ ...params,
3321
+ prompt: promptBuild.prompt
3322
+ })];
3097
3323
  let turn;
3098
3324
  const startCodexTurn = async () => assertCodexTurnStartResponse(await client.request("turn/start", buildTurnStartParams(params, {
3099
3325
  threadId: thread.threadId,
@@ -3106,7 +3332,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3106
3332
  }));
3107
3333
  try {
3108
3334
  runAgentHarnessLlmInputHook({
3109
- event: llmInputEvent,
3335
+ event: buildLlmInputEvent(),
3110
3336
  ctx: hookContext
3111
3337
  });
3112
3338
  emitCodexAppServerEvent(params, {
@@ -3128,7 +3354,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
3128
3354
  threadId: thread.threadId,
3129
3355
  error: formatErrorMessage(turnStartError)
3130
3356
  });
3131
- await clearCodexAppServerBinding(params.sessionFile);
3357
+ const preRetrySessionFile = activeSessionFile;
3358
+ const compactedForRetry = await forceContextEngineCompactionForCodexOverflow(turnStartError);
3359
+ await clearCodexAppServerBinding(preRetrySessionFile);
3360
+ if (activeSessionFile !== preRetrySessionFile) await clearCodexAppServerBinding(activeSessionFile);
3361
+ if (compactedForRetry) await rebuildPromptAfterContextEngineCompaction();
3132
3362
  thread = await restartContextEngineCodexThread();
3133
3363
  emitCodexAppServerEvent(params, {
3134
3364
  stream: "codex_app_server.lifecycle",
@@ -3182,7 +3412,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3182
3412
  });
3183
3413
  runAgentHarnessAgentEndHook({
3184
3414
  event: {
3185
- messages: turnStartFailureMessages,
3415
+ messages: buildTurnStartFailureMessages(),
3186
3416
  success: false,
3187
3417
  error: turnStartErrorMessage,
3188
3418
  durationMs: Date.now() - attemptStartedAt
@@ -3211,7 +3441,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3211
3441
  return buildCodexTurnStartFailureResult({
3212
3442
  params,
3213
3443
  message: usageLimitError.message,
3214
- messagesSnapshot: turnStartFailureMessages,
3444
+ messagesSnapshot: buildTurnStartFailureMessages(),
3215
3445
  systemPromptReport
3216
3446
  });
3217
3447
  }
@@ -3237,6 +3467,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
3237
3467
  projector = new CodexAppServerEventProjector(params, thread.threadId, activeTurnId, { nativePostToolUseRelayEnabled: nativeHookRelay?.allowedEvents.includes("post_tool_use") === true });
3238
3468
  emitLifecycleStart();
3239
3469
  const activeProjector = projector;
3470
+ turnTerminalIdleWatchArmed = true;
3471
+ touchTurnCompletionActivity("turn:start", { arm: true });
3240
3472
  for (const notification of pendingNotifications.splice(0)) await enqueueNotification(notification);
3241
3473
  if (!completed && isTerminalTurnStatus(turn.turn.status)) await enqueueNotification({
3242
3474
  method: "turn/completed",
@@ -3263,8 +3495,6 @@ async function runCodexAppServerAttempt(params, options = {}) {
3263
3495
  abort: () => runAbortController.abort("aborted")
3264
3496
  };
3265
3497
  setActiveEmbeddedRun(params.sessionId, handle, params.sessionKey);
3266
- turnTerminalIdleWatchArmed = true;
3267
- touchTurnCompletionActivity("turn:start");
3268
3498
  const timeout = setTimeout(() => {
3269
3499
  timedOut = true;
3270
3500
  projector?.markTimedOut();
@@ -3342,22 +3572,25 @@ async function runCodexAppServerAttempt(params, options = {}) {
3342
3572
  ...finalAborted ? { aborted: true } : {}
3343
3573
  });
3344
3574
  if (activeContextEngine) {
3345
- const finalMessages = await readMirroredSessionHistoryMessages(params.sessionFile) ?? historyMessages.concat(result.messagesSnapshot);
3575
+ const activeContextEnginePluginId = resolveContextEngineOwnerPluginId(activeContextEngine);
3576
+ const finalMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? historyMessages.concat(result.messagesSnapshot);
3346
3577
  await finalizeHarnessContextEngineTurn({
3347
3578
  contextEngine: activeContextEngine,
3348
3579
  promptError: Boolean(finalPromptError),
3349
3580
  aborted: finalAborted,
3350
3581
  yieldAborted: Boolean(result.yieldDetected),
3351
- sessionIdUsed: params.sessionId,
3582
+ sessionIdUsed: activeSessionId,
3352
3583
  sessionKey: sandboxSessionKey,
3353
- sessionFile: params.sessionFile,
3584
+ sessionFile: activeSessionFile,
3354
3585
  messagesSnapshot: finalMessages,
3355
3586
  prePromptMessageCount,
3356
3587
  tokenBudget: params.contextTokenBudget,
3357
3588
  runtimeContext: buildHarnessContextEngineRuntimeContextFromUsage({
3358
- attempt: runtimeParams,
3589
+ attempt: buildActiveRunAttemptParams(),
3359
3590
  workspaceDir: effectiveWorkspace,
3360
3591
  agentDir,
3592
+ activeAgentId: sessionAgentId,
3593
+ contextEnginePluginId: activeContextEnginePluginId,
3361
3594
  tokenBudget: params.contextTokenBudget,
3362
3595
  lastCallUsage: result.attemptUsage,
3363
3596
  promptCache: result.promptCache
@@ -3650,14 +3883,12 @@ function resolveOpenClawCodingToolsSessionKeys(params, sandboxSessionKey) {
3650
3883
  runSessionKey: params.sessionKey && params.sessionKey !== sandboxSessionKey ? params.sessionKey : void 0
3651
3884
  };
3652
3885
  }
3653
- async function buildDynamicTools(input) {
3886
+ function buildOpenClawCodingToolsOptions(input) {
3654
3887
  const { params } = input;
3655
- if (params.disableTools || !supportsModelTools(params.model)) return [];
3656
3888
  const modelHasVision = params.model.input?.includes("image") ?? false;
3657
3889
  const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, input.sessionAgentId);
3658
- const createOpenClawCodingTools = openClawCodingToolsFactoryForTests ?? (await import("openclaw/plugin-sdk/agent-harness")).createOpenClawCodingTools;
3659
3890
  const sessionKeys = resolveOpenClawCodingToolsSessionKeys(params, input.sandboxSessionKey);
3660
- const filteredTools = filterCodexDynamicToolsForAllowlist(filterToolsForVisionInputs(filterCodexDynamicTools(createOpenClawCodingTools({
3891
+ return {
3661
3892
  agentId: input.sessionAgentId,
3662
3893
  ...buildEmbeddedAttemptToolRunContext(params),
3663
3894
  exec: {
@@ -3721,8 +3952,15 @@ async function buildDynamicTools(input) {
3721
3952
  });
3722
3953
  input.runAbortController.abort("sessions_yield");
3723
3954
  }
3724
- }), input.pluginConfig), {
3725
- modelHasVision,
3955
+ };
3956
+ }
3957
+ async function buildDynamicTools(input) {
3958
+ const { params } = input;
3959
+ if (params.disableTools || !supportsModelTools(params.model)) return [];
3960
+ const createOpenClawCodingTools = openClawCodingToolsFactoryForTests ?? (await import("openclaw/plugin-sdk/agent-harness")).createOpenClawCodingTools;
3961
+ const toolOptions = buildOpenClawCodingToolsOptions(input);
3962
+ const filteredTools = filterCodexDynamicToolsForAllowlist(filterToolsForVisionInputs(filterCodexDynamicTools(createOpenClawCodingTools(toolOptions), input.pluginConfig), {
3963
+ modelHasVision: toolOptions.modelHasVision ?? false,
3726
3964
  hasInboundImages: (params.images?.length ?? 0) > 0
3727
3965
  }), includeForcedMessageToolAllow(params.toolsAllow, params));
3728
3966
  return normalizeAgentRuntimeTools({
@@ -3759,6 +3997,45 @@ function shouldProjectMirroredHistoryForCodexStart(params) {
3759
3997
  next: params.dynamicToolsFingerprint
3760
3998
  });
3761
3999
  }
4000
+ function readContextEngineThreadBootstrapProjection(projection) {
4001
+ if (projection?.mode !== "thread_bootstrap") return;
4002
+ const epoch = projection.epoch?.trim();
4003
+ if (!epoch) {
4004
+ embeddedAgentLog.warn("context engine requested Codex thread-bootstrap projection without an epoch; using per-turn projection");
4005
+ return;
4006
+ }
4007
+ const fingerprint = projection.fingerprint?.trim();
4008
+ return {
4009
+ mode: "thread_bootstrap",
4010
+ epoch,
4011
+ ...fingerprint ? { fingerprint } : {}
4012
+ };
4013
+ }
4014
+ function resolveContextEngineBootstrapProjectionDecision(params) {
4015
+ const bindingProjection = params.startupBinding?.contextEngine?.projection;
4016
+ if (!params.startupBinding?.threadId || !bindingProjection) return {
4017
+ project: true,
4018
+ reason: !params.startupBinding?.threadId ? "missing-thread-binding" : "missing-projection-binding"
4019
+ };
4020
+ if (!params.expectedBinding || !isContextEngineBindingCompatible(params.startupBinding.contextEngine, params.expectedBinding)) return {
4021
+ project: true,
4022
+ reason: "context-engine-binding-mismatch"
4023
+ };
4024
+ if (!areCodexDynamicToolFingerprintsCompatible({
4025
+ previous: params.startupBinding.dynamicToolsFingerprint,
4026
+ next: params.dynamicToolsFingerprint
4027
+ })) return {
4028
+ project: true,
4029
+ reason: "dynamic-tools-mismatch"
4030
+ };
4031
+ return bindingProjection.mode !== "thread_bootstrap" || bindingProjection.epoch !== params.projection.epoch || bindingProjection.fingerprint !== params.projection.fingerprint ? {
4032
+ project: true,
4033
+ reason: "projection-mismatch"
4034
+ } : {
4035
+ project: false,
4036
+ reason: "matching-thread-bootstrap-binding"
4037
+ };
4038
+ }
3762
4039
  async function withCodexStartupTimeout(params) {
3763
4040
  if (params.signal.aborted) throw new Error("codex app-server startup aborted");
3764
4041
  let timeout;
@@ -3959,6 +4236,11 @@ function isTrackedOpenClawDynamicToolCompletionNotification(notification, active
3959
4236
  const itemType = item ? readString(item, "type") : void 0;
3960
4237
  return itemType === void 0 || itemType === "dynamicToolCall";
3961
4238
  }
4239
+ function isRawToolOutputCompletionNotification(notification) {
4240
+ if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
4241
+ const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
4242
+ return item ? readString(item, "type") === "custom_tool_call_output" : false;
4243
+ }
3962
4244
  function readRawAssistantTextPreview(item) {
3963
4245
  if (readString(item, "role") !== "assistant" || !Array.isArray(item.content)) return;
3964
4246
  const text = item.content.flatMap((content) => {
@@ -4244,6 +4526,11 @@ function prependCurrentTurnContext(prompt, context) {
4244
4526
  const text = context?.text.trim();
4245
4527
  return text ? [text, prompt].filter(Boolean).join("\n\n") : prompt;
4246
4528
  }
4529
+ function waitForCodexNotificationDispatchTurn() {
4530
+ return new Promise((resolve) => {
4531
+ setImmediate(resolve);
4532
+ });
4533
+ }
4247
4534
  function handleApprovalRequest(params) {
4248
4535
  return handleCodexAppServerApprovalRequest({
4249
4536
  method: params.method,