@openclaw/acpx 2026.5.27 → 2026.5.28-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createAcpxRuntimeService } from "./register.runtime.js";
1
+ import { t as createAcpxRuntimeService } from "./register.runtime-CIbEVqqU.js";
2
2
  import { tryDispatchAcpReplyHook } from "openclaw/plugin-sdk/acp-runtime-backend";
3
3
  //#region extensions/acpx/index.ts
4
4
  const plugin = {
@@ -4,9 +4,15 @@ import { spawn } from "node:child_process";
4
4
  import path from "node:path";
5
5
  import { createInterface } from "node:readline";
6
6
  import { pathToFileURL } from "node:url";
7
- import { formatErrorMessage } from "./error-format.mjs";
8
7
  import { splitCommandLine } from "./mcp-command-line.mjs";
9
8
 
9
+ function formatErrorMessage(error) {
10
+ if (error instanceof Error) {
11
+ return error.message || error.name || "Error";
12
+ }
13
+ return String(error);
14
+ }
15
+
10
16
  function decodePayload(argv) {
11
17
  const payloadIndex = argv.indexOf("--payload");
12
18
  if (payloadIndex < 0) {
@@ -0,0 +1,250 @@
1
+ import { getAcpRuntimeBackend, registerAcpRuntimeBackend, unregisterAcpRuntimeBackend } from "openclaw/plugin-sdk/acp-runtime-backend";
2
+ //#region extensions/acpx/src/runtime-turn.ts
3
+ function createDeferredResult() {
4
+ let resolve;
5
+ let reject;
6
+ return {
7
+ promise: new Promise((resolvePromise, rejectPromise) => {
8
+ resolve = resolvePromise;
9
+ reject = rejectPromise;
10
+ }),
11
+ resolve,
12
+ reject
13
+ };
14
+ }
15
+ var LegacyRunTurnEventQueue = class {
16
+ constructor() {
17
+ this.items = [];
18
+ this.waits = [];
19
+ this.closed = false;
20
+ }
21
+ push(item) {
22
+ if (this.closed) return;
23
+ const waiter = this.waits.shift();
24
+ if (waiter) {
25
+ waiter.resolve(item);
26
+ return;
27
+ }
28
+ this.items.push(item);
29
+ }
30
+ clear() {
31
+ this.items.length = 0;
32
+ }
33
+ close() {
34
+ if (this.closed) return;
35
+ this.closed = true;
36
+ for (const waiter of this.waits.splice(0)) waiter.resolve(null);
37
+ }
38
+ fail(error) {
39
+ if (this.closed) return;
40
+ this.error = error;
41
+ this.closed = true;
42
+ for (const waiter of this.waits.splice(0)) waiter.reject(error);
43
+ }
44
+ async next() {
45
+ const item = this.items.shift();
46
+ if (item) return item;
47
+ if (this.error) throw this.error;
48
+ if (this.closed) return null;
49
+ return await new Promise((resolve, reject) => {
50
+ this.waits.push({
51
+ resolve,
52
+ reject
53
+ });
54
+ });
55
+ }
56
+ async *iterate() {
57
+ for (;;) {
58
+ const item = await this.next();
59
+ if (!item) return;
60
+ yield item;
61
+ }
62
+ }
63
+ };
64
+ function legacyRunTurnAsStartTurn(runtime, input) {
65
+ const result = createDeferredResult();
66
+ result.promise.catch(() => {});
67
+ const queue = new LegacyRunTurnEventQueue();
68
+ let resultSettled = false;
69
+ const settleResult = (next) => {
70
+ if (resultSettled) return;
71
+ resultSettled = true;
72
+ result.resolve(next);
73
+ };
74
+ (async () => {
75
+ try {
76
+ for await (const event of runtime.runTurn(input)) {
77
+ if (event.type === "done") {
78
+ settleResult({
79
+ status: "completed",
80
+ ...event.stopReason ? { stopReason: event.stopReason } : {}
81
+ });
82
+ continue;
83
+ }
84
+ if (event.type === "error") {
85
+ settleResult({
86
+ status: "failed",
87
+ error: {
88
+ message: event.message,
89
+ ...event.code ? { code: event.code } : {},
90
+ ...event.detailCode ? { detailCode: event.detailCode } : {},
91
+ ...event.retryable === void 0 ? {} : { retryable: event.retryable }
92
+ }
93
+ });
94
+ continue;
95
+ }
96
+ queue.push(event);
97
+ }
98
+ settleResult({
99
+ status: "failed",
100
+ error: {
101
+ code: "ACP_TURN_FAILED",
102
+ message: "ACP turn ended without a terminal done event."
103
+ }
104
+ });
105
+ } catch (error) {
106
+ result.reject(error);
107
+ queue.fail(error);
108
+ return;
109
+ }
110
+ queue.close();
111
+ })();
112
+ return {
113
+ requestId: input.requestId,
114
+ events: queue.iterate(),
115
+ result: result.promise,
116
+ async cancel(inputArgs) {
117
+ await runtime.cancel({
118
+ handle: input.handle,
119
+ reason: inputArgs?.reason
120
+ });
121
+ },
122
+ async closeStream() {
123
+ queue.clear();
124
+ queue.close();
125
+ }
126
+ };
127
+ }
128
+ function startRuntimeTurn(runtime, input) {
129
+ return runtime.startTurn?.(input) ?? legacyRunTurnAsStartTurn(runtime, input);
130
+ }
131
+ function lazyStartRuntimeTurn(resolveRuntime, input) {
132
+ const turnPromise = resolveRuntime().then((runtime) => startRuntimeTurn(runtime, input));
133
+ return {
134
+ requestId: input.requestId,
135
+ events: { async *[Symbol.asyncIterator]() {
136
+ yield* (await turnPromise).events;
137
+ } },
138
+ result: turnPromise.then((turn) => turn.result),
139
+ cancel(inputArgs) {
140
+ return turnPromise.then((turn) => turn.cancel(inputArgs));
141
+ },
142
+ closeStream(inputArgs) {
143
+ return turnPromise.then((turn) => turn.closeStream(inputArgs));
144
+ }
145
+ };
146
+ }
147
+ //#endregion
148
+ //#region extensions/acpx/register.runtime.ts
149
+ const ACPX_BACKEND_ID = "acpx";
150
+ let serviceModulePromise = null;
151
+ function loadServiceModule() {
152
+ serviceModulePromise ??= import("./service-Dj4-xaW3.js");
153
+ return serviceModulePromise;
154
+ }
155
+ async function startRealService(state) {
156
+ if (state.realRuntime) return state.realRuntime;
157
+ if (!state.ctx) throw new Error("ACPX runtime service is not started");
158
+ state.startPromise ??= (async () => {
159
+ const { createAcpxRuntimeService } = await loadServiceModule();
160
+ const service = createAcpxRuntimeService(state.params);
161
+ state.realService = service;
162
+ await service.start(state.ctx);
163
+ const backend = getAcpRuntimeBackend(ACPX_BACKEND_ID);
164
+ if (!backend?.runtime) throw new Error("ACPX runtime service did not register an ACP backend");
165
+ state.realRuntime = backend.runtime;
166
+ return state.realRuntime;
167
+ })();
168
+ try {
169
+ return await state.startPromise;
170
+ } catch (error) {
171
+ state.startPromise = null;
172
+ state.realService = null;
173
+ throw error;
174
+ }
175
+ }
176
+ function createDeferredRuntime(state) {
177
+ const resolveRuntime = () => startRealService(state);
178
+ return {
179
+ async ensureSession(input) {
180
+ return await (await resolveRuntime()).ensureSession(input);
181
+ },
182
+ startTurn(input) {
183
+ return lazyStartRuntimeTurn(resolveRuntime, input);
184
+ },
185
+ async *runTurn(input) {
186
+ yield* (await resolveRuntime()).runTurn(input);
187
+ },
188
+ async getCapabilities(input) {
189
+ return await (await resolveRuntime()).getCapabilities?.(input) ?? { controls: [] };
190
+ },
191
+ async getStatus(input) {
192
+ return await (await resolveRuntime()).getStatus?.(input) ?? {};
193
+ },
194
+ async setMode(input) {
195
+ await (await resolveRuntime()).setMode?.(input);
196
+ },
197
+ async setConfigOption(input) {
198
+ await (await resolveRuntime()).setConfigOption?.(input);
199
+ },
200
+ async doctor() {
201
+ return await (await resolveRuntime()).doctor?.() ?? {
202
+ ok: true,
203
+ message: "ok"
204
+ };
205
+ },
206
+ async prepareFreshSession(input) {
207
+ await (await resolveRuntime()).prepareFreshSession?.(input);
208
+ },
209
+ async cancel(input) {
210
+ await (await resolveRuntime()).cancel(input);
211
+ },
212
+ async close(input) {
213
+ await (await resolveRuntime()).close(input);
214
+ }
215
+ };
216
+ }
217
+ function createAcpxRuntimeService(params = {}) {
218
+ const state = {
219
+ ctx: null,
220
+ params,
221
+ realRuntime: null,
222
+ realService: null,
223
+ startPromise: null
224
+ };
225
+ return {
226
+ id: "acpx-runtime",
227
+ async start(ctx) {
228
+ if (process.env.OPENCLAW_SKIP_ACPX_RUNTIME === "1") {
229
+ ctx.logger.info("skipping embedded acpx runtime backend (OPENCLAW_SKIP_ACPX_RUNTIME=1)");
230
+ return;
231
+ }
232
+ state.ctx = ctx;
233
+ registerAcpRuntimeBackend({
234
+ id: ACPX_BACKEND_ID,
235
+ runtime: createDeferredRuntime(state)
236
+ });
237
+ ctx.logger.info("embedded acpx runtime backend registered lazily");
238
+ },
239
+ async stop(ctx) {
240
+ if (state.realService) await state.realService.stop?.(ctx);
241
+ else unregisterAcpRuntimeBackend(ACPX_BACKEND_ID);
242
+ state.ctx = null;
243
+ state.realRuntime = null;
244
+ state.realService = null;
245
+ state.startPromise = null;
246
+ }
247
+ };
248
+ }
249
+ //#endregion
250
+ export { lazyStartRuntimeTurn as n, createAcpxRuntimeService as t };
@@ -1,248 +1,2 @@
1
- import { getAcpRuntimeBackend, registerAcpRuntimeBackend, unregisterAcpRuntimeBackend } from "openclaw/plugin-sdk/acp-runtime-backend";
2
- //#region extensions/acpx/register.runtime.ts
3
- const ACPX_BACKEND_ID = "acpx";
4
- let serviceModulePromise = null;
5
- function createDeferredResult() {
6
- let resolve;
7
- let reject;
8
- return {
9
- promise: new Promise((resolvePromise, rejectPromise) => {
10
- resolve = resolvePromise;
11
- reject = rejectPromise;
12
- }),
13
- resolve,
14
- reject
15
- };
16
- }
17
- var LegacyRunTurnEventQueue = class {
18
- constructor() {
19
- this.items = [];
20
- this.waits = [];
21
- this.closed = false;
22
- }
23
- push(item) {
24
- if (this.closed) return;
25
- const waiter = this.waits.shift();
26
- if (waiter) {
27
- waiter.resolve(item);
28
- return;
29
- }
30
- this.items.push(item);
31
- }
32
- clear() {
33
- this.items.length = 0;
34
- }
35
- close() {
36
- if (this.closed) return;
37
- this.closed = true;
38
- for (const waiter of this.waits.splice(0)) waiter.resolve(null);
39
- }
40
- fail(error) {
41
- if (this.closed) return;
42
- this.error = error;
43
- this.closed = true;
44
- for (const waiter of this.waits.splice(0)) waiter.reject(error);
45
- }
46
- async next() {
47
- const item = this.items.shift();
48
- if (item) return item;
49
- if (this.error) throw this.error;
50
- if (this.closed) return null;
51
- return await new Promise((resolve, reject) => {
52
- this.waits.push({
53
- resolve,
54
- reject
55
- });
56
- });
57
- }
58
- async *iterate() {
59
- for (;;) {
60
- const item = await this.next();
61
- if (!item) return;
62
- yield item;
63
- }
64
- }
65
- };
66
- function loadServiceModule() {
67
- serviceModulePromise ??= import("./service-CvQo2rym.js");
68
- return serviceModulePromise;
69
- }
70
- async function startRealService(state) {
71
- if (state.realRuntime) return state.realRuntime;
72
- if (!state.ctx) throw new Error("ACPX runtime service is not started");
73
- state.startPromise ??= (async () => {
74
- const { createAcpxRuntimeService } = await loadServiceModule();
75
- const service = createAcpxRuntimeService(state.params);
76
- state.realService = service;
77
- await service.start(state.ctx);
78
- const backend = getAcpRuntimeBackend(ACPX_BACKEND_ID);
79
- if (!backend?.runtime) throw new Error("ACPX runtime service did not register an ACP backend");
80
- state.realRuntime = backend.runtime;
81
- return state.realRuntime;
82
- })();
83
- try {
84
- return await state.startPromise;
85
- } catch (error) {
86
- state.startPromise = null;
87
- state.realService = null;
88
- throw error;
89
- }
90
- }
91
- function lazyStartTurn(resolveRuntime, input) {
92
- const turnPromise = resolveRuntime().then((runtime) => {
93
- if (runtime.startTurn) return runtime.startTurn(input);
94
- return legacyRunTurnAsStartTurn(runtime, input);
95
- });
96
- return {
97
- requestId: input.requestId,
98
- events: { async *[Symbol.asyncIterator]() {
99
- yield* (await turnPromise).events;
100
- } },
101
- result: turnPromise.then((turn) => turn.result),
102
- cancel(inputArgs) {
103
- return turnPromise.then((turn) => turn.cancel(inputArgs));
104
- },
105
- closeStream(inputArgs) {
106
- return turnPromise.then((turn) => turn.closeStream(inputArgs));
107
- }
108
- };
109
- }
110
- function legacyRunTurnAsStartTurn(runtime, input) {
111
- const result = createDeferredResult();
112
- result.promise.catch(() => {});
113
- const queue = new LegacyRunTurnEventQueue();
114
- let resultSettled = false;
115
- const settleResult = (next) => {
116
- if (resultSettled) return;
117
- resultSettled = true;
118
- result.resolve(next);
119
- };
120
- (async () => {
121
- try {
122
- for await (const event of runtime.runTurn(input)) {
123
- if (event.type === "done") {
124
- settleResult({
125
- status: "completed",
126
- ...event.stopReason ? { stopReason: event.stopReason } : {}
127
- });
128
- continue;
129
- }
130
- if (event.type === "error") {
131
- settleResult({
132
- status: "failed",
133
- error: {
134
- message: event.message,
135
- ...event.code ? { code: event.code } : {},
136
- ...event.detailCode ? { detailCode: event.detailCode } : {},
137
- ...event.retryable === void 0 ? {} : { retryable: event.retryable }
138
- }
139
- });
140
- continue;
141
- }
142
- queue.push(event);
143
- }
144
- settleResult({
145
- status: "failed",
146
- error: {
147
- code: "ACP_TURN_FAILED",
148
- message: "ACP turn ended without a terminal done event."
149
- }
150
- });
151
- } catch (error) {
152
- result.reject(error);
153
- queue.fail(error);
154
- return;
155
- }
156
- queue.close();
157
- })();
158
- return {
159
- requestId: input.requestId,
160
- events: queue.iterate(),
161
- result: result.promise,
162
- async cancel(inputArgs) {
163
- await runtime.cancel({
164
- handle: input.handle,
165
- reason: inputArgs?.reason
166
- });
167
- },
168
- async closeStream() {
169
- queue.clear();
170
- queue.close();
171
- }
172
- };
173
- }
174
- function createDeferredRuntime(state) {
175
- const resolveRuntime = () => startRealService(state);
176
- return {
177
- async ensureSession(input) {
178
- return await (await resolveRuntime()).ensureSession(input);
179
- },
180
- startTurn(input) {
181
- return lazyStartTurn(resolveRuntime, input);
182
- },
183
- async *runTurn(input) {
184
- yield* (await resolveRuntime()).runTurn(input);
185
- },
186
- async getCapabilities(input) {
187
- return await (await resolveRuntime()).getCapabilities?.(input) ?? { controls: [] };
188
- },
189
- async getStatus(input) {
190
- return await (await resolveRuntime()).getStatus?.(input) ?? {};
191
- },
192
- async setMode(input) {
193
- await (await resolveRuntime()).setMode?.(input);
194
- },
195
- async setConfigOption(input) {
196
- await (await resolveRuntime()).setConfigOption?.(input);
197
- },
198
- async doctor() {
199
- return await (await resolveRuntime()).doctor?.() ?? {
200
- ok: true,
201
- message: "ok"
202
- };
203
- },
204
- async prepareFreshSession(input) {
205
- await (await resolveRuntime()).prepareFreshSession?.(input);
206
- },
207
- async cancel(input) {
208
- await (await resolveRuntime()).cancel(input);
209
- },
210
- async close(input) {
211
- await (await resolveRuntime()).close(input);
212
- }
213
- };
214
- }
215
- function createAcpxRuntimeService(params = {}) {
216
- const state = {
217
- ctx: null,
218
- params,
219
- realRuntime: null,
220
- realService: null,
221
- startPromise: null
222
- };
223
- return {
224
- id: "acpx-runtime",
225
- async start(ctx) {
226
- if (process.env.OPENCLAW_SKIP_ACPX_RUNTIME === "1") {
227
- ctx.logger.info("skipping embedded acpx runtime backend (OPENCLAW_SKIP_ACPX_RUNTIME=1)");
228
- return;
229
- }
230
- state.ctx = ctx;
231
- registerAcpRuntimeBackend({
232
- id: ACPX_BACKEND_ID,
233
- runtime: createDeferredRuntime(state)
234
- });
235
- ctx.logger.info("embedded acpx runtime backend registered lazily");
236
- },
237
- async stop(ctx) {
238
- if (state.realService) await state.realService.stop?.(ctx);
239
- else unregisterAcpRuntimeBackend(ACPX_BACKEND_ID);
240
- state.ctx = null;
241
- state.realRuntime = null;
242
- state.realService = null;
243
- state.startPromise = null;
244
- }
245
- };
246
- }
247
- //#endregion
1
+ import { t as createAcpxRuntimeService } from "./register.runtime-CIbEVqqU.js";
248
2
  export { createAcpxRuntimeService };
@@ -5,6 +5,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
5
5
  import fs from "node:fs/promises";
6
6
  import path, { resolve } from "node:path";
7
7
  import { ACPX_BACKEND_ID, AcpxRuntime as AcpxRuntime$1, createAcpRuntime, createAgentRegistry, createFileSessionStore, decodeAcpxRuntimeHandleState, encodeAcpxRuntimeHandleState } from "acpx/runtime";
8
+ import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
8
9
  import { redactSensitiveText } from "openclaw/plugin-sdk/security-runtime";
9
10
  //#region extensions/acpx/src/runtime.ts
10
11
  function withOpenClawManagedTurnTimeout(input) {
@@ -63,7 +64,7 @@ function readRecordAgentPid(record) {
63
64
  if (typeof record !== "object" || record === null) return;
64
65
  const { pid, processId } = record;
65
66
  const rawPid = pid ?? processId;
66
- const numericPid = typeof rawPid === "number" ? rawPid : typeof rawPid === "string" ? Number.parseInt(rawPid, 10) : void 0;
67
+ const numericPid = typeof rawPid === "number" ? rawPid : typeof rawPid === "string" ? parseStrictPositiveInteger(rawPid) : void 0;
67
68
  return numericPid && Number.isInteger(numericPid) && numericPid > 0 ? numericPid : void 0;
68
69
  }
69
70
  function readOpenClawLeaseIdFromRecord(record) {
@@ -1,3 +1,4 @@
1
+ import { n as lazyStartRuntimeTurn } from "./register.runtime-CIbEVqqU.js";
1
2
  import { registerAcpRuntimeBackend, unregisterAcpRuntimeBackend } from "./runtime-api.js";
2
3
  import { a as resolveAcpxPluginRoot, c as OPENCLAW_ACPX_LEASE_ID_ENV, d as createAcpxProcessLeaseStore, h as splitCommandParts, i as resolveAcpxPluginConfig, l as OPENCLAW_GATEWAY_INSTANCE_ID_ARG, m as quoteCommandPart, o as toAcpMcpServers, r as reapStaleOpenClawOwnedAcpxOrphans, s as OPENCLAW_ACPX_LEASE_ID_ARG, t as cleanupOpenClawOwnedAcpxProcessTree } from "./process-reaper-CAUlLOkM.js";
3
4
  import { createRequire } from "node:module";
@@ -800,137 +801,9 @@ const SKIP_RUNTIME_PROBE_ENV = "OPENCLAW_SKIP_ACPX_RUNTIME_PROBE";
800
801
  const ACPX_BACKEND_ID = "acpx";
801
802
  let runtimeModulePromise = null;
802
803
  function loadRuntimeModule() {
803
- runtimeModulePromise ??= import("./runtime-BMXFIXQq.js");
804
+ runtimeModulePromise ??= import("./runtime-BaP1xg1D.js");
804
805
  return runtimeModulePromise;
805
806
  }
806
- function createDeferredResult() {
807
- let resolve;
808
- let reject;
809
- return {
810
- promise: new Promise((resolvePromise, rejectPromise) => {
811
- resolve = resolvePromise;
812
- reject = rejectPromise;
813
- }),
814
- resolve,
815
- reject
816
- };
817
- }
818
- var LegacyRunTurnEventQueue = class {
819
- constructor() {
820
- this.items = [];
821
- this.waits = [];
822
- this.closed = false;
823
- }
824
- push(item) {
825
- if (this.closed) return;
826
- const waiter = this.waits.shift();
827
- if (waiter) {
828
- waiter.resolve(item);
829
- return;
830
- }
831
- this.items.push(item);
832
- }
833
- clear() {
834
- this.items.length = 0;
835
- }
836
- close() {
837
- if (this.closed) return;
838
- this.closed = true;
839
- for (const waiter of this.waits.splice(0)) waiter.resolve(null);
840
- }
841
- fail(error) {
842
- if (this.closed) return;
843
- this.error = error;
844
- this.closed = true;
845
- for (const waiter of this.waits.splice(0)) waiter.reject(error);
846
- }
847
- async next() {
848
- const item = this.items.shift();
849
- if (item) return item;
850
- if (this.error) throw this.error;
851
- if (this.closed) return null;
852
- return await new Promise((resolve, reject) => {
853
- this.waits.push({
854
- resolve,
855
- reject
856
- });
857
- });
858
- }
859
- async *iterate() {
860
- for (;;) {
861
- const item = await this.next();
862
- if (!item) return;
863
- yield item;
864
- }
865
- }
866
- };
867
- function legacyRunTurnAsStartTurn(runtime, input) {
868
- const result = createDeferredResult();
869
- result.promise.catch(() => {});
870
- const queue = new LegacyRunTurnEventQueue();
871
- let resultSettled = false;
872
- const settleResult = (next) => {
873
- if (resultSettled) return;
874
- resultSettled = true;
875
- result.resolve(next);
876
- };
877
- (async () => {
878
- try {
879
- for await (const event of runtime.runTurn(input)) {
880
- if (event.type === "done") {
881
- settleResult({
882
- status: "completed",
883
- ...event.stopReason ? { stopReason: event.stopReason } : {}
884
- });
885
- continue;
886
- }
887
- if (event.type === "error") {
888
- settleResult({
889
- status: "failed",
890
- error: {
891
- message: event.message,
892
- ...event.code ? { code: event.code } : {},
893
- ...event.detailCode ? { detailCode: event.detailCode } : {},
894
- ...event.retryable === void 0 ? {} : { retryable: event.retryable }
895
- }
896
- });
897
- continue;
898
- }
899
- queue.push(event);
900
- }
901
- settleResult({
902
- status: "failed",
903
- error: {
904
- code: "ACP_TURN_FAILED",
905
- message: "ACP turn ended without a terminal done event."
906
- }
907
- });
908
- } catch (error) {
909
- result.reject(error);
910
- queue.fail(error);
911
- return;
912
- }
913
- queue.close();
914
- })();
915
- return {
916
- requestId: input.requestId,
917
- events: queue.iterate(),
918
- result: result.promise,
919
- async cancel(inputArgs) {
920
- await runtime.cancel({
921
- handle: input.handle,
922
- reason: inputArgs?.reason
923
- });
924
- },
925
- async closeStream() {
926
- queue.clear();
927
- queue.close();
928
- }
929
- };
930
- }
931
- function startRuntimeTurn(runtime, input) {
932
- return runtime.startTurn?.(input) ?? legacyRunTurnAsStartTurn(runtime, input);
933
- }
934
807
  function createLazyDefaultRuntime(params) {
935
808
  let runtime = null;
936
809
  let runtimePromise = null;
@@ -959,20 +832,7 @@ function createLazyDefaultRuntime(params) {
959
832
  return await (await resolveRuntime()).ensureSession(input);
960
833
  },
961
834
  startTurn(input) {
962
- const turnPromise = resolveRuntime().then((resolved) => startRuntimeTurn(resolved, input));
963
- return {
964
- requestId: input.requestId,
965
- events: { async *[Symbol.asyncIterator]() {
966
- yield* (await turnPromise).events;
967
- } },
968
- result: turnPromise.then((turn) => turn.result),
969
- cancel(inputArgs) {
970
- return turnPromise.then((turn) => turn.cancel(inputArgs));
971
- },
972
- closeStream(inputArgs) {
973
- return turnPromise.then((turn) => turn.closeStream(inputArgs));
974
- }
975
- };
835
+ return lazyStartRuntimeTurn(resolveRuntime, input);
976
836
  },
977
837
  async *runTurn(input) {
978
838
  yield* (await resolveRuntime()).runTurn(input);
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@openclaw/acpx",
3
- "version": "2026.5.27",
3
+ "version": "2026.5.28-beta.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/acpx",
9
- "version": "2026.5.27",
9
+ "version": "2026.5.28-beta.1",
10
10
  "dependencies": {
11
11
  "@agentclientprotocol/claude-agent-acp": "0.37.0",
12
12
  "@zed-industries/codex-acp": "0.15.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/acpx",
3
- "version": "2026.5.27",
3
+ "version": "2026.5.28-beta.1",
4
4
  "description": "OpenClaw ACP runtime backend with plugin-owned session and transport management.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,19 +26,15 @@
26
26
  "minHostVersion": ">=2026.4.25"
27
27
  },
28
28
  "compat": {
29
- "pluginApi": ">=2026.5.27"
29
+ "pluginApi": ">=2026.5.28-beta.1"
30
30
  },
31
31
  "build": {
32
- "openclawVersion": "2026.5.27",
32
+ "openclawVersion": "2026.5.28-beta.1",
33
33
  "staticAssets": [
34
34
  {
35
35
  "source": "./src/runtime-internals/mcp-proxy.mjs",
36
36
  "output": "mcp-proxy.mjs"
37
37
  },
38
- {
39
- "source": "./src/runtime-internals/error-format.mjs",
40
- "output": "error-format.mjs"
41
- },
42
38
  {
43
39
  "source": "./src/runtime-internals/mcp-command-line.mjs",
44
40
  "output": "mcp-command-line.mjs"
@@ -61,7 +57,7 @@
61
57
  "skills/**"
62
58
  ],
63
59
  "peerDependencies": {
64
- "openclaw": ">=2026.5.27"
60
+ "openclaw": ">=2026.5.28-beta.1"
65
61
  },
66
62
  "peerDependenciesMeta": {
67
63
  "openclaw": {
@@ -1,12 +1,12 @@
1
1
  ---
2
2
  name: acp-router
3
- description: Route plain-language requests for Pi, Claude Code, Cursor, Copilot, OpenClaw ACP, OpenCode, Gemini CLI, Qwen, Kiro, Kimi, iFlow, Factory Droid, Kilocode, or explicit ACP harness work into either OpenClaw ACP runtime sessions or direct acpx-driven sessions ("telephone game" flow). For coding-agent thread requests, read this skill first, then use only `sessions_spawn` for thread creation. Codex chat binding defaults to the native Codex app-server plugin unless ACP is explicit or background spawn needs ACP.
3
+ description: Route plain-language requests for Claude Code, Cursor, Copilot, OpenClaw ACP, OpenCode, Gemini CLI, Qwen, Kiro, Kimi, iFlow, Factory Droid, Kilocode, or explicit ACP harness work into either OpenClaw ACP runtime sessions or direct acpx-driven sessions ("telephone game" flow). For coding-agent thread requests, read this skill first, then use only `sessions_spawn` for thread creation. Codex chat binding defaults to the native Codex app-server plugin unless ACP is explicit or background spawn needs ACP.
4
4
  user-invocable: false
5
5
  ---
6
6
 
7
7
  # ACP Harness Router
8
8
 
9
- When user intent is "run this in Pi/Claude Code/Cursor/Copilot/OpenClaw/OpenCode/Gemini/Qwen/Kiro/Kimi/iFlow/Droid/Kilocode (ACP harness)", do not use subagent runtime or PTY scraping. Route through ACP-aware flows.
9
+ When user intent is "run this in Claude Code/Cursor/Copilot/OpenClaw/OpenCode/Gemini/Qwen/Kiro/Kimi/iFlow/Droid/Kilocode (ACP harness)", do not use subagent runtime or PTY scraping. Route through ACP-aware flows.
10
10
 
11
11
  Codex is special: plain chat/conversation binding and control should use the native Codex app-server plugin (`/codex bind`, `/codex threads`, `/codex resume`) instead of the default ACP path. Use ACP for Codex only when the user explicitly names ACP/`/acp`/acpx, or when spawning background child sessions through `sessions_spawn` where a native Codex runtime spawn is not available yet.
12
12
 
@@ -14,7 +14,7 @@ Codex is special: plain chat/conversation binding and control should use the nat
14
14
 
15
15
  Trigger this skill when the user asks OpenClaw to:
16
16
 
17
- - run something in Pi / Claude Code / Cursor / Copilot / OpenClaw / OpenCode / Gemini / Qwen / Kiro / Kimi / iFlow / Droid / Kilocode
17
+ - run something in Claude Code / Cursor / Copilot / OpenClaw / OpenCode / Gemini / Qwen / Kiro / Kimi / iFlow / Droid / Kilocode
18
18
  - run Codex explicitly through ACP, `/acp`, or acpx
19
19
  - continue existing harness work
20
20
  - relay instructions to an external coding harness
@@ -48,7 +48,6 @@ Do not use:
48
48
 
49
49
  Use these defaults when user names a harness directly:
50
50
 
51
- - "pi" -> `agentId: "pi"`
52
51
  - "openclaw" -> `agentId: "openclaw"`
53
52
  - "claude" or "claude code" -> `agentId: "claude"`
54
53
  - "codex" -> `agentId: "codex"` only for explicit ACP/acpx requests or background ACP runtime spawn
@@ -203,7 +202,6 @@ ${ACPX_CMD} codex sessions close oc-codex-<conversationId>
203
202
  - `kiro`
204
203
  - `openclaw`
205
204
  - `opencode`
206
- - `pi`
207
205
  - `qwen`
208
206
 
209
207
  ### Built-in adapter commands in acpx
@@ -222,7 +220,6 @@ Defaults are:
222
220
  - `kimi -> kimi acp`
223
221
  - `kiro -> kiro-cli acp`
224
222
  - `opencode -> npx -y opencode-ai acp`
225
- - `pi -> npx pi-acp@^0.0.22`
226
223
  - `qwen -> qwen --acp`
227
224
 
228
225
  If `~/.acpx/config.json` overrides `agents`, those overrides replace defaults.
@@ -1,6 +0,0 @@
1
- export function formatErrorMessage(error) {
2
- if (error instanceof Error) {
3
- return error.message || error.name || "Error";
4
- }
5
- return String(error);
6
- }