@openclaw/codex 2026.6.11-beta.2 → 2026.7.1-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/{app-server-policy-BPTiVNsW.js → app-server-policy-C968Kgin.js} +5 -5
  2. package/dist/{attempt-notifications-BYnndyFl.js → attempt-notifications-BGsEIIDI.js} +29 -40
  3. package/dist/{command-handlers-DEPTJYk0.js → command-handlers-Dv-pzAmg.js} +278 -237
  4. package/dist/command-rpc-eLM_mtC7.js +784 -0
  5. package/dist/compact-4mVBriKT.js +603 -0
  6. package/dist/{computer-use-ClrJwoFp.js → computer-use-Bmaz333N.js} +3 -3
  7. package/dist/{config-CszD0vP3.js → config-CYEDnLJ2.js} +44 -18
  8. package/dist/conversation-binding-data-BHRpYbX3.js +121 -0
  9. package/dist/doctor-contract-api.js +590 -22
  10. package/dist/harness.js +29 -10
  11. package/dist/index.js +1134 -35
  12. package/dist/{media-understanding-provider-ZUQHN7gT.js → media-understanding-provider-BHOu9-Gg.js} +13 -8
  13. package/dist/media-understanding-provider.js +1 -1
  14. package/dist/{models-CAmfBWRl.js → models-DDmO1zwd.js} +2 -2
  15. package/dist/notification-correlation-Bo7KB3ks.js +35 -0
  16. package/dist/{plugin-app-cache-key-C9ILt7bl.js → plugin-app-cache-key-BrhVdeEf.js} +13 -5
  17. package/dist/{protocol-dh-ETiNd.js → protocol-2POPqAY4.js} +2 -1
  18. package/dist/{protocol-validators-B19q5BIX.js → protocol-validators-dZQ-UTOa.js} +205 -56
  19. package/dist/provider-capabilities-DzI8fgEu.js +6172 -0
  20. package/dist/provider-catalog.js +4 -2
  21. package/dist/{provider-B-OHpbD3.js → provider-zjPfx5Fs.js} +94 -23
  22. package/dist/provider.js +2 -2
  23. package/dist/{request-Dcd452Nk.js → request-BcJyl8KL.js} +2 -2
  24. package/dist/{run-attempt-CXxtFC9d.js → run-attempt-DNSNk_G8.js} +1250 -2992
  25. package/dist/{sandbox-guard-3tnjhjFb.js → sandbox-guard-DA2TQfZW.js} +5 -3
  26. package/dist/session-binding-C1ZXdP-x.js +627 -0
  27. package/dist/session-binding-meta-B7aEMU7g.js +6 -0
  28. package/dist/shared-client-4ICy3U6d.js +1853 -0
  29. package/dist/{side-question-C-DhgJOd.js → side-question-CMOpEhvY.js} +134 -142
  30. package/dist/{thread-lifecycle-DtT3-ehU.js → thread-lifecycle-qWE88Dn2.js} +803 -481
  31. package/dist/{web-search-provider.runtime-CkwxrXQj.js → web-search-provider.runtime-BSlriav6.js} +3 -3
  32. package/npm-shrinkwrap.json +34 -34
  33. package/openclaw.plugin.json +23 -3
  34. package/package.json +9 -6
  35. package/dist/client-CLrtWgrD.js +0 -729
  36. package/dist/client-factory-Bm6HsGob.js +0 -18
  37. package/dist/compact-aQJ0ZKhe.js +0 -278
  38. package/dist/conversation-binding-t0XMLz-j.js +0 -1557
  39. package/dist/provider-capabilities-D7hnTO76.js +0 -3201
  40. package/dist/rate-limit-cache-C7qmZ0Jh.js +0 -26
  41. package/dist/session-binding-HOuPt-E0.js +0 -338
  42. package/dist/shared-client-Dtx5i7Ez.js +0 -1013
