@openclaw/acpx 2026.5.2-beta.1 → 2026.5.3-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 +14 -0
- package/dist/register.runtime.js +108 -0
- package/dist/runtime-B3LWev_t.js +357 -0
- package/dist/runtime-api.js +4 -0
- package/dist/service-YhcC786_.js +665 -0
- package/dist/setup-api.js +16 -0
- package/package.json +33 -3
- package/AGENTS.md +0 -54
- package/index.test.ts +0 -119
- package/index.ts +0 -19
- package/register.runtime.ts +0 -154
- package/runtime-api.ts +0 -46
- package/setup-api.ts +0 -18
- package/src/acpx-runtime-compat.d.ts +0 -62
- package/src/claude-agent-acp-completion.test.ts +0 -129
- package/src/codex-auth-bridge.test.ts +0 -448
- package/src/codex-auth-bridge.ts +0 -385
- package/src/config-schema.ts +0 -117
- package/src/config.test.ts +0 -144
- package/src/config.ts +0 -273
- package/src/manifest.test.ts +0 -20
- package/src/runtime-internals/mcp-command-line.test.ts +0 -59
- package/src/runtime-internals/mcp-proxy.test.ts +0 -114
- package/src/runtime.test.ts +0 -816
- package/src/runtime.ts +0 -613
- package/src/service.test.ts +0 -401
- package/src/service.ts +0 -278
- package/tsconfig.json +0 -16
- /package/{src/runtime-internals → dist}/error-format.mjs +0 -0
- /package/{src/runtime-internals → dist}/mcp-command-line.mjs +0 -0
- /package/{src/runtime-internals → dist}/mcp-proxy.mjs +0 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createAcpxRuntimeService } from "./register.runtime.js";
|
|
2
|
+
import { tryDispatchAcpReplyHook } from "openclaw/plugin-sdk/acp-runtime-backend";
|
|
3
|
+
//#region extensions/acpx/index.ts
|
|
4
|
+
const plugin = {
|
|
5
|
+
id: "acpx",
|
|
6
|
+
name: "ACPX Runtime",
|
|
7
|
+
description: "Embedded ACP runtime backend with plugin-owned session and transport management.",
|
|
8
|
+
register(api) {
|
|
9
|
+
api.registerService(createAcpxRuntimeService({ pluginConfig: api.pluginConfig }));
|
|
10
|
+
api.on("reply_dispatch", tryDispatchAcpReplyHook);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { plugin as default };
|
|
@@ -0,0 +1,108 @@
|
|
|
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
|
+
const ENABLE_STARTUP_PROBE_ENV = "OPENCLAW_ACPX_RUNTIME_STARTUP_PROBE";
|
|
5
|
+
let serviceModulePromise = null;
|
|
6
|
+
function loadServiceModule() {
|
|
7
|
+
serviceModulePromise ??= import("./service-YhcC786_.js");
|
|
8
|
+
return serviceModulePromise;
|
|
9
|
+
}
|
|
10
|
+
function shouldRunStartupProbe(env = process.env) {
|
|
11
|
+
return env[ENABLE_STARTUP_PROBE_ENV] === "1";
|
|
12
|
+
}
|
|
13
|
+
async function startRealService(state) {
|
|
14
|
+
if (state.realRuntime) return state.realRuntime;
|
|
15
|
+
if (!state.ctx) throw new Error("ACPX runtime service is not started");
|
|
16
|
+
state.startPromise ??= (async () => {
|
|
17
|
+
const { createAcpxRuntimeService } = await loadServiceModule();
|
|
18
|
+
const service = createAcpxRuntimeService(state.params);
|
|
19
|
+
state.realService = service;
|
|
20
|
+
await service.start(state.ctx);
|
|
21
|
+
const backend = getAcpRuntimeBackend(ACPX_BACKEND_ID);
|
|
22
|
+
if (!backend?.runtime) throw new Error("ACPX runtime service did not register an ACP backend");
|
|
23
|
+
state.realRuntime = backend.runtime;
|
|
24
|
+
return state.realRuntime;
|
|
25
|
+
})();
|
|
26
|
+
return await state.startPromise;
|
|
27
|
+
}
|
|
28
|
+
function createDeferredRuntime(state) {
|
|
29
|
+
return {
|
|
30
|
+
async ensureSession(input) {
|
|
31
|
+
return await (await startRealService(state)).ensureSession(input);
|
|
32
|
+
},
|
|
33
|
+
async *runTurn(input) {
|
|
34
|
+
yield* (await startRealService(state)).runTurn(input);
|
|
35
|
+
},
|
|
36
|
+
async getCapabilities(input) {
|
|
37
|
+
return await (await startRealService(state)).getCapabilities?.(input) ?? { controls: [] };
|
|
38
|
+
},
|
|
39
|
+
async getStatus(input) {
|
|
40
|
+
return await (await startRealService(state)).getStatus?.(input) ?? {};
|
|
41
|
+
},
|
|
42
|
+
async setMode(input) {
|
|
43
|
+
await (await startRealService(state)).setMode?.(input);
|
|
44
|
+
},
|
|
45
|
+
async setConfigOption(input) {
|
|
46
|
+
await (await startRealService(state)).setConfigOption?.(input);
|
|
47
|
+
},
|
|
48
|
+
async doctor() {
|
|
49
|
+
return await (await startRealService(state)).doctor?.() ?? {
|
|
50
|
+
ok: true,
|
|
51
|
+
message: "ok"
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
async prepareFreshSession(input) {
|
|
55
|
+
await (await startRealService(state)).prepareFreshSession?.(input);
|
|
56
|
+
},
|
|
57
|
+
async cancel(input) {
|
|
58
|
+
await (await startRealService(state)).cancel(input);
|
|
59
|
+
},
|
|
60
|
+
async close(input) {
|
|
61
|
+
await (await startRealService(state)).close(input);
|
|
62
|
+
},
|
|
63
|
+
async probeAvailability() {
|
|
64
|
+
await (await startRealService(state)).probeAvailability();
|
|
65
|
+
},
|
|
66
|
+
isHealthy() {
|
|
67
|
+
return state.realRuntime?.isHealthy() ?? false;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function createAcpxRuntimeService(params = {}) {
|
|
72
|
+
const state = {
|
|
73
|
+
ctx: null,
|
|
74
|
+
params,
|
|
75
|
+
realRuntime: null,
|
|
76
|
+
realService: null,
|
|
77
|
+
startPromise: null
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
id: "acpx-runtime",
|
|
81
|
+
async start(ctx) {
|
|
82
|
+
if (process.env.OPENCLAW_SKIP_ACPX_RUNTIME === "1") {
|
|
83
|
+
ctx.logger.info("skipping embedded acpx runtime backend (OPENCLAW_SKIP_ACPX_RUNTIME=1)");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
state.ctx = ctx;
|
|
87
|
+
if (shouldRunStartupProbe()) {
|
|
88
|
+
await startRealService(state);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
registerAcpRuntimeBackend({
|
|
92
|
+
id: ACPX_BACKEND_ID,
|
|
93
|
+
runtime: createDeferredRuntime(state)
|
|
94
|
+
});
|
|
95
|
+
ctx.logger.info("embedded acpx runtime backend registered lazily");
|
|
96
|
+
},
|
|
97
|
+
async stop(ctx) {
|
|
98
|
+
if (state.realService) await state.realService.stop?.(ctx);
|
|
99
|
+
else unregisterAcpRuntimeBackend(ACPX_BACKEND_ID);
|
|
100
|
+
state.ctx = null;
|
|
101
|
+
state.realRuntime = null;
|
|
102
|
+
state.realService = null;
|
|
103
|
+
state.startPromise = null;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
export { createAcpxRuntimeService };
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { AcpRuntimeError } from "./runtime-api.js";
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
import { ACPX_BACKEND_ID, AcpxRuntime as AcpxRuntime$1, createAcpRuntime, createAgentRegistry, createFileSessionStore, decodeAcpxRuntimeHandleState, encodeAcpxRuntimeHandleState } from "acpx/runtime";
|
|
4
|
+
//#region extensions/acpx/src/runtime.ts
|
|
5
|
+
function readSessionRecordName(record) {
|
|
6
|
+
if (typeof record !== "object" || record === null) return "";
|
|
7
|
+
const { name } = record;
|
|
8
|
+
return typeof name === "string" ? name.trim() : "";
|
|
9
|
+
}
|
|
10
|
+
function createResetAwareSessionStore(baseStore) {
|
|
11
|
+
const freshSessionKeys = /* @__PURE__ */ new Set();
|
|
12
|
+
return {
|
|
13
|
+
async load(sessionId) {
|
|
14
|
+
const normalized = sessionId.trim();
|
|
15
|
+
if (normalized && freshSessionKeys.has(normalized)) return;
|
|
16
|
+
return await baseStore.load(sessionId);
|
|
17
|
+
},
|
|
18
|
+
async save(record) {
|
|
19
|
+
await baseStore.save(record);
|
|
20
|
+
const sessionName = readSessionRecordName(record);
|
|
21
|
+
if (sessionName) freshSessionKeys.delete(sessionName);
|
|
22
|
+
},
|
|
23
|
+
markFresh(sessionKey) {
|
|
24
|
+
const normalized = sessionKey.trim();
|
|
25
|
+
if (normalized) freshSessionKeys.add(normalized);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const OPENCLAW_BRIDGE_EXECUTABLE = "openclaw";
|
|
30
|
+
const OPENCLAW_BRIDGE_SUBCOMMAND = "acp";
|
|
31
|
+
const CODEX_ACP_AGENT_ID = "codex";
|
|
32
|
+
const CODEX_ACP_OPENCLAW_PREFIX = "openai-codex/";
|
|
33
|
+
const CODEX_ACP_REASONING_EFFORTS = new Set([
|
|
34
|
+
"low",
|
|
35
|
+
"medium",
|
|
36
|
+
"high",
|
|
37
|
+
"xhigh"
|
|
38
|
+
]);
|
|
39
|
+
const CODEX_ACP_THINKING_ALIASES = new Map([
|
|
40
|
+
["off", void 0],
|
|
41
|
+
["minimal", "low"],
|
|
42
|
+
["low", "low"],
|
|
43
|
+
["medium", "medium"],
|
|
44
|
+
["high", "high"],
|
|
45
|
+
["x-high", "xhigh"],
|
|
46
|
+
["x_high", "xhigh"],
|
|
47
|
+
["extra-high", "xhigh"],
|
|
48
|
+
["extra_high", "xhigh"],
|
|
49
|
+
["extra high", "xhigh"],
|
|
50
|
+
["xhigh", "xhigh"]
|
|
51
|
+
]);
|
|
52
|
+
function normalizeAgentName(value) {
|
|
53
|
+
const normalized = value?.trim().toLowerCase();
|
|
54
|
+
return normalized ? normalized : void 0;
|
|
55
|
+
}
|
|
56
|
+
function readAgentFromSessionKey(sessionKey) {
|
|
57
|
+
const normalized = sessionKey?.trim();
|
|
58
|
+
if (!normalized) return;
|
|
59
|
+
return normalizeAgentName(/^agent:(?<agent>[^:]+):/i.exec(normalized)?.groups?.agent);
|
|
60
|
+
}
|
|
61
|
+
function readAgentFromHandle(handle) {
|
|
62
|
+
const decoded = decodeAcpxRuntimeHandleState(handle.runtimeSessionName);
|
|
63
|
+
if (typeof decoded === "object" && decoded !== null) {
|
|
64
|
+
const { agent } = decoded;
|
|
65
|
+
if (typeof agent === "string") return normalizeAgentName(agent) ?? readAgentFromSessionKey(handle.sessionKey);
|
|
66
|
+
}
|
|
67
|
+
return readAgentFromSessionKey(handle.sessionKey);
|
|
68
|
+
}
|
|
69
|
+
function readAgentCommandFromRecord(record) {
|
|
70
|
+
if (typeof record !== "object" || record === null) return;
|
|
71
|
+
const { agentCommand } = record;
|
|
72
|
+
return typeof agentCommand === "string" ? agentCommand.trim() || void 0 : void 0;
|
|
73
|
+
}
|
|
74
|
+
function splitCommandParts(value) {
|
|
75
|
+
const parts = [];
|
|
76
|
+
let current = "";
|
|
77
|
+
let quote = null;
|
|
78
|
+
let escaping = false;
|
|
79
|
+
for (const ch of value) {
|
|
80
|
+
if (escaping) {
|
|
81
|
+
current += ch;
|
|
82
|
+
escaping = false;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (ch === "\\" && quote !== "'") {
|
|
86
|
+
escaping = true;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (quote) {
|
|
90
|
+
if (ch === quote) quote = null;
|
|
91
|
+
else current += ch;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (ch === "'" || ch === "\"") {
|
|
95
|
+
quote = ch;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (/\s/.test(ch)) {
|
|
99
|
+
if (current) {
|
|
100
|
+
parts.push(current);
|
|
101
|
+
current = "";
|
|
102
|
+
}
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
current += ch;
|
|
106
|
+
}
|
|
107
|
+
if (escaping) current += "\\";
|
|
108
|
+
if (current) parts.push(current);
|
|
109
|
+
return parts;
|
|
110
|
+
}
|
|
111
|
+
function basename(value) {
|
|
112
|
+
return value.split(/[\\/]/).pop() ?? value;
|
|
113
|
+
}
|
|
114
|
+
function isEnvAssignment(value) {
|
|
115
|
+
return /^[A-Za-z_][A-Za-z0-9_]*=/.test(value);
|
|
116
|
+
}
|
|
117
|
+
function unwrapEnvCommand(parts) {
|
|
118
|
+
if (!parts.length || basename(parts[0]) !== "env") return parts;
|
|
119
|
+
let index = 1;
|
|
120
|
+
while (index < parts.length && isEnvAssignment(parts[index])) index += 1;
|
|
121
|
+
return parts.slice(index);
|
|
122
|
+
}
|
|
123
|
+
function isOpenClawBridgeCommand(command) {
|
|
124
|
+
if (!command) return false;
|
|
125
|
+
const parts = unwrapEnvCommand(splitCommandParts(command.trim()));
|
|
126
|
+
if (basename(parts[0] ?? "") === OPENCLAW_BRIDGE_EXECUTABLE) return parts[1] === OPENCLAW_BRIDGE_SUBCOMMAND;
|
|
127
|
+
if (basename(parts[0] ?? "") !== "node") return false;
|
|
128
|
+
const scriptName = basename(parts[1] ?? "");
|
|
129
|
+
return /^openclaw(?:\.[cm]?js)?$/i.test(scriptName) && parts[2] === OPENCLAW_BRIDGE_SUBCOMMAND;
|
|
130
|
+
}
|
|
131
|
+
function isCodexAcpPackageSpec(value) {
|
|
132
|
+
return /^@zed-industries\/codex-acp(?:@.+)?$/i.test(value.trim());
|
|
133
|
+
}
|
|
134
|
+
function isCodexAcpCommand(command) {
|
|
135
|
+
if (!command) return false;
|
|
136
|
+
const parts = unwrapEnvCommand(splitCommandParts(command.trim()));
|
|
137
|
+
if (!parts.length) return false;
|
|
138
|
+
if (parts.some(isCodexAcpPackageSpec)) return true;
|
|
139
|
+
const commandName = basename(parts[0] ?? "");
|
|
140
|
+
if (/^codex-acp(?:\.exe)?$/i.test(commandName)) return true;
|
|
141
|
+
if (commandName !== "node") return false;
|
|
142
|
+
const scriptName = basename(parts[1] ?? "");
|
|
143
|
+
return /^codex-acp(?:-wrapper)?(?:\.[cm]?js)?$/i.test(scriptName);
|
|
144
|
+
}
|
|
145
|
+
function failUnsupportedCodexAcpModel(rawModel, detail) {
|
|
146
|
+
throw new AcpRuntimeError("ACP_INVALID_RUNTIME_OPTION", detail ?? `Codex ACP model "${rawModel}" is not supported. Use openai-codex/<model> or <model>/<reasoning-effort>.`);
|
|
147
|
+
}
|
|
148
|
+
const SUPPORTED_RUNTIME_SESSION_MODES = new Set(["persistent", "oneshot"]);
|
|
149
|
+
function assertSupportedRuntimeSessionMode(mode) {
|
|
150
|
+
if (typeof mode === "string" && SUPPORTED_RUNTIME_SESSION_MODES.has(mode)) return;
|
|
151
|
+
const supported = Array.from(SUPPORTED_RUNTIME_SESSION_MODES).join(", ");
|
|
152
|
+
throw new AcpRuntimeError("ACP_INVALID_RUNTIME_OPTION", `Unsupported ACP runtime session mode ${JSON.stringify(mode)}. Expected one of: ${supported}.`);
|
|
153
|
+
}
|
|
154
|
+
function failUnsupportedCodexAcpThinking(rawThinking) {
|
|
155
|
+
throw new AcpRuntimeError("ACP_INVALID_RUNTIME_OPTION", `Codex ACP thinking level "${rawThinking}" is not supported. Use off, minimal, low, medium, high, or xhigh.`);
|
|
156
|
+
}
|
|
157
|
+
function normalizeCodexAcpReasoningEffort(rawThinking) {
|
|
158
|
+
const normalized = rawThinking?.trim().toLowerCase();
|
|
159
|
+
if (!normalized) return;
|
|
160
|
+
if (!CODEX_ACP_THINKING_ALIASES.has(normalized)) failUnsupportedCodexAcpThinking(rawThinking ?? "");
|
|
161
|
+
return CODEX_ACP_THINKING_ALIASES.get(normalized);
|
|
162
|
+
}
|
|
163
|
+
function normalizeCodexAcpModelOverride(rawModel, rawThinking) {
|
|
164
|
+
const raw = rawModel?.trim();
|
|
165
|
+
const thinkingReasoningEffort = normalizeCodexAcpReasoningEffort(rawThinking);
|
|
166
|
+
if (!raw) return thinkingReasoningEffort ? { reasoningEffort: thinkingReasoningEffort } : void 0;
|
|
167
|
+
let value = raw;
|
|
168
|
+
if (value.toLowerCase().startsWith(CODEX_ACP_OPENCLAW_PREFIX)) value = value.slice(13);
|
|
169
|
+
const parts = value.split("/");
|
|
170
|
+
if (parts.length > 2) failUnsupportedCodexAcpModel(raw, `Codex ACP model "${raw}" is not supported. Use openai-codex/<model> or <model>/<reasoning-effort>.`);
|
|
171
|
+
const model = (parts[0] ?? "").trim();
|
|
172
|
+
const modelReasoningEffort = normalizeCodexAcpReasoningEffort(parts[1]);
|
|
173
|
+
if (!model) failUnsupportedCodexAcpModel(raw, `Codex ACP model "${raw}" is not supported. Use openai-codex/<model> or <model>/<reasoning-effort>.`);
|
|
174
|
+
const reasoningEffort = thinkingReasoningEffort ?? modelReasoningEffort;
|
|
175
|
+
if (reasoningEffort && !CODEX_ACP_REASONING_EFFORTS.has(reasoningEffort)) failUnsupportedCodexAcpThinking(reasoningEffort);
|
|
176
|
+
return {
|
|
177
|
+
model,
|
|
178
|
+
...reasoningEffort ? { reasoningEffort } : {}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function codexAcpSessionModelId(override) {
|
|
182
|
+
if (!override.model) return "";
|
|
183
|
+
return override.reasoningEffort ? `${override.model}/${override.reasoningEffort}` : override.model;
|
|
184
|
+
}
|
|
185
|
+
function quoteShellArg(value) {
|
|
186
|
+
if (/^[A-Za-z0-9_./:=@+-]+$/.test(value)) return value;
|
|
187
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
188
|
+
}
|
|
189
|
+
function appendCodexAcpConfigOverrides(command, override) {
|
|
190
|
+
const configArgs = override.model ? [`model=${override.model}`] : [];
|
|
191
|
+
if (override.reasoningEffort) configArgs.push(`model_reasoning_effort=${override.reasoningEffort}`);
|
|
192
|
+
if (configArgs.length === 0) return command;
|
|
193
|
+
return `${command} ${configArgs.map((arg) => `-c ${quoteShellArg(arg)}`).join(" ")}`;
|
|
194
|
+
}
|
|
195
|
+
function createModelScopedAgentRegistry(params) {
|
|
196
|
+
return {
|
|
197
|
+
resolve(agentName) {
|
|
198
|
+
const command = params.agentRegistry.resolve(agentName);
|
|
199
|
+
const override = params.scope.getStore();
|
|
200
|
+
if (!override || normalizeAgentName(agentName) !== CODEX_ACP_AGENT_ID || typeof command !== "string" || !isCodexAcpCommand(command)) return command;
|
|
201
|
+
return appendCodexAcpConfigOverrides(command, override);
|
|
202
|
+
},
|
|
203
|
+
list() {
|
|
204
|
+
return params.agentRegistry.list();
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function resolveAgentCommand(params) {
|
|
209
|
+
const normalizedAgentName = normalizeAgentName(params.agentName);
|
|
210
|
+
if (!normalizedAgentName) return;
|
|
211
|
+
const resolvedCommand = params.agentRegistry.resolve(normalizedAgentName);
|
|
212
|
+
return typeof resolvedCommand === "string" ? resolvedCommand.trim() || void 0 : void 0;
|
|
213
|
+
}
|
|
214
|
+
function resolveProbeAgentName(options) {
|
|
215
|
+
const { probeAgent } = options;
|
|
216
|
+
return normalizeAgentName(typeof probeAgent === "string" ? probeAgent : void 0) ?? "codex";
|
|
217
|
+
}
|
|
218
|
+
function resolveAgentCommandForName(params) {
|
|
219
|
+
return resolveAgentCommand(params);
|
|
220
|
+
}
|
|
221
|
+
function shouldUseBridgeSafeDelegateForCommand(command) {
|
|
222
|
+
return isOpenClawBridgeCommand(command);
|
|
223
|
+
}
|
|
224
|
+
function shouldUseDistinctBridgeDelegate(options) {
|
|
225
|
+
const { mcpServers } = options;
|
|
226
|
+
return Array.isArray(mcpServers) && mcpServers.length > 0;
|
|
227
|
+
}
|
|
228
|
+
var AcpxRuntime = class {
|
|
229
|
+
constructor(options, testOptions) {
|
|
230
|
+
this.codexAcpModelOverrideScope = new AsyncLocalStorage();
|
|
231
|
+
this.sessionStore = createResetAwareSessionStore(options.sessionStore);
|
|
232
|
+
this.agentRegistry = options.agentRegistry;
|
|
233
|
+
this.scopedAgentRegistry = createModelScopedAgentRegistry({
|
|
234
|
+
agentRegistry: this.agentRegistry,
|
|
235
|
+
scope: this.codexAcpModelOverrideScope
|
|
236
|
+
});
|
|
237
|
+
const sharedOptions = {
|
|
238
|
+
...options,
|
|
239
|
+
sessionStore: this.sessionStore,
|
|
240
|
+
agentRegistry: this.scopedAgentRegistry
|
|
241
|
+
};
|
|
242
|
+
this.delegate = new AcpxRuntime$1(sharedOptions, testOptions);
|
|
243
|
+
this.bridgeSafeDelegate = shouldUseDistinctBridgeDelegate(options) ? new AcpxRuntime$1({
|
|
244
|
+
...sharedOptions,
|
|
245
|
+
mcpServers: []
|
|
246
|
+
}, testOptions) : this.delegate;
|
|
247
|
+
this.probeDelegate = this.resolveDelegateForAgent(resolveProbeAgentName(options));
|
|
248
|
+
}
|
|
249
|
+
resolveDelegateForAgent(agentName) {
|
|
250
|
+
const command = resolveAgentCommandForName({
|
|
251
|
+
agentName,
|
|
252
|
+
agentRegistry: this.agentRegistry
|
|
253
|
+
});
|
|
254
|
+
return this.resolveDelegateForCommand(command);
|
|
255
|
+
}
|
|
256
|
+
resolveDelegateForCommand(command) {
|
|
257
|
+
return shouldUseBridgeSafeDelegateForCommand(command) ? this.bridgeSafeDelegate : this.delegate;
|
|
258
|
+
}
|
|
259
|
+
async resolveDelegateForHandle(handle) {
|
|
260
|
+
const recordCommand = readAgentCommandFromRecord(await this.sessionStore.load(handle.acpxRecordId ?? handle.sessionKey));
|
|
261
|
+
if (recordCommand) return this.resolveDelegateForCommand(recordCommand);
|
|
262
|
+
return this.resolveDelegateForAgent(readAgentFromHandle(handle));
|
|
263
|
+
}
|
|
264
|
+
async resolveCommandForHandle(handle) {
|
|
265
|
+
const recordCommand = readAgentCommandFromRecord(await this.sessionStore.load(handle.acpxRecordId ?? handle.sessionKey));
|
|
266
|
+
if (recordCommand) return recordCommand;
|
|
267
|
+
return resolveAgentCommandForName({
|
|
268
|
+
agentName: readAgentFromHandle(handle),
|
|
269
|
+
agentRegistry: this.agentRegistry
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
isHealthy() {
|
|
273
|
+
return this.probeDelegate.isHealthy();
|
|
274
|
+
}
|
|
275
|
+
probeAvailability() {
|
|
276
|
+
return this.probeDelegate.probeAvailability();
|
|
277
|
+
}
|
|
278
|
+
doctor() {
|
|
279
|
+
return this.probeDelegate.doctor();
|
|
280
|
+
}
|
|
281
|
+
async ensureSession(input) {
|
|
282
|
+
assertSupportedRuntimeSessionMode(input.mode);
|
|
283
|
+
const command = resolveAgentCommandForName({
|
|
284
|
+
agentName: input.agent,
|
|
285
|
+
agentRegistry: this.agentRegistry
|
|
286
|
+
});
|
|
287
|
+
const delegate = this.resolveDelegateForCommand(command);
|
|
288
|
+
const codexModelOverride = normalizeAgentName(input.agent) === CODEX_ACP_AGENT_ID && isCodexAcpCommand(command) ? normalizeCodexAcpModelOverride(input.model, input.thinking) : void 0;
|
|
289
|
+
if (!codexModelOverride) return delegate.ensureSession(input);
|
|
290
|
+
const normalizedInput = {
|
|
291
|
+
...input,
|
|
292
|
+
...codexAcpSessionModelId(codexModelOverride) ? { model: codexAcpSessionModelId(codexModelOverride) } : {}
|
|
293
|
+
};
|
|
294
|
+
return this.codexAcpModelOverrideScope.run(codexModelOverride, () => delegate.ensureSession(normalizedInput));
|
|
295
|
+
}
|
|
296
|
+
async *runTurn(input) {
|
|
297
|
+
yield* (await this.resolveDelegateForHandle(input.handle)).runTurn(input);
|
|
298
|
+
}
|
|
299
|
+
getCapabilities() {
|
|
300
|
+
return this.delegate.getCapabilities();
|
|
301
|
+
}
|
|
302
|
+
async getStatus(input) {
|
|
303
|
+
return (await this.resolveDelegateForHandle(input.handle)).getStatus(input);
|
|
304
|
+
}
|
|
305
|
+
async setMode(input) {
|
|
306
|
+
await (await this.resolveDelegateForHandle(input.handle)).setMode(input);
|
|
307
|
+
}
|
|
308
|
+
async setConfigOption(input) {
|
|
309
|
+
const delegate = await this.resolveDelegateForHandle(input.handle);
|
|
310
|
+
const command = await this.resolveCommandForHandle(input.handle);
|
|
311
|
+
const key = input.key.trim().toLowerCase();
|
|
312
|
+
if (isCodexAcpCommand(command)) {
|
|
313
|
+
if (key === "timeout" || key === "timeout_seconds") return;
|
|
314
|
+
if (key === "model" || key === "thinking" || key === "thought_level" || key === "reasoning_effort") {
|
|
315
|
+
const override = key === "model" ? normalizeCodexAcpModelOverride(input.value) : normalizeCodexAcpModelOverride(void 0, input.value);
|
|
316
|
+
if (!override && key !== "model") return;
|
|
317
|
+
if (override) {
|
|
318
|
+
if (override.model) await delegate.setConfigOption({
|
|
319
|
+
...input,
|
|
320
|
+
key: "model",
|
|
321
|
+
value: override.model
|
|
322
|
+
});
|
|
323
|
+
if (override.reasoningEffort) await delegate.setConfigOption({
|
|
324
|
+
...input,
|
|
325
|
+
key: "reasoning_effort",
|
|
326
|
+
value: override.reasoningEffort
|
|
327
|
+
});
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
await delegate.setConfigOption(input);
|
|
333
|
+
}
|
|
334
|
+
async cancel(input) {
|
|
335
|
+
await (await this.resolveDelegateForHandle(input.handle)).cancel(input);
|
|
336
|
+
}
|
|
337
|
+
async prepareFreshSession(input) {
|
|
338
|
+
this.sessionStore.markFresh(input.sessionKey);
|
|
339
|
+
}
|
|
340
|
+
async close(input) {
|
|
341
|
+
await (await this.resolveDelegateForHandle(input.handle)).close({
|
|
342
|
+
handle: input.handle,
|
|
343
|
+
reason: input.reason,
|
|
344
|
+
discardPersistentState: input.discardPersistentState
|
|
345
|
+
});
|
|
346
|
+
if (input.discardPersistentState) this.sessionStore.markFresh(input.handle.sessionKey);
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
const __testing = {
|
|
350
|
+
appendCodexAcpConfigOverrides,
|
|
351
|
+
assertSupportedRuntimeSessionMode,
|
|
352
|
+
codexAcpSessionModelId,
|
|
353
|
+
isCodexAcpCommand,
|
|
354
|
+
normalizeCodexAcpModelOverride
|
|
355
|
+
};
|
|
356
|
+
//#endregion
|
|
357
|
+
export { ACPX_BACKEND_ID, AcpxRuntime, __testing, createAcpRuntime, createAgentRegistry, createFileSessionStore, decodeAcpxRuntimeHandleState, encodeAcpxRuntimeHandleState };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { AcpRuntimeError, getAcpRuntimeBackend, registerAcpRuntimeBackend, tryDispatchAcpReplyHook, unregisterAcpRuntimeBackend } from "openclaw/plugin-sdk/acp-runtime-backend";
|
|
2
|
+
import { applyWindowsSpawnProgramPolicy, materializeWindowsSpawnProgram, resolveWindowsSpawnProgramCandidate } from "openclaw/plugin-sdk/windows-spawn";
|
|
3
|
+
import { listKnownProviderAuthEnvVarNames, omitEnvKeysCaseInsensitive } from "openclaw/plugin-sdk/provider-env-vars";
|
|
4
|
+
export { AcpRuntimeError, applyWindowsSpawnProgramPolicy, getAcpRuntimeBackend, listKnownProviderAuthEnvVarNames, materializeWindowsSpawnProgram, omitEnvKeysCaseInsensitive, registerAcpRuntimeBackend, resolveWindowsSpawnProgramCandidate, tryDispatchAcpReplyHook, unregisterAcpRuntimeBackend };
|