@openclaw/codex 2026.9.2 → 2026.9.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.
Files changed (108) hide show
  1. package/README.md +2 -0
  2. package/dist/api.js +14 -19
  3. package/dist/apply-B6el6hdO.js +357 -0
  4. package/dist/{attempt-client-cleanup-Bp1ZOnk2.js → attempt-client-cleanup-D6cR54TV.js} +39 -19
  5. package/dist/{attempt-context-CSazkWns.js → attempt-context-AO4DSjE0.js} +8 -6
  6. package/dist/{event-projector-usage-ZqEVbAEY.js → attempt-notifications--H8zXR5-.js} +3 -106
  7. package/dist/auth-cache-key-Kq6oerr6.js +498 -0
  8. package/dist/auth-profile-CwzO4_RG.js +43 -0
  9. package/dist/auth-profile-selection-DFu9e167.js +45 -0
  10. package/dist/binding-connection-QqgcPCgk.js +60 -0
  11. package/dist/{bounded-turn-DxGJRYbY.js → bounded-turn-lRpmZHFv.js} +25 -122
  12. package/dist/build-state-6RL6qohz.js +19 -0
  13. package/dist/{capabilities-B1mgvpP8.js → capabilities-BeqLPbtM.js} +1 -1
  14. package/dist/cli-metadata.js +1 -1
  15. package/dist/client-BEKu4yDx.js +3983 -0
  16. package/dist/command-dispatch-CisT9Jqq.js +21 -0
  17. package/dist/{command-formatters-DSbGMXA0.js → command-formatters-DeTfrapr.js} +2 -2
  18. package/dist/{command-handlers-DOJvGv6-.js → command-handlers-BfIsJEuA.js} +31 -21
  19. package/dist/command-rpc-BMqRQOFX.js +226 -0
  20. package/dist/{compact-Y_xBqrHN.js → compact-CGJZ2rlb.js} +19 -14
  21. package/dist/config-JDfTI4VI.js +106 -0
  22. package/dist/{config-CyapYSji.js → config-options-jnIFvwxD.js} +204 -592
  23. package/dist/config-runtime-BWf6JLWG.js +11 -0
  24. package/dist/conversation-binding-CxOlHiix.js +889 -0
  25. package/dist/{plugin-marketplace-discovery-B7gHXJ3d.js → conversation-control-CUCrSIQI.js} +10 -142
  26. package/dist/doctor-contract-api.js +5 -5
  27. package/dist/{dynamic-tools-BwpvTxaX.js → dynamic-tools-D-JBoaLt.js} +66 -70
  28. package/dist/{effective-mcp-catalog-CY9Jn4bA.js → effective-mcp-catalog-J_5Ep5Um.js} +3 -3
  29. package/dist/{elicitation-input-DMkeki8d.js → elicitation-input-DPoK8F7w.js} +8 -22
  30. package/dist/ephemeral-turn-DSwzP8YY.js +101 -0
  31. package/dist/{event-projector-assistant-message-B9kp6iGC.js → event-projector-assistant-message-BmBM4qBV.js} +12 -25
  32. package/dist/event-projector-usage-CIyrYYid.js +102 -0
  33. package/dist/{harness-Czh2Sdoc.js → harness-FR6eQgyO.js} +31 -24
  34. package/dist/harness.js +1 -1
  35. package/dist/history-rejection-B4nOXNXF.js +13 -0
  36. package/dist/incognito-session-uhrBF6wJ.js +15 -0
  37. package/dist/index.js +411 -2875
  38. package/dist/{isolated-completion-CRh-51AK.js → isolated-completion-DHBefrzg.js} +7 -4
  39. package/dist/launch-args-RXQwn8zV.js +90 -0
  40. package/dist/{managed-binary-DcpnJF9x.js → managed-binary-DrjjRRUD.js} +4 -103
  41. package/dist/managed-thread-store-D1t5jh3G.js +66 -0
  42. package/dist/media-understanding-provider.js +4 -1
  43. package/dist/{model-catalog-DT5vo6qo.js → model-catalog-B_6M04Wo.js} +6 -5
  44. package/dist/{models-CcrgSMQR.js → models-P9k2qAof.js} +3 -3
  45. package/dist/native-execution-policy-umd0tgh4.js +128 -0
  46. package/dist/{native-subagent-monitor-B3bvQGcg.js → native-subagent-monitor-BbCUKRwC.js} +69 -42
  47. package/dist/node-cli-sessions-rj0ysJwM.js +527 -0
  48. package/dist/{node-exec-server.runtime-nfbUOtUB.js → node-exec-server.runtime-BY_ctYnT.js} +53 -22
  49. package/dist/plan-BMJdMOEF.js +711 -0
  50. package/dist/plugin-activation-BQK-f5sV.js +133 -0
  51. package/dist/{thread-resume-BLgqkUc1.js → plugin-app-cache-key-CdSQzWyX.js} +4 -52
  52. package/dist/{plugin-approval-roundtrip-aQVdyL5g.js → plugin-approval-roundtrip-DeW95wB5.js} +1 -1
  53. package/dist/plugin-inventory-CoRCzWW4.js +325 -0
  54. package/dist/plugin-marketplace-discovery-3akBizzF.js +134 -0
  55. package/dist/{plugin-metadata-cache-BwCLTY_U.js → plugin-metadata-cache-DgNfRAGA.js} +13 -9
  56. package/dist/protocol-CAAcVIKF.js +275 -0
  57. package/dist/{provider-capabilities-BpG9Ltc5.js → provider-capabilities-W4tfK5Y5.js} +2 -2
  58. package/dist/{rate-limits-Fx_l4eNa.js → rate-limits-Bqnx1N4z.js} +1 -1
  59. package/dist/request-CGvGOpeR.js +198 -0
  60. package/dist/{run-attempt-BzthFQSM.js → run-attempt-DwKds3DN.js} +589 -373
  61. package/dist/{runtime-artifact-Bh_gf6-t.js → runtime-artifact-T-NwqeSH.js} +27 -27
  62. package/dist/sandbox-guard-BcT66fWy.js +165 -0
  63. package/dist/{session-binding-4Ki04sW-.js → session-binding-CKSepwIC.js} +29 -47
  64. package/dist/{session-binding-record-CyaXZvTe.js → session-binding-record-CaZjYwNS.js} +11 -25
  65. package/dist/session-catalog-HaDcp7Sv.js +1533 -0
  66. package/dist/session-catalog-adoption-BKLtSrwi.js +251 -0
  67. package/dist/session-catalog-archive-D0i2pGj2.js +56 -0
  68. package/dist/session-catalog-home-id-D7-aLiNt.js +190 -0
  69. package/dist/session-catalog-node-adoption-BUuDYY8R.js +182 -0
  70. package/dist/session-catalog-node-continue-CBtc4wkI.js +238 -0
  71. package/dist/session-catalog-parsing-CdD3JhdM.js +280 -0
  72. package/dist/session-catalog-provenance-DkJHo735.js +124 -0
  73. package/dist/{session-cli-BjLhpmS1.js → session-cli-CbgaHh0f.js} +3 -2
  74. package/dist/{session-history-DWmMqiqW.js → session-history-Cz-tOOYj.js} +6 -3
  75. package/dist/{session-upstream-marker-DReTpGz6.js → session-history-import-DFN7sWRU.js} +5 -50
  76. package/dist/{session-history-read-LHldwvyh.js → session-history-read-cxPUxyVV.js} +21 -7
  77. package/dist/session-history-worker-runtime.js +18 -6
  78. package/dist/{session-history.worker-zZVcx0ME.js → session-history.worker-CNEvGaU5.js} +58 -51
  79. package/dist/session-history.worker.js +1 -1
  80. package/dist/{session-initialization-BCFVnLL4.js → session-initialization-Jo86C60I.js} +2 -2
  81. package/dist/{session-permission-policy-BaueHmSj.js → session-permission-policy-B22InTp_.js} +4 -7
  82. package/dist/{session-retirement-DNdmYdFc.js → session-retirement-BSNG_mhf.js} +6 -5
  83. package/dist/session-upstream-marker-D15C9NHp.js +46 -0
  84. package/dist/{settled-turn-context-BOM3Y1pl.js → settled-turn-context-Du6gdUDd.js} +9 -9
  85. package/dist/{settled-turn-finalizer-BI-b1sry.js → settled-turn-finalizer-BuLUrZl2.js} +7 -6
  86. package/dist/shared-client-CVhez2Uo.js +2911 -0
  87. package/dist/{side-question-B6DWAw1A.js → side-question-DLbr2vUU.js} +64 -169
  88. package/dist/source-Da-h6f7e.js +518 -0
  89. package/dist/thread-archive-guard-D1bP04Tf.js +53 -0
  90. package/dist/{thread-lifecycle-DPK30jad.js → thread-lifecycle-D1pzRwHB.js} +112 -616
  91. package/dist/{thread-ownership-CbucAmmp.js → thread-ownership-D6oASVRu.js} +13 -15
  92. package/dist/thread-policy-D8kI7yAO.js +54 -0
  93. package/dist/thread-resume-T5cveyxA.js +52 -0
  94. package/dist/timeout-BVw8aaM1.js +33 -0
  95. package/dist/{transcript-mirror-attestation-Byl34PC-.js → transcript-mirror-attestation-DibE0krH.js} +17 -4
  96. package/dist/{transcript-mirror-_njEB84z.js → transcript-mirror-t5TOccct.js} +50 -260
  97. package/dist/{transport-stdio-CzTngV0j.js → transport-stdio-BGjHoYLr.js} +73 -43
  98. package/dist/{upstream-session-fork-1fwbNKzQ.js → upstream-session-fork-De-sLJ2r.js} +26 -18
  99. package/dist/{usage-i9fv5-4m.js → usage-CPPTmBvZ.js} +4 -3
  100. package/dist/version-omm6IPI3.js +12 -0
  101. package/dist/{web-search-provider.runtime-DKQn67A7.js → web-search-provider.runtime-CSVgQL0w.js} +3 -3
  102. package/openclaw.plugin.json +22 -1
  103. package/package.json +4 -4
  104. package/dist/request-C8H22rPi.js +0 -475
  105. package/dist/session-catalog-B47uwekb.js +0 -3272
  106. package/dist/shared-client-CKhX2kFt.js +0 -7505
  107. package/dist/thread-policy-CTalhWFy.js +0 -105
  108. package/dist/{auth-binding-Ds_QVm-X.js → auth-binding-Co2Vfcf_.js} +1 -1
