@openclaw/codex 2026.6.5-beta.2 → 2026.6.5-beta.5

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-CWfXFq9Q.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) {
@@ -4233,6 +4238,7 @@ var CodexAppServerEventProjector = class {
4233
4238
  this.toolTrajectoryCallIds = /* @__PURE__ */ new Set();
4234
4239
  this.toolTrajectoryResultIds = /* @__PURE__ */ new Set();
4235
4240
  this.toolTrajectoryNamesById = /* @__PURE__ */ new Map();
4241
+ this.toolTrajectoryItemsById = /* @__PURE__ */ new Map();
4236
4242
  this.transcriptToolProgressCallIds = /* @__PURE__ */ new Set();
4237
4243
  this.nativeGeneratedMediaUrls = /* @__PURE__ */ new Set();
4238
4244
  this.nativeGeneratedMediaItemIds = /* @__PURE__ */ new Set();
@@ -4321,7 +4327,13 @@ var CodexAppServerEventProjector = class {
4321
4327
  const assistantTexts = this.collectAssistantTexts();
4322
4328
  const reasoningText = collectReasoningTextValues(this.reasoningTextByGroup, this.reasoningItemOrder).join("\n\n");
4323
4329
  const planText = collectTextValues(this.planTextByItem).join("\n\n");
4324
- 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
+ });
4325
4337
  const lastAssistant = assistantTexts.length > 0 ? this.createAssistantMessage(assistantTexts.join("\n\n")) : void 0;
4326
4338
  const turnId = this.turnId;
4327
4339
  const messagesSnapshot = this.params.suppressNextUserMessagePersistence ? [] : [attachCodexMirrorIdentity(buildCodexUserPromptMessage(this.params), `${turnId}:prompt`)];
@@ -4983,6 +4995,7 @@ var CodexAppServerEventProjector = class {
4983
4995
  if (params.phase === "start") {
4984
4996
  this.toolTrajectoryCallIds.add(params.item.id);
4985
4997
  this.toolTrajectoryNamesById.set(params.item.id, params.name);
4998
+ this.toolTrajectoryItemsById.set(params.item.id, params.item);
4986
4999
  this.options.trajectoryRecorder?.recordEvent("tool.call", {
4987
5000
  threadId: this.threadId,
4988
5001
  turnId: this.turnId,
@@ -5178,7 +5191,7 @@ var CodexAppServerEventProjector = class {
5178
5191
  this.toolTranscriptMessages.push(attachCodexMirrorIdentity(this.createToolResultMessage(params), `${this.turnId}:tool:${params.id}:result`));
5179
5192
  }
5180
5193
  synthesizeMissingToolResults(params) {
5181
- if (!params.failClosed) return;
5194
+ if (!params.synthesize) return;
5182
5195
  const missingTranscriptIds = [...this.toolTranscriptCallIds].filter((id) => !this.toolTranscriptResultIds.has(id));
5183
5196
  const missingTrajectoryIds = [...this.toolTrajectoryCallIds].filter((id) => !this.toolTrajectoryResultIds.has(id));
5184
5197
  if (missingTranscriptIds.length === 0 && missingTrajectoryIds.length === 0) return;
@@ -5218,6 +5231,34 @@ var CodexAppServerEventProjector = class {
5218
5231
  output: text
5219
5232
  });
5220
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
+ }
5221
5262
  const missingCount = new Set([...missingTranscriptIds, ...missingTrajectoryIds]).size;
5222
5263
  this.synthesizedMissingToolResultError = missingCount === 1 ? MISSING_TOOL_RESULT_ERROR : `${MISSING_TOOL_RESULT_ERROR} missingToolResultCount=${missingCount}`;
5223
5264
  this.promptErrorSource = this.promptErrorSource ?? "prompt";
@@ -5283,6 +5324,16 @@ var CodexAppServerEventProjector = class {
5283
5324
  const finalText = this.resolveFinalAssistantText();
5284
5325
  return finalText ? [finalText] : [];
5285
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
+ }
5286
5337
  resolveFinalAssistantText() {
5287
5338
  return this.resolveFinalAssistantTextItem()?.text;
5288
5339
  }
@@ -5864,10 +5915,11 @@ function readCompletionStatus(status) {
5864
5915
  for (const [rawKey, value] of Object.entries(status)) {
5865
5916
  const mappedStatus = mapCompletionStatus(normalizeStatusKey(rawKey));
5866
5917
  if (!mappedStatus) continue;
5918
+ const result = stringifyResult(value, mappedStatus);
5867
5919
  return {
5868
5920
  status: mappedStatus,
5869
- label: rawKey,
5870
- result: stringifyResult(value)
5921
+ label: mappedStatus === "succeeded" && result.kind === "no_final_assistant_message" ? "completed_without_final_message" : rawKey,
5922
+ result: result.text
5871
5923
  };
5872
5924
  }
5873
5925
  }
@@ -5876,15 +5928,25 @@ function mapCompletionStatus(value) {
5876
5928
  if (value === "cancelled" || value === "canceled" || value === "interrupted" || value === "shutdown") return "cancelled";
5877
5929
  if (value === "failed" || value === "error" || value === "errored" || value === "systemerror" || value === "notfound") return "failed";
5878
5930
  }
5879
- function stringifyResult(value) {
5880
- if (typeof value === "string") return value.trim() || "(no output)";
5881
- 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)" };
5882
5938
  try {
5883
- return JSON.stringify(value);
5939
+ return { text: JSON.stringify(value) };
5884
5940
  } catch {
5885
- return "(unserializable output)";
5941
+ return { text: "(unserializable output)" };
5886
5942
  }
5887
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
+ }
5888
5950
  function readTrustedInterAgentCommunicationContent(item) {
5889
5951
  const communication = readTrustedInterAgentCommunication(item);
5890
5952
  return typeof communication?.content === "string" ? communication.content : void 0;
@@ -6415,6 +6477,14 @@ var CodexNativeSubagentMonitor = class {
6415
6477
  continue;
6416
6478
  }
6417
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
+ }
6418
6488
  await this.processCompletion(state, completion);
6419
6489
  }
6420
6490
  }
@@ -6448,6 +6518,10 @@ var CodexNativeSubagentMonitor = class {
6448
6518
  clearTimeout(childState.transcriptPollTimer);
6449
6519
  childState.transcriptPollTimer = void 0;
6450
6520
  }
6521
+ if (childState.noFinalCompletionFallbackTimer) {
6522
+ clearTimeout(childState.noFinalCompletionFallbackTimer);
6523
+ childState.noFinalCompletionFallbackTimer = void 0;
6524
+ }
6451
6525
  }
