@openclaw/codex 2026.5.28-beta.4 → 2026.5.30-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 (25) hide show
  1. package/dist/{client-DMXvboVu.js → client-B08x7Y93.js} +6 -0
  2. package/dist/client-factory-bqIbmRDu.js +20 -0
  3. package/dist/{command-handlers-C2t6-ChO.js → command-handlers-VSWuNdgc.js} +10 -10
  4. package/dist/{compact-Dlnt5G3v.js → compact-DJruF_vy.js} +3 -3
  5. package/dist/{computer-use-Ba4vW9fO.js → computer-use-Cq-EEnLL.js} +1 -1
  6. package/dist/{conversation-binding-CC9XMAwn.js → conversation-binding-DzF_JII7.js} +67 -90
  7. package/dist/harness.js +6 -10
  8. package/dist/index.js +16 -56
  9. package/dist/media-understanding-provider.js +5 -5
  10. package/dist/{models-QT-XOhE7.js → models-DuyStYTT.js} +1 -1
  11. package/dist/{native-hook-relay-B8qM8ZwR.js → native-hook-relay-zY7m-pAu.js} +74 -6
  12. package/dist/{notification-correlation-BDakP_d3.js → notification-correlation-DR9cQN_M.js} +3 -3
  13. package/dist/provider-catalog.js +2 -2
  14. package/dist/provider.js +1 -1
  15. package/dist/{request-CF4f5hWY.js → request-DGOj3AyX.js} +4 -4
  16. package/dist/{run-attempt-C6EMmamz.js → run-attempt-lD4FLxNV.js} +424 -246
  17. package/dist/{sandbox-guard-mXE4_vE_.js → sandbox-guard-DMCJlzmz.js} +4 -1
  18. package/dist/{session-binding-ueMCn4om.js → session-binding-BGOpicy0.js} +17 -2
  19. package/dist/{shared-client-Duh1bHaP.js → shared-client-2d0XB7wz.js} +32 -3
  20. package/dist/{side-question-B-Cjb9wm.js → side-question-BsyY3v3K.js} +7 -7
  21. package/dist/{thread-lifecycle-Dv9Npl7a.js → thread-lifecycle-BR74qMaY.js} +32 -90
  22. package/npm-shrinkwrap.json +2 -2
  23. package/openclaw.plugin.json +4 -3
  24. package/package.json +4 -4
  25. package/dist/client-factory-qZvhyyXr.js +0 -15
@@ -1,15 +1,15 @@
1
- import { n as defaultLeasedCodexAppServerClientFactory } from "./client-factory-qZvhyyXr.js";
1
+ import { n as defaultLeasedCodexAppServerClientFactory } from "./client-factory-bqIbmRDu.js";
2
2
  import { c as readCodexPluginConfig, d as resolveCodexPluginsPolicy, f as resolveOpenClawExecPolicyForCodexAppServer, i as isCodexAppServerApprovalPolicyAllowedByRequirements, l as resolveCodexAppServerRuntimeOptions, m as withMcpElicitationsApprovalPolicy, o as isCodexSandboxExecServerEnabled, p as shouldAutoApproveCodexAppServerApprovals, u as resolveCodexComputerUseConfig } from "./config--tW89bHH.js";
3
3
  import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-DtjYmUw_.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-DMXvboVu.js";