@@ -1,21 +1,26 @@
1
- import { l as sessionBindingIdentity } from "./session-binding-record-CyaXZvTe.js";
2
- import { A as resolveOpenClawExecPolicyForCodexAppServer, B as isJsonObject, D as isCodexSandboxExecServerEnabled, E as isCodexRemoteExecPlacementSandbox, O as readCodexPluginConfig, T as isCodexPairedNodeRemoteExecPlacementSandbox, d as shouldAutoApproveCodexAppServerApprovals, f as withMcpElicitationsApprovalPolicy, h as resolveCodexModelBackedReviewerPolicyContext, l as hasCodexMcpToolApprovalOverrides, m as canUseCodexModelBackedApprovalsReviewerForModel, r as resolveCodexAppServerHomeScope, y as readCodexRequirementsToml } from "./config-CyapYSji.js";
3
- import { B as isCodexAppServerIndeterminateRequestCancellationError, C as withLeasedCodexAppServerClientStartSelectionRetry, Kt as resolveCodexAppServerPreparedAuthHandoff, L as isCodexAppServerApprovalRequest, Lt as readRecentCodexRateLimits, Tt as ensureCodexAppServerClientRuntime, c as getLeasedSharedCodexAppServerClient, ct as createCodexElicitationResponse, et as assertCodexThreadForkResponse, it as readCodexDynamicToolCallParams, lt as handleDynamicToolCallWithTimeout, m as releaseCodexAppServerClientLease, ot as readCodexTurn, pt as resolveDynamicToolCallTimeoutMs, rt as assertCodexTurnStartResponse, yt as resolveCodexToolAbortTerminalReason } from "./shared-client-CKhX2kFt.js";
4
- import { l as resolveCodexSessionBinding } from "./session-binding-4Ki04sW-.js";
5
- import { d as unsubscribeCodexThreadBestEffort, h as isCodexNotificationForTurn, l as retireUnsafeCodexTurnClientBestEffort, o as interruptCodexTurnAndWaitBestEffort } from "./attempt-client-cleanup-Bp1ZOnk2.js";
6
- import { B as emitCodexNativePreToolUseFailureDiagnostic, Dt as refreshCodexPluginAppApprovalPolicy, E as resolveCodexAppServerRequestModelSelection, Et as mergeCodexThreadConfigs, I as buildCodexNativeHookRelayConfig, L as buildCodexNativeHookRelayDisabledConfig, N as CODEX_NATIVE_HOOK_RELAY_EVENTS, O as resolveCodexBindingModelProviderFallback, S as resolveCodexWebSearchPlan, T as resolveCodexAppServerModelProvider, a as readCodexSupportedReasoningEfforts, at as filterCodexDynamicTools, dt as resolveCodexDynamicToolsLoading, o as resolveCodexAppServerReasoningEffort, t as buildCodexTemporalAdditionalContext, v as buildCodexRuntimeThreadConfig, w as CODEX_NATIVE_PERSONALITY_NONE } from "./thread-lifecycle-DPK30jad.js";
7
- import { i as refreshCodexThreadPolicy, n as CodexThreadPolicyHandoffError, o as requireCodexSupervisionModelSelection, r as assertCodexSupervisionThreadLineage, s as resolveCodexBindingAppServerConnection } from "./thread-policy-CTalhWFy.js";
8
- import { s as resolveCodexNativeExecutionBlock } from "./request-C8H22rPi.js";
9
- import { n as formatCodexUsageLimitErrorMessage } from "./rate-limits-Fx_l4eNa.js";
10
- import { a as resolveCodexAppServerForModelProvider, i as resolveCodexSessionPermissionCwd, n as applyCodexSessionPermissionPolicy, r as resolveCodexEffectiveSessionPermissionPolicy, t as CODEX_SESSION_PERMISSION_EXEC_MODES } from "./session-permission-policy-BaueHmSj.js";
11
- import { C as shouldRequireCodexSandboxExecServerEnvironment, S as shouldEnableCodexAppServerNativeToolSurface, T as filterCodexVisionTools, a as emitDynamicToolStartedDiagnostic, b as resolveCodexNodePlacementToolConstructionPlan, c as ensureCodexSandboxExecServerEnvironment, d as CodexNativeToolLifecycleProjector, i as emitDynamicToolErrorDiagnostic, l as releaseCodexSandboxExecServerEnvironment, o as emitDynamicToolTerminalDiagnostic, r as routeCodexAppServerElicitationRequest, s as handleCodexAppServerApprovalRequest, t as createCodexDynamicToolBridge, v as resolveCodexExternalSandboxPolicyForOpenClawSandbox, x as resolveCodexSandboxEnvironmentSelection, y as resolveCodexMessageToolProvider } from "./dynamic-tools-BwpvTxaX.js";
12
- import { n as resolveCodexProviderWebSearchSupportForClient } from "./provider-capabilities-BpG9Ltc5.js";
1
+ import { l as sessionBindingIdentity } from "./session-binding-record-CaZjYwNS.js";
2
+ import { b as readCodexRequirementsToml, c as hasCodexMcpToolApprovalOverrides, d as withMcpElicitationsApprovalPolicy, i as resolveCodexAppServerHomeScope, m as resolveCodexModelBackedReviewerPolicyContext, u as shouldAutoApproveCodexAppServerApprovals } from "./config-options-jnIFvwxD.js";
3
+ import { b as isCodexSandboxExecServerEnabled, o as isJsonObject, v as isCodexPairedNodeRemoteExecPlacementSandbox, x as readCodexPluginConfig, y as isCodexRemoteExecPlacementSandbox } from "./protocol-CAAcVIKF.js";
4
+ import { D as handleDynamicToolCallWithTimeout, E as createCodexElicitationResponse, L as resolveCodexToolAbortTerminalReason, S as readCodexDynamicToolCallParams, i as isCodexAppServerApprovalRequest, j as resolveDynamicToolCallTimeoutMs, s as isCodexAppServerIndeterminateRequestCancellationError, v as assertCodexThreadForkResponse, x as assertCodexTurnStartResponse } from "./client-BEKu4yDx.js";
5
+ import { n as formatCodexUsageLimitErrorMessage } from "./rate-limits-Bqnx1N4z.js";
6
+ import { n as resolveOpenClawExecPolicyForCodexAppServer, t as canUseCodexModelBackedApprovalsReviewerForModel } from "./config-JDfTI4VI.js";
7
+ import { i as resolveCodexBindingAppServerConnection, r as requireCodexSupervisionModelSelection } from "./binding-connection-QqgcPCgk.js";
8
+ import { F as ensureCodexAppServerClientRuntime, Z as resolveCodexAppServerPreparedAuthHandoff, c as getLeasedSharedCodexAppServerClient, m as releaseCodexAppServerClientLease, q as readRecentCodexRateLimits, x as withLeasedCodexAppServerClientStartSelectionRetry } from "./shared-client-CVhez2Uo.js";
9
+ import { d as unsubscribeCodexThreadBestEffort, l as retireUnsafeCodexTurnClientBestEffort, o as interruptCodexTurnAndWaitBestEffort } from "./attempt-client-cleanup-D6cR54TV.js";
10
+ import { t as CodexEphemeralTurn } from "./ephemeral-turn-DSwzP8YY.js";
11
+ import { B as emitCodexNativePreToolUseFailureDiagnostic, E as resolveCodexAppServerRequestModelSelection, Et as refreshCodexPluginAppApprovalPolicy, I as buildCodexNativeHookRelayConfig, L as buildCodexNativeHookRelayDisabledConfig, N as CODEX_NATIVE_HOOK_RELAY_EVENTS, O as resolveCodexBindingModelProviderFallback, S as resolveCodexWebSearchPlan, T as resolveCodexAppServerModelProvider, Tt as mergeCodexThreadConfigs, a as readCodexSupportedReasoningEfforts, ct as resolveCodexDynamicToolsLoading, nt as filterCodexDynamicTools, o as resolveCodexAppServerReasoningEffort, t as buildCodexTemporalAdditionalContext, v as buildCodexRuntimeThreadConfig, w as CODEX_NATIVE_PERSONALITY_NONE } from "./thread-lifecycle-D1pzRwHB.js";
12
+ import { o as resolveCodexSessionBinding } from "./session-binding-CKSepwIC.js";
13
+ import { i as refreshCodexThreadPolicy, n as CodexThreadPolicyHandoffError, r as assertCodexSupervisionThreadLineage } from "./thread-policy-D8kI7yAO.js";
14
+ import { t as resolveCodexNativeExecutionBlock } from "./sandbox-guard-BcT66fWy.js";
15
+ import { C as shouldRequireCodexSandboxExecServerEnvironment, S as shouldEnableCodexAppServerNativeToolSurface, T as filterCodexVisionTools, a as emitDynamicToolStartedDiagnostic, b as resolveCodexNodePlacementToolConstructionPlan, c as ensureCodexSandboxExecServerEnvironment, d as CodexNativeToolLifecycleProjector, i as emitDynamicToolErrorDiagnostic, l as releaseCodexSandboxExecServerEnvironment, o as emitDynamicToolTerminalDiagnostic, r as routeCodexAppServerElicitationRequest, s as handleCodexAppServerApprovalRequest, t as createCodexDynamicToolBridge, v as resolveCodexExternalSandboxPolicyForOpenClawSandbox, x as resolveCodexSandboxEnvironmentSelection, y as resolveCodexMessageToolProvider } from "./dynamic-tools-D-JBoaLt.js";
16
+ import { n as resolveCodexProviderWebSearchSupportForClient } from "./provider-capabilities-W4tfK5Y5.js";
17
+ import { a as resolveCodexAppServerForModelProvider, i as resolveCodexSessionPermissionCwd, n as applyCodexSessionPermissionPolicy, r as resolveCodexEffectiveSessionPermissionPolicy, t as CODEX_SESSION_PERMISSION_EXEC_MODES } from "./session-permission-policy-B22InTp_.js";
13
18
  import { readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
14
19
  import { randomUUID } from "node:crypto";
15
20
  import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
16
- import { buildAgentHookContextChannelFields, embeddedAgentLog, formatErrorMessage, registerNativeHookRelay, resolveAgentDir as resolveAgentDir$1, resolveAttemptSpawnWorkspaceDir, resolveModelAuthMode, resolveSandboxContext, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
17
21
  import { isDeepStrictEqual } from "node:util";
18
22
  import { resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
23
+ import { buildAgentHookContextChannelFields, embeddedAgentLog, formatErrorMessage, registerNativeHookRelay, resolveAgentDir as resolveAgentDir$2, resolveAttemptSpawnWorkspaceDir, resolveModelAuthMode, resolveSandboxContext, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
19
24
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
20
25
  import { loadCodexBundleMcpApprovalConfig, resolveCodexMcpToolOverridesForAgent } from "openclaw/plugin-sdk/codex-mcp-projection";
21
26
  //#region extensions/codex/src/app-server/side-question.ts
@@ -227,10 +232,9 @@ async function runCodexAppServerSideQuestion(params, options) {
227
232
  };
228
233
  let client = await getLeasedSharedCodexAppServerClient(clientOptions);
229
234
  const clientLease = { client };
230
- const collector = new CodexSideQuestionCollector(params, () => readRecentCodexRateLimits(client));
235
+ let collector;
231
236
  const runAbortController = new AbortController();
232
237
  let nativeToolLifecycleProjector;
233
- const pendingNativeToolNotifications = [];
234
238
  const pendingNativePreToolUseFailures = [];
235
239
  let nativePreToolUseFailureFallbackActive = false;
236
240
  let nativeToolRunWasAbortedBeforeCleanup;
@@ -256,16 +260,6 @@ async function runCodexAppServerSideQuestion(params, options) {
256
260
  }
257
261
  flushPendingNativePreToolUseFailures();
258
262
  };
259
- const handleNotification = (notification) => {
260
- collector.handleNotification(notification);
261
- if (notification.method !== "item/started" && notification.method !== "item/completed" && notification.method !== "rawResponseItem/completed" && notification.method !== "turn/completed") return;
262
- if (!nativeToolLifecycleProjector) {
263
- pendingNativeToolNotifications.push(notification);
264
- return;
265
- }
266
- nativeToolLifecycleProjector.handleNotification(notification);
267
- };
268
- let removeNotificationHandler = client.addNotificationHandler(handleNotification);
269
263
  const abortFromUpstream = () => runAbortController.abort(params.opts?.abortSignal?.reason ?? "codex_side_question_abort");
270
264
  if (params.opts?.abortSignal?.aborted) abortFromUpstream();
271
265
  else params.opts?.abortSignal?.addEventListener("abort", abortFromUpstream, { once: true });
@@ -275,8 +269,8 @@ async function runCodexAppServerSideQuestion(params, options) {
275
269
  let policyWriteUncertain = false;
276
270
  let turnId;
277
271
  let sandboxEnvironment;
272
+ let sandboxDisconnectError;
278
273
  let sandboxEnvironmentClient;
279
- let removeRequestHandler;
280
274
  let nativeHookRelay;
281
275
  const activeDynamicToolCalls = /* @__PURE__ */ new Set();
282
276
  const releaseSandboxEnvironment = async () => {
@@ -298,7 +292,7 @@ async function runCodexAppServerSideQuestion(params, options) {
298
292
  timeoutMs: appServer.requestTimeoutMs,
299
293
  signal: runAbortController.signal,
300
294
  onExecutionDisconnect: (error) => {
301
- collector.reject(error);
295
+ sandboxDisconnectError = error;
302
296
  embeddedAgentLog.warn(error.message);
303
297
  runAbortController.abort("client_closed");
304
298
  }
@@ -348,7 +342,9 @@ async function runCodexAppServerSideQuestion(params, options) {
348
342
  } : {},
349
343
  config: params.cfg
350
344
  });
351
- const registerRequestHandler = (targetClient) => targetClient.addRequestHandler(async (request) => {
345
+ const handleServerRequest = async (request, _scope, requestSignal) => {
346
+ const signal = AbortSignal.any([requestSignal, runAbortController.signal]);
347
+ if (signal.aborted) return;
352
348
  if (!childThreadId || !turnId) return;
353
349
  if (request.method === "mcpServer/elicitation/request") {
354
350
  const approvalResult = await routeCodexAppServerElicitationRequest({
@@ -360,7 +356,7 @@ async function runCodexAppServerSideQuestion(params, options) {
360
356
  projectedMcpServers,
361
357
  getActiveMcpToolCall: (serverName) => nativeToolLifecycleProjector?.getActiveMcpToolCall(serverName),
362
358
  pluginAppPolicyContext,
363
- signal: runAbortController.signal
359
+ signal
364
360
  });
365
361
  return approvalResult.kind === "handled" ? approvalResult.response : createCodexElicitationResponse("decline", null, { message: "OpenClaw Codex side questions do not support interactive MCP input." });
366
362
  }
@@ -373,7 +369,7 @@ async function runCodexAppServerSideQuestion(params, options) {
373
369
  turnId,
374
370
  nativeHookRelay,
375
371
  autoApprove: autoApproveMcpTools,
376
- signal: runAbortController.signal,
372
+ signal,
377
373
  onNativeToolFailureDisposition: (itemId, disposition) => nativeToolLifecycleProjector?.recordApprovalFailureDisposition(itemId, disposition)
378
374
  });
379
375
  if (request.method !== "item/tool/call") return;
@@ -395,7 +391,7 @@ async function runCodexAppServerSideQuestion(params, options) {
395
391
  const toolCall = handleDynamicToolCallWithTimeout({
396
392
  call,
397
393
  toolBridge,
398
- signal: runAbortController.signal,
394
+ signal,
399
395
  timeoutMs,
400
396
  observeToolTerminal: sideRunParams.observeToolTerminal
401
397
  });
@@ -415,25 +411,20 @@ async function runCodexAppServerSideQuestion(params, options) {
415
411
  emitDynamicToolErrorDiagnostic({
416
412
  ...diagnosticContext,
417
413
  durationMs: Math.max(0, Date.now() - toolStartedAt),
418
- terminalReason: runAbortController.signal.aborted ? resolveCodexToolAbortTerminalReason(runAbortController.signal) : "failed"
414
+ terminalReason: signal.aborted ? resolveCodexToolAbortTerminalReason(signal) : "failed"
419
415
  });
420
416
  throw error;
421
417
  } finally {
422
418
  activeDynamicToolCalls.delete(toolCall);
423
419
  }
424
- });
425
- removeRequestHandler = registerRequestHandler(client);
426
- const rebindClientHandlers = (nextClient) => {
427
- removeRequestHandler?.();
428
- removeNotificationHandler();
420
+ };
421
+ const selectClient = (nextClient) => {
429
422
  client = nextClient;
430
423
  ensureCodexAppServerClientRuntime(client, {
431
424
  agentDir: params.agentDir,
432
425
  authProfileId: connection.requestAuthProfileId,
433
426
  config: params.cfg
434
427
  });
435
- removeNotificationHandler = client.addNotificationHandler(handleNotification);
436
- removeRequestHandler = registerRequestHandler(client);
437
428
  };
438
429
  const serviceTier = binding.serviceTier ?? appServer.serviceTier;
439
430
  const nativeHookRelayEvents = resolveCodexSideNativeHookRelayEvents({
@@ -548,6 +539,15 @@ async function runCodexAppServerSideQuestion(params, options) {
548
539
  }
549
540
  childThreadId = response.thread.id;
550
541
  childClient = forkClient;
542
+ collector = new CodexEphemeralTurn(forkClient, childThreadId, {
543
+ textMode: "last",
544
+ onRequest: handleServerRequest,
545
+ onAssistantMessageStart: async () => {
546
+ await params.opts?.onAssistantMessageStart?.();
547
+ },
548
+ onNotification: (notification) => nativeToolLifecycleProjector?.handleNotification(notification)
549
+ });
550
+ if (nativeHookRelay) collector.route.signal.addEventListener("abort", nativeHookRelay.unregister, { once: true });
551
551
  try {
552
552
  assertCurrentBinding();
553
553
  if (supervisionModelSelection && (response.model !== supervisionModelSelection.model || response.modelProvider !== supervisionModelSelection.modelProvider)) throw new Error("Codex supervised side thread did not preserve its native model and provider");
@@ -570,14 +570,14 @@ async function runCodexAppServerSideQuestion(params, options) {
570
570
  }
571
571
  return response.thread.id;
572
572
  }),
573
- onClientChange: rebindClientHandlers
573
+ onClientChange: selectClient
574
574
  });
575
575
  const effort = usesSupervisionConnection ? void 0 : resolveCodexAppServerReasoningEffort({
576
576
  thinkLevel: params.resolvedThinkLevel ?? "off",
577
577
  modelId: modelSelection.model,
578
578
  supportedReasoningEfforts: readCodexSupportedReasoningEfforts(params.runtimeModel?.compat)
579
579
  });
580
- turnId = assertCodexTurnStartResponse(await client.request("turn/start", {
580
+ const turnResponse = assertCodexTurnStartResponse(await client.request("turn/start", {
581
581
  threadId: sideThreadId,
582
582
  input: [{
583
583
  type: "text",
@@ -611,49 +611,59 @@ async function runCodexAppServerSideQuestion(params, options) {
611
611
  }).catch((error) => {
612
612
  if (isCodexAppServerIndeterminateRequestCancellationError(error)) turnId = "";
613
613
  throw error;
614
- })).turn.id;
614
+ }));
615
+ turnId = turnResponse.turn.id;
615
616
  assertCurrent();
616
- collector.setTurn(sideThreadId, turnId);
617
617
  nativeToolLifecycleProjector = new CodexNativeToolLifecycleProjector({
618
618
  ...sideRunParams,
619
619
  agentId: sessionAgentId
620
620
  }, sideThreadId, turnId, { runAbortSignal: runAbortController.signal });
621
621
  for (const failure of pendingNativePreToolUseFailures) nativeToolLifecycleProjector.recordPreToolUseFailure(failure);
622
622
  pendingNativePreToolUseFailures.length = 0;
623
- for (const notification of pendingNativeToolNotifications) nativeToolLifecycleProjector.handleNotification(notification);
624
- pendingNativeToolNotifications.length = 0;
625
- let text;
623
+ if (!collector) throw new Error("Codex side thread route was not reserved");
624
+ let result;
626
625
  try {
627
- text = await collector.wait({
626
+ result = await collector.wait(turnResponse.turn, {
628
627
  signal: runAbortController.signal,
629
- timeoutMs: SIDE_QUESTION_COMPLETION_TIMEOUT_MS
628
+ abortError: () => sandboxDisconnectError ?? /* @__PURE__ */ new Error("Codex /btw was aborted."),
629
+ timeout: {
630
+ ms: SIDE_QUESTION_COMPLETION_TIMEOUT_MS,
631
+ error: new CodexSideQuestionTimeoutError("Codex /btw timed out waiting for the side thread to finish.")
632
+ }
630
633
  });
631
634
  } catch (error) {
632
635
  if (error instanceof CodexSideQuestionTimeoutError && !runAbortController.signal.aborted) runAbortController.abort(error);
633
636
  throw error;
634
637
  }
635
- const trimmed = text.trim();
638
+ if (result.error || result.turn?.status === "failed") throw formatCodexErrorMessage(result.error ?? { error: {
639
+ message: result.turn?.error?.message ?? null,
640
+ codexErrorInfo: result.turn?.error?.codexErrorInfo ?? null
641
+ } }, readRecentCodexRateLimits(client));
642
+ if (result.turn?.status === "interrupted") throw new Error("Codex /btw side thread was interrupted.");
643
+ const trimmed = result.text;
636
644
  assertCurrent();
637
645
  if (!trimmed) throw new Error("Codex /btw completed without an answer.");
638
- return { text: trimmed };
646
+ return {
647
+ text: trimmed,
648
+ usage: result.usage
649
+ };
639
650
  } finally {
640
651
  try {
641
652
  const runWasAbortedBeforeCleanup = runAbortController.signal.aborted;
642
653
  nativeToolRunWasAbortedBeforeCleanup = runWasAbortedBeforeCleanup;
643
654
  params.opts?.abortSignal?.removeEventListener("abort", abortFromUpstream);
644
- removeRequestHandler?.();
645
655
  if (!runAbortController.signal.aborted) runAbortController.abort("codex_side_question_finished");
646
656
  await Promise.allSettled(activeDynamicToolCalls);
647
657
  try {
648
658
  await cleanupCodexSideThread(childClient ?? client, {
649
659
  threadId: childThreadId,
650
660
  turnId,
651
- interrupt: !collector.completed,
661
+ interrupt: !collector?.completed,
652
662
  timeoutMs: appServer.requestTimeoutMs
653
663
  });
654
664
  } finally {
655
665
  if (policyWriteUncertain && childClient) await retireUnsafeCodexTurnClientBestEffort(childClient, "side policy handoff");
656
- removeNotificationHandler();
666
+ collector?.route.release();
657
667
  try {
658
668
  nativeToolLifecycleProjector?.finalizeActive(runWasAbortedBeforeCleanup);
659
669
  } finally {
@@ -798,7 +808,7 @@ async function createCodexSideToolBridge(input) {
798
808
  exec: input.sessionPermissionPolicy && { mode: input.sessionPermissionPolicy.execMode },
799
809
  sessionPermissionPolicy: input.sessionPermissionPolicy,
800
810
  runId: input.runId,
801
- agentDir: input.params.agentDir ?? resolveAgentDir$1(input.params.cfg ?? {}, input.sessionAgentId),
811
+ agentDir: input.params.agentDir ?? resolveAgentDir$2(input.params.cfg ?? {}, input.sessionAgentId),
802
812
  workspaceDir: input.cwd,
803
813
  spawnWorkspaceDir: resolveAttemptSpawnWorkspaceDir({
804
814
  sandbox,
@@ -927,121 +937,6 @@ async function cleanupCodexSideThread(client, params) {
927
937
  timeoutMs: params.timeoutMs
928
938
  })) await retireUnsafeCodexTurnClientBestEffort(client, "side thread unsubscribe");
929
939
  }
930
- var CodexSideQuestionCollector = class {
931
- constructor(params, readRecentRateLimits) {
932
- this.params = params;
933
- this.readRecentRateLimits = readRecentRateLimits;
934
- this.pendingNotifications = [];
935
- this.assistantStarted = false;
936
- this.assistantText = "";
937
- this.completed = false;
938
- }
939
- setTurn(threadId, turnId) {
940
- this.threadId = threadId;
941
- this.turnId = turnId;
942
- const pending = this.pendingNotifications;
943
- this.pendingNotifications = [];
944
- for (const notification of pending) this.handleNotification(notification);
945
- }
946
- handleNotification(notification) {
947
- const params = isJsonObject(notification.params) ? notification.params : void 0;
948
- if (!params) return;
949
- if (!this.threadId || !this.turnId) {
950
- this.pendingNotifications.push(notification);
951
- return;
952
- }
953
- if (!isCodexNotificationForTurn(params, this.threadId, this.turnId)) return;
954
- if (notification.method === "item/agentMessage/delta") {
955
- this.appendAssistantDelta(params);
956
- return;
957
- }
958
- if (notification.method === "turn/completed") {
959
- this.completeFromTurn(params);
960
- return;
961
- }
962
- if (notification.method === "error" && params.willRetry !== true) this.reject(formatCodexErrorMessage(params, this.readRecentRateLimits()));
963
- }
964
- wait(options) {
965
- if (this.terminalError) return Promise.reject(this.terminalError);
966
- if (this.completed) return Promise.resolve(this.finalText ?? this.assistantText);
967
- if (options.signal?.aborted) return Promise.reject(/* @__PURE__ */ new Error("Codex /btw was aborted."));
968
- return new Promise((resolve, reject) => {
969
- let timeout;
970
- const cleanup = () => {
971
- if (timeout) {
972
- clearTimeout(timeout);
973
- timeout = void 0;
974
- }
975
- options.signal?.removeEventListener("abort", abort);
976
- };
977
- const abort = () => {
978
- cleanup();
979
- this.settle = void 0;
980
- reject(/* @__PURE__ */ new Error("Codex /btw was aborted."));
981
- };
982
- timeout = setTimeout(() => {
983
- cleanup();
984
- this.settle = void 0;
985
- reject(new CodexSideQuestionTimeoutError("Codex /btw timed out waiting for the side thread to finish."));
986
- }, Math.max(100, options.timeoutMs));
987
- timeout.unref?.();
988
- options.signal?.addEventListener("abort", abort, { once: true });
989
- this.settle = {
990
- resolve: (text) => {
991
- cleanup();
992
- resolve(text);
993
- },
994
- reject: (error) => {
995
- cleanup();
996
- reject(error);
997
- }
998
- };
999
- });
1000
- }
1001
- async appendAssistantDelta(params) {
1002
- const delta = readStringField(params, "delta") ?? "";
1003
- if (!delta) return;
1004
- if (!this.assistantStarted) {
1005
- this.assistantStarted = true;
1006
- await this.params.opts?.onAssistantMessageStart?.();
1007
- }
1008
- this.assistantText += delta;
1009
- }
1010
- completeFromTurn(params) {
1011
- const turn = readCodexTurn(params.turn);
1012
- if (!turn || turn.id !== this.turnId) return;
1013
- this.completed = true;
1014
- if (turn.status === "failed") {
1015
- this.reject(formatCodexUsageLimitErrorMessage({
1016
- message: turn.error?.message,
1017
- codexErrorInfo: turn.error?.codexErrorInfo,
1018
- rateLimits: this.readRecentRateLimits()
1019
- }) ?? turn.error?.message ?? "Codex /btw side thread failed.");
1020
- return;
1021
- }
1022
- if (turn.status === "interrupted") {
1023
- this.reject("Codex /btw side thread was interrupted.");
1024
- return;
1025
- }
1026
- const finalText = collectAssistantText(turn) || this.assistantText;
1027
- this.resolve(finalText);
1028
- }
1029
- resolve(text) {
1030
- this.finalText = text;
1031
- const settle = this.settle;
1032
- this.settle = void 0;
1033
- settle?.resolve(text);
1034
- }
1035
- reject(error) {
1036
- this.terminalError = error instanceof Error ? error : new Error(error);
1037
- const settle = this.settle;
1038
- this.settle = void 0;
1039
- settle?.reject(this.terminalError);
1040
- }
1041
- };
1042
- function collectAssistantText(turn) {
1043
- return (turn.items ?? []).filter((item) => item.type === "agentMessage" && typeof item.text === "string").map((item) => item.text.trim()).filter(Boolean).at(-1) ?? "";
1044
- }
1045
940
  function formatCodexErrorMessage(params, rateLimits) {
1046
941
  const error = isJsonObject(params.error) ? params.error : void 0;
1047
942
  const message = formatCodexUsageLimitErrorMessage({