@openclaw/codex 2026.7.2-beta.7 → 2026.8.1-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +2 -0
  2. package/dist/api.js +147 -0
  3. package/dist/app-server-policy-bg5QPSVP.js +25 -0
  4. package/dist/attempt-client-cleanup-URjUlCHg.js +735 -0
  5. package/dist/binding-connection-DAvZwp96.js +45 -0
  6. package/dist/{bounded-turn-D2ZAgZVz.js → bounded-turn-4BjrZEwW.js} +63 -56
  7. package/dist/{capabilities-BFDTVYr4.js → capabilities-CH3K57v4.js} +8 -2
  8. package/dist/cli-metadata.js +1 -1
  9. package/dist/{command-formatters-C336eRVS.js → command-formatters-D0nZ3qtd.js} +18 -18
  10. package/dist/{command-handlers-DAHUSry9.js → command-handlers-DC86lgT4.js} +507 -101
  11. package/dist/command-rpc-xUIIonsO.js +90 -0
  12. package/dist/{compact-D_uvHurS.js → compact-COqgBRny.js} +234 -214
  13. package/dist/{session-binding-BXpo9ymA.js → config-CpNeo5AE.js} +284 -1163
  14. package/dist/context-compaction-activity-BOeJf7yo.js +58 -0
  15. package/dist/{conversation-binding-data-BHRpYbX3.js → conversation-binding-data-CW2GuupV.js} +6 -10
  16. package/dist/doctor-contract-api.js +48 -50
  17. package/dist/{dynamic-tools-D2gYkSBO.js → dynamic-tools-fJZhl4CE.js} +3442 -1433
  18. package/dist/{effective-mcp-catalog-Bbd98Inw.js → effective-mcp-catalog-4YKn51aG.js} +20 -15
  19. package/dist/elicitation-input-DMkeki8d.js +71 -0
  20. package/dist/{event-projector-assistant-message-DTgnPPVF.js → event-projector-assistant-message-BwxV4d6N.js} +11 -23
  21. package/dist/{attempt-notifications-AP-a-Q5k.js → event-projector-usage-CLwNEJqW.js} +113 -29
  22. package/dist/harness-DoKQcF8n.js +258 -0
  23. package/dist/harness.js +2 -160
  24. package/dist/image-payload-sanitizer-CnfoUPCE.js +65 -0
  25. package/dist/index.js +730 -256
  26. package/dist/isolated-completion-DPMtlH9r.js +75 -0
  27. package/dist/local-runtime-attribution-B_2mnqhb.js +19 -0
  28. package/dist/managed-binary-By4FZC6i.js +212 -0
  29. package/dist/media-understanding-provider.js +5 -5
  30. package/dist/model-catalog-CmGoqVKB.js +48 -0
  31. package/dist/{models-BBMKU4jA.js → models-CZw1wClT.js} +12 -17
  32. package/dist/native-subagent-monitor-GGq3RnOo.js +3225 -0
  33. package/dist/node-exec-server.runtime-Bsu1LdFZ.js +192 -0
  34. package/dist/{plugin-app-cache-key-DztPafOA.js → plugin-app-cache-key-DMNQ8Zi8.js} +18 -6
  35. package/dist/plugin-approval-roundtrip-C75Yiiwc.js +95 -0
  36. package/dist/plugin-marketplace-discovery-CSWDkMrP.js +399 -0
  37. package/dist/{computer-use-CYEc8U3w.js → plugin-metadata-cache-BXH5NF-4.js} +109 -6
  38. package/dist/protocol-validators-VAVyEnDp.js +2399 -0
  39. package/dist/{rate-limits-CU-gVCCS.js → rate-limits-BI1dMHDG.js} +17 -35
  40. package/dist/{request-qKh331yu.js → request-DSK0W6YI.js} +3 -3
  41. package/dist/{run-attempt-CY9WlDLc.js → run-attempt-BV3HzuCf.js} +3416 -7194
  42. package/dist/{runtime-artifact-CmtG_t1L.js → runtime-artifact-BvyT1uyd.js} +11 -29
  43. package/dist/{sandbox-guard-NuhpXmPB.js → sandbox-guard-C1qEeZ5C.js} +29 -30
  44. package/dist/session-binding-BTrLf9Qm.js +874 -0
  45. package/dist/{session-catalog-DyOgR4WH.js → session-catalog-ezP_UcRM.js} +1584 -1289
  46. package/dist/session-catalog-home-id-BNwAJ9D7.js +18 -0
  47. package/dist/{session-cli-2PZaFLRh.js → session-cli-B1hKvfkI.js} +20 -7
  48. package/dist/session-retirement-CE4iMiLh.js +36 -0
  49. package/dist/{session-upstream-marker-B6U7tLw5.js → session-upstream-marker-D_2npHlA.js} +1 -1
  50. package/dist/{settled-turn-finalizer-CXY2Z9dT.js → settled-turn-finalizer-Dx1onIqg.js} +40 -28
  51. package/dist/{shared-client-DTbvH-XV.js → shared-client-Dw-rzii0.js} +1315 -469
  52. package/dist/{side-question-_ulBk1AL.js → side-question-DbXkJZzg.js} +140 -69
  53. package/dist/{thread-lifecycle-DF53ogiA.js → thread-lifecycle-DKdrnTMX.js} +927 -768
  54. package/dist/thread-ownership-i2NBwDUL.js +92 -0
  55. package/dist/thread-resume-CdJk2Ehf.js +30 -0
  56. package/dist/transcript-mirror-BU0_LKAL.js +588 -0
  57. package/dist/{transport-stdio-DXgGZ7Ib.js → transport-stdio-DhoGy33Z.js} +13 -2
  58. package/dist/upstream-prompt-provenance-CFmsKwr9.js +39 -0
  59. package/dist/{upstream-session-fork-Dy4Xvuoj.js → upstream-session-fork-BDVJCLAD.js} +14 -8
  60. package/dist/{usage-CQ6GhD5-.js → usage-9dKJCgcy.js} +3 -3
  61. package/dist/{web-search-provider.runtime-CCFhg2z5.js → web-search-provider.runtime-DCdx4DGu.js} +8 -9
  62. package/openclaw.plugin.json +49 -4
  63. package/package.json +6 -5
  64. package/dist/app-server-policy-BSaO2JIT.js +0 -49
  65. package/dist/conversation-control-xsIeXbo4.js +0 -287
  66. package/dist/event-projector-usage-Xp4AlR2k.js +0 -86
  67. package/dist/notification-correlation-CU6_AnOb.js +0 -67
  68. package/dist/transcript-mirror-DzsdNCf5.js +0 -6924
