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

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.
@@ -1,16 +1,16 @@
1
- import { c as resolveCodexAppServerRuntimeOptions, d as withMcpElicitationsApprovalPolicy, i as isCodexAppServerApprovalPolicyAllowedByRequirements, s as readCodexPluginConfig, u as resolveCodexPluginsPolicy } from "./config-3ATInASk.js";
2
- import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-CSY0BFBo.js";
1
+ import { c as resolveCodexAppServerRuntimeOptions, d as withMcpElicitationsApprovalPolicy, i as isCodexAppServerApprovalPolicyAllowedByRequirements, s as readCodexPluginConfig, u as resolveCodexPluginsPolicy } from "./config-B5pq6hEz.js";
2
+ import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-BGBspNmF.js";
3
3
  import { t as isJsonObject } from "./protocol-C9UWI98H.js";
4
- import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-CA7amCZ8.js";
5
- import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-Czoa60Nt.js";
4
+ import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-6FkrXfaz.js";
5
+ import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-XPjLayGw.js";
6
6
  import { d as resolveCodexUsageLimitResetAtMs, f as shouldRefreshCodexRateLimitsForUsageLimitMessage, r as formatCodexDisplayText, u as formatCodexUsageLimitErrorMessage } from "./command-formatters-BRW7_Nu7.js";
7
- import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, l as resolveCodexAppServerAuthProfileId, n as clearSharedCodexAppServerClientIfCurrent, s as refreshCodexAppServerAuthTokens, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-CnbrvEfV.js";
8
- import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-DbdVqMzW.js";
9
- import { a as defaultCodexAppInventoryCache } from "./plugin-activation-BDU4e-NA.js";
10
- import { S as normalizeCodexDynamicToolName, _ as projectContextEngineAssemblyForCodex, b as createCodexDynamicToolBridge, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as shouldBuildCodexPluginThreadConfig, h as mergeCodexThreadConfigs, i as buildDeveloperInstructions, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfigInputFingerprint, p as buildCodexPluginThreadConfig, r as buildContextEngineBinding, s as buildTurnStartParams, t as areCodexDynamicToolFingerprintsCompatible, v as resolveCodexContextEngineProjectionMaxChars, x as filterCodexDynamicTools, y as resolveCodexContextEngineProjectionReserveTokens } from "./thread-lifecycle-BMK4m_PL.js";
11
- import { t as defaultCodexAppServerClientFactory } from "./client-factory-DwzPofwS.js";
7
+ import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, l as resolveCodexAppServerAuthProfileId, s as refreshCodexAppServerAuthTokens, t as clearSharedCodexAppServerClientIfCurrent, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-DlvmoLBJ.js";
8
+ import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-DqApZIgD.js";
9
+ import { a as defaultCodexAppInventoryCache } from "./plugin-activation-B49xb7pI.js";
10
+ import { S as normalizeCodexDynamicToolName, _ as projectContextEngineAssemblyForCodex, b as createCodexDynamicToolBridge, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as shouldBuildCodexPluginThreadConfig, h as mergeCodexThreadConfigs, i as buildDeveloperInstructions, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfigInputFingerprint, p as buildCodexPluginThreadConfig, r as buildContextEngineBinding, s as buildTurnStartParams, t as areCodexDynamicToolFingerprintsCompatible, v as resolveCodexContextEngineProjectionMaxChars, x as filterCodexDynamicTools, y as resolveCodexContextEngineProjectionReserveTokens } from "./thread-lifecycle-wcyYqwrl.js";
11
+ import { t as defaultCodexAppServerClientFactory } from "./client-factory-9L6Ie1dC.js";
12
12
  import { n as handleCodexAppServerElicitationRequest, r as handleCodexAppServerApprovalRequest, t as filterToolsForVisionInputs } from "./vision-tools-Cm_YicZb.js";
13
- import { t as ensureCodexComputerUse } from "./computer-use-BX02ojP4.js";
13
+ import { t as ensureCodexComputerUse } from "./computer-use-UJ3dxrXF.js";
14
14
  import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-dvhq-4pi.js";
15
15
  import { createHash } from "node:crypto";
16
16
  import nodeFs from "node:fs";
@@ -23,6 +23,26 @@ import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugi
23
23
  import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
24
24
  import { createRunningTaskRun, finalizeTaskRunByRunId, recordTaskRunProgressByRunId } from "openclaw/plugin-sdk/codex-native-task-runtime";
25
25
  import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "@earendil-works/pi-coding-agent";
26
+ //#region extensions/codex/src/app-server/local-runtime-attribution.ts
27
+ const OPENAI_PROVIDER_ID = "openai";
28
+ const OPENAI_RESPONSES_API = "openai-responses";
29
+ const OPENAI_CODEX_PROVIDER_ID = "openai-codex";
30
+ const OPENAI_CODEX_RESPONSES_API = "openai-codex-responses";
31
+ function normalizeRuntimeId(value) {
32
+ return value?.trim().toLowerCase() ?? "";
33
+ }
34
+ function resolveCodexLocalRuntimeAttribution(params) {
35
+ const authProfileProvider = normalizeRuntimeId(params.runtimePlan?.auth?.authProfileProviderForAuth);
36
+ 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 {
37
+ provider: OPENAI_CODEX_PROVIDER_ID,
38
+ api: OPENAI_CODEX_RESPONSES_API
39
+ };
40
+ return {
41
+ provider: params.provider,
42
+ api: params.model.api
43
+ };
44
+ }
45
+ //#endregion
26
46
  //#region extensions/codex/src/app-server/native-subagent-task-mirror.ts
27
47
  const CODEX_NATIVE_SUBAGENT_RUNTIME = "subagent";
28
48
  const CODEX_NATIVE_SUBAGENT_TASK_KIND = "codex-native";
