@openclaw/acpx 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.
@@ -1,14 +1,17 @@
1
- import { d as withAcpxLeaseEnvironment, i as createAcpxProcessLeaseId, o as hashAcpxProcessCommand, t as ACPX_PROBE_LEASE_SESSION_KEY, u as readAcpxProcessLeaseIdentity, v as splitCommandParts } from "./process-lease-Cwvj7WGe.js";
1
+ import { _ as splitCommandParts, a as hashAcpxProcessCommand, g as renderAgentCommand, l as readAcpxProcessLeaseIdentity, t as ACPX_PROBE_LEASE_SESSION_KEY, u as withAcpxLeaseArgs } from "./process-lease-B83BGiLj.js";
2
2
  import { AcpRuntimeError } from "./runtime-api.js";
3
3
  import { t as resolveAcpxSessionResource } from "./session-resource-UWe7qD3m.js";
4
- import { a as CODEX_ACP_PACKAGE, i as isOpenClawLeaseAwareAcpxProcessCommand, n as cleanupOpenClawOwnedAcpxPendingLease, o as OPENCLAW_CODEX_CONFIG_ARG, r as cleanupOpenClawOwnedAcpxProcessTree } from "./service-COMUTA5A.js";
4
+ import { a as CODEX_ACP_PACKAGE, i as isOpenClawLeaseAwareAcpxProcessCommand, n as cleanupOpenClawOwnedAcpxPendingLease, o as OPENCLAW_CODEX_CONFIG_ARG, r as cleanupOpenClawOwnedAcpxProcessTree } from "./service-BAf6nuci.js";
5
5
  import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
6
6
  import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import path, { resolve } from "node:path";
8
8
  import fs from "node:fs/promises";
9
+ import { randomUUID } from "node:crypto";
9
10
  import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
10
11
  import { AsyncLocalStorage } from "node:async_hooks";
12
+ import { isDeepStrictEqual } from "node:util";
11
13
  import { ACPX_BACKEND_ID, AcpxRuntime as AcpxRuntime$1, createAcpRuntime, createAgentRegistry, createFileSessionStore, decodeAcpxRuntimeHandleState, decodeAcpxRuntimeHandleState as decodeAcpxRuntimeHandleState$1, encodeAcpxRuntimeHandleState, isRequestedModelUnsupportedError } from "acpx/runtime";
14
+ import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
12
15
  import { redactSensitiveText } from "openclaw/plugin-sdk/security-runtime";
13
16
  //#region extensions/acpx/src/session-owner.ts
