
























@@ -1 +1,154 @@
1-export { createAcpxRuntimeService } from "./src/service.js";
1+import {
2+getAcpRuntimeBackend,
3+registerAcpRuntimeBackend,
4+unregisterAcpRuntimeBackend,
5+type AcpRuntime,
6+type AcpRuntimeCapabilities,
7+type AcpRuntimeDoctorReport,
8+type AcpRuntimeStatus,
9+} from "openclaw/plugin-sdk/acp-runtime-backend";
10+import type { OpenClawPluginService, OpenClawPluginServiceContext } from "openclaw/plugin-sdk/core";
11+12+const ACPX_BACKEND_ID = "acpx";
13+const ENABLE_STARTUP_PROBE_ENV = "OPENCLAW_ACPX_RUNTIME_STARTUP_PROBE";
14+15+type RealAcpxServiceModule = typeof import("./src/service.js");
16+type CreateAcpxRuntimeServiceParams = NonNullable<
17+Parameters<RealAcpxServiceModule["createAcpxRuntimeService"]>[0]
18+>;
19+20+type AcpxRuntimeLike = AcpRuntime & {
21+probeAvailability(): Promise<void>;
22+doctor?(): Promise<AcpRuntimeDoctorReport>;
23+isHealthy(): boolean;
24+};
25+26+type DeferredServiceState = {
27+ctx: OpenClawPluginServiceContext | null;
28+params: CreateAcpxRuntimeServiceParams;
29+realRuntime: AcpxRuntimeLike | null;
30+realService: OpenClawPluginService | null;
31+startPromise: Promise<AcpxRuntimeLike> | null;
32+};
33+34+let serviceModulePromise: Promise<RealAcpxServiceModule> | null = null;
35+36+function loadServiceModule(): Promise<RealAcpxServiceModule> {
37+serviceModulePromise ??= import("./src/service.js");
38+return serviceModulePromise;
39+}
40+41+function shouldRunStartupProbe(env: NodeJS.ProcessEnv = process.env): boolean {
42+return env[ENABLE_STARTUP_PROBE_ENV] === "1";
43+}
44+45+async function startRealService(state: DeferredServiceState): Promise<AcpxRuntimeLike> {
46+if (state.realRuntime) {
47+return state.realRuntime;
48+}
49+if (!state.ctx) {
50+throw new Error("ACPX runtime service is not started");
51+}
52+state.startPromise ??= (async () => {
53+const { createAcpxRuntimeService } = await loadServiceModule();
54+const service = createAcpxRuntimeService(state.params);
55+state.realService = service;
56+await service.start(state.ctx as OpenClawPluginServiceContext);
57+const backend = getAcpRuntimeBackend(ACPX_BACKEND_ID);
58+if (!backend?.runtime) {
59+throw new Error("ACPX runtime service did not register an ACP backend");
60+}
61+state.realRuntime = backend.runtime as AcpxRuntimeLike;
62+return state.realRuntime;
63+})();
64+return await state.startPromise;
65+}
66+67+function createDeferredRuntime(state: DeferredServiceState): AcpxRuntimeLike {
68+return {
69+async ensureSession(input) {
70+return await (await startRealService(state)).ensureSession(input);
71+},
72+async *runTurn(input) {
73+yield* (await startRealService(state)).runTurn(input);
74+},
75+async getCapabilities(input): Promise<AcpRuntimeCapabilities> {
76+const runtime = await startRealService(state);
77+return (await runtime.getCapabilities?.(input)) ?? { controls: [] };
78+},
79+async getStatus(input): Promise<AcpRuntimeStatus> {
80+const runtime = await startRealService(state);
81+return (await runtime.getStatus?.(input)) ?? {};
82+},
83+async setMode(input) {
84+await (await startRealService(state)).setMode?.(input);
85+},
86+async setConfigOption(input) {
87+await (await startRealService(state)).setConfigOption?.(input);
88+},
89+async doctor(): Promise<AcpRuntimeDoctorReport> {
90+const runtime = await startRealService(state);
91+return (await runtime.doctor?.()) ?? { ok: true, message: "ok" };
92+},
93+async prepareFreshSession(input) {
94+await (await startRealService(state)).prepareFreshSession?.(input);
95+},
96+async cancel(input) {
97+await (await startRealService(state)).cancel(input);
98+},
99+async close(input) {
100+await (await startRealService(state)).close(input);
101+},
102+async probeAvailability() {
103+await (await startRealService(state)).probeAvailability();
104+},
105+isHealthy() {
106+return state.realRuntime?.isHealthy() ?? false;
107+},
108+};
109+}
110+111+export function createAcpxRuntimeService(
112+params: CreateAcpxRuntimeServiceParams = {},
113+): OpenClawPluginService {
114+const state: DeferredServiceState = {
115+ctx: null,
116+ params,
117+realRuntime: null,
118+realService: null,
119+startPromise: null,
120+};
121+122+return {
123+id: "acpx-runtime",
124+async start(ctx) {
125+if (process.env.OPENCLAW_SKIP_ACPX_RUNTIME === "1") {
126+ctx.logger.info("skipping embedded acpx runtime backend (OPENCLAW_SKIP_ACPX_RUNTIME=1)");
127+return;
128+}
129+130+state.ctx = ctx;
131+if (shouldRunStartupProbe()) {
132+await startRealService(state);
133+return;
134+}
135+136+registerAcpRuntimeBackend({
137+id: ACPX_BACKEND_ID,
138+runtime: createDeferredRuntime(state),
139+});
140+ctx.logger.info("embedded acpx runtime backend registered lazily");
141+},
142+async stop(ctx) {
143+if (state.realService) {
144+await state.realService.stop?.(ctx);
145+} else {
146+unregisterAcpRuntimeBackend(ACPX_BACKEND_ID);
147+}
148+state.ctx = null;
149+state.realRuntime = null;
150+state.realService = null;
151+state.startPromise = null;
152+},
153+};
154+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。