@openclaw/codex 2026.5.28 → 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-CuhGEh0u.js → run-attempt-lD4FLxNV.js} +424 -244
  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 { parseStrictNonNegativeInteger, resolveTimerTimeoutMs } 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,67 +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
- return resolveTimerTimeoutMs(value, resolveTimerTimeoutMs(fallbackMs, 1));
973
- }
974
- async function withCodexStartupTimeout(params) {
975
- if (params.signal.aborted) throw new Error("codex app-server startup aborted");
976
- let timeout;
977
- let abortCleanup;
978
- let timeoutError;
979
- let timeoutCleanup;
980
- try {
981
- return await Promise.race([params.operation(), new Promise((_, reject) => {
982
- const rejectOnce = (error) => {
983
- if (timeout) {
984
- clearTimeout(timeout);
985
- timeout = void 0;
986
- }
987
- reject(error);
988
- };
989
- timeout = setTimeout(() => {
990
- timeoutError = /* @__PURE__ */ new Error("codex app-server startup timed out");
991
- timeoutCleanup = Promise.resolve(params.onTimeout?.()).then(() => void 0, () => void 0);
992
- timeoutCleanup.finally(() => {
993
- rejectOnce(timeoutError);
994
- });
995
- }, params.timeoutMs);
996
- const abortListener = () => rejectOnce(/* @__PURE__ */ new Error("codex app-server startup aborted"));
997
- params.signal.addEventListener("abort", abortListener, { once: true });
998
- abortCleanup = () => params.signal.removeEventListener("abort", abortListener);
999
- })]);
1000
- } catch (error) {
1001
- if (timeoutError) {
1002
- await timeoutCleanup;
1003
- throw timeoutError;
1004
- }
1005
- throw error;
1006
- } finally {
1007
- if (timeout) clearTimeout(timeout);
1008
- abortCleanup?.();
1009
- }
1010
- }
1011
- function resolveCodexStartupTimeoutMs(params) {
1012
- const timeoutFloorMs = resolvePositiveIntegerTimeoutMs(params.timeoutFloorMs, 100);
1013
- const timeoutMs = resolvePositiveIntegerTimeoutMs(params.timeoutMs, timeoutFloorMs);
1014
- return Math.max(timeoutFloorMs, timeoutMs);
1015
- }
1016
- function resolveCodexTurnCompletionIdleTimeoutMs(value) {
1017
- return resolvePositiveIntegerTimeoutMs(value, CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS);
1018
- }
1019
- function resolveCodexTurnAssistantCompletionIdleTimeoutMs(value) {
1020
- return resolvePositiveIntegerTimeoutMs(value, CODEX_TURN_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS);
1021
- }
1022
- function resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs(value, fallbackMs) {
1023
- return resolvePositiveIntegerTimeoutMs(value, fallbackMs);
1024
- }
1025
- function resolveCodexTurnTerminalIdleTimeoutMs(value) {
1026
- return resolvePositiveIntegerTimeoutMs(value, CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS);
1027
- }
1028
961
  //#endregion
1029
962
  //#region extensions/codex/src/app-server/attempt-notification-state.ts
