@openclaw/acpx 2026.9.4 → 2026.9.6
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/README.md +51 -0
- package/assets/activity.svg +3 -0
- package/assets/icon.png +0 -0
- package/dist/.setup/command-line-CPBLOiZM.mjs +138 -0
- package/dist/{config-D2FTk0K7.js → .setup/config-CdPsIued.mjs} +54 -4
- package/dist/.setup/harness-attempt-CDXMeP5Z.mjs +369 -0
- package/dist/{pi-session-catalog-runtime-BrPX6xQV.js → .setup/pi-session-catalog-runtime-UhiQSaDw.mjs} +5 -5
- package/dist/{process-lease-B83BGiLj.js → .setup/process-lease-C3dNPtu8.mjs} +2 -62
- package/dist/{register.runtime-CksaMeEx.js → .setup/register.runtime-Bm4HrMCp.mjs} +54 -15
- package/dist/.setup/service-DMae5pPH.mjs +2740 -0
- package/dist/{session-owner-migration-D36AH9RC.js → .setup/session-owner-migration-CdJSYRk1.mjs} +15 -12
- package/dist/{session-resource-UWe7qD3m.js → .setup/session-resource-BaJ6bs5d.mjs} +14 -2
- package/dist/doctor-contract-api.js +3 -3
- package/dist/index.js +266 -30
- package/dist/register.runtime.js +1 -1
- package/openclaw.plugin.json +44 -2
- package/package.json +10 -8
- package/skills/acp-router/SKILL.md +2 -2
- package/dist/config-schema-DN_uAi4R.js +0 -37
- package/dist/rolldown-runtime-8H4AJuhK.js +0 -14
- package/dist/runtime-CSNBTQIs.js +0 -1040
- package/dist/service-BAf6nuci.js +0 -1565
- package/dist/{pi-session-paths-EMbd4Hkz.js → .setup/pi-session-paths-CIvyk6KB.mjs} +2 -2
package/dist/runtime-CSNBTQIs.js
DELETED
|
@@ -1,1040 +0,0 @@
|
|
|
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
|
-
import { AcpRuntimeError } from "./runtime-api.js";
|
|
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-BAf6nuci.js";
|
|
5
|
-
import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
6
|
-
import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
7
|
-
import path, { resolve } from "node:path";
|
|
8
|
-
import fs from "node:fs/promises";
|
|
9
|
-
import { randomUUID } from "node:crypto";
|
|
10
|
-
import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
11
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
12
|
-
import { isDeepStrictEqual } from "node:util";
|
|
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";
|
|
15
|
-
import { redactSensitiveText } from "openclaw/plugin-sdk/security-runtime";
|
|
16
|
-
//#region extensions/acpx/src/session-owner.ts
|
|
17
|
-
function requireAcpxOwnerMigration(sessionKey) {
|
|
18
|
-
throw new AcpRuntimeError("ACP_SESSION_INIT_FAILED", `ACP session "${sessionKey}" has an unqualified or unverifiable backend locator. Stop the Gateway and run "openclaw doctor --fix" to migrate ownership without losing history, then restart.`, { detailCode: "SESSION_OWNER_MIGRATION_REQUIRED" });
|
|
19
|
-
}
|
|
20
|
-
function assertAcpxSessionOwnerLocator(target, legacyBareSessionKeys) {
|
|
21
|
-
const resource = resolveAcpxSessionResource(target);
|
|
22
|
-
const qualified = resource === target.sessionKey.trim().toLowerCase();
|
|
23
|
-
const persisted = target.persistedHandle;
|
|
24
|
-
if (!qualified && (legacyBareSessionKeys?.has(target.sessionKey.trim().toLowerCase()) || legacyBareSessionKeys?.has(resource) && !persisted)) requireAcpxOwnerMigration(target.sessionKey);
|
|
25
|
-
if (persisted) {
|
|
26
|
-
const decoded = decodeAcpxRuntimeHandleState$1(persisted.runtimeSessionName);
|
|
27
|
-
if (!qualified && !decoded || decoded && (decoded.name !== resource || persisted.acpxRecordId && decoded.acpxRecordId !== persisted.acpxRecordId)) requireAcpxOwnerMigration(target.sessionKey);
|
|
28
|
-
}
|
|
29
|
-
return resource;
|
|
30
|
-
}
|
|
31
|
-
/** Preserve physical oneshot record IDs and the upstream-encoded runtime handle. */
|
|
32
|
-
function toAcpxResourceInput(input) {
|
|
33
|
-
const sessionKey = assertAcpxSessionOwnerLocator({
|
|
34
|
-
...input.handle,
|
|
35
|
-
persistedHandle: input.handle
|
|
36
|
-
});
|
|
37
|
-
return {
|
|
38
|
-
...input,
|
|
39
|
-
handle: {
|
|
40
|
-
...input.handle,
|
|
41
|
-
sessionKey
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
//#endregion
|
|
46
|
-
//#region extensions/acpx/src/runtime.ts
|
|
47
|
-
/**
|
|
48
|
-
* OpenClaw ACPX runtime adapter. It wraps the upstream acpx runtime with
|
|
49
|
-
* OpenClaw session metadata, lease tracking, model scoping, and cleanup policy.
|
|
50
|
-
*/
|
|
51
|
-
const ACPX_PLUGIN_TOOLS_MCP_SERVER_NAME = "openclaw-plugin-tools";
|
|
52
|
-
const ACPX_OPENCLAW_TOOLS_MCP_SERVER_NAME = "openclaw-tools";
|
|
53
|
-
const OPENCLAW_TOOLS_MCP_AGENT_SESSION_KEY_ENV = "OPENCLAW_TOOLS_MCP_AGENT_SESSION_KEY";
|
|
54
|
-
function withOpenClawLeaseSessionMetadata(record, lease) {
|
|
55
|
-
return {
|
|
56
|
-
...record,
|
|
57
|
-
openclawLeaseId: lease.leaseId,
|
|
58
|
-
openclawGatewayInstanceId: lease.gatewayInstanceId
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
const CODEX_WRAPPER_STDERR_LOG_PREFIX = "codex-acp-wrapper.stderr";
|
|
62
|
-
function safeDiagnosticFilePart(value) {
|
|
63
|
-
return value.replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 120) || "unknown";
|
|
64
|
-
}
|
|
65
|
-
function codexWrapperStderrLogFileName(leaseId) {
|
|
66
|
-
return `${CODEX_WRAPPER_STDERR_LOG_PREFIX}.${safeDiagnosticFilePart(leaseId)}.log`;
|
|
67
|
-
}
|
|
68
|
-
function compactDiagnosticText(value) {
|
|
69
|
-
return value.replace(/\s+/g, " ").trim();
|
|
70
|
-
}
|
|
71
|
-
function isGenericInternalAcpErrorMessage(message) {
|
|
72
|
-
return message.trim() === "Internal error";
|
|
73
|
-
}
|
|
74
|
-
function isGenericInternalAcpError(error) {
|
|
75
|
-
return error instanceof Error && isGenericInternalAcpErrorMessage(error.message);
|
|
76
|
-
}
|
|
77
|
-
async function readCodexWrapperStderrTail(params) {
|
|
78
|
-
if (!params.wrapperRoot || !params.leaseId) return "";
|
|
79
|
-
try {
|
|
80
|
-
const text = await fs.readFile(path.join(params.wrapperRoot, codexWrapperStderrLogFileName(params.leaseId)), "utf8");
|
|
81
|
-
return compactDiagnosticText(redactSensitiveText(sliceUtf16Safe(text, -6e3)));
|
|
82
|
-
} catch {
|
|
83
|
-
return "";
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
function readSessionRecordName(record) {
|
|
87
|
-
if (typeof record !== "object" || record === null) return "";
|
|
88
|
-
const { name } = record;
|
|
89
|
-
return typeof name === "string" ? name.trim() : "";
|
|
90
|
-
}
|
|
91
|
-
function readRecordAgentCommand(record) {
|
|
92
|
-
return record?.agentArgv ?? record?.agentCommand;
|
|
93
|
-
}
|
|
94
|
-
function readRecordCwd(record) {
|
|
95
|
-
if (typeof record !== "object" || record === null) return;
|
|
96
|
-
const { cwd } = record;
|
|
97
|
-
return typeof cwd === "string" ? cwd.trim() || void 0 : void 0;
|
|
98
|
-
}
|
|
99
|
-
function readRecordResetOnNextEnsure(record) {
|
|
100
|
-
if (typeof record !== "object" || record === null) return false;
|
|
101
|
-
const { acpx } = record;
|
|
102
|
-
if (typeof acpx !== "object" || acpx === null) return false;
|
|
103
|
-
return acpx.reset_on_next_ensure === true;
|
|
104
|
-
}
|
|
105
|
-
function readRecordAgentPid(record) {
|
|
106
|
-
if (typeof record !== "object" || record === null) return;
|
|
107
|
-
const { pid, processId } = record;
|
|
108
|
-
const rawPid = pid ?? processId;
|
|
109
|
-
const numericPid = typeof rawPid === "number" ? rawPid : typeof rawPid === "string" ? parseStrictPositiveInteger(rawPid) : void 0;
|
|
110
|
-
return numericPid && Number.isInteger(numericPid) && numericPid > 0 ? numericPid : void 0;
|
|
111
|
-
}
|
|
112
|
-
function readOpenClawLeaseIdFromRecord(record) {
|
|
113
|
-
if (typeof record !== "object" || record === null) return;
|
|
114
|
-
const { openclawLeaseId } = record;
|
|
115
|
-
return typeof openclawLeaseId === "string" ? openclawLeaseId.trim() || void 0 : void 0;
|
|
116
|
-
}
|
|
117
|
-
function readOpenClawGatewayInstanceIdFromRecord(record) {
|
|
118
|
-
if (typeof record !== "object" || record === null) return;
|
|
119
|
-
const { openclawGatewayInstanceId } = record;
|
|
120
|
-
return typeof openclawGatewayInstanceId === "string" ? openclawGatewayInstanceId.trim() || void 0 : void 0;
|
|
121
|
-
}
|
|
122
|
-
function extractGeneratedWrapperPath(command) {
|
|
123
|
-
return splitCommandParts(command ?? "").find((part) => basename(part) === "codex-acp-wrapper.mjs" || basename(part) === "claude-agent-acp-wrapper.mjs") ?? "";
|
|
124
|
-
}
|
|
125
|
-
function selectCurrentSessionLease(params) {
|
|
126
|
-
const sessionKeys = new Set(normalizeStringEntries(params.sessionKeys));
|
|
127
|
-
const candidates = params.leases.filter((lease) => sessionKeys.has(lease.sessionKey));
|
|
128
|
-
if (params.rootPid) return candidates.find((lease) => lease.rootPid === params.rootPid);
|
|
129
|
-
let selected;
|
|
130
|
-
for (const lease of candidates) if (!selected || lease.startedAt > selected.startedAt) selected = lease;
|
|
131
|
-
return selected;
|
|
132
|
-
}
|
|
133
|
-
function createResetAwareSessionStore(baseStore, params) {
|
|
134
|
-
const freshSessionKeys = /* @__PURE__ */ new Set();
|
|
135
|
-
return {
|
|
136
|
-
async load(sessionId) {
|
|
137
|
-
const normalized = sessionId.trim();
|
|
138
|
-
if (normalized && freshSessionKeys.has(normalized)) return;
|
|
139
|
-
const record = await baseStore.load(sessionId);
|
|
140
|
-
if (!record || !params?.leaseStore || !params.gatewayInstanceId) return record;
|
|
141
|
-
const sessionName = readSessionRecordName(record) || normalized;
|
|
142
|
-
const lease = selectCurrentSessionLease({
|
|
143
|
-
leases: await params.leaseStore.listOpen(params.gatewayInstanceId),
|
|
144
|
-
sessionKeys: [sessionName, normalized],
|
|
145
|
-
rootPid: readRecordAgentPid(record)
|
|
146
|
-
});
|
|
147
|
-
if (!lease) return record;
|
|
148
|
-
return withOpenClawLeaseSessionMetadata(record, lease);
|
|
149
|
-
},
|
|
150
|
-
async save(record) {
|
|
151
|
-
let recordToSave = record;
|
|
152
|
-
const launch = params?.launchScope?.getStore();
|
|
153
|
-
const sessionName = readSessionRecordName(record);
|
|
154
|
-
const agentCommand = readRecordAgentCommand(record);
|
|
155
|
-
const leasedCommand = launch?.leasedCommand ?? agentCommand;
|
|
156
|
-
const leaseIdentity = launch ?? readAcpxProcessLeaseIdentity(leasedCommand);
|
|
157
|
-
if (params?.leaseStore && params.gatewayInstanceId && params.wrapperRoot && (!launch || sessionName === launch.sessionKey) && leasedCommand && leaseIdentity?.gatewayInstanceId === params.gatewayInstanceId && isOpenClawLeaseAwareAcpxProcessCommand({
|
|
158
|
-
command: leasedCommand,
|
|
159
|
-
wrapperRoot: params.wrapperRoot
|
|
160
|
-
})) {
|
|
161
|
-
const existing = await params.leaseStore.load(leaseIdentity.leaseId);
|
|
162
|
-
if (!existing || existing.gatewayInstanceId === leaseIdentity.gatewayInstanceId && existing.sessionKey === sessionName && existing.wrapperRoot === params.wrapperRoot) {
|
|
163
|
-
const adoptingLease = Boolean(launch && !isDeepStrictEqual(splitCommandParts(launch.resolvedCommand), splitCommandParts(launch.leasedCommand)));
|
|
164
|
-
const persistedCommand = launch && !adoptingLease ? launch.resolvedCommand : leasedCommand;
|
|
165
|
-
const lifecycleRecord = adoptingLease ? {
|
|
166
|
-
...record,
|
|
167
|
-
pid: void 0,
|
|
168
|
-
processId: void 0,
|
|
169
|
-
agentStartedAt: void 0
|
|
170
|
-
} : record;
|
|
171
|
-
const rootPid = readRecordAgentPid(lifecycleRecord);
|
|
172
|
-
if (rootPid) await params.leaseStore.save({
|
|
173
|
-
leaseId: leaseIdentity.leaseId,
|
|
174
|
-
gatewayInstanceId: leaseIdentity.gatewayInstanceId,
|
|
175
|
-
sessionKey: sessionName,
|
|
176
|
-
wrapperRoot: params.wrapperRoot,
|
|
177
|
-
wrapperPath: extractGeneratedWrapperPath(leasedCommand),
|
|
178
|
-
rootPid,
|
|
179
|
-
...existing?.rootPid === rootPid && existing.processGroupId ? { processGroupId: existing.processGroupId } : {},
|
|
180
|
-
commandHash: hashAcpxProcessCommand(persistedCommand),
|
|
181
|
-
startedAt: existing?.rootPid === rootPid ? existing.startedAt : Date.now(),
|
|
182
|
-
state: "open"
|
|
183
|
-
});
|
|
184
|
-
recordToSave = withOpenClawLeaseSessionMetadata({
|
|
185
|
-
...lifecycleRecord,
|
|
186
|
-
agentCommand: renderAgentCommand(persistedCommand),
|
|
187
|
-
agentArgv: Array.isArray(persistedCommand) ? persistedCommand : void 0
|
|
188
|
-
}, leaseIdentity);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
await baseStore.save(recordToSave);
|
|
192
|
-
if (sessionName) freshSessionKeys.delete(sessionName);
|
|
193
|
-
},
|
|
194
|
-
markFresh(sessionKey) {
|
|
195
|
-
const normalized = sessionKey.trim();
|
|
196
|
-
if (normalized) freshSessionKeys.add(normalized);
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
const OPENCLAW_BRIDGE_EXECUTABLE = "openclaw";
|
|
201
|
-
const OPENCLAW_BRIDGE_SUBCOMMAND = "acp";
|
|
202
|
-
const CODEX_ACP_AGENT_ID = "codex";
|
|
203
|
-
const CODEX_ACP_OPENCLAW_PREFIX = "openai/";
|
|
204
|
-
const CLAUDE_ACP_OPENCLAW_PREFIX = /^(?:anthropic|amazon-bedrock)\//i;
|
|
205
|
-
const CODEX_ACP_THINKING_ALIASES = /* @__PURE__ */ new Map([
|
|
206
|
-
["off", void 0],
|
|
207
|
-
["minimal", "low"],
|
|
208
|
-
["low", "low"],
|
|
209
|
-
["medium", "medium"],
|
|
210
|
-
["high", "high"],
|
|
211
|
-
["x-high", "xhigh"],
|
|
212
|
-
["x_high", "xhigh"],
|
|
213
|
-
["extra-high", "xhigh"],
|
|
214
|
-
["extra_high", "xhigh"],
|
|
215
|
-
["extra high", "xhigh"],
|
|
216
|
-
["xhigh", "xhigh"]
|
|
217
|
-
]);
|
|
218
|
-
function normalizeAgentName(value) {
|
|
219
|
-
const normalized = value?.trim().toLowerCase();
|
|
220
|
-
return normalized ? normalized : void 0;
|
|
221
|
-
}
|
|
222
|
-
function readAgentFromSessionKey(sessionKey) {
|
|
223
|
-
const normalized = sessionKey?.trim();
|
|
224
|
-
if (!normalized) return;
|
|
225
|
-
return normalizeAgentName(/^agent:(?<agent>[^:]+):/i.exec(normalized)?.groups?.agent);
|
|
226
|
-
}
|
|
227
|
-
function readAgentFromHandle(handle) {
|
|
228
|
-
return normalizeAgentName(decodeAcpxRuntimeHandleState(handle.runtimeSessionName)?.agent) ?? readAgentFromSessionKey(handle.sessionKey);
|
|
229
|
-
}
|
|
230
|
-
function basename(value) {
|
|
231
|
-
return value.split(/[\\/]/).pop() ?? value;
|
|
232
|
-
}
|
|
233
|
-
function isEnvAssignment(value) {
|
|
234
|
-
return /^[A-Za-z_][A-Za-z0-9_]*=/.test(value);
|
|
235
|
-
}
|
|
236
|
-
function unwrapEnvCommand(parts) {
|
|
237
|
-
const command = parts.at(0);
|
|
238
|
-
if (!command || basename(command) !== "env") return parts;
|
|
239
|
-
let index = 1;
|
|
240
|
-
while (true) {
|
|
241
|
-
const part = parts.at(index);
|
|
242
|
-
if (!part || !isEnvAssignment(part)) break;
|
|
243
|
-
index += 1;
|
|
244
|
-
}
|
|
245
|
-
return parts.slice(index);
|
|
246
|
-
}
|
|
247
|
-
function matchesExecutableName(value, executableName) {
|
|
248
|
-
const normalized = basename(value).toLowerCase();
|
|
249
|
-
return normalized === executableName || normalized === `${executableName}.exe`;
|
|
250
|
-
}
|
|
251
|
-
function matchesPackageSpec(value, packageName) {
|
|
252
|
-
const normalized = value.trim().toLowerCase();
|
|
253
|
-
return normalized === packageName || normalized.startsWith(`${packageName}@`);
|
|
254
|
-
}
|
|
255
|
-
function stripModuleExtension(value) {
|
|
256
|
-
return value.replace(/\.[cm]?js$/i, "").toLowerCase();
|
|
257
|
-
}
|
|
258
|
-
function isAcpCommand(command, params) {
|
|
259
|
-
if (!command) return false;
|
|
260
|
-
const parts = unwrapEnvCommand(splitCommandParts(command));
|
|
261
|
-
if (!parts.length) return false;
|
|
262
|
-
if (parts.some((part) => matchesPackageSpec(part, params.packageName))) return true;
|
|
263
|
-
const commandName = basename(parts[0] ?? "");
|
|
264
|
-
if (matchesExecutableName(commandName, params.executableName)) return true;
|
|
265
|
-
if (!matchesExecutableName(commandName, "node")) return false;
|
|
266
|
-
const scriptName = stripModuleExtension(basename(parts[1] ?? ""));
|
|
267
|
-
return scriptName === params.executableName || scriptName === `${params.executableName}-wrapper`;
|
|
268
|
-
}
|
|
269
|
-
function isOpenClawBridgeCommand(command) {
|
|
270
|
-
if (!command) return false;
|
|
271
|
-
const parts = unwrapEnvCommand(splitCommandParts(command));
|
|
272
|
-
if (basename(parts[0] ?? "") === OPENCLAW_BRIDGE_EXECUTABLE) return parts[1] === OPENCLAW_BRIDGE_SUBCOMMAND;
|
|
273
|
-
if (basename(parts[0] ?? "") !== "node") return false;
|
|
274
|
-
const scriptName = basename(parts[1] ?? "");
|
|
275
|
-
return /^openclaw(?:\.[cm]?js)?$/i.test(scriptName) && parts[2] === OPENCLAW_BRIDGE_SUBCOMMAND;
|
|
276
|
-
}
|
|
277
|
-
function isCodexAcpCommand(command) {
|
|
278
|
-
return isAcpCommand(command, {
|
|
279
|
-
packageName: CODEX_ACP_PACKAGE,
|
|
280
|
-
executableName: "codex-acp"
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
function isClaudeAcpCommand(command) {
|
|
284
|
-
return isAcpCommand(command, {
|
|
285
|
-
packageName: "@agentclientprotocol/claude-agent-acp",
|
|
286
|
-
executableName: "claude-agent-acp"
|
|
287
|
-
});
|
|
288
|
-
}
|
|
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>.`);
|
|
291
|
-
}
|
|
292
|
-
const WIRE_TIMEOUT_CONFIG_KEYS = /* @__PURE__ */ new Set(["timeout", "timeout_seconds"]);
|
|
293
|
-
function assertSupportedRuntimeSessionMode(mode) {
|
|
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.`);
|
|
296
|
-
}
|
|
297
|
-
function failUnsupportedCodexAcpThinking(rawThinking) {
|
|
298
|
-
throw new AcpRuntimeError("ACP_INVALID_RUNTIME_OPTION", `Codex ACP thinking level "${rawThinking}" is not supported. Use off, minimal, low, medium, high, or xhigh.`);
|
|
299
|
-
}
|
|
300
|
-
function normalizeCodexAcpReasoningEffort(rawThinking) {
|
|
301
|
-
const normalized = rawThinking?.trim().toLowerCase();
|
|
302
|
-
if (!normalized) return;
|
|
303
|
-
if (!CODEX_ACP_THINKING_ALIASES.has(normalized)) failUnsupportedCodexAcpThinking(rawThinking ?? "");
|
|
304
|
-
return CODEX_ACP_THINKING_ALIASES.get(normalized);
|
|
305
|
-
}
|
|
306
|
-
function isCodexAcpReasoningEffortAlias(value) {
|
|
307
|
-
const normalized = value?.trim().toLowerCase();
|
|
308
|
-
return Boolean(normalized && CODEX_ACP_THINKING_ALIASES.has(normalized));
|
|
309
|
-
}
|
|
310
|
-
function classifyCodexAcpModelRequest(rawModel, rawThinking) {
|
|
311
|
-
const raw = rawModel?.trim();
|
|
312
|
-
const thinkingReasoningEffort = normalizeCodexAcpReasoningEffort(rawThinking);
|
|
313
|
-
const thinkingOnlyOverride = thinkingReasoningEffort ? { reasoningEffort: thinkingReasoningEffort } : void 0;
|
|
314
|
-
if (!raw) return {
|
|
315
|
-
kind: "override",
|
|
316
|
-
override: thinkingOnlyOverride ?? {}
|
|
317
|
-
};
|
|
318
|
-
let value = raw;
|
|
319
|
-
let hadOpenAiQualifier = false;
|
|
320
|
-
if (value.toLowerCase().startsWith(CODEX_ACP_OPENCLAW_PREFIX)) {
|
|
321
|
-
value = value.slice(7);
|
|
322
|
-
hadOpenAiQualifier = true;
|
|
323
|
-
}
|
|
324
|
-
let model = value.trim();
|
|
325
|
-
let modelReasoningEffort;
|
|
326
|
-
const slashIndex = value.lastIndexOf("/");
|
|
327
|
-
if (slashIndex >= 0 && isCodexAcpReasoningEffortAlias(value.slice(slashIndex + 1))) {
|
|
328
|
-
modelReasoningEffort = normalizeCodexAcpReasoningEffort(value.slice(slashIndex + 1));
|
|
329
|
-
model = value.slice(0, slashIndex).trim();
|
|
330
|
-
}
|
|
331
|
-
if (hadOpenAiQualifier && (!model || model.includes("/"))) failUnsupportedCodexAcpModel(raw);
|
|
332
|
-
if (!model || model.includes("/")) return thinkingOnlyOverride ? {
|
|
333
|
-
kind: "unsupported",
|
|
334
|
-
thinkingOverride: thinkingOnlyOverride
|
|
335
|
-
} : { kind: "unsupported" };
|
|
336
|
-
const reasoningEffort = rawThinking?.trim() ? thinkingReasoningEffort : modelReasoningEffort;
|
|
337
|
-
return {
|
|
338
|
-
kind: "override",
|
|
339
|
-
override: {
|
|
340
|
-
model,
|
|
341
|
-
...reasoningEffort ? { reasoningEffort } : {}
|
|
342
|
-
}
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
function withCodexSessionModel(input, override) {
|
|
346
|
-
const next = { ...input };
|
|
347
|
-
if (override?.model) next.model = override.model;
|
|
348
|
-
else delete next.model;
|
|
349
|
-
return next;
|
|
350
|
-
}
|
|
351
|
-
function normalizeClaudeAcpModelOverride(rawModel) {
|
|
352
|
-
const raw = rawModel?.trim();
|
|
353
|
-
if (!raw) return;
|
|
354
|
-
const prefix = raw.match(CLAUDE_ACP_OPENCLAW_PREFIX);
|
|
355
|
-
if (!prefix) return raw;
|
|
356
|
-
return raw.slice(prefix[0].length).trim() || void 0;
|
|
357
|
-
}
|
|
358
|
-
function withAcpxSessionOptions(input) {
|
|
359
|
-
const existingOptions = input.sessionOptions;
|
|
360
|
-
const model = input.model?.trim() || existingOptions?.model;
|
|
361
|
-
const sessionOptions = model ? {
|
|
362
|
-
...existingOptions,
|
|
363
|
-
model
|
|
364
|
-
} : existingOptions;
|
|
365
|
-
const { modelExplicit: _modelExplicit, ...rest } = input;
|
|
366
|
-
return {
|
|
367
|
-
...rest,
|
|
368
|
-
...sessionOptions ? { sessionOptions } : {}
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
function isAcpModelCapabilityMissingError(error) {
|
|
372
|
-
return isRequestedModelUnsupportedError(error) && error.reason === "missing-capability";
|
|
373
|
-
}
|
|
374
|
-
async function ensureDelegateSessionWithModelFallback(delegate, input) {
|
|
375
|
-
try {
|
|
376
|
-
return await delegate.ensureSession(withAcpxSessionOptions(input));
|
|
377
|
-
} catch (error) {
|
|
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
|
-
};
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
function appendCodexAcpConfigOverrides(command, override) {
|
|
389
|
-
const config = {
|
|
390
|
-
...override.model ? { model: override.model } : {},
|
|
391
|
-
...override.reasoningEffort ? { model_reasoning_effort: override.reasoningEffort } : {}
|
|
392
|
-
};
|
|
393
|
-
if (Object.keys(config).length === 0) return command;
|
|
394
|
-
return [
|
|
395
|
-
...splitCommandParts(command),
|
|
396
|
-
OPENCLAW_CODEX_CONFIG_ARG,
|
|
397
|
-
JSON.stringify(config)
|
|
398
|
-
];
|
|
399
|
-
}
|
|
400
|
-
function resolveAgentCommand(params) {
|
|
401
|
-
const normalizedAgentName = normalizeAgentName(params.agentName);
|
|
402
|
-
if (!normalizedAgentName) return;
|
|
403
|
-
return splitCommandParts(params.agentRegistry.resolve(normalizedAgentName));
|
|
404
|
-
}
|
|
405
|
-
function shouldUseDistinctBridgeDelegate(options) {
|
|
406
|
-
const { mcpServers } = options;
|
|
407
|
-
return Array.isArray(mcpServers) && mcpServers.length > 0;
|
|
408
|
-
}
|
|
409
|
-
function withManagedToolsMcpSessionEnv(params) {
|
|
410
|
-
const sessionKey = params.sessionKey.trim();
|
|
411
|
-
if (!params.pluginToolsEnabled && !params.openclawToolsEnabled || !sessionKey || !params.mcpServers?.length) return params.mcpServers;
|
|
412
|
-
let changed = false;
|
|
413
|
-
const nextServers = params.mcpServers.map((server) => {
|
|
414
|
-
const isManagedPluginTools = params.pluginToolsEnabled && server.name === ACPX_PLUGIN_TOOLS_MCP_SERVER_NAME;
|
|
415
|
-
const isManagedOpenClawTools = params.openclawToolsEnabled && server.name === ACPX_OPENCLAW_TOOLS_MCP_SERVER_NAME;
|
|
416
|
-
if (!isManagedPluginTools && !isManagedOpenClawTools || !("command" in server)) return server;
|
|
417
|
-
changed = true;
|
|
418
|
-
const env = [...server.env.filter((entry) => entry.name !== OPENCLAW_TOOLS_MCP_AGENT_SESSION_KEY_ENV), {
|
|
419
|
-
name: OPENCLAW_TOOLS_MCP_AGENT_SESSION_KEY_ENV,
|
|
420
|
-
value: sessionKey
|
|
421
|
-
}];
|
|
422
|
-
return {
|
|
423
|
-
...server,
|
|
424
|
-
env,
|
|
425
|
-
args: params.agentId ? [
|
|
426
|
-
...server.args,
|
|
427
|
-
"--openclaw-agent-id",
|
|
428
|
-
params.agentId
|
|
429
|
-
] : server.args
|
|
430
|
-
};
|
|
431
|
-
});
|
|
432
|
-
return changed ? nextServers : params.mcpServers;
|
|
433
|
-
}
|
|
434
|
-
/** OpenClaw-managed ACP runtime implementation backed by the upstream acpx runtime. */
|
|
435
|
-
var AcpxRuntime = class {
|
|
436
|
-
constructor(options, testOptions) {
|
|
437
|
-
this.ownerAwareSessions = 1;
|
|
438
|
-
this.launchCommandScope = new AsyncLocalStorage();
|
|
439
|
-
this.managedToolsSessionDelegates = /* @__PURE__ */ new Map();
|
|
440
|
-
this.launchLeaseScope = new AsyncLocalStorage();
|
|
441
|
-
this.sessionEnsureQueue = new KeyedAsyncQueue();
|
|
442
|
-
this.processLeaseTransitionQueue = new KeyedAsyncQueue();
|
|
443
|
-
this.processLeaseOperationCounts = /* @__PURE__ */ new Map();
|
|
444
|
-
this.uncertainProcessLeaseIds = /* @__PURE__ */ new Set();
|
|
445
|
-
this.legacyBareSessionKeys = new Set(options.openclawLegacyBareSessionKeys);
|
|
446
|
-
const { openclawProcessCleanup, ...delegateTestOptions } = testOptions ?? {};
|
|
447
|
-
this.processCleanupDeps = openclawProcessCleanup;
|
|
448
|
-
this.wrapperRoot = options.openclawWrapperRoot;
|
|
449
|
-
this.gatewayInstanceId = options.openclawGatewayInstanceId;
|
|
450
|
-
this.processLeaseStore = options.openclawProcessLeaseStore;
|
|
451
|
-
this.pluginToolsMcpBridgeEnabled = options.pluginToolsMcpBridgeEnabled === true;
|
|
452
|
-
this.openclawToolsMcpBridgeEnabled = options.openclawToolsMcpBridgeEnabled === true;
|
|
453
|
-
this.managedToolsMcpBridgeEnabled = this.pluginToolsMcpBridgeEnabled || this.openclawToolsMcpBridgeEnabled;
|
|
454
|
-
this.cwd = options.cwd;
|
|
455
|
-
this.sessionStore = createResetAwareSessionStore(options.sessionStore, {
|
|
456
|
-
gatewayInstanceId: this.gatewayInstanceId,
|
|
457
|
-
leaseStore: this.processLeaseStore,
|
|
458
|
-
launchScope: this.launchLeaseScope,
|
|
459
|
-
wrapperRoot: this.wrapperRoot
|
|
460
|
-
});
|
|
461
|
-
this.agentRegistry = options.agentRegistry;
|
|
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
|
-
};
|
|
469
|
-
const sharedOptions = {
|
|
470
|
-
...options,
|
|
471
|
-
sessionStore: this.sessionStore,
|
|
472
|
-
agentRegistry: this.scopedAgentRegistry
|
|
473
|
-
};
|
|
474
|
-
this.delegateOptions = sharedOptions;
|
|
475
|
-
this.delegateTestOptions = delegateTestOptions;
|
|
476
|
-
this.delegate = new AcpxRuntime$1(sharedOptions, this.delegateTestOptions);
|
|
477
|
-
this.bridgeSafeDelegate = shouldUseDistinctBridgeDelegate(options) ? new AcpxRuntime$1({
|
|
478
|
-
...sharedOptions,
|
|
479
|
-
mcpServers: []
|
|
480
|
-
}, this.delegateTestOptions) : this.delegate;
|
|
481
|
-
this.probeAgent = normalizeAgentName(options.probeAgent) ?? "codex";
|
|
482
|
-
const probeCommand = resolveAgentCommand({
|
|
483
|
-
agentName: this.probeAgent,
|
|
484
|
-
agentRegistry: this.agentRegistry
|
|
485
|
-
});
|
|
486
|
-
this.probeCommand = probeCommand;
|
|
487
|
-
const useBridgeSafeProbe = this.managedToolsMcpBridgeEnabled || isOpenClawBridgeCommand(probeCommand);
|
|
488
|
-
this.probeDelegate = useBridgeSafeProbe ? this.bridgeSafeDelegate : this.delegate;
|
|
489
|
-
}
|
|
490
|
-
resolveDelegateForSession(params) {
|
|
491
|
-
if (isOpenClawBridgeCommand(params.command)) return this.bridgeSafeDelegate;
|
|
492
|
-
return this.resolveManagedToolsDelegateForSession(params);
|
|
493
|
-
}
|
|
494
|
-
resolveManagedToolsDelegateForSession(target) {
|
|
495
|
-
if (!this.managedToolsMcpBridgeEnabled) return this.delegate;
|
|
496
|
-
const normalizedSessionKey = resolveAcpxSessionResource(target);
|
|
497
|
-
const cached = this.managedToolsSessionDelegates.get(normalizedSessionKey);
|
|
498
|
-
if (cached) return cached;
|
|
499
|
-
const delegate = new AcpxRuntime$1({
|
|
500
|
-
...this.delegateOptions,
|
|
501
|
-
mcpServers: withManagedToolsMcpSessionEnv({
|
|
502
|
-
pluginToolsEnabled: this.pluginToolsMcpBridgeEnabled,
|
|
503
|
-
openclawToolsEnabled: this.openclawToolsMcpBridgeEnabled,
|
|
504
|
-
mcpServers: this.delegateOptions.mcpServers,
|
|
505
|
-
sessionKey: target.sessionKey,
|
|
506
|
-
agentId: target.agentId
|
|
507
|
-
})
|
|
508
|
-
}, this.delegateTestOptions);
|
|
509
|
-
this.managedToolsSessionDelegates.set(normalizedSessionKey, delegate);
|
|
510
|
-
return delegate;
|
|
511
|
-
}
|
|
512
|
-
async loadOperationSnapshotForHandle(handle) {
|
|
513
|
-
assertAcpxSessionOwnerLocator({
|
|
514
|
-
...handle,
|
|
515
|
-
persistedHandle: handle
|
|
516
|
-
}, this.legacyBareSessionKeys);
|
|
517
|
-
const record = await this.sessionStore.load(handle.acpxRecordId ?? resolveAcpxSessionResource(handle));
|
|
518
|
-
return {
|
|
519
|
-
record,
|
|
520
|
-
command: readRecordAgentCommand(record) ?? resolveAgentCommand({
|
|
521
|
-
agentName: readAgentFromHandle(handle),
|
|
522
|
-
agentRegistry: this.agentRegistry
|
|
523
|
-
})
|
|
524
|
-
};
|
|
525
|
-
}
|
|
526
|
-
resolveDelegateForOperationSnapshot(handle, snapshot) {
|
|
527
|
-
return this.resolveDelegateForSession({
|
|
528
|
-
command: snapshot.command,
|
|
529
|
-
sessionKey: handle.sessionKey,
|
|
530
|
-
agentId: handle.agentId
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
async readReusablePersistentSessionCommand(params) {
|
|
534
|
-
if (params.mode !== "persistent" || !params.command) return;
|
|
535
|
-
const existing = await this.sessionStore.load(params.sessionKey);
|
|
536
|
-
if (!existing || readRecordResetOnNextEnsure(existing)) return;
|
|
537
|
-
const recordCwd = readRecordCwd(existing);
|
|
538
|
-
if (!recordCwd || resolve(recordCwd) !== resolve(params.cwd?.trim() || this.cwd)) return;
|
|
539
|
-
const recordCommand = readRecordAgentCommand(existing);
|
|
540
|
-
if (!recordCommand) return;
|
|
541
|
-
const leaseIdentity = readAcpxProcessLeaseIdentity(recordCommand);
|
|
542
|
-
if (leaseIdentity && leaseIdentity.gatewayInstanceId !== this.gatewayInstanceId) return;
|
|
543
|
-
const stableRecordCommand = leaseIdentity ? withAcpxLeaseArgs({
|
|
544
|
-
command: params.command,
|
|
545
|
-
leaseId: leaseIdentity.leaseId,
|
|
546
|
-
gatewayInstanceId: leaseIdentity.gatewayInstanceId
|
|
547
|
-
}) : params.command;
|
|
548
|
-
if (!isDeepStrictEqual(splitCommandParts(recordCommand), splitCommandParts(stableRecordCommand))) return;
|
|
549
|
-
return !params.resumeSessionId || existing.acpSessionId === params.resumeSessionId ? recordCommand : void 0;
|
|
550
|
-
}
|
|
551
|
-
async runWithLaunchLease(params) {
|
|
552
|
-
if (!params.command || !this.wrapperRoot || !this.gatewayInstanceId || !this.processLeaseStore || !isOpenClawLeaseAwareAcpxProcessCommand({
|
|
553
|
-
command: params.command,
|
|
554
|
-
wrapperRoot: this.wrapperRoot
|
|
555
|
-
})) return await this.launchCommandScope.run({
|
|
556
|
-
agent: normalizeAgentName(params.agent) ?? params.agent,
|
|
557
|
-
command: params.reusableCommand ?? params.command
|
|
558
|
-
}, params.run);
|
|
559
|
-
const processLeaseStore = this.processLeaseStore;
|
|
560
|
-
const reusableIdentity = readAcpxProcessLeaseIdentity(params.reusableCommand);
|
|
561
|
-
const canReuseLeaseIdentity = reusableIdentity?.gatewayInstanceId === this.gatewayInstanceId;
|
|
562
|
-
const leaseId = canReuseLeaseIdentity ? reusableIdentity.leaseId : params.finalizeCompletedProbe ? `probe-${hashAcpxProcessCommand(`${this.gatewayInstanceId}\0${extractGeneratedWrapperPath(params.command)}`)}` : randomUUID();
|
|
563
|
-
const leasedCommand = withAcpxLeaseArgs({
|
|
564
|
-
command: params.command,
|
|
565
|
-
leaseId,
|
|
566
|
-
gatewayInstanceId: this.gatewayInstanceId
|
|
567
|
-
});
|
|
568
|
-
const launch = {
|
|
569
|
-
leaseId,
|
|
570
|
-
gatewayInstanceId: this.gatewayInstanceId,
|
|
571
|
-
sessionKey: params.sessionKey,
|
|
572
|
-
wrapperRoot: this.wrapperRoot,
|
|
573
|
-
resolvedCommand: params.reusableCommand ?? leasedCommand,
|
|
574
|
-
leasedCommand
|
|
575
|
-
};
|
|
576
|
-
await this.retainProcessLeaseOperation(launch, async () => {
|
|
577
|
-
const reusableLease = canReuseLeaseIdentity ? await processLeaseStore.load(launch.leaseId) : void 0;
|
|
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`);
|
|
579
|
-
if (!(!reusableLease && (!params.reusableCommand || isDeepStrictEqual(splitCommandParts(params.reusableCommand), splitCommandParts(leasedCommand))))) return;
|
|
580
|
-
await processLeaseStore.save({
|
|
581
|
-
leaseId: launch.leaseId,
|
|
582
|
-
gatewayInstanceId: launch.gatewayInstanceId,
|
|
583
|
-
sessionKey: launch.sessionKey,
|
|
584
|
-
wrapperRoot: launch.wrapperRoot,
|
|
585
|
-
wrapperPath: extractGeneratedWrapperPath(leasedCommand),
|
|
586
|
-
rootPid: 0,
|
|
587
|
-
commandHash: hashAcpxProcessCommand(leasedCommand),
|
|
588
|
-
startedAt: Date.now(),
|
|
589
|
-
state: "open"
|
|
590
|
-
});
|
|
591
|
-
});
|
|
592
|
-
try {
|
|
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));
|
|
597
|
-
if (params.finalizeCompletedProbe) await this.finalizeCompletedProbeLease(launch);
|
|
598
|
-
else await this.finalizeProcessLeaseForSession(params.sessionKey, launch);
|
|
599
|
-
return result;
|
|
600
|
-
} catch (error) {
|
|
601
|
-
await this.releaseProcessLeaseAfterUncertainFailure(launch);
|
|
602
|
-
throw error;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
async prepareProcessLeaseForOperation(handle, record) {
|
|
606
|
-
if (!this.processLeaseStore || !this.gatewayInstanceId || !this.wrapperRoot) return;
|
|
607
|
-
const processLeaseStore = this.processLeaseStore;
|
|
608
|
-
const wrapperRoot = this.wrapperRoot;
|
|
609
|
-
const recordPid = readRecordAgentPid(record);
|
|
610
|
-
const command = readRecordAgentCommand(record);
|
|
611
|
-
const identity = readAcpxProcessLeaseIdentity(command);
|
|
612
|
-
if (!command || !isOpenClawLeaseAwareAcpxProcessCommand({
|
|
613
|
-
command,
|
|
614
|
-
wrapperRoot
|
|
615
|
-
})) return;
|
|
616
|
-
if (!identity) return;
|
|
617
|
-
if (identity.gatewayInstanceId !== this.gatewayInstanceId) throw new AcpRuntimeError("ACP_TURN_FAILED", `ACPX process lease ${identity.leaseId} belongs to another gateway`);
|
|
618
|
-
await this.retainProcessLeaseOperation(identity, async () => {
|
|
619
|
-
const existing = await processLeaseStore.load(identity.leaseId);
|
|
620
|
-
if (!existing) {
|
|
621
|
-
await processLeaseStore.save({
|
|
622
|
-
leaseId: identity.leaseId,
|
|
623
|
-
gatewayInstanceId: identity.gatewayInstanceId,
|
|
624
|
-
sessionKey: resolveAcpxSessionResource(handle),
|
|
625
|
-
wrapperRoot,
|
|
626
|
-
wrapperPath: extractGeneratedWrapperPath(command),
|
|
627
|
-
rootPid: recordPid ?? 0,
|
|
628
|
-
commandHash: hashAcpxProcessCommand(command),
|
|
629
|
-
startedAt: Date.now(),
|
|
630
|
-
state: "open"
|
|
631
|
-
});
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
if (existing.gatewayInstanceId !== identity.gatewayInstanceId || existing.sessionKey !== resolveAcpxSessionResource(handle) || existing.wrapperRoot !== wrapperRoot) throw new AcpRuntimeError("ACP_TURN_FAILED", `ACPX process lease ${identity.leaseId} belongs to another session`);
|
|
635
|
-
});
|
|
636
|
-
return identity;
|
|
637
|
-
}
|
|
638
|
-
async retainProcessLeaseOperation(identity, prepare) {
|
|
639
|
-
await this.processLeaseTransitionQueue.enqueue(identity.leaseId, async () => {
|
|
640
|
-
await prepare();
|
|
641
|
-
this.processLeaseOperationCounts.set(identity.leaseId, (this.processLeaseOperationCounts.get(identity.leaseId) ?? 0) + 1);
|
|
642
|
-
});
|
|
643
|
-
}
|
|
644
|
-
async releaseProcessLeaseOperation(identity, finalize) {
|
|
645
|
-
if (!identity) return;
|
|
646
|
-
await this.processLeaseTransitionQueue.enqueue(identity.leaseId, async () => {
|
|
647
|
-
const count = this.processLeaseOperationCounts.get(identity.leaseId) ?? 0;
|
|
648
|
-
if (count > 1) {
|
|
649
|
-
this.processLeaseOperationCounts.set(identity.leaseId, count - 1);
|
|
650
|
-
return;
|
|
651
|
-
}
|
|
652
|
-
if (count === 0) return;
|
|
653
|
-
this.processLeaseOperationCounts.delete(identity.leaseId);
|
|
654
|
-
await finalize();
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
async finalizeProcessLeaseForOperation(handle, identity) {
|
|
658
|
-
await this.finalizeProcessLeaseForSession(handle.acpxRecordId ?? resolveAcpxSessionResource(handle), identity);
|
|
659
|
-
}
|
|
660
|
-
async finalizeProcessLeaseForSession(sessionId, identity) {
|
|
661
|
-
if (!identity || !this.processLeaseStore) return;
|
|
662
|
-
const processLeaseStore = this.processLeaseStore;
|
|
663
|
-
await this.releaseProcessLeaseOperation(identity, async () => {
|
|
664
|
-
const lease = await processLeaseStore.load(identity.leaseId);
|
|
665
|
-
if (!lease || lease.gatewayInstanceId !== identity.gatewayInstanceId) return;
|
|
666
|
-
if (lease.rootPid <= 0) {
|
|
667
|
-
if (this.uncertainProcessLeaseIds.has(identity.leaseId)) return;
|
|
668
|
-
await processLeaseStore.markState(identity.leaseId, "lost");
|
|
669
|
-
return;
|
|
670
|
-
}
|
|
671
|
-
this.uncertainProcessLeaseIds.delete(identity.leaseId);
|
|
672
|
-
try {
|
|
673
|
-
const record = await this.sessionStore.load(sessionId);
|
|
674
|
-
const recordIdentity = readAcpxProcessLeaseIdentity(readRecordAgentCommand(record));
|
|
675
|
-
if (recordIdentity?.leaseId !== identity.leaseId || recordIdentity.gatewayInstanceId !== identity.gatewayInstanceId) await processLeaseStore.markState(identity.leaseId, "lost");
|
|
676
|
-
} catch {}
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
async finalizeCompletedProbeLease(identity) {
|
|
680
|
-
if (!this.processLeaseStore) return;
|
|
681
|
-
const processLeaseStore = this.processLeaseStore;
|
|
682
|
-
await this.releaseProcessLeaseOperation(identity, async () => {
|
|
683
|
-
const lease = await processLeaseStore.load(identity.leaseId);
|
|
684
|
-
if (!lease || lease.gatewayInstanceId !== identity.gatewayInstanceId) return;
|
|
685
|
-
if (lease.rootPid > 0) return;
|
|
686
|
-
await cleanupOpenClawOwnedAcpxPendingLease({
|
|
687
|
-
leaseId: lease.leaseId,
|
|
688
|
-
gatewayInstanceId: lease.gatewayInstanceId,
|
|
689
|
-
wrapperRoot: lease.wrapperRoot,
|
|
690
|
-
wrapperPath: lease.wrapperPath,
|
|
691
|
-
deps: this.processCleanupDeps
|
|
692
|
-
});
|
|
693
|
-
});
|
|
694
|
-
}
|
|
695
|
-
async releaseProcessLeaseAfterUncertainFailure(identity) {
|
|
696
|
-
if (!identity || !this.processLeaseStore) return;
|
|
697
|
-
this.uncertainProcessLeaseIds.add(identity.leaseId);
|
|
698
|
-
const processLeaseStore = this.processLeaseStore;
|
|
699
|
-
await this.releaseProcessLeaseOperation(identity, async () => {
|
|
700
|
-
const lease = await processLeaseStore.load(identity.leaseId);
|
|
701
|
-
if (!lease || lease.gatewayInstanceId !== identity.gatewayInstanceId || lease.rootPid > 0) this.uncertainProcessLeaseIds.delete(identity.leaseId);
|
|
702
|
-
});
|
|
703
|
-
}
|
|
704
|
-
async runWithProcessLeaseForHandle(handle, record, run) {
|
|
705
|
-
const identity = await this.prepareProcessLeaseForOperation(handle, record);
|
|
706
|
-
try {
|
|
707
|
-
return await run();
|
|
708
|
-
} finally {
|
|
709
|
-
await this.finalizeProcessLeaseForOperation(handle, identity);
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
async finalizeProcessLeaseAfter(handle, identityPromise, resultPromise) {
|
|
713
|
-
try {
|
|
714
|
-
return await resultPromise;
|
|
715
|
-
} finally {
|
|
716
|
-
await this.finalizeProcessLeaseForOperation(handle, await identityPromise);
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
async withCodexWrapperDiagnostics(params) {
|
|
720
|
-
try {
|
|
721
|
-
return await params.run();
|
|
722
|
-
} catch (error) {
|
|
723
|
-
if (!isCodexAcpCommand(params.command) || !isGenericInternalAcpError(error)) throw error;
|
|
724
|
-
const stderrTail = params.handle ? await this.readCodexTurnFailureStderr({ handle: params.handle }) : await readCodexWrapperStderrTail({
|
|
725
|
-
wrapperRoot: this.wrapperRoot,
|
|
726
|
-
leaseId: this.launchLeaseScope.getStore()?.leaseId
|
|
727
|
-
});
|
|
728
|
-
if (!stderrTail) throw error;
|
|
729
|
-
throw new AcpRuntimeError(params.fallbackCode, `Internal error: ${stderrTail}`, { cause: error });
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
async readCodexTurnFailureStderr(params) {
|
|
733
|
-
const record = await this.sessionStore.load(params.handle.acpxRecordId ?? resolveAcpxSessionResource(params.handle));
|
|
734
|
-
return readCodexWrapperStderrTail({
|
|
735
|
-
wrapperRoot: this.wrapperRoot,
|
|
736
|
-
leaseId: readOpenClawLeaseIdFromRecord(record)
|
|
737
|
-
});
|
|
738
|
-
}
|
|
739
|
-
async cleanupProcessTreeForRecord(handle, record) {
|
|
740
|
-
const leaseId = readOpenClawLeaseIdFromRecord(record);
|
|
741
|
-
const rootPid = readRecordAgentPid(record);
|
|
742
|
-
const sessionKeys = [resolveAcpxSessionResource(handle), readSessionRecordName(record)];
|
|
743
|
-
const selectedLease = selectCurrentSessionLease({
|
|
744
|
-
leases: this.gatewayInstanceId && this.processLeaseStore ? await this.processLeaseStore.listOpen(this.gatewayInstanceId) : [],
|
|
745
|
-
sessionKeys,
|
|
746
|
-
rootPid
|
|
747
|
-
});
|
|
748
|
-
const loadedLease = leaseId ? await this.processLeaseStore?.load(leaseId) : void 0;
|
|
749
|
-
const lease = selectedLease ?? (loadedLease && loadedLease.gatewayInstanceId === this.gatewayInstanceId && (!rootPid || loadedLease.rootPid === rootPid) && sessionKeys.includes(loadedLease.sessionKey) ? loadedLease : void 0);
|
|
750
|
-
if (lease && lease.gatewayInstanceId === this.gatewayInstanceId && lease.rootPid > 0) {
|
|
751
|
-
await this.processLeaseStore?.markState(lease.leaseId, "closing");
|
|
752
|
-
const result = await cleanupOpenClawOwnedAcpxProcessTree({
|
|
753
|
-
rootPid: lease.rootPid,
|
|
754
|
-
rootCommand: record?.agentCommand,
|
|
755
|
-
expectedLeaseId: lease.leaseId,
|
|
756
|
-
expectedGatewayInstanceId: lease.gatewayInstanceId,
|
|
757
|
-
wrapperRoot: lease.wrapperRoot,
|
|
758
|
-
deps: this.processCleanupDeps
|
|
759
|
-
});
|
|
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");
|
|
761
|
-
return;
|
|
762
|
-
}
|
|
763
|
-
const rootCommand = readRecordAgentCommand(record) ?? resolveAgentCommand({
|
|
764
|
-
agentName: readAgentFromHandle(handle),
|
|
765
|
-
agentRegistry: this.agentRegistry
|
|
766
|
-
});
|
|
767
|
-
if (!rootPid || !rootCommand) return;
|
|
768
|
-
const expectedGatewayInstanceId = readOpenClawGatewayInstanceIdFromRecord(record);
|
|
769
|
-
await cleanupOpenClawOwnedAcpxProcessTree({
|
|
770
|
-
rootPid,
|
|
771
|
-
rootCommand: renderAgentCommand(rootCommand),
|
|
772
|
-
...leaseId ? { expectedLeaseId: leaseId } : {},
|
|
773
|
-
...expectedGatewayInstanceId ? { expectedGatewayInstanceId } : {},
|
|
774
|
-
wrapperRoot: this.wrapperRoot,
|
|
775
|
-
deps: this.processCleanupDeps
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
isHealthy() {
|
|
779
|
-
return this.probeDelegate.isHealthy();
|
|
780
|
-
}
|
|
781
|
-
async probeAvailability() {
|
|
782
|
-
await this.runWithLaunchLease({
|
|
783
|
-
agent: this.probeAgent,
|
|
784
|
-
sessionKey: ACPX_PROBE_LEASE_SESSION_KEY,
|
|
785
|
-
command: this.probeCommand,
|
|
786
|
-
finalizeCompletedProbe: true,
|
|
787
|
-
run: () => this.probeDelegate.probeAvailability()
|
|
788
|
-
});
|
|
789
|
-
}
|
|
790
|
-
async doctor() {
|
|
791
|
-
return await this.runWithLaunchLease({
|
|
792
|
-
agent: this.probeAgent,
|
|
793
|
-
sessionKey: ACPX_PROBE_LEASE_SESSION_KEY,
|
|
794
|
-
command: this.probeCommand,
|
|
795
|
-
finalizeCompletedProbe: true,
|
|
796
|
-
run: () => this.probeDelegate.doctor()
|
|
797
|
-
});
|
|
798
|
-
}
|
|
799
|
-
async ensureSession(input) {
|
|
800
|
-
const resource = assertAcpxSessionOwnerLocator(input, this.legacyBareSessionKeys);
|
|
801
|
-
return await this.sessionEnsureQueue.enqueue(resource.trim() || resource, () => this.ensureSessionUnlocked(input));
|
|
802
|
-
}
|
|
803
|
-
async ensureSessionUnlocked(logicalInput) {
|
|
804
|
-
assertSupportedRuntimeSessionMode(logicalInput.mode);
|
|
805
|
-
const command = resolveAgentCommand({
|
|
806
|
-
agentName: logicalInput.agent,
|
|
807
|
-
agentRegistry: this.agentRegistry
|
|
808
|
-
});
|
|
809
|
-
const delegate = this.resolveDelegateForSession({
|
|
810
|
-
command,
|
|
811
|
-
sessionKey: logicalInput.sessionKey,
|
|
812
|
-
agentId: logicalInput.agentId
|
|
813
|
-
});
|
|
814
|
-
const logicalTarget = {
|
|
815
|
-
sessionKey: logicalInput.sessionKey,
|
|
816
|
-
agentId: logicalInput.agentId
|
|
817
|
-
};
|
|
818
|
-
const input = {
|
|
819
|
-
...logicalInput,
|
|
820
|
-
sessionKey: resolveAcpxSessionResource(logicalInput)
|
|
821
|
-
};
|
|
822
|
-
const isCodexAcp = normalizeAgentName(input.agent) === CODEX_ACP_AGENT_ID && isCodexAcpCommand(command);
|
|
823
|
-
const claudeModelOverride = isClaudeAcpCommand(command) ? normalizeClaudeAcpModelOverride(input.model) : void 0;
|
|
824
|
-
const codexClassification = isCodexAcp ? classifyCodexAcpModelRequest(input.model, input.thinking) : void 0;
|
|
825
|
-
if (codexClassification?.kind === "unsupported" && input.modelExplicit) failUnsupportedCodexAcpModel(input.model ?? "");
|
|
826
|
-
const classifiedCodexOverride = codexClassification?.kind === "override" ? codexClassification.override : codexClassification?.thinkingOverride;
|
|
827
|
-
const codexModelOverride = classifiedCodexOverride && Object.keys(classifiedCodexOverride).length > 0 ? classifiedCodexOverride : void 0;
|
|
828
|
-
const requestedModel = input.model?.trim();
|
|
829
|
-
const appliedModel = isCodexAcp && requestedModel ? codexModelOverride?.model ? {
|
|
830
|
-
kind: "applied",
|
|
831
|
-
model: requestedModel
|
|
832
|
-
} : { kind: "dropped" } : void 0;
|
|
833
|
-
const ensureInput = isCodexAcp ? withCodexSessionModel(input, codexModelOverride) : claudeModelOverride ? {
|
|
834
|
-
...input,
|
|
835
|
-
model: claudeModelOverride
|
|
836
|
-
} : input;
|
|
837
|
-
const stableLaunchCommand = codexModelOverride && command ? appendCodexAcpConfigOverrides(command, codexModelOverride) : command;
|
|
838
|
-
const reusableCommand = await this.readReusablePersistentSessionCommand({
|
|
839
|
-
sessionKey: input.sessionKey,
|
|
840
|
-
mode: input.mode,
|
|
841
|
-
cwd: input.cwd,
|
|
842
|
-
command: stableLaunchCommand,
|
|
843
|
-
resumeSessionId: input.resumeSessionId
|
|
844
|
-
});
|
|
845
|
-
return {
|
|
846
|
-
...await this.runWithLaunchLease({
|
|
847
|
-
agent: ensureInput.agent,
|
|
848
|
-
sessionKey: ensureInput.sessionKey,
|
|
849
|
-
command: stableLaunchCommand,
|
|
850
|
-
reusableCommand,
|
|
851
|
-
run: () => this.withCodexWrapperDiagnostics({
|
|
852
|
-
command: stableLaunchCommand,
|
|
853
|
-
fallbackCode: "ACP_SESSION_INIT_FAILED",
|
|
854
|
-
run: () => codexModelOverride ? delegate.ensureSession(withAcpxSessionOptions(ensureInput)) : ensureDelegateSessionWithModelFallback(delegate, ensureInput)
|
|
855
|
-
})
|
|
856
|
-
}),
|
|
857
|
-
...logicalTarget,
|
|
858
|
-
...appliedModel ? { appliedModel } : {}
|
|
859
|
-
};
|
|
860
|
-
}
|
|
861
|
-
async *runTurn(input) {
|
|
862
|
-
const turn = this.startTurn(input);
|
|
863
|
-
turn.result.catch(() => {});
|
|
864
|
-
let completed = false;
|
|
865
|
-
try {
|
|
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
|
-
};
|
|
876
|
-
} finally {
|
|
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
|
-
}
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
startTurn(input) {
|
|
885
|
-
const withTurnDiagnostics = (command, run) => this.withCodexWrapperDiagnostics({
|
|
886
|
-
command,
|
|
887
|
-
handle: input.handle,
|
|
888
|
-
fallbackCode: "ACP_TURN_FAILED",
|
|
889
|
-
run
|
|
890
|
-
});
|
|
891
|
-
const snapshotPromise = this.loadOperationSnapshotForHandle(input.handle);
|
|
892
|
-
const turnLeasePromise = snapshotPromise.then(({ record }) => this.prepareProcessLeaseForOperation(input.handle, record));
|
|
893
|
-
const turnPromise = Promise.all([snapshotPromise, turnLeasePromise]).then(([snapshot]) => {
|
|
894
|
-
const { command } = snapshot;
|
|
895
|
-
const delegate = this.resolveDelegateForOperationSnapshot(input.handle, snapshot);
|
|
896
|
-
return withTurnDiagnostics(command, async () => ({
|
|
897
|
-
command,
|
|
898
|
-
turn: delegate.startTurn({
|
|
899
|
-
...toAcpxResourceInput(input),
|
|
900
|
-
timeoutMs: 0
|
|
901
|
-
})
|
|
902
|
-
}));
|
|
903
|
-
});
|
|
904
|
-
return {
|
|
905
|
-
requestId: input.requestId,
|
|
906
|
-
get promptStarted() {
|
|
907
|
-
return turnPromise.then(({ turn }) => turn.promptStarted);
|
|
908
|
-
},
|
|
909
|
-
events: { async *[Symbol.asyncIterator]() {
|
|
910
|
-
const { command, turn } = await turnPromise;
|
|
911
|
-
try {
|
|
912
|
-
yield* turn.events;
|
|
913
|
-
} catch (error) {
|
|
914
|
-
if (!isGenericInternalAcpError(error)) throw error;
|
|
915
|
-
await withTurnDiagnostics(command, () => Promise.reject(error));
|
|
916
|
-
}
|
|
917
|
-
} },
|
|
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
|
-
}))),
|
|
932
|
-
cancel(inputArgs) {
|
|
933
|
-
return turnPromise.then(({ turn }) => turn.cancel(inputArgs));
|
|
934
|
-
},
|
|
935
|
-
closeStream(inputArgs) {
|
|
936
|
-
return turnPromise.then(({ turn }) => turn.closeStream(inputArgs));
|
|
937
|
-
}
|
|
938
|
-
};
|
|
939
|
-
}
|
|
940
|
-
getCapabilities(input) {
|
|
941
|
-
return this.delegate.getCapabilities(input?.handle ? toAcpxResourceInput({ handle: input.handle }) : input);
|
|
942
|
-
}
|
|
943
|
-
async getStatus(input) {
|
|
944
|
-
const snapshot = await this.loadOperationSnapshotForHandle(input.handle);
|
|
945
|
-
return this.resolveDelegateForOperationSnapshot(input.handle, snapshot).getStatus(toAcpxResourceInput(input));
|
|
946
|
-
}
|
|
947
|
-
async setMode(input) {
|
|
948
|
-
const snapshot = await this.loadOperationSnapshotForHandle(input.handle);
|
|
949
|
-
await this.runWithProcessLeaseForHandle(input.handle, snapshot.record, () => this.resolveDelegateForOperationSnapshot(input.handle, snapshot).setMode(toAcpxResourceInput(input)));
|
|
950
|
-
}
|
|
951
|
-
async setConfigOption(input) {
|
|
952
|
-
const snapshot = await this.loadOperationSnapshotForHandle(input.handle);
|
|
953
|
-
return await this.runWithProcessLeaseForHandle(input.handle, snapshot.record, () => this.setConfigOptionUnlocked(input, snapshot));
|
|
954
|
-
}
|
|
955
|
-
async setConfigOptionUnlocked(logicalInput, snapshot) {
|
|
956
|
-
const { command } = snapshot;
|
|
957
|
-
const delegate = this.resolveDelegateForOperationSnapshot(logicalInput.handle, snapshot);
|
|
958
|
-
const input = toAcpxResourceInput(logicalInput);
|
|
959
|
-
const key = input.key.trim().toLowerCase();
|
|
960
|
-
const isCodexAcp = isCodexAcpCommand(command);
|
|
961
|
-
if (WIRE_TIMEOUT_CONFIG_KEYS.has(key) && (isCodexAcp || isClaudeAcpCommand(command))) return;
|
|
962
|
-
if (isCodexAcp) {
|
|
963
|
-
if (key === "model") {
|
|
964
|
-
const classification = classifyCodexAcpModelRequest(input.value);
|
|
965
|
-
if (classification.kind === "unsupported") failUnsupportedCodexAcpModel(input.value);
|
|
966
|
-
const { override } = classification;
|
|
967
|
-
const modelResult = override.model ? await delegate.setConfigOption({
|
|
968
|
-
...input,
|
|
969
|
-
key: "model",
|
|
970
|
-
value: override.model
|
|
971
|
-
}) : void 0;
|
|
972
|
-
if (override.reasoningEffort) return await delegate.setConfigOption({
|
|
973
|
-
...input,
|
|
974
|
-
key: "reasoning_effort",
|
|
975
|
-
value: override.reasoningEffort
|
|
976
|
-
});
|
|
977
|
-
return modelResult;
|
|
978
|
-
}
|
|
979
|
-
if (key === "thinking" || key === "thought_level" || key === "reasoning_effort") {
|
|
980
|
-
const classification = classifyCodexAcpModelRequest(void 0, input.value);
|
|
981
|
-
const reasoningEffort = classification.kind === "override" ? classification.override.reasoningEffort : void 0;
|
|
982
|
-
if (!reasoningEffort) throw new AcpRuntimeError("ACP_BACKEND_UNSUPPORTED_CONTROL", "Clearing Codex reasoning effort on an existing session is unsupported. Choose a supported explicit effort; the current effort is unchanged.");
|
|
983
|
-
return await delegate.setConfigOption({
|
|
984
|
-
...input,
|
|
985
|
-
key: "reasoning_effort",
|
|
986
|
-
value: reasoningEffort
|
|
987
|
-
});
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
if (isClaudeAcpCommand(command) && key === "model") return await delegate.setConfigOption({
|
|
991
|
-
...input,
|
|
992
|
-
value: normalizeClaudeAcpModelOverride(input.value) ?? input.value
|
|
993
|
-
});
|
|
994
|
-
return await delegate.setConfigOption(input);
|
|
995
|
-
}
|
|
996
|
-
async cancel(input) {
|
|
997
|
-
const snapshot = await this.loadOperationSnapshotForHandle(input.handle);
|
|
998
|
-
await this.resolveDelegateForOperationSnapshot(input.handle, snapshot).cancel(toAcpxResourceInput(input));
|
|
999
|
-
}
|
|
1000
|
-
async prepareFreshSession(input) {
|
|
1001
|
-
const resource = assertAcpxSessionOwnerLocator(input, this.legacyBareSessionKeys);
|
|
1002
|
-
this.sessionStore.markFresh(resource);
|
|
1003
|
-
this.legacyBareSessionKeys.delete(resource);
|
|
1004
|
-
}
|
|
1005
|
-
async close(input) {
|
|
1006
|
-
const snapshot = await this.loadOperationSnapshotForHandle(input.handle);
|
|
1007
|
-
const closeLease = await this.prepareProcessLeaseForOperation(input.handle, snapshot.record);
|
|
1008
|
-
let cleanupSucceeded = false;
|
|
1009
|
-
try {
|
|
1010
|
-
const delegate = this.resolveDelegateForOperationSnapshot(input.handle, snapshot);
|
|
1011
|
-
const handle = toAcpxResourceInput(input).handle;
|
|
1012
|
-
try {
|
|
1013
|
-
await delegate.close({
|
|
1014
|
-
handle,
|
|
1015
|
-
reason: input.reason,
|
|
1016
|
-
discardPersistentState: input.discardPersistentState
|
|
1017
|
-
});
|
|
1018
|
-
if (this.managedToolsSessionDelegates.get(handle.sessionKey) === delegate) this.managedToolsSessionDelegates.delete(handle.sessionKey);
|
|
1019
|
-
} finally {
|
|
1020
|
-
await this.cleanupProcessTreeForRecord(input.handle, snapshot.record);
|
|
1021
|
-
cleanupSucceeded = true;
|
|
1022
|
-
}
|
|
1023
|
-
if (input.discardPersistentState) await this.prepareFreshSession({
|
|
1024
|
-
...input.handle,
|
|
1025
|
-
persistedHandle: input.handle
|
|
1026
|
-
});
|
|
1027
|
-
} finally {
|
|
1028
|
-
if (cleanupSucceeded) await this.finalizeProcessLeaseForOperation(input.handle, closeLease);
|
|
1029
|
-
else await this.releaseProcessLeaseAfterUncertainFailure(closeLease);
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
};
|
|
1033
|
-
/** Test-only hooks for ACPX runtime behavior that is otherwise private. */
|
|
1034
|
-
const testing = {
|
|
1035
|
-
appendCodexAcpConfigOverrides,
|
|
1036
|
-
isClaudeAcpCommand,
|
|
1037
|
-
isCodexAcpCommand
|
|
1038
|
-
};
|
|
1039
|
-
//#endregion
|
|
1040
|
-
export { ACPX_BACKEND_ID, AcpxRuntime, createAcpRuntime, createAgentRegistry, createFileSessionStore, decodeAcpxRuntimeHandleState, encodeAcpxRuntimeHandleState, testing };
|