acpx 0.7.0 → 0.9.0
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 +14 -6
- package/dist/{cli-T-Z-9x6a.js → cli-Bf3yjqzE.js} +35 -10
- package/dist/cli-Bf3yjqzE.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +724 -241
- package/dist/cli.js.map +1 -1
- package/dist/{client-COPilhO_.d.ts → client-BssohYqM.d.ts} +35 -4
- package/dist/client-BssohYqM.d.ts.map +1 -0
- package/dist/flags-C-rwARqg.js +260 -0
- package/dist/flags-C-rwARqg.js.map +1 -0
- package/dist/{flows-CF8w1rPI.js → flows-WLs26_5Y.js} +405 -337
- package/dist/flows-WLs26_5Y.js.map +1 -0
- package/dist/flows.d.ts +23 -2
- package/dist/flows.d.ts.map +1 -1
- package/dist/flows.js +1 -1
- package/dist/{prompt-turn-CVPMWdj1.js → live-checkpoint-D5d-K9s1.js} +2487 -609
- package/dist/live-checkpoint-D5d-K9s1.js.map +1 -0
- package/dist/output-DPg20dvn.js +4146 -0
- package/dist/output-DPg20dvn.js.map +1 -0
- package/dist/runtime.d.ts +56 -4
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +676 -393
- package/dist/runtime.js.map +1 -1
- package/dist/{types-CVBeQyi3.d.ts → session-options-CFudjdkU.d.ts} +62 -3
- package/dist/session-options-CFudjdkU.d.ts.map +1 -0
- package/package.json +30 -25
- package/skills/acpx/SKILL.md +211 -13
- package/dist/cli-T-Z-9x6a.js.map +0 -1
- package/dist/client-COPilhO_.d.ts.map +0 -1
- package/dist/flags-Dj-IXgo9.js +0 -163
- package/dist/flags-Dj-IXgo9.js.map +0 -1
- package/dist/flows-CF8w1rPI.js.map +0 -1
- package/dist/ipc-ABXlXzGP.js +0 -1290
- package/dist/ipc-ABXlXzGP.js.map +0 -1
- package/dist/jsonrpc-DSxh2w5R.js +0 -68
- package/dist/jsonrpc-DSxh2w5R.js.map +0 -1
- package/dist/output-DmHvT8vm.js +0 -807
- package/dist/output-DmHvT8vm.js.map +0 -1
- package/dist/perf-metrics-C2pXfxvR.js +0 -598
- package/dist/perf-metrics-C2pXfxvR.js.map +0 -1
- package/dist/prompt-turn-CVPMWdj1.js.map +0 -1
- package/dist/render-N5YwotCy.js +0 -172
- package/dist/render-N5YwotCy.js.map +0 -1
- package/dist/rolldown-runtime-CiIaOW0V.js +0 -13
- package/dist/session-CDaQe6BH.js +0 -1538
- package/dist/session-CDaQe6BH.js.map +0 -1
- package/dist/session-options-pCbHn_n7.d.ts +0 -13
- package/dist/session-options-pCbHn_n7.d.ts.map +0 -1
- package/dist/types-CVBeQyi3.d.ts.map +0 -1
package/dist/runtime.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { C as isAcpResourceNotFoundError,
|
|
2
|
-
import { $ as resolveAgentCommand, C as AcpClient, G as serializeSessionRecordForDisk, L as parseSessionRecord, S as trimConversationForRuntime, W as assertPersistedKeyPolicy, X as DEFAULT_AGENT_NAME, Y as withTimeout, Z as listBuiltInAgents, _ as cloneSessionConversation, a as connectAndLoadSession, b as recordPromptSubmission, c as reconcileAgentSessionId, d as setDesiredConfigOption, f as setDesiredModeId, g as cloneSessionAcpxState, h as applyConfigOptionsToRecord, n as withConnectedSession, o as applyConversation, s as applyLifecycleSnapshotToRecord, t as runPromptTurn, v as createSessionConversation, x as recordSessionUpdate, y as recordClientOperation, z as defaultSessionEventLog } from "./prompt-turn-CVPMWdj1.js";
|
|
1
|
+
import { C as applyConversation, Dt as isAcpResourceNotFoundError, E as AcpClient, Et as extractAcpError, K as defaultSessionEventLog, T as reconcileAgentSessionId, Tt as normalizeOutputError, W as parseSessionRecord, Z as assertPersistedKeyPolicy, _ as recordPromptSubmission, _t as withTimeout, a as applyRequestedModelIfAdvertised, c as setDesiredConfigOption, d as syncAdvertisedModelState, f as applyConfigOptionsToRecord, g as recordClientOperation, h as createSessionConversation, i as connectAndLoadSession, l as setDesiredModeId, m as cloneSessionConversation, n as runPromptTurn, ot as serializeSessionRecordForDisk, p as cloneSessionAcpxState, pt as textPrompt, r as withConnectedSession, s as setCurrentModelId, t as LiveSessionCheckpoint, v as recordSessionUpdate, vt as DEFAULT_AGENT_NAME, w as applyLifecycleSnapshotToRecord, x as persistSessionOptions, xt as resolveAgentCommand, y as trimConversationForRuntime, yt as listBuiltInAgents } from "./live-checkpoint-D5d-K9s1.js";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import fs from "node:fs/promises";
|
|
5
4
|
import { randomUUID } from "node:crypto";
|
|
@@ -37,6 +36,7 @@ function deriveAgentFromSessionKey(sessionKey, fallbackAgent) {
|
|
|
37
36
|
}
|
|
38
37
|
//#endregion
|
|
39
38
|
//#region src/runtime/public/events.ts
|
|
39
|
+
const TOOL_OUTPUT_SUMMARY_MAX_CHARS = 500;
|
|
40
40
|
function safeParseJsonObject(line) {
|
|
41
41
|
try {
|
|
42
42
|
const parsed = JSON.parse(line);
|
|
@@ -76,28 +76,36 @@ function resolveStructuredPromptPayload(parsed) {
|
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
78
|
function resolveStatusTextForTag(params) {
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return
|
|
79
|
+
const resolver = STATUS_TEXT_RESOLVERS[params.tag];
|
|
80
|
+
return resolver ? resolver(params.payload) : null;
|
|
81
|
+
}
|
|
82
|
+
const STATUS_TEXT_RESOLVERS = {
|
|
83
|
+
available_commands_update: availableCommandsStatusText,
|
|
84
|
+
current_mode_update: currentModeStatusText,
|
|
85
|
+
config_option_update: configOptionStatusText,
|
|
86
|
+
session_info_update: sessionInfoStatusText,
|
|
87
|
+
plan: planStatusText
|
|
88
|
+
};
|
|
89
|
+
function availableCommandsStatusText(payload) {
|
|
90
|
+
const commands = Array.isArray(payload.availableCommands) ? payload.availableCommands : [];
|
|
91
|
+
return commands.length > 0 ? `available commands updated (${commands.length})` : "available commands updated";
|
|
92
|
+
}
|
|
93
|
+
function currentModeStatusText(payload) {
|
|
94
|
+
const mode = asTrimmedString(payload.currentModeId) || asTrimmedString(payload.modeId) || asTrimmedString(payload.mode);
|
|
95
|
+
return mode ? `mode updated: ${mode}` : "mode updated";
|
|
96
|
+
}
|
|
97
|
+
function configOptionStatusText(payload) {
|
|
98
|
+
const id = asTrimmedString(payload.id) || asTrimmedString(payload.configOptionId);
|
|
99
|
+
const value = asTrimmedString(payload.currentValue) || asTrimmedString(payload.value) || asTrimmedString(payload.optionValue);
|
|
100
|
+
if (id && value) return `config updated: ${id}=${value}`;
|
|
101
|
+
return id ? `config updated: ${id}` : "config updated";
|
|
102
|
+
}
|
|
103
|
+
function sessionInfoStatusText(payload) {
|
|
104
|
+
return asTrimmedString(payload.summary) || asTrimmedString(payload.message) || "session updated";
|
|
105
|
+
}
|
|
106
|
+
function planStatusText(payload) {
|
|
107
|
+
const content = asTrimmedString((Array.isArray(payload.entries) ? payload.entries : []).find((entry) => isRecord(entry))?.content);
|
|
108
|
+
return content ? `plan: ${content}` : null;
|
|
101
109
|
}
|
|
102
110
|
function resolveTextChunk(params) {
|
|
103
111
|
const contentRaw = params.payload.content;
|
|
@@ -169,20 +177,108 @@ function summarizeToolInput(rawInput) {
|
|
|
169
177
|
"search"
|
|
170
178
|
]);
|
|
171
179
|
}
|
|
180
|
+
function truncateToolSummary(value) {
|
|
181
|
+
if (value.length <= TOOL_OUTPUT_SUMMARY_MAX_CHARS) return value;
|
|
182
|
+
return `${value.slice(0, TOOL_OUTPUT_SUMMARY_MAX_CHARS - 1)}…`;
|
|
183
|
+
}
|
|
184
|
+
function readToolContentText(value) {
|
|
185
|
+
const record = isRecord(value) ? value : void 0;
|
|
186
|
+
if (!record) return;
|
|
187
|
+
if (record.type === "content") return readToolContentText(record.content);
|
|
188
|
+
return toolContentTextReader(String(record.type))?.(record);
|
|
189
|
+
}
|
|
190
|
+
const TOOL_CONTENT_TEXT_READERS = {
|
|
191
|
+
text: (record) => asString(record.text),
|
|
192
|
+
audio: (record) => `[audio] ${asOptionalString(record.mimeType) || "audio"}`,
|
|
193
|
+
resource_link: (record) => asOptionalString(record.title) || asOptionalString(record.name) || asOptionalString(record.uri),
|
|
194
|
+
resource: (record) => {
|
|
195
|
+
const resource = isRecord(record.resource) ? record.resource : void 0;
|
|
196
|
+
return asString(resource?.text) || asOptionalString(resource?.uri);
|
|
197
|
+
},
|
|
198
|
+
diff: (record) => `diff ${asOptionalString(record.path) || "file"}`,
|
|
199
|
+
terminal: (record) => {
|
|
200
|
+
const terminalId = asOptionalString(record.terminalId) || asOptionalString(record.id);
|
|
201
|
+
return terminalId ? `[terminal] ${terminalId}` : "[terminal]";
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
function toolContentTextReader(type) {
|
|
205
|
+
return Object.hasOwn(TOOL_CONTENT_TEXT_READERS, type) ? TOOL_CONTENT_TEXT_READERS[type] : void 0;
|
|
206
|
+
}
|
|
207
|
+
function summarizeToolContent(content) {
|
|
208
|
+
if (!Array.isArray(content)) return;
|
|
209
|
+
const fragments = content.map((entry) => readToolContentText(entry)?.trim()).filter((entry) => Boolean(entry));
|
|
210
|
+
if (fragments.length === 0) return;
|
|
211
|
+
return truncateToolSummary([...new Set(fragments)].join("\n"));
|
|
212
|
+
}
|
|
213
|
+
function summarizeToolOutput(rawOutput) {
|
|
214
|
+
if (rawOutput == null) return;
|
|
215
|
+
if (isScalarToolOutput(rawOutput)) return truncateToolSummary(String(rawOutput));
|
|
216
|
+
const record = isRecord(rawOutput) ? rawOutput : void 0;
|
|
217
|
+
if (!record) return;
|
|
218
|
+
return truncateToolSummary(readFirstString(record, [
|
|
219
|
+
"text",
|
|
220
|
+
"message",
|
|
221
|
+
"error",
|
|
222
|
+
"stdout",
|
|
223
|
+
"stderr",
|
|
224
|
+
"content"
|
|
225
|
+
]) ?? "") || void 0;
|
|
226
|
+
}
|
|
227
|
+
function isScalarToolOutput(value) {
|
|
228
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
229
|
+
}
|
|
230
|
+
function shouldForwardArray(value) {
|
|
231
|
+
return Array.isArray(value);
|
|
232
|
+
}
|
|
233
|
+
function readToolKind(value) {
|
|
234
|
+
const kind = asOptionalString(value);
|
|
235
|
+
return kind && TOOL_KINDS.has(kind) ? kind : void 0;
|
|
236
|
+
}
|
|
237
|
+
const TOOL_KINDS = new Set([
|
|
238
|
+
"read",
|
|
239
|
+
"edit",
|
|
240
|
+
"delete",
|
|
241
|
+
"move",
|
|
242
|
+
"search",
|
|
243
|
+
"execute",
|
|
244
|
+
"fetch",
|
|
245
|
+
"think",
|
|
246
|
+
"other"
|
|
247
|
+
]);
|
|
172
248
|
function createToolCallEvent(params) {
|
|
173
249
|
const title = asTrimmedString(params.payload.title) || "tool call";
|
|
174
250
|
const status = asTrimmedString(params.payload.status);
|
|
175
251
|
const inputSummary = summarizeToolInput(params.payload.rawInput);
|
|
252
|
+
const outputSummary = summarizeToolContent(params.payload.content) ?? summarizeToolOutput(params.payload.rawOutput);
|
|
176
253
|
const toolCallId = asOptionalString(params.payload.toolCallId);
|
|
254
|
+
const kind = readToolKind(params.payload.kind);
|
|
177
255
|
const summaryText = status ? `${title} (${status})` : title;
|
|
178
|
-
|
|
256
|
+
const detailSummary = params.tag === "tool_call_update" ? outputSummary ?? inputSummary : inputSummary ?? outputSummary;
|
|
257
|
+
const event = {
|
|
179
258
|
type: "tool_call",
|
|
180
|
-
text:
|
|
259
|
+
text: detailSummary ? `${summaryText}: ${detailSummary}` : summaryText,
|
|
181
260
|
tag: params.tag,
|
|
182
|
-
...toolCallId ? { toolCallId } : {},
|
|
183
|
-
...status ? { status } : {},
|
|
184
261
|
title
|
|
185
262
|
};
|
|
263
|
+
assignToolCallEventMetadata(event, params.payload, {
|
|
264
|
+
toolCallId,
|
|
265
|
+
status,
|
|
266
|
+
kind
|
|
267
|
+
});
|
|
268
|
+
return event;
|
|
269
|
+
}
|
|
270
|
+
function assignToolCallEventMetadata(event, payload, values) {
|
|
271
|
+
if (event.type !== "tool_call") return;
|
|
272
|
+
if (values.toolCallId) event.toolCallId = values.toolCallId;
|
|
273
|
+
if (values.status) event.status = values.status;
|
|
274
|
+
if (values.kind) event.kind = values.kind;
|
|
275
|
+
assignForwardedToolPayload(event, payload);
|
|
276
|
+
}
|
|
277
|
+
function assignForwardedToolPayload(event, payload) {
|
|
278
|
+
if (shouldForwardArray(payload.locations)) event.locations = payload.locations;
|
|
279
|
+
if (Object.prototype.hasOwnProperty.call(payload, "rawInput")) event.rawInput = payload.rawInput;
|
|
280
|
+
if (Object.prototype.hasOwnProperty.call(payload, "rawOutput")) event.rawOutput = payload.rawOutput;
|
|
281
|
+
if (shouldForwardArray(payload.content)) event.content = payload.content;
|
|
186
282
|
}
|
|
187
283
|
function parsePromptEventLine(line) {
|
|
188
284
|
const trimmed = line.trim();
|
|
@@ -196,88 +292,94 @@ function parsePromptEventLine(line) {
|
|
|
196
292
|
const type = structured.type;
|
|
197
293
|
const payload = structured.payload;
|
|
198
294
|
const tag = structured.tag;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
295
|
+
const parser = promptEventParser(type);
|
|
296
|
+
return parser ? parser(payload, tag) : null;
|
|
297
|
+
}
|
|
298
|
+
const PROMPT_EVENT_PARSERS = {
|
|
299
|
+
text: (payload, tag) => createTextDeltaEvent({
|
|
300
|
+
content: asString(payload.content),
|
|
301
|
+
stream: "output",
|
|
302
|
+
tag
|
|
303
|
+
}),
|
|
304
|
+
thought: (payload, tag) => createTextDeltaEvent({
|
|
305
|
+
content: asString(payload.content),
|
|
306
|
+
stream: "thought",
|
|
307
|
+
tag
|
|
308
|
+
}),
|
|
309
|
+
tool_call: (payload, tag) => createToolCallEvent({
|
|
310
|
+
payload,
|
|
311
|
+
tag: tag ?? "tool_call"
|
|
312
|
+
}),
|
|
313
|
+
tool_call_update: (payload, tag) => createToolCallEvent({
|
|
314
|
+
payload,
|
|
315
|
+
tag: tag ?? "tool_call_update"
|
|
316
|
+
}),
|
|
317
|
+
agent_message_chunk: (payload) => resolveTextChunk({
|
|
318
|
+
payload,
|
|
319
|
+
stream: "output",
|
|
320
|
+
tag: "agent_message_chunk"
|
|
321
|
+
}),
|
|
322
|
+
agent_thought_chunk: (payload) => resolveTextChunk({
|
|
323
|
+
payload,
|
|
324
|
+
stream: "thought",
|
|
325
|
+
tag: "agent_thought_chunk"
|
|
326
|
+
}),
|
|
327
|
+
usage_update: usageUpdateEvent,
|
|
328
|
+
available_commands_update: (payload) => statusUpdateEvent("available_commands_update", payload),
|
|
329
|
+
current_mode_update: (payload) => statusUpdateEvent("current_mode_update", payload),
|
|
330
|
+
config_option_update: (payload) => statusUpdateEvent("config_option_update", payload),
|
|
331
|
+
session_info_update: (payload) => statusUpdateEvent("session_info_update", payload),
|
|
332
|
+
plan: (payload) => statusUpdateEvent("plan", payload),
|
|
333
|
+
client_operation: clientOperationEvent,
|
|
334
|
+
update: updateStatusEvent,
|
|
335
|
+
done: () => null,
|
|
336
|
+
error: () => null
|
|
337
|
+
};
|
|
338
|
+
function promptEventParser(type) {
|
|
339
|
+
return Object.hasOwn(PROMPT_EVENT_PARSERS, type) ? PROMPT_EVENT_PARSERS[type] : void 0;
|
|
340
|
+
}
|
|
341
|
+
function usageUpdateEvent(payload) {
|
|
342
|
+
const used = asOptionalFiniteNumber(payload.used);
|
|
343
|
+
const size = asOptionalFiniteNumber(payload.size);
|
|
344
|
+
return {
|
|
345
|
+
type: "status",
|
|
346
|
+
text: used != null && size != null ? `usage updated: ${used}/${size}` : "usage updated",
|
|
347
|
+
tag: "usage_update",
|
|
348
|
+
...used != null ? { used } : {},
|
|
349
|
+
...size != null ? { size } : {}
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function statusUpdateEvent(tag, payload) {
|
|
353
|
+
const text = resolveStatusTextForTag({
|
|
354
|
+
tag,
|
|
355
|
+
payload
|
|
356
|
+
});
|
|
357
|
+
if (!text) return null;
|
|
358
|
+
return {
|
|
359
|
+
type: "status",
|
|
360
|
+
text,
|
|
361
|
+
tag
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
function clientOperationEvent(payload, tag) {
|
|
365
|
+
const text = [
|
|
366
|
+
asTrimmedString(payload.method) || "operation",
|
|
367
|
+
asTrimmedString(payload.status),
|
|
368
|
+
asTrimmedString(payload.summary)
|
|
369
|
+
].filter(Boolean).join(" ");
|
|
370
|
+
return text ? {
|
|
371
|
+
type: "status",
|
|
372
|
+
text,
|
|
373
|
+
...tag ? { tag } : {}
|
|
374
|
+
} : null;
|
|
375
|
+
}
|
|
376
|
+
function updateStatusEvent(payload, tag) {
|
|
377
|
+
const update = asTrimmedString(payload.update);
|
|
378
|
+
return update ? {
|
|
379
|
+
type: "status",
|
|
380
|
+
text: update,
|
|
381
|
+
...tag ? { tag } : {}
|
|
382
|
+
} : null;
|
|
281
383
|
}
|
|
282
384
|
//#endregion
|
|
283
385
|
//#region src/runtime/engine/reuse-policy.ts
|
|
@@ -357,12 +459,23 @@ function toPromptInput(text, attachments) {
|
|
|
357
459
|
text
|
|
358
460
|
});
|
|
359
461
|
for (const attachment of attachments) {
|
|
360
|
-
if (
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
462
|
+
if (attachment.mediaType.startsWith("image/")) {
|
|
463
|
+
blocks.push({
|
|
464
|
+
type: "image",
|
|
465
|
+
mimeType: attachment.mediaType,
|
|
466
|
+
data: attachment.data
|
|
467
|
+
});
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
if (attachment.mediaType.startsWith("audio/")) {
|
|
471
|
+
blocks.push({
|
|
472
|
+
type: "audio",
|
|
473
|
+
mimeType: attachment.mediaType,
|
|
474
|
+
data: attachment.data
|
|
475
|
+
});
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
throw new AcpRuntimeError("ACP_TURN_FAILED", `Unsupported ACP runtime attachment media type: ${attachment.mediaType}`);
|
|
366
479
|
}
|
|
367
480
|
return blocks.length > 0 ? blocks : textPrompt(text);
|
|
368
481
|
}
|
|
@@ -415,7 +528,60 @@ function statusSummary(record) {
|
|
|
415
528
|
record.closed ? "closed" : "open"
|
|
416
529
|
].filter(Boolean).join(" ");
|
|
417
530
|
}
|
|
531
|
+
function buildModelsField(record) {
|
|
532
|
+
const available = record.acpx?.available_models;
|
|
533
|
+
const currentModelId = record.acpx?.current_model_id;
|
|
534
|
+
if (!available || available.length === 0) return currentModelId === void 0 ? {} : { models: {
|
|
535
|
+
currentModelId,
|
|
536
|
+
availableModelIds: []
|
|
537
|
+
} };
|
|
538
|
+
return { models: {
|
|
539
|
+
...currentModelId !== void 0 ? { currentModelId } : {},
|
|
540
|
+
availableModelIds: [...available]
|
|
541
|
+
} };
|
|
542
|
+
}
|
|
543
|
+
function advertisedConfigOptionIds(record) {
|
|
544
|
+
const configOptions = record.acpx?.config_options;
|
|
545
|
+
if (!configOptions) return;
|
|
546
|
+
return new Set(configOptions.map((option) => option.id).filter((id) => typeof id === "string" && id.trim().length > 0));
|
|
547
|
+
}
|
|
548
|
+
function resolveSupportedConfigOptionId(record, configId) {
|
|
549
|
+
const advertisedIds = advertisedConfigOptionIds(record);
|
|
550
|
+
if (!advertisedIds) return configId;
|
|
551
|
+
if (advertisedIds.has(configId)) return configId;
|
|
552
|
+
if (configId === "thinking" && advertisedIds.has("effort")) return "effort";
|
|
553
|
+
const supported = [...advertisedIds].toSorted();
|
|
554
|
+
const supportedText = supported.length > 0 ? supported.join(", ") : "none";
|
|
555
|
+
throw new AcpRuntimeError("ACP_BACKEND_UNSUPPORTED_CONTROL", `ACP session ${record.acpxRecordId} does not advertise config option '${configId}'. Supported config options: ${supportedText}.`);
|
|
556
|
+
}
|
|
557
|
+
async function createOrLoadRuntimeSession(client, resumeSessionId, cwd) {
|
|
558
|
+
if (resumeSessionId) {
|
|
559
|
+
if (client.supportsResumeSession()) {
|
|
560
|
+
const resumed = await client.resumeSession(resumeSessionId, cwd);
|
|
561
|
+
return {
|
|
562
|
+
sessionId: resumeSessionId,
|
|
563
|
+
agentSessionId: resumed.agentSessionId,
|
|
564
|
+
sessionResult: resumed
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
if (!client.supportsLoadSession()) throw new Error(`Agent does not support session/resume or session/load; cannot resume session ${resumeSessionId}`);
|
|
568
|
+
const loaded = await client.loadSession(resumeSessionId, cwd);
|
|
569
|
+
return {
|
|
570
|
+
sessionId: resumeSessionId,
|
|
571
|
+
agentSessionId: loaded.agentSessionId,
|
|
572
|
+
sessionResult: loaded
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
const created = await client.createSession(cwd);
|
|
576
|
+
return {
|
|
577
|
+
sessionId: created.sessionId,
|
|
578
|
+
agentSessionId: created.agentSessionId,
|
|
579
|
+
sessionResult: created
|
|
580
|
+
};
|
|
581
|
+
}
|
|
418
582
|
var AcpRuntimeManager = class {
|
|
583
|
+
options;
|
|
584
|
+
deps;
|
|
419
585
|
activeControllers = /* @__PURE__ */ new Map();
|
|
420
586
|
pendingPersistentClients = /* @__PURE__ */ new Map();
|
|
421
587
|
closingActiveRecords = /* @__PURE__ */ new Set();
|
|
@@ -489,6 +655,7 @@ var AcpRuntimeManager = class {
|
|
|
489
655
|
mcpServers: [...this.options.mcpServers ?? []],
|
|
490
656
|
permissionMode: this.options.permissionMode,
|
|
491
657
|
nonInteractivePermissions: this.options.nonInteractivePermissions,
|
|
658
|
+
onPermissionRequest: this.options.onPermissionRequest,
|
|
492
659
|
verbose: this.options.verbose,
|
|
493
660
|
timeoutMs: this.options.timeoutMs,
|
|
494
661
|
resumePolicy: resumePolicyForSessionMode(sessionMode),
|
|
@@ -520,50 +687,63 @@ var AcpRuntimeManager = class {
|
|
|
520
687
|
mcpServers: [...this.options.mcpServers ?? []],
|
|
521
688
|
permissionMode: this.options.permissionMode,
|
|
522
689
|
nonInteractivePermissions: this.options.nonInteractivePermissions,
|
|
523
|
-
|
|
690
|
+
onPermissionRequest: this.options.onPermissionRequest,
|
|
691
|
+
verbose: this.options.verbose,
|
|
692
|
+
sessionOptions: input.sessionOptions
|
|
524
693
|
});
|
|
525
694
|
let keepClientOpen = false;
|
|
526
695
|
try {
|
|
527
696
|
await client.start();
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
const loaded = await client.loadSession(input.resumeSessionId, cwd);
|
|
533
|
-
sessionId = input.resumeSessionId;
|
|
534
|
-
agentSessionId = loaded.agentSessionId;
|
|
535
|
-
sessionResult = loaded;
|
|
536
|
-
} else {
|
|
537
|
-
const created = await client.createSession(cwd);
|
|
538
|
-
sessionId = created.sessionId;
|
|
539
|
-
agentSessionId = created.agentSessionId;
|
|
540
|
-
sessionResult = created;
|
|
541
|
-
}
|
|
542
|
-
const record = createInitialRecord({
|
|
543
|
-
recordId: createRecordId(input.sessionKey, input.mode),
|
|
544
|
-
sessionName: input.sessionKey,
|
|
545
|
-
sessionId,
|
|
697
|
+
const session = await createOrLoadRuntimeSession(client, input.resumeSessionId, cwd);
|
|
698
|
+
const record = await this.createAndSaveRuntimeRecord({
|
|
699
|
+
input,
|
|
700
|
+
client,
|
|
546
701
|
agentCommand,
|
|
547
702
|
cwd,
|
|
548
|
-
|
|
703
|
+
session
|
|
549
704
|
});
|
|
550
|
-
this.
|
|
551
|
-
record.protocolVersion = client.initializeResult?.protocolVersion;
|
|
552
|
-
record.agentCapabilities = client.initializeResult?.agentCapabilities;
|
|
553
|
-
applyConfigOptionsToRecord(record, sessionResult);
|
|
554
|
-
applyLifecycleSnapshotToRecord(record, client.getAgentLifecycleSnapshot());
|
|
555
|
-
await this.options.sessionStore.save(record);
|
|
556
|
-
if (input.mode === "persistent") {
|
|
557
|
-
const previousClient = this.pendingPersistentClients.get(record.acpxRecordId);
|
|
558
|
-
this.pendingPersistentClients.set(record.acpxRecordId, client);
|
|
559
|
-
keepClientOpen = true;
|
|
560
|
-
await previousClient?.close().catch(() => {});
|
|
561
|
-
}
|
|
705
|
+
keepClientOpen = await this.keepPersistentClient(input.mode, record.acpxRecordId, client);
|
|
562
706
|
return record;
|
|
563
707
|
} finally {
|
|
564
708
|
if (!keepClientOpen) await client.close();
|
|
565
709
|
}
|
|
566
710
|
}
|
|
711
|
+
async createAndSaveRuntimeRecord(params) {
|
|
712
|
+
const { input, client, agentCommand, cwd, session } = params;
|
|
713
|
+
const record = createInitialRecord({
|
|
714
|
+
recordId: createRecordId(input.sessionKey, input.mode),
|
|
715
|
+
sessionName: input.sessionKey,
|
|
716
|
+
sessionId: session.sessionId,
|
|
717
|
+
agentCommand,
|
|
718
|
+
cwd,
|
|
719
|
+
agentSessionId: session.agentSessionId
|
|
720
|
+
});
|
|
721
|
+
this.closingActiveRecords.delete(record.acpxRecordId);
|
|
722
|
+
record.protocolVersion = client.initializeResult?.protocolVersion;
|
|
723
|
+
record.agentCapabilities = client.initializeResult?.agentCapabilities;
|
|
724
|
+
applyConfigOptionsToRecord(record, session.sessionResult);
|
|
725
|
+
const requestedModelApplied = await applyRequestedModelIfAdvertised({
|
|
726
|
+
client,
|
|
727
|
+
sessionId: session.sessionId,
|
|
728
|
+
requestedModel: input.sessionOptions?.model,
|
|
729
|
+
models: session.sessionResult.models,
|
|
730
|
+
agentCommand,
|
|
731
|
+
timeoutMs: this.options.timeoutMs
|
|
732
|
+
});
|
|
733
|
+
syncAdvertisedModelState(record, session.sessionResult.models);
|
|
734
|
+
if (requestedModelApplied) setCurrentModelId(record, input.sessionOptions?.model);
|
|
735
|
+
applyLifecycleSnapshotToRecord(record, client.getAgentLifecycleSnapshot());
|
|
736
|
+
persistSessionOptions(record, input.sessionOptions);
|
|
737
|
+
await this.options.sessionStore.save(record);
|
|
738
|
+
return record;
|
|
739
|
+
}
|
|
740
|
+
async keepPersistentClient(mode, recordId, client) {
|
|
741
|
+
if (mode !== "persistent") return false;
|
|
742
|
+
const previousClient = this.pendingPersistentClients.get(recordId);
|
|
743
|
+
this.pendingPersistentClients.set(recordId, client);
|
|
744
|
+
await previousClient?.close().catch(() => {});
|
|
745
|
+
return true;
|
|
746
|
+
}
|
|
567
747
|
startTurn(input) {
|
|
568
748
|
const promptInput = toPromptInput(input.text, input.attachments);
|
|
569
749
|
const queue = new AsyncEventQueue();
|
|
@@ -571,10 +751,12 @@ var AcpRuntimeManager = class {
|
|
|
571
751
|
const sessionReady = createDeferred();
|
|
572
752
|
sessionReady.promise.catch(() => {});
|
|
573
753
|
let resultSettled = false;
|
|
574
|
-
|
|
575
|
-
|
|
754
|
+
const state = {
|
|
755
|
+
pendingCancel: false,
|
|
756
|
+
turnActive: true,
|
|
757
|
+
activeController: null
|
|
758
|
+
};
|
|
576
759
|
let streamClosed = false;
|
|
577
|
-
let activeController = null;
|
|
578
760
|
const settleResult = (next) => {
|
|
579
761
|
if (resultSettled) return;
|
|
580
762
|
resultSettled = true;
|
|
@@ -587,9 +769,9 @@ var AcpRuntimeManager = class {
|
|
|
587
769
|
queue.close();
|
|
588
770
|
};
|
|
589
771
|
const requestCancel = async () => {
|
|
590
|
-
if (activeController) return await activeController.requestCancelActivePrompt();
|
|
591
|
-
if (!turnActive) return false;
|
|
592
|
-
pendingCancel = true;
|
|
772
|
+
if (state.activeController) return await state.activeController.requestCancelActivePrompt();
|
|
773
|
+
if (!state.turnActive) return false;
|
|
774
|
+
state.pendingCancel = true;
|
|
593
775
|
return true;
|
|
594
776
|
};
|
|
595
777
|
const abortHandler = () => {
|
|
@@ -612,207 +794,15 @@ var AcpRuntimeManager = class {
|
|
|
612
794
|
}
|
|
613
795
|
input.signal.addEventListener("abort", abortHandler, { once: true });
|
|
614
796
|
}
|
|
615
|
-
(
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
const promptStartedAt = isoNow();
|
|
625
|
-
const promptMessageId = recordPromptSubmission(conversation, promptInput, promptStartedAt);
|
|
626
|
-
trimConversationForRuntime(conversation);
|
|
627
|
-
record.lastPromptAt = promptStartedAt;
|
|
628
|
-
record.lastUsedAt = promptStartedAt;
|
|
629
|
-
record.acpx = acpxState;
|
|
630
|
-
applyConversation(record, conversation);
|
|
631
|
-
await this.options.sessionStore.save(record);
|
|
632
|
-
const pendingClient = await this.readPendingPersistentClient(record, { consume: true });
|
|
633
|
-
client = pendingClient ?? this.createClient({
|
|
634
|
-
agentCommand: record.agentCommand,
|
|
635
|
-
cwd: record.cwd,
|
|
636
|
-
mcpServers: [...this.options.mcpServers ?? []],
|
|
637
|
-
permissionMode: this.options.permissionMode,
|
|
638
|
-
nonInteractivePermissions: this.options.nonInteractivePermissions,
|
|
639
|
-
verbose: this.options.verbose
|
|
640
|
-
});
|
|
641
|
-
const runtimeClient = client;
|
|
642
|
-
const runtimeConversation = conversation;
|
|
643
|
-
const runtimeRecord = record;
|
|
644
|
-
let activeSessionId = record.acpSessionId;
|
|
645
|
-
const applyPendingCancel = async () => {
|
|
646
|
-
if (!pendingCancel || !runtimeClient.hasActivePrompt()) return false;
|
|
647
|
-
const cancelled = await runtimeClient.requestCancelActivePrompt();
|
|
648
|
-
if (cancelled) pendingCancel = false;
|
|
649
|
-
return cancelled;
|
|
650
|
-
};
|
|
651
|
-
activeController = {
|
|
652
|
-
hasActivePrompt: () => runtimeClient.hasActivePrompt(),
|
|
653
|
-
requestCancelActivePrompt: async () => {
|
|
654
|
-
if (runtimeClient.hasActivePrompt()) return await runtimeClient.requestCancelActivePrompt();
|
|
655
|
-
if (!turnActive) return false;
|
|
656
|
-
pendingCancel = true;
|
|
657
|
-
return true;
|
|
658
|
-
},
|
|
659
|
-
setSessionMode: async (modeId) => {
|
|
660
|
-
if (!runtimeClient.hasActivePrompt()) await sessionReady.promise;
|
|
661
|
-
await runtimeClient.setSessionMode(activeSessionId, modeId);
|
|
662
|
-
const nextState = cloneSessionAcpxState(acpxState) ?? {};
|
|
663
|
-
nextState.desired_mode_id = modeId;
|
|
664
|
-
acpxState = nextState;
|
|
665
|
-
},
|
|
666
|
-
setSessionModel: async (modelId) => {
|
|
667
|
-
if (!runtimeClient.hasActivePrompt()) await sessionReady.promise;
|
|
668
|
-
await runtimeClient.setSessionModel(activeSessionId, modelId);
|
|
669
|
-
},
|
|
670
|
-
setSessionConfigOption: async (configId, value) => {
|
|
671
|
-
if (!runtimeClient.hasActivePrompt()) await sessionReady.promise;
|
|
672
|
-
const response = await runtimeClient.setSessionConfigOption(activeSessionId, configId, value);
|
|
673
|
-
if (response?.configOptions) {
|
|
674
|
-
const nextState = cloneSessionAcpxState(acpxState) ?? {};
|
|
675
|
-
nextState.config_options = structuredClone(response.configOptions);
|
|
676
|
-
acpxState = nextState;
|
|
677
|
-
}
|
|
678
|
-
if (configId === "mode") {
|
|
679
|
-
const nextState = cloneSessionAcpxState(acpxState) ?? {};
|
|
680
|
-
nextState.desired_mode_id = value;
|
|
681
|
-
acpxState = nextState;
|
|
682
|
-
} else if (configId !== "model") {
|
|
683
|
-
const nextState = cloneSessionAcpxState(acpxState) ?? {};
|
|
684
|
-
nextState.desired_config_options = {
|
|
685
|
-
...nextState.desired_config_options,
|
|
686
|
-
[configId]: value
|
|
687
|
-
};
|
|
688
|
-
acpxState = nextState;
|
|
689
|
-
}
|
|
690
|
-
return response;
|
|
691
|
-
}
|
|
692
|
-
};
|
|
693
|
-
const emitParsed = (payload) => {
|
|
694
|
-
if (streamClosed) return;
|
|
695
|
-
const parsed = parsePromptEventLine(JSON.stringify(payload));
|
|
696
|
-
if (!parsed) return;
|
|
697
|
-
queue.push(parsed);
|
|
698
|
-
};
|
|
699
|
-
this.activeControllers.set(runtimeRecord.acpxRecordId, activeController);
|
|
700
|
-
runtimeClient.setEventHandlers({
|
|
701
|
-
onSessionUpdate: (notification) => {
|
|
702
|
-
acpxState = recordSessionUpdate(runtimeConversation, acpxState, notification);
|
|
703
|
-
trimConversationForRuntime(runtimeConversation);
|
|
704
|
-
emitParsed({
|
|
705
|
-
jsonrpc: "2.0",
|
|
706
|
-
method: "session/update",
|
|
707
|
-
params: notification
|
|
708
|
-
});
|
|
709
|
-
},
|
|
710
|
-
onClientOperation: (operation) => {
|
|
711
|
-
acpxState = recordClientOperation(runtimeConversation, acpxState, operation);
|
|
712
|
-
trimConversationForRuntime(runtimeConversation);
|
|
713
|
-
emitParsed({
|
|
714
|
-
type: "client_operation",
|
|
715
|
-
...operation
|
|
716
|
-
});
|
|
717
|
-
}
|
|
718
|
-
});
|
|
719
|
-
const { sessionId, resumed, loadError } = pendingClient ? {
|
|
720
|
-
sessionId: record.acpSessionId,
|
|
721
|
-
resumed: false,
|
|
722
|
-
loadError: void 0
|
|
723
|
-
} : await connectAndLoadSession({
|
|
724
|
-
client: runtimeClient,
|
|
725
|
-
record: runtimeRecord,
|
|
726
|
-
resumePolicy: resumePolicyForSessionMode(input.sessionMode),
|
|
727
|
-
timeoutMs: this.options.timeoutMs,
|
|
728
|
-
activeController,
|
|
729
|
-
onClientAvailable: (controller) => {
|
|
730
|
-
activeController = controller;
|
|
731
|
-
this.activeControllers.set(runtimeRecord.acpxRecordId, controller);
|
|
732
|
-
},
|
|
733
|
-
onConnectedRecord: (connectedRecord) => {
|
|
734
|
-
connectedRecord.lastPromptAt = isoNow();
|
|
735
|
-
},
|
|
736
|
-
onSessionIdResolved: (sessionIdValue) => {
|
|
737
|
-
activeSessionId = sessionIdValue;
|
|
738
|
-
}
|
|
739
|
-
});
|
|
740
|
-
sessionReady.resolve();
|
|
741
|
-
runtimeRecord.lastRequestId = input.requestId;
|
|
742
|
-
runtimeRecord.lastPromptAt = isoNow();
|
|
743
|
-
runtimeRecord.closed = false;
|
|
744
|
-
runtimeRecord.closedAt = void 0;
|
|
745
|
-
runtimeRecord.lastUsedAt = isoNow();
|
|
746
|
-
if (resumed || loadError) emitParsed({
|
|
747
|
-
type: "status",
|
|
748
|
-
text: loadError ? `load fallback: ${loadError}` : "session resumed"
|
|
749
|
-
});
|
|
750
|
-
if (pendingCancel || input.signal?.aborted) {
|
|
751
|
-
pendingCancel = false;
|
|
752
|
-
settleResult({
|
|
753
|
-
status: "cancelled",
|
|
754
|
-
stopReason: "cancelled"
|
|
755
|
-
});
|
|
756
|
-
return;
|
|
757
|
-
}
|
|
758
|
-
await applyPendingCancel();
|
|
759
|
-
const response = await runPromptTurn({
|
|
760
|
-
client: runtimeClient,
|
|
761
|
-
sessionId,
|
|
762
|
-
prompt: promptInput,
|
|
763
|
-
timeoutMs: input.timeoutMs ?? this.options.timeoutMs,
|
|
764
|
-
conversation: runtimeConversation,
|
|
765
|
-
promptMessageId
|
|
766
|
-
});
|
|
767
|
-
runtimeRecord.acpSessionId = activeSessionId;
|
|
768
|
-
reconcileAgentSessionId(runtimeRecord, runtimeRecord.agentSessionId);
|
|
769
|
-
runtimeRecord.protocolVersion = runtimeClient.initializeResult?.protocolVersion;
|
|
770
|
-
runtimeRecord.agentCapabilities = runtimeClient.initializeResult?.agentCapabilities;
|
|
771
|
-
runtimeRecord.acpx = acpxState;
|
|
772
|
-
applyConversation(runtimeRecord, runtimeConversation);
|
|
773
|
-
applyLifecycleSnapshotToRecord(runtimeRecord, runtimeClient.getAgentLifecycleSnapshot());
|
|
774
|
-
await this.options.sessionStore.save(runtimeRecord);
|
|
775
|
-
settleResult({
|
|
776
|
-
status: response.stopReason === "cancelled" ? "cancelled" : "completed",
|
|
777
|
-
...response.stopReason ? { stopReason: response.stopReason } : {}
|
|
778
|
-
});
|
|
779
|
-
} catch (error) {
|
|
780
|
-
sessionReady.reject(error);
|
|
781
|
-
const normalized = normalizeOutputError(error, { origin: "runtime" });
|
|
782
|
-
settleResult({
|
|
783
|
-
status: "failed",
|
|
784
|
-
error: {
|
|
785
|
-
message: normalized.message,
|
|
786
|
-
...normalized.code ? { code: normalized.code } : {},
|
|
787
|
-
...normalized.detailCode ? { detailCode: normalized.detailCode } : {},
|
|
788
|
-
...normalized.retryable !== void 0 ? { retryable: normalized.retryable } : {}
|
|
789
|
-
}
|
|
790
|
-
});
|
|
791
|
-
} finally {
|
|
792
|
-
turnActive = false;
|
|
793
|
-
if (input.signal) input.signal.removeEventListener("abort", abortHandler);
|
|
794
|
-
client?.clearEventHandlers();
|
|
795
|
-
let pooled = false;
|
|
796
|
-
if (record && conversation) {
|
|
797
|
-
applyLifecycleSnapshotToRecord(record, client?.getAgentLifecycleSnapshot() ?? { running: false });
|
|
798
|
-
record.acpx = acpxState;
|
|
799
|
-
applyConversation(record, conversation);
|
|
800
|
-
record.lastUsedAt = isoNow();
|
|
801
|
-
const closed = await this.refreshClosedState(record);
|
|
802
|
-
await this.options.sessionStore.save(record).catch(() => {});
|
|
803
|
-
if (!closed && client) pooled = await this.retainPersistentClientAfterTurn({
|
|
804
|
-
record,
|
|
805
|
-
client
|
|
806
|
-
});
|
|
807
|
-
}
|
|
808
|
-
if (!pooled) await client?.close().catch(() => {});
|
|
809
|
-
if (record) {
|
|
810
|
-
this.activeControllers.delete(record.acpxRecordId);
|
|
811
|
-
this.closingActiveRecords.delete(record.acpxRecordId);
|
|
812
|
-
}
|
|
813
|
-
queue.close();
|
|
814
|
-
}
|
|
815
|
-
})();
|
|
797
|
+
this.runRuntimeTurnTask({
|
|
798
|
+
input,
|
|
799
|
+
promptInput,
|
|
800
|
+
queue,
|
|
801
|
+
sessionReady,
|
|
802
|
+
state,
|
|
803
|
+
settleResult,
|
|
804
|
+
abortHandler
|
|
805
|
+
});
|
|
816
806
|
return {
|
|
817
807
|
requestId: input.requestId,
|
|
818
808
|
events: queue.iterate(),
|
|
@@ -825,6 +815,284 @@ var AcpRuntimeManager = class {
|
|
|
825
815
|
}
|
|
826
816
|
};
|
|
827
817
|
}
|
|
818
|
+
async runRuntimeTurnTask(task) {
|
|
819
|
+
let turn;
|
|
820
|
+
try {
|
|
821
|
+
turn = await this.prepareRuntimeTurn(task);
|
|
822
|
+
const { sessionId, resumed, loadError } = await this.connectRuntimeTurn(task, turn);
|
|
823
|
+
await this.resolveRuntimeTurnReady(task, turn, resumed, loadError);
|
|
824
|
+
if (this.cancelRuntimeTurnBeforePrompt(task)) return;
|
|
825
|
+
await this.applyPendingRuntimeTurnCancel(task, turn);
|
|
826
|
+
const response = await runPromptTurn({
|
|
827
|
+
client: turn.client,
|
|
828
|
+
sessionId,
|
|
829
|
+
prompt: task.promptInput,
|
|
830
|
+
timeoutMs: task.input.timeoutMs ?? this.options.timeoutMs,
|
|
831
|
+
conversation: turn.conversation,
|
|
832
|
+
promptMessageId: turn.promptMessageId
|
|
833
|
+
});
|
|
834
|
+
await this.saveCompletedRuntimeTurn(turn, response.stopReason);
|
|
835
|
+
task.settleResult({
|
|
836
|
+
status: response.stopReason === "cancelled" ? "cancelled" : "completed",
|
|
837
|
+
...response.stopReason ? { stopReason: response.stopReason } : {}
|
|
838
|
+
});
|
|
839
|
+
} catch (error) {
|
|
840
|
+
this.failRuntimeTurn(task, error);
|
|
841
|
+
} finally {
|
|
842
|
+
await this.finalizeRuntimeTurn(task, turn);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
async prepareRuntimeTurn(task) {
|
|
846
|
+
const record = await this.requireRecord(task.input.handle.acpxRecordId ?? task.input.handle.sessionKey);
|
|
847
|
+
const conversation = cloneSessionConversation(record);
|
|
848
|
+
let acpxState = cloneSessionAcpxState(record.acpx);
|
|
849
|
+
const promptStartedAt = isoNow();
|
|
850
|
+
const promptMessageId = recordPromptSubmission(conversation, task.promptInput, promptStartedAt);
|
|
851
|
+
trimConversationForRuntime(conversation);
|
|
852
|
+
record.lastPromptAt = promptStartedAt;
|
|
853
|
+
record.lastUsedAt = promptStartedAt;
|
|
854
|
+
record.acpx = acpxState;
|
|
855
|
+
applyConversation(record, conversation);
|
|
856
|
+
await this.options.sessionStore.save(record);
|
|
857
|
+
const pendingClient = await this.readPendingPersistentClient(record, { consume: true });
|
|
858
|
+
const client = pendingClient ?? this.createTurnClient(record);
|
|
859
|
+
const turn = {
|
|
860
|
+
record,
|
|
861
|
+
conversation,
|
|
862
|
+
acpxState,
|
|
863
|
+
liveCheckpoint: this.createRuntimeTurnCheckpoint(record, conversation, () => turn.acpxState),
|
|
864
|
+
client,
|
|
865
|
+
pendingClient,
|
|
866
|
+
promptMessageId,
|
|
867
|
+
activeSessionId: record.acpSessionId
|
|
868
|
+
};
|
|
869
|
+
task.state.activeController = this.buildRuntimeTurnController(task, turn);
|
|
870
|
+
this.activeControllers.set(record.acpxRecordId, task.state.activeController);
|
|
871
|
+
this.installRuntimeTurnEventHandlers(task, turn);
|
|
872
|
+
return turn;
|
|
873
|
+
}
|
|
874
|
+
createTurnClient(record) {
|
|
875
|
+
return this.createClient({
|
|
876
|
+
agentCommand: record.agentCommand,
|
|
877
|
+
cwd: record.cwd,
|
|
878
|
+
mcpServers: [...this.options.mcpServers ?? []],
|
|
879
|
+
permissionMode: this.options.permissionMode,
|
|
880
|
+
nonInteractivePermissions: this.options.nonInteractivePermissions,
|
|
881
|
+
onPermissionRequest: this.options.onPermissionRequest,
|
|
882
|
+
verbose: this.options.verbose
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
createRuntimeTurnCheckpoint(record, conversation, readAcpxState) {
|
|
886
|
+
return new LiveSessionCheckpoint({ save: async () => {
|
|
887
|
+
record.lastUsedAt = isoNow();
|
|
888
|
+
record.acpx = readAcpxState();
|
|
889
|
+
applyConversation(record, conversation);
|
|
890
|
+
await this.refreshClosedState(record);
|
|
891
|
+
await this.options.sessionStore.save(record);
|
|
892
|
+
} });
|
|
893
|
+
}
|
|
894
|
+
buildRuntimeTurnController(task, turn) {
|
|
895
|
+
return {
|
|
896
|
+
hasActivePrompt: () => turn.client.hasActivePrompt(),
|
|
897
|
+
requestCancelActivePrompt: async () => await this.requestRuntimeTurnCancel(task, turn),
|
|
898
|
+
setSessionMode: async (modeId) => {
|
|
899
|
+
await this.waitForRuntimeControlSession(task, turn);
|
|
900
|
+
await turn.client.setSessionMode(turn.activeSessionId, modeId);
|
|
901
|
+
const nextState = cloneSessionAcpxState(turn.acpxState) ?? {};
|
|
902
|
+
nextState.desired_mode_id = modeId;
|
|
903
|
+
turn.acpxState = nextState;
|
|
904
|
+
},
|
|
905
|
+
setSessionModel: async (modelId) => {
|
|
906
|
+
await this.waitForRuntimeControlSession(task, turn);
|
|
907
|
+
await turn.client.setSessionModel(turn.activeSessionId, modelId);
|
|
908
|
+
},
|
|
909
|
+
setSessionConfigOption: async (configId, value) => {
|
|
910
|
+
return (await task.state.activeController.setResolvedSessionConfigOption(configId, value)).response;
|
|
911
|
+
},
|
|
912
|
+
setResolvedSessionConfigOption: async (configId, value) => await this.setRuntimeResolvedSessionConfigOption(task, turn, configId, value)
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
async waitForRuntimeControlSession(task, turn) {
|
|
916
|
+
if (turn.client.hasActivePrompt()) return;
|
|
917
|
+
await task.sessionReady.promise;
|
|
918
|
+
}
|
|
919
|
+
async requestRuntimeTurnCancel(task, turn) {
|
|
920
|
+
if (turn.client.hasActivePrompt()) return await turn.client.requestCancelActivePrompt();
|
|
921
|
+
if (!task.state.turnActive) return false;
|
|
922
|
+
task.state.pendingCancel = true;
|
|
923
|
+
return true;
|
|
924
|
+
}
|
|
925
|
+
async setRuntimeResolvedSessionConfigOption(task, turn, configId, value) {
|
|
926
|
+
await this.waitForRuntimeControlSession(task, turn);
|
|
927
|
+
const resolvedConfigId = resolveSupportedConfigOptionId({
|
|
928
|
+
...turn.record,
|
|
929
|
+
acpx: turn.acpxState ?? void 0
|
|
930
|
+
}, configId);
|
|
931
|
+
const response = await turn.client.setSessionConfigOption(turn.activeSessionId, resolvedConfigId, value);
|
|
932
|
+
this.applyRuntimeConfigOptionState(turn, resolvedConfigId, value, response);
|
|
933
|
+
return {
|
|
934
|
+
configId: resolvedConfigId,
|
|
935
|
+
response
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
applyRuntimeConfigOptionState(turn, configId, value, response) {
|
|
939
|
+
if (response?.configOptions) {
|
|
940
|
+
const nextState = cloneSessionAcpxState(turn.acpxState) ?? {};
|
|
941
|
+
nextState.config_options = structuredClone(response.configOptions);
|
|
942
|
+
turn.acpxState = nextState;
|
|
943
|
+
}
|
|
944
|
+
if (configId === "mode") {
|
|
945
|
+
const nextState = cloneSessionAcpxState(turn.acpxState) ?? {};
|
|
946
|
+
nextState.desired_mode_id = value;
|
|
947
|
+
turn.acpxState = nextState;
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
if (configId !== "model") {
|
|
951
|
+
const nextState = cloneSessionAcpxState(turn.acpxState) ?? {};
|
|
952
|
+
nextState.desired_config_options = {
|
|
953
|
+
...nextState.desired_config_options,
|
|
954
|
+
[configId]: value
|
|
955
|
+
};
|
|
956
|
+
turn.acpxState = nextState;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
installRuntimeTurnEventHandlers(task, turn) {
|
|
960
|
+
turn.client.setEventHandlers({
|
|
961
|
+
onSessionUpdate: (notification) => {
|
|
962
|
+
turn.acpxState = recordSessionUpdate(turn.conversation, turn.acpxState, notification);
|
|
963
|
+
trimConversationForRuntime(turn.conversation);
|
|
964
|
+
turn.liveCheckpoint.request();
|
|
965
|
+
this.emitRuntimeTurnEvent(task, {
|
|
966
|
+
jsonrpc: "2.0",
|
|
967
|
+
method: "session/update",
|
|
968
|
+
params: notification
|
|
969
|
+
});
|
|
970
|
+
},
|
|
971
|
+
onClientOperation: (operation) => {
|
|
972
|
+
turn.acpxState = recordClientOperation(turn.conversation, turn.acpxState, operation);
|
|
973
|
+
trimConversationForRuntime(turn.conversation);
|
|
974
|
+
turn.liveCheckpoint.request();
|
|
975
|
+
this.emitRuntimeTurnEvent(task, {
|
|
976
|
+
type: "client_operation",
|
|
977
|
+
...operation
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
emitRuntimeTurnEvent(task, payload) {
|
|
983
|
+
const parsed = parsePromptEventLine(JSON.stringify(payload));
|
|
984
|
+
if (!parsed) return;
|
|
985
|
+
task.queue.push(parsed);
|
|
986
|
+
}
|
|
987
|
+
async connectRuntimeTurn(task, turn) {
|
|
988
|
+
const loaded = turn.pendingClient ? {
|
|
989
|
+
sessionId: turn.record.acpSessionId,
|
|
990
|
+
resumed: false,
|
|
991
|
+
loadError: void 0
|
|
992
|
+
} : await this.connectRuntimeTurnClient(task, turn);
|
|
993
|
+
turn.acpxState = cloneSessionAcpxState(turn.record.acpx);
|
|
994
|
+
return loaded;
|
|
995
|
+
}
|
|
996
|
+
async connectRuntimeTurnClient(task, turn) {
|
|
997
|
+
return await connectAndLoadSession({
|
|
998
|
+
client: turn.client,
|
|
999
|
+
record: turn.record,
|
|
1000
|
+
resumePolicy: resumePolicyForSessionMode(task.input.sessionMode),
|
|
1001
|
+
timeoutMs: this.options.timeoutMs,
|
|
1002
|
+
activeController: task.state.activeController,
|
|
1003
|
+
onClientAvailable: () => this.publishRuntimeTurnController(task, turn),
|
|
1004
|
+
onConnectedRecord: (connectedRecord) => {
|
|
1005
|
+
connectedRecord.lastPromptAt = isoNow();
|
|
1006
|
+
},
|
|
1007
|
+
onSessionIdResolved: (sessionIdValue) => {
|
|
1008
|
+
turn.activeSessionId = sessionIdValue;
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
publishRuntimeTurnController(task, turn) {
|
|
1013
|
+
const controller = task.state.activeController;
|
|
1014
|
+
if (controller) this.activeControllers.set(turn.record.acpxRecordId, controller);
|
|
1015
|
+
}
|
|
1016
|
+
async resolveRuntimeTurnReady(task, turn, resumed, loadError) {
|
|
1017
|
+
task.sessionReady.resolve();
|
|
1018
|
+
turn.record.lastRequestId = task.input.requestId;
|
|
1019
|
+
turn.record.lastPromptAt = isoNow();
|
|
1020
|
+
turn.record.closed = false;
|
|
1021
|
+
turn.record.closedAt = void 0;
|
|
1022
|
+
turn.record.lastUsedAt = isoNow();
|
|
1023
|
+
await turn.liveCheckpoint.checkpoint();
|
|
1024
|
+
this.emitRuntimeTurnLoadStatus(task, resumed, loadError);
|
|
1025
|
+
}
|
|
1026
|
+
emitRuntimeTurnLoadStatus(task, resumed, loadError) {
|
|
1027
|
+
if (!resumed && !loadError) return;
|
|
1028
|
+
this.emitRuntimeTurnEvent(task, {
|
|
1029
|
+
type: "status",
|
|
1030
|
+
text: loadError ? `session reconnect fallback: ${loadError}` : "session resumed"
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
cancelRuntimeTurnBeforePrompt(task) {
|
|
1034
|
+
if (!task.state.pendingCancel && !task.input.signal?.aborted) return false;
|
|
1035
|
+
task.state.pendingCancel = false;
|
|
1036
|
+
task.settleResult({
|
|
1037
|
+
status: "cancelled",
|
|
1038
|
+
stopReason: "cancelled"
|
|
1039
|
+
});
|
|
1040
|
+
return true;
|
|
1041
|
+
}
|
|
1042
|
+
async applyPendingRuntimeTurnCancel(task, turn) {
|
|
1043
|
+
if (!task.state.pendingCancel || !turn.client.hasActivePrompt()) return false;
|
|
1044
|
+
const cancelled = await turn.client.requestCancelActivePrompt();
|
|
1045
|
+
if (cancelled) task.state.pendingCancel = false;
|
|
1046
|
+
return cancelled;
|
|
1047
|
+
}
|
|
1048
|
+
async saveCompletedRuntimeTurn(turn, _stopReason) {
|
|
1049
|
+
turn.record.acpSessionId = turn.activeSessionId;
|
|
1050
|
+
reconcileAgentSessionId(turn.record, turn.record.agentSessionId);
|
|
1051
|
+
turn.record.protocolVersion = turn.client.initializeResult?.protocolVersion;
|
|
1052
|
+
turn.record.agentCapabilities = turn.client.initializeResult?.agentCapabilities;
|
|
1053
|
+
turn.record.acpx = turn.acpxState;
|
|
1054
|
+
applyConversation(turn.record, turn.conversation);
|
|
1055
|
+
applyLifecycleSnapshotToRecord(turn.record, turn.client.getAgentLifecycleSnapshot());
|
|
1056
|
+
await this.options.sessionStore.save(turn.record);
|
|
1057
|
+
}
|
|
1058
|
+
failRuntimeTurn(task, error) {
|
|
1059
|
+
task.sessionReady.reject(error);
|
|
1060
|
+
const normalized = normalizeOutputError(error, { origin: "runtime" });
|
|
1061
|
+
task.settleResult({
|
|
1062
|
+
status: "failed",
|
|
1063
|
+
error: {
|
|
1064
|
+
message: normalized.message,
|
|
1065
|
+
...normalized.code ? { code: normalized.code } : {},
|
|
1066
|
+
...normalized.detailCode ? { detailCode: normalized.detailCode } : {},
|
|
1067
|
+
...normalized.retryable !== void 0 ? { retryable: normalized.retryable } : {}
|
|
1068
|
+
}
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
async finalizeRuntimeTurn(task, turn) {
|
|
1072
|
+
task.state.turnActive = false;
|
|
1073
|
+
task.input.signal?.removeEventListener("abort", task.abortHandler);
|
|
1074
|
+
turn?.client.clearEventHandlers();
|
|
1075
|
+
if (!(turn ? await this.finalizeRuntimeTurnRecord(turn) : false)) await turn?.client.close().catch(() => {});
|
|
1076
|
+
if (turn) {
|
|
1077
|
+
this.activeControllers.delete(turn.record.acpxRecordId);
|
|
1078
|
+
this.closingActiveRecords.delete(turn.record.acpxRecordId);
|
|
1079
|
+
}
|
|
1080
|
+
task.queue.close();
|
|
1081
|
+
}
|
|
1082
|
+
async finalizeRuntimeTurnRecord(turn) {
|
|
1083
|
+
applyLifecycleSnapshotToRecord(turn.record, turn.client.getAgentLifecycleSnapshot());
|
|
1084
|
+
turn.record.acpx = turn.acpxState;
|
|
1085
|
+
applyConversation(turn.record, turn.conversation);
|
|
1086
|
+
turn.record.lastUsedAt = isoNow();
|
|
1087
|
+
await turn.liveCheckpoint.flush().catch(() => {});
|
|
1088
|
+
const closed = await this.refreshClosedState(turn.record);
|
|
1089
|
+
await this.options.sessionStore.save(turn.record).catch(() => {});
|
|
1090
|
+
if (closed) return false;
|
|
1091
|
+
return await this.retainPersistentClientAfterTurn({
|
|
1092
|
+
record: turn.record,
|
|
1093
|
+
client: turn.client
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
828
1096
|
async *runTurn(input) {
|
|
829
1097
|
const turn = this.startTurn(input);
|
|
830
1098
|
yield* turn.events;
|
|
@@ -837,6 +1105,7 @@ var AcpRuntimeManager = class {
|
|
|
837
1105
|
acpxRecordId: record.acpxRecordId,
|
|
838
1106
|
backendSessionId: record.acpSessionId,
|
|
839
1107
|
agentSessionId: record.agentSessionId,
|
|
1108
|
+
...buildModelsField(record),
|
|
840
1109
|
details: {
|
|
841
1110
|
cwd: record.cwd,
|
|
842
1111
|
lastUsedAt: record.lastUsedAt,
|
|
@@ -859,18 +1128,21 @@ var AcpRuntimeManager = class {
|
|
|
859
1128
|
async setConfigOption(handle, key, value, sessionMode = "persistent") {
|
|
860
1129
|
const record = await this.requireRecord(handle.acpxRecordId ?? handle.sessionKey);
|
|
861
1130
|
const controller = this.activeControllers.get(record.acpxRecordId);
|
|
862
|
-
let targetRecord = record;
|
|
863
1131
|
if (controller) {
|
|
864
|
-
const response = await controller.
|
|
865
|
-
applyConfigOptionsToRecord(
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
1132
|
+
const { configId, response } = await controller.setResolvedSessionConfigOption(key, value);
|
|
1133
|
+
applyConfigOptionsToRecord(record, response);
|
|
1134
|
+
if (configId === "mode") setDesiredModeId(record, value);
|
|
1135
|
+
else setDesiredConfigOption(record, configId, value);
|
|
1136
|
+
await this.options.sessionStore.save(record);
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
const result = await this.withRuntimeControlSession(record, sessionMode, async ({ client, sessionId, record: connectedRecord }) => {
|
|
1140
|
+
const configId = resolveSupportedConfigOptionId(connectedRecord, key);
|
|
1141
|
+
applyConfigOptionsToRecord(connectedRecord, await client.setSessionConfigOption(sessionId, configId, value));
|
|
1142
|
+
if (configId === "mode") setDesiredModeId(connectedRecord, value);
|
|
1143
|
+
else setDesiredConfigOption(connectedRecord, configId, value);
|
|
1144
|
+
});
|
|
1145
|
+
await this.options.sessionStore.save(result.record);
|
|
874
1146
|
}
|
|
875
1147
|
async cancel(handle) {
|
|
876
1148
|
await this.activeControllers.get(handle.acpxRecordId ?? handle.sessionKey)?.requestCancelActivePrompt();
|
|
@@ -898,6 +1170,7 @@ var AcpRuntimeManager = class {
|
|
|
898
1170
|
mcpServers: [...this.options.mcpServers ?? []],
|
|
899
1171
|
permissionMode: this.options.permissionMode,
|
|
900
1172
|
nonInteractivePermissions: this.options.nonInteractivePermissions,
|
|
1173
|
+
onPermissionRequest: this.options.onPermissionRequest,
|
|
901
1174
|
verbose: this.options.verbose
|
|
902
1175
|
});
|
|
903
1176
|
try {
|
|
@@ -924,6 +1197,7 @@ function safeSessionId(sessionId) {
|
|
|
924
1197
|
return encodeURIComponent(sessionId);
|
|
925
1198
|
}
|
|
926
1199
|
var FileSessionStore = class {
|
|
1200
|
+
stateDir;
|
|
927
1201
|
constructor(stateDir) {
|
|
928
1202
|
this.stateDir = stateDir;
|
|
929
1203
|
}
|
|
@@ -999,21 +1273,30 @@ function writeHandleState(handle, state) {
|
|
|
999
1273
|
}
|
|
1000
1274
|
//#endregion
|
|
1001
1275
|
//#region src/runtime/public/probe.ts
|
|
1276
|
+
function isPrimitiveDetail(value) {
|
|
1277
|
+
return value == null || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "symbol";
|
|
1278
|
+
}
|
|
1279
|
+
function formatFunctionDetail(value) {
|
|
1280
|
+
return value.name ? `[Function ${value.name}]` : "[Function]";
|
|
1281
|
+
}
|
|
1282
|
+
function serializeRuntimeDetail(value) {
|
|
1283
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
1284
|
+
return JSON.stringify(value, (_key, nested) => {
|
|
1285
|
+
if (nested instanceof Error) return nested.message || nested.name;
|
|
1286
|
+
if (nested && typeof nested === "object") {
|
|
1287
|
+
if (seen.has(nested)) return "[Circular]";
|
|
1288
|
+
seen.add(nested);
|
|
1289
|
+
}
|
|
1290
|
+
return nested;
|
|
1291
|
+
}) ?? "undefined";
|
|
1292
|
+
}
|
|
1002
1293
|
function formatRuntimeDetail(value) {
|
|
1003
1294
|
if (value instanceof Error) return value.message || value.name;
|
|
1004
1295
|
if (typeof value === "string") return value;
|
|
1005
|
-
if (value
|
|
1006
|
-
if (typeof value === "function") return value
|
|
1007
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
1296
|
+
if (isPrimitiveDetail(value)) return String(value);
|
|
1297
|
+
if (typeof value === "function") return formatFunctionDetail(value);
|
|
1008
1298
|
try {
|
|
1009
|
-
return
|
|
1010
|
-
if (nested instanceof Error) return nested.message || nested.name;
|
|
1011
|
-
if (nested && typeof nested === "object") {
|
|
1012
|
-
if (seen.has(nested)) return "[Circular]";
|
|
1013
|
-
seen.add(nested);
|
|
1014
|
-
}
|
|
1015
|
-
return nested;
|
|
1016
|
-
}) ?? "undefined";
|
|
1299
|
+
return serializeRuntimeDetail(value);
|
|
1017
1300
|
} catch {
|
|
1018
1301
|
return "unserializable object";
|
|
1019
1302
|
}
|
|
@@ -1024,21 +1307,7 @@ function normalizeRuntimeDetails(details) {
|
|
|
1024
1307
|
async function probeRuntime(options, deps = {}) {
|
|
1025
1308
|
const agentName = options.probeAgent?.trim() || "codex";
|
|
1026
1309
|
const agentCommand = options.agentRegistry.resolve(agentName);
|
|
1027
|
-
const client = deps
|
|
1028
|
-
agentCommand,
|
|
1029
|
-
cwd: options.cwd,
|
|
1030
|
-
mcpServers: [...options.mcpServers ?? []],
|
|
1031
|
-
permissionMode: options.permissionMode,
|
|
1032
|
-
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
1033
|
-
verbose: options.verbose
|
|
1034
|
-
}) ?? new AcpClient({
|
|
1035
|
-
agentCommand,
|
|
1036
|
-
cwd: options.cwd,
|
|
1037
|
-
mcpServers: [...options.mcpServers ?? []],
|
|
1038
|
-
permissionMode: options.permissionMode,
|
|
1039
|
-
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
1040
|
-
verbose: options.verbose
|
|
1041
|
-
});
|
|
1310
|
+
const client = createProbeClient(options, agentCommand, deps);
|
|
1042
1311
|
try {
|
|
1043
1312
|
await client.start();
|
|
1044
1313
|
return {
|
|
@@ -1066,6 +1335,17 @@ async function probeRuntime(options, deps = {}) {
|
|
|
1066
1335
|
await client.close().catch(() => {});
|
|
1067
1336
|
}
|
|
1068
1337
|
}
|
|
1338
|
+
function createProbeClient(options, agentCommand, deps) {
|
|
1339
|
+
const clientOptions = {
|
|
1340
|
+
agentCommand,
|
|
1341
|
+
cwd: options.cwd,
|
|
1342
|
+
mcpServers: [...options.mcpServers ?? []],
|
|
1343
|
+
permissionMode: options.permissionMode,
|
|
1344
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
1345
|
+
verbose: options.verbose
|
|
1346
|
+
};
|
|
1347
|
+
return deps.clientFactory?.(clientOptions) ?? new AcpClient(clientOptions);
|
|
1348
|
+
}
|
|
1069
1349
|
//#endregion
|
|
1070
1350
|
//#region src/runtime.ts
|
|
1071
1351
|
const ACPX_BACKEND_ID = "acpx";
|
|
@@ -1085,6 +1365,8 @@ function createAgentRegistry(params) {
|
|
|
1085
1365
|
};
|
|
1086
1366
|
}
|
|
1087
1367
|
var AcpxRuntime = class {
|
|
1368
|
+
options;
|
|
1369
|
+
testOptions;
|
|
1088
1370
|
healthy = false;
|
|
1089
1371
|
manager = null;
|
|
1090
1372
|
managerPromise = null;
|
|
@@ -1119,7 +1401,8 @@ var AcpxRuntime = class {
|
|
|
1119
1401
|
agent,
|
|
1120
1402
|
mode: input.mode,
|
|
1121
1403
|
cwd: input.cwd ?? this.options.cwd,
|
|
1122
|
-
resumeSessionId: input.resumeSessionId
|
|
1404
|
+
resumeSessionId: input.resumeSessionId,
|
|
1405
|
+
sessionOptions: input.sessionOptions
|
|
1123
1406
|
});
|
|
1124
1407
|
const handle = {
|
|
1125
1408
|
sessionKey: input.sessionKey,
|