@openclaw/codex 2026.6.5-beta.1 → 2026.6.5-beta.3

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.
package/dist/harness.js CHANGED
@@ -32,14 +32,14 @@ function createCodexAppServerAgentHarness(options) {
32
32
  };
33
33
  },
34
34
  runAttempt: async (params) => {
35
- const { runCodexAppServerAttempt } = await import("./run-attempt-B_6VkFQN.js");
35
+ const { runCodexAppServerAttempt } = await import("./run-attempt-DOr_d98I.js");
36
36
  return runCodexAppServerAttempt(params, {
37
37
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
38
38
  nativeHookRelay: { enabled: true }
39
39
  });
40
40
  },
41
41
  runSideQuestion: async (params) => {
42
- const { runCodexAppServerSideQuestion } = await import("./side-question-BEpALo9c.js");
42
+ const { runCodexAppServerSideQuestion } = await import("./side-question-BnvBQPqW.js");
43
43
  return runCodexAppServerSideQuestion(params, {
44
44
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
45
45
  nativeHookRelay: { enabled: true }
@@ -992,23 +992,17 @@ function createCodexDynamicToolBridge(params) {
992
992
  const toolResultMaxChars = resolveCodexDynamicToolResultMaxChars(params.hookContext);
993
993
  const availableProjection = projectCodexDynamicTools(params.tools);
994
994
  const registeredProjection = params.registeredTools ? projectCodexDynamicTools(params.registeredTools) : availableProjection;
995
- const availableTools = availableProjection.tools.map(({ tool, inputSchema }) => {
996
- if (isToolWrappedWithBeforeToolCallHook(tool)) {
997
- setBeforeToolCallDiagnosticsEnabled(tool, false);
998
- return {
999
- tool,
1000
- inputSchema
1001
- };
1002
- }
1003
- return {
1004
- tool: wrapToolWithBeforeToolCallHook(tool, params.hookContext, { emitDiagnostics: false }),
1005
- inputSchema
1006
- };
1007
- });
1008
- const toolMap = new Map(availableTools.map(({ tool }) => [tool.name, tool]));
1009
- const registeredTools = registeredProjection.tools.map(({ tool }) => tool);
1010
- const registeredToolNames = new Set(registeredTools.map((tool) => tool.name));
1011
- const quarantinedTools = dedupeQuarantinedDynamicTools([...availableProjection.quarantinedTools, ...registeredProjection.quarantinedTools]);
995
+ const wrappedAvailableProjection = wrapProjectedCodexDynamicTools(availableProjection.tools, params.hookContext);
996
+ const availableTools = wrappedAvailableProjection.tools;
997
+ const quarantinedAvailableToolNames = new Set([...availableProjection.quarantinedTools, ...wrappedAvailableProjection.quarantinedTools].map((tool) => tool.tool));
998
+ const registeredSpecTools = (params.registeredTools ? registeredProjection.tools : availableTools).filter((entry) => !quarantinedAvailableToolNames.has(entry.name));
999
+ const toolMap = new Map(availableTools.map((entry) => [entry.name, entry]));
1000
+ const registeredToolNames = new Set(registeredSpecTools.map((entry) => entry.name));
1001
+ const quarantinedTools = dedupeQuarantinedDynamicTools([
1002
+ ...availableProjection.quarantinedTools,
1003
+ ...registeredProjection.quarantinedTools,
1004
+ ...wrappedAvailableProjection.quarantinedTools
1005
+ ]);
1012
1006
  warnQuarantinedDynamicTools(quarantinedTools);
1013
1007
  emitQuarantinedDynamicToolDiagnostics(quarantinedTools, params.hookContext);
1014
1008
  const telemetry = {
@@ -1028,22 +1022,20 @@ function createCodexDynamicToolBridge(params) {
1028
1022
  const legacyExtensionRunner = createCodexAppServerToolResultExtensionRunner(toolResultHookContext);
1029
1023
  const directToolNames = new Set([...ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES, ...params.directToolNames ?? []]);
1030
1024
  return {
1031
- availableSpecs: availableTools.map(({ tool, inputSchema }) => createCodexDynamicToolSpec({
1032
- tool,
1033
- inputSchema,
1025
+ availableSpecs: availableTools.map((entry) => createCodexDynamicToolSpec({
1026
+ entry,
1034
1027
  loading: params.loading ?? "searchable",
1035
1028
  directToolNames
1036
1029
  })),
1037
- specs: registeredProjection.tools.map(({ tool, inputSchema }) => createCodexDynamicToolSpec({
1038
- tool,
1039
- inputSchema,
1030
+ specs: registeredSpecTools.map((entry) => createCodexDynamicToolSpec({
1031
+ entry,
1040
1032
  loading: params.loading ?? "searchable",
1041
1033
  directToolNames
1042
1034
  })),
1043
1035
  telemetry,
1044
1036
  handleToolCall: async (call, options) => {
1045
- const tool = toolMap.get(call.tool);
1046
- if (!tool) {
1037
+ const toolEntry = toolMap.get(call.tool);
1038
+ if (!toolEntry) {
1047
1039
  if (registeredToolNames.has(call.tool)) return {
1048
1040
  contentItems: [{
1049
1041
  type: "inputText",
@@ -1059,6 +1051,7 @@ function createCodexDynamicToolBridge(params) {
1059
1051
  success: false
1060
1052
  };
1061
1053
  }
1054
+ const { tool, name: toolName } = toolEntry;
1062
1055
  const args = jsonObjectToRecord(call.arguments);
1063
1056
  const startedAt = Date.now();
1064
1057
  const signal = composeAbortSignals(params.signal, options?.signal);
@@ -1072,7 +1065,7 @@ function createCodexDynamicToolBridge(params) {
1072
1065
  threadId: call.threadId,
1073
1066
  turnId: call.turnId,
1074
1067
  toolCallId: call.callId,
1075
- toolName: tool.name,
1068
+ toolName,
1076
1069
  args,
1077
1070
  isError: rawIsError,
1078
1071
  result: rawResult
@@ -1081,13 +1074,13 @@ function createCodexDynamicToolBridge(params) {
1081
1074
  threadId: call.threadId,
1082
1075
  turnId: call.turnId,
1083
1076
  toolCallId: call.callId,
1084
- toolName: tool.name,
1077
+ toolName,
1085
1078
  args,
1086
1079
  result: middlewareResult
1087
1080
  });
1088
1081
  const resultIsError = rawIsError || isToolResultError(result);
1089
1082
  collectToolTelemetry({
1090
- toolName: tool.name,
1083
+ toolName,
1091
1084
  args,
1092
1085
  result,
1093
1086
  mediaTrustResult: rawResult,
@@ -1095,7 +1088,7 @@ function createCodexDynamicToolBridge(params) {
1095
1088
  isError: resultIsError
1096
1089
  });
1097
1090
  runAgentHarnessAfterToolCallHook({
1098
- toolName: tool.name,
1091
+ toolName,
1099
1092
  toolCallId: call.callId,
1100
1093
  runId: toolResultHookContext.runId,
1101
1094
  agentId: toolResultHookContext.agentId,
@@ -1116,14 +1109,14 @@ function createCodexDynamicToolBridge(params) {
1116
1109
  return withSideEffectEvidence(response, terminalType !== "blocked");
1117
1110
  } catch (error) {
1118
1111
  collectToolTelemetry({
1119
- toolName: tool.name,
1112
+ toolName,
1120
1113
  args,
1121
1114
  result: void 0,
1122
1115
  telemetry,
1123
1116
  isError: true
1124
1117
  });
1125
1118
  runAgentHarnessAfterToolCallHook({
1126
- toolName: tool.name,
1119
+ toolName,
1127
1120
  toolCallId: call.callId,
1128
1121
  runId: toolResultHookContext.runId,
1129
1122
  agentId: toolResultHookContext.agentId,
@@ -1145,13 +1138,37 @@ function createCodexDynamicToolBridge(params) {
1145
1138
  }
1146
1139
  };
1147
1140
  }
1141
+ function wrapProjectedCodexDynamicTools(tools, hookContext) {
1142
+ const wrappedTools = [];
1143
+ const quarantinedTools = [];
1144
+ for (const entry of tools) try {
1145
+ if (isToolWrappedWithBeforeToolCallHook(entry.tool)) {
1146
+ setBeforeToolCallDiagnosticsEnabled(entry.tool, false);
1147
+ wrappedTools.push(entry);
1148
+ continue;
1149
+ }
1150
+ wrappedTools.push({
1151
+ ...entry,
1152
+ tool: wrapToolWithBeforeToolCallHook(entry.tool, hookContext, { emitDiagnostics: false })
1153
+ });
1154
+ } catch {
1155
+ quarantinedTools.push({
1156
+ tool: entry.name,
1157
+ violations: [`${entry.name} could not be wrapped for before-tool-call hooks`]
1158
+ });
1159
+ }
1160
+ return {
1161
+ tools: wrappedTools,
1162
+ quarantinedTools
1163
+ };
1164
+ }
1148
1165
  function createCodexDynamicToolSpec(params) {
1149
1166
  const base = {
1150
- name: params.tool.name,
1151
- description: params.tool.description,
1152
- inputSchema: params.inputSchema
1167
+ name: params.entry.name,
1168
+ description: params.entry.description,
1169
+ inputSchema: params.entry.inputSchema
1153
1170
  };
1154
- if (params.loading === "direct" || params.directToolNames.has(params.tool.name)) return base;
1171
+ if (params.loading === "direct" || params.directToolNames.has(params.entry.name)) return base;
1155
1172
  return {
1156
1173
  ...base,
1157
1174
  namespace: CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE,
@@ -1161,17 +1178,46 @@ function createCodexDynamicToolSpec(params) {
1161
1178
  function projectCodexDynamicTools(tools) {
1162
1179
  const projectedTools = [];
1163
1180
  const quarantinedTools = [];
1164
- for (const tool of tools) {
1165
- const projection = projectRuntimeToolInputSchema(tool.parameters, `${tool.name}.inputSchema`);
1181
+ let length;
1182
+ try {
1183
+ length = tools.length;
1184
+ } catch {
1185
+ return {
1186
+ tools: [],
1187
+ quarantinedTools: [{
1188
+ tool: "tool[0]",
1189
+ violations: ["tool[0] is unreadable"]
1190
+ }]
1191
+ };
1192
+ }
1193
+ for (let toolIndex = 0; toolIndex < length; toolIndex += 1) {
1194
+ let tool;
1195
+ try {
1196
+ tool = tools[toolIndex];
1197
+ } catch {
1198
+ quarantinedTools.push({
1199
+ tool: `tool[${toolIndex}]`,
1200
+ violations: [`tool[${toolIndex}] is unreadable`]
1201
+ });
1202
+ continue;
1203
+ }
1204
+ const descriptor = readCodexDynamicToolDescriptor(tool, toolIndex);
1205
+ if (!descriptor.ok) {
1206
+ quarantinedTools.push(descriptor.diagnostic);
1207
+ continue;
1208
+ }
1209
+ const projection = projectRuntimeToolInputSchema(descriptor.parameters, `${descriptor.name}.inputSchema`);
1166
1210
  if (projection.violations.length > 0) {
1167
1211
  quarantinedTools.push({
1168
- tool: tool.name,
1212
+ tool: descriptor.name,
1169
1213
  violations: projection.violations
1170
1214
  });
1171
1215
  continue;
1172
1216
  }
1173
1217
  projectedTools.push({
1174
1218
  tool,
1219
+ name: descriptor.name,
1220
+ description: descriptor.description,
1175
1221
  inputSchema: projection.schema
1176
1222
  });
1177
1223
  }
@@ -1180,6 +1226,59 @@ function projectCodexDynamicTools(tools) {
1180
1226
  quarantinedTools
1181
1227
  };
1182
1228
  }
1229
+ function readCodexDynamicToolDescriptor(tool, toolIndex) {
1230
+ const fallbackName = `tool[${toolIndex}]`;
1231
+ let name;
1232
+ try {
1233
+ const rawName = tool.name;
1234
+ if (typeof rawName !== "string" || !rawName) return {
1235
+ ok: false,
1236
+ diagnostic: {
1237
+ tool: fallbackName,
1238
+ violations: [`${fallbackName}.name must be a non-empty string`]
1239
+ }
1240
+ };
1241
+ name = rawName;
1242
+ } catch {
1243
+ return {
1244
+ ok: false,
1245
+ diagnostic: {
1246
+ tool: fallbackName,
1247
+ violations: [`${fallbackName}.name is unreadable`]
1248
+ }
1249
+ };
1250
+ }
1251
+ let description;
1252
+ try {
1253
+ description = typeof tool.description === "string" ? tool.description : "";
1254
+ } catch {
1255
+ return {
1256
+ ok: false,
1257
+ diagnostic: {
1258
+ tool: name,
1259
+ violations: [`${name}.description is unreadable`]
1260
+ }
1261
+ };
1262
+ }
1263
+ let parameters;
1264
+ try {
1265
+ parameters = tool.parameters;
1266
+ } catch {
1267
+ return {
1268
+ ok: false,
1269
+ diagnostic: {
1270
+ tool: name,
1271
+ violations: [`${name}.inputSchema is unreadable`]
1272
+ }
1273
+ };
1274
+ }
1275
+ return {
1276
+ ok: true,
1277
+ name,
1278
+ description,
1279
+ parameters
1280
+ };
1281
+ }
1183
1282
  function warnQuarantinedDynamicTools(tools) {
1184
1283
  if (tools.length === 0) return;
1185
1284
  const unique = /* @__PURE__ */ new Map();
@@ -8,7 +8,7 @@ import { _ as shouldRefreshCodexRateLimitsForUsageLimitMessage, g as resolveCode
8
8
  import { d as resolveCodexAppServerAuthAccountCacheKey, f as resolveCodexAppServerAuthProfileId, h as resolveCodexAppServerHomeDir, m as resolveCodexAppServerFallbackApiKeyCacheKey, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as releaseLeasedSharedCodexAppServerClient, p as resolveCodexAppServerAuthProfileIdForAgent, s as retireSharedCodexAppServerClientIfCurrent, t as clearSharedCodexAppServerClientIfCurrent, u as refreshCodexAppServerAuthTokens } from "./shared-client-xytpSKD0.js";
9
9
  import { i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-C-Yv9uwY.js";
10
10
  import { t as defaultLeasedCodexAppServerClientFactory } from "./client-factory-Bt49r45B.js";
11
- import { S as withCodexStartupTimeout, _ as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, a as createCodexNativeHookRelay, b as resolveCodexTurnCompletionIdleTimeoutMs, c as scheduleCodexNativeHookRelayUnregister, d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, g as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, h as handleCodexAppServerApprovalRequest, 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 resolveCodexStartupTimeoutMs, x as resolveCodexTurnTerminalIdleTimeoutMs, y as resolveCodexTurnAssistantCompletionIdleTimeoutMs } from "./native-hook-relay-DZ3Oon0b.js";
11
+ import { S as withCodexStartupTimeout, _ as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, a as createCodexNativeHookRelay, b as resolveCodexTurnCompletionIdleTimeoutMs, c as scheduleCodexNativeHookRelayUnregister, d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, g as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, h as handleCodexAppServerApprovalRequest, 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 resolveCodexStartupTimeoutMs, x as resolveCodexTurnTerminalIdleTimeoutMs, y as resolveCodexTurnAssistantCompletionIdleTimeoutMs } from "./native-hook-relay-DHwz_ICg.js";
12
12
  import { t as ensureCodexComputerUse } from "./computer-use-ClweWaMz.js";
13
13
  import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-C7qmZ0Jh.js";
14
14
  import { asDateTimestampMs, parseStrictNonNegativeInteger, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
@@ -25,6 +25,7 @@ import fs from "node:fs/promises";
25
25
  import path, { posix } from "node:path";
26
26
  import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, hasPendingInternalDiagnosticEvent, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
27
27
  import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
28
+ import { loadSessionStore } from "openclaw/plugin-sdk/session-store-runtime";
28
29
  import { isToolAllowed } from "openclaw/plugin-sdk/sandbox";
29
30
  import { appendRegularFile, pathExists } from "openclaw/plugin-sdk/security-runtime";
30
31
  import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "openclaw/plugin-sdk/agent-sessions";
@@ -893,6 +894,10 @@ function isRawReasoningCompletionNotification(notification) {
893
894
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
894
895
  return item ? readString$6(item, "type") === "reasoning" : false;
895
896
  }
897
+ /** Returns true for streamed app-server reasoning progress. */
898
+ function isReasoningProgressNotification(notification) {
899
+ return notification.method === "item/reasoning/textDelta" || notification.method === "item/reasoning/summaryTextDelta" || notification.method === "item/reasoning/summaryPartAdded";
900
+ }
896
901
  /** Returns true when assistant completion can release the short idle watch. */
897
902
  function isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff) {
898
903
  if (isCompletedAssistantNotification(notification)) return true;
@@ -1116,13 +1121,13 @@ function applyCodexTurnNotificationState(params) {
1116
1121
  const rawToolOutputCompletion = isRawToolOutputCompletionNotification(notification);
1117
1122
  if (isCurrentTurnNotification && (rawToolOutputCompletion || isNativeToolProgressNotification(notification))) turnCrossedToolHandoff = true;
1118
1123
  const assistantCompletionCanRelease = isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff);
1119
- const postToolRawAssistantCompletionNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && isRawAssistantProgressNotification(notification) && params.activeTurnItemIds.size === 0;
1124
+ const postToolProgressNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && ((isRawAssistantProgressNotification(notification) || isRawReasoningCompletionNotification(notification)) && params.activeTurnItemIds.size === 0 || isReasoningProgressNotification(notification));
1120
1125
  const postToolPatchUpdateNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && isFileChangePatchUpdatedNotification(notification);
1121
- const rawResponseItemCompletedWithNoActiveItems = isCurrentTurnNotification && notification.method === "rawResponseItem/completed" && params.activeTurnItemIds.size === 0 && params.activeAppServerTurnRequests === 0 && !assistantCompletionCanRelease && !postToolRawAssistantCompletionNeedsTerminalGuard && !rawToolOutputCompletion;
1126
+ const rawResponseItemCompletedWithNoActiveItems = isCurrentTurnNotification && notification.method === "rawResponseItem/completed" && params.activeTurnItemIds.size === 0 && params.activeAppServerTurnRequests === 0 && !assistantCompletionCanRelease && !postToolProgressNeedsTerminalGuard && !rawToolOutputCompletion;
1122
1127
  const shouldArmNoToolPostProgressReplyWatch = isCurrentTurnNotification && !turnCrossedToolHandoff && params.activeTurnItemIds.size === 0 && (isReasoningItemCompletionNotification(notification) || isAssistantCommentaryCompletionNotification(notification));
1123
1128
  const shouldArmNoToolPostRawProgressReplyWatch = !turnCrossedToolHandoff && rawResponseItemCompletedWithNoActiveItems && (isRawReasoningCompletionNotification(notification) || isRawAssistantProgressNotification(notification));
1124
1129
  const shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem = isCurrentTurnNotification && notification.method === "item/completed" && params.activeTurnItemIds.size === 0 && !trackedDynamicToolCompletion && !assistantCompletionCanRelease && !shouldArmNoToolPostProgressReplyWatch;
1125
- const shouldUsePostToolContinuationWatch = turnCrossedToolHandoff && (postToolRawAssistantCompletionNeedsTerminalGuard || postToolPatchUpdateNeedsTerminalGuard || rawToolOutputCompletion || trackedDynamicToolCompletion || shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem);
1130
+ const shouldUsePostToolContinuationWatch = turnCrossedToolHandoff && (postToolProgressNeedsTerminalGuard || postToolPatchUpdateNeedsTerminalGuard || rawToolOutputCompletion || trackedDynamicToolCompletion || shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem);
1126
1131
  const armPostToolContinuationWatch = () => {
1127
1132
  turnWatches.armCompletionIdleWatch({ timeoutMs: params.postToolRawAssistantCompletionIdleTimeoutMs });
1128
1133
  turnWatches.extendAttemptIdleWatch(params.postToolRawAssistantCompletionIdleTimeoutMs);
@@ -1137,7 +1142,7 @@ function applyCodexTurnNotificationState(params) {
1137
1142
  turnWatches.disarmAssistantCompletionIdleWatch();
1138
1143
  } else if (isTurnCompletion) turnWatches.disarmAssistantCompletionIdleWatch();
1139
1144
  else if (isCurrentTurnNotification && assistantCompletionCanRelease) turnWatches.armAssistantCompletionIdleWatch(describeNotificationActivity(notification));
1140
- else if (postToolRawAssistantCompletionNeedsTerminalGuard || postToolPatchUpdateNeedsTerminalGuard) armPostToolContinuationWatch();
1145
+ else if (postToolProgressNeedsTerminalGuard || postToolPatchUpdateNeedsTerminalGuard) armPostToolContinuationWatch();
1141
1146
  else if (shouldArmNoToolPostProgressReplyWatch || shouldArmNoToolPostRawProgressReplyWatch) armPostProgressReplyWatch();
1142
1147
  else if (trackedDynamicToolCompletion) armPostToolContinuationWatch();
1143
1148
  else if (unblockedAssistantCompletionRelease) turnWatches.armAssistantCompletionIdleWatch(describeNotificationActivity(notification));
@@ -1146,7 +1151,7 @@ function applyCodexTurnNotificationState(params) {
1146
1151
  else if (rawResponseItemCompletedWithNoActiveItems) turnWatches.armCompletionIdleWatch();
1147
1152
  else if (isCurrentTurnNotification && rawToolOutputCompletion) armPostToolContinuationWatch();
1148
1153
  else if (isCurrentTurnNotification && shouldDisarmAssistantCompletionIdleWatch(notification)) turnWatches.disarmAssistantCompletionIdleWatch();
1149
- if (turnWatches.isCompletionIdleWatchArmed() && !turnWatches.isCompletionIdleWatchPinnedByTerminalError() && notification.method !== "turn/completed" && isCurrentTurnNotification && !isNativeResponseStreamDelta && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !postToolRawAssistantCompletionNeedsTerminalGuard && !postToolPatchUpdateNeedsTerminalGuard && !rawResponseItemCompletedWithNoActiveItems && !shouldArmNoToolPostProgressReplyWatch && !shouldArmNoToolPostRawProgressReplyWatch && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) turnWatches.disarmCompletionIdleWatch();
1154
+ if (turnWatches.isCompletionIdleWatchArmed() && !turnWatches.isCompletionIdleWatchPinnedByTerminalError() && notification.method !== "turn/completed" && isCurrentTurnNotification && !isNativeResponseStreamDelta && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !postToolProgressNeedsTerminalGuard && !postToolPatchUpdateNeedsTerminalGuard && !rawResponseItemCompletedWithNoActiveItems && !shouldArmNoToolPostProgressReplyWatch && !shouldArmNoToolPostRawProgressReplyWatch && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) turnWatches.disarmCompletionIdleWatch();
1150
1155
  if (trackedDynamicToolCompletion) {
1151
1156
  const itemId = readNotificationItemId(notification);
1152
1157
  if (itemId) {
@@ -1174,21 +1179,17 @@ const CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_SIDE_EFFECT_USER_MESSAGE = "Codex
1174
1179
  function collectTerminalAssistantText(result) {
1175
1180
  return result.assistantTexts.join("\n\n").trim();
1176
1181
  }
1177
- /** Returns whether attempt metadata saw potential side effects. */
1178
- function hasCodexAppServerPotentialSideEffectEvidence(result) {
1179
- return result.replayMetadata.hadPotentialSideEffects;
1180
- }
1181
1182
  /**
1182
1183
  * Builds the user-facing timeout outcome when Codex stops without a terminal
1183
1184
  * turn event.
1184
1185
  */
1185
1186
  function buildCodexAppServerPromptTimeoutOutcome(params) {
1186
- const completionIdleTimeoutHadPotentialSideEffects = hasCodexAppServerPotentialSideEffectEvidence(params.result);
1187
+ if (!params.turnCompletionIdleTimedOut) return;
1188
+ if (params.turnWatchTimeoutKind !== void 0 && params.turnWatchTimeoutKind !== "completion") return;
1187
1189
  const replayBlockedReason = resolveCodexAppServerReplayBlockedReason(params.result);
1188
- if (!params.turnCompletionIdleTimedOut || params.result.itemLifecycle.completedCount === 0 && !completionIdleTimeoutHadPotentialSideEffects && replayBlockedReason === void 0) return;
1189
1190
  return {
1190
- message: completionIdleTimeoutHadPotentialSideEffects ? CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_SIDE_EFFECT_USER_MESSAGE : CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_USER_MESSAGE,
1191
- ...completionIdleTimeoutHadPotentialSideEffects ? {
1191
+ message: replayBlockedReason === "tool_activity" || replayBlockedReason === "potential_side_effect" || replayBlockedReason === "active_item" ? CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_SIDE_EFFECT_USER_MESSAGE : CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_USER_MESSAGE,
1192
+ ...replayBlockedReason ? {
1192
1193
  replayInvalid: true,
1193
1194
  livenessState: "abandoned"
1194
1195
  } : {}
@@ -3484,12 +3485,21 @@ function createCodexAttemptTurnWatchController(params) {
3484
3485
  scheduleCompletionIdleWatch();
3485
3486
  return;
3486
3487
  }
3488
+ const details = {
3489
+ ...completionLastActivityDetails,
3490
+ activeAppServerTurnRequests: params.getActiveAppServerTurnRequests(),
3491
+ activeTurnItemCount: params.getActiveTurnItemCount(),
3492
+ terminalTurnNotificationQueued: params.isTerminalTurnNotificationQueued(),
3493
+ completionIdleWatchArmed,
3494
+ assistantCompletionIdleWatchArmed,
3495
+ terminalIdleWatchArmed
3496
+ };
3487
3497
  const timeout = {
3488
3498
  kind: "completion",
3489
3499
  idleMs,
3490
3500
  timeoutMs,
3491
3501
  lastActivityReason: completionLastActivityReason,
3492
- details: completionLastActivityDetails
3502
+ details
3493
3503
  };
3494
3504
  params.onTimeout(timeout);
3495
3505
  params.onMarkTimedOut();
@@ -4228,6 +4238,7 @@ var CodexAppServerEventProjector = class {
4228
4238
  this.toolTrajectoryCallIds = /* @__PURE__ */ new Set();
4229
4239
  this.toolTrajectoryResultIds = /* @__PURE__ */ new Set();
4230
4240
  this.toolTrajectoryNamesById = /* @__PURE__ */ new Map();
4241
+ this.toolTrajectoryItemsById = /* @__PURE__ */ new Map();
4231
4242
  this.transcriptToolProgressCallIds = /* @__PURE__ */ new Set();
4232
4243
  this.nativeGeneratedMediaUrls = /* @__PURE__ */ new Set();
4233
4244
  this.nativeGeneratedMediaItemIds = /* @__PURE__ */ new Set();
@@ -4246,6 +4257,10 @@ var CodexAppServerEventProjector = class {
4246
4257
  getCompletedTurnStatus() {
4247
4258
  return this.completedTurn?.status;
4248
4259
  }
4260
+ hasCompletedTerminalAssistantText() {
4261
+ const finalItem = this.resolveFinalAssistantTextItem();
4262
+ return finalItem !== void 0 && this.completedItemIds.has(finalItem.itemId);
4263
+ }
4249
4264
  async handleNotification(notification) {
4250
4265
  const params = isJsonObject(notification.params) ? notification.params : void 0;
4251
4266
  if (!params) return;
@@ -4312,7 +4327,13 @@ var CodexAppServerEventProjector = class {
4312
4327
  const assistantTexts = this.collectAssistantTexts();
4313
4328
  const reasoningText = collectReasoningTextValues(this.reasoningTextByGroup, this.reasoningItemOrder).join("\n\n");
4314
4329
  const planText = collectTextValues(this.planTextByItem).join("\n\n");
4315
- this.synthesizeMissingToolResults({ failClosed: !this.completedTurn || this.completedTurn.status !== "completed" || assistantTexts.length > 0 });
4330
+ const hasAssistantItemText = this.hasAssistantItemTextForSynthesis();
4331
+ const legacyFailClosed = !this.completedTurn || this.completedTurn.status !== "completed" || hasAssistantItemText;
4332
+ const hasDeliverableAssistantOnCompletedTurn = this.completedTurn?.status === "completed" && assistantTexts.some((text) => text.trim().length > 0);
4333
+ this.synthesizeMissingToolResults({
4334
+ synthesize: legacyFailClosed,
4335
+ recordPromptError: legacyFailClosed && !hasDeliverableAssistantOnCompletedTurn
4336
+ });
4316
4337
  const lastAssistant = assistantTexts.length > 0 ? this.createAssistantMessage(assistantTexts.join("\n\n")) : void 0;
4317
4338
  const turnId = this.turnId;
4318
4339
  const messagesSnapshot = this.params.suppressNextUserMessagePersistence ? [] : [attachCodexMirrorIdentity(buildCodexUserPromptMessage(this.params), `${turnId}:prompt`)];
@@ -4974,6 +4995,7 @@ var CodexAppServerEventProjector = class {
4974
4995
  if (params.phase === "start") {
4975
4996
  this.toolTrajectoryCallIds.add(params.item.id);
4976
4997
  this.toolTrajectoryNamesById.set(params.item.id, params.name);
4998
+ this.toolTrajectoryItemsById.set(params.item.id, params.item);
4977
4999
  this.options.trajectoryRecorder?.recordEvent("tool.call", {
4978
5000
  threadId: this.threadId,
4979
5001
  turnId: this.turnId,
@@ -5169,7 +5191,7 @@ var CodexAppServerEventProjector = class {
5169
5191
  this.toolTranscriptMessages.push(attachCodexMirrorIdentity(this.createToolResultMessage(params), `${this.turnId}:tool:${params.id}:result`));
5170
5192
  }
5171
5193
  synthesizeMissingToolResults(params) {
5172
- if (!params.failClosed) return;
5194
+ if (!params.synthesize) return;
5173
5195
  const missingTranscriptIds = [...this.toolTranscriptCallIds].filter((id) => !this.toolTranscriptResultIds.has(id));
5174
5196
  const missingTrajectoryIds = [...this.toolTrajectoryCallIds].filter((id) => !this.toolTrajectoryResultIds.has(id));
5175
5197
  if (missingTranscriptIds.length === 0 && missingTrajectoryIds.length === 0) return;
@@ -5209,6 +5231,34 @@ var CodexAppServerEventProjector = class {
5209
5231
  output: text
5210
5232
  });
5211
5233
  }
5234
+ if (!params.recordPromptError) {
5235
+ const firstMissingId = missingTranscriptIds.find((id) => {
5236
+ const name = this.toolTranscriptNamesById.get(id) ?? this.toolTrajectoryNamesById.get(id);
5237
+ return Boolean(name);
5238
+ }) ?? missingTrajectoryIds.find((id) => {
5239
+ const name = this.toolTrajectoryNamesById.get(id) ?? this.toolTranscriptNamesById.get(id);
5240
+ return Boolean(name);
5241
+ });
5242
+ if (firstMissingId) {
5243
+ const name = this.toolTranscriptNamesById.get(firstMissingId) ?? this.toolTrajectoryNamesById.get(firstMissingId);
5244
+ if (name) {
5245
+ const item = this.toolTrajectoryItemsById.get(firstMissingId);
5246
+ const meta = item ? itemMeta(item, this.toolProgressDetailMode()) : this.toolMetas.get(firstMissingId)?.meta;
5247
+ const actionFingerprint = item ? nativeToolActionFingerprint(item) : void 0;
5248
+ this.lastNativeToolError = {
5249
+ toolName: name,
5250
+ ...meta ? { meta } : {},
5251
+ error: formatMissingToolResultError({
5252
+ id: firstMissingId,
5253
+ name
5254
+ }),
5255
+ ...item && isMutatingNativeToolItem(item) ? { mutatingAction: true } : {},
5256
+ ...actionFingerprint ? { actionFingerprint } : {}
5257
+ };
5258
+ }
5259
+ }
5260
+ return;
5261
+ }
5212
5262
  const missingCount = new Set([...missingTranscriptIds, ...missingTrajectoryIds]).size;
5213
5263
  this.synthesizedMissingToolResultError = missingCount === 1 ? MISSING_TOOL_RESULT_ERROR : `${MISSING_TOOL_RESULT_ERROR} missingToolResultCount=${missingCount}`;
5214
5264
  this.promptErrorSource = this.promptErrorSource ?? "prompt";
@@ -5274,13 +5324,29 @@ var CodexAppServerEventProjector = class {
5274
5324
  const finalText = this.resolveFinalAssistantText();
5275
5325
  return finalText ? [finalText] : [];
5276
5326
  }
5327
+ hasAssistantItemTextForSynthesis() {
5328
+ for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
5329
+ const itemId = this.assistantItemOrder[i];
5330
+ if (!itemId) continue;
5331
+ if (this.assistantPhaseByItem.get(itemId) === "commentary") continue;
5332
+ const text = this.assistantTextByItem.get(itemId);
5333
+ if (text && text.length > 0) return true;
5334
+ }
5335
+ return false;
5336
+ }
5277
5337
  resolveFinalAssistantText() {
5338
+ return this.resolveFinalAssistantTextItem()?.text;
5339
+ }
5340
+ resolveFinalAssistantTextItem() {
5278
5341
  for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
5279
5342
  const itemId = this.assistantItemOrder[i];
5280
5343
  if (!itemId) continue;
5281
5344
  const text = this.assistantTextByItem.get(itemId)?.trim();
5282
5345
  if (this.assistantPhaseByItem.get(itemId) === "commentary") continue;
5283
- if (text && !this.toolProgressTexts.has(text)) return text;
5346
+ if (text && !this.toolProgressTexts.has(text)) return {
5347
+ itemId,
5348
+ text
5349
+ };
5284
5350
  }
5285
5351
  }
5286
5352
  rememberAssistantItem(itemId) {
@@ -5849,10 +5915,11 @@ function readCompletionStatus(status) {
5849
5915
  for (const [rawKey, value] of Object.entries(status)) {
5850
5916
  const mappedStatus = mapCompletionStatus(normalizeStatusKey(rawKey));
5851
5917
  if (!mappedStatus) continue;
5918
+ const result = stringifyResult(value, mappedStatus);
5852
5919
  return {
5853
5920
  status: mappedStatus,
5854
- label: rawKey,
5855
- result: stringifyResult(value)
5921
+ label: mappedStatus === "succeeded" && result.kind === "no_final_assistant_message" ? "completed_without_final_message" : rawKey,
5922
+ result: result.text
5856
5923
  };
5857
5924
  }
5858
5925
  }
@@ -5861,15 +5928,25 @@ function mapCompletionStatus(value) {
5861
5928
  if (value === "cancelled" || value === "canceled" || value === "interrupted" || value === "shutdown") return "cancelled";
5862
5929
  if (value === "failed" || value === "error" || value === "errored" || value === "systemerror" || value === "notfound") return "failed";
5863
5930
  }
5864
- function stringifyResult(value) {
5865
- if (typeof value === "string") return value.trim() || "(no output)";
5866
- if (value === null || value === void 0) return "(no output)";
5931
+ function stringifyResult(value, status) {
5932
+ if (typeof value === "string") {
5933
+ const text = value.trim();
5934
+ if (text) return { text };
5935
+ return status === "succeeded" ? completedWithoutFinalAssistantMessage() : { text: "(no output)" };
5936
+ }
5937
+ if (value === null || value === void 0) return status === "succeeded" ? completedWithoutFinalAssistantMessage() : { text: "(no output)" };
5867
5938
  try {
5868
- return JSON.stringify(value);
5939
+ return { text: JSON.stringify(value) };
5869
5940
  } catch {
5870
- return "(unserializable output)";
5941
+ return { text: "(unserializable output)" };
5871
5942
  }
5872
5943
  }
5944
+ function completedWithoutFinalAssistantMessage() {
5945
+ return {
5946
+ text: "Codex native subagent completed without a final assistant message.",
5947
+ kind: "no_final_assistant_message"
5948
+ };
5949
+ }
5873
5950
  function readTrustedInterAgentCommunicationContent(item) {
5874
5951
  const communication = readTrustedInterAgentCommunication(item);
5875
5952
  return typeof communication?.content === "string" ? communication.content : void 0;
@@ -6400,6 +6477,14 @@ var CodexNativeSubagentMonitor = class {
6400
6477
  continue;
6401
6478
  }
6402
6479
  const completion = toThreadCompletion(nativeCompletion, childState.childThreadId);
6480
+ if (shouldWaitForTranscriptCompletion(completion, this.codexHome)) {
6481
+ const eventAt = Date.now();
6482
+ if (!await this.reconcileChildTranscript(childState.childThreadId)) {
6483
+ this.scheduleTranscriptPoll(childState);
6484
+ this.scheduleNoFinalCompletionFallback(state, childState, completion, eventAt);
6485
+ }
6486
+ continue;
6487
+ }
6403
6488
  await this.processCompletion(state, completion);
6404
6489
  }
6405
6490
  }
@@ -6433,6 +6518,10 @@ var CodexNativeSubagentMonitor = class {
6433
6518
  clearTimeout(childState.transcriptPollTimer);
6434
6519
  childState.transcriptPollTimer = void 0;
6435
6520
  }
6521
+ if (childState.noFinalCompletionFallbackTimer) {
6522
+ clearTimeout(childState.noFinalCompletionFallbackTimer);
6523
+ childState.noFinalCompletionFallbackTimer = void 0;
6524
+ }
6436
6525
  }
6437
6526
  if (!state.requesterSessionKey) return;
6438
6527
  const completionKey = buildCompletionDedupeKey(state.parentThreadId, completion);
@@ -6586,6 +6675,24 @@ var CodexNativeSubagentMonitor = class {
6586
6675
  }, delayMs);
6587
6676
  unrefTimer(childState.transcriptPollTimer);
6588
6677
  }
6678
+ scheduleNoFinalCompletionFallback(state, childState, completion, eventAt) {
6679
+ if (childState.transcriptTerminal || childState.noFinalCompletionFallbackTimer) return;
6680
+ const delayMs = noFinalCompletionFallbackDelayMs(this.transcriptPollDelaysMs);
6681
+ childState.noFinalCompletionFallbackTimer = setTimeout(() => {
6682
+ childState.noFinalCompletionFallbackTimer = void 0;
6683
+ this.deliverNoFinalCompletionFallback(state, childState, completion, eventAt);
6684
+ }, delayMs);
6685
+ unrefTimer(childState.noFinalCompletionFallbackTimer);
6686
+ }
6687
+ async deliverNoFinalCompletionFallback(state, childState, completion, eventAt) {
6688
+ if (!await this.reconcileChildTranscript(childState.childThreadId).catch((error) => {
6689
+ embeddedAgentLog.warn("Failed to reconcile Codex native subagent transcript", {
6690
+ childThreadId: childState.childThreadId,
6691
+ error: formatErrorMessage(error)
6692
+ });
6693
+ return false;
6694
+ }) && !childState.transcriptTerminal) await this.processCompletion(state, completion, eventAt);
6695
+ }
6589
6696
  clearTimers() {
6590
6697
  if (this.taskRowReconcileTimer) {
6591
6698
  clearInterval(this.taskRowReconcileTimer);
@@ -6600,6 +6707,10 @@ var CodexNativeSubagentMonitor = class {
6600
6707
  clearTimeout(childState.completionDeliveryTimer);
6601
6708
  childState.completionDeliveryTimer = void 0;
6602
6709
  }
6710
+ if (childState.noFinalCompletionFallbackTimer) {
6711
+ clearTimeout(childState.noFinalCompletionFallbackTimer);
6712
+ childState.noFinalCompletionFallbackTimer = void 0;
6713
+ }
6603
6714
  }
6604
6715
  }
6605
6716
  startTaskRowReconciler(intervalMs) {
@@ -6733,6 +6844,14 @@ function toThreadCompletion(completion, childThreadId) {
6733
6844
  result: completion.result
6734
6845
  };
6735
6846
  }
6847
+ function shouldWaitForTranscriptCompletion(completion, codexHome) {
6848
+ return Boolean(codexHome && completion.status === "succeeded" && completion.statusLabel === "completed_without_final_message");
6849
+ }
6850
+ function noFinalCompletionFallbackDelayMs(delays) {
6851
+ const first = delays[0] ?? 0;
6852
+ const second = delays[1] ?? 0;
6853
+ return Math.max(1, first + second);
6854
+ }
6736
6855
  function readSpawnParentThreadId(thread) {
6737
6856
  const source = isJsonObject(thread?.source) ? thread.source : void 0;
6738
6857
  const subAgent = isJsonObject(source?.subAgent) ? source.subAgent : void 0;
@@ -6841,15 +6960,17 @@ async function readTranscriptCompletion(transcriptPath, childThreadId) {
6841
6960
  }
6842
6961
  if (readString$2(entry, "type") !== "event_msg") continue;
6843
6962
  const payloadType = readString$2(payload, "type");
6844
- if (payloadType === "task_complete") completion = {
6845
- childThreadId,
6846
- parentThreadId,
6847
- status: "succeeded",
6848
- statusLabel: "task_complete",
6849
- result: readString$2(payload, "last_agent_message")?.trim() || readString$2(payload, "message")?.trim() || "(no output)",
6850
- completedAt: secondsToMillis(readNumber(payload, "completed_at")) ?? readTimestamp(entry)
6851
- };
6852
- else if (payloadType === "task_failed") {
6963
+ if (payloadType === "task_complete") {
6964
+ const result = readString$2(payload, "last_agent_message")?.trim() || readString$2(payload, "message")?.trim();
6965
+ completion = {
6966
+ childThreadId,
6967
+ parentThreadId,
6968
+ status: "succeeded",
6969
+ statusLabel: result ? "task_complete" : "completed_without_final_message",
6970
+ result: result ?? "Codex native subagent completed without a final assistant message.",
6971
+ completedAt: secondsToMillis(readNumber(payload, "completed_at")) ?? readTimestamp(entry)
6972
+ };
6973
+ } else if (payloadType === "task_failed") {
6853
6974
  const result = readString$2(payload, "last_agent_message")?.trim() || readString$2(payload, "error")?.trim() || readString$2(payload, "message")?.trim() || "Codex native subagent failed.";
6854
6975
  completion = {
6855
6976
  childThreadId,
@@ -6904,7 +7025,6 @@ const CODEX_APP_SERVER_BYTE_UNITS = {
6904
7025
  tb: 1024 * 1024 * 1024 * 1024,
6905
7026
  tib: 1024 * 1024 * 1024 * 1024
6906
7027
  };
6907
- const codexSessionRecordCache = /* @__PURE__ */ new Map();
6908
7028
  function parseCodexAppServerByteLimit(value) {
6909
7029
  if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.floor(value);
6910
7030
  if (typeof value !== "string") return;
@@ -6959,45 +7079,22 @@ async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codex
6959
7079
  return files;
6960
7080
  }
6961
7081
  async function readCodexSessionRecordForSessionFile(sessionFile) {
6962
- const sessionsFile = path.join(path.dirname(sessionFile), "sessions.json");
7082
+ const storePath = path.join(path.dirname(sessionFile), "sessions.json");
6963
7083
  const resolvedSessionFile = path.resolve(sessionFile);
6964
- let stat;
6965
- try {
6966
- stat = await fs.stat(sessionsFile);
6967
- } catch {
6968
- codexSessionRecordCache.delete(resolvedSessionFile);
6969
- return;
6970
- }
6971
- const cached = codexSessionRecordCache.get(resolvedSessionFile);
6972
- if (cached?.sessionsFile === sessionsFile && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) return cached.record;
6973
7084
  let store;
6974
7085
  try {
6975
- store = JSON.parse(await fs.readFile(sessionsFile, "utf8"));
7086
+ store = loadSessionStore(storePath, { skipCache: true });
6976
7087
  } catch {
6977
- codexSessionRecordCache.delete(resolvedSessionFile);
6978
- return;
6979
- }
6980
- if (!isJsonObject(store)) {
6981
- codexSessionRecordCache.delete(resolvedSessionFile);
6982
7088
  return;
6983
7089
  }
6984
- let found;
6985
7090
  for (const [sessionKey, record] of Object.entries(store)) {
6986
7091
  if (!isJsonObject(record) || typeof record.sessionFile !== "string") continue;
6987
7092
  if (path.resolve(record.sessionFile) !== resolvedSessionFile) continue;
6988
- found = {
7093
+ return {
6989
7094
  sessionKey,
6990
7095
  ...record
6991
7096
  };
6992
- break;
6993
7097
  }
6994
- codexSessionRecordCache.set(resolvedSessionFile, {
6995
- sessionsFile,
6996
- mtimeMs: stat.mtimeMs,
6997
- size: stat.size,
6998
- record: found
6999
- });
7000
- return found;
7001
7098
  }
7002
7099
  async function readCodexAppServerRolloutTokenSnapshot(file) {
7003
7100
  let handle;
@@ -8343,6 +8440,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
8343
8440
  let timedOut = false;
8344
8441
  let turnCompletionIdleTimedOut = false;
8345
8442
  let turnWatchTimeoutKind;
8443
+ let turnWatchTimeoutIdleMs;
8444
+ let turnWatchTimeoutMs;
8445
+ let turnWatchTimeoutLastActivityReason;
8446
+ let turnWatchTimeoutDetails;
8346
8447
  let turnCompletionIdleTimeoutMessage;
8347
8448
  let clientClosedPromptError;
8348
8449
  let clientClosedAbort = false;
@@ -8403,6 +8504,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
8403
8504
  timedOut = true;
8404
8505
  turnCompletionIdleTimedOut = true;
8405
8506
  turnWatchTimeoutKind = timeout.kind;
8507
+ turnWatchTimeoutIdleMs = timeout.idleMs;
8508
+ turnWatchTimeoutMs = timeout.timeoutMs;
8509
+ turnWatchTimeoutLastActivityReason = timeout.lastActivityReason;
8510
+ turnWatchTimeoutDetails = timeout.details;
8406
8511
  turnCompletionIdleTimeoutMessage = "codex app-server turn idle timed out waiting for turn/completed";
8407
8512
  },
8408
8513
  onMarkTimedOut: () => projectorRef.current?.markTimedOut(),
@@ -9197,7 +9302,9 @@ async function runCodexAppServerAttempt(params, options = {}) {
9197
9302
  await notificationQueue;
9198
9303
  const result = activeProjector.buildResult(toolBridge.telemetry, { yieldDetected });
9199
9304
  const finalAborted = result.aborted || runAbortController.signal.aborted && !clientClosedAbort;
9200
- let finalPromptError = clientClosedPromptError ?? (turnCompletionIdleTimedOut ? turnCompletionIdleTimeoutMessage : timedOut ? "codex app-server attempt timed out" : result.promptError);
9305
+ const canUseCompletedAssistantTextAfterClientClose = activeProjector.hasCompletedTerminalAssistantText() && activeAppServerTurnRequests === 0 && activeTurnItemIds.size === 0 && pendingOpenClawDynamicToolCompletionIds.size === 0;
9306
+ const clientClosedPromptErrorForFinal = clientClosedPromptError && canUseCompletedAssistantTextAfterClientClose ? void 0 : clientClosedPromptError;
9307
+ let finalPromptError = clientClosedPromptErrorForFinal ?? (turnCompletionIdleTimedOut ? turnCompletionIdleTimeoutMessage : timedOut ? "codex app-server attempt timed out" : result.promptError);
9201
9308
  const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
9202
9309
  if (isInvalidCodexImagePayloadError(finalPromptErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(activeSessionFile, {
9203
9310
  phase: "turn_completed",
@@ -9226,13 +9333,20 @@ async function runCodexAppServerAttempt(params, options = {}) {
9226
9333
  signal: runAbortController.signal
9227
9334
  });
9228
9335
  if (refreshedUsageLimitPromptError) finalPromptError = refreshedUsageLimitPromptError;
9229
- const finalPromptErrorSource = timedOut || clientClosedPromptError ? "prompt" : result.promptErrorSource;
9230
- const codexAppServerFailureKind = clientClosedPromptError ? "client_closed_before_turn_completed" : turnCompletionIdleTimedOut ? "turn_completion_idle_timeout" : void 0;
9336
+ const finalPromptErrorSource = timedOut || clientClosedPromptErrorForFinal ? "prompt" : result.promptErrorSource;
9337
+ const codexAppServerFailureKind = clientClosedPromptErrorForFinal ? "client_closed_before_turn_completed" : turnCompletionIdleTimedOut ? "turn_completion_idle_timeout" : void 0;
9231
9338
  const codexAppServerReplayBlockedReason = codexAppServerFailureKind ? resolveCodexAppServerReplayBlockedReason(result) : void 0;
9232
9339
  const promptTimeoutOutcome = buildCodexAppServerPromptTimeoutOutcome({
9233
9340
  result,
9234
- turnCompletionIdleTimedOut
9341
+ turnCompletionIdleTimedOut,
9342
+ turnWatchTimeoutKind
9235
9343
  });
9344
+ const codexAppServerFailureDiagnostics = codexAppServerFailureKind === "turn_completion_idle_timeout" && turnWatchTimeoutKind === "completion" ? buildCodexAppServerTimeoutDiagnostics({
9345
+ idleMs: turnWatchTimeoutIdleMs,
9346
+ timeoutMs: turnWatchTimeoutMs,
9347
+ lastActivityReason: turnWatchTimeoutLastActivityReason,
9348
+ details: turnWatchTimeoutDetails
9349
+ }) : void 0;
9236
9350
  const modelCallFailureKind = classifyCodexModelCallFailureKind({
9237
9351
  error: finalPromptError,
9238
9352
  timedOut,
@@ -9363,7 +9477,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
9363
9477
  threadId: thread.threadId,
9364
9478
  turnId: activeTurnId,
9365
9479
  replaySafe: codexAppServerReplayBlockedReason === void 0,
9366
- ...codexAppServerReplayBlockedReason ? { replayBlockedReason: codexAppServerReplayBlockedReason } : {}
9480
+ ...codexAppServerReplayBlockedReason ? { replayBlockedReason: codexAppServerReplayBlockedReason } : {},
9481
+ ...codexAppServerFailureDiagnostics ? { diagnostics: codexAppServerFailureDiagnostics } : {}
9367
9482
  } } : {},
9368
9483
  ...promptTimeoutOutcome ? { promptTimeoutOutcome } : {},
9369
9484
  systemPromptReport
@@ -9472,6 +9587,36 @@ function waitForCodexNotificationDispatchTurn() {
9472
9587
  setImmediate(resolve);
9473
9588
  });
9474
9589
  }
9590
+ function buildCodexAppServerTimeoutDiagnostics(params) {
9591
+ const readString = (key) => {
9592
+ const value = params.details?.[key];
9593
+ return typeof value === "string" && value.trim() ? value : void 0;
9594
+ };
9595
+ const readNumber = (key) => {
9596
+ const value = params.details?.[key];
9597
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
9598
+ };
9599
+ const readBoolean = (key) => {
9600
+ const value = params.details?.[key];
9601
+ return typeof value === "boolean" ? value : void 0;
9602
+ };
9603
+ return {
9604
+ ...params.idleMs !== void 0 ? { idleMs: params.idleMs } : {},
9605
+ ...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
9606
+ ...params.lastActivityReason ? { lastActivityReason: params.lastActivityReason } : {},
9607
+ ...readString("lastNotificationMethod") ? { lastNotificationMethod: readString("lastNotificationMethod") } : {},
9608
+ ...readString("lastNotificationItemId") ? { lastNotificationItemId: readString("lastNotificationItemId") } : {},
9609
+ ...readString("lastNotificationItemType") ? { lastNotificationItemType: readString("lastNotificationItemType") } : {},
9610
+ ...readString("lastNotificationItemRole") ? { lastNotificationItemRole: readString("lastNotificationItemRole") } : {},
9611
+ ...readString("lastAssistantTextPreview") ? { lastAssistantTextPreview: readString("lastAssistantTextPreview") } : {},
9612
+ ...readNumber("activeAppServerTurnRequests") !== void 0 ? { activeAppServerTurnRequests: readNumber("activeAppServerTurnRequests") } : {},
9613
+ ...readNumber("activeTurnItemCount") !== void 0 ? { activeTurnItemCount: readNumber("activeTurnItemCount") } : {},
9614
+ ...readBoolean("terminalTurnNotificationQueued") !== void 0 ? { terminalTurnNotificationQueued: readBoolean("terminalTurnNotificationQueued") } : {},
9615
+ ...readBoolean("completionIdleWatchArmed") !== void 0 ? { completionIdleWatchArmed: readBoolean("completionIdleWatchArmed") } : {},
9616
+ ...readBoolean("assistantCompletionIdleWatchArmed") !== void 0 ? { assistantCompletionIdleWatchArmed: readBoolean("assistantCompletionIdleWatchArmed") } : {},
9617
+ ...readBoolean("terminalIdleWatchArmed") !== void 0 ? { terminalIdleWatchArmed: readBoolean("terminalIdleWatchArmed") } : {}
9618
+ };
9619
+ }
9475
9620
  function handleApprovalRequest(params) {
9476
9621
  return handleCodexAppServerApprovalRequest({
9477
9622
  method: params.method,
@@ -6,7 +6,7 @@ import { a as readCodexAppServerBinding } from "./session-binding-BgTv_YGm.js";
6
6
  import { h as formatCodexUsageLimitErrorMessage, i as readCodexNotificationTurnId, r as readCodexNotificationThreadId } from "./notification-correlation-o8quHmTK.js";
7
7
  import { a as getLeasedSharedCodexAppServerClient, o as releaseLeasedSharedCodexAppServerClient, u as refreshCodexAppServerAuthTokens } from "./shared-client-xytpSKD0.js";
8
8
  import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-C-Yv9uwY.js";
9
- import { d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, h as handleCodexAppServerApprovalRequest, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerElicitationRequest, m as filterToolsForVisionInputs, p as emitDynamicToolTerminalDiagnostic, r as buildCodexNativeHookRelayConfig, t as CODEX_NATIVE_HOOK_RELAY_EVENTS, u as createCodexDynamicToolBridge } from "./native-hook-relay-DZ3Oon0b.js";
9
+ import { d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, h as handleCodexAppServerApprovalRequest, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerElicitationRequest, m as filterToolsForVisionInputs, p as emitDynamicToolTerminalDiagnostic, r as buildCodexNativeHookRelayConfig, t as CODEX_NATIVE_HOOK_RELAY_EVENTS, u as createCodexDynamicToolBridge } from "./native-hook-relay-DHwz_ICg.js";
10
10
  import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-C7qmZ0Jh.js";
11
11
  import { buildAgentHookContextChannelFields, embeddedAgentLog, formatErrorMessage, registerNativeHookRelay, resolveAgentDir, resolveAttemptSpawnWorkspaceDir, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
12
12
  //#region extensions/codex/src/app-server/side-question.ts
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@openclaw/codex",
3
- "version": "2026.6.5-beta.1",
3
+ "version": "2026.6.5-beta.3",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/codex",
9
- "version": "2026.6.5-beta.1",
9
+ "version": "2026.6.5-beta.3",
10
10
  "dependencies": {
11
11
  "@openai/codex": "0.135.0",
12
12
  "typebox": "1.1.39",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/codex",
3
- "version": "2026.6.5-beta.1",
3
+ "version": "2026.6.5-beta.3",
4
4
  "description": "OpenClaw Codex app-server harness and model provider plugin with a Codex-managed GPT catalog.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,10 +26,10 @@
26
26
  "minHostVersion": ">=2026.5.1-beta.1"
27
27
  },
28
28
  "compat": {
29
- "pluginApi": ">=2026.6.5-beta.1"
29
+ "pluginApi": ">=2026.6.5-beta.3"
30
30
  },
31
31
  "build": {
32
- "openclawVersion": "2026.6.5-beta.1"
32
+ "openclawVersion": "2026.6.5-beta.3"
33
33
  },
34
34
  "release": {
35
35
  "publishToClawHub": true,
@@ -47,7 +47,7 @@
47
47
  "README.md"
48
48
  ],
49
49
  "peerDependencies": {
50
- "openclaw": ">=2026.6.5-beta.1"
50
+ "openclaw": ">=2026.6.5-beta.3"
51
51
  },
52
52
  "peerDependenciesMeta": {
53
53
  "openclaw": {