5
- import { C as sanitizeCodexHistoryImagePayloads, D as resolveCodexContextEngineProjectionReserveTokens, E as resolveCodexContextEngineProjectionMaxChars, T as projectContextEngineAssemblyForCodex, _ as shouldBuildCodexPluginThreadConfig, a as buildDeveloperInstructions, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as mergeCodexThreadConfigs, h as buildCodexPluginThreadConfigInputFingerprint, i as buildContextEngineBinding, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfig, n as areCodexDynamicToolFingerprintsCompatible, o as buildTurnCollaborationMode, p as isCodexAppServerProfilerEnabled, s as buildTurnStartParams, x as defaultCodexAppInventoryCache } from "./thread-lifecycle-Dv9Npl7a.js";
6
- import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-ueMCn4om.js";
7
- import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-CF4f5hWY.js";
8
- import { _ as shouldRefreshCodexRateLimitsForUsageLimitMessage, g as resolveCodexUsageLimitResetAtMs, h as formatCodexUsageLimitErrorMessage, i as readCodexNotificationTurnId, n as isCodexNotificationForTurn, r as readCodexNotificationThreadId, s as formatCodexDisplayText, t as describeCodexNotificationCorrelation } from "./notification-correlation-BDakP_d3.js";
9
- import { a as releaseLeasedSharedCodexAppServerClient, d as resolveCodexAppServerAuthProfileId, f as resolveCodexAppServerAuthProfileIdForAgent, l as refreshCodexAppServerAuthTokens, m as resolveCodexAppServerHomeDir, o as retireSharedCodexAppServerClientIfCurrent, p as resolveCodexAppServerFallbackApiKeyCacheKey, t as clearSharedCodexAppServerClientIfCurrent, u as resolveCodexAppServerAuthAccountCacheKey } from "./shared-client-Duh1bHaP.js";
10
- import { i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-mXE4_vE_.js";
11
- import { _ as normalizeCodexDynamicToolName$1, a as createCodexNativeHookRelay, c as scheduleCodexNativeHookRelayUnregister, d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, g as isForcedPrivateQaCodexRuntime, h as filterCodexDynamicTools, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerElicitationRequest, m as filterToolsForVisionInputs, n as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, o as resolveCodexNativeHookRelayEvents, p as emitDynamicToolTerminalDiagnostic, r as buildCodexNativeHookRelayConfig, s as resolveCodexNativeHookRelayTtlMs, u as createCodexDynamicToolBridge, v as resolveCodexDynamicToolsLoading, y as handleCodexAppServerApprovalRequest } from "./native-hook-relay-B8qM8ZwR.js";
12
- import { t as ensureCodexComputerUse } from "./computer-use-Ba4vW9fO.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-B08x7Y93.js";
5
+ import { C as sanitizeCodexHistoryImagePayloads, D as resolveCodexContextEngineProjectionReserveTokens, E as resolveCodexContextEngineProjectionMaxChars, T as projectContextEngineAssemblyForCodex, _ as shouldBuildCodexPluginThreadConfig, a as buildDeveloperInstructions, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as mergeCodexThreadConfigs, h as buildCodexPluginThreadConfigInputFingerprint, i as buildContextEngineBinding, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfig, n as areCodexDynamicToolFingerprintsCompatible, o as buildTurnCollaborationMode, p as isCodexAppServerProfilerEnabled, s as buildTurnStartParams, x as defaultCodexAppInventoryCache } from "./thread-lifecycle-BR74qMaY.js";
6
+ import { a as readCodexAppServerBinding, n as clearCodexAppServerBindingForThread, t as clearCodexAppServerBinding } from "./session-binding-BGOpicy0.js";
7
+ import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-DGOj3AyX.js";
8
+ import { _ as shouldRefreshCodexRateLimitsForUsageLimitMessage, g as resolveCodexUsageLimitResetAtMs, h as formatCodexUsageLimitErrorMessage, i as readCodexNotificationTurnId, n as isCodexNotificationForTurn, r as readCodexNotificationThreadId, s as formatCodexDisplayText, t as describeCodexNotificationCorrelation } from "./notification-correlation-DR9cQN_M.js";
9
+ import { a as releaseLeasedSharedCodexAppServerClient, d as resolveCodexAppServerAuthProfileId, f as resolveCodexAppServerAuthProfileIdForAgent, l as refreshCodexAppServerAuthTokens, m as resolveCodexAppServerHomeDir, o as retireSharedCodexAppServerClientIfCurrent, p as resolveCodexAppServerFallbackApiKeyCacheKey, t as clearSharedCodexAppServerClientIfCurrent, u as resolveCodexAppServerAuthAccountCacheKey } from "./shared-client-2d0XB7wz.js";
10
+ import { i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-DMCJlzmz.js";
11
+ import { C as resolveCodexTurnAssistantCompletionIdleTimeoutMs, E as withCodexStartupTimeout, S as resolveCodexStartupTimeoutMs, T as resolveCodexTurnTerminalIdleTimeoutMs, _ as normalizeCodexDynamicToolName$1, a as createCodexNativeHookRelay, b as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, c as scheduleCodexNativeHookRelayUnregister, d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, g as isForcedPrivateQaCodexRuntime, h as filterCodexDynamicTools, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerElicitationRequest, m as filterToolsForVisionInputs, n as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, o as resolveCodexNativeHookRelayEvents, p as emitDynamicToolTerminalDiagnostic, r as buildCodexNativeHookRelayConfig, s as resolveCodexNativeHookRelayTtlMs, u as createCodexDynamicToolBridge, v as resolveCodexDynamicToolsLoading, w as resolveCodexTurnCompletionIdleTimeoutMs, x as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, y as handleCodexAppServerApprovalRequest } from "./native-hook-relay-zY7m-pAu.js";
12
+ import { t as ensureCodexComputerUse } from "./computer-use-Cq-EEnLL.js";
13
13
  import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-N66I-Rd7.js";
14
14
  import { createHash, randomUUID } from "node:crypto";
15
15
  import fsSync from "node:fs";
@@ -20,15 +20,17 @@ 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
+ import { parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
23
24
  import fs from "node:fs/promises";
24
25
  import path, { posix } from "node:path";
25
26
  import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, hasPendingInternalDiagnosticEvent, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
26
27
  import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
27
28
  import { isToolAllowed } from "openclaw/plugin-sdk/sandbox";
28
29
  import { appendRegularFile, pathExists } from "openclaw/plugin-sdk/security-runtime";
29
- import { parseFiniteNumber, parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
30
30
  import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "openclaw/plugin-sdk/agent-sessions";
31
31
  import { isIP } from "node:net";
32
+ import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
33
+ import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
32
34
  import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
33
35
  //#region extensions/codex/src/app-server/app-server-policy.ts
34
36
  function resolveCodexAppServerForOpenClawToolPolicy(params) {
@@ -155,37 +157,6 @@ async function readMirroredSessionHistoryMessages(sessionFile) {
155
157
  if (!messages) embeddedAgentLog.warn("failed to read mirrored session history for codex harness hooks", { sessionFile });
156
158
  return messages;
157
159
  }
158
- function shouldProjectMirroredHistoryForCodexStart(params) {
159
- if (!params.historyMessages.some((message) => message.role === "user")) return false;
160
- if (params.forceProject) return true;
161
- if (!params.startupBinding?.threadId) return true;
162
- if (hasUserVisibleHistoryAfterCodexBinding({
163
- startupBinding: params.startupBinding,
164
- historyMessages: params.historyMessages
165
- })) return true;
166
- return !areCodexDynamicToolFingerprintsCompatible({
167
- previous: params.startupBinding.dynamicToolsFingerprint,
168
- next: params.dynamicToolsFingerprint
169
- });
170
- }
171
- function hasUserVisibleHistoryAfterCodexBinding(params) {
172
- const bindingUpdatedAt = Date.parse(params.startupBinding.updatedAt);
173
- if (!Number.isFinite(bindingUpdatedAt)) return false;
174
- return params.historyMessages.some((message) => {
175
- if (message.role !== "user" && message.role !== "assistant") return false;
176
- if (isCodexAppServerMirroredTranscriptMessage(message)) return false;
177
- const timestamp = typeof message.timestamp === "number" ? message.timestamp : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
178
- return Number.isFinite(timestamp) && timestamp > bindingUpdatedAt;
179
- });
180
- }
181
- function isCodexAppServerMirroredTranscriptMessage(message) {
182
- const record = message;
183
- const idempotencyKey = record.idempotencyKey;
184
- if (typeof idempotencyKey === "string" && idempotencyKey.startsWith("codex-app-server:")) return true;
185
- const meta = record["__openclaw"];
186
- if (!meta || typeof meta !== "object" || Array.isArray(meta)) return false;
187
- return typeof meta.mirrorIdentity === "string";
188
- }
189
160
  function readContextEngineThreadBootstrapProjection(projection) {
190
161
  if (projection?.mode !== "thread_bootstrap") return;
191
162
  const epoch = projection.epoch?.trim();
@@ -284,6 +255,10 @@ async function buildCodexWorkspaceBootstrapContext(params) {
284
255
  promptContext: renderCodexWorkspaceBootstrapPromptContext(promptContextFiles),
285
256
  developerInstructions: renderCodexWorkspaceThreadDeveloperInstructions(developerInstructionFiles),
286
257
  turnScopedDeveloperInstructions: renderCodexWorkspaceCollaborationDeveloperInstructions(turnScopedDeveloperInstructionFiles),
258
+ memoryCollaborationInstructions: shouldInjectCodexOpenClawPromptContext(params.params) ? renderCodexWorkspaceMemoryReference({
259
+ files: memoryReferenceFiles,
260
+ toolNames: params.memoryToolNames
261
+ }) : void 0,
287
262
  heartbeatCollaborationInstructions: renderCodexWorkspaceHeartbeatReference(heartbeatReferenceFiles)
288
263
  };
289
264
  } catch (error) {
@@ -454,19 +429,11 @@ function readNonEmptyString$1(value) {
454
429
  }
455
430
  function buildCodexOpenClawPromptContext(params) {
456
431
  if (!shouldInjectCodexOpenClawPromptContext(params.params)) return;
457
- const sections = [
458
- params.skillsPrompt?.trim() ? [
459
- "## OpenClaw Skills",
460
- "",
461
- params.skillsPrompt.trim()
462
- ].join("\n") : void 0,
463
- params.workspaceMemoryReference?.trim() ? params.workspaceMemoryReference.trim() : void 0,
464
- params.workspacePromptContext?.trim() ? [
465
- "## OpenClaw Workspace Context",
466
- "",
467
- params.workspacePromptContext.trim()
468
- ].join("\n") : void 0
469
- ].filter(isNonEmptyString$2);
432
+ const sections = [params.workspacePromptContext?.trim() ? [
433
+ "## OpenClaw Workspace Context",
434
+ "",
435
+ params.workspacePromptContext.trim()
436
+ ].join("\n") : void 0].filter(isNonEmptyString$2);
470
437
  if (sections.length === 0) return;
471
438
  return [
472
439
  "OpenClaw runtime context for this turn:",
@@ -478,9 +445,17 @@ function buildCodexOpenClawPromptContext(params) {
478
445
  function shouldInjectCodexOpenClawPromptContext(params) {
479
446
  return !(params.bootstrapContextMode === "lightweight" && params.bootstrapContextRunKind === "cron");
480
447
  }
481
- function prependCodexOpenClawPromptContext(prompt, context) {
482
- if (!context?.trim()) return prompt;
448
+ function renderCodexSkillsCollaborationInstructions(params) {
449
+ if (!shouldInjectCodexOpenClawPromptContext(params.attempt)) return;
450
+ return params.skillsPrompt?.trim() ? [
451
+ "## OpenClaw Skills",
452
+ "",
453
+ params.skillsPrompt.trim()
454
+ ].join("\n") : void 0;
455
+ }
456
+ function prependCodexOpenClawPromptContext(prompt, context, options = {}) {
483
457
  const { deliveryHint, prompt: promptWithoutDeliveryHint } = splitLeadingCodexDeliveryHint(prompt);
458
+ if (!context?.trim() && (!deliveryHint || options.preservePromptWithoutContext)) return prompt;
484
459
  const promptSection = promptWithoutDeliveryHint.startsWith("OpenClaw assembled context for this turn:") ? promptWithoutDeliveryHint : ["Current user request:", promptWithoutDeliveryHint].join("\n");
485
460
  const deliverySection = deliveryHint ? [
486
461
  "OpenClaw delivery metadata:",
@@ -488,7 +463,7 @@ function prependCodexOpenClawPromptContext(prompt, context) {
488
463
  deliveryHint
489
464
  ].join("\n") : void 0;
490
465
  return [
491
- context.trim(),
466
+ context?.trim(),
492
467
  deliverySection,
493
468
  promptSection
494
469
  ].filter(Boolean).join("\n\n");
@@ -550,11 +525,12 @@ function renderCodexWorkspaceCollaborationDeveloperInstructions(files) {
550
525
  return renderCodexWorkspaceDeveloperInstructions({
551
526
  files,
552
527
  header: "## OpenClaw Agent Soul",
553
- preamble: "OpenClaw loaded these workspace instruction files from the active agent workspace. They are the canonical definitions of who you are, how you think and work, and the human you work alongside. Internalize and follow them accordingly."
528
+ preamble: "OpenClaw loaded these workspace instruction files from the active agent workspace. They are the canonical definitions of who you are, how you think and work, and the human you work alongside. Internalize and follow them accordingly.",
529
+ wrapperTag: "AGENT_SOUL"
554
530
  });
555
531
  }
556
532
  function renderCodexWorkspaceDeveloperInstructions(params) {
557
- const { files, header, preamble } = params;
533
+ const { files, header, preamble, wrapperTag } = params;
558
534
  if (files.length === 0) return;
559
535
  const lines = [
560
536
  header,
@@ -562,7 +538,9 @@ function renderCodexWorkspaceDeveloperInstructions(params) {
562
538
  preamble,
563
539
  ""
564
540
  ];
541
+ if (wrapperTag) lines.push(`<${wrapperTag}>`, "");
565
542
  for (const file of files) lines.push(`### ${file.path}`, "", file.content, "");
543
+ if (wrapperTag) lines.push(`</${wrapperTag}>`);
566
544
  return lines.join("\n").trim();
567
545
  }
568
546
  function selectCodexWorkspaceHeartbeatReferenceFiles(contextFiles) {
@@ -594,7 +572,7 @@ function renderCodexWorkspaceMemoryReference(params) {
594
572
  const lines = [
595
573
  "## OpenClaw Workspace Memory",
596
574
  "",
597
- `MEMORY.md exists in the active agent workspace. OpenClaw does not paste its contents into native Codex turns; use ${(params.toolNames?.length ? params.toolNames : Array.from(CODEX_MEMORY_TOOL_NAMES)).join(" or ")} when durable memory is relevant and the tools are available.`,
575
+ `MEMORY.md exists in the active agent workspace as a memory file, not an instruction file. OpenClaw does not paste its contents into native Codex turns; use ${(params.toolNames?.length ? params.toolNames : Array.from(CODEX_MEMORY_TOOL_NAMES)).join(" or ")} when durable memory is relevant and the tools are available.`,
598
576
  ""
599
577
  ];
600
578
  for (const file of params.files) lines.push(`- ${file.path}`);
@@ -825,6 +803,11 @@ function isReasoningItemCompletionNotification(notification) {
825
803
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
826
804
  return item ? readString$6(item, "type") === "reasoning" : false;
827
805
  }
806
+ function isAssistantCommentaryCompletionNotification(notification) {
807
+ if (!isJsonObject(notification.params) || notification.method !== "item/completed") return false;
808
+ const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
809
+ return Boolean(item && readString$6(item, "type") === "agentMessage" && readString$6(item, "phase") === "commentary");
810
+ }
828
811
  function isRawReasoningCompletionNotification(notification) {
829
812
  if (!isJsonObject(notification.params) || notification.method !== "rawResponseItem/completed") return false;
830
813
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
@@ -870,10 +853,21 @@ function isNativeToolProgressNotification(notification) {
870
853
  default: return false;
871
854
  }
872
855
  }
873
- function isRawAssistantCompletionNotification(notification) {
856
+ function isNativeResponseStreamDeltaNotification(notification) {
857
+ return notification.method.startsWith("response.") && notification.method.endsWith(".delta");
858
+ }
859
+ function isFileChangePatchUpdatedNotification(notification) {
860
+ return notification.method === "item/fileChange/patchUpdated" && isJsonObject(notification.params);
861
+ }
862
+ function isRawAssistantProgressNotification(notification) {
874
863
  if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
875
864
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
876
- return Boolean(item && readString$6(item, "type") === "message" && readString$6(item, "role") === "assistant" && readString$6(item, "phase") !== "commentary" && readRawAssistantTextPreview(item));
865
+ return Boolean(item && readString$6(item, "type") === "message" && readString$6(item, "role") === "assistant" && readRawAssistantTextPreview(item));
866
+ }
867
+ function isRawAssistantCompletionNotification(notification) {
868
+ if (!isRawAssistantProgressNotification(notification) || !isJsonObject(notification.params)) return false;
869
+ const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
870
+ return Boolean(item && readString$6(item, "phase") !== "commentary");
877
871
  }
878
872
  function readRawAssistantTextPreview(item) {
879
873
  if (readString$6(item, "role") !== "assistant" || !Array.isArray(item.content)) return;
@@ -964,69 +958,6 @@ function codexExecutionToolName(item) {
964
958
  function isNonEmptyString$1(value) {
965
959
  return typeof value === "string" && value.length > 0;
966
960
  }
967
- const CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS = 6e4;
968
- const CODEX_TURN_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS = 1e4;
969
- const CODEX_POST_REASONING_SOURCE_REPLY_IDLE_TIMEOUT_MS = 5 * 6e4;
970
- const CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS = 30 * 6e4;
971
- function resolvePositiveIntegerTimeoutMs(value, fallbackMs) {
972
- const fallback = parseFiniteNumber(fallbackMs) ?? 1;
973
- const candidate = parseFiniteNumber(value) ?? fallback;
974
- return Math.max(1, Math.floor(candidate));
975
- }
976
- async function withCodexStartupTimeout(params) {
977
- if (params.signal.aborted) throw new Error("codex app-server startup aborted");
978
- let timeout;
979
- let abortCleanup;
980
- let timeoutError;
981
- let timeoutCleanup;
982
- try {
983
- return await Promise.race([params.operation(), new Promise((_, reject) => {
984
- const rejectOnce = (error) => {
985
- if (timeout) {
986
- clearTimeout(timeout);
987
- timeout = void 0;
988
- }
989
- reject(error);
990
- };
991
- timeout = setTimeout(() => {
992
- timeoutError = /* @__PURE__ */ new Error("codex app-server startup timed out");
993
- timeoutCleanup = Promise.resolve(params.onTimeout?.()).then(() => void 0, () => void 0);
994
- timeoutCleanup.finally(() => {
995
- rejectOnce(timeoutError);
996
- });
997
- }, params.timeoutMs);
998
- const abortListener = () => rejectOnce(/* @__PURE__ */ new Error("codex app-server startup aborted"));
999
- params.signal.addEventListener("abort", abortListener, { once: true });
1000
- abortCleanup = () => params.signal.removeEventListener("abort", abortListener);
1001
- })]);
1002
- } catch (error) {
1003
- if (timeoutError) {
1004
- await timeoutCleanup;
1005
- throw timeoutError;
1006
- }
1007
- throw error;
1008
- } finally {
1009
- if (timeout) clearTimeout(timeout);
1010
- abortCleanup?.();
1011
- }
1012
- }
1013
- function resolveCodexStartupTimeoutMs(params) {
1014
- const timeoutFloorMs = resolvePositiveIntegerTimeoutMs(params.timeoutFloorMs, 100);
1015
- const timeoutMs = resolvePositiveIntegerTimeoutMs(params.timeoutMs, timeoutFloorMs);
1016
- return Math.max(timeoutFloorMs, timeoutMs);
1017
- }
1018
- function resolveCodexTurnCompletionIdleTimeoutMs(value) {
1019
- return resolvePositiveIntegerTimeoutMs(value, CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS);
1020
- }
1021
- function resolveCodexTurnAssistantCompletionIdleTimeoutMs(value) {
1022
- return resolvePositiveIntegerTimeoutMs(value, CODEX_TURN_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS);
1023
- }
1024
- function resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs(value, fallbackMs) {
1025
- return resolvePositiveIntegerTimeoutMs(value, fallbackMs);
1026
- }
1027
- function resolveCodexTurnTerminalIdleTimeoutMs(value) {
1028
- return resolvePositiveIntegerTimeoutMs(value, CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS);
1029
- }
1030
961
  //#endregion
1031
962
  //#region extensions/codex/src/app-server/attempt-notification-state.ts
1032
963
  function reportCodexExecutionNotification(params) {
@@ -1057,8 +988,9 @@ function applyCodexTurnNotificationState(params) {
1057
988
  const { notification, turnWatches } = params;
1058
989
  const isCurrentTurnNotification = isTurnNotification(notification.params, params.threadId, params.turnId);
1059
990
  const isTurnCompletion = notification.method === "turn/completed" && isCurrentTurnNotification;
991
+ const isNativeResponseStreamDelta = isNativeResponseStreamDeltaNotification(notification);
1060
992
  let turnCrossedToolHandoff = params.turnCrossedToolHandoff;
1061
- if (isCurrentTurnNotification) {
993
+ if (isCurrentTurnNotification && !isNativeResponseStreamDelta) {
1062
994
  turnWatches.touchActivity(`notification:${notification.method}`, {
1063
995
  details: describeNotificationActivity(notification),
1064
996
  attemptProgress: true
@@ -1072,25 +1004,37 @@ function applyCodexTurnNotificationState(params) {
1072
1004
  const rawToolOutputCompletion = isRawToolOutputCompletionNotification(notification);
1073
1005
  if (isCurrentTurnNotification && (rawToolOutputCompletion || isNativeToolProgressNotification(notification))) turnCrossedToolHandoff = true;
1074
1006
  const assistantCompletionCanRelease = isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff);
1075
- const postToolRawAssistantCompletionNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && isRawAssistantCompletionNotification(notification) && params.activeTurnItemIds.size === 0;
1076
- const rawResponseItemCompletedWithNoActiveItems = isCurrentTurnNotification && notification.method === "rawResponseItem/completed" && params.activeTurnItemIds.size === 0 && params.activeAppServerTurnRequests === 0 && !assistantCompletionCanRelease && !postToolRawAssistantCompletionNeedsTerminalGuard;
1077
- const shouldArmPostReasoningSourceReplyWatch = isCurrentTurnNotification && isReasoningItemCompletionNotification(notification) && params.activeTurnItemIds.size === 0 && params.sourceReplyDeliveryMode === "message_tool_only";
1078
- const shouldArmPostRawReasoningSourceReplyWatch = rawResponseItemCompletedWithNoActiveItems && isRawReasoningCompletionNotification(notification) && params.sourceReplyDeliveryMode === "message_tool_only";
1079
- const shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem = isCurrentTurnNotification && notification.method === "item/completed" && params.activeTurnItemIds.size === 0 && !trackedDynamicToolCompletion && !assistantCompletionCanRelease && !shouldArmPostReasoningSourceReplyWatch;
1007
+ const postToolRawAssistantCompletionNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && isRawAssistantProgressNotification(notification) && params.activeTurnItemIds.size === 0;
1008
+ const postToolPatchUpdateNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && isFileChangePatchUpdatedNotification(notification);
1009
+ const rawResponseItemCompletedWithNoActiveItems = isCurrentTurnNotification && notification.method === "rawResponseItem/completed" && params.activeTurnItemIds.size === 0 && params.activeAppServerTurnRequests === 0 && !assistantCompletionCanRelease && !postToolRawAssistantCompletionNeedsTerminalGuard && !rawToolOutputCompletion;
1010
+ const shouldArmNoToolPostProgressReplyWatch = isCurrentTurnNotification && !turnCrossedToolHandoff && params.activeTurnItemIds.size === 0 && (isReasoningItemCompletionNotification(notification) || isAssistantCommentaryCompletionNotification(notification));
1011
+ const shouldArmNoToolPostRawProgressReplyWatch = !turnCrossedToolHandoff && rawResponseItemCompletedWithNoActiveItems && (isRawReasoningCompletionNotification(notification) || isRawAssistantProgressNotification(notification));
1012
+ const shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem = isCurrentTurnNotification && notification.method === "item/completed" && params.activeTurnItemIds.size === 0 && !trackedDynamicToolCompletion && !assistantCompletionCanRelease && !shouldArmNoToolPostProgressReplyWatch;
1013
+ const shouldUsePostToolContinuationWatch = turnCrossedToolHandoff && (postToolRawAssistantCompletionNeedsTerminalGuard || postToolPatchUpdateNeedsTerminalGuard || rawToolOutputCompletion || trackedDynamicToolCompletion || shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem);
1014
+ const armPostToolContinuationWatch = () => {
1015
+ turnWatches.armCompletionIdleWatch({ timeoutMs: params.postToolRawAssistantCompletionIdleTimeoutMs });
1016
+ turnWatches.extendAttemptIdleWatch(params.postToolRawAssistantCompletionIdleTimeoutMs);
1017
+ };
1018
+ const armPostProgressReplyWatch = () => {
1019
+ turnWatches.armCompletionIdleWatch({ timeoutMs: CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS });
1020
+ turnWatches.extendAttemptIdleWatch(CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS);
1021
+ };
1080
1022
  if (isCurrentTurnNotification && notification.method === "error") {
1081
1023
  if (isRetryableErrorNotification(notification.params)) turnWatches.disarmCompletionIdleWatch();
1082
1024
  else turnWatches.armCompletionIdleWatch({ pinnedByTerminalError: true });
1083
1025
  turnWatches.disarmAssistantCompletionIdleWatch();
1084
1026
  } else if (isTurnCompletion) turnWatches.disarmAssistantCompletionIdleWatch();
1085
1027
  else if (isCurrentTurnNotification && assistantCompletionCanRelease) turnWatches.armAssistantCompletionIdleWatch(describeNotificationActivity(notification));
1086
- else if (postToolRawAssistantCompletionNeedsTerminalGuard) turnWatches.armCompletionIdleWatch({ timeoutMs: params.postToolRawAssistantCompletionIdleTimeoutMs });
1087
- else if (shouldArmPostReasoningSourceReplyWatch || shouldArmPostRawReasoningSourceReplyWatch) turnWatches.armCompletionIdleWatch({ timeoutMs: CODEX_POST_REASONING_SOURCE_REPLY_IDLE_TIMEOUT_MS });
1028
+ else if (postToolRawAssistantCompletionNeedsTerminalGuard || postToolPatchUpdateNeedsTerminalGuard) armPostToolContinuationWatch();
1029
+ else if (shouldArmNoToolPostProgressReplyWatch || shouldArmNoToolPostRawProgressReplyWatch) armPostProgressReplyWatch();
1030
+ else if (trackedDynamicToolCompletion) armPostToolContinuationWatch();
1088
1031
  else if (unblockedAssistantCompletionRelease) turnWatches.armAssistantCompletionIdleWatch(describeNotificationActivity(notification));
1089
- else if (shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) turnWatches.armCompletionIdleWatch();
1032
+ else if (shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) if (shouldUsePostToolContinuationWatch) armPostToolContinuationWatch();
1033
+ else turnWatches.armCompletionIdleWatch();
1090
1034
  else if (rawResponseItemCompletedWithNoActiveItems) turnWatches.armCompletionIdleWatch();
1091
- else if (isCurrentTurnNotification && rawToolOutputCompletion) turnWatches.armCompletionIdleWatch();
1035
+ else if (isCurrentTurnNotification && rawToolOutputCompletion) armPostToolContinuationWatch();
1092
1036
  else if (isCurrentTurnNotification && shouldDisarmAssistantCompletionIdleWatch(notification)) turnWatches.disarmAssistantCompletionIdleWatch();
1093
- if (turnWatches.isCompletionIdleWatchArmed() && !turnWatches.isCompletionIdleWatchPinnedByTerminalError() && notification.method !== "turn/completed" && isCurrentTurnNotification && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !postToolRawAssistantCompletionNeedsTerminalGuard && !rawResponseItemCompletedWithNoActiveItems && !shouldArmPostReasoningSourceReplyWatch && !shouldArmPostRawReasoningSourceReplyWatch && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) turnWatches.disarmCompletionIdleWatch();
1037
+ if (turnWatches.isCompletionIdleWatchArmed() && !turnWatches.isCompletionIdleWatchPinnedByTerminalError() && notification.method !== "turn/completed" && isCurrentTurnNotification && !isNativeResponseStreamDelta && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !postToolRawAssistantCompletionNeedsTerminalGuard && !postToolPatchUpdateNeedsTerminalGuard && !rawResponseItemCompletedWithNoActiveItems && !shouldArmNoToolPostProgressReplyWatch && !shouldArmNoToolPostRawProgressReplyWatch && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) turnWatches.disarmCompletionIdleWatch();
1094
1038
  if (trackedDynamicToolCompletion) {
1095
1039
  const itemId = readNotificationItemId(notification);
1096
1040
  if (itemId) {
@@ -1122,7 +1066,8 @@ function hasCodexAppServerPotentialSideEffectEvidence(result) {
1122
1066
  }
1123
1067
  function buildCodexAppServerPromptTimeoutOutcome(params) {
1124
1068
  const completionIdleTimeoutHadPotentialSideEffects = hasCodexAppServerPotentialSideEffectEvidence(params.result);
1125
- if (!params.turnCompletionIdleTimedOut || params.result.itemLifecycle.completedCount === 0 && !completionIdleTimeoutHadPotentialSideEffects) return;
1069
+ const replayBlockedReason = resolveCodexAppServerReplayBlockedReason(params.result);
1070
+ if (!params.turnCompletionIdleTimedOut || params.result.itemLifecycle.completedCount === 0 && !completionIdleTimeoutHadPotentialSideEffects && replayBlockedReason === void 0) return;
1126
1071
  return {
1127
1072
  message: completionIdleTimeoutHadPotentialSideEffects ? CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_SIDE_EFFECT_USER_MESSAGE : CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_USER_MESSAGE,
1128
1073
  ...completionIdleTimeoutHadPotentialSideEffects ? {
@@ -3015,6 +2960,7 @@ function createCodexAttemptTurnWatchController(params) {
3015
2960
  let completionLastActivityAt = Date.now();
3016
2961
  let completionLastActivityReason = "startup";
3017
2962
  let completionLastActivityDetails;
2963
+ let attemptIdleTimeoutOverrideMs;
3018
2964
  let attemptLastProgressAt = Date.now();
3019
2965
  let attemptLastProgressReason = "startup";
3020
2966
  let attemptLastProgressDetails;
@@ -3069,7 +3015,8 @@ function createCodexAttemptTurnWatchController(params) {
3069
3015
  clearAttemptIdleTimer();
3070
3016
  if (params.isCompleted() || params.signal.aborted || !attemptIdleWatchArmed) return;
3071
3017
  const elapsedMs = Math.max(0, Date.now() - attemptLastProgressAt);
3072
- const delayMs = Math.max(1, params.turnAttemptIdleTimeoutMs - elapsedMs);
3018
+ const timeoutMs = attemptIdleTimeoutOverrideMs ?? params.turnAttemptIdleTimeoutMs;
3019
+ const delayMs = Math.max(1, timeoutMs - elapsedMs);
3073
3020
  attemptIdleTimer = setTimeout(fireAttemptIdleTimeout, delayMs);
3074
3021
  attemptIdleTimer.unref?.();
3075
3022
  }
@@ -3086,6 +3033,14 @@ function createCodexAttemptTurnWatchController(params) {
3086
3033
  scheduleCompletionIdleWatch();
3087
3034
  scheduleTerminalIdleWatch();
3088
3035
  }
3036
+ function recordAttemptProgress(reason, options) {
3037
+ attemptIdleTimeoutOverrideMs = options?.attemptTimeoutMs !== void 0 ? Math.max(1, Math.floor(options.attemptTimeoutMs)) : void 0;
3038
+ attemptLastProgressAt = completionLastActivityAt;
3039
+ attemptLastProgressReason = reason;
3040
+ attemptLastProgressDetails = options?.details;
3041
+ params.onAttemptProgress(reason, options?.details);
3042
+ scheduleAttemptIdleWatch();
3043
+ }
3089
3044
  function fireAssistantCompletionIdleRelease() {
3090
3045
  if (params.isCompleted() || params.signal.aborted || !assistantCompletionIdleWatchArmed) return;
3091
3046
  if (params.getActiveAppServerTurnRequests() > 0 || params.getActiveTurnItemCount() > 0) {
@@ -3126,14 +3081,15 @@ function createCodexAttemptTurnWatchController(params) {
3126
3081
  function fireAttemptIdleTimeout() {
3127
3082
  if (params.isCompleted() || params.signal.aborted || !attemptIdleWatchArmed) return;
3128
3083
  const idleMs = Math.max(0, Date.now() - attemptLastProgressAt);
3129
- if (idleMs < params.turnAttemptIdleTimeoutMs) {
3084
+ const timeoutMs = attemptIdleTimeoutOverrideMs ?? params.turnAttemptIdleTimeoutMs;
3085
+ if (idleMs < timeoutMs) {
3130
3086
  scheduleAttemptIdleWatch();
3131
3087
  return;
3132
3088
  }
3133
3089
  const timeout = {
3134
3090
  kind: "progress",
3135
3091
  idleMs,
3136
- timeoutMs: params.turnAttemptIdleTimeoutMs,
3092
+ timeoutMs,
3137
3093
  lastActivityReason: attemptLastProgressReason,
3138
3094
  details: attemptLastProgressDetails
3139
3095
  };
@@ -3266,12 +3222,7 @@ function createCodexAttemptTurnWatchController(params) {
3266
3222
  completionLastActivityReason = reason;
3267
3223
  completionLastActivityDetails = options?.details;
3268
3224
  completionIdleTimeoutOverrideMs = void 0;
3269
- if (options?.attemptProgress) {
3270
- attemptLastProgressAt = completionLastActivityAt;
3271
- attemptLastProgressReason = reason;
3272
- attemptLastProgressDetails = options.details;
3273
- params.onAttemptProgress(reason, options.details);
3274
- }
3225
+ if (options?.attemptProgress) recordAttemptProgress(reason, options);
3275
3226
  params.onProgressDiagnostic(reason);
3276
3227
  if (options?.arm) {
3277
3228
  completionIdleWatchArmed = true;
@@ -3279,9 +3230,15 @@ function createCodexAttemptTurnWatchController(params) {
3279
3230
  }
3280
3231
  scheduleProgressWatches();
3281
3232
  },
3282
- noteNotificationReceived: (method) => {
3233
+ noteNotificationReceived: (method, options) => {
3283
3234
  completionLastActivityAt = Date.now();
3284
3235
  completionLastActivityReason = `notification:${method}`;
3236
+ if (options?.details !== void 0) completionLastActivityDetails = options.details;
3237
+ if (options?.attemptProgress) recordAttemptProgress(completionLastActivityReason, options);
3238
+ },
3239
+ extendAttemptIdleWatch: (timeoutMs) => {
3240
+ attemptIdleTimeoutOverrideMs = Math.max(1, Math.floor(timeoutMs));
3241
+ scheduleAttemptIdleWatch();
3285
3242
  },
3286
3243
  scheduleProgressWatches,
3287
3244
  clearCompletionIdleTimer,
@@ -3488,15 +3445,14 @@ function clampDynamicToolTimeoutMs(timeoutMs) {
3488
3445
  //#region extensions/codex/src/app-server/local-runtime-attribution.ts
3489
3446
  const OPENAI_PROVIDER_ID = "openai";
3490
3447
  const OPENAI_RESPONSES_API = "openai-responses";
3491
- const OPENAI_CODEX_PROVIDER_ID = "openai-codex";
3492
- const OPENAI_CODEX_RESPONSES_API = "openai-codex-responses";
3448
+ const OPENAI_CODEX_RESPONSES_API = "openai-chatgpt-responses";
3493
3449
  function normalizeRuntimeId(value) {
3494
3450
  return value?.trim().toLowerCase() ?? "";
3495
3451
  }
3496
3452
  function resolveCodexLocalRuntimeAttribution(params) {
3497
3453
  const authProfileProvider = normalizeRuntimeId(params.runtimePlan?.auth?.authProfileProviderForAuth);
3498
3454
  if (normalizeRuntimeId(params.runtimePlan?.observability.harnessId) === "codex" && authProfileProvider !== OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.provider) === OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.api) === OPENAI_RESPONSES_API) return {
3499
- provider: OPENAI_CODEX_PROVIDER_ID,
3455
+ provider: OPENAI_PROVIDER_ID,
3500
3456
  api: OPENAI_CODEX_RESPONSES_API
3501
3457
  };
3502
3458
  return {
@@ -3756,6 +3712,7 @@ async function mirrorCodexAppServerTranscript(params) {
3756
3712
  for (const update of appendedUpdates) emitSessionTranscriptUpdate({
3757
3713
  sessionFile: params.sessionFile,
3758
3714
  ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
3715
+ ...params.agentId ? { agentId: params.agentId } : {},
3759
3716
  message: update.message,
3760
3717
  messageId: update.messageId,
3761
3718
  messageSeq: update.messageSeq
@@ -3828,6 +3785,9 @@ const CODEX_PROMPT_TOTAL_INPUT_KEYS = [
3828
3785
  ];
3829
3786
  const MAX_TOOL_OUTPUT_DELTA_MESSAGES_PER_ITEM = 20;
3830
3787
  const TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS = 12e3;
3788
+ const GENERATED_IMAGE_MEDIA_SUBDIR = "tool-image-generation";
3789
+ const BYTES_PER_MB = 1024 * 1024;
3790
+ const DEFAULT_GENERATED_IMAGE_MAX_BYTES = 6 * BYTES_PER_MB;
3831
3791
  const TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES = new Set([
3832
3792
  "message",
3833
3793
  "messages",
@@ -3873,6 +3833,8 @@ var CodexAppServerEventProjector = class {
3873
3833
  this.toolTranscriptResultIds = /* @__PURE__ */ new Set();
3874
3834
  this.transcriptToolProgressCallIds = /* @__PURE__ */ new Set();
3875
3835
  this.nativeGeneratedMediaUrls = /* @__PURE__ */ new Set();
3836
+ this.nativeGeneratedMediaItemIds = /* @__PURE__ */ new Set();
3837
+ this.nativeGeneratedMediaUrlsByItemId = /* @__PURE__ */ new Map();
3876
3838
  this.diagnosticToolStartedAtByItem = /* @__PURE__ */ new Map();
3877
3839
  this.afterToolCallObservedItemIds = /* @__PURE__ */ new Set();
3878
3840
  this.assistantStarted = false;
@@ -3938,7 +3900,7 @@ var CodexAppServerEventProjector = class {
3938
3900
  await this.handleTurnCompleted(params);
3939
3901
  break;
3940
3902
  case "rawResponseItem/completed":
3941
- this.handleRawResponseItemCompleted(params);
3903
+ await this.handleRawResponseItemCompleted(params);
3942
3904
  break;
3943
3905
  case "error":
3944
3906
  if (readBooleanAlias(params, ["willRetry", "will_retry"]) === true) break;
@@ -3969,7 +3931,7 @@ var CodexAppServerEventProjector = class {
3969
3931
  turnCompleted: Boolean(this.completedTurn)
3970
3932
  });
3971
3933
  const toolMetas = [...this.toolMetas.values()];
3972
- const hadPotentialSideEffects = toolTelemetry.didSendViaMessagingTool || (toolTelemetry.successfulCronAdds ?? 0) > 0 || this.sideEffectingToolItemIds.size > 0 || this.sideEffectingDynamicToolCallIds.size > 0;
3934
+ const hadPotentialSideEffects = toolTelemetry.didSendViaMessagingTool || (toolTelemetry.successfulCronAdds ?? 0) > 0 || this.nativeGeneratedMediaItemIds.size > 0 || this.sideEffectingToolItemIds.size > 0 || this.sideEffectingDynamicToolCallIds.size > 0;
3973
3935
  return {
3974
3936
  aborted: this.aborted,
3975
3937
  externalAbort: false,
@@ -4390,9 +4352,11 @@ var CodexAppServerEventProjector = class {
4390
4352
  text: formatToolOutput(toolName, void 0, reachedLimit ? `${chunk}\n...(truncated)...` : chunk)
4391
4353
  });
4392
4354
  }
4393
- handleRawResponseItemCompleted(params) {
4355
+ async handleRawResponseItemCompleted(params) {
4394
4356
  const item = isJsonObject(params.item) ? params.item : void 0;
4395
- if (!item || readString$5(item, "role") !== "assistant") return;
4357
+ if (!item) return;
4358
+ await this.recordRawGeneratedImageMedia(item);
4359
+ if (readString$5(item, "role") !== "assistant") return;
4396
4360
  const text = extractRawAssistantText(item);
4397
4361
  if (!text) return;
4398
4362
  const itemId = readString$5(item, "id") ?? `raw-assistant-${this.assistantItemOrder.length + 1}`;
@@ -4408,7 +4372,56 @@ var CodexAppServerEventProjector = class {
4408
4372
  recordNativeGeneratedMedia(item) {
4409
4373
  if (item?.type !== "imageGeneration") return;
4410
4374
  const savedPath = readItemString(item, "savedPath")?.trim();
4411
- if (savedPath) this.nativeGeneratedMediaUrls.add(savedPath);
4375
+ if (savedPath) this.recordNativeGeneratedMediaUrl({
4376
+ itemId: item.id,
4377
+ mediaUrl: savedPath
4378
+ });
4379
+ }
4380
+ async recordRawGeneratedImageMedia(item) {
4381
+ if (readString$5(item, "type") !== "image_generation_call") return;
4382
+ const result = readString$5(item, "result");
4383
+ if (!result) return;
4384
+ const itemId = readString$5(item, "id") ?? `raw-image-${this.nativeGeneratedMediaItemIds.size}`;
4385
+ this.nativeGeneratedMediaItemIds.add(itemId);
4386
+ const maxBytes = resolveGeneratedImageMaxBytes(this.params.config);
4387
+ const estimatedDecodedBytes = estimateBase64DecodedBytes(result);
4388
+ if (estimatedDecodedBytes !== void 0 && estimatedDecodedBytes > maxBytes) {
4389
+ embeddedAgentLog.warn("codex app-server raw image generation result exceeds media limit", {
4390
+ itemId,
4391
+ estimatedDecodedBytes,
4392
+ maxBytes
4393
+ });
4394
+ return;
4395
+ }
4396
+ const asset = generatedImageAssetFromBase64({
4397
+ base64: result,
4398
+ index: this.nativeGeneratedMediaItemIds.size,
4399
+ revisedPrompt: readString$5(item, "revised_prompt") ?? readString$5(item, "revisedPrompt"),
4400
+ fileNamePrefix: "codex-image-generation",
4401
+ sniffMimeType: true
4402
+ });
4403
+ if (!asset) return;
4404
+ try {
4405
+ const saved = await saveMediaBuffer(asset.buffer, asset.mimeType, GENERATED_IMAGE_MEDIA_SUBDIR, maxBytes, asset.fileName);
4406
+ this.recordNativeGeneratedMediaUrl({
4407
+ itemId,
4408
+ mediaUrl: saved.path
4409
+ });
4410
+ } catch (error) {
4411
+ embeddedAgentLog.warn("codex app-server raw image generation result save failed", {
4412
+ itemId,
4413
+ error
4414
+ });
4415
+ }
4416
+ }
4417
+ recordNativeGeneratedMediaUrl(params) {
4418
+ if (this.nativeGeneratedMediaUrlsByItemId.has(params.itemId)) {
4419
+ this.nativeGeneratedMediaItemIds.add(params.itemId);
4420
+ return;
4421
+ }
4422
+ this.nativeGeneratedMediaUrlsByItemId.set(params.itemId, params.mediaUrl);
4423
+ this.nativeGeneratedMediaUrls.add(params.mediaUrl);
4424
+ this.nativeGeneratedMediaItemIds.add(params.itemId);
4412
4425
  }
4413
4426
  buildToolMediaUrls(toolTelemetry) {
4414
4427
  const mediaUrls = new Set(toolTelemetry.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []);
@@ -4835,7 +4848,7 @@ var CodexAppServerEventProjector = class {
4835
4848
  type: "text",
4836
4849
  text
4837
4850
  }],
4838
- api: attribution.api ?? "openai-codex-responses",
4851
+ api: attribution.api ?? "openai-chatgpt-responses",
4839
4852
  provider: attribution.provider,
4840
4853
  model: this.params.modelId,
4841
4854
  usage,
@@ -4852,7 +4865,7 @@ var CodexAppServerEventProjector = class {
4852
4865
  type: "text",
4853
4866
  text: `${title}:\n${text}`
4854
4867
  }],
4855
- api: attribution.api ?? "openai-codex-responses",
4868
+ api: attribution.api ?? "openai-chatgpt-responses",
4856
4869
  provider: attribution.provider,
4857
4870
  model: this.params.modelId,
4858
4871
  usage: ZERO_USAGE,
@@ -4872,7 +4885,7 @@ var CodexAppServerEventProjector = class {
4872
4885
  arguments: args,
4873
4886
  input: args
4874
4887
  }],
4875
- api: attribution.api ?? "openai-codex-responses",
4888
+ api: attribution.api ?? "openai-chatgpt-responses",
4876
4889
  provider: attribution.provider,
4877
4890
  model: this.params.modelId,
4878
4891
  usage: ZERO_USAGE,
@@ -4922,6 +4935,30 @@ function readString$5(record, key) {
4922
4935
  const value = record[key];
4923
4936
  return typeof value === "string" ? value : void 0;
4924
4937
  }
4938
+ function estimateBase64DecodedBytes(base64) {
4939
+ let nonWhitespaceLength = 0;
4940
+ let previousCode = -1;
4941
+ let lastCode = -1;
4942
+ for (let i = 0; i < base64.length; i += 1) {
4943
+ const code = base64.charCodeAt(i);
4944
+ if (isBase64WhitespaceCode(code)) continue;
4945
+ nonWhitespaceLength += 1;
4946
+ previousCode = lastCode;
4947
+ lastCode = code;
4948
+ }
4949
+ if (nonWhitespaceLength === 0) return;
4950
+ const equalsCode = "=".charCodeAt(0);
4951
+ const padding = lastCode === equalsCode ? previousCode === equalsCode ? 2 : 1 : 0;
4952
+ return Math.max(0, Math.floor(nonWhitespaceLength * 3 / 4) - padding);
4953
+ }
4954
+ function isBase64WhitespaceCode(code) {
4955
+ return code === 32 || code === 9 || code === 10 || code === 13;
4956
+ }
4957
+ function resolveGeneratedImageMaxBytes(config) {
4958
+ const configured = config?.agents?.defaults?.mediaMaxMb;
4959
+ if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) return Math.floor(configured * BYTES_PER_MB);
4960
+ return DEFAULT_GENERATED_IMAGE_MAX_BYTES;
4961
+ }
4925
4962
  function normalizeNonEmptyString(value) {
4926
4963
  if (typeof value !== "string") return;
4927
4964
  return value.trim() || void 0;
@@ -6351,6 +6388,9 @@ function unrefTimer(timer) {
6351
6388
  //#endregion
6352
6389
  //#region extensions/codex/src/app-server/startup-binding.ts
6353
6390
  const CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS = 3e5;
6391
+ const CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS = 2e4;
6392
+ const CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_TOKENS = 8e3;
6393
+ const CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_RATIO = .5;
6354
6394
  const CODEX_APP_SERVER_BYTE_UNITS = {
6355
6395
  b: 1,
6356
6396
  k: 1024,
@@ -6366,6 +6406,7 @@ const CODEX_APP_SERVER_BYTE_UNITS = {
6366
6406
  tb: 1024 * 1024 * 1024 * 1024,
6367
6407
  tib: 1024 * 1024 * 1024 * 1024
6368
6408
  };
6409
+ const codexSessionRecordCache = /* @__PURE__ */ new Map();
6369
6410
  function parseCodexAppServerByteLimit(value) {
6370
6411
  if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.floor(value);
6371
6412
  if (typeof value !== "string") return;
@@ -6421,22 +6462,44 @@ async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codex
6421
6462
  }
6422
6463
  async function readCodexSessionRecordForSessionFile(sessionFile) {
6423
6464
  const sessionsFile = path.join(path.dirname(sessionFile), "sessions.json");
6465
+ const resolvedSessionFile = path.resolve(sessionFile);
6466
+ let stat;
6467
+ try {
6468
+ stat = await fs.stat(sessionsFile);
6469
+ } catch {
6470
+ codexSessionRecordCache.delete(resolvedSessionFile);
6471
+ return;
6472
+ }
6473
+ const cached = codexSessionRecordCache.get(resolvedSessionFile);
6474
+ if (cached?.sessionsFile === sessionsFile && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) return cached.record;
6424
6475
  let store;
6425
6476
  try {
6426
6477
  store = JSON.parse(await fs.readFile(sessionsFile, "utf8"));
6427
6478
  } catch {
6479
+ codexSessionRecordCache.delete(resolvedSessionFile);
6428
6480
  return;
6429
6481
  }
6430
- if (!isJsonObject(store)) return;
6431
- const resolvedSessionFile = path.resolve(sessionFile);
6482
+ if (!isJsonObject(store)) {
6483
+ codexSessionRecordCache.delete(resolvedSessionFile);
6484
+ return;
6485
+ }
6486
+ let found;
6432
6487
  for (const [sessionKey, record] of Object.entries(store)) {
6433
6488
  if (!isJsonObject(record) || typeof record.sessionFile !== "string") continue;
6434
6489
  if (path.resolve(record.sessionFile) !== resolvedSessionFile) continue;
6435
- return {
6490
+ found = {
6436
6491
  sessionKey,
6437
6492
  ...record
6438
6493
  };
6494
+ break;
6439
6495
  }
6496
+ codexSessionRecordCache.set(resolvedSessionFile, {
6497
+ sessionsFile,
6498
+ mtimeMs: stat.mtimeMs,
6499
+ size: stat.size,
6500
+ record: found
6501
+ });
6502
+ return found;
6440
6503
  }
6441
6504
  async function readCodexAppServerRolloutTokenSnapshot(file) {
6442
6505
  let handle;
@@ -6480,52 +6543,75 @@ function readCodexAppServerRolloutTokenSnapshotLine(line) {
6480
6543
  return;
6481
6544
  }
6482
6545
  }
6483
- function resolveCodexAppServerNativeThreadTokenFuse(modelContextWindow) {
6484
- return modelContextWindow ?? CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS;
6546
+ function toNonNegativeInt(value) {
6547
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return;
6548
+ return Math.floor(value);
6549
+ }
6550
+ function readCompactionConfig(config) {
6551
+ return isJsonObject(config?.agents?.defaults?.compaction) ? config.agents.defaults.compaction : void 0;
6552
+ }
6553
+ function resolveCodexAppServerNativeThreadReserveTokens(config) {
6554
+ const compaction = readCompactionConfig(config);
6555
+ const reserveTokens = toNonNegativeInt(compaction?.reserveTokens);
6556
+ const reserveTokensFloor = toNonNegativeInt(compaction?.reserveTokensFloor);
6557
+ if (reserveTokens !== void 0) return Math.max(reserveTokens, reserveTokensFloor ?? CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS);
6558
+ return reserveTokensFloor ?? CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS;
6559
+ }
6560
+ function resolveCodexAppServerNativeThreadTokenFuse(params) {
6561
+ const projectedTurnTokens = typeof params.projectedTurnTokens === "number" && Number.isFinite(params.projectedTurnTokens) && params.projectedTurnTokens > 0 ? Math.floor(params.projectedTurnTokens) : 0;
6562
+ const contextWindow = params.modelContextWindow ?? CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS;
6563
+ const minPromptBudget = Math.min(CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_TOKENS, Math.max(1, Math.floor(contextWindow * CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_RATIO)));
6564
+ const effectiveReserveTokens = Math.min(params.reserveTokens, Math.max(0, contextWindow - minPromptBudget));
6565
+ return Math.max(1, contextWindow - effectiveReserveTokens - projectedTurnTokens);
6485
6566
  }
6486
6567
  function maxFiniteNumber(values) {
6487
6568
  const nums = values.filter((value) => typeof value === "number" && Number.isFinite(value));
6488
6569
  if (nums.length === 0) return;
6489
6570
  return Math.max(...nums);
6490
6571
  }
6572
+ function minFiniteNumber(values) {
6573
+ const nums = values.filter((value) => typeof value === "number" && Number.isFinite(value));
6574
+ if (nums.length === 0) return;
6575
+ return Math.min(...nums);
6576
+ }
6491
6577
  function hasContextEngineThreadBootstrapProjection(binding) {
6492
6578
  return binding.contextEngine?.projection?.mode === "thread_bootstrap";
6493
6579
  }
6494
6580
  async function rotateOversizedCodexAppServerStartupBinding(params) {
6495
6581
  const binding = params.binding;
6496
6582
  if (!binding?.threadId) return binding;
6497
- if (params.config?.agents?.defaults?.compaction?.truncateAfterCompaction !== true) return binding;
6498
- if (params.contextEngineActive === true && hasContextEngineThreadBootstrapProjection(binding)) {
6499
- embeddedAgentLog.debug("codex app-server deferring native transcript size guard for context-engine thread bootstrap", {
6500
- threadId: binding.threadId,
6501
- engineId: binding.contextEngine?.engineId,
6502
- epoch: binding.contextEngine?.projection?.epoch,
6503
- fingerprint: binding.contextEngine?.projection?.fingerprint
6504
- });
6505
- return binding;
6506
- }
6507
6583
  const sessionRecord = await readCodexSessionRecordForSessionFile(params.sessionFile);
6508
- const maxBytes = parseCodexAppServerByteLimit(params.config?.agents?.defaults?.compaction?.maxActiveTranscriptBytes);
6509
6584
  const rolloutFiles = await listCodexAppServerRolloutFilesForThread(params.agentDir, binding.threadId, params.codexHome);
6510
- if (maxBytes !== void 0) {
6511
- const oversizedFiles = rolloutFiles.filter((file) => file.bytes >= maxBytes);
6512
- if (oversizedFiles.length > 0) {
6513
- embeddedAgentLog.warn("codex app-server native transcript exceeded active byte limit; starting a fresh thread", {
6514
- threadId: binding.threadId,
6515
- maxBytes,
6516
- files: oversizedFiles.map((file) => ({
6517
- path: file.path,
6518
- bytes: file.bytes
6519
- }))
6520
- });
6521
- await clearCodexAppServerBinding(params.sessionFile);
6522
- return;
6585
+ const compaction = readCompactionConfig(params.config);
6586
+ const shouldDeferByteGuard = compaction?.truncateAfterCompaction === true && params.contextEngineActive === true && hasContextEngineThreadBootstrapProjection(binding);
6587
+ if (compaction?.truncateAfterCompaction === true && !shouldDeferByteGuard) {
6588
+ const maxBytes = parseCodexAppServerByteLimit(compaction.maxActiveTranscriptBytes);
6589
+ if (maxBytes !== void 0) {
6590
+ const oversizedFiles = rolloutFiles.filter((file) => file.bytes >= maxBytes);
6591
+ if (oversizedFiles.length > 0) {
6592
+ embeddedAgentLog.warn("codex app-server native transcript exceeded active byte limit; starting a fresh thread", {
6593
+ threadId: binding.threadId,
6594
+ maxBytes,
6595
+ files: oversizedFiles.map((file) => ({
6596
+ path: file.path,
6597
+ bytes: file.bytes
6598
+ }))
6599
+ });
6600
+ await clearCodexAppServerBinding(params.sessionFile);
6601
+ return;
6602
+ }
6523
6603
  }
6524
6604
  }
6525
6605
  const nativeTokenSnapshots = await Promise.all(rolloutFiles.map(async (file) => readCodexAppServerRolloutTokenSnapshot(file.path)));
6526
6606
  const nativeTokens = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.totalTokens));
6527
6607
  const nativeModelContextWindow = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.modelContextWindow));
6528
- const maxTokens = resolveCodexAppServerNativeThreadTokenFuse(nativeModelContextWindow);
6608
+ const sessionModelContextWindow = typeof sessionRecord?.contextTokens === "number" && Number.isFinite(sessionRecord.contextTokens) && sessionRecord.contextTokens > 0 ? Math.floor(sessionRecord.contextTokens) : void 0;
6609
+ const reserveTokens = resolveCodexAppServerNativeThreadReserveTokens(params.config);
6610
+ const maxTokens = resolveCodexAppServerNativeThreadTokenFuse({
6611
+ modelContextWindow: minFiniteNumber([nativeModelContextWindow, sessionModelContextWindow]),
6612
+ reserveTokens,
6613
+ projectedTurnTokens: params.projectedTurnTokens
6614
+ });
6529
6615
  const sessionTokens = sessionRecord?.totalTokensFresh !== false && typeof sessionRecord?.totalTokens === "number" && Number.isFinite(sessionRecord.totalTokens) ? sessionRecord.totalTokens : void 0;
6530
6616
  const tokenCount = maxFiniteNumber([sessionTokens, nativeTokens]);
6531
6617
  if (tokenCount !== void 0 && tokenCount >= maxTokens) {
@@ -6535,11 +6621,24 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
6535
6621
  sessionKey: sessionRecord?.sessionKey,
6536
6622
  sessionTokens,
6537
6623
  nativeTokens,
6538
- nativeModelContextWindow
6624
+ nativeModelContextWindow,
6625
+ sessionModelContextWindow,
6626
+ reserveTokens,
6627
+ projectedTurnTokens: params.projectedTurnTokens
6539
6628
  });
6540
6629
  await clearCodexAppServerBinding(params.sessionFile);
6541
6630
  return;
6542
6631
  }
6632
+ if (compaction?.truncateAfterCompaction !== true) return binding;
6633
+ if (shouldDeferByteGuard) {
6634
+ embeddedAgentLog.debug("codex app-server deferring native transcript byte guard for context-engine thread bootstrap", {
6635
+ threadId: binding.threadId,
6636
+ engineId: binding.contextEngine?.engineId,
6637
+ epoch: binding.contextEngine?.projection?.epoch,
6638
+ fingerprint: binding.contextEngine?.projection?.fingerprint
6639
+ });
6640
+ return binding;
6641
+ }
6543
6642
  return binding;
6544
6643
  }
6545
6644
  //#endregion
@@ -7058,7 +7157,12 @@ function readRequestId(record) {
7058
7157
  //#endregion
7059
7158
  //#region extensions/codex/src/app-server/run-attempt.ts
7060
7159
  const CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS = 6e4;
7160
+ const CODEX_APP_SERVER_PROJECTED_CHARS_PER_TOKEN = 4;
7061
7161
  const ensuredCodexWorkspaceDirs = /* @__PURE__ */ new Set();
7162
+ function estimateCodexAppServerProjectedTurnTokens(params) {
7163
+ const inputChars = params.prompt.length + (params.developerInstructions?.length ?? 0);
7164
+ return Math.max(1, Math.ceil(inputChars / CODEX_APP_SERVER_PROJECTED_CHARS_PER_TOKEN));
7165
+ }
7062
7166
  async function ensureCodexWorkspaceDirOnce(workspaceDir) {
7063
7167
  const normalized = path.resolve(workspaceDir);
7064
7168
  if (ensuredCodexWorkspaceDirs.has(normalized)) {
@@ -7365,12 +7469,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
7365
7469
  const baseDeveloperInstructions = joinPresentSections(buildDeveloperInstructions(params, { dynamicTools: toolBridge.availableSpecs }), workspaceBootstrapContext.developerInstructions);
7366
7470
  const openClawPromptContext = buildCodexOpenClawPromptContext({
7367
7471
  params,
7368
- skillsPrompt: params.skillsSnapshot?.prompt,
7369
- workspacePromptContext: workspaceBootstrapContext.promptContext,
7370
- workspaceMemoryReference: renderCodexWorkspaceMemoryReference({
7371
- files: workspaceBootstrapContext.memoryReferenceFiles ?? [],
7372
- toolNames: workspaceBootstrapContext.memoryToolNames
7373
- })
7472
+ workspacePromptContext: workspaceBootstrapContext.promptContext
7473
+ });
7474
+ const skillsCollaborationInstructions = renderCodexSkillsCollaborationInstructions({
7475
+ attempt: params,
7476
+ skillsPrompt: params.skillsSnapshot?.prompt
7374
7477
  });
7375
7478
  let promptText = params.prompt;
7376
7479
  let developerInstructions = baseDeveloperInstructions;
@@ -7437,41 +7540,69 @@ async function runCodexAppServerAttempt(params, options = {}) {
7437
7540
  } catch (assembleErr) {
7438
7541
  embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
7439
7542
  }
7440
- else if (shouldProjectMirroredHistoryForCodexStart({
7441
- startupBinding,
7442
- dynamicToolsFingerprint: codexDynamicToolsFingerprint(toolBridge.specs),
7443
- historyMessages,
7444
- forceProject: !nativeToolSurfaceEnabled
7445
- })) {
7446
- const projection = projectContextEngineAssemblyForCodex({
7447
- assembledMessages: historyMessages,
7448
- originalHistoryMessages: historyMessages,
7449
- prompt: params.prompt
7450
- });
7451
- promptText = projection.promptText;
7452
- prePromptMessageCount = projection.prePromptMessageCount;
7453
- }
7543
+ const codexModelInputHistoryMessages = [];
7454
7544
  const buildPromptFromCurrentInputs = () => resolveAgentHarnessBeforePromptBuildResult({
7455
7545
  prompt: prependCurrentInboundContext(promptText, params.currentInboundContext),
7456
7546
  developerInstructions,
7457
- messages: historyMessages,
7547
+ messages: codexModelInputHistoryMessages,
7458
7548
  ctx: hookContext
7459
7549
  });
7460
7550
  let promptBuild = await buildPromptFromCurrentInputs();
7461
- const decorateCodexTurnPromptText = (prompt) => prependCodexOpenClawPromptContext(prompt, openClawPromptContext);
7551
+ const decorateCodexTurnPromptText = (prompt) => prependCodexOpenClawPromptContext(prompt, openClawPromptContext, { preservePromptWithoutContext: params.bootstrapContextMode === "lightweight" && params.bootstrapContextRunKind === "cron" });
7462
7552
  let codexTurnPromptText = decorateCodexTurnPromptText(promptBuild.prompt);
7463
7553
  const buildCodexTurnCollaborationDeveloperInstructions = () => buildTurnCollaborationMode(params, {
7464
7554
  turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
7555
+ skillsCollaborationInstructions,
7556
+ memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
7465
7557
  heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
7466
7558
  }).settings.developer_instructions ?? void 0;
7467
7559
  const buildRenderedCodexDeveloperInstructions = () => joinPresentSections(promptBuild.developerInstructions, buildCodexTurnCollaborationDeveloperInstructions());
7560
+ const rebuildCodexTurnPromptFromCurrentProjection = async () => {
7561
+ promptBuild = await buildPromptFromCurrentInputs();
7562
+ codexTurnPromptText = decorateCodexTurnPromptText(promptBuild.prompt);
7563
+ };
7564
+ const rotateStartupBindingForProjectedTurn = async () => {
7565
+ if (!startupBinding?.threadId) return;
7566
+ const previousThreadId = startupBinding.threadId;
7567
+ const projectedTurnTokens = estimateCodexAppServerProjectedTurnTokens({
7568
+ prompt: codexTurnPromptText,
7569
+ developerInstructions: buildRenderedCodexDeveloperInstructions()
7570
+ });
7571
+ startupBinding = await rotateOversizedCodexAppServerStartupBinding({
7572
+ binding: startupBinding,
7573
+ sessionFile: params.sessionFile,
7574
+ agentDir,
7575
+ codexHome: appServer.start.env?.CODEX_HOME,
7576
+ config: params.config,
7577
+ contextEngineActive: Boolean(activeContextEngine),
7578
+ projectedTurnTokens
7579
+ });
7580
+ if (startupBinding?.threadId) return;
7581
+ if (activeContextEngine) {
7582
+ contextEngineProjection = void 0;
7583
+ try {
7584
+ await applyActiveContextEngineProjection(void 0);
7585
+ } catch (assembleErr) {
7586
+ embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
7587
+ }
7588
+ }
7589
+ await rebuildCodexTurnPromptFromCurrentProjection();
7590
+ embeddedAgentLog.info("codex app-server rebuilt turn prompt after native thread rotation", {
7591
+ sessionId: params.sessionId,
7592
+ sessionKey: contextSessionKey,
7593
+ previousThreadId,
7594
+ promptChars: codexTurnPromptText.length,
7595
+ developerInstructionChars: buildRenderedCodexDeveloperInstructions()?.length ?? 0
7596
+ });
7597
+ };
7598
+ await rotateStartupBindingForProjectedTurn();
7468
7599
  const systemPromptReport = buildCodexSystemPromptReport({
7469
7600
  attempt: params,
7470
7601
  sessionKey: contextSessionKey,
7471
7602
  workspaceDir: effectiveWorkspace,
7472
7603
  developerInstructions: buildRenderedCodexDeveloperInstructions(),
7473
7604
  workspaceBootstrapContext,
7474
- skillsPrompt: openClawPromptContext ? params.skillsSnapshot?.prompt ?? "" : "",
7605
+ skillsPrompt: skillsCollaborationInstructions ? params.skillsSnapshot?.prompt ?? "" : "",
7475
7606
  tools: toolBridge.availableSpecs
7476
7607
  });
7477
7608
  const trajectoryRecorder = createCodexTrajectoryRecorder({
@@ -7594,7 +7725,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
7594
7725
  recordCodexTrajectoryContext(trajectoryRecorder, {
7595
7726
  attempt: params,
7596
7727
  cwd: effectiveCwd,
7597
- developerInstructions: promptBuild.developerInstructions,
7728
+ developerInstructions: buildRenderedCodexDeveloperInstructions(),
7598
7729
  prompt: codexTurnPromptText,
7599
7730
  tools: toolBridge.availableSpecs
7600
7731
  });
@@ -7607,6 +7738,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
7607
7738
  let terminalTurnNotificationQueued = false;
7608
7739
  let timedOut = false;
7609
7740
  let turnCompletionIdleTimedOut = false;
7741
+ let turnWatchTimeoutKind;
7610
7742
  let turnCompletionIdleTimeoutMessage;
7611
7743
  let clientClosedPromptError;
7612
7744
  let clientClosedAbort = false;
@@ -7659,9 +7791,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
7659
7791
  turnTerminalIdleTimeoutMs,
7660
7792
  interruptTimeoutMs: CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS,
7661
7793
  onInterruptTurn: (input) => interruptCodexTurnBestEffort(client, input),
7662
- onTimeout: () => {
7794
+ onTimeout: (timeout) => {
7663
7795
  timedOut = true;
7664
7796
  turnCompletionIdleTimedOut = true;
7797
+ turnWatchTimeoutKind = timeout.kind;
7665
7798
  turnCompletionIdleTimeoutMessage = "codex app-server turn idle timed out waiting for turn/completed";
7666
7799
  },
7667
7800
  onMarkTimedOut: () => projector?.markTimedOut(),
@@ -7805,7 +7938,6 @@ async function runCodexAppServerAttempt(params, options = {}) {
7805
7938
  threadId: thread.threadId,
7806
7939
  turnId,
7807
7940
  currentPromptTexts: [codexTurnPromptText],
7808
- sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
7809
7941
  turnWatches,
7810
7942
  activeTurnItemIds,
7811
7943
  activeAppServerTurnRequests,
@@ -7852,7 +7984,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
7852
7984
  return Promise.resolve();
7853
7985
  }
7854
7986
  if (isTerminalTurnNotificationForTurn(notification, turnId)) terminalTurnNotificationQueued = true;
7855
- if (correlation.matchesActiveTurn !== false) turnWatches.noteNotificationReceived(notification.method);
7987
+ const isNativeResponseStreamDelta = isNativeResponseStreamDeltaNotification(notification);
7988
+ const nativeResponseStreamDeltaMatchesActiveTurn = isNativeResponseStreamDelta && (correlation.matchesActiveTurn === true || isUnscopedCodexNotification(correlation) && canAttributeUnscopedNativeResponseDeltaToThisTurn(client));
7989
+ if (correlation.matchesActiveTurn === true || !isNativeResponseStreamDelta && correlation.matchesActiveTurn !== false || nativeResponseStreamDeltaMatchesActiveTurn) turnWatches.noteNotificationReceived(notification.method, isNativeResponseStreamDelta ? {
7990
+ attemptProgress: true,
7991
+ ...turnCrossedToolHandoff ? { attemptTimeoutMs: postToolRawAssistantCompletionIdleTimeoutMs } : {},
7992
+ details: { lastNotificationMethod: notification.method }
7993
+ } : void 0);
7856
7994
  notificationQueue = notificationQueue.then(() => handleNotification(notification), () => handleNotification(notification));
7857
7995
  return notificationQueue;
7858
7996
  };
@@ -8079,10 +8217,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
8079
8217
  } finally {
8080
8218
  if (requestCountsAsTurnActivity) {
8081
8219
  activeAppServerTurnRequests = Math.max(0, activeAppServerTurnRequests - 1);
8220
+ const postToolContinuationTimeoutMs = request.method === "item/tool/call" && turnCrossedToolHandoff ? postToolRawAssistantCompletionIdleTimeoutMs : void 0;
8082
8221
  turnWatches.touchActivity(`request:${request.method}:response`, {
8083
8222
  arm: armCompletionWatchOnResponse,
8084
- attemptProgress: true
8223
+ attemptProgress: true,
8224
+ ...postToolContinuationTimeoutMs !== void 0 ? { attemptTimeoutMs: postToolContinuationTimeoutMs } : {}
8085
8225
  });
8226
+ if (armCompletionWatchOnResponse && postToolContinuationTimeoutMs !== void 0) turnWatches.armCompletionIdleWatch({ timeoutMs: postToolContinuationTimeoutMs });
8086
8227
  scheduleTerminalDynamicToolReleaseCheck();
8087
8228
  } else turnWatches.scheduleProgressWatches();
8088
8229
  }
@@ -8095,11 +8236,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
8095
8236
  model: params.modelId,
8096
8237
  systemPrompt: buildRenderedCodexDeveloperInstructions(),
8097
8238
  prompt: codexTurnPromptText,
8098
- historyMessages,
8239
+ historyMessages: codexModelInputHistoryMessages,
8099
8240
  imagesCount: params.images?.length ?? 0,
8100
8241
  tools
8101
8242
  });
8102
- const buildTurnStartFailureMessages = () => [...historyMessages, buildCodexUserPromptMessage({
8243
+ const buildCodexModelInputMessages = () => [...codexModelInputHistoryMessages, buildCodexUserPromptMessage({
8103
8244
  ...params,
8104
8245
  prompt: codexTurnPromptText
8105
8246
  })];
@@ -8118,7 +8259,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
8118
8259
  },
8119
8260
  capture: codexModelContentCapture,
8120
8261
  tools,
8121
- buildInputMessages: buildTurnStartFailureMessages,
8262
+ buildInputMessages: buildCodexModelInputMessages,
8122
8263
  buildSystemPrompt: buildRenderedCodexDeveloperInstructions,
8123
8264
  onErrorDiagnostic: (error) => {
8124
8265
  embeddedAgentLog.debug("codex app-server model call diagnostic ended with error", { error: formatErrorMessage(error) });
@@ -8134,6 +8275,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
8134
8275
  sandboxPolicy: codexSandboxPolicy,
8135
8276
  environmentSelection: codexEnvironmentSelection,
8136
8277
  turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
8278
+ skillsCollaborationInstructions,
8279
+ memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
8137
8280
  heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
8138
8281
  });
8139
8282
  codexModelCallDiagnostics.setRequestPayloadBytes(utf8JsonByteLength(turnStartParams));
@@ -8159,7 +8302,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
8159
8302
  turn = await startCodexTurn();
8160
8303
  } catch (error) {
8161
8304
  let turnStartError = error;
8162
- if (shouldRetryContextEngineTurnOnFreshCodexThread({
8305
+ if (shouldUseFreshCodexThreadAfterContextEngineOverflow({
8163
8306
  error: turnStartError,
8164
8307
  contextEngineActive: Boolean(activeContextEngine),
8165
8308
  thread
@@ -8170,20 +8313,26 @@ async function runCodexAppServerAttempt(params, options = {}) {
8170
8313
  });
8171
8314
  try {
8172
8315
  const preRetrySessionFile = activeSessionFile;
8173
- await clearCodexAppServerBinding(preRetrySessionFile);
8174
- if (activeSessionFile !== preRetrySessionFile) await clearCodexAppServerBinding(activeSessionFile);
8175
- thread = await restartContextEngineCodexThread();
8176
- emitCodexAppServerEvent(params, {
8177
- stream: "codex_app_server.lifecycle",
8178
- data: {
8179
- phase: "thread_ready_retry",
8180
- threadId: thread.threadId
8181
- }
8316
+ const clearedPreRetryBinding = await clearCodexAppServerBindingForThread(preRetrySessionFile, thread.threadId);
8317
+ const clearedActiveBinding = activeSessionFile !== preRetrySessionFile ? await clearCodexAppServerBindingForThread(activeSessionFile, thread.threadId) : false;
8318
+ if (!clearedPreRetryBinding && !clearedActiveBinding) embeddedAgentLog.warn("codex app-server preserved newer context-engine binding after resume overflow; skipping fresh retry", {
8319
+ threadId: thread.threadId,
8320
+ error: formatErrorMessage(turnStartError)
8182
8321
  });
8183
- try {
8184
- turn = await startCodexTurn();
8185
- } catch (retryError) {
8186
- turnStartError = retryError;
8322
+ else {
8323
+ thread = await restartContextEngineCodexThread();
8324
+ emitCodexAppServerEvent(params, {
8325
+ stream: "codex_app_server.lifecycle",
8326
+ data: {
8327
+ phase: "thread_ready_retry",
8328
+ threadId: thread.threadId
8329
+ }
8330
+ });
8331
+ try {
8332
+ turn = await startCodexTurn();
8333
+ } catch (retryError) {
8334
+ turnStartError = retryError;
8335
+ }
8187
8336
  }
8188
8337
  } catch (retrySetupError) {
8189
8338
  turnStartError = retrySetupError;
@@ -8242,9 +8391,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
8242
8391
  formatError: formatErrorMessage
8243
8392
  });
8244
8393
  codexModelCallDiagnostics.emitError(turnStartErrorMessage, turnStartFailureKind ? { failureKind: turnStartFailureKind } : {});
8394
+ const turnStartFailureMessages = [...historyMessages, buildCodexUserPromptMessage({
8395
+ ...params,
8396
+ prompt: codexTurnPromptText
8397
+ })];
8245
8398
  await runCodexAgentEndHook(params, {
8246
8399
  event: {
8247
- messages: buildTurnStartFailureMessages(),
8400
+ messages: turnStartFailureMessages,
8248
8401
  success: false,
8249
8402
  error: turnStartErrorMessage,
8250
8403
  durationMs: Date.now() - attemptStartedAt
@@ -8281,7 +8434,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
8281
8434
  return { ...buildCodexTurnStartFailureResult({
8282
8435
  params,
8283
8436
  message: usageLimitError.message,
8284
- messagesSnapshot: buildTurnStartFailureMessages(),
8437
+ messagesSnapshot: turnStartFailureMessages,
8285
8438
  systemPromptReport
8286
8439
  }) };
8287
8440
  }
@@ -8334,6 +8487,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
8334
8487
  const activeProjector = projector;
8335
8488
  turnWatches.armTerminalIdleWatch();
8336
8489
  turnWatches.touchActivity("turn:start", { arm: true });
8490
+ turnWatches.armAttemptIdleWatch();
8491
+ turnWatches.touchActivity("turn:start", { attemptProgress: true });
8337
8492
  for (const notification of pendingNotifications.splice(0)) await enqueueNotification(notification);
8338
8493
  if (!completed && isTerminalTurnStatus(turn.turn.status)) await enqueueNotification({
8339
8494
  method: "turn/completed",
@@ -8371,16 +8526,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
8371
8526
  threadId: thread.threadId,
8372
8527
  turnId: activeTurnId
8373
8528
  });
8374
- turnWatches.armAttemptIdleWatch();
8375
- turnWatches.armTerminalIdleWatch();
8376
- turnWatches.touchActivity("turn:start", { attemptProgress: true });
8377
8529
  const abortListener = () => {
8378
8530
  if (timedOut) {
8379
- retireCodexAppServerClientAfterTimedOutTurn(client, {
8380
- threadId: thread.threadId,
8381
- turnId: activeTurnId,
8382
- reason: String(runAbortController.signal.reason ?? "timeout")
8383
- }).finally(() => {
8531
+ (async () => {
8532
+ await clearCodexAppServerBindingForThread(activeSessionFile, thread.threadId);
8533
+ await retireCodexAppServerClientAfterTimedOutTurn(client, {
8534
+ threadId: thread.threadId,
8535
+ turnId: activeTurnId,
8536
+ reason: String(runAbortController.signal.reason ?? "timeout")
8537
+ });
8538
+ })().finally(() => {
8384
8539
  resolveCompletion?.();
8385
8540
  });
8386
8541
  return;
@@ -8395,6 +8550,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
8395
8550
  if (runAbortController.signal.aborted) abortListener();
8396
8551
  try {
8397
8552
  await completion;
8553
+ await notificationQueue;
8398
8554
  const result = activeProjector.buildResult(toolBridge.telemetry, { yieldDetected });
8399
8555
  const finalAborted = result.aborted || runAbortController.signal.aborted && !clientClosedAbort;
8400
8556
  let finalPromptError = clientClosedPromptError ?? (turnCompletionIdleTimedOut ? turnCompletionIdleTimeoutMessage : timedOut ? "codex app-server attempt timed out" : result.promptError);
@@ -8405,6 +8561,20 @@ async function runCodexAppServerAttempt(params, options = {}) {
8405
8561
  turnId: activeTurnId,
8406
8562
  error: finalPromptErrorMessage
8407
8563
  });
8564
+ if (shouldUseFreshCodexThreadAfterContextEngineOverflow({
8565
+ error: finalPromptError,
8566
+ contextEngineActive: Boolean(activeContextEngine),
8567
+ thread
8568
+ })) {
8569
+ embeddedAgentLog.warn("codex app-server context-engine turn overflowed after resume; clearing thread binding for recovery", {
8570
+ threadId: thread.threadId,
8571
+ turnId: activeTurnId,
8572
+ error: finalPromptErrorMessage
8573
+ });
8574
+ const preClearSessionFile = activeSessionFile;
8575
+ await clearCodexAppServerBindingForThread(preClearSessionFile, thread.threadId);
8576
+ if (activeSessionFile !== preClearSessionFile) await clearCodexAppServerBindingForThread(activeSessionFile, thread.threadId);
8577
+ }
8408
8578
  const refreshedUsageLimitPromptError = await refreshCodexUsageLimitPromptError({
8409
8579
  client,
8410
8580
  message: finalPromptErrorMessage,
@@ -8536,6 +8706,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
8536
8706
  promptErrorSource: finalPromptErrorSource,
8537
8707
  ...codexAppServerFailureKind ? { codexAppServerFailure: {
8538
8708
  kind: codexAppServerFailureKind,
8709
+ ...codexAppServerFailureKind === "turn_completion_idle_timeout" && turnWatchTimeoutKind ? { turnWatchTimeoutKind } : {},
8539
8710
  transport: appServer.start.transport,
8540
8711
  threadId: thread.threadId,
8541
8712
  turnId: activeTurnId,
@@ -8608,7 +8779,14 @@ async function clearCodexBindingAfterInvalidImagePayload(sessionFile, fields) {
8608
8779
  function isNonEmptyString(value) {
8609
8780
  return typeof value === "string" && value.length > 0;
8610
8781
  }
8611
- function shouldRetryContextEngineTurnOnFreshCodexThread(params) {
8782
+ function canAttributeUnscopedNativeResponseDeltaToThisTurn(client) {
8783
+ const activeLeases = client.getActiveSharedLeaseCountForUnscopedNotifications?.();
8784
+ return activeLeases === void 0 || activeLeases <= 1;
8785
+ }
8786
+ function isUnscopedCodexNotification(correlation) {
8787
+ return !correlation.threadId && !correlation.turnId && !correlation.nestedTurnThreadId && !correlation.nestedTurnId;
8788
+ }
8789
+ function shouldUseFreshCodexThreadAfterContextEngineOverflow(params) {
8612
8790
  if (!params.contextEngineActive || params.thread.lifecycle.action !== "resumed") return false;
8613
8791
  return isCodexContextWindowError(params.error);
8614
8792
  }