@@ -860,6 +880,7 @@ var CodexAppServerEventProjector = class {
860
880
  data: {
861
881
  phase: "end",
862
882
  backend: "codex-app-server",
883
+ completed: true,
863
884
  threadId: this.threadId,
864
885
  turnId: this.turnId,
865
886
  itemId
@@ -1017,8 +1038,14 @@ var CodexAppServerEventProjector = class {
1017
1038
  const text = extractRawAssistantText(item);
1018
1039
  if (!text) return;
1019
1040
  const itemId = readString$2(item, "id") ?? `raw-assistant-${this.assistantItemOrder.length + 1}`;
1041
+ const phase = readString$2(item, "phase");
1042
+ if (phase) this.assistantPhaseByItem.set(itemId, phase);
1020
1043
  this.rememberAssistantItem(itemId);
1021
1044
  this.assistantTextByItem.set(itemId, text);
1045
+ if (phase === "commentary") this.emitCommentaryProgress({
1046
+ itemId,
1047
+ text
1048
+ });
1022
1049
  }
1023
1050
  recordNativeGeneratedMedia(item) {
1024
1051
  if (item?.type !== "imageGeneration") return;
@@ -1327,6 +1354,7 @@ var CodexAppServerEventProjector = class {
1327
1354
  return await readCodexMirroredSessionHistoryMessages(this.params.sessionFile) ?? [];
1328
1355
  }
1329
1356
  createAssistantMessage(text) {
1357
+ const attribution = resolveCodexLocalRuntimeAttribution(this.params);
1330
1358
  const usage = this.tokenUsage ? {
1331
1359
  input: this.tokenUsage.input ?? 0,
1332
1360
  output: this.tokenUsage.output ?? 0,
@@ -1341,8 +1369,8 @@ var CodexAppServerEventProjector = class {
1341
1369
  type: "text",
1342
1370
  text
1343
1371
  }],
1344
- api: this.params.model.api ?? "openai-codex-responses",
1345
- provider: this.params.provider,
1372
+ api: attribution.api ?? "openai-codex-responses",
1373
+ provider: attribution.provider,
1346
1374
  model: this.params.modelId,
1347
1375
  usage,
1348
1376
  stopReason: this.aborted ? "aborted" : this.promptError ? "error" : "stop",
@@ -1351,14 +1379,15 @@ var CodexAppServerEventProjector = class {
1351
1379
  };
1352
1380
  }
1353
1381
  createAssistantMirrorMessage(title, text) {
1382
+ const attribution = resolveCodexLocalRuntimeAttribution(this.params);
1354
1383
  return {
1355
1384
  role: "assistant",
1356
1385
  content: [{
1357
1386
  type: "text",
1358
1387
  text: `${title}:\n${text}`
1359
1388
  }],
1360
- api: this.params.model.api ?? "openai-codex-responses",
1361
- provider: this.params.provider,
1389
+ api: attribution.api ?? "openai-codex-responses",
1390
+ provider: attribution.provider,
1362
1391
  model: this.params.modelId,
1363
1392
  usage: ZERO_USAGE,
1364
1393
  stopReason: "stop",
@@ -1367,6 +1396,7 @@ var CodexAppServerEventProjector = class {
1367
1396
  }
1368
1397
  createToolCallMessage(params) {
1369
1398
  const args = normalizeToolTranscriptArguments(params.arguments);
1399
+ const attribution = resolveCodexLocalRuntimeAttribution(this.params);
1370
1400
  return {
1371
1401
  role: "assistant",
1372
1402
  content: [{
@@ -1376,8 +1406,8 @@ var CodexAppServerEventProjector = class {
1376
1406
  arguments: args,
1377
1407
  input: args
1378
1408
  }],
1379
- api: this.params.model.api ?? "openai-codex-responses",
1380
- provider: this.params.provider,
1409
+ api: attribution.api ?? "openai-codex-responses",
1410
+ provider: attribution.provider,
1381
1411
  model: this.params.modelId,
1382
1412
  usage: ZERO_USAGE,
1383
1413
  stopReason: "toolUse",
@@ -1882,6 +1912,7 @@ function createCodexTrajectoryRecorder(params) {
1882
1912
  });
1883
1913
  let queue = Promise.resolve();
1884
1914
  let seq = 0;
1915
+ const attribution = resolveCodexLocalRuntimeAttribution(params.attempt);
1885
1916
  return {
1886
1917
  filePath,
1887
1918
  recordEvent: (type, data) => {
@@ -1898,9 +1929,9 @@ function createCodexTrajectoryRecorder(params) {
1898
1929
  sessionKey: params.attempt.sessionKey,
1899
1930
  runId: params.attempt.runId,
1900
1931
  workspaceDir: params.cwd,
1901
- provider: params.attempt.provider,
1932
+ provider: attribution.provider,
1902
1933
  modelId: params.attempt.modelId,
1903
- modelApi: params.attempt.model.api,
1934
+ modelApi: attribution.api,
1904
1935
  data: data ? sanitizeValue(data) : void 0
1905
1936
  });
1906
1937
  if (!line) return;
@@ -2186,6 +2217,7 @@ const CODEX_TURN_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS = 1e4;
2186
2217
  const CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS = 30 * 6e4;
2187
2218
  const CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS = 30 * 6e4;
2188
2219
  const CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS = 5 * 6e4;
2220
+ const CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS = 6e4;
2189
2221
  const CODEX_STEER_ALL_DEBOUNCE_MS = 500;
2190
2222
  const LOG_FIELD_MAX_LENGTH = 160;
2191
2223
  const CODEX_NATIVE_PROJECT_DOC_BASENAMES = new Set(["agents.md"]);
@@ -2612,7 +2644,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
2612
2644
  prePromptMessageCount = projection.prePromptMessageCount;
2613
2645
  }
2614
2646
  const buildPromptFromCurrentInputs = () => resolveAgentHarnessBeforePromptBuildResult({
2615
- prompt: prependCurrentTurnContext(promptText, params.currentTurnContext),
2647
+ prompt: prependCurrentInboundContext(promptText, params.currentInboundContext),
2616
2648
  developerInstructions,
2617
2649
  messages: historyMessages,
2618
2650
  ctx: hookContext
@@ -2661,11 +2693,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
2661
2693
  turnStartTimeoutMs: params.timeoutMs,
2662
2694
  signal: runAbortController.signal
2663
2695
  });
2664
- const threadConfig = mergeCodexThreadConfigs(nativeHookRelay ? buildCodexNativeHookRelayConfig({
2696
+ const nativeHookRelayConfig = nativeHookRelay ? buildCodexNativeHookRelayConfig({
2665
2697
  relay: nativeHookRelay,
2666
2698
  events: nativeHookRelayEvents,
2667
2699
  hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec
2668
- }) : options.nativeHookRelay?.enabled === false ? buildCodexNativeHookRelayDisabledConfig() : void 0, bundleMcpThreadConfig?.configPatch);
2700
+ }) : options.nativeHookRelay?.enabled === false ? buildCodexNativeHookRelayDisabledConfig() : void 0;
2701
+ const threadConfig = mergeCodexThreadConfigs(bundleMcpThreadConfig?.configPatch);
2669
2702
  const pluginThreadConfigEnabled = shouldBuildCodexPluginThreadConfig(pluginConfig);
2670
2703
  const pluginAppCacheKey = buildCodexPluginAppCacheKey({
2671
2704
  appServer,
@@ -2708,6 +2741,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
2708
2741
  appServer: pluginAppServer,
2709
2742
  developerInstructions: promptBuild.developerInstructions,
2710
2743
  config: threadConfig,
2744
+ finalConfigPatch: nativeHookRelayConfig,
2711
2745
  mcpServersFingerprint: bundleMcpThreadConfig.fingerprint,
2712
2746
  mcpServersFingerprintEvaluated: bundleMcpThreadConfig.evaluated,
2713
2747
  contextEngineProjection,
@@ -2794,9 +2828,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
2794
2828
  let userInputBridge;
2795
2829
  let steeringQueue;
2796
2830
  let completed = false;
2831
+ let terminalTurnNotificationQueued = false;
2797
2832
  let timedOut = false;
2798
2833
  let turnCompletionIdleTimedOut = false;
2799
2834
  let turnCompletionIdleTimeoutMessage;
2835
+ let clientClosedPromptError;
2836
+ let clientClosedAbort = false;
2800
2837
  let lifecycleStarted = false;
2801
2838
  let lifecycleTerminalEmitted = false;
2802
2839
  let resolveCompletion;
@@ -2810,18 +2847,27 @@ async function runCodexAppServerAttempt(params, options = {}) {
2810
2847
  let turnCompletionIdleTimer;
2811
2848
  let turnCompletionIdleWatchArmed = false;
2812
2849
  let turnCompletionIdleWatchPinnedByTerminalError = false;
2850
+ let turnCompletionIdleTimeoutOverrideMs;
2813
2851
  let turnAssistantCompletionIdleTimer;
2814
2852
  let turnAssistantCompletionIdleWatchArmed = false;
2815
2853
  let turnAssistantCompletionLastActivityAt = Date.now();
2816
2854
  let turnAssistantCompletionLastActivityDetails;
2855
+ const turnAttemptIdleTimeoutMs = Math.max(100, Math.floor(params.timeoutMs));
2856
+ let turnAttemptIdleTimer;
2857
+ let turnAttemptIdleWatchArmed = false;
2817
2858
  let turnTerminalIdleTimer;
2818
2859
  let turnTerminalIdleWatchArmed = false;
2819
2860
  let turnCompletionLastActivityAt = Date.now();
2820
2861
  let turnCompletionLastActivityReason = "startup";
2821
2862
  let turnCompletionLastActivityDetails;
2863
+ let turnAttemptLastProgressAt = Date.now();
2864
+ let turnAttemptLastProgressReason = "startup";
2865
+ let turnAttemptLastProgressDetails;
2866
+ let nativeHookRelayLastRenewedAt = 0;
2822
2867
  let activeAppServerTurnRequests = 0;
2823
2868
  const activeOpenClawDynamicToolCallIds = /* @__PURE__ */ new Set();
2824
2869
  const activeTurnItemIds = /* @__PURE__ */ new Set();
2870
+ let turnCrossedToolHandoff = false;
2825
2871
  const clearTurnCompletionIdleTimer = () => {
2826
2872
  if (turnCompletionIdleTimer) {
2827
2873
  clearTimeout(turnCompletionIdleTimer);
@@ -2840,6 +2886,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
2840
2886
  turnAssistantCompletionIdleTimer = void 0;
2841
2887
  }
2842
2888
  };
2889
+ const clearTurnAttemptIdleTimer = () => {
2890
+ if (turnAttemptIdleTimer) {
2891
+ clearTimeout(turnAttemptIdleTimer);
2892
+ turnAttemptIdleTimer = void 0;
2893
+ }
2894
+ };
2843
2895
  const fireTurnAssistantCompletionIdleRelease = () => {
2844
2896
  if (completed || runAbortController.signal.aborted || !turnAssistantCompletionIdleWatchArmed) return;
2845
2897
  if (activeAppServerTurnRequests > 0 || activeTurnItemIds.size > 0) {
@@ -2876,10 +2928,40 @@ async function runCodexAppServerAttempt(params, options = {}) {
2876
2928
  completed = true;
2877
2929
  resolveCompletion?.();
2878
2930
  };
2931
+ const fireTurnAttemptIdleTimeout = () => {
2932
+ if (completed || runAbortController.signal.aborted || !turnAttemptIdleWatchArmed) return;
2933
+ const idleMs = Math.max(0, Date.now() - turnAttemptLastProgressAt);
2934
+ if (idleMs < turnAttemptIdleTimeoutMs) {
2935
+ scheduleTurnAttemptIdleWatch();
2936
+ return;
2937
+ }
2938
+ timedOut = true;
2939
+ turnCompletionIdleTimedOut = true;
2940
+ turnCompletionIdleTimeoutMessage = "codex app-server turn idle timed out waiting for turn/completed";
2941
+ projector?.markTimedOut();
2942
+ trajectoryRecorder?.recordEvent("turn.progress_idle_timeout", {
2943
+ threadId: thread.threadId,
2944
+ turnId,
2945
+ idleMs,
2946
+ timeoutMs: turnAttemptIdleTimeoutMs,
2947
+ lastActivityReason: turnAttemptLastProgressReason,
2948
+ ...turnAttemptLastProgressDetails
2949
+ });
2950
+ embeddedAgentLog.warn("codex app-server turn idle timed out waiting for progress", {
2951
+ threadId: thread.threadId,
2952
+ turnId,
2953
+ idleMs,
2954
+ timeoutMs: turnAttemptIdleTimeoutMs,
2955
+ lastActivityReason: turnAttemptLastProgressReason,
2956
+ ...turnAttemptLastProgressDetails
2957
+ });
2958
+ runAbortController.abort("turn_progress_idle_timeout");
2959
+ };
2879
2960
  const fireTurnCompletionIdleTimeout = () => {
2880
2961
  if (completed || runAbortController.signal.aborted || !turnCompletionIdleWatchArmed || activeAppServerTurnRequests > 0) return;
2962
+ const timeoutMs = turnCompletionIdleTimeoutOverrideMs ?? turnCompletionIdleTimeoutMs;
2881
2963
  const idleMs = Math.max(0, Date.now() - turnCompletionLastActivityAt);
2882
- if (idleMs < turnCompletionIdleTimeoutMs) {
2964
+ if (idleMs < timeoutMs) {
2883
2965
  scheduleTurnCompletionIdleWatch();
2884
2966
  return;
2885
2967
  }
@@ -2891,7 +2973,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
2891
2973
  threadId: thread.threadId,
2892
2974
  turnId,
2893
2975
  idleMs,
2894
- timeoutMs: turnCompletionIdleTimeoutMs,
2976
+ timeoutMs,
2895
2977
  lastActivityReason: turnCompletionLastActivityReason,
2896
2978
  ...turnCompletionLastActivityDetails
2897
2979
  });
@@ -2899,7 +2981,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
2899
2981
  threadId: thread.threadId,
2900
2982
  turnId,
2901
2983
  idleMs,
2902
- timeoutMs: turnCompletionIdleTimeoutMs,
2984
+ timeoutMs,
2903
2985
  lastActivityReason: turnCompletionLastActivityReason,
2904
2986
  ...turnCompletionLastActivityDetails
2905
2987
  });
@@ -2938,7 +3020,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
2938
3020
  clearTurnCompletionIdleTimer();
2939
3021
  if (completed || runAbortController.signal.aborted || !turnCompletionIdleWatchArmed || activeAppServerTurnRequests > 0) return;
2940
3022
  const elapsedMs = Math.max(0, Date.now() - turnCompletionLastActivityAt);
2941
- const delayMs = Math.max(1, turnCompletionIdleTimeoutMs - elapsedMs);
3023
+ const delayMs = Math.max(1, (turnCompletionIdleTimeoutOverrideMs ?? turnCompletionIdleTimeoutMs) - elapsedMs);
2942
3024
  turnCompletionIdleTimer = setTimeout(fireTurnCompletionIdleTimeout, delayMs);
2943
3025
  turnCompletionIdleTimer.unref?.();
2944
3026
  }
@@ -2950,6 +3032,14 @@ async function runCodexAppServerAttempt(params, options = {}) {
2950
3032
  turnAssistantCompletionIdleTimer = setTimeout(fireTurnAssistantCompletionIdleRelease, delayMs);
2951
3033
  turnAssistantCompletionIdleTimer.unref?.();
2952
3034
  }
3035
+ function scheduleTurnAttemptIdleWatch() {
3036
+ clearTurnAttemptIdleTimer();
3037
+ if (completed || runAbortController.signal.aborted || !turnAttemptIdleWatchArmed) return;
3038
+ const elapsedMs = Math.max(0, Date.now() - turnAttemptLastProgressAt);
3039
+ const delayMs = Math.max(1, turnAttemptIdleTimeoutMs - elapsedMs);
3040
+ turnAttemptIdleTimer = setTimeout(fireTurnAttemptIdleTimeout, delayMs);
3041
+ turnAttemptIdleTimer.unref?.();
3042
+ }
2953
3043
  function scheduleTurnTerminalIdleWatch() {
2954
3044
  clearTurnTerminalIdleTimer();
2955
3045
  if (completed || runAbortController.signal.aborted || !turnTerminalIdleWatchArmed || activeAppServerTurnRequests > 0) return;
@@ -2958,10 +3048,42 @@ async function runCodexAppServerAttempt(params, options = {}) {
2958
3048
  turnTerminalIdleTimer = setTimeout(fireTurnTerminalIdleTimeout, delayMs);
2959
3049
  turnTerminalIdleTimer.unref?.();
2960
3050
  }
3051
+ function scheduleTurnProgressWatches() {
3052
+ scheduleTurnAttemptIdleWatch();
3053
+ scheduleTurnCompletionIdleWatch();
3054
+ scheduleTurnTerminalIdleWatch();
3055
+ }
3056
+ const renewNativeHookRelayForTurnProgress = () => {
3057
+ if (!nativeHookRelay || options.nativeHookRelay?.ttlMs !== void 0) return;
3058
+ const now = Date.now();
3059
+ const renewsRecently = now - nativeHookRelayLastRenewedAt < CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS;
3060
+ const expiresSoon = now >= nativeHookRelay.expiresAtMs - CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS;
3061
+ if (renewsRecently && !expiresSoon) return;
3062
+ nativeHookRelayLastRenewedAt = now;
3063
+ nativeHookRelay.renew(resolveCodexNativeHookRelayTtlMs({
3064
+ explicitTtlMs: void 0,
3065
+ attemptTimeoutMs: turnAttemptIdleTimeoutMs,
3066
+ startupTimeoutMs,
3067
+ turnStartTimeoutMs: params.timeoutMs
3068
+ }));
3069
+ };
2961
3070
  const touchTurnCompletionActivity = (reason, options) => {
2962
3071
  turnCompletionLastActivityAt = Date.now();
2963
3072
  turnCompletionLastActivityReason = reason;
2964
3073
  turnCompletionLastActivityDetails = options?.details;
3074
+ turnCompletionIdleTimeoutOverrideMs = void 0;
3075
+ if (options?.attemptProgress) {
3076
+ turnAttemptLastProgressAt = turnCompletionLastActivityAt;
3077
+ turnAttemptLastProgressReason = reason;
3078
+ turnAttemptLastProgressDetails = options.details;
3079
+ renewNativeHookRelayForTurnProgress();
3080
+ params.onRunProgress?.({
3081
+ reason,
3082
+ provider: params.provider,
3083
+ model: params.modelId,
3084
+ backend: "codex-app-server"
3085
+ });
3086
+ }
2965
3087
  emitTrustedDiagnosticEvent({
2966
3088
  type: "run.progress",
2967
3089
  runId: params.runId,
@@ -2973,12 +3095,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
2973
3095
  turnCompletionIdleWatchArmed = true;
2974
3096
  turnCompletionIdleWatchPinnedByTerminalError = false;
2975
3097
  }
2976
- scheduleTurnCompletionIdleWatch();
2977
- scheduleTurnTerminalIdleWatch();
3098
+ scheduleTurnProgressWatches();
2978
3099
  };
2979
3100
  const disarmTurnCompletionIdleWatch = () => {
2980
3101
  turnCompletionIdleWatchArmed = false;
2981
3102
  turnCompletionIdleWatchPinnedByTerminalError = false;
3103
+ turnCompletionIdleTimeoutOverrideMs = void 0;
2982
3104
  clearTurnCompletionIdleTimer();
2983
3105
  };
2984
3106
  const disarmTurnAssistantCompletionIdleWatch = () => {
@@ -2995,6 +3117,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
2995
3117
  const armTurnCompletionIdleWatch = (options) => {
2996
3118
  turnCompletionIdleWatchArmed = true;
2997
3119
  turnCompletionIdleWatchPinnedByTerminalError = options?.pinnedByTerminalError === true;
3120
+ turnCompletionIdleTimeoutOverrideMs = options?.timeoutMs !== void 0 ? Math.max(1, Math.floor(options.timeoutMs)) : void 0;
2998
3121
  scheduleTurnCompletionIdleWatch();
2999
3122
  };
3000
3123
  const emitLifecycleStart = () => {
@@ -3049,6 +3172,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
3049
3172
  itemId: item.id
3050
3173
  });
3051
3174
  };
3175
+ const isTerminalTurnNotificationForTurn = (notification, notificationTurnId) => {
3176
+ if (!isTurnNotification(notification.params, thread.threadId, notificationTurnId)) return false;
3177
+ return notification.method === "turn/completed" || isCodexTurnAbortMarkerNotification(notification, { currentPromptText: promptBuild.prompt });
3178
+ };
3052
3179
  const handleNotification = async (notification) => {
3053
3180
  userInputBridge?.handleNotification(notification);
3054
3181
  if (!projector || !turnId) {
@@ -3058,27 +3185,35 @@ async function runCodexAppServerAttempt(params, options = {}) {
3058
3185
  const isCurrentTurnNotification = isTurnNotification(notification.params, thread.threadId, turnId);
3059
3186
  const isTurnCompletion = notification.method === "turn/completed" && isCurrentTurnNotification;
3060
3187
  if (isCurrentTurnNotification) {
3061
- touchTurnCompletionActivity(`notification:${notification.method}`, { details: describeNotificationActivity(notification) });
3188
+ touchTurnCompletionActivity(`notification:${notification.method}`, {
3189
+ details: describeNotificationActivity(notification),
3190
+ attemptProgress: true
3191
+ });
3062
3192
  reportCodexExecutionNotification(notification);
3063
3193
  }
3064
3194
  if (isCurrentTurnNotification) updateActiveTurnItemIds(notification, activeTurnItemIds);
3065
3195
  const unblockedAssistantCompletionRelease = isCurrentTurnNotification && turnAssistantCompletionIdleWatchArmed && notification.method === "item/completed" && activeTurnItemIds.size === 0;
3066
3196
  const trackedDynamicToolCompletion = isTrackedOpenClawDynamicToolCompletionNotification(notification, activeOpenClawDynamicToolCallIds);
3067
3197
  const rawToolOutputCompletion = isRawToolOutputCompletionNotification(notification);
3068
- const shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem = isCurrentTurnNotification && notification.method === "item/completed" && activeTurnItemIds.size === 0 && !trackedDynamicToolCompletion && !isCompletedAssistantNotification(notification);
3198
+ if (isCurrentTurnNotification && (rawToolOutputCompletion || isNativeToolProgressNotification(notification))) turnCrossedToolHandoff = true;
3199
+ const assistantCompletionCanRelease = isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff);
3200
+ const postToolRawAssistantCompletionNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && isRawAssistantCompletionNotification(notification) && activeTurnItemIds.size === 0;
3201
+ const shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem = isCurrentTurnNotification && notification.method === "item/completed" && activeTurnItemIds.size === 0 && !trackedDynamicToolCompletion && !assistantCompletionCanRelease;
3069
3202
  if (isCurrentTurnNotification && notification.method === "error") {
3070
3203
  if (isRetryableErrorNotification(notification.params)) disarmTurnCompletionIdleWatch();
3071
3204
  else armTurnCompletionIdleWatch({ pinnedByTerminalError: true });
3072
3205
  disarmTurnAssistantCompletionIdleWatch();
3073
3206
  } else if (isTurnCompletion) disarmTurnAssistantCompletionIdleWatch();
3074
- else if (isCurrentTurnNotification && isCompletedAssistantNotification(notification)) armTurnAssistantCompletionIdleWatch(describeNotificationActivity(notification));
3207
+ else if (isCurrentTurnNotification && assistantCompletionCanRelease) armTurnAssistantCompletionIdleWatch(describeNotificationActivity(notification));
3208
+ else if (postToolRawAssistantCompletionNeedsTerminalGuard) armTurnCompletionIdleWatch({ timeoutMs: turnAssistantCompletionIdleTimeoutMs });
3075
3209
  else if (unblockedAssistantCompletionRelease) armTurnAssistantCompletionIdleWatch(describeNotificationActivity(notification));
3076
3210
  else if (shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) armTurnCompletionIdleWatch();
3077
3211
  else if (isCurrentTurnNotification && rawToolOutputCompletion) armTurnCompletionIdleWatch();
3078
3212
  else if (isCurrentTurnNotification && shouldDisarmAssistantCompletionIdleWatch(notification)) disarmTurnAssistantCompletionIdleWatch();
3079
- if (turnCompletionIdleWatchArmed && !turnCompletionIdleWatchPinnedByTerminalError && notification.method !== "turn/completed" && isCurrentTurnNotification && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) disarmTurnCompletionIdleWatch();
3213
+ if (turnCompletionIdleWatchArmed && !turnCompletionIdleWatchPinnedByTerminalError && notification.method !== "turn/completed" && isCurrentTurnNotification && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !postToolRawAssistantCompletionNeedsTerminalGuard && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) disarmTurnCompletionIdleWatch();
3080
3214
  const isTurnAbortMarker = isCurrentTurnNotification && isCodexTurnAbortMarkerNotification(notification, { currentPromptText: promptBuild.prompt });
3081
- const isTurnTerminal = isTurnCompletion || isTurnAbortMarker;
3215
+ const isTurnTerminal = isTerminalTurnNotificationForTurn(notification, turnId);
3216
+ if (isTurnTerminal) terminalTurnNotificationQueued = true;
3082
3217
  try {
3083
3218
  await waitForCodexNotificationDispatchTurn();
3084
3219
  await projector.handleNotification(notification);
@@ -3105,16 +3240,21 @@ async function runCodexAppServerAttempt(params, options = {}) {
3105
3240
  pendingNotifications.push(notification);
3106
3241
  return Promise.resolve();
3107
3242
  }
3243
+ if (isTerminalTurnNotificationForTurn(notification, turnId)) terminalTurnNotificationQueued = true;
3108
3244
  notificationQueue = notificationQueue.then(() => handleNotification(notification), () => handleNotification(notification));
3109
3245
  return notificationQueue;
3110
3246
  };
3111
3247
  const notificationCleanup = client.addNotificationHandler(enqueueNotification);
3112
3248
  const requestCleanup = client.addRequestHandler(async (request) => {
3113
- activeAppServerTurnRequests += 1;
3114
- clearTurnCompletionIdleTimer();
3115
- disarmTurnAssistantCompletionIdleWatch();
3116
- touchTurnCompletionActivity(`request:${request.method}`);
3117
3249
  let armCompletionWatchOnResponse = false;
3250
+ let requestCountsAsTurnActivity = false;
3251
+ const markCurrentTurnRequestProgress = () => {
3252
+ activeAppServerTurnRequests += 1;
3253
+ clearTurnCompletionIdleTimer();
3254
+ disarmTurnAssistantCompletionIdleWatch();
3255
+ requestCountsAsTurnActivity = true;
3256
+ touchTurnCompletionActivity(`request:${request.method}:start`, { attemptProgress: true });
3257
+ };
3118
3258
  try {
3119
3259
  if (request.method === "account/chatgptAuthTokens/refresh") return refreshCodexAppServerAuthTokens({
3120
3260
  agentDir,
@@ -3123,7 +3263,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
3123
3263
  });
3124
3264
  if (!turnId) return;
3125
3265
  if (request.method === "mcpServer/elicitation/request") {
3126
- armCompletionWatchOnResponse = true;
3266
+ if (isCurrentThreadOptionalTurnRequestParams(request.params, thread.threadId, turnId)) {
3267
+ armCompletionWatchOnResponse = true;
3268
+ markCurrentTurnRequestProgress();
3269
+ }
3127
3270
  return handleCodexAppServerElicitationRequest({
3128
3271
  requestParams: request.params,
3129
3272
  paramsForRun: params,
@@ -3134,7 +3277,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
3134
3277
  });
3135
3278
  }
3136
3279
  if (request.method === "item/tool/requestUserInput") {
3137
- armCompletionWatchOnResponse = true;
3280
+ if (isCurrentThreadTurnRequestParams(request.params, thread.threadId, turnId)) {
3281
+ armCompletionWatchOnResponse = true;
3282
+ markCurrentTurnRequestProgress();
3283
+ }
3138
3284
  return userInputBridge?.handleRequest({
3139
3285
  id: request.id,
3140
3286
  params: request.params
@@ -3142,7 +3288,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
3142
3288
  }
3143
3289
  if (request.method !== "item/tool/call") {
3144
3290
  if (isCodexAppServerApprovalRequest(request.method)) {
3145
- armCompletionWatchOnResponse = true;
3291
+ if (isCurrentApprovalTurnRequestParams(request.params, thread.threadId, turnId)) {
3292
+ armCompletionWatchOnResponse = true;
3293
+ markCurrentTurnRequestProgress();
3294
+ }
3146
3295
  return handleApprovalRequest({
3147
3296
  method: request.method,
3148
3297
  params: request.params,
@@ -3157,6 +3306,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
3157
3306
  const call = readDynamicToolCallParams(request.params);
3158
3307
  if (!call || call.threadId !== thread.threadId || call.turnId !== turnId) return;
3159
3308
  armCompletionWatchOnResponse = true;
3309
+ markCurrentTurnRequestProgress();
3310
+ turnCrossedToolHandoff = true;
3160
3311
  activeOpenClawDynamicToolCallIds.add(call.callId);
3161
3312
  trajectoryRecorder?.recordEvent("tool.call", {
3162
3313
  threadId: call.threadId,
@@ -3233,10 +3384,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
3233
3384
  });
3234
3385
  return response;
3235
3386
  } finally {
3236
- activeAppServerTurnRequests = Math.max(0, activeAppServerTurnRequests - 1);
3237
- touchTurnCompletionActivity(`request:${request.method}:response`, { arm: armCompletionWatchOnResponse });
3387
+ if (requestCountsAsTurnActivity) {
3388
+ activeAppServerTurnRequests = Math.max(0, activeAppServerTurnRequests - 1);
3389
+ touchTurnCompletionActivity(`request:${request.method}:response`, {
3390
+ arm: armCompletionWatchOnResponse,
3391
+ attemptProgress: true
3392
+ });
3393
+ } else scheduleTurnProgressWatches();
3238
3394
  }
3239
3395
  });
3396
+ let closeCleanup;
3240
3397
  const forceContextEngineCompactionForCodexOverflow = async (error) => {
3241
3398
  if (!activeContextEngine?.info.ownsCompaction) return false;
3242
3399
  embeddedAgentLog.warn("codex app-server context-engine turn overflowed; forcing context-engine compaction", {
@@ -3465,6 +3622,27 @@ async function runCodexAppServerAttempt(params, options = {}) {
3465
3622
  imagesCount: params.images?.length ?? 0
3466
3623
  });
3467
3624
  projector = new CodexAppServerEventProjector(params, thread.threadId, activeTurnId, { nativePostToolUseRelayEnabled: nativeHookRelay?.allowedEvents.includes("post_tool_use") === true });
3625
+ if (isTerminalTurnStatus(turn.turn.status) || pendingNotifications.some((notification) => isTerminalTurnNotificationForTurn(notification, activeTurnId))) terminalTurnNotificationQueued = true;
3626
+ closeCleanup = client.addCloseHandler?.(() => {
3627
+ if (completed || terminalTurnNotificationQueued || runAbortController.signal.aborted) return;
3628
+ clientClosedPromptError = "codex app-server client closed before turn completed";
3629
+ trajectoryRecorder?.recordEvent("turn.client_closed", {
3630
+ threadId: thread.threadId,
3631
+ turnId: activeTurnId
3632
+ });
3633
+ embeddedAgentLog.warn("codex app-server client closed before turn completed", {
3634
+ threadId: thread.threadId,
3635
+ turnId: activeTurnId
3636
+ });
3637
+ clientClosedAbort = true;
3638
+ runAbortController.abort("client_closed");
3639
+ completed = true;
3640
+ clearTurnAttemptIdleTimer();
3641
+ clearTurnCompletionIdleTimer();
3642
+ clearTurnAssistantCompletionIdleTimer();
3643
+ clearTurnTerminalIdleTimer();
3644
+ resolveCompletion?.();
3645
+ });
3468
3646
  emitLifecycleStart();
3469
3647
  const activeProjector = projector;
3470
3648
  turnTerminalIdleWatchArmed = true;
@@ -3495,11 +3673,9 @@ async function runCodexAppServerAttempt(params, options = {}) {
3495
3673
  abort: () => runAbortController.abort("aborted")
3496
3674
  };
3497
3675
  setActiveEmbeddedRun(params.sessionId, handle, params.sessionKey);
3498
- const timeout = setTimeout(() => {
3499
- timedOut = true;
3500
- projector?.markTimedOut();
3501
- runAbortController.abort("timeout");
3502
- }, Math.max(100, params.timeoutMs));
3676
+ turnAttemptIdleWatchArmed = true;
3677
+ turnTerminalIdleWatchArmed = true;
3678
+ touchTurnCompletionActivity("turn:start", { attemptProgress: true });
3503
3679
  const abortListener = () => {
3504
3680
  const shouldRetireClient = timedOut;
3505
3681
  interruptCodexTurnBestEffort(client, {
@@ -3519,8 +3695,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
3519
3695
  try {
3520
3696
  await completion;
3521
3697
  const result = activeProjector.buildResult(toolBridge.telemetry, { yieldDetected });
3522
- const finalAborted = result.aborted || runAbortController.signal.aborted;
3523
- let finalPromptError = turnCompletionIdleTimedOut ? turnCompletionIdleTimeoutMessage : timedOut ? "codex app-server attempt timed out" : result.promptError;
3698
+ const finalAborted = result.aborted || runAbortController.signal.aborted && !clientClosedAbort;
3699
+ let finalPromptError = clientClosedPromptError ?? (turnCompletionIdleTimedOut ? turnCompletionIdleTimeoutMessage : timedOut ? "codex app-server attempt timed out" : result.promptError);
3524
3700
  const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
3525
3701
  if (shouldRefreshCodexRateLimitsForUsageLimitMessage(finalPromptErrorMessage)) finalPromptError = await refreshCodexUsageLimitErrorMessage({
3526
3702
  client,
@@ -3532,7 +3708,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3532
3708
  timeoutMs: appServer.requestTimeoutMs,
3533
3709
  signal: runAbortController.signal
3534
3710
  });
3535
- const finalPromptErrorSource = timedOut ? "prompt" : result.promptErrorSource;
3711
+ const finalPromptErrorSource = timedOut || clientClosedPromptError ? "prompt" : result.promptErrorSource;
3536
3712
  recordCodexTrajectoryCompletion(trajectoryRecorder, {
3537
3713
  attempt: params,
3538
3714
  result,
@@ -3638,11 +3814,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
3638
3814
  error: "codex app-server run completed without lifecycle terminal event"
3639
3815
  });
3640
3816
  if (trajectoryRecorder && !trajectoryEndRecorded) trajectoryRecorder.recordEvent("session.ended", {
3641
- status: timedOut || runAbortController.signal.aborted ? "interrupted" : "cleanup",
3817
+ status: timedOut || runAbortController.signal.aborted && !clientClosedAbort ? "interrupted" : "cleanup",
3642
3818
  threadId: thread.threadId,
3643
3819
  turnId: activeTurnId,
3644
3820
  timedOut,
3645
- aborted: runAbortController.signal.aborted
3821
+ aborted: runAbortController.signal.aborted && !clientClosedAbort
3646
3822
  });
3647
3823
  await runAgentCleanupStep({
3648
3824
  runId: params.runId,
@@ -3655,12 +3831,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
3655
3831
  });
3656
3832
  if (!timedOut && !runAbortController.signal.aborted) await steeringQueue?.flushPending();
3657
3833
  userInputBridge?.cancelPending();
3658
- clearTimeout(timeout);
3834
+ clearTurnAttemptIdleTimer();
3659
3835
  clearTurnCompletionIdleTimer();
3660
3836
  clearTurnAssistantCompletionIdleTimer();
3661
3837
  clearTurnTerminalIdleTimer();
3662
3838
  notificationCleanup();
3663
3839
  requestCleanup();
3840
+ closeCleanup?.();
3664
3841
  nativeHookRelay?.unregister();
3665
3842
  runAbortController.signal.removeEventListener("abort", abortListener);
3666
3843
  params.abortSignal?.removeEventListener("abort", abortFromUpstream);
@@ -4217,6 +4394,10 @@ function isCompletedAssistantNotification(notification) {
4217
4394
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
4218
4395
  return Boolean(item && readString(item, "type") === "agentMessage" && readString(item, "phase") !== "commentary");
4219
4396
  }
4397
+ function isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff) {
4398
+ if (isCompletedAssistantNotification(notification)) return true;
4399
+ return !turnCrossedToolHandoff && isRawAssistantCompletionNotification(notification);
4400
+ }
4220
4401
  function shouldDisarmAssistantCompletionIdleWatch(notification) {
4221
4402
  if (!isJsonObject(notification.params)) return false;
4222
4403
  if (notification.method === "item/started") return true;
@@ -4241,6 +4422,23 @@ function isRawToolOutputCompletionNotification(notification) {
4241
4422
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
4242
4423
  return item ? readString(item, "type") === "custom_tool_call_output" : false;
4243
4424
  }
4425
+ function isNativeToolProgressNotification(notification) {
4426
+ if (notification.method !== "item/started" && notification.method !== "item/completed" && notification.method !== "item/updated") return false;
4427
+ if (!isJsonObject(notification.params)) return false;
4428
+ const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
4429
+ switch (item ? readString(item, "type") : void 0) {
4430
+ case "commandExecution":
4431
+ case "fileChange":
4432
+ case "mcpToolCall":
4433
+ case "webSearch": return true;
4434
+ default: return false;
4435
+ }
4436
+ }
4437
+ function isRawAssistantCompletionNotification(notification) {
4438
+ if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
4439
+ const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
4440
+ return Boolean(item && readString(item, "type") === "message" && readString(item, "role") === "assistant" && readString(item, "phase") !== "commentary" && readRawAssistantTextPreview(item));
4441
+ }
4244
4442
  function readRawAssistantTextPreview(item) {
4245
4443
  if (readString(item, "role") !== "assistant" || !Array.isArray(item.content)) return;
4246
4444
  const text = item.content.flatMap((content) => {
@@ -4255,6 +4453,19 @@ function isTurnNotification(value, threadId, turnId) {
4255
4453
  if (!isJsonObject(value)) return false;
4256
4454
  return readString(value, "threadId") === threadId && readNotificationTurnId(value) === turnId;
4257
4455
  }
4456
+ function isCurrentThreadTurnRequestParams(value, threadId, turnId) {
4457
+ if (!isJsonObject(value)) return false;
4458
+ return readString(value, "threadId") === threadId && readString(value, "turnId") === turnId;
4459
+ }
4460
+ function isCurrentApprovalTurnRequestParams(value, threadId, turnId) {
4461
+ if (!isJsonObject(value)) return false;
4462
+ return (readString(value, "threadId") ?? readString(value, "conversationId")) === threadId && readString(value, "turnId") === turnId;
4463
+ }
4464
+ function isCurrentThreadOptionalTurnRequestParams(value, threadId, turnId) {
4465
+ if (!isJsonObject(value) || readString(value, "threadId") !== threadId) return false;
4466
+ const requestTurnId = value.turnId;
4467
+ return requestTurnId === null || requestTurnId === void 0 || requestTurnId === turnId;
4468
+ }
4258
4469
  function isRetryableErrorNotification(value) {
4259
4470
  if (!isJsonObject(value)) return false;
4260
4471
  return readBoolean(value, "willRetry") === true || readBoolean(value, "will_retry") === true;
@@ -4522,7 +4733,7 @@ function codexExecutionToolName(item) {
4522
4733
  function joinPresentSections(...sections) {
4523
4734
  return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
4524
4735
  }
4525
- function prependCurrentTurnContext(prompt, context) {
4736
+ function prependCurrentInboundContext(prompt, context) {
4526
4737
  const text = context?.text.trim();
4527
4738
  return text ? [text, prompt].filter(Boolean).join("\n\n") : prompt;
4528
4739
  }