14
17
  function requireAcpxOwnerMigration(sessionKey) {
@@ -48,17 +51,11 @@ function toAcpxResourceInput(input) {
48
51
  const ACPX_PLUGIN_TOOLS_MCP_SERVER_NAME = "openclaw-plugin-tools";
49
52
  const ACPX_OPENCLAW_TOOLS_MCP_SERVER_NAME = "openclaw-tools";
50
53
  const OPENCLAW_TOOLS_MCP_AGENT_SESSION_KEY_ENV = "OPENCLAW_TOOLS_MCP_AGENT_SESSION_KEY";
51
- function withOpenClawManagedTurnTimeout(input) {
52
- return {
53
- ...input,
54
- timeoutMs: 0
55
- };
56
- }
57
- function withOpenClawLeaseSessionMetadata(record, metadata) {
54
+ function withOpenClawLeaseSessionMetadata(record, lease) {
58
55
  return {
59
56
  ...record,
60
- openclawLeaseId: metadata.openclawLeaseId,
61
- openclawGatewayInstanceId: metadata.openclawGatewayInstanceId
57
+ openclawLeaseId: lease.leaseId,
58
+ openclawGatewayInstanceId: lease.gatewayInstanceId
62
59
  };
63
60
  }
64
61
  const CODEX_WRAPPER_STDERR_LOG_PREFIX = "codex-acp-wrapper.stderr";
@@ -75,8 +72,7 @@ function isGenericInternalAcpErrorMessage(message) {
75
72
  return message.trim() === "Internal error";
76
73
  }
77
74
  function isGenericInternalAcpError(error) {
78
- if (!(error instanceof Error)) return false;
79
- return isGenericInternalAcpErrorMessage(error.message);
75
+ return error instanceof Error && isGenericInternalAcpErrorMessage(error.message);
80
76
  }
81
77
  async function readCodexWrapperStderrTail(params) {
82
78
  if (!params.wrapperRoot || !params.leaseId) return "";
@@ -93,9 +89,7 @@ function readSessionRecordName(record) {
93
89
  return typeof name === "string" ? name.trim() : "";
94
90
  }
95
91
  function readRecordAgentCommand(record) {
96
- if (typeof record !== "object" || record === null) return;
97
- const { agentCommand } = record;
98
- return typeof agentCommand === "string" ? agentCommand.trim() || void 0 : void 0;
92
+ return record?.agentArgv ?? record?.agentCommand;
99
93
  }
100
94
  function readRecordCwd(record) {
101
95
  if (typeof record !== "object" || record === null) return;
@@ -151,10 +145,7 @@ function createResetAwareSessionStore(baseStore, params) {
151
145
  rootPid: readRecordAgentPid(record)
152
146
  });
153
147
  if (!lease) return record;
154
- return withOpenClawLeaseSessionMetadata(record, {
155
- openclawLeaseId: lease.leaseId,
156
- openclawGatewayInstanceId: lease.gatewayInstanceId
157
- });
148
+ return withOpenClawLeaseSessionMetadata(record, lease);
158
149
  },
159
150
  async save(record) {
160
151
  let recordToSave = record;
@@ -169,7 +160,9 @@ function createResetAwareSessionStore(baseStore, params) {
169
160
  })) {
170
161
  const existing = await params.leaseStore.load(leaseIdentity.leaseId);
171
162
  if (!existing || existing.gatewayInstanceId === leaseIdentity.gatewayInstanceId && existing.sessionKey === sessionName && existing.wrapperRoot === params.wrapperRoot) {
172
- const lifecycleRecord = Boolean(launch && launch.resolvedCommand !== launch.leasedCommand) ? {
163
+ const adoptingLease = Boolean(launch && !isDeepStrictEqual(splitCommandParts(launch.resolvedCommand), splitCommandParts(launch.leasedCommand)));
164
+ const persistedCommand = launch && !adoptingLease ? launch.resolvedCommand : leasedCommand;
165
+ const lifecycleRecord = adoptingLease ? {
173
166
  ...record,
174
167
  pid: void 0,
175
168
  processId: void 0,
@@ -184,17 +177,15 @@ function createResetAwareSessionStore(baseStore, params) {
184
177
  wrapperPath: extractGeneratedWrapperPath(leasedCommand),
185
178
  rootPid,
186
179
  ...existing?.rootPid === rootPid && existing.processGroupId ? { processGroupId: existing.processGroupId } : {},
187
- commandHash: hashAcpxProcessCommand(leasedCommand),
180
+ commandHash: hashAcpxProcessCommand(persistedCommand),
188
181
  startedAt: existing?.rootPid === rootPid ? existing.startedAt : Date.now(),
189
182
  state: "open"
190
183
  });
191
184
  recordToSave = withOpenClawLeaseSessionMetadata({
192
185
  ...lifecycleRecord,
193
- agentCommand: leasedCommand
194
- }, {
195
- openclawLeaseId: leaseIdentity.leaseId,
196
- openclawGatewayInstanceId: leaseIdentity.gatewayInstanceId
197
- });
186
+ agentCommand: renderAgentCommand(persistedCommand),
187
+ agentArgv: Array.isArray(persistedCommand) ? persistedCommand : void 0
188
+ }, leaseIdentity);
198
189
  }
199
190
  }
200
191
  await baseStore.save(recordToSave);
@@ -234,18 +225,7 @@ function readAgentFromSessionKey(sessionKey) {
234
225
  return normalizeAgentName(/^agent:(?<agent>[^:]+):/i.exec(normalized)?.groups?.agent);
235
226
  }
236
227
  function readAgentFromHandle(handle) {
237
- const decoded = decodeAcpxRuntimeHandleState(handle.runtimeSessionName);
238
- if (typeof decoded === "object" && decoded !== null) {
239
- const { agent } = decoded;
240
- if (typeof agent === "string") return normalizeAgentName(agent) ?? readAgentFromSessionKey(handle.sessionKey);
241
- }
242
- return readAgentFromSessionKey(handle.sessionKey);
243
- }
244
- function readAgentCommandFromRecord(record) {
245
- return readRecordAgentCommand(record);
246
- }
247
- function readAgentPidFromRecord(record) {
248
- return readRecordAgentPid(record);
228
+ return normalizeAgentName(decodeAcpxRuntimeHandleState(handle.runtimeSessionName)?.agent) ?? readAgentFromSessionKey(handle.sessionKey);
249
229
  }
250
230
  function basename(value) {
251
231
  return value.split(/[\\/]/).pop() ?? value;
@@ -277,7 +257,7 @@ function stripModuleExtension(value) {
277
257
  }
278
258
  function isAcpCommand(command, params) {
279
259
  if (!command) return false;
280
- const parts = unwrapEnvCommand(splitCommandParts(command.trim()));
260
+ const parts = unwrapEnvCommand(splitCommandParts(command));
281
261
  if (!parts.length) return false;
282
262
  if (parts.some((part) => matchesPackageSpec(part, params.packageName))) return true;
283
263
  const commandName = basename(parts[0] ?? "");
@@ -288,7 +268,7 @@ function isAcpCommand(command, params) {
288
268
  }
289
269
  function isOpenClawBridgeCommand(command) {
290
270
  if (!command) return false;
291
- const parts = unwrapEnvCommand(splitCommandParts(command.trim()));
271
+ const parts = unwrapEnvCommand(splitCommandParts(command));
292
272
  if (basename(parts[0] ?? "") === OPENCLAW_BRIDGE_EXECUTABLE) return parts[1] === OPENCLAW_BRIDGE_SUBCOMMAND;
293
273
  if (basename(parts[0] ?? "") !== "node") return false;
294
274
  const scriptName = basename(parts[1] ?? "");
@@ -306,15 +286,13 @@ function isClaudeAcpCommand(command) {
306
286
  executableName: "claude-agent-acp"
307
287
  });
308
288
  }
309
- function failUnsupportedCodexAcpModel(rawModel, detail) {
310
- throw new AcpRuntimeError("ACP_INVALID_RUNTIME_OPTION", detail ?? `Codex ACP model "${rawModel}" is not supported. Use openai/<model> or <model>/<reasoning-effort>.`);
289
+ function failUnsupportedCodexAcpModel(rawModel) {
290
+ throw new AcpRuntimeError("ACP_INVALID_RUNTIME_OPTION", `Codex ACP model "${rawModel}" is not supported. Use openai/<model> or <model>/<reasoning-effort>.`);
311
291
  }
312
- const SUPPORTED_RUNTIME_SESSION_MODES = /* @__PURE__ */ new Set(["persistent", "oneshot"]);
313
292
  const WIRE_TIMEOUT_CONFIG_KEYS = /* @__PURE__ */ new Set(["timeout", "timeout_seconds"]);
314
293
  function assertSupportedRuntimeSessionMode(mode) {
315
- if (typeof mode === "string" && SUPPORTED_RUNTIME_SESSION_MODES.has(mode)) return;
316
- const supported = Array.from(SUPPORTED_RUNTIME_SESSION_MODES).join(", ");
317
- throw new AcpRuntimeError("ACP_INVALID_RUNTIME_OPTION", `Unsupported ACP runtime session mode ${JSON.stringify(mode)}. Expected one of: ${supported}.`);
294
+ if (mode === "persistent" || mode === "oneshot") return;
295
+ throw new AcpRuntimeError("ACP_INVALID_RUNTIME_OPTION", `Unsupported ACP runtime session mode ${JSON.stringify(mode)}. Expected one of: persistent, oneshot.`);
318
296
  }
319
297
  function failUnsupportedCodexAcpThinking(rawThinking) {
320
298
  throw new AcpRuntimeError("ACP_INVALID_RUNTIME_OPTION", `Codex ACP thinking level "${rawThinking}" is not supported. Use off, minimal, low, medium, high, or xhigh.`);
@@ -350,12 +328,12 @@ function classifyCodexAcpModelRequest(rawModel, rawThinking) {
350
328
  modelReasoningEffort = normalizeCodexAcpReasoningEffort(value.slice(slashIndex + 1));
351
329
  model = value.slice(0, slashIndex).trim();
352
330
  }
353
- if (hadOpenAiQualifier && (!model || model.includes("/"))) failUnsupportedCodexAcpModel(raw, `Codex ACP model "${raw}" is not supported. Use openai/<model> or <model>/<reasoning-effort>.`);
331
+ if (hadOpenAiQualifier && (!model || model.includes("/"))) failUnsupportedCodexAcpModel(raw);
354
332
  if (!model || model.includes("/")) return thinkingOnlyOverride ? {
355
333
  kind: "unsupported",
356
334
  thinkingOverride: thinkingOnlyOverride
357
335
  } : { kind: "unsupported" };
358
- const reasoningEffort = thinkingReasoningEffort ?? modelReasoningEffort;
336
+ const reasoningEffort = rawThinking?.trim() ? thinkingReasoningEffort : modelReasoningEffort;
359
337
  return {
360
338
  kind: "override",
361
339
  override: {
@@ -397,48 +375,32 @@ async function ensureDelegateSessionWithModelFallback(delegate, input) {
397
375
  try {
398
376
  return await delegate.ensureSession(withAcpxSessionOptions(input));
399
377
  } catch (error) {
400
- if (!input.model || !isAcpModelCapabilityMissingError(error)) throw error;
401
- return await delegate.ensureSession(withAcpxSessionOptions({
402
- ...input,
403
- model: void 0
404
- }));
378
+ if (input.modelExplicit || !input.model || !isAcpModelCapabilityMissingError(error)) throw error;
379
+ return {
380
+ ...await delegate.ensureSession(withAcpxSessionOptions({
381
+ ...input,
382
+ model: void 0
383
+ })),
384
+ appliedModel: { kind: "dropped" }
385
+ };
405
386
  }
406
387
  }
407
- function quoteShellArg(value) {
408
- if (/^[A-Za-z0-9_./:=@+-]+$/.test(value)) return value;
409
- return `'${value.replace(/'/g, "'\\''")}'`;
410
- }
411
- function normalizeAgentCommand(command) {
412
- return (Array.isArray(command) ? command.map((part) => quoteShellArg(part)).join(" ") : command).trim() || void 0;
413
- }
414
388
  function appendCodexAcpConfigOverrides(command, override) {
415
389
  const config = {
416
390
  ...override.model ? { model: override.model } : {},
417
391
  ...override.reasoningEffort ? { model_reasoning_effort: override.reasoningEffort } : {}
418
392
  };
419
393
  if (Object.keys(config).length === 0) return command;
420
- return `${command} ${OPENCLAW_CODEX_CONFIG_ARG} ${quoteShellArg(JSON.stringify(config))}`;
421
- }
422
- function createModelScopedAgentRegistry(params) {
423
- return {
424
- resolve(agentName) {
425
- const command = normalizeAgentCommand(params.agentRegistry.resolve(agentName)) ?? "";
426
- const override = params.scope.getStore();
427
- if (!override || normalizeAgentName(agentName) !== CODEX_ACP_AGENT_ID || !isCodexAcpCommand(command)) return params.leaseCommand(command);
428
- return params.leaseCommand(appendCodexAcpConfigOverrides(command, override));
429
- },
430
- list() {
431
- return params.agentRegistry.list();
432
- }
433
- };
394
+ return [
395
+ ...splitCommandParts(command),
396
+ OPENCLAW_CODEX_CONFIG_ARG,
397
+ JSON.stringify(config)
398
+ ];
434
399
  }
435
400
  function resolveAgentCommand(params) {
436
401
  const normalizedAgentName = normalizeAgentName(params.agentName);
437
402
  if (!normalizedAgentName) return;
438
- return normalizeAgentCommand(params.agentRegistry.resolve(normalizedAgentName));
439
- }
440
- function shouldUseBridgeSafeDelegateForCommand(command) {
441
- return isOpenClawBridgeCommand(command);
403
+ return splitCommandParts(params.agentRegistry.resolve(normalizedAgentName));
442
404
  }
443
405
  function shouldUseDistinctBridgeDelegate(options) {
444
406
  const { mcpServers } = options;
@@ -473,11 +435,11 @@ function withManagedToolsMcpSessionEnv(params) {
473
435
  var AcpxRuntime = class {
474
436
  constructor(options, testOptions) {
475
437
  this.ownerAwareSessions = 1;
476
- this.codexAcpModelOverrideScope = new AsyncLocalStorage();
438
+ this.launchCommandScope = new AsyncLocalStorage();
477
439
  this.managedToolsSessionDelegates = /* @__PURE__ */ new Map();
478
440
  this.launchLeaseScope = new AsyncLocalStorage();
479
- this.ensureSessionTails = /* @__PURE__ */ new Map();
480
- this.processLeaseTransitionTails = /* @__PURE__ */ new Map();
441
+ this.sessionEnsureQueue = new KeyedAsyncQueue();
442
+ this.processLeaseTransitionQueue = new KeyedAsyncQueue();
481
443
  this.processLeaseOperationCounts = /* @__PURE__ */ new Map();
482
444
  this.uncertainProcessLeaseIds = /* @__PURE__ */ new Set();
483
445
  this.legacyBareSessionKeys = new Set(options.openclawLegacyBareSessionKeys);
@@ -497,11 +459,13 @@ var AcpxRuntime = class {
497
459
  wrapperRoot: this.wrapperRoot
498
460
  });
499
461
  this.agentRegistry = options.agentRegistry;
500
- this.scopedAgentRegistry = createModelScopedAgentRegistry({
501
- agentRegistry: this.agentRegistry,
502
- scope: this.codexAcpModelOverrideScope,
503
- leaseCommand: (command) => this.commandWithLaunchLease(command)
504
- });
462
+ this.scopedAgentRegistry = {
463
+ resolve: (agentName) => {
464
+ const launch = this.launchCommandScope.getStore();
465
+ return launch && launch.agent === normalizeAgentName(agentName) && launch.command ? launch.command : this.agentRegistry.resolve(agentName);
466
+ },
467
+ list: () => this.agentRegistry.list()
468
+ };
505
469
  const sharedOptions = {
506
470
  ...options,
507
471
  sessionStore: this.sessionStore,
@@ -514,16 +478,17 @@ var AcpxRuntime = class {
514
478
  ...sharedOptions,
515
479
  mcpServers: []
516
480
  }, this.delegateTestOptions) : this.delegate;
481
+ this.probeAgent = normalizeAgentName(options.probeAgent) ?? "codex";
517
482
  const probeCommand = resolveAgentCommand({
518
- agentName: normalizeAgentName(options.probeAgent) ?? "codex",
483
+ agentName: this.probeAgent,
519
484
  agentRegistry: this.agentRegistry
520
485
  });
521
486
  this.probeCommand = probeCommand;
522
- const useBridgeSafeProbe = this.managedToolsMcpBridgeEnabled || shouldUseBridgeSafeDelegateForCommand(probeCommand);
487
+ const useBridgeSafeProbe = this.managedToolsMcpBridgeEnabled || isOpenClawBridgeCommand(probeCommand);
523
488
  this.probeDelegate = useBridgeSafeProbe ? this.bridgeSafeDelegate : this.delegate;
524
489
  }
525
490
  resolveDelegateForSession(params) {
526
- if (shouldUseBridgeSafeDelegateForCommand(params.command)) return this.bridgeSafeDelegate;
491
+ if (isOpenClawBridgeCommand(params.command)) return this.bridgeSafeDelegate;
527
492
  return this.resolveManagedToolsDelegateForSession(params);
528
493
  }
529
494
  resolveManagedToolsDelegateForSession(target) {
@@ -544,12 +509,6 @@ var AcpxRuntime = class {
544
509
  this.managedToolsSessionDelegates.set(normalizedSessionKey, delegate);
545
510
  return delegate;
546
511
  }
547
- releaseManagedToolsDelegateForSession(sessionKey) {
548
- if (!this.managedToolsMcpBridgeEnabled) return;
549
- const normalizedSessionKey = sessionKey.trim();
550
- if (!normalizedSessionKey) return;
551
- this.managedToolsSessionDelegates.delete(normalizedSessionKey);
552
- }
553
512
  async loadOperationSnapshotForHandle(handle) {
554
513
  assertAcpxSessionOwnerLocator({
555
514
  ...handle,
@@ -558,7 +517,7 @@ var AcpxRuntime = class {
558
517
  const record = await this.sessionStore.load(handle.acpxRecordId ?? resolveAcpxSessionResource(handle));
559
518
  return {
560
519
  record,
561
- command: readAgentCommandFromRecord(record) ?? resolveAgentCommand({
520
+ command: readRecordAgentCommand(record) ?? resolveAgentCommand({
562
521
  agentName: readAgentFromHandle(handle),
563
522
  agentRegistry: this.agentRegistry
564
523
  })
@@ -571,16 +530,6 @@ var AcpxRuntime = class {
571
530
  agentId: handle.agentId
572
531
  });
573
532
  }
574
- commandWithLaunchLease(command) {
575
- const launch = this.launchLeaseScope.getStore();
576
- if (!launch) return command;
577
- if (command === launch.stableCommand) return launch.resolvedCommand;
578
- return withAcpxLeaseEnvironment({
579
- command,
580
- leaseId: launch.leaseId,
581
- gatewayInstanceId: launch.gatewayInstanceId
582
- });
583
- }
584
533
  async readReusablePersistentSessionCommand(params) {
585
534
  if (params.mode !== "persistent" || !params.command) return;
586
535
  const existing = await this.sessionStore.load(params.sessionKey);
@@ -591,24 +540,27 @@ var AcpxRuntime = class {
591
540
  if (!recordCommand) return;
592
541
  const leaseIdentity = readAcpxProcessLeaseIdentity(recordCommand);
593
542
  if (leaseIdentity && leaseIdentity.gatewayInstanceId !== this.gatewayInstanceId) return;
594
- if (recordCommand !== (leaseIdentity ? withAcpxLeaseEnvironment({
543
+ const stableRecordCommand = leaseIdentity ? withAcpxLeaseArgs({
595
544
  command: params.command,
596
545
  leaseId: leaseIdentity.leaseId,
597
546
  gatewayInstanceId: leaseIdentity.gatewayInstanceId
598
- }) : params.command)) return;
599
- const existingSessionId = typeof existing === "object" && existing !== null ? existing.acpSessionId : void 0;
600
- return !params.resumeSessionId || existingSessionId === params.resumeSessionId ? recordCommand : void 0;
547
+ }) : params.command;
548
+ if (!isDeepStrictEqual(splitCommandParts(recordCommand), splitCommandParts(stableRecordCommand))) return;
549
+ return !params.resumeSessionId || existing.acpSessionId === params.resumeSessionId ? recordCommand : void 0;
601
550
  }
602
551
  async runWithLaunchLease(params) {
603
552
  if (!params.command || !this.wrapperRoot || !this.gatewayInstanceId || !this.processLeaseStore || !isOpenClawLeaseAwareAcpxProcessCommand({
604
553
  command: params.command,
605
554
  wrapperRoot: this.wrapperRoot
606
- })) return await params.run();
555
+ })) return await this.launchCommandScope.run({
556
+ agent: normalizeAgentName(params.agent) ?? params.agent,
557
+ command: params.reusableCommand ?? params.command
558
+ }, params.run);
607
559
  const processLeaseStore = this.processLeaseStore;
608
560
  const reusableIdentity = readAcpxProcessLeaseIdentity(params.reusableCommand);
609
561
  const canReuseLeaseIdentity = reusableIdentity?.gatewayInstanceId === this.gatewayInstanceId;
610
- const leaseId = canReuseLeaseIdentity ? reusableIdentity.leaseId : params.finalizeCompletedProbe ? `probe-${hashAcpxProcessCommand(`${this.gatewayInstanceId}\0${extractGeneratedWrapperPath(params.command)}`)}` : createAcpxProcessLeaseId();
611
- const leasedCommand = withAcpxLeaseEnvironment({
562
+ const leaseId = canReuseLeaseIdentity ? reusableIdentity.leaseId : params.finalizeCompletedProbe ? `probe-${hashAcpxProcessCommand(`${this.gatewayInstanceId}\0${extractGeneratedWrapperPath(params.command)}`)}` : randomUUID();
563
+ const leasedCommand = withAcpxLeaseArgs({
612
564
  command: params.command,
613
565
  leaseId,
614
566
  gatewayInstanceId: this.gatewayInstanceId
@@ -618,14 +570,13 @@ var AcpxRuntime = class {
618
570
  gatewayInstanceId: this.gatewayInstanceId,
619
571
  sessionKey: params.sessionKey,
620
572
  wrapperRoot: this.wrapperRoot,
621
- stableCommand: params.command,
622
573
  resolvedCommand: params.reusableCommand ?? leasedCommand,
623
574
  leasedCommand
624
575
  };
625
576
  await this.retainProcessLeaseOperation(launch, async () => {
626
577
  const reusableLease = canReuseLeaseIdentity ? await processLeaseStore.load(launch.leaseId) : void 0;
627
578
  if (reusableLease && (reusableLease.gatewayInstanceId !== launch.gatewayInstanceId || reusableLease.sessionKey !== launch.sessionKey || reusableLease.wrapperRoot !== launch.wrapperRoot)) throw new AcpRuntimeError("ACP_SESSION_INIT_FAILED", `ACPX process lease ${launch.leaseId} belongs to another session`);
628
- if (!(!reusableLease && (!params.reusableCommand || params.reusableCommand === leasedCommand))) return;
579
+ if (!(!reusableLease && (!params.reusableCommand || isDeepStrictEqual(splitCommandParts(params.reusableCommand), splitCommandParts(leasedCommand))))) return;
629
580
  await processLeaseStore.save({
630
581
  leaseId: launch.leaseId,
631
582
  gatewayInstanceId: launch.gatewayInstanceId,
@@ -639,7 +590,10 @@ var AcpxRuntime = class {
639
590
  });
640
591
  });
641
592
  try {
642
- const result = await this.launchLeaseScope.run(launch, params.run);
593
+ const result = await this.launchLeaseScope.run(launch, () => this.launchCommandScope.run({
594
+ agent: normalizeAgentName(params.agent) ?? params.agent,
595
+ command: launch.resolvedCommand
596
+ }, params.run));
643
597
  if (params.finalizeCompletedProbe) await this.finalizeCompletedProbeLease(launch);
644
598
  else await this.finalizeProcessLeaseForSession(params.sessionKey, launch);
645
599
  return result;
@@ -653,7 +607,7 @@ var AcpxRuntime = class {
653
607
  const processLeaseStore = this.processLeaseStore;
654
608
  const wrapperRoot = this.wrapperRoot;
655
609
  const recordPid = readRecordAgentPid(record);
656
- const command = readAgentCommandFromRecord(record);
610
+ const command = readRecordAgentCommand(record);
657
611
  const identity = readAcpxProcessLeaseIdentity(command);
658
612
  if (!command || !isOpenClawLeaseAwareAcpxProcessCommand({
659
613
  command,
@@ -681,31 +635,15 @@ var AcpxRuntime = class {
681
635
  });
682
636
  return identity;
683
637
  }
684
- async runSerializedProcessLeaseTransition(leaseId, run) {
685
- const previous = this.processLeaseTransitionTails.get(leaseId) ?? Promise.resolve();
686
- let release;
687
- const current = new Promise((resolve) => {
688
- release = resolve;
689
- });
690
- const tail = previous.then(() => current);
691
- this.processLeaseTransitionTails.set(leaseId, tail);
692
- await previous;
693
- try {
694
- return await run();
695
- } finally {
696
- release();
697
- if (this.processLeaseTransitionTails.get(leaseId) === tail) this.processLeaseTransitionTails.delete(leaseId);
698
- }
699
- }
700
638
  async retainProcessLeaseOperation(identity, prepare) {
701
- await this.runSerializedProcessLeaseTransition(identity.leaseId, async () => {
639
+ await this.processLeaseTransitionQueue.enqueue(identity.leaseId, async () => {
702
640
  await prepare();
703
641
  this.processLeaseOperationCounts.set(identity.leaseId, (this.processLeaseOperationCounts.get(identity.leaseId) ?? 0) + 1);
704
642
  });
705
643
  }
706
644
  async releaseProcessLeaseOperation(identity, finalize) {
707
645
  if (!identity) return;
708
- await this.runSerializedProcessLeaseTransition(identity.leaseId, async () => {
646
+ await this.processLeaseTransitionQueue.enqueue(identity.leaseId, async () => {
709
647
  const count = this.processLeaseOperationCounts.get(identity.leaseId) ?? 0;
710
648
  if (count > 1) {
711
649
  this.processLeaseOperationCounts.set(identity.leaseId, count - 1);
@@ -733,7 +671,7 @@ var AcpxRuntime = class {
733
671
  this.uncertainProcessLeaseIds.delete(identity.leaseId);
734
672
  try {
735
673
  const record = await this.sessionStore.load(sessionId);
736
- const recordIdentity = readAcpxProcessLeaseIdentity(readAgentCommandFromRecord(record));
674
+ const recordIdentity = readAcpxProcessLeaseIdentity(readRecordAgentCommand(record));
737
675
  if (recordIdentity?.leaseId !== identity.leaseId || recordIdentity.gatewayInstanceId !== identity.gatewayInstanceId) await processLeaseStore.markState(identity.leaseId, "lost");
738
676
  } catch {}
739
677
  });
@@ -778,29 +716,12 @@ var AcpxRuntime = class {
778
716
  await this.finalizeProcessLeaseForOperation(handle, await identityPromise);
779
717
  }
780
718
  }
781
- async runSerializedSessionEnsure(sessionKey, run) {
782
- const key = sessionKey.trim() || sessionKey;
783
- const previous = this.ensureSessionTails.get(key) ?? Promise.resolve();
784
- let release;
785
- const current = new Promise((resolve) => {
786
- release = resolve;
787
- });
788
- const tail = previous.then(() => current);
789
- this.ensureSessionTails.set(key, tail);
790
- await previous;
791
- try {
792
- return await run();
793
- } finally {
794
- release();
795
- if (this.ensureSessionTails.get(key) === tail) this.ensureSessionTails.delete(key);
796
- }
797
- }
798
719
  async withCodexWrapperDiagnostics(params) {
799
720
  try {
800
721
  return await params.run();
801
722
  } catch (error) {
802
723
  if (!isCodexAcpCommand(params.command) || !isGenericInternalAcpError(error)) throw error;
803
- const stderrTail = await readCodexWrapperStderrTail({
724
+ const stderrTail = params.handle ? await this.readCodexTurnFailureStderr({ handle: params.handle }) : await readCodexWrapperStderrTail({
804
725
  wrapperRoot: this.wrapperRoot,
805
726
  leaseId: this.launchLeaseScope.getStore()?.leaseId
806
727
  });
@@ -817,7 +738,7 @@ var AcpxRuntime = class {
817
738
  }
818
739
  async cleanupProcessTreeForRecord(handle, record) {
819
740
  const leaseId = readOpenClawLeaseIdFromRecord(record);
820
- const rootPid = readAgentPidFromRecord(record);
741
+ const rootPid = readRecordAgentPid(record);
821
742
  const sessionKeys = [resolveAcpxSessionResource(handle), readSessionRecordName(record)];
822
743
  const selectedLease = selectCurrentSessionLease({
823
744
  leases: this.gatewayInstanceId && this.processLeaseStore ? await this.processLeaseStore.listOpen(this.gatewayInstanceId) : [],
@@ -830,7 +751,7 @@ var AcpxRuntime = class {
830
751
  await this.processLeaseStore?.markState(lease.leaseId, "closing");
831
752
  const result = await cleanupOpenClawOwnedAcpxProcessTree({
832
753
  rootPid: lease.rootPid,
833
- rootCommand: readAgentCommandFromRecord(record),
754
+ rootCommand: record?.agentCommand,
834
755
  expectedLeaseId: lease.leaseId,
835
756
  expectedGatewayInstanceId: lease.gatewayInstanceId,
836
757
  wrapperRoot: lease.wrapperRoot,
@@ -839,7 +760,7 @@ var AcpxRuntime = class {
839
760
  await this.processLeaseStore?.markState(lease.leaseId, result.skippedReason === "process-list-unavailable" || result.skippedReason === "unsupported-platform" ? "open" : result.terminatedPids.length > 0 || result.skippedReason === "missing-root" ? "closed" : "lost");
840
761
  return;
841
762
  }
842
- const rootCommand = readAgentCommandFromRecord(record) ?? resolveAgentCommand({
763
+ const rootCommand = readRecordAgentCommand(record) ?? resolveAgentCommand({
843
764
  agentName: readAgentFromHandle(handle),
844
765
  agentRegistry: this.agentRegistry
845
766
  });
@@ -847,7 +768,7 @@ var AcpxRuntime = class {
847
768
  const expectedGatewayInstanceId = readOpenClawGatewayInstanceIdFromRecord(record);
848
769
  await cleanupOpenClawOwnedAcpxProcessTree({
849
770
  rootPid,
850
- rootCommand,
771
+ rootCommand: renderAgentCommand(rootCommand),
851
772
  ...leaseId ? { expectedLeaseId: leaseId } : {},
852
773
  ...expectedGatewayInstanceId ? { expectedGatewayInstanceId } : {},
853
774
  wrapperRoot: this.wrapperRoot,
@@ -859,6 +780,7 @@ var AcpxRuntime = class {
859
780
  }
860
781
  async probeAvailability() {
861
782
  await this.runWithLaunchLease({
783
+ agent: this.probeAgent,
862
784
  sessionKey: ACPX_PROBE_LEASE_SESSION_KEY,
863
785
  command: this.probeCommand,
864
786
  finalizeCompletedProbe: true,
@@ -867,6 +789,7 @@ var AcpxRuntime = class {
867
789
  }
868
790
  async doctor() {
869
791
  return await this.runWithLaunchLease({
792
+ agent: this.probeAgent,
870
793
  sessionKey: ACPX_PROBE_LEASE_SESSION_KEY,
871
794
  command: this.probeCommand,
872
795
  finalizeCompletedProbe: true,
@@ -875,7 +798,7 @@ var AcpxRuntime = class {
875
798
  }
876
799
  async ensureSession(input) {
877
800
  const resource = assertAcpxSessionOwnerLocator(input, this.legacyBareSessionKeys);
878
- return await this.runSerializedSessionEnsure(resource, () => this.ensureSessionUnlocked(input));
801
+ return await this.sessionEnsureQueue.enqueue(resource.trim() || resource, () => this.ensureSessionUnlocked(input));
879
802
  }
880
803
  async ensureSessionUnlocked(logicalInput) {
881
804
  assertSupportedRuntimeSessionMode(logicalInput.mode);
@@ -920,83 +843,63 @@ var AcpxRuntime = class {
920
843
  resumeSessionId: input.resumeSessionId
921
844
  });
922
845
  return {
923
- ...!codexModelOverride ? await this.runWithLaunchLease({
846
+ ...await this.runWithLaunchLease({
847
+ agent: ensureInput.agent,
924
848
  sessionKey: ensureInput.sessionKey,
925
849
  command: stableLaunchCommand,
926
850
  reusableCommand,
927
851
  run: () => this.withCodexWrapperDiagnostics({
928
852
  command: stableLaunchCommand,
929
853
  fallbackCode: "ACP_SESSION_INIT_FAILED",
930
- run: () => ensureDelegateSessionWithModelFallback(delegate, ensureInput)
854
+ run: () => codexModelOverride ? delegate.ensureSession(withAcpxSessionOptions(ensureInput)) : ensureDelegateSessionWithModelFallback(delegate, ensureInput)
931
855
  })
932
- }) : await this.runWithLaunchLease({
933
- sessionKey: input.sessionKey,
934
- command: stableLaunchCommand,
935
- reusableCommand,
936
- run: () => this.codexAcpModelOverrideScope.run(codexModelOverride, () => this.withCodexWrapperDiagnostics({
937
- command: stableLaunchCommand,
938
- fallbackCode: "ACP_SESSION_INIT_FAILED",
939
- run: () => delegate.ensureSession(withAcpxSessionOptions(ensureInput))
940
- }))
941
856
  }),
942
857
  ...logicalTarget,
943
858
  ...appliedModel ? { appliedModel } : {}
944
859
  };
945
860
  }
946
861
  async *runTurn(input) {
947
- assertAcpxSessionOwnerLocator({
948
- ...input.handle,
949
- persistedHandle: input.handle
950
- }, this.legacyBareSessionKeys);
951
- const record = await this.sessionStore.load(input.handle.acpxRecordId ?? resolveAcpxSessionResource(input.handle));
952
- const turnLease = await this.prepareProcessLeaseForOperation(input.handle, record);
953
- let command;
862
+ const turn = this.startTurn(input);
863
+ turn.result.catch(() => {});
864
+ let completed = false;
954
865
  try {
955
- command = (await this.loadOperationSnapshotForHandle(input.handle)).command;
956
- const delegate = this.resolveDelegateForOperationSnapshot(input.handle, await this.loadOperationSnapshotForHandle(input.handle));
957
- for await (const event of delegate.runTurn(withOpenClawManagedTurnTimeout(toAcpxResourceInput(input)))) {
958
- if (event.type !== "error" || !isCodexAcpCommand(command) || !isGenericInternalAcpErrorMessage(event.message)) {
959
- yield event;
960
- continue;
961
- }
962
- const stderrTail = await this.readCodexTurnFailureStderr({ handle: input.handle });
963
- if (!stderrTail) {
964
- yield event;
965
- continue;
966
- }
967
- yield {
968
- ...event,
969
- code: "ACP_TURN_FAILED",
970
- message: `Internal error: ${stderrTail}`
971
- };
972
- }
973
- } catch (error) {
974
- if (!isCodexAcpCommand(command) || !isGenericInternalAcpError(error)) throw error;
975
- const stderrTail = await this.readCodexTurnFailureStderr({ handle: input.handle });
976
- if (!stderrTail) throw error;
977
- throw new AcpRuntimeError("ACP_TURN_FAILED", `Internal error: ${stderrTail}`, { cause: error });
866
+ yield* turn.events;
867
+ const result = await turn.result;
868
+ completed = true;
869
+ yield result.status === "failed" ? {
870
+ type: "error",
871
+ ...result.error
872
+ } : {
873
+ type: "done",
874
+ ...result.stopReason ? { stopReason: result.stopReason } : {}
875
+ };
978
876
  } finally {
979
- await this.finalizeProcessLeaseForOperation(input.handle, turnLease);
877
+ if (!completed) {
878
+ await turn.cancel({ reason: "stream-closed" }).catch(() => {});
879
+ await turn.closeStream({ reason: "stream-closed" }).catch(() => {});
880
+ await turn.result.catch(() => {});
881
+ }
980
882
  }
981
883
  }
982
884
  startTurn(input) {
983
- const readCodexTurnFailureStderr = () => this.readCodexTurnFailureStderr({ handle: input.handle });
885
+ const withTurnDiagnostics = (command, run) => this.withCodexWrapperDiagnostics({
886
+ command,
887
+ handle: input.handle,
888
+ fallbackCode: "ACP_TURN_FAILED",
889
+ run
890
+ });
984
891
  const snapshotPromise = this.loadOperationSnapshotForHandle(input.handle);
985
892
  const turnLeasePromise = snapshotPromise.then(({ record }) => this.prepareProcessLeaseForOperation(input.handle, record));
986
- const turnPromise = Promise.all([snapshotPromise, turnLeasePromise]).then(async ([snapshot]) => {
893
+ const turnPromise = Promise.all([snapshotPromise, turnLeasePromise]).then(([snapshot]) => {
987
894
  const { command } = snapshot;
988
895
  const delegate = this.resolveDelegateForOperationSnapshot(input.handle, snapshot);
989
- try {
990
- return {
991
- command,
992
- turn: delegate.startTurn(withOpenClawManagedTurnTimeout(toAcpxResourceInput(input)))
993
- };
994
- } catch (error) {
995
- if (!isCodexAcpCommand(command) || !isGenericInternalAcpError(error)) throw error;
996
- const stderrTail = await readCodexTurnFailureStderr();
997
- if (!stderrTail) throw error;
998
- throw new AcpRuntimeError("ACP_TURN_FAILED", `Internal error: ${stderrTail}`, { cause: error });
999
- }
896
+ return withTurnDiagnostics(command, async () => ({
897
+ command,
898
+ turn: delegate.startTurn({
899
+ ...toAcpxResourceInput(input),
900
+ timeoutMs: 0
901
+ })
902
+ }));
1000
903
  });
1001
904
  return {
1002
905
  requestId: input.requestId,
@@ -1006,50 +909,26 @@ var AcpxRuntime = class {
1006
909
  events: { async *[Symbol.asyncIterator]() {
1007
910
  const { command, turn } = await turnPromise;
1008
911
  try {
1009
- for await (const event of turn.events) {
1010
- if (event.type !== "error" || !isCodexAcpCommand(command) || !isGenericInternalAcpErrorMessage(event.message)) {
1011
- yield event;
1012
- continue;
1013
- }
1014
- const stderrTail = await readCodexTurnFailureStderr();
1015
- if (!stderrTail) {
1016
- yield event;
1017
- continue;
1018
- }
1019
- yield {
1020
- ...event,
1021
- code: "ACP_TURN_FAILED",
1022
- message: `Internal error: ${stderrTail}`
1023
- };
1024
- }
912
+ yield* turn.events;
1025
913
  } catch (error) {
1026
- if (!isCodexAcpCommand(command) || !isGenericInternalAcpError(error)) throw error;
1027
- const stderrTail = await readCodexTurnFailureStderr();
1028
- if (!stderrTail) throw error;
1029
- throw new AcpRuntimeError("ACP_TURN_FAILED", `Internal error: ${stderrTail}`, { cause: error });
914
+ if (!isGenericInternalAcpError(error)) throw error;
915
+ await withTurnDiagnostics(command, () => Promise.reject(error));
1030
916
  }
1031
917
  } },
1032
- result: this.finalizeProcessLeaseAfter(input.handle, turnLeasePromise, turnPromise.then(async ({ command, turn }) => {
1033
- try {
1034
- const result = await turn.result;
1035
- if (result.status !== "failed" || !isCodexAcpCommand(command) || !isGenericInternalAcpErrorMessage(result.error.message)) return result;
1036
- const stderrTail = await this.readCodexTurnFailureStderr({ handle: input.handle });
1037
- if (!stderrTail) return result;
1038
- return {
1039
- status: "failed",
1040
- error: {
1041
- ...result.error,
1042
- code: "ACP_TURN_FAILED",
1043
- message: `Internal error: ${stderrTail}`
1044
- }
1045
- };
1046
- } catch (error) {
1047
- if (!isCodexAcpCommand(command) || !isGenericInternalAcpError(error)) throw error;
1048
- const stderrTail = await this.readCodexTurnFailureStderr({ handle: input.handle });
1049
- if (!stderrTail) throw error;
1050
- throw new AcpRuntimeError("ACP_TURN_FAILED", `Internal error: ${stderrTail}`, { cause: error });
1051
- }
1052
- })),
918
+ result: this.finalizeProcessLeaseAfter(input.handle, turnLeasePromise, turnPromise.then(({ command, turn }) => withTurnDiagnostics(command, async () => {
919
+ const result = await turn.result;
920
+ if (result.status !== "failed" || !isCodexAcpCommand(command) || !isGenericInternalAcpErrorMessage(result.error.message)) return result;
921
+ const stderrTail = await this.readCodexTurnFailureStderr({ handle: input.handle });
922
+ if (!stderrTail) return result;
923
+ return {
924
+ status: "failed",
925
+ error: {
926
+ ...result.error,
927
+ code: "ACP_TURN_FAILED",
928
+ message: `Internal error: ${stderrTail}`
929
+ }
930
+ };
931
+ }))),
1053
932
  cancel(inputArgs) {
1054
933
  return turnPromise.then(({ turn }) => turn.cancel(inputArgs));
1055
934
  },
@@ -1129,20 +1008,19 @@ var AcpxRuntime = class {
1129
1008
  let cleanupSucceeded = false;
1130
1009
  try {
1131
1010
  const delegate = this.resolveDelegateForOperationSnapshot(input.handle, snapshot);
1132
- let closeSucceeded;
1011
+ const handle = toAcpxResourceInput(input).handle;
1133
1012
  try {
1134
1013
  await delegate.close({
1135
- handle: toAcpxResourceInput(input).handle,
1014
+ handle,
1136
1015
  reason: input.reason,
1137
1016
  discardPersistentState: input.discardPersistentState
1138
1017
  });
1139
- closeSucceeded = true;
1018
+ if (this.managedToolsSessionDelegates.get(handle.sessionKey) === delegate) this.managedToolsSessionDelegates.delete(handle.sessionKey);
1140
1019
  } finally {
1141
1020
  await this.cleanupProcessTreeForRecord(input.handle, snapshot.record);
1142
1021
  cleanupSucceeded = true;
1143
1022
  }
1144
- if (closeSucceeded) this.releaseManagedToolsDelegateForSession(resolveAcpxSessionResource(input.handle));
1145
- if (closeSucceeded && input.discardPersistentState) await this.prepareFreshSession({
1023
+ if (input.discardPersistentState) await this.prepareFreshSession({
1146
1024
  ...input.handle,
1147
1025
  persistedHandle: input.handle
1148
1026
  });
@@ -1156,8 +1034,7 @@ var AcpxRuntime = class {
1156
1034
  const testing = {
1157
1035
  appendCodexAcpConfigOverrides,
1158
1036
  isClaudeAcpCommand,
1159
- isCodexAcpCommand,
1160
- normalizeAgentCommand
1037
+ isCodexAcpCommand
1161
1038
  };
1162
1039
  //#endregion
1163
1040
  export { ACPX_BACKEND_ID, AcpxRuntime, createAcpRuntime, createAgentRegistry, createFileSessionStore, decodeAcpxRuntimeHandleState, encodeAcpxRuntimeHandleState, testing };