1030
963
  function reportCodexExecutionNotification(params) {
@@ -1055,8 +988,9 @@ function applyCodexTurnNotificationState(params) {
1055
988
  const { notification, turnWatches } = params;
1056
989
  const isCurrentTurnNotification = isTurnNotification(notification.params, params.threadId, params.turnId);
1057
990
  const isTurnCompletion = notification.method === "turn/completed" && isCurrentTurnNotification;
991
+ const isNativeResponseStreamDelta = isNativeResponseStreamDeltaNotification(notification);
1058
992
  let turnCrossedToolHandoff = params.turnCrossedToolHandoff;
1059
- if (isCurrentTurnNotification) {
993
+ if (isCurrentTurnNotification && !isNativeResponseStreamDelta) {
1060
994
  turnWatches.touchActivity(`notification:${notification.method}`, {
1061
995
  details: describeNotificationActivity(notification),
1062
996
  attemptProgress: true
@@ -1070,25 +1004,37 @@ function applyCodexTurnNotificationState(params) {
1070
1004
  const rawToolOutputCompletion = isRawToolOutputCompletionNotification(notification);
1071
1005
  if (isCurrentTurnNotification && (rawToolOutputCompletion || isNativeToolProgressNotification(notification))) turnCrossedToolHandoff = true;
1072
1006
  const assistantCompletionCanRelease = isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff);
1073
- const postToolRawAssistantCompletionNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && isRawAssistantCompletionNotification(notification) && params.activeTurnItemIds.size === 0;
1074
- const rawResponseItemCompletedWithNoActiveItems = isCurrentTurnNotification && notification.method === "rawResponseItem/completed" && params.activeTurnItemIds.size === 0 && params.activeAppServerTurnRequests === 0 && !assistantCompletionCanRelease && !postToolRawAssistantCompletionNeedsTerminalGuard;
1075
- const shouldArmPostReasoningSourceReplyWatch = isCurrentTurnNotification && isReasoningItemCompletionNotification(notification) && params.activeTurnItemIds.size === 0 && params.sourceReplyDeliveryMode === "message_tool_only";
1076
- const shouldArmPostRawReasoningSourceReplyWatch = rawResponseItemCompletedWithNoActiveItems && isRawReasoningCompletionNotification(notification) && params.sourceReplyDeliveryMode === "message_tool_only";
1077
- 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
+ };
1078
1022
  if (isCurrentTurnNotification && notification.method === "error") {
1079
1023
  if (isRetryableErrorNotification(notification.params)) turnWatches.disarmCompletionIdleWatch();
1080
1024
  else turnWatches.armCompletionIdleWatch({ pinnedByTerminalError: true });
1081
1025
  turnWatches.disarmAssistantCompletionIdleWatch();
1082
1026
  } else if (isTurnCompletion) turnWatches.disarmAssistantCompletionIdleWatch();
1083
1027
  else if (isCurrentTurnNotification && assistantCompletionCanRelease) turnWatches.armAssistantCompletionIdleWatch(describeNotificationActivity(notification));
1084
- else if (postToolRawAssistantCompletionNeedsTerminalGuard) turnWatches.armCompletionIdleWatch({ timeoutMs: params.postToolRawAssistantCompletionIdleTimeoutMs });
1085
- 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();
1086
1031
  else if (unblockedAssistantCompletionRelease) turnWatches.armAssistantCompletionIdleWatch(describeNotificationActivity(notification));
1087
- else if (shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) turnWatches.armCompletionIdleWatch();
1032
+ else if (shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) if (shouldUsePostToolContinuationWatch) armPostToolContinuationWatch();
1033
+ else turnWatches.armCompletionIdleWatch();
1088
1034
  else if (rawResponseItemCompletedWithNoActiveItems) turnWatches.armCompletionIdleWatch();
1089
- else if (isCurrentTurnNotification && rawToolOutputCompletion) turnWatches.armCompletionIdleWatch();
1035
+ else if (isCurrentTurnNotification && rawToolOutputCompletion) armPostToolContinuationWatch();
1090
1036
  else if (isCurrentTurnNotification && shouldDisarmAssistantCompletionIdleWatch(notification)) turnWatches.disarmAssistantCompletionIdleWatch();
1091
- 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();
1092
1038
  if (trackedDynamicToolCompletion) {
1093
1039
  const itemId = readNotificationItemId(notification);
1094
1040
  if (itemId) {
@@ -1120,7 +1066,8 @@ function hasCodexAppServerPotentialSideEffectEvidence(result) {
1120
1066
  }
1121
1067
  function buildCodexAppServerPromptTimeoutOutcome(params) {
1122
1068
  const completionIdleTimeoutHadPotentialSideEffects = hasCodexAppServerPotentialSideEffectEvidence(params.result);
1123
- 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;
1124
1071
  return {
1125
1072
  message: completionIdleTimeoutHadPotentialSideEffects ? CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_SIDE_EFFECT_USER_MESSAGE : CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_USER_MESSAGE,
1126
1073
  ...completionIdleTimeoutHadPotentialSideEffects ? {
@@ -3013,6 +2960,7 @@ function createCodexAttemptTurnWatchController(params) {
3013
2960
  let completionLastActivityAt = Date.now();
3014
2961
  let completionLastActivityReason = "startup";
3015
2962
  let completionLastActivityDetails;
2963
+ let attemptIdleTimeoutOverrideMs;
3016
2964
  let attemptLastProgressAt = Date.now();
3017
2965
  let attemptLastProgressReason = "startup";
3018
2966
  let attemptLastProgressDetails;
@@ -3067,7 +3015,8 @@ function createCodexAttemptTurnWatchController(params) {
3067
3015
  clearAttemptIdleTimer();
3068
3016
  if (params.isCompleted() || params.signal.aborted || !attemptIdleWatchArmed) return;
3069
3017
  const elapsedMs = Math.max(0, Date.now() - attemptLastProgressAt);
3070
- const delayMs = Math.max(1, params.turnAttemptIdleTimeoutMs - elapsedMs);
3018
+ const timeoutMs = attemptIdleTimeoutOverrideMs ?? params.turnAttemptIdleTimeoutMs;
3019
+ const delayMs = Math.max(1, timeoutMs - elapsedMs);
3071
3020
  attemptIdleTimer = setTimeout(fireAttemptIdleTimeout, delayMs);
3072
3021
  attemptIdleTimer.unref?.();
3073
3022
  }
@@ -3084,6 +3033,14 @@ function createCodexAttemptTurnWatchController(params) {
3084
3033
  scheduleCompletionIdleWatch();
3085
3034
  scheduleTerminalIdleWatch();
3086
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
+ }
3087
3044
  function fireAssistantCompletionIdleRelease() {
3088
3045
  if (params.isCompleted() || params.signal.aborted || !assistantCompletionIdleWatchArmed) return;
3089
3046
  if (params.getActiveAppServerTurnRequests() > 0 || params.getActiveTurnItemCount() > 0) {
@@ -3124,14 +3081,15 @@ function createCodexAttemptTurnWatchController(params) {
3124
3081
  function fireAttemptIdleTimeout() {
3125
3082
  if (params.isCompleted() || params.signal.aborted || !attemptIdleWatchArmed) return;
3126
3083
  const idleMs = Math.max(0, Date.now() - attemptLastProgressAt);
3127
- if (idleMs < params.turnAttemptIdleTimeoutMs) {
3084
+ const timeoutMs = attemptIdleTimeoutOverrideMs ?? params.turnAttemptIdleTimeoutMs;
3085
+ if (idleMs < timeoutMs) {
3128
3086
  scheduleAttemptIdleWatch();
3129
3087
  return;
3130
3088
  }
3131
3089
  const timeout = {
3132
3090
  kind: "progress",
3133
3091
  idleMs,
3134
- timeoutMs: params.turnAttemptIdleTimeoutMs,
3092
+ timeoutMs,
3135
3093
  lastActivityReason: attemptLastProgressReason,
3136
3094
  details: attemptLastProgressDetails
3137
3095
  };
@@ -3264,12 +3222,7 @@ function createCodexAttemptTurnWatchController(params) {
3264
3222
  completionLastActivityReason = reason;
3265
3223
  completionLastActivityDetails = options?.details;
3266
3224
  completionIdleTimeoutOverrideMs = void 0;
3267
- if (options?.attemptProgress) {
3268
- attemptLastProgressAt = completionLastActivityAt;
3269
- attemptLastProgressReason = reason;
3270
- attemptLastProgressDetails = options.details;
3271
- params.onAttemptProgress(reason, options.details);
3272
- }
3225
+ if (options?.attemptProgress) recordAttemptProgress(reason, options);
3273
3226
  params.onProgressDiagnostic(reason);
3274
3227
  if (options?.arm) {
3275
3228
  completionIdleWatchArmed = true;
@@ -3277,9 +3230,15 @@ function createCodexAttemptTurnWatchController(params) {
3277
3230
  }
3278
3231
  scheduleProgressWatches();
3279
3232
  },
3280
- noteNotificationReceived: (method) => {
3233
+ noteNotificationReceived: (method, options) => {
3281
3234
  completionLastActivityAt = Date.now();
3282
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();
3283
3242
  },
3284
3243
  scheduleProgressWatches,
3285
3244
  clearCompletionIdleTimer,
@@ -3486,15 +3445,14 @@ function clampDynamicToolTimeoutMs(timeoutMs) {
3486
3445
  //#region extensions/codex/src/app-server/local-runtime-attribution.ts
3487
3446
  const OPENAI_PROVIDER_ID = "openai";
3488
3447
  const OPENAI_RESPONSES_API = "openai-responses";
3489
- const OPENAI_CODEX_PROVIDER_ID = "openai-codex";
3490
- const OPENAI_CODEX_RESPONSES_API = "openai-codex-responses";
3448
+ const OPENAI_CODEX_RESPONSES_API = "openai-chatgpt-responses";
3491
3449
  function normalizeRuntimeId(value) {
3492
3450
  return value?.trim().toLowerCase() ?? "";
3493
3451
  }
3494
3452
  function resolveCodexLocalRuntimeAttribution(params) {
3495
3453
  const authProfileProvider = normalizeRuntimeId(params.runtimePlan?.auth?.authProfileProviderForAuth);
3496
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 {
3497
- provider: OPENAI_CODEX_PROVIDER_ID,
3455
+ provider: OPENAI_PROVIDER_ID,
3498
3456
  api: OPENAI_CODEX_RESPONSES_API
3499
3457
  };
3500
3458
  return {
@@ -3754,6 +3712,7 @@ async function mirrorCodexAppServerTranscript(params) {
3754
3712
  for (const update of appendedUpdates) emitSessionTranscriptUpdate({
3755
3713
  sessionFile: params.sessionFile,
3756
3714
  ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
3715
+ ...params.agentId ? { agentId: params.agentId } : {},
3757
3716
  message: update.message,
3758
3717
  messageId: update.messageId,
3759
3718
  messageSeq: update.messageSeq
@@ -3826,6 +3785,9 @@ const CODEX_PROMPT_TOTAL_INPUT_KEYS = [
3826
3785
  ];
3827
3786
  const MAX_TOOL_OUTPUT_DELTA_MESSAGES_PER_ITEM = 20;
3828
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;
3829
3791
  const TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES = new Set([
3830
3792
  "message",
3831
3793
  "messages",
@@ -3871,6 +3833,8 @@ var CodexAppServerEventProjector = class {
3871
3833
  this.toolTranscriptResultIds = /* @__PURE__ */ new Set();
3872
3834
  this.transcriptToolProgressCallIds = /* @__PURE__ */ new Set();
3873
3835
  this.nativeGeneratedMediaUrls = /* @__PURE__ */ new Set();
3836
+ this.nativeGeneratedMediaItemIds = /* @__PURE__ */ new Set();
3837
+ this.nativeGeneratedMediaUrlsByItemId = /* @__PURE__ */ new Map();
3874
3838
  this.diagnosticToolStartedAtByItem = /* @__PURE__ */ new Map();
3875
3839
  this.afterToolCallObservedItemIds = /* @__PURE__ */ new Set();
3876
3840
  this.assistantStarted = false;
@@ -3936,7 +3900,7 @@ var CodexAppServerEventProjector = class {
3936
3900
  await this.handleTurnCompleted(params);
3937
3901
  break;
3938
3902
  case "rawResponseItem/completed":
3939
- this.handleRawResponseItemCompleted(params);
3903
+ await this.handleRawResponseItemCompleted(params);
3940
3904
  break;
3941
3905
  case "error":
3942
3906
  if (readBooleanAlias(params, ["willRetry", "will_retry"]) === true) break;
@@ -3967,7 +3931,7 @@ var CodexAppServerEventProjector = class {
3967
3931
  turnCompleted: Boolean(this.completedTurn)
3968
3932
  });
3969
3933
  const toolMetas = [...this.toolMetas.values()];
3970
- 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;
3971
3935
  return {
3972
3936
  aborted: this.aborted,
3973
3937
  externalAbort: false,
@@ -4388,9 +4352,11 @@ var CodexAppServerEventProjector = class {
4388
4352
  text: formatToolOutput(toolName, void 0, reachedLimit ? `${chunk}\n...(truncated)...` : chunk)
4389
4353
  });
4390
4354
  }
4391
- handleRawResponseItemCompleted(params) {
4355
+ async handleRawResponseItemCompleted(params) {
4392
4356
  const item = isJsonObject(params.item) ? params.item : void 0;
4393
- 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;
4394
4360
  const text = extractRawAssistantText(item);
4395
4361
  if (!text) return;
4396
4362
  const itemId = readString$5(item, "id") ?? `raw-assistant-${this.assistantItemOrder.length + 1}`;
@@ -4406,7 +4372,56 @@ var CodexAppServerEventProjector = class {
4406
4372
  recordNativeGeneratedMedia(item) {
4407
4373
  if (item?.type !== "imageGeneration") return;
4408
4374
  const savedPath = readItemString(item, "savedPath")?.trim();
4409
- 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);
4410
4425
  }
4411
4426
  buildToolMediaUrls(toolTelemetry) {
4412
4427
  const mediaUrls = new Set(toolTelemetry.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []);
@@ -4833,7 +4848,7 @@ var CodexAppServerEventProjector = class {
4833
4848
  type: "text",
4834
4849
  text
4835
4850
  }],
4836
- api: attribution.api ?? "openai-codex-responses",
4851
+ api: attribution.api ?? "openai-chatgpt-responses",
4837
4852
  provider: attribution.provider,
4838
4853
  model: this.params.modelId,
4839
4854
  usage,
@@ -4850,7 +4865,7 @@ var CodexAppServerEventProjector = class {
4850
4865
  type: "text",
4851
4866
  text: `${title}:\n${text}`
4852
4867
  }],
4853
- api: attribution.api ?? "openai-codex-responses",
4868
+ api: attribution.api ?? "openai-chatgpt-responses",
4854
4869
  provider: attribution.provider,
4855
4870
  model: this.params.modelId,
4856
4871
  usage: ZERO_USAGE,
@@ -4870,7 +4885,7 @@ var CodexAppServerEventProjector = class {
4870
4885
  arguments: args,
4871
4886
  input: args
4872
4887
  }],
4873
- api: attribution.api ?? "openai-codex-responses",
4888
+ api: attribution.api ?? "openai-chatgpt-responses",
4874
4889
  provider: attribution.provider,
4875
4890
  model: this.params.modelId,
4876
4891
  usage: ZERO_USAGE,
@@ -4920,6 +4935,30 @@ function readString$5(record, key) {
4920
4935
  const value = record[key];
4921
4936
  return typeof value === "string" ? value : void 0;
4922
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
+ }
4923
4962
  function normalizeNonEmptyString(value) {
4924
4963
  if (typeof value !== "string") return;
4925
4964
  return value.trim() || void 0;
@@ -6349,6 +6388,9 @@ function unrefTimer(timer) {
6349
6388
  //#endregion
6350
6389
  //#region extensions/codex/src/app-server/startup-binding.ts
6351
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;
6352
6394
  const CODEX_APP_SERVER_BYTE_UNITS = {
6353
6395
  b: 1,
6354
6396
  k: 1024,
@@ -6364,6 +6406,7 @@ const CODEX_APP_SERVER_BYTE_UNITS = {
6364
6406
  tb: 1024 * 1024 * 1024 * 1024,
6365
6407
  tib: 1024 * 1024 * 1024 * 1024
6366
6408
  };
6409
+ const codexSessionRecordCache = /* @__PURE__ */ new Map();
6367
6410
  function parseCodexAppServerByteLimit(value) {
6368
6411
  if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.floor(value);
6369
6412
  if (typeof value !== "string") return;
@@ -6419,22 +6462,44 @@ async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codex
6419
6462
  }
6420
6463
  async function readCodexSessionRecordForSessionFile(sessionFile) {
6421
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;
6422
6475
  let store;
6423
6476
  try {
6424
6477
  store = JSON.parse(await fs.readFile(sessionsFile, "utf8"));
6425
6478
  } catch {
6479
+ codexSessionRecordCache.delete(resolvedSessionFile);
6426
6480
  return;
6427
6481
  }
6428
- if (!isJsonObject(store)) return;
6429
- const resolvedSessionFile = path.resolve(sessionFile);
6482
+ if (!isJsonObject(store)) {
6483
+ codexSessionRecordCache.delete(resolvedSessionFile);
6484
+ return;
6485
+ }
6486
+ let found;
6430
6487
  for (const [sessionKey, record] of Object.entries(store)) {
6431
6488
  if (!isJsonObject(record) || typeof record.sessionFile !== "string") continue;
6432
6489
  if (path.resolve(record.sessionFile) !== resolvedSessionFile) continue;
6433
- return {
6490
+ found = {
6434
6491
  sessionKey,
6435
6492
  ...record
6436
6493
  };
6494
+ break;
6437
6495
  }
6496
+ codexSessionRecordCache.set(resolvedSessionFile, {
6497
+ sessionsFile,
6498
+ mtimeMs: stat.mtimeMs,
6499
+ size: stat.size,
6500
+ record: found
6501
+ });
6502
+ return found;
6438
6503
  }
6439
6504
  async function readCodexAppServerRolloutTokenSnapshot(file) {
6440
6505
  let handle;
@@ -6478,52 +6543,75 @@ function readCodexAppServerRolloutTokenSnapshotLine(line) {
6478
6543
  return;
6479
6544
  }
6480
6545
  }
6481
- function resolveCodexAppServerNativeThreadTokenFuse(modelContextWindow) {
6482
- 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);
6483
6566
  }
6484
6567
  function maxFiniteNumber(values) {
6485
6568
  const nums = values.filter((value) => typeof value === "number" && Number.isFinite(value));
6486
6569
  if (nums.length === 0) return;
6487
6570
  return Math.max(...nums);
6488
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
+ }
6489
6577
  function hasContextEngineThreadBootstrapProjection(binding) {
6490
6578
  return binding.contextEngine?.projection?.mode === "thread_bootstrap";
6491
6579
  }
6492
6580
  async function rotateOversizedCodexAppServerStartupBinding(params) {
6493
6581
  const binding = params.binding;
6494
6582
  if (!binding?.threadId) return binding;
6495
- if (params.config?.agents?.defaults?.compaction?.truncateAfterCompaction !== true) return binding;
6496
- if (params.contextEngineActive === true && hasContextEngineThreadBootstrapProjection(binding)) {
6497
- embeddedAgentLog.debug("codex app-server deferring native transcript size guard for context-engine thread bootstrap", {
6498
- threadId: binding.threadId,
6499
- engineId: binding.contextEngine?.engineId,
6500
- epoch: binding.contextEngine?.projection?.epoch,
6501
- fingerprint: binding.contextEngine?.projection?.fingerprint
6502
- });
6503
- return binding;
6504
- }
6505
6583
  const sessionRecord = await readCodexSessionRecordForSessionFile(params.sessionFile);
6506
- const maxBytes = parseCodexAppServerByteLimit(params.config?.agents?.defaults?.compaction?.maxActiveTranscriptBytes);
6507
6584
  const rolloutFiles = await listCodexAppServerRolloutFilesForThread(params.agentDir, binding.threadId, params.codexHome);
6508
- if (maxBytes !== void 0) {
6509
- const oversizedFiles = rolloutFiles.filter((file) => file.bytes >= maxBytes);
6510
- if (oversizedFiles.length > 0) {
6511
- embeddedAgentLog.warn("codex app-server native transcript exceeded active byte limit; starting a fresh thread", {
6512
- threadId: binding.threadId,
6513
- maxBytes,
6514
- files: oversizedFiles.map((file) => ({
6515
- path: file.path,
6516
- bytes: file.bytes
6517
- }))
6518
- });
6519
- await clearCodexAppServerBinding(params.sessionFile);
6520
- 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
+ }
6521
6603
  }
6522
6604
  }
6523
6605
  const nativeTokenSnapshots = await Promise.all(rolloutFiles.map(async (file) => readCodexAppServerRolloutTokenSnapshot(file.path)));
6524
6606
  const nativeTokens = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.totalTokens));
6525
6607
  const nativeModelContextWindow = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.modelContextWindow));
6526
- 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
+ });
6527
6615
  const sessionTokens = sessionRecord?.totalTokensFresh !== false && typeof sessionRecord?.totalTokens === "number" && Number.isFinite(sessionRecord.totalTokens) ? sessionRecord.totalTokens : void 0;
6528
6616
  const tokenCount = maxFiniteNumber([sessionTokens, nativeTokens]);
6529
6617
  if (tokenCount !== void 0 && tokenCount >= maxTokens) {
@@ -6533,11 +6621,24 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
6533
6621
  sessionKey: sessionRecord?.sessionKey,
6534
6622
  sessionTokens,
6535
6623
  nativeTokens,
6536
- nativeModelContextWindow
6624
+ nativeModelContextWindow,
6625
+ sessionModelContextWindow,
6626
+ reserveTokens,
6627
+ projectedTurnTokens: params.projectedTurnTokens
6537
6628
  });
6538
6629
  await clearCodexAppServerBinding(params.sessionFile);
6539
6630
  return;
6540
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
+ }
6541
6642
  return binding;
6542
6643
  }
6543
6644
  //#endregion
@@ -7056,7 +7157,12 @@ function readRequestId(record) {
7056
7157
  //#endregion
7057
7158
  //#region extensions/codex/src/app-server/run-attempt.ts
7058
7159
  const CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS = 6e4;
7160
+ const CODEX_APP_SERVER_PROJECTED_CHARS_PER_TOKEN = 4;
7059
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
+ }
7060
7166
  async function ensureCodexWorkspaceDirOnce(workspaceDir) {
7061
7167
  const normalized = path.resolve(workspaceDir);
7062
7168
  if (ensuredCodexWorkspaceDirs.has(normalized)) {
@@ -7363,12 +7469,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
7363
7469
  const baseDeveloperInstructions = joinPresentSections(buildDeveloperInstructions(params, { dynamicTools: toolBridge.availableSpecs }), workspaceBootstrapContext.developerInstructions);
7364
7470
  const openClawPromptContext = buildCodexOpenClawPromptContext({
7365
7471
  params,
7366
- skillsPrompt: params.skillsSnapshot?.prompt,
7367
- workspacePromptContext: workspaceBootstrapContext.promptContext,
7368
- workspaceMemoryReference: renderCodexWorkspaceMemoryReference({
7369
- files: workspaceBootstrapContext.memoryReferenceFiles ?? [],
7370
- toolNames: workspaceBootstrapContext.memoryToolNames
7371
- })
7472
+ workspacePromptContext: workspaceBootstrapContext.promptContext
7473
+ });
7474
+ const skillsCollaborationInstructions = renderCodexSkillsCollaborationInstructions({
7475
+ attempt: params,
7476
+ skillsPrompt: params.skillsSnapshot?.prompt
7372
7477
  });
7373
7478
  let promptText = params.prompt;
7374
7479
  let developerInstructions = baseDeveloperInstructions;
@@ -7435,41 +7540,69 @@ async function runCodexAppServerAttempt(params, options = {}) {
7435
7540
  } catch (assembleErr) {
7436
7541
  embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
7437
7542
  }
7438
- else if (shouldProjectMirroredHistoryForCodexStart({
7439
- startupBinding,
7440
- dynamicToolsFingerprint: codexDynamicToolsFingerprint(toolBridge.specs),
7441
- historyMessages,
7442
- forceProject: !nativeToolSurfaceEnabled
7443
- })) {
7444
- const projection = projectContextEngineAssemblyForCodex({
7445
- assembledMessages: historyMessages,
7446
- originalHistoryMessages: historyMessages,
7447
- prompt: params.prompt
7448
- });
7449
- promptText = projection.promptText;
7450
- prePromptMessageCount = projection.prePromptMessageCount;
7451
- }
7543
+ const codexModelInputHistoryMessages = [];
7452
7544
  const buildPromptFromCurrentInputs = () => resolveAgentHarnessBeforePromptBuildResult({
7453
7545
  prompt: prependCurrentInboundContext(promptText, params.currentInboundContext),
7454
7546
  developerInstructions,
7455
- messages: historyMessages,
7547
+ messages: codexModelInputHistoryMessages,
7456
7548
  ctx: hookContext
7457
7549
  });
7458
7550
  let promptBuild = await buildPromptFromCurrentInputs();
7459
- const decorateCodexTurnPromptText = (prompt) => prependCodexOpenClawPromptContext(prompt, openClawPromptContext);
7551
+ const decorateCodexTurnPromptText = (prompt) => prependCodexOpenClawPromptContext(prompt, openClawPromptContext, { preservePromptWithoutContext: params.bootstrapContextMode === "lightweight" && params.bootstrapContextRunKind === "cron" });
7460
7552
  let codexTurnPromptText = decorateCodexTurnPromptText(promptBuild.prompt);
7461
7553
  const buildCodexTurnCollaborationDeveloperInstructions = () => buildTurnCollaborationMode(params, {
7462
7554
  turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
7555
+ skillsCollaborationInstructions,
7556
+ memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
7463
7557
  heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
7464
7558
  }).settings.developer_instructions ?? void 0;
7465
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();
7466
7599
  const systemPromptReport = buildCodexSystemPromptReport({
7467
7600
  attempt: params,
7468
7601
  sessionKey: contextSessionKey,
7469
7602
  workspaceDir: effectiveWorkspace,
7470
7603
  developerInstructions: buildRenderedCodexDeveloperInstructions(),
7471
7604
  workspaceBootstrapContext,
7472
- skillsPrompt: openClawPromptContext ? params.skillsSnapshot?.prompt ?? "" : "",
7605
+ skillsPrompt: skillsCollaborationInstructions ? params.skillsSnapshot?.prompt ?? "" : "",
7473
7606
  tools: toolBridge.availableSpecs
7474
7607
  });
7475
7608
  const trajectoryRecorder = createCodexTrajectoryRecorder({
@@ -7592,7 +7725,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
7592
7725
  recordCodexTrajectoryContext(trajectoryRecorder, {
7593
7726
  attempt: params,
7594
7727
  cwd: effectiveCwd,
7595
- developerInstructions: promptBuild.developerInstructions,
7728
+ developerInstructions: buildRenderedCodexDeveloperInstructions(),
7596
7729
  prompt: codexTurnPromptText,
7597
7730
  tools: toolBridge.availableSpecs
7598
7731
  });
@@ -7605,6 +7738,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
7605
7738
  let terminalTurnNotificationQueued = false;
7606
7739
  let timedOut = false;
7607
7740
  let turnCompletionIdleTimedOut = false;
7741
+ let turnWatchTimeoutKind;
7608
7742
  let turnCompletionIdleTimeoutMessage;
7609
7743
  let clientClosedPromptError;
7610
7744
  let clientClosedAbort = false;
@@ -7657,9 +7791,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
7657
7791
  turnTerminalIdleTimeoutMs,
7658
7792
  interruptTimeoutMs: CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS,
7659
7793
  onInterruptTurn: (input) => interruptCodexTurnBestEffort(client, input),
7660
- onTimeout: () => {
7794
+ onTimeout: (timeout) => {
7661
7795
  timedOut = true;
7662
7796
  turnCompletionIdleTimedOut = true;
7797
+ turnWatchTimeoutKind = timeout.kind;
7663
7798
  turnCompletionIdleTimeoutMessage = "codex app-server turn idle timed out waiting for turn/completed";
7664
7799
  },
7665
7800
  onMarkTimedOut: () => projector?.markTimedOut(),
@@ -7803,7 +7938,6 @@ async function runCodexAppServerAttempt(params, options = {}) {
7803
7938
  threadId: thread.threadId,
7804
7939
  turnId,
7805
7940
  currentPromptTexts: [codexTurnPromptText],
7806
- sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
7807
7941
  turnWatches,
7808
7942
  activeTurnItemIds,
7809
7943
  activeAppServerTurnRequests,
@@ -7850,7 +7984,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
7850
7984
  return Promise.resolve();
7851
7985
  }
7852
7986
  if (isTerminalTurnNotificationForTurn(notification, turnId)) terminalTurnNotificationQueued = true;
7853
- 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);
7854
7994
  notificationQueue = notificationQueue.then(() => handleNotification(notification), () => handleNotification(notification));
7855
7995
  return notificationQueue;
7856
7996
  };
@@ -8077,10 +8217,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
8077
8217
  } finally {
8078
8218
  if (requestCountsAsTurnActivity) {
8079
8219
  activeAppServerTurnRequests = Math.max(0, activeAppServerTurnRequests - 1);
8220
+ const postToolContinuationTimeoutMs = request.method === "item/tool/call" && turnCrossedToolHandoff ? postToolRawAssistantCompletionIdleTimeoutMs : void 0;
8080
8221
  turnWatches.touchActivity(`request:${request.method}:response`, {
8081
8222
  arm: armCompletionWatchOnResponse,
8082
- attemptProgress: true
8223
+ attemptProgress: true,
8224
+ ...postToolContinuationTimeoutMs !== void 0 ? { attemptTimeoutMs: postToolContinuationTimeoutMs } : {}
8083
8225
  });
8226
+ if (armCompletionWatchOnResponse && postToolContinuationTimeoutMs !== void 0) turnWatches.armCompletionIdleWatch({ timeoutMs: postToolContinuationTimeoutMs });
8084
8227
  scheduleTerminalDynamicToolReleaseCheck();
8085
8228
  } else turnWatches.scheduleProgressWatches();
8086
8229
  }
@@ -8093,11 +8236,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
8093
8236
  model: params.modelId,
8094
8237
  systemPrompt: buildRenderedCodexDeveloperInstructions(),
8095
8238
  prompt: codexTurnPromptText,
8096
- historyMessages,
8239
+ historyMessages: codexModelInputHistoryMessages,
8097
8240
  imagesCount: params.images?.length ?? 0,
8098
8241
  tools
8099
8242
  });
8100
- const buildTurnStartFailureMessages = () => [...historyMessages, buildCodexUserPromptMessage({
8243
+ const buildCodexModelInputMessages = () => [...codexModelInputHistoryMessages, buildCodexUserPromptMessage({
8101
8244
  ...params,
8102
8245
  prompt: codexTurnPromptText
8103
8246
  })];
@@ -8116,7 +8259,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
8116
8259
  },
8117
8260
  capture: codexModelContentCapture,
8118
8261
  tools,
8119
- buildInputMessages: buildTurnStartFailureMessages,
8262
+ buildInputMessages: buildCodexModelInputMessages,
8120
8263
  buildSystemPrompt: buildRenderedCodexDeveloperInstructions,
8121
8264
  onErrorDiagnostic: (error) => {
8122
8265
  embeddedAgentLog.debug("codex app-server model call diagnostic ended with error", { error: formatErrorMessage(error) });
@@ -8132,6 +8275,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
8132
8275
  sandboxPolicy: codexSandboxPolicy,
8133
8276
  environmentSelection: codexEnvironmentSelection,
8134
8277
  turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
8278
+ skillsCollaborationInstructions,
8279
+ memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
8135
8280
  heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
8136
8281
  });
8137
8282
  codexModelCallDiagnostics.setRequestPayloadBytes(utf8JsonByteLength(turnStartParams));
@@ -8157,7 +8302,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
8157
8302
  turn = await startCodexTurn();
8158
8303
  } catch (error) {
8159
8304
  let turnStartError = error;
8160
- if (shouldRetryContextEngineTurnOnFreshCodexThread({
8305
+ if (shouldUseFreshCodexThreadAfterContextEngineOverflow({
8161
8306
  error: turnStartError,
8162
8307
  contextEngineActive: Boolean(activeContextEngine),
8163
8308
  thread
@@ -8168,20 +8313,26 @@ async function runCodexAppServerAttempt(params, options = {}) {
8168
8313
  });
8169
8314
  try {
8170
8315
  const preRetrySessionFile = activeSessionFile;
8171
- await clearCodexAppServerBinding(preRetrySessionFile);
8172
- if (activeSessionFile !== preRetrySessionFile) await clearCodexAppServerBinding(activeSessionFile);
8173
- thread = await restartContextEngineCodexThread();
8174
- emitCodexAppServerEvent(params, {
8175
- stream: "codex_app_server.lifecycle",
8176
- data: {
8177
- phase: "thread_ready_retry",
8178
- threadId: thread.threadId
8179
- }
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)
8180
8321
  });
8181
- try {
8182
- turn = await startCodexTurn();
8183
- } catch (retryError) {
8184
- 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
+ }
8185
8336
  }
8186
8337
  } catch (retrySetupError) {
8187
8338
  turnStartError = retrySetupError;
@@ -8240,9 +8391,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
8240
8391
  formatError: formatErrorMessage
8241
8392
  });
8242
8393
  codexModelCallDiagnostics.emitError(turnStartErrorMessage, turnStartFailureKind ? { failureKind: turnStartFailureKind } : {});
8394
+ const turnStartFailureMessages = [...historyMessages, buildCodexUserPromptMessage({
8395
+ ...params,
8396
+ prompt: codexTurnPromptText
8397
+ })];
8243
8398
  await runCodexAgentEndHook(params, {
8244
8399
  event: {
8245
- messages: buildTurnStartFailureMessages(),
8400
+ messages: turnStartFailureMessages,
8246
8401
  success: false,
8247
8402
  error: turnStartErrorMessage,
8248
8403
  durationMs: Date.now() - attemptStartedAt
@@ -8279,7 +8434,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
8279
8434
  return { ...buildCodexTurnStartFailureResult({
8280
8435
  params,
8281
8436
  message: usageLimitError.message,
8282
- messagesSnapshot: buildTurnStartFailureMessages(),
8437
+ messagesSnapshot: turnStartFailureMessages,
8283
8438
  systemPromptReport
8284
8439
  }) };
8285
8440
  }
@@ -8332,6 +8487,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
8332
8487
  const activeProjector = projector;
8333
8488
  turnWatches.armTerminalIdleWatch();
8334
8489
  turnWatches.touchActivity("turn:start", { arm: true });
8490
+ turnWatches.armAttemptIdleWatch();
8491
+ turnWatches.touchActivity("turn:start", { attemptProgress: true });
8335
8492
  for (const notification of pendingNotifications.splice(0)) await enqueueNotification(notification);
8336
8493
  if (!completed && isTerminalTurnStatus(turn.turn.status)) await enqueueNotification({
8337
8494
  method: "turn/completed",
@@ -8369,16 +8526,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
8369
8526
  threadId: thread.threadId,
8370
8527
  turnId: activeTurnId
8371
8528
  });
8372
- turnWatches.armAttemptIdleWatch();
8373
- turnWatches.armTerminalIdleWatch();
8374
- turnWatches.touchActivity("turn:start", { attemptProgress: true });
8375
8529
  const abortListener = () => {
8376
8530
  if (timedOut) {
8377
- retireCodexAppServerClientAfterTimedOutTurn(client, {
8378
- threadId: thread.threadId,
8379
- turnId: activeTurnId,
8380
- reason: String(runAbortController.signal.reason ?? "timeout")
8381
- }).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(() => {
8382
8539
  resolveCompletion?.();
8383
8540
  });
8384
8541
  return;
@@ -8393,6 +8550,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
8393
8550
  if (runAbortController.signal.aborted) abortListener();
8394
8551
  try {
8395
8552
  await completion;
8553
+ await notificationQueue;
8396
8554
  const result = activeProjector.buildResult(toolBridge.telemetry, { yieldDetected });
8397
8555
  const finalAborted = result.aborted || runAbortController.signal.aborted && !clientClosedAbort;
8398
8556
  let finalPromptError = clientClosedPromptError ?? (turnCompletionIdleTimedOut ? turnCompletionIdleTimeoutMessage : timedOut ? "codex app-server attempt timed out" : result.promptError);
@@ -8403,6 +8561,20 @@ async function runCodexAppServerAttempt(params, options = {}) {
8403
8561
  turnId: activeTurnId,
8404
8562
  error: finalPromptErrorMessage
8405
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
+ }
8406
8578
  const refreshedUsageLimitPromptError = await refreshCodexUsageLimitPromptError({
8407
8579
  client,
8408
8580
  message: finalPromptErrorMessage,
@@ -8534,6 +8706,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
8534
8706
  promptErrorSource: finalPromptErrorSource,
8535
8707
  ...codexAppServerFailureKind ? { codexAppServerFailure: {
8536
8708
  kind: codexAppServerFailureKind,
8709
+ ...codexAppServerFailureKind === "turn_completion_idle_timeout" && turnWatchTimeoutKind ? { turnWatchTimeoutKind } : {},
8537
8710
  transport: appServer.start.transport,
8538
8711
  threadId: thread.threadId,
8539
8712
  turnId: activeTurnId,
@@ -8606,7 +8779,14 @@ async function clearCodexBindingAfterInvalidImagePayload(sessionFile, fields) {
8606
8779
  function isNonEmptyString(value) {
8607
8780
  return typeof value === "string" && value.length > 0;
8608
8781
  }
8609
- 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) {
8610
8790
  if (!params.contextEngineActive || params.thread.lifecycle.action !== "resumed") return false;
8611
8791
  return isCodexContextWindowError(params.error);
8612
8792
  }