@@ -1,23 +1,25 @@
1
- import { n as isJsonObject } from "./protocol-dh-ETiNd.js";
2
- import { H as readCodexNotificationTurnId, N as mergeCodexThreadConfigs, S as filterCodexDynamicTools, T as resolveCodexDynamicToolsLoading, V as readCodexNotificationThreadId, _ as resolveCodexWebSearchPlan, d as resolveCodexAppServerRequestModelSelection, m as resolveReasoningEffort, p as resolveCodexBindingModelProviderFallback, r as buildCodexRuntimeThreadConfig, t as CODEX_NATIVE_PERSONALITY_NONE, u as resolveCodexAppServerModelProvider } from "./thread-lifecycle-DtT3-ehU.js";
3
- import { d as resolveCodexAppServerRuntimeOptions, g as shouldAutoApproveCodexAppServerApprovals, h as resolveOpenClawExecPolicyForCodexAppServer, n as canUseCodexModelBackedApprovalsReviewerForModel, p as resolveCodexModelBackedReviewerPolicyContext, u as readCodexPluginConfig } from "./config-CszD0vP3.js";
4
- import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse, t as assertCodexThreadForkResponse } from "./protocol-validators-B19q5BIX.js";
5
- import { i as formatCodexUsageLimitErrorMessage } from "./provider-B-OHpbD3.js";
6
- import { i as isCodexAppServerApprovalRequest } from "./client-CLrtWgrD.js";
7
- import { i as isCodexAppServerNativeAuthProfile, o as readCodexAppServerBinding } from "./session-binding-HOuPt-E0.js";
8
- import { t as resolveCodexAppServerForModelProvider } from "./app-server-policy-BPTiVNsW.js";
9
- import { a as getLeasedSharedCodexAppServerClient, o as releaseLeasedSharedCodexAppServerClient, u as refreshCodexAppServerAuthTokens } from "./shared-client-Dtx5i7Ez.js";
10
- import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-3tnjhjFb.js";
11
- import { C as resolveCodexMessageToolProvider, O as filterToolsForVisionInputs, T as shouldEnableCodexAppServerNativeToolSurface, a as buildCodexNativeHookRelayConfig, d as handleCodexAppServerElicitationRequest, f as createCodexDynamicToolBridge, h as emitDynamicToolTerminalDiagnostic, k as handleCodexAppServerApprovalRequest, m as emitDynamicToolStartedDiagnostic, n as resolveCodexProviderWebSearchSupportForClient, o as buildCodexNativeHookRelayDisabledConfig, p as emitDynamicToolErrorDiagnostic, r as CODEX_NATIVE_HOOK_RELAY_EVENTS } from "./provider-capabilities-D7hnTO76.js";
12
- import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-C7qmZ0Jh.js";
1
+ import { r as isJsonObject } from "./protocol-2POPqAY4.js";
2
+ import { _ as shouldAutoApproveCodexAppServerApprovals, d as resolveCodexAppServerRuntimeOptions, g as resolveOpenClawExecPolicyForCodexAppServer, m as resolveCodexModelBackedReviewerPolicyContext, n as canUseCodexModelBackedApprovalsReviewerForModel, u as readCodexPluginConfig } from "./config-CYEDnLJ2.js";
3
+ import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse, t as assertCodexThreadForkResponse } from "./protocol-validators-dZQ-UTOa.js";
4
+ import { C as filterCodexDynamicTools, E as resolveCodexDynamicToolsLoading, H as mergeCodexThreadConfigs, d as resolveCodexAppServerModelProvider, f as resolveCodexAppServerRequestModelSelection, h as resolveReasoningEffort, m as resolveCodexBindingModelProviderFallback, r as buildCodexRuntimeThreadConfig, t as CODEX_NATIVE_PERSONALITY_NONE, v as resolveCodexWebSearchPlan, z as buildCodexPluginAppsConfigPatchFromPolicyContext } from "./thread-lifecycle-qWE88Dn2.js";
5
+ import { a as readCodexSupportedReasoningEfforts, c as formatCodexUsageLimitErrorMessage } from "./provider-zjPfx5Fs.js";
6
+ import { a as getLeasedSharedCodexAppServerClient, d as isCodexAppServerApprovalRequest, h as readRecentCodexRateLimits, o as releaseLeasedSharedCodexAppServerClient, p as ensureCodexAppServerClientRuntime } from "./shared-client-4ICy3U6d.js";
7
+ import { i as isCodexAppServerNativeAuthProfile, s as sessionBindingIdentity } from "./session-binding-C1ZXdP-x.js";
8
+ import { t as resolveCodexAppServerForModelProvider } from "./app-server-policy-C968Kgin.js";
9
+ import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-DA2TQfZW.js";
10
+ import { n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-Bo7KB3ks.js";
11
+ import { D as emitDynamicToolStartedDiagnostic, E as emitDynamicToolErrorDiagnostic, I as resolveCodexMessageToolProvider, O as emitDynamicToolTerminalDiagnostic, R as shouldEnableCodexAppServerNativeToolSurface, T as createCodexDynamicToolBridge, U as handleCodexAppServerApprovalRequest, V as filterToolsForVisionInputs, Z as handleDynamicToolCallWithTimeout, _ as buildCodexNativeHookRelayDisabledConfig, g as buildCodexNativeHookRelayConfig, i as CodexNativeToolLifecycleProjector, m as CODEX_NATIVE_HOOK_RELAY_EVENTS, n as resolveCodexProviderWebSearchSupportForClient, st as resolveCodexToolAbortTerminalReason, tt as resolveDynamicToolCallTimeoutMs, w as handleCodexAppServerElicitationRequest, y as emitCodexNativePreToolUseFailureDiagnostic } from "./provider-capabilities-DzI8fgEu.js";
12
+ import { randomUUID } from "node:crypto";
13
13
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
14
14
  import { buildAgentHookContextChannelFields, embeddedAgentLog, formatErrorMessage, registerNativeHookRelay, resolveAgentDir, resolveAttemptSpawnWorkspaceDir, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
15
15
  //#region extensions/codex/src/app-server/side-question.ts
16
- const CODEX_SIDE_DYNAMIC_TOOL_TIMEOUT_MS = 9e4;
17
- const CODEX_SIDE_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 6e5;
18
- const CODEX_SIDE_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS = 12e4;
19
- const CODEX_SIDE_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS = 6e4;
20
16
  const SIDE_QUESTION_COMPLETION_TIMEOUT_MS = 6e5;
17
+ var CodexSideQuestionTimeoutError = class extends Error {
18
+ constructor(..._args) {
19
+ super(..._args);
20
+ this.name = "TimeoutError";
21
+ }
22
+ };
21
23
  const CODEX_SIDE_NATIVE_HOOK_RELAY_MIN_TTL_MS = 30 * 6e4;
22
24
  const CODEX_SIDE_NATIVE_HOOK_RELAY_TTL_GRACE_MS = 5 * 6e4;
23
25
  const CODEX_SIDE_NATIVE_HOOK_RELAY_STARTUP_REQUEST_COUNT = 3;
@@ -46,11 +48,13 @@ External tools may be available according to this thread's current permissions.
46
48
  You may perform non-mutating inspection, including reading or searching files and running checks that do not alter repo-tracked files.
47
49
 
48
50
  Do not modify files, source, git state, permissions, configuration, workspace state, or external state unless the user explicitly requests that mutation in this side conversation. Do not request escalated permissions or broader sandbox access unless the user explicitly requests a mutation that requires it. If the user explicitly requests a mutation, keep it minimal, local to the request, and avoid disrupting the main thread.`;
49
- async function runCodexAppServerSideQuestion(params, options = {}) {
50
- const binding = await readCodexAppServerBinding(params.sessionFile, {
51
- agentDir: params.agentDir,
51
+ async function runCodexAppServerSideQuestion(params, options) {
52
+ const binding = await options.bindingStore.read(sessionBindingIdentity({
53
+ sessionId: params.sessionId,
54
+ sessionKey: params.sessionKey,
55
+ agentId: params.agentId,
52
56
  config: params.cfg
53
- });
57
+ }));
54
58
  if (!binding?.threadId) throw new Error("Codex /btw needs an active Codex thread. Send a normal message first, then try /btw again.");
55
59
  const pluginConfig = readCodexPluginConfig(options.pluginConfig);
56
60
  const { sessionAgentId } = resolveSessionAgentIds({
@@ -102,9 +106,11 @@ async function runCodexAppServerSideQuestion(params, options = {}) {
102
106
  agentDir: params.agentDir
103
107
  });
104
108
  const cwd = binding.cwd || params.workspaceDir || process.cwd();
109
+ const runId = params.opts?.runId ?? randomUUID();
105
110
  const sideRunParams = buildSideRunAttemptParams(params, {
106
111
  cwd,
107
- authProfileId
112
+ authProfileId,
113
+ runId
108
114
  });
109
115
  const nativeExecutionBlock = resolveCodexNativeExecutionBlock({
110
116
  config: sideRunParams.config,
@@ -122,9 +128,44 @@ async function runCodexAppServerSideQuestion(params, options = {}) {
122
128
  agentDir: params.agentDir,
123
129
  config: params.cfg
124
130
  });
125
- const collector = new CodexSideQuestionCollector(params);
126
- const removeNotificationHandler = client.addNotificationHandler((notification) => collector.handleNotification(notification));
131
+ const collector = new CodexSideQuestionCollector(params, () => readRecentCodexRateLimits(client));
127
132
  const runAbortController = new AbortController();
133
+ let nativeToolLifecycleProjector;
134
+ const pendingNativeToolNotifications = [];
135
+ const pendingNativePreToolUseFailures = [];
136
+ let nativePreToolUseFailureFallbackActive = false;
137
+ let nativeToolRunWasAbortedBeforeCleanup;
138
+ let nativePreToolUseFailureFallbackTerminalReason;
139
+ const emitNativePreToolUseFailure = (failure) => {
140
+ emitCodexNativePreToolUseFailureDiagnostic({
141
+ agentId: sessionAgentId,
142
+ sessionId: params.sessionId,
143
+ sessionKey: params.sessionKey,
144
+ runId: sideRunParams.runId,
145
+ signal: runAbortController.signal,
146
+ failure,
147
+ ...nativePreToolUseFailureFallbackActive ? { terminalReason: nativePreToolUseFailureFallbackTerminalReason ?? failure.disposition } : {}
148
+ });
149
+ };
150
+ const flushPendingNativePreToolUseFailures = () => {
151
+ for (const failure of pendingNativePreToolUseFailures.splice(0)) emitNativePreToolUseFailure(failure);
152
+ };
153
+ const activateNativePreToolUseFailureFallback = () => {
154
+ if (!nativePreToolUseFailureFallbackActive) {
155
+ nativePreToolUseFailureFallbackTerminalReason = nativeToolRunWasAbortedBeforeCleanup ? resolveCodexToolAbortTerminalReason(runAbortController.signal) : void 0;
156
+ nativePreToolUseFailureFallbackActive = true;
157
+ }
158
+ flushPendingNativePreToolUseFailures();
159
+ };
160
+ const removeNotificationHandler = client.addNotificationHandler((notification) => {
161
+ collector.handleNotification(notification);
162
+ if (notification.method !== "item/started" && notification.method !== "item/completed" && notification.method !== "rawResponseItem/completed" && notification.method !== "turn/completed") return;
163
+ if (!nativeToolLifecycleProjector) {
164
+ pendingNativeToolNotifications.push(notification);
165
+ return;
166
+ }
167
+ nativeToolLifecycleProjector.handleNotification(notification);
168
+ });
128
169
  const abortFromUpstream = () => runAbortController.abort(params.opts?.abortSignal?.reason ?? "codex_side_question_abort");
129
170
  if (params.opts?.abortSignal?.aborted) abortFromUpstream();
130
171
  else params.opts?.abortSignal?.addEventListener("abort", abortFromUpstream, { once: true });
@@ -165,14 +206,15 @@ async function runCodexAppServerSideQuestion(params, options = {}) {
165
206
  modelProviderOverride: modelSelection.modelProvider,
166
207
  signal: runAbortController.signal
167
208
  }) : "unsupported",
209
+ runId,
168
210
  signal: runAbortController.signal
169
211
  });
212
+ ensureCodexAppServerClientRuntime(client, {
213
+ agentDir: params.agentDir,
214
+ authProfileId,
215
+ config: params.cfg
216
+ });
170
217
  removeRequestHandler = client.addRequestHandler(async (request) => {
171
- if (request.method === "account/chatgptAuthTokens/refresh") return await refreshCodexAppServerAuthTokens({
172
- agentDir: params.agentDir,
173
- authProfileId,
174
- config: params.cfg
175
- });
176
218
  if (!childThreadId || !turnId) return;
177
219
  if (request.method === "mcpServer/elicitation/request") return handleCodexAppServerElicitationRequest({
178
220
  requestParams: request.params,
@@ -198,25 +240,27 @@ async function runCodexAppServerSideQuestion(params, options = {}) {
198
240
  networkProxy: modelScopedAppServer.networkProxy,
199
241
  sandbox
200
242
  }),
201
- signal: runAbortController.signal
243
+ signal: runAbortController.signal,
244
+ onNativeToolFailureDisposition: (itemId, disposition) => nativeToolLifecycleProjector?.recordApprovalFailureDisposition(itemId, disposition)
202
245
  });
203
246
  if (request.method !== "item/tool/call") return;
204
247
  const call = readCodexDynamicToolCallParams(request.params);
205
248
  if (!call || call.threadId !== childThreadId || call.turnId !== turnId) return;
206
- const timeoutMs = resolveSideDynamicToolCallTimeoutMs({
249
+ const timeoutMs = resolveDynamicToolCallTimeoutMs({
207
250
  call,
208
251
  config: params.cfg
209
252
  });
210
253
  const toolStartedAt = Date.now();
211
254
  const diagnosticContext = {
212
255
  call,
256
+ agentId: sessionAgentId,
213
257
  runId: sideRunParams.runId,
214
258
  sessionId: params.sessionId,
215
259
  sessionKey: params.sessionKey
216
260
  };
217
261
  emitDynamicToolStartedDiagnostic(diagnosticContext);
218
262
  try {
219
- const response = await handleSideDynamicToolCallWithTimeout({
263
+ const response = await handleDynamicToolCallWithTimeout({
220
264
  call,
221
265
  toolBridge,
222
266
  signal: runAbortController.signal,
@@ -234,7 +278,8 @@ async function runCodexAppServerSideQuestion(params, options = {}) {
234
278
  } catch (error) {
235
279
  emitDynamicToolErrorDiagnostic({
236
280
  ...diagnosticContext,
237
- durationMs: Math.max(0, Date.now() - toolStartedAt)
281
+ durationMs: Math.max(0, Date.now() - toolStartedAt),
282
+ terminalReason: runAbortController.signal.aborted ? resolveCodexToolAbortTerminalReason(runAbortController.signal) : "failed"
238
283
  });
239
284
  throw error;
240
285
  }
@@ -260,7 +305,12 @@ async function runCodexAppServerSideQuestion(params, options = {}) {
260
305
  }).channelId,
261
306
  requestTimeoutMs: appServer.requestTimeoutMs,
262
307
  completionTimeoutMs: Math.max(appServer.turnCompletionIdleTimeoutMs, SIDE_QUESTION_COMPLETION_TIMEOUT_MS),
263
- signal: runAbortController.signal
308
+ signal: runAbortController.signal,
309
+ onPreToolUseFailure: (failure) => {
310
+ if (nativePreToolUseFailureFallbackActive) emitNativePreToolUseFailure(failure);
311
+ else if (nativeToolLifecycleProjector) nativeToolLifecycleProjector.recordPreToolUseFailure(failure, nativeToolRunWasAbortedBeforeCleanup);
312
+ else pendingNativePreToolUseFailures.push(failure);
313
+ }
264
314
  }) : void 0;
265
315
  const nativeHookRelayConfig = nativeHookRelay ? buildCodexNativeHookRelayConfig({
266
316
  relay: nativeHookRelay,
@@ -272,7 +322,7 @@ async function runCodexAppServerSideQuestion(params, options = {}) {
272
322
  nativeCodeModeEnabled: nativeToolSurfaceEnabled,
273
323
  nativeCodeModeOnlyEnabled: appServer.codeModeOnly
274
324
  });
275
- const threadConfig = mergeCodexThreadConfigs(nativeHookRelayConfig, runtimeThreadConfig, modelScopedAppServer.networkProxy?.configPatch) ?? runtimeThreadConfig;
325
+ const threadConfig = mergeCodexThreadConfigs(nativeHookRelayConfig, runtimeThreadConfig, binding.pluginAppPolicyContext ? buildCodexPluginAppsConfigPatchFromPolicyContext(binding.pluginAppPolicyContext) : void 0, modelScopedAppServer.networkProxy?.configPatch) ?? runtimeThreadConfig;
276
326
  childThreadId = assertCodexThreadForkResponse(await forkCodexSideThread(client, {
277
327
  threadId: binding.threadId,
278
328
  model: modelSelection.model,
@@ -298,7 +348,7 @@ async function runCodexAppServerSideQuestion(params, options = {}) {
298
348
  timeoutMs: appServer.requestTimeoutMs,
299
349
  signal: params.opts?.abortSignal
300
350
  });
301
- const effort = resolveReasoningEffort(params.resolvedThinkLevel ?? "off", modelSelection.model);
351
+ const effort = resolveReasoningEffort(params.resolvedThinkLevel ?? "off", modelSelection.model, readCodexSupportedReasoningEfforts(params.runtimeModel?.compat));
302
352
  turnId = assertCodexTurnStartResponse(await client.request("turn/start", {
303
353
  threadId: childThreadId,
304
354
  input: [{
@@ -324,25 +374,51 @@ async function runCodexAppServerSideQuestion(params, options = {}) {
324
374
  signal: params.opts?.abortSignal
325
375
  })).turn.id;
326
376
  collector.setTurn(childThreadId, turnId);
327
- const trimmed = (await collector.wait({
328
- signal: params.opts?.abortSignal,
329
- timeoutMs: Math.max(appServer.turnCompletionIdleTimeoutMs, SIDE_QUESTION_COMPLETION_TIMEOUT_MS)
330
- })).trim();
377
+ nativeToolLifecycleProjector = new CodexNativeToolLifecycleProjector({
378
+ ...sideRunParams,
379
+ agentId: sessionAgentId
380
+ }, childThreadId, turnId, { runAbortSignal: runAbortController.signal });
381
+ for (const failure of pendingNativePreToolUseFailures) nativeToolLifecycleProjector.recordPreToolUseFailure(failure);
382
+ pendingNativePreToolUseFailures.length = 0;
383
+ for (const notification of pendingNativeToolNotifications) nativeToolLifecycleProjector.handleNotification(notification);
384
+ pendingNativeToolNotifications.length = 0;
385
+ let text;
386
+ try {
387
+ text = await collector.wait({
388
+ signal: params.opts?.abortSignal,
389
+ timeoutMs: Math.max(appServer.turnCompletionIdleTimeoutMs, SIDE_QUESTION_COMPLETION_TIMEOUT_MS)
390
+ });
391
+ } catch (error) {
392
+ if (error instanceof CodexSideQuestionTimeoutError && !runAbortController.signal.aborted) runAbortController.abort(error);
393
+ throw error;
394
+ }
395
+ const trimmed = text.trim();
331
396
  if (!trimmed) throw new Error("Codex /btw completed without an answer.");
332
397
  return { text: trimmed };
333
398
  } finally {
334
399
  try {
400
+ const runWasAbortedBeforeCleanup = runAbortController.signal.aborted;
401
+ nativeToolRunWasAbortedBeforeCleanup = runWasAbortedBeforeCleanup;
335
402
  params.opts?.abortSignal?.removeEventListener("abort", abortFromUpstream);
336
- if (!runAbortController.signal.aborted) runAbortController.abort("codex_side_question_finished");
337
- removeNotificationHandler();
338
403
  removeRequestHandler?.();
339
- await cleanupCodexSideThread(client, {
340
- threadId: childThreadId,
341
- turnId,
342
- interrupt: !collector.completed,
343
- timeoutMs: appServer.requestTimeoutMs
344
- });
404
+ if (!runAbortController.signal.aborted) runAbortController.abort("codex_side_question_finished");
405
+ try {
406
+ await cleanupCodexSideThread(client, {
407
+ threadId: childThreadId,
408
+ turnId,
409
+ interrupt: !collector.completed,
410
+ timeoutMs: appServer.requestTimeoutMs
411
+ });
412
+ } finally {
413
+ removeNotificationHandler();
414
+ try {
415
+ nativeToolLifecycleProjector?.finalizeActive(runWasAbortedBeforeCleanup);
416
+ } finally {
417
+ activateNativePreToolUseFailureFallback();
418
+ }
419
+ }
345
420
  } finally {
421
+ flushPendingNativePreToolUseFailures();
346
422
  releaseLeasedSharedCodexAppServerClient(client);
347
423
  nativeHookRelay?.unregister();
348
424
  }
@@ -369,6 +445,7 @@ function registerCodexSideNativeHookRelay(params) {
369
445
  completionTimeoutMs: params.completionTimeoutMs
370
446
  }),
371
447
  signal: params.signal,
448
+ onPreToolUseFailure: params.onPreToolUseFailure,
372
449
  command: { timeoutMs: params.options.gatewayTimeoutMs }
373
450
  });
374
451
  }
@@ -418,7 +495,7 @@ function buildSideRunAttemptParams(params, options) {
418
495
  authStorage: void 0,
419
496
  authProfileStore: void 0,
420
497
  modelRegistry: void 0,
421
- runId: params.opts?.runId ?? `codex-btw:${params.sessionId}`,
498
+ runId: options.runId,
422
499
  abortSignal: params.opts?.abortSignal,
423
500
  onAgentEvent: (event) => {
424
501
  if (event.stream === "approval") params.opts?.onApprovalEvent?.(event.data);
@@ -447,7 +524,7 @@ async function createCodexSideToolBridge(input) {
447
524
  sessionKey: sandboxSessionKey,
448
525
  runSessionKey: input.params.sessionKey && input.params.sessionKey !== sandboxSessionKey ? input.params.sessionKey : void 0,
449
526
  sessionId: input.params.sessionId,
450
- runId: input.params.opts?.runId ?? `codex-btw:${input.params.sessionId}`,
527
+ runId: input.runId,
451
528
  agentDir: input.params.agentDir ?? resolveAgentDir(input.params.cfg ?? {}, input.sessionAgentId),
452
529
  workspaceDir: input.cwd,
453
530
  spawnWorkspaceDir: resolveAttemptSpawnWorkspaceDir({
@@ -523,7 +600,7 @@ async function createCodexSideToolBridge(input) {
523
600
  config: input.params.cfg,
524
601
  sessionId: input.params.sessionId,
525
602
  sessionKey: input.params.sessionKey,
526
- runId: input.params.opts?.runId ?? `codex-btw:${input.params.sessionId}`,
603
+ runId: input.runId,
527
604
  currentChannelProvider: messageToolProvider,
528
605
  ...hookChannelFields
529
606
  }
@@ -531,87 +608,12 @@ async function createCodexSideToolBridge(input) {
531
608
  webSearchPlan
532
609
  };
533
610
  }
534
- async function handleSideDynamicToolCallWithTimeout(params) {
535
- if (params.signal.aborted) return failedSideDynamicToolResponse("OpenClaw dynamic tool call aborted before execution.");
536
- const controller = new AbortController();
537
- let timeout;
538
- let resolveAbort;
539
- const abortFromRun = () => {
540
- const message = "OpenClaw dynamic tool call aborted.";
541
- controller.abort(params.signal.reason ?? /* @__PURE__ */ new Error(message));
542
- resolveAbort?.(failedSideDynamicToolResponse(message));
543
- };
544
- const abortPromise = new Promise((resolve) => {
545
- resolveAbort = resolve;
546
- });
547
- const timeoutPromise = new Promise((resolve) => {
548
- const timeoutMs = clampSideDynamicToolTimeoutMs(params.timeoutMs);
549
- timeout = setTimeout(() => {
550
- controller.abort(/* @__PURE__ */ new Error(`OpenClaw dynamic tool call timed out after ${timeoutMs}ms.`));
551
- resolve(failedSideDynamicToolResponse(`OpenClaw dynamic tool call timed out after ${timeoutMs}ms.`));
552
- }, timeoutMs);
553
- timeout.unref?.();
554
- });
555
- try {
556
- params.signal.addEventListener("abort", abortFromRun, { once: true });
557
- if (params.signal.aborted) abortFromRun();
558
- return await Promise.race([
559
- params.toolBridge.handleToolCall(params.call, { signal: controller.signal }),
560
- abortPromise,
561
- timeoutPromise
562
- ]);
563
- } catch (error) {
564
- return failedSideDynamicToolResponse(error instanceof Error ? error.message : String(error));
565
- } finally {
566
- if (timeout) clearTimeout(timeout);
567
- params.signal.removeEventListener("abort", abortFromRun);
568
- resolveAbort = void 0;
569
- if (!controller.signal.aborted) controller.abort(/* @__PURE__ */ new Error("OpenClaw dynamic tool call finished."));
570
- }
571
- }
572
- function failedSideDynamicToolResponse(message) {
573
- const response = {
574
- contentItems: [{
575
- type: "inputText",
576
- text: message
577
- }],
578
- success: false
579
- };
580
- Object.defineProperty(response, "diagnosticTerminalType", {
581
- configurable: true,
582
- enumerable: false,
583
- value: "error"
584
- });
585
- return response;
586
- }
587
611
  function emptySideUserInputResponse() {
588
612
  return { answers: {} };
589
613
  }
590
614
  function isSideUserInputRequest(value, threadId, turnId) {
591
615
  return isJsonObject(value) && value.threadId === threadId && value.turnId === turnId;
592
616
  }
593
- function resolveSideDynamicToolCallTimeoutMs(params) {
594
- return clampSideDynamicToolTimeoutMs(readSideDynamicToolCallTimeoutMs(params.call.arguments) ?? (params.call.tool === "image_generate" ? readSideImageGenerationModelTimeoutMs(params.config) ?? CODEX_SIDE_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS : void 0) ?? (params.call.tool === "image" ? readSideTimeoutSecondsAsMs(params.config?.tools?.media?.image?.timeoutSeconds) ?? CODEX_SIDE_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS : void 0) ?? CODEX_SIDE_DYNAMIC_TOOL_TIMEOUT_MS);
595
- }
596
- function readSideDynamicToolCallTimeoutMs(value) {
597
- if (!isJsonObject(value)) return;
598
- return readSidePositiveFiniteTimeoutMs(value.timeoutMs);
599
- }
600
- function readSideImageGenerationModelTimeoutMs(config) {
601
- const imageGenerationModel = config?.agents?.defaults?.imageGenerationModel;
602
- if (!imageGenerationModel || typeof imageGenerationModel !== "object") return;
603
- return readSidePositiveFiniteTimeoutMs(imageGenerationModel.timeoutMs);
604
- }
605
- function readSideTimeoutSecondsAsMs(value) {
606
- const seconds = readSidePositiveFiniteTimeoutMs(value);
607
- return seconds === void 0 ? void 0 : seconds * 1e3;
608
- }
609
- function readSidePositiveFiniteTimeoutMs(value) {
610
- return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : void 0;
611
- }
612
- function clampSideDynamicToolTimeoutMs(timeoutMs) {
613
- return Math.max(1, Math.min(CODEX_SIDE_DYNAMIC_TOOL_MAX_TIMEOUT_MS, Math.floor(timeoutMs)));
614
- }
615
617
  async function forkCodexSideThread(client, params, options) {
616
618
  try {
617
619
  return await client.request("thread/fork", params, options);
@@ -651,8 +653,9 @@ async function cleanupCodexSideThread(client, params) {
651
653
  }
652
654
  }
653
655
  var CodexSideQuestionCollector = class {
654
- constructor(params) {
656
+ constructor(params, readRecentRateLimits) {
655
657
  this.params = params;
658
+ this.readRecentRateLimits = readRecentRateLimits;
656
659
  this.pendingNotifications = [];
657
660
  this.assistantStarted = false;
658
661
  this.assistantText = "";
@@ -668,11 +671,6 @@ var CodexSideQuestionCollector = class {
668
671
  handleNotification(notification) {
669
672
  const params = isJsonObject(notification.params) ? notification.params : void 0;
670
673
  if (!params) return;
671
- if (notification.method === "account/rateLimits/updated") {
672
- this.latestRateLimits = params;
673
- rememberCodexRateLimits(params);
674
- return;
675
- }
676
674
  if (!this.threadId || !this.turnId) {
677
675
  this.pendingNotifications.push(notification);
678
676
  return;
@@ -686,7 +684,7 @@ var CodexSideQuestionCollector = class {
686
684
  this.completeFromTurn(params);
687
685
  return;
688
686
  }
689
- if (notification.method === "error" && readBooleanAlias(params, ["willRetry", "will_retry"]) !== true) this.reject(formatCodexErrorMessage(params, this.latestRateLimits));
687
+ if (notification.method === "error" && params.willRetry !== true) this.reject(formatCodexErrorMessage(params, this.readRecentRateLimits()));
690
688
  }
691
689
  wait(options) {
692
690
  if (this.terminalError) return Promise.reject(this.terminalError);
@@ -709,7 +707,7 @@ var CodexSideQuestionCollector = class {
709
707
  timeout = setTimeout(() => {
710
708
  cleanup();
711
709
  this.settle = void 0;
712
- reject(/* @__PURE__ */ new Error("Codex /btw timed out waiting for the side thread to finish."));
710
+ reject(new CodexSideQuestionTimeoutError("Codex /btw timed out waiting for the side thread to finish."));
713
711
  }, Math.max(100, options.timeoutMs));
714
712
  timeout.unref?.();
715
713
  options.signal?.addEventListener("abort", abort, { once: true });
@@ -742,7 +740,7 @@ var CodexSideQuestionCollector = class {
742
740
  this.reject(formatCodexUsageLimitErrorMessage({
743
741
  message: turn.error?.message,
744
742
  codexErrorInfo: turn.error?.codexErrorInfo,
745
- rateLimits: this.latestRateLimits ?? readRecentCodexRateLimits()
743
+ rateLimits: this.readRecentRateLimits()
746
744
  }) ?? turn.error?.message ?? "Codex /btw side thread failed.");
747
745
  return;
748
746
  }
@@ -775,22 +773,16 @@ function isNotificationForTurn(params, threadId, turnId) {
775
773
  function readNotificationTurnId(record) {
776
774
  return readCodexNotificationTurnId(record);
777
775
  }
778
- function readBooleanAlias(record, keys) {
779
- for (const key of keys) {
780
- const value = record[key];
781
- if (typeof value === "boolean") return value;
782
- }
783
- }
784
776
  function readString(record, key) {
785
777
  const value = record[key];
786
778
  return typeof value === "string" ? value : void 0;
787
779
  }
788
- function formatCodexErrorMessage(params, latestRateLimits) {
780
+ function formatCodexErrorMessage(params, rateLimits) {
789
781
  const error = isJsonObject(params.error) ? params.error : void 0;
790
782
  const message = formatCodexUsageLimitErrorMessage({
791
783
  message: error ? readString(error, "message") : void 0,
792
784
  codexErrorInfo: error?.codexErrorInfo,
793
- rateLimits: latestRateLimits ?? readRecentCodexRateLimits()
785
+ rateLimits
794
786
  }) ?? (error ? readString(error, "message") ?? readString(error, "error") : void 0) ?? readString(params, "message") ?? "Codex /btw side thread failed.";
795
787
  return new Error(formatErrorMessage(message));
796
788
  }