6452
6526
  if (!state.requesterSessionKey) return;
6453
6527
  const completionKey = buildCompletionDedupeKey(state.parentThreadId, completion);
@@ -6601,6 +6675,24 @@ var CodexNativeSubagentMonitor = class {
6601
6675
  }, delayMs);
6602
6676
  unrefTimer(childState.transcriptPollTimer);
6603
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
+ }
6604
6696
  clearTimers() {
6605
6697
  if (this.taskRowReconcileTimer) {
6606
6698
  clearInterval(this.taskRowReconcileTimer);
@@ -6615,6 +6707,10 @@ var CodexNativeSubagentMonitor = class {
6615
6707
  clearTimeout(childState.completionDeliveryTimer);
6616
6708
  childState.completionDeliveryTimer = void 0;
6617
6709
  }
6710
+ if (childState.noFinalCompletionFallbackTimer) {
6711
+ clearTimeout(childState.noFinalCompletionFallbackTimer);
6712
+ childState.noFinalCompletionFallbackTimer = void 0;
6713
+ }
6618
6714
  }
6619
6715
  }
6620
6716
  startTaskRowReconciler(intervalMs) {
@@ -6748,6 +6844,14 @@ function toThreadCompletion(completion, childThreadId) {
6748
6844
  result: completion.result
6749
6845
  };
6750
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
+ }
6751
6855
  function readSpawnParentThreadId(thread) {
6752
6856
  const source = isJsonObject(thread?.source) ? thread.source : void 0;
6753
6857
  const subAgent = isJsonObject(source?.subAgent) ? source.subAgent : void 0;
@@ -6856,15 +6960,17 @@ async function readTranscriptCompletion(transcriptPath, childThreadId) {
6856
6960
  }
6857
6961
  if (readString$2(entry, "type") !== "event_msg") continue;
6858
6962
  const payloadType = readString$2(payload, "type");
6859
- if (payloadType === "task_complete") completion = {
6860
- childThreadId,
6861
- parentThreadId,
6862
- status: "succeeded",
6863
- statusLabel: "task_complete",
6864
- result: readString$2(payload, "last_agent_message")?.trim() || readString$2(payload, "message")?.trim() || "(no output)",
6865
- completedAt: secondsToMillis(readNumber(payload, "completed_at")) ?? readTimestamp(entry)
6866
- };
6867
- 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") {
6868
6974
  const result = readString$2(payload, "last_agent_message")?.trim() || readString$2(payload, "error")?.trim() || readString$2(payload, "message")?.trim() || "Codex native subagent failed.";
6869
6975
  completion = {
6870
6976
  childThreadId,
@@ -6919,7 +7025,6 @@ const CODEX_APP_SERVER_BYTE_UNITS = {
6919
7025
  tb: 1024 * 1024 * 1024 * 1024,
6920
7026
  tib: 1024 * 1024 * 1024 * 1024
6921
7027
  };
6922
- const codexSessionRecordCache = /* @__PURE__ */ new Map();
6923
7028
  function parseCodexAppServerByteLimit(value) {
6924
7029
  if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.floor(value);
6925
7030
  if (typeof value !== "string") return;
@@ -6974,45 +7079,22 @@ async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codex
6974
7079
  return files;
6975
7080
  }
6976
7081
  async function readCodexSessionRecordForSessionFile(sessionFile) {
6977
- const sessionsFile = path.join(path.dirname(sessionFile), "sessions.json");
7082
+ const storePath = path.join(path.dirname(sessionFile), "sessions.json");
6978
7083
  const resolvedSessionFile = path.resolve(sessionFile);
6979
- let stat;
6980
- try {
6981
- stat = await fs.stat(sessionsFile);
6982
- } catch {
6983
- codexSessionRecordCache.delete(resolvedSessionFile);
6984
- return;
6985
- }
6986
- const cached = codexSessionRecordCache.get(resolvedSessionFile);
6987
- if (cached?.sessionsFile === sessionsFile && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) return cached.record;
6988
7084
  let store;
6989
7085
  try {
6990
- store = JSON.parse(await fs.readFile(sessionsFile, "utf8"));
7086
+ store = loadSessionStore(storePath, { skipCache: true });
6991
7087
  } catch {
6992
- codexSessionRecordCache.delete(resolvedSessionFile);
6993
- return;
6994
- }
6995
- if (!isJsonObject(store)) {
6996
- codexSessionRecordCache.delete(resolvedSessionFile);
6997
7088
  return;
6998
7089
  }
6999
- let found;
7000
7090
  for (const [sessionKey, record] of Object.entries(store)) {
7001
7091
  if (!isJsonObject(record) || typeof record.sessionFile !== "string") continue;
7002
7092
  if (path.resolve(record.sessionFile) !== resolvedSessionFile) continue;
7003
- found = {
7093
+ return {
7004
7094
  sessionKey,
7005
7095
  ...record
7006
7096
  };
7007
- break;
7008
7097
  }
7009
- codexSessionRecordCache.set(resolvedSessionFile, {
7010
- sessionsFile,
7011
- mtimeMs: stat.mtimeMs,
7012
- size: stat.size,
7013
- record: found
7014
- });
7015
- return found;
7016
7098
  }
7017
7099
  async function readCodexAppServerRolloutTokenSnapshot(file) {
7018
7100
  let handle;
@@ -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.2",
3
+ "version": "2026.6.5-beta.5",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/codex",
9
- "version": "2026.6.5-beta.2",
9
+ "version": "2026.6.5-beta.5",
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.2",
3
+ "version": "2026.6.5-beta.5",
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.2"
29
+ "pluginApi": ">=2026.6.5-beta.5"
30
30
  },
31
31
  "build": {
32
- "openclawVersion": "2026.6.5-beta.2"
32
+ "openclawVersion": "2026.6.5-beta.5"
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.2"
50
+ "openclaw": ">=2026.6.5-beta.5"
51
51
  },
52
52
  "peerDependenciesMeta": {
53
53
  "openclaw": {