@@ -1,12 +1,15 @@
1
- import { M as readRecentCodexRateLimits, W as isJsonObject, a as getLeasedSharedCodexAppServerClient, b as isCodexAppServerApprovalRequest, c as releaseCodexAppServerClientLease, h as withLeasedCodexAppServerClientStartSelectionRetry, k as ensureCodexAppServerClientRuntime, z as resolveCodexAppServerPreparedAuthHandoff } from "./shared-client-DTbvH-XV.js";
2
- import { A as resolveOpenClawExecPolicyForCodexAppServer, C as canUseCodexModelBackedApprovalsReviewerForModel, O as readCodexPluginConfig, T as resolveCodexModelBackedReviewerPolicyContext, d as sessionBindingIdentity, h as resolveCodexAppServerHomeScope, x as shouldAutoApproveCodexAppServerApprovals } from "./session-binding-BXpo9ymA.js";
3
- import { A as resolveCodexDynamicToolsLoading, C as resolveReasoningEffort, G as mergeCodexThreadConfigs, S as resolveCodexBindingModelProviderFallback, T as filterCodexDynamicTools, V as buildCodexPluginAppsConfigPatchFromPolicyContext, b as resolveCodexAppServerRequestModelSelection, g as resolveCodexWebSearchPlan, p as buildCodexRuntimeThreadConfig, v as CODEX_NATIVE_PERSONALITY_NONE, w as readCodexSupportedReasoningEfforts, y as resolveCodexAppServerModelProvider } from "./thread-lifecycle-DF53ogiA.js";
4
- import { S as readCodexTurn, h as assertCodexThreadForkResponse, v as assertCodexTurnStartResponse, y as readCodexDynamicToolCallParams } from "./transcript-mirror-DzsdNCf5.js";
5
- import { n as formatCodexUsageLimitErrorMessage } from "./rate-limits-CU-gVCCS.js";
6
- import { t as resolveCodexAppServerForModelProvider } from "./app-server-policy-BSaO2JIT.js";
7
- import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-NuhpXmPB.js";
8
- import { a as resolveCodexBindingAppServerConnection, i as requireCodexSupervisionModelSelection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-CU6_AnOb.js";
9
- import { C as filterToolsForVisionInputs, E as CODEX_NATIVE_HOOK_RELAY_EVENTS, F as handleDynamicToolCallWithTimeout, G as resolveCodexToolAbortTerminalReason, O as buildCodexNativeHookRelayConfig, T as CodexNativeToolLifecycleProjector, a as emitDynamicToolStartedDiagnostic, b as shouldEnableCodexAppServerNativeToolSurface, c as resolveCodexProviderWebSearchSupportForClient, i as emitDynamicToolErrorDiagnostic, j as emitCodexNativePreToolUseFailureDiagnostic, k as buildCodexNativeHookRelayDisabledConfig, n as handleCodexAppServerApprovalRequest, o as emitDynamicToolTerminalDiagnostic, r as handleCodexAppServerElicitationRequest, t as createCodexDynamicToolBridge, v as resolveCodexMessageToolProvider, z as resolveDynamicToolCallTimeoutMs } from "./dynamic-tools-D2gYkSBO.js";
1
+ import { A as resolveOpenClawExecPolicyForCodexAppServer, S as resolveCodexModelBackedReviewerPolicyContext, b as canUseCodexModelBackedApprovalsReviewerForModel, f as isCodexPairedNodeRemoteExecPlacementSandbox, h as readCodexPluginConfig, m as isCodexSandboxExecServerEnabled, p as isCodexRemoteExecPlacementSandbox, r as resolveCodexAppServerHomeScope, u as shouldAutoApproveCodexAppServerApprovals } from "./config-CpNeo5AE.js";
2
+ import { A as isCodexAppServerApprovalRequest, N as isCodexAppServerIndeterminateRequestCancellationError, Q as readRecentCodexRateLimits, V as createCodexElicitationResponse, W as ensureCodexAppServerClientRuntime, a as getLeasedSharedCodexAppServerClient, at as resolveCodexAppServerPreparedAuthHandoff, c as releaseCodexAppServerClientLease, h as withLeasedCodexAppServerClientStartSelectionRetry, ut as isJsonObject } from "./shared-client-Dw-rzii0.js";
3
+ import { d as sessionBindingIdentity } from "./session-binding-BTrLf9Qm.js";
4
+ import { d as unsubscribeCodexThreadBestEffort, h as isCodexNotificationForTurn, s as isCodexAlreadyTerminalInterruptError, u as retireUnsafeCodexTurnClientBestEffort } from "./attempt-client-cleanup-URjUlCHg.js";
5
+ import { l as readCodexTurn, o as assertCodexTurnStartResponse, r as assertCodexThreadForkResponse, s as readCodexDynamicToolCallParams } from "./protocol-validators-VAVyEnDp.js";
6
+ import { G as buildCodexPluginAppsConfigPatchFromPolicyContext, O as filterCodexDynamicTools, P as resolveCodexDynamicToolsLoading, Z as mergeCodexThreadConfigs, _ as resolveCodexAppServerRequestModelSelection, b as resolveReasoningEffort, f as resolveCodexWebSearchPlan, g as resolveCodexAppServerModelProvider, h as CODEX_NATIVE_PERSONALITY_NONE, l as buildCodexRuntimeThreadConfig, x as readCodexSupportedReasoningEfforts, y as resolveCodexBindingModelProviderFallback } from "./thread-lifecycle-DKdrnTMX.js";
7
+ import { n as formatCodexUsageLimitErrorMessage } from "./rate-limits-BI1dMHDG.js";
8
+ import { t as resolveCodexAppServerForModelProvider } from "./app-server-policy-bg5QPSVP.js";
9
+ import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-C1qEeZ5C.js";
10
+ import { n as resolveCodexBindingAppServerConnection, t as requireCodexSupervisionModelSelection } from "./binding-connection-DAvZwp96.js";
11
+ import { A as buildCodexNativeHookRelayConfig, C as shouldRequireCodexSandboxExecServerEnvironment, D as CodexNativeToolLifecycleProjector, L as handleDynamicToolCallWithTimeout, N as emitCodexNativePreToolUseFailureDiagnostic, O as CODEX_NATIVE_HOOK_RELAY_EVENTS, S as shouldEnableCodexAppServerNativeToolSurface, T as filterCodexVisionTools, V as resolveDynamicToolCallTimeoutMs, a as emitDynamicToolStartedDiagnostic, b as resolveCodexNodePlacementToolConstructionPlan, d as releaseCodexSandboxExecServerEnvironment, i as emitDynamicToolErrorDiagnostic, j as buildCodexNativeHookRelayDisabledConfig, l as resolveCodexProviderWebSearchSupportForClient, o as emitDynamicToolTerminalDiagnostic, q as resolveCodexToolAbortTerminalReason, r as routeCodexAppServerElicitationRequest, s as handleCodexAppServerApprovalRequest, t as createCodexDynamicToolBridge, u as ensureCodexSandboxExecServerEnvironment, v as resolveCodexExternalSandboxPolicyForOpenClawSandbox, x as resolveCodexSandboxEnvironmentSelection, y as resolveCodexMessageToolProvider } from "./dynamic-tools-fJZhl4CE.js";
12
+ import { readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
10
13
  import { buildAgentHookContextChannelFields, embeddedAgentLog, formatErrorMessage, registerNativeHookRelay, resolveAgentDir, resolveAttemptSpawnWorkspaceDir, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
11
14
  import { randomUUID } from "node:crypto";
12
15
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
@@ -54,6 +57,7 @@ async function runCodexAppServerSideQuestion(params, options) {
54
57
  config: params.cfg
55
58
  }));
56
59
  if (!binding?.threadId) throw new Error("Codex /btw needs an active Codex thread. Send a normal message first, then try /btw again.");
60
+ if (isCodexPairedNodeRemoteExecPlacementSandbox(params.sandbox)) throw new Error("Normal Codex turns are supported on paired devices, but /btw is not yet bound to the active placement.");
57
61
  const pluginConfig = readCodexPluginConfig(options.pluginConfig);
58
62
  const { sessionAgentId } = resolveSessionAgentIds({
59
63
  sessionKey: params.sessionKey,
@@ -79,6 +83,7 @@ async function runCodexAppServerSideQuestion(params, options) {
79
83
  authProfileStore: preparedRuntimeAuth.authProfileStore,
80
84
  agentDir: params.agentDir,
81
85
  homeScope: resolveCodexAppServerHomeScope({ appServer: pluginConfig.appServer }),
86
+ requirePreparedAuth: isCodexRemoteExecPlacementSandbox(params.sandbox),
82
87
  config: params.cfg,
83
88
  subscriptionProfileRequiredError: "Prepared Codex subscription route requires a scoped native OAuth or token profile.",
84
89
  subscriptionProfileUnusableError: `Prepared Codex auth profile "${preparedRuntimeAuth.plan.forwardedAuthProfileId}" is unusable.`
@@ -96,7 +101,7 @@ async function runCodexAppServerSideQuestion(params, options) {
96
101
  bindingModelProvider: binding.modelProvider
97
102
  });
98
103
  const modelSelection = resolveCodexAppServerRequestModelSelection({
99
- model: supervisionModelSelection?.model ?? params.model,
104
+ model: supervisionModelSelection?.model ?? options.runtimeModelId ?? params.model,
100
105
  modelProvider,
101
106
  authProfileId,
102
107
  authProfileStore: preparedRuntimeAuth.authProfileStore,
@@ -145,16 +150,29 @@ async function runCodexAppServerSideQuestion(params, options) {
145
150
  const sideRunParams = buildSideRunAttemptParams(effectiveParams, {
146
151
  cwd,
147
152
  authProfileId,
148
- runId
153
+ runId,
154
+ timeoutMs: appServer.requestTimeoutMs
155
+ });
156
+ const sandboxExecServerEnabled = isCodexSandboxExecServerEnabled(pluginConfig, params.sandbox);
157
+ const nativeToolSurfaceEnabled = shouldEnableCodexAppServerNativeToolSurface(sideRunParams, params.sandbox ?? void 0, {
158
+ agentId: sideRunParams.agentId,
159
+ sandboxExecServerEnabled
160
+ });
161
+ const sandboxEnvironmentRequired = shouldRequireCodexSandboxExecServerEnvironment({
162
+ sandbox: params.sandbox ?? void 0,
163
+ nativeToolSurfaceEnabled,
164
+ sandboxExecServerEnabled
149
165
  });
150
166
  const nativeExecutionBlock = resolveCodexNativeExecutionBlock({
151
167
  config: sideRunParams.config,
152
168
  sessionKey: sideRunParams.sandboxSessionKey?.trim() || sideRunParams.sessionKey,
153
169
  sessionId: sideRunParams.sessionId,
170
+ agentId: sideRunParams.agentId,
171
+ sandbox: params.sandbox,
172
+ sandboxEnvironmentSelected: sandboxEnvironmentRequired,
154
173
  surface: "/btw side-question mode"
155
174
  });
156
175
  if (nativeExecutionBlock) throw new Error(nativeExecutionBlock);
157
- const nativeToolSurfaceEnabled = shouldEnableCodexAppServerNativeToolSurface(sideRunParams);
158
176
  if (!nativeToolSurfaceEnabled) throw new Error("Codex-native /btw side-question mode is unavailable because the effective tool policy restricts Codex native tools for this session.");
159
177
  const clientOptions = {
160
178
  startOptions: appServer.start,
@@ -211,9 +229,38 @@ async function runCodexAppServerSideQuestion(params, options) {
211
229
  else params.opts?.abortSignal?.addEventListener("abort", abortFromUpstream, { once: true });
212
230
  let childThreadId;
213
231
  let turnId;
232
+ let sandboxEnvironment;
233
+ let sandboxEnvironmentClient;
214
234
  let removeRequestHandler;
215
235
  let nativeHookRelay;
216
236
  const activeDynamicToolCalls = /* @__PURE__ */ new Set();
237
+ const releaseSandboxEnvironment = async () => {
238
+ if (!sandboxEnvironment) return;
239
+ const environment = sandboxEnvironment;
240
+ sandboxEnvironment = void 0;
241
+ sandboxEnvironmentClient = void 0;
242
+ await releaseCodexSandboxExecServerEnvironment(params.sandbox, environment);
243
+ };
244
+ const ensureSandboxEnvironment = async (targetClient) => {
245
+ if (!sandboxEnvironmentRequired || sandboxEnvironmentClient === targetClient) return;
246
+ await releaseSandboxEnvironment();
247
+ const environment = await ensureCodexSandboxExecServerEnvironment({
248
+ client: targetClient,
249
+ sandbox: params.sandbox ?? null,
250
+ runtime: options.runtime,
251
+ appServerStartOptions: appServer.start,
252
+ timeoutMs: appServer.requestTimeoutMs,
253
+ signal: runAbortController.signal,
254
+ onExecutionDisconnect: (error) => {
255
+ collector.reject(error);
256
+ embeddedAgentLog.warn(error.message);
257
+ runAbortController.abort("client_closed");
258
+ }
259
+ });
260
+ if (!environment) throw new Error("Codex app-server did not register an OpenClaw sandbox exec-server environment.");
261
+ sandboxEnvironment = environment;
262
+ sandboxEnvironmentClient = targetClient;
263
+ };
217
264
  try {
218
265
  const modelScopedAppServer = resolveCodexAppServerForModelProvider({
219
266
  appServer,
@@ -261,14 +308,17 @@ async function runCodexAppServerSideQuestion(params, options) {
261
308
  });
262
309
  const registerRequestHandler = (targetClient) => targetClient.addRequestHandler(async (request) => {
263
310
  if (!childThreadId || !turnId) return;
264
- if (request.method === "mcpServer/elicitation/request") return handleCodexAppServerElicitationRequest({
265
- requestParams: request.params,
266
- paramsForRun: sideRunParams,
267
- threadId: childThreadId,
268
- turnId,
269
- pluginAppPolicyContext: binding.pluginAppPolicyContext,
270
- signal: runAbortController.signal
271
- });
311
+ if (request.method === "mcpServer/elicitation/request") {
312
+ const approvalResult = await routeCodexAppServerElicitationRequest({
313
+ requestParams: request.params,
314
+ paramsForRun: sideRunParams,
315
+ threadId: childThreadId,
316
+ turnId,
317
+ pluginAppPolicyContext: binding.pluginAppPolicyContext,
318
+ signal: runAbortController.signal
319
+ });
320
+ return approvalResult.kind === "handled" ? approvalResult.response : createCodexElicitationResponse("decline", null, { message: "OpenClaw Codex side questions do not support interactive MCP input." });
321
+ }
272
322
  if (request.method === "item/tool/requestUserInput") return isSideUserInputRequest(request.params, childThreadId, turnId) ? emptySideUserInputResponse() : void 0;
273
323
  if (isCodexAppServerApprovalRequest(request.method)) return handleCodexAppServerApprovalRequest({
274
324
  method: request.method,
@@ -367,6 +417,7 @@ async function runCodexAppServerSideQuestion(params, options) {
367
417
  completionTimeoutMs: Math.max(appServer.turnCompletionIdleTimeoutMs, SIDE_QUESTION_COMPLETION_TIMEOUT_MS),
368
418
  loopDetectionPreToolUseRelay: appServer.loopDetectionPreToolUseRelay,
369
419
  signal: runAbortController.signal,
420
+ hostCapabilities: sideRunParams.hostCapabilities,
370
421
  onPreToolUseFailure: (failure) => {
371
422
  if (nativePreToolUseFailureFallbackActive) emitNativePreToolUseFailure(failure);
372
423
  else if (nativeToolLifecycleProjector) nativeToolLifecycleProjector.recordPreToolUseFailure(failure, nativeToolRunWasAbortedBeforeCleanup);
@@ -377,8 +428,7 @@ async function runCodexAppServerSideQuestion(params, options) {
377
428
  relay: nativeHookRelay,
378
429
  events: nativeHookRelayEvents,
379
430
  hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec,
380
- clearOmittedEvents: true,
381
- loopDetectionPreToolUseRelay: appServer.loopDetectionPreToolUseRelay
431
+ clearOmittedEvents: true
382
432
  }) : options.nativeHookRelay?.enabled === false ? buildCodexNativeHookRelayDisabledConfig() : void 0;
383
433
  const runtimeThreadConfig = buildCodexRuntimeThreadConfig(webSearchPlan.threadConfig, {
384
434
  nativeCodeModeEnabled: nativeToolSurfaceEnabled,
@@ -388,21 +438,25 @@ async function runCodexAppServerSideQuestion(params, options) {
388
438
  const forkResponse = assertCodexThreadForkResponse(await withLeasedCodexAppServerClientStartSelectionRetry({
389
439
  lease: clientLease,
390
440
  options: clientOptions,
391
- signal: params.opts?.abortSignal,
392
- run: async (forkClient, requestOptions) => await forkCodexSideThread(forkClient, {
393
- threadId: binding.threadId,
394
- model: modelSelection.model,
395
- ...modelSelection.modelProvider ? { modelProvider: modelSelection.modelProvider } : {},
396
- cwd,
397
- approvalPolicy,
398
- approvalsReviewer: modelScopedAppServer.approvalsReviewer,
399
- ...modelScopedAppServer.networkProxy ? {} : { sandbox },
400
- ...serviceTier ? { serviceTier } : {},
401
- config: threadConfig,
402
- developerInstructions: SIDE_DEVELOPER_INSTRUCTIONS,
403
- ephemeral: true,
404
- threadSource: "user"
405
- }, requestOptions),
441
+ signal: runAbortController.signal,
442
+ run: async (forkClient, requestOptions) => {
443
+ await ensureSandboxEnvironment(forkClient);
444
+ const executionCwd = sandboxEnvironment?.cwd ?? cwd;
445
+ return await forkCodexSideThread(forkClient, {
446
+ threadId: binding.threadId,
447
+ model: modelSelection.model,
448
+ ...modelSelection.modelProvider ? { modelProvider: modelSelection.modelProvider } : {},
449
+ cwd: executionCwd,
450
+ approvalPolicy,
451
+ approvalsReviewer: modelScopedAppServer.approvalsReviewer,
452
+ ...sandboxEnvironment || modelScopedAppServer.networkProxy ? {} : { sandbox },
453
+ ...serviceTier ? { serviceTier } : {},
454
+ config: threadConfig,
455
+ developerInstructions: SIDE_DEVELOPER_INSTRUCTIONS,
456
+ ephemeral: true,
457
+ threadSource: "user"
458
+ }, requestOptions);
459
+ },
406
460
  onClientChange: rebindClientHandlers
407
461
  }));
408
462
  childThreadId = forkResponse.thread.id;
@@ -412,7 +466,7 @@ async function runCodexAppServerSideQuestion(params, options) {
412
466
  items: [sideBoundaryPromptItem()]
413
467
  }, {
414
468
  timeoutMs: appServer.requestTimeoutMs,
415
- signal: params.opts?.abortSignal
469
+ signal: runAbortController.signal
416
470
  });
417
471
  const effort = usesSupervisionConnection ? void 0 : resolveReasoningEffort(params.resolvedThinkLevel ?? "off", modelSelection.model, readCodexSupportedReasoningEfforts(params.runtimeModel?.compat));
418
472
  turnId = assertCodexTurnStartResponse(await client.request("turn/start", {
@@ -422,7 +476,11 @@ async function runCodexAppServerSideQuestion(params, options) {
422
476
  text: params.question.trim(),
423
477
  text_elements: []
424
478
  }],
425
- cwd,
479
+ ...sandboxEnvironment ? {
480
+ cwd: sandboxEnvironment.cwd,
481
+ sandboxPolicy: resolveCodexExternalSandboxPolicyForOpenClawSandbox(params.sandbox ?? void 0),
482
+ environments: resolveCodexSandboxEnvironmentSelection(sandboxEnvironment, nativeToolSurfaceEnabled)
483
+ } : { cwd },
426
484
  model: modelSelection.model,
427
485
  ...usesSupervisionConnection ? {} : { personality: CODEX_NATIVE_PERSONALITY_NONE },
428
486
  ...serviceTier ? { serviceTier } : {},
@@ -439,7 +497,10 @@ async function runCodexAppServerSideQuestion(params, options) {
439
497
  }
440
498
  }, {
441
499
  timeoutMs: appServer.requestTimeoutMs,
442
- signal: params.opts?.abortSignal
500
+ signal: runAbortController.signal
501
+ }).catch((error) => {
502
+ if (isCodexAppServerIndeterminateRequestCancellationError(error)) turnId = "";
503
+ throw error;
443
504
  })).turn.id;
444
505
  collector.setTurn(childThreadId, turnId);
445
506
  nativeToolLifecycleProjector = new CodexNativeToolLifecycleProjector({
@@ -453,7 +514,7 @@ async function runCodexAppServerSideQuestion(params, options) {
453
514
  let text;
454
515
  try {
455
516
  text = await collector.wait({
456
- signal: params.opts?.abortSignal,
517
+ signal: runAbortController.signal,
457
518
  timeoutMs: Math.max(appServer.turnCompletionIdleTimeoutMs, SIDE_QUESTION_COMPLETION_TIMEOUT_MS)
458
519
  });
459
520
  } catch (error) {
@@ -488,8 +549,12 @@ async function runCodexAppServerSideQuestion(params, options) {
488
549
  }
489
550
  } finally {
490
551
  flushPendingNativePreToolUseFailures();
491
- releaseCodexAppServerClientLease(clientLease);
492
- nativeHookRelay?.unregister();
552
+ try {
553
+ await releaseSandboxEnvironment();
554
+ } finally {
555
+ releaseCodexAppServerClientLease(clientLease);
556
+ nativeHookRelay?.unregister();
557
+ }
493
558
  }
494
559
  }
495
560
  }
@@ -515,6 +580,8 @@ function registerCodexSideNativeHookRelay(params) {
515
580
  completionTimeoutMs: params.completionTimeoutMs
516
581
  }),
517
582
  signal: params.signal,
583
+ runBeforeToolCall: params.hostCapabilities.runBeforeToolCall,
584
+ assertActive: params.hostCapabilities.assertActive,
518
585
  onPreToolUseFailure: params.onPreToolUseFailure,
519
586
  command: { timeoutMs: params.options.gatewayTimeoutMs }
520
587
  });
@@ -535,6 +602,8 @@ function buildSideRunAttemptParams(params, options) {
535
602
  id: params.model,
536
603
  provider: params.provider
537
604
  },
605
+ prompt: params.question,
606
+ timeoutMs: options.timeoutMs,
538
607
  sessionId: params.sessionId,
539
608
  sessionFile: params.sessionFile,
540
609
  sessionKey: params.sessionKey,
@@ -568,6 +637,7 @@ function buildSideRunAttemptParams(params, options) {
568
637
  authStorage: params.preparedRuntimeAuth.authStorage,
569
638
  authProfileStore: params.preparedRuntimeAuth.authProfileStore,
570
639
  modelRegistry: params.preparedRuntimeAuth.modelRegistry,
640
+ preparedModelRuntime: params.preparedModelRuntime,
571
641
  ...params.preparedRuntimeAuth.resolvedApiKey ? { resolvedApiKey: params.preparedRuntimeAuth.resolvedApiKey } : {},
572
642
  runId: options.runId,
573
643
  abortSignal: params.opts?.abortSignal,
@@ -575,7 +645,9 @@ function buildSideRunAttemptParams(params, options) {
575
645
  if (event.stream === "approval") params.opts?.onApprovalEvent?.(event.data);
576
646
  },
577
647
  onBlockReply: params.opts?.onBlockReply,
578
- onPartialReply: params.opts?.onPartialReply
648
+ onPartialReply: params.opts?.onPartialReply,
649
+ hostCapabilities: params.hostCapabilities,
650
+ sandbox: params.sandbox
579
651
  };
580
652
  }
581
653
  async function createCodexSideToolBridge(input) {
@@ -585,15 +657,17 @@ async function createCodexSideToolBridge(input) {
585
657
  };
586
658
  const messageToolProvider = resolveCodexMessageToolProvider(input.params);
587
659
  let tools = [];
660
+ const webFetchHostnameAllowlistRef = {};
588
661
  if (supportsModelTools(runtimeModel)) {
589
662
  const createOpenClawCodingTools = (await import("openclaw/plugin-sdk/agent-harness")).createOpenClawCodingTools;
590
663
  const sandboxSessionKey = input.params.sandboxSessionKey?.trim() || input.params.sessionKey?.trim() || input.params.sessionId || input.sessionAgentId;
591
- const sandbox = await resolveSandboxContext({
664
+ const sandbox = input.params.sandbox !== void 0 ? input.params.sandbox : await resolveSandboxContext({
592
665
  config: input.params.cfg,
593
666
  sessionKey: sandboxSessionKey,
594
667
  workspaceDir: input.cwd
595
668
  });
596
- tools = filterToolsForVisionInputs(filterCodexDynamicTools(createOpenClawCodingTools({
669
+ const toolConstructionPlan = resolveCodexNodePlacementToolConstructionPlan(sandbox, input.nativeToolSurfaceEnabled);
670
+ tools = filterCodexVisionTools(filterCodexDynamicTools(createOpenClawCodingTools({
597
671
  agentId: input.sessionAgentId,
598
672
  sessionKey: sandboxSessionKey,
599
673
  runSessionKey: input.params.sessionKey && input.params.sessionKey !== sandboxSessionKey ? input.params.sessionKey : void 0,
@@ -606,6 +680,7 @@ async function createCodexSideToolBridge(input) {
606
680
  resolvedWorkspace: input.params.workspaceDir ?? input.cwd
607
681
  }),
608
682
  config: input.params.cfg,
683
+ preparedModelRuntime: input.params.preparedModelRuntime,
609
684
  abortSignal: input.signal,
610
685
  modelProvider: runtimeModel.provider,
611
686
  modelId: input.params.model,
@@ -614,6 +689,7 @@ async function createCodexSideToolBridge(input) {
614
689
  modelContextWindowTokens: runtimeModel.contextWindow,
615
690
  modelAuthMode: resolveModelAuthMode(runtimeModel.provider, input.params.cfg, void 0, { workspaceDir: input.cwd }),
616
691
  suppressManagedWebSearch: false,
692
+ webFetchHostnameAllowlistRef,
617
693
  ...input.params.messageProvider || input.params.messageChannel ? {
618
694
  messageProvider: messageToolProvider,
619
695
  toolPolicyMessageProvider: input.params.messageProvider ?? input.params.messageChannel
@@ -642,12 +718,13 @@ async function createCodexSideToolBridge(input) {
642
718
  currentChannelId: input.params.currentChannelId
643
719
  }).channelId,
644
720
  sandbox,
721
+ ...toolConstructionPlan ? { toolConstructionPlan } : {},
645
722
  emitBeforeToolCallDiagnostics: false,
646
723
  modelHasVision: runtimeModel.input?.includes("image") ?? false,
647
724
  requireExplicitMessageTarget: true
648
725
  }), input.pluginConfig), {
649
726
  modelHasVision: runtimeModel.input?.includes("image") ?? false,
650
- hasInboundImages: false
727
+ nativeImageInspectionEnabled: input.nativeToolSurfaceEnabled
651
728
  });
652
729
  }
653
730
  const requestedWebSearchPlan = resolveCodexWebSearchPlan({
@@ -656,11 +733,12 @@ async function createCodexSideToolBridge(input) {
656
733
  nativeProviderWebSearchSupport: input.nativeProviderWebSearchSupport,
657
734
  webSearchAllowed: tools.some((tool) => tool.name === "web_search")
658
735
  });
736
+ webFetchHostnameAllowlistRef.value = requestedWebSearchPlan.webFetchHostnameAllowlist;
659
737
  const webSearchPlan = requestedWebSearchPlan.kind === "managed" ? resolveCodexWebSearchPlan({
660
738
  config: input.params.cfg,
661
739
  webSearchAllowed: false
662
740
  }) : requestedWebSearchPlan;
663
- const exposedTools = tools.filter((tool) => tool.name !== "web_search" && tool.name !== "computer");
741
+ const exposedTools = input.params.hostCapabilities.bindToolSurface(tools.filter((tool) => tool.name !== "web_search" && tool.name !== "computer"), { cwd: input.cwd });
664
742
  const hookChannelFields = buildAgentHookContextChannelFields({
665
743
  sessionKey: input.params.sessionKey,
666
744
  messageChannel: input.params.messageChannel,
@@ -716,19 +794,22 @@ function sideBoundaryPromptItem() {
716
794
  }
717
795
  async function cleanupCodexSideThread(client, params) {
718
796
  if (!params.threadId) return;
719
- if (params.interrupt && params.turnId) try {
797
+ if (params.interrupt && params.turnId !== void 0) try {
720
798
  await client.request("turn/interrupt", {
721
799
  threadId: params.threadId,
722
800
  turnId: params.turnId
723
801
  }, { timeoutMs: params.timeoutMs });
724
802
  } catch (error) {
725
- embeddedAgentLog.debug("codex /btw side thread interrupt cleanup failed", { error });
726
- }
727
- try {
728
- await client.request("thread/unsubscribe", { threadId: params.threadId }, { timeoutMs: params.timeoutMs });
729
- } catch (error) {
730
- embeddedAgentLog.debug("codex /btw side thread unsubscribe cleanup failed", { error });
803
+ if (!isCodexAlreadyTerminalInterruptError(error)) {
804
+ embeddedAgentLog.debug("codex /btw side thread interrupt cleanup failed", { error });
805
+ await retireUnsafeCodexTurnClientBestEffort(client, "side turn interrupt");
806
+ return;
807
+ }
731
808
  }
809
+ if (!await unsubscribeCodexThreadBestEffort(client, {
810
+ threadId: params.threadId,
811
+ timeoutMs: params.timeoutMs
812
+ })) await retireUnsafeCodexTurnClientBestEffort(client, "side thread unsubscribe");
732
813
  }
733
814
  var CodexSideQuestionCollector = class {
734
815
  constructor(params, readRecentRateLimits) {
@@ -753,7 +834,7 @@ var CodexSideQuestionCollector = class {
753
834
  this.pendingNotifications.push(notification);
754
835
  return;
755
836
  }
756
- if (!isNotificationForTurn(params, this.threadId, this.turnId)) return;
837
+ if (!isCodexNotificationForTurn(params, this.threadId, this.turnId)) return;
757
838
  if (notification.method === "item/agentMessage/delta") {
758
839
  this.appendAssistantDelta(params);
759
840
  return;
@@ -802,7 +883,7 @@ var CodexSideQuestionCollector = class {
802
883
  });
803
884
  }
804
885
  async appendAssistantDelta(params) {
805
- const delta = readString(params, "delta") ?? "";
886
+ const delta = readStringField(params, "delta") ?? "";
806
887
  if (!delta) return;
807
888
  if (!this.assistantStarted) {
808
889
  this.assistantStarted = true;
@@ -845,23 +926,13 @@ var CodexSideQuestionCollector = class {
845
926
  function collectAssistantText(turn) {
846
927
  return (turn.items ?? []).filter((item) => item.type === "agentMessage" && typeof item.text === "string").map((item) => item.text.trim()).filter(Boolean).at(-1) ?? "";
847
928
  }
848
- function isNotificationForTurn(params, threadId, turnId) {
849
- return readCodexNotificationThreadId(params) === threadId && readNotificationTurnId(params) === turnId;
850
- }
851
- function readNotificationTurnId(record) {
852
- return readCodexNotificationTurnId(record);
853
- }
854
- function readString(record, key) {
855
- const value = record[key];
856
- return typeof value === "string" ? value : void 0;
857
- }
858
929
  function formatCodexErrorMessage(params, rateLimits) {
859
930
  const error = isJsonObject(params.error) ? params.error : void 0;
860
931
  const message = formatCodexUsageLimitErrorMessage({
861
- message: error ? readString(error, "message") : void 0,
932
+ message: error ? readStringField(error, "message") : void 0,
862
933
  codexErrorInfo: error?.codexErrorInfo,
863
934
  rateLimits
864
- }) ?? (error ? readString(error, "message") ?? readString(error, "error") : void 0) ?? readString(params, "message") ?? "Codex /btw side thread failed.";
935
+ }) ?? (error ? readStringField(error, "message") ?? readStringField(error, "error") : void 0) ?? readStringField(params, "message") ?? "Codex /btw side thread failed.";
865
936
  return new Error(formatErrorMessage(message));
866
937
  }
867
938
  //#endregion