@wrongstack/acp 1.1.1 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/stdio-transport.d.ts +2 -0
- package/dist/client/acp-request-state.d.ts +4 -0
- package/dist/client/acp-session-ops.d.ts +19 -0
- package/dist/client/acp-session-prompt.d.ts +2 -2
- package/dist/client/acp-session-types.d.ts +67 -1
- package/dist/client/acp-session-updates.d.ts +9 -0
- package/dist/client/acp-session.d.ts +21 -1
- package/dist/client.js +343 -41
- package/dist/index.d.ts +3 -1
- package/dist/index.js +347 -42
- package/dist/integration/acp-agent-failure.d.ts +20 -0
- package/dist/integration/acp-subagent-runner-options.d.ts +88 -0
- package/dist/integration/acp-subagent-runner.d.ts +4 -63
- package/dist/integration/run-one-acp-task.d.ts +3 -0
- package/dist/registry/contracts.d.ts +6 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1015,6 +1015,19 @@ import {
|
|
|
1015
1015
|
var DEFAULT_MAX_FRAME_CHARS = 20 * 1024 * 1024;
|
|
1016
1016
|
var DEFAULT_MAX_QUEUED_MESSAGES = 1e3;
|
|
1017
1017
|
var DEFAULT_MAX_QUEUED_CHARS = 32 * 1024 * 1024;
|
|
1018
|
+
var STDERR_TAIL_CHARS = 4096;
|
|
1019
|
+
function echoChildStderr() {
|
|
1020
|
+
const v = process.env.WRONGSTACK_DEBUG;
|
|
1021
|
+
return !!v && v !== "0" && v !== "false";
|
|
1022
|
+
}
|
|
1023
|
+
function lastLine(text) {
|
|
1024
|
+
const lines = text.split(/\r?\n/);
|
|
1025
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
1026
|
+
const line = lines[i]?.trim();
|
|
1027
|
+
if (line) return line.length > 300 ? `${line.slice(0, 300)}\u2026` : line;
|
|
1028
|
+
}
|
|
1029
|
+
return "";
|
|
1030
|
+
}
|
|
1018
1031
|
function takeLines(pending, chunk) {
|
|
1019
1032
|
const lines = [];
|
|
1020
1033
|
let start = 0;
|
|
@@ -1196,6 +1209,8 @@ var StdioTransport = class {
|
|
|
1196
1209
|
var ClientTransport = class {
|
|
1197
1210
|
child = null;
|
|
1198
1211
|
buffer = "";
|
|
1212
|
+
stderrTail = "";
|
|
1213
|
+
stopRequested = false;
|
|
1199
1214
|
handlers = /* @__PURE__ */ new Set();
|
|
1200
1215
|
claimHandlers = /* @__PURE__ */ new Set();
|
|
1201
1216
|
closeHandlers = /* @__PURE__ */ new Set();
|
|
@@ -1296,9 +1311,11 @@ var ClientTransport = class {
|
|
|
1296
1311
|
}
|
|
1297
1312
|
const idx = this.buffer.indexOf("[wstack-acp]\n");
|
|
1298
1313
|
if (idx !== -1) {
|
|
1299
|
-
|
|
1314
|
+
const rest = this.buffer.slice(idx + "[wstack-acp]\n".length);
|
|
1315
|
+
this.buffer = "";
|
|
1300
1316
|
child.stdout.removeListener("data", waitForMarker);
|
|
1301
1317
|
onReady();
|
|
1318
|
+
if (rest) this.onChildData(rest);
|
|
1302
1319
|
}
|
|
1303
1320
|
};
|
|
1304
1321
|
child.stdout.on("data", waitForMarker);
|
|
@@ -1361,6 +1378,7 @@ var ClientTransport = class {
|
|
|
1361
1378
|
}
|
|
1362
1379
|
stop(reason = "transport stopped") {
|
|
1363
1380
|
this.closed = true;
|
|
1381
|
+
this.stopRequested = true;
|
|
1364
1382
|
this.resolveRead?.(null);
|
|
1365
1383
|
this.resolveRead = null;
|
|
1366
1384
|
this.buffer = "";
|
|
@@ -1398,7 +1416,8 @@ var ClientTransport = class {
|
|
|
1398
1416
|
}
|
|
1399
1417
|
}
|
|
1400
1418
|
onChildError(chunk) {
|
|
1401
|
-
|
|
1419
|
+
this.stderrTail = (this.stderrTail + chunk).slice(-STDERR_TAIL_CHARS);
|
|
1420
|
+
if (echoChildStderr()) writeErr(`[acp-child stderr] ${chunk}`);
|
|
1402
1421
|
}
|
|
1403
1422
|
onChildClose(code) {
|
|
1404
1423
|
this.closed = true;
|
|
@@ -1410,11 +1429,16 @@ var ClientTransport = class {
|
|
|
1410
1429
|
this.queuedChars = 0;
|
|
1411
1430
|
this.handlers.clear();
|
|
1412
1431
|
this.claimHandlers.clear();
|
|
1413
|
-
|
|
1432
|
+
const failed = code !== 0 && code !== null && !this.stopRequested;
|
|
1433
|
+
if (failed) {
|
|
1434
|
+
const tail = echoChildStderr() ? "" : this.stderrTail.trimEnd();
|
|
1414
1435
|
writeErr(`[acp-child exited with code ${code}]
|
|
1415
|
-
|
|
1436
|
+
${tail ? `${tail}
|
|
1437
|
+
` : ""}`);
|
|
1416
1438
|
}
|
|
1417
|
-
|
|
1439
|
+
const cause = failed ? lastLine(this.stderrTail) : "";
|
|
1440
|
+
this.stderrTail = "";
|
|
1441
|
+
this.notifyClosed(`agent process exited with code ${code}${cause ? `: ${cause}` : ""}`);
|
|
1418
1442
|
}
|
|
1419
1443
|
dispatch(msg, chars = JSON.stringify(msg).length) {
|
|
1420
1444
|
if (this.resolveRead) {
|
|
@@ -1939,6 +1963,9 @@ function isAuthRequiredError(err) {
|
|
|
1939
1963
|
}
|
|
1940
1964
|
|
|
1941
1965
|
// src/client/acp-request-state.ts
|
|
1966
|
+
function touchIdleRequests(pending) {
|
|
1967
|
+
for (const p of pending.values()) p.rearm?.();
|
|
1968
|
+
}
|
|
1942
1969
|
function rejectPendingRequests(pending, reason) {
|
|
1943
1970
|
for (const p of pending.values()) {
|
|
1944
1971
|
clearTimeout(p.timeoutHandle);
|
|
@@ -2135,11 +2162,21 @@ async function executeMcpMessage(ctx, connectionId, message) {
|
|
|
2135
2162
|
}
|
|
2136
2163
|
async function executeCreateSession(ctx) {
|
|
2137
2164
|
const servers = filterMcpServers(ctx.agentCapabilities, ctx.opts.mcpServers);
|
|
2138
|
-
const
|
|
2139
|
-
const result = await ctx.sendRequest(id, "session/new", {
|
|
2165
|
+
const params = {
|
|
2140
2166
|
cwd: ctx.opts.cwd ?? ctx.opts.projectRoot,
|
|
2141
|
-
mcpServers: servers
|
|
2142
|
-
|
|
2167
|
+
mcpServers: servers,
|
|
2168
|
+
...ctx.opts.sessionMeta ? { _meta: ctx.opts.sessionMeta } : {}
|
|
2169
|
+
};
|
|
2170
|
+
const resumeId = ctx.opts.resumeSessionId;
|
|
2171
|
+
if (resumeId && ctx.agentCapabilities.sessionCapabilities?.resume) {
|
|
2172
|
+
const resumed = await ctx.sendRequest(ctx.allocId(), "session/resume", { ...params, sessionId: resumeId }).catch((err) => ({ refused: err }));
|
|
2173
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
2174
|
+
if (!isJsonRpcError(resumed) && !resumed.refused) {
|
|
2175
|
+
return adoptSessionMode(ctx, resumeId, resumed);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
const id = ctx.allocId();
|
|
2179
|
+
const result = await ctx.sendRequest(id, "session/new", params);
|
|
2143
2180
|
if (isJsonRpcError(result)) {
|
|
2144
2181
|
throw new ACPSessionError(
|
|
2145
2182
|
"session_create_failed",
|
|
@@ -2151,8 +2188,53 @@ async function executeCreateSession(ctx) {
|
|
|
2151
2188
|
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
2152
2189
|
throw new ACPSessionError("protocol_error", "session/new returned no sessionId", result);
|
|
2153
2190
|
}
|
|
2191
|
+
return adoptSessionMode(ctx, sessionId, result);
|
|
2192
|
+
}
|
|
2193
|
+
async function executeOpenSession(ctx, create) {
|
|
2194
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
2195
|
+
if (ctx.sessionId) return { sessionId: ctx.sessionId, resumed: false };
|
|
2196
|
+
const sessionId = await create();
|
|
2197
|
+
ctx.setSessionId(sessionId);
|
|
2198
|
+
return { sessionId, resumed: sessionId === ctx.opts.resumeSessionId };
|
|
2199
|
+
}
|
|
2200
|
+
async function adoptSessionMode(ctx, sessionId, result) {
|
|
2201
|
+
const want = ctx.opts.initialModeId;
|
|
2202
|
+
const modes = result.modes;
|
|
2203
|
+
const offered = Array.isArray(modes?.availableModes) && modes.availableModes.some((m) => m?.id === want);
|
|
2204
|
+
if (want && !offered && ctx.opts.requireInitialMode) {
|
|
2205
|
+
throw new ACPSessionError(
|
|
2206
|
+
"session_create_failed",
|
|
2207
|
+
`the agent does not offer the "${want}" session mode this host requires`,
|
|
2208
|
+
result
|
|
2209
|
+
);
|
|
2210
|
+
}
|
|
2211
|
+
if (want && offered && modes?.currentModeId !== want) {
|
|
2212
|
+
await executeSetMode(ctx, sessionId, want);
|
|
2213
|
+
}
|
|
2154
2214
|
return sessionId;
|
|
2155
2215
|
}
|
|
2216
|
+
async function executeSteer(ctx, supported, text) {
|
|
2217
|
+
if (ctx.closed || !ctx.sessionId || !supported) return "unsupported";
|
|
2218
|
+
const result = await ctx.sendRequest(
|
|
2219
|
+
ctx.allocId(),
|
|
2220
|
+
"_session/steering",
|
|
2221
|
+
{
|
|
2222
|
+
sessionId: ctx.sessionId,
|
|
2223
|
+
prompt: [{ type: "text", text }],
|
|
2224
|
+
_meta: { steering: { idleBehavior: "promptRequired" } }
|
|
2225
|
+
},
|
|
2226
|
+
1e4
|
|
2227
|
+
);
|
|
2228
|
+
if (isJsonRpcError(result)) {
|
|
2229
|
+
throw new ACPSessionError(
|
|
2230
|
+
"prompt_failed",
|
|
2231
|
+
`_session/steering failed: ${result.message}`,
|
|
2232
|
+
result
|
|
2233
|
+
);
|
|
2234
|
+
}
|
|
2235
|
+
const outcome = result?.outcome;
|
|
2236
|
+
return outcome === "injected" || outcome === "promptRequired" || outcome === "startedNewTurn" ? outcome : "unsupported";
|
|
2237
|
+
}
|
|
2156
2238
|
|
|
2157
2239
|
// src/client/acp-session-auth.ts
|
|
2158
2240
|
function ensureOpen(host) {
|
|
@@ -2517,6 +2599,10 @@ async function handleAcpFsRequest(msg, fileServer, permissionPolicy, sender, cal
|
|
|
2517
2599
|
return;
|
|
2518
2600
|
}
|
|
2519
2601
|
if (msg.method === "fs/write_text_file") {
|
|
2602
|
+
if (typeof params.content !== "string") {
|
|
2603
|
+
await sender.sendErrorResponse(id, -32602, "content must be a string");
|
|
2604
|
+
return;
|
|
2605
|
+
}
|
|
2520
2606
|
const authorization = await authorizeAcpCallback(
|
|
2521
2607
|
permissionPolicy,
|
|
2522
2608
|
{
|
|
@@ -2550,7 +2636,7 @@ async function handleAcpFsRequest(msg, fileServer, permissionPolicy, sender, cal
|
|
|
2550
2636
|
await fileServer.writeTextFile({
|
|
2551
2637
|
sessionId: params.sessionId ?? "",
|
|
2552
2638
|
path: params.path,
|
|
2553
|
-
content: params.content
|
|
2639
|
+
content: params.content
|
|
2554
2640
|
});
|
|
2555
2641
|
await sender.sendResult(id, {});
|
|
2556
2642
|
}
|
|
@@ -2567,17 +2653,22 @@ async function handleAcpTerminalRequest(msg, terminalServer, permissionPolicy, s
|
|
|
2567
2653
|
try {
|
|
2568
2654
|
switch (msg.method) {
|
|
2569
2655
|
case "terminal/create": {
|
|
2656
|
+
const env = Array.isArray(params.env) ? params.env.filter(
|
|
2657
|
+
(entry) => !!entry && typeof entry.name === "string" && typeof entry.value === "string"
|
|
2658
|
+
) : [];
|
|
2659
|
+
const envSuffix = env.length > 0 ? ` (env: ${env.map((e) => `${e.name}=${e.value}`).join(" ")})` : "";
|
|
2570
2660
|
const authorization = await authorizeAcpCallback(
|
|
2571
2661
|
permissionPolicy,
|
|
2572
2662
|
{
|
|
2573
2663
|
toolCallId: `acp-terminal-create-${id}`,
|
|
2574
|
-
title: `Run command: ${String(params.command ?? "")} ${(Array.isArray(params.args) ? params.args : []).join(" ")}`.trim(),
|
|
2664
|
+
title: `Run command: ${String(params.command ?? "")} ${(Array.isArray(params.args) ? params.args : []).join(" ")}`.trim() + envSuffix,
|
|
2575
2665
|
kind: "execute",
|
|
2576
2666
|
rawInput: {
|
|
2577
2667
|
command: params.command,
|
|
2578
2668
|
args: params.args,
|
|
2579
2669
|
cwd: params.cwd,
|
|
2580
|
-
sessionId: params.sessionId
|
|
2670
|
+
sessionId: params.sessionId,
|
|
2671
|
+
...env.length > 0 ? { env } : {}
|
|
2581
2672
|
}
|
|
2582
2673
|
},
|
|
2583
2674
|
callbackOptions2
|
|
@@ -2596,9 +2687,7 @@ async function handleAcpTerminalRequest(msg, terminalServer, permissionPolicy, s
|
|
|
2596
2687
|
command: String(params.command ?? ""),
|
|
2597
2688
|
args: Array.isArray(params.args) ? params.args : []
|
|
2598
2689
|
};
|
|
2599
|
-
if (
|
|
2600
|
-
createOpts.env = params.env;
|
|
2601
|
-
}
|
|
2690
|
+
if (env.length > 0) createOpts.env = env;
|
|
2602
2691
|
if (typeof params.cwd === "string") {
|
|
2603
2692
|
createOpts.cwd = params.cwd;
|
|
2604
2693
|
}
|
|
@@ -2752,6 +2841,7 @@ function emptyRunResult(stopReason) {
|
|
|
2752
2841
|
function createSessionScratch() {
|
|
2753
2842
|
return { text: "", thoughts: "", toolCalls: /* @__PURE__ */ new Map(), diffs: [] };
|
|
2754
2843
|
}
|
|
2844
|
+
var MESSAGE_SEPARATOR = "\n\n";
|
|
2755
2845
|
function handleAcpSessionUpdate(msg, scratch, emitProgress2) {
|
|
2756
2846
|
const update = msg.params?.update;
|
|
2757
2847
|
if (typeof update !== "object" || update === null) return;
|
|
@@ -2761,6 +2851,10 @@ function handleAcpSessionUpdate(msg, scratch, emitProgress2) {
|
|
|
2761
2851
|
case "agent_message_chunk": {
|
|
2762
2852
|
const text = extractText(u.content);
|
|
2763
2853
|
if (text) {
|
|
2854
|
+
if (scratch.messageBreak && scratch.text && !/\s$/.test(scratch.text)) {
|
|
2855
|
+
scratch.text += MESSAGE_SEPARATOR;
|
|
2856
|
+
}
|
|
2857
|
+
scratch.messageBreak = false;
|
|
2764
2858
|
scratch.text += text;
|
|
2765
2859
|
emitProgress2({ type: "message", text });
|
|
2766
2860
|
}
|
|
@@ -2785,7 +2879,9 @@ function handleAcpSessionUpdate(msg, scratch, emitProgress2) {
|
|
|
2785
2879
|
emitProgress2({ type: "plan", entries: u.entries });
|
|
2786
2880
|
}
|
|
2787
2881
|
return;
|
|
2788
|
-
case "usage_update":
|
|
2882
|
+
case "usage_update": {
|
|
2883
|
+
const rateLimit = u._meta?.["_claude/rateLimit"];
|
|
2884
|
+
if (isRecord(rateLimit)) emitProgress2({ type: "rate_limit", info: rateLimit });
|
|
2789
2885
|
if (typeof u.used === "number" && Number.isFinite(u.used) && u.used >= 0 && typeof u.size === "number" && Number.isFinite(u.size) && u.size >= 0) {
|
|
2790
2886
|
const usage = {
|
|
2791
2887
|
used: u.used,
|
|
@@ -2796,6 +2892,7 @@ function handleAcpSessionUpdate(msg, scratch, emitProgress2) {
|
|
|
2796
2892
|
emitProgress2({ type: "usage", usage });
|
|
2797
2893
|
}
|
|
2798
2894
|
return;
|
|
2895
|
+
}
|
|
2799
2896
|
case "available_commands_update":
|
|
2800
2897
|
case "current_mode_update":
|
|
2801
2898
|
case "config_option_update":
|
|
@@ -2808,6 +2905,20 @@ function handleAcpSessionUpdate(msg, scratch, emitProgress2) {
|
|
|
2808
2905
|
return;
|
|
2809
2906
|
}
|
|
2810
2907
|
}
|
|
2908
|
+
function toolOutputText(u) {
|
|
2909
|
+
const joined = (blocks) => blocks.map(extractText).filter((text) => text.length > 0).join("\n");
|
|
2910
|
+
if (Array.isArray(u.content)) {
|
|
2911
|
+
const text = joined(
|
|
2912
|
+
u.content.map(
|
|
2913
|
+
(c) => c && typeof c === "object" && c.type === "content" ? c.content : void 0
|
|
2914
|
+
)
|
|
2915
|
+
);
|
|
2916
|
+
if (text) return text;
|
|
2917
|
+
}
|
|
2918
|
+
if (typeof u.rawOutput === "string") return u.rawOutput || void 0;
|
|
2919
|
+
if (Array.isArray(u.rawOutput)) return joined(u.rawOutput) || void 0;
|
|
2920
|
+
return void 0;
|
|
2921
|
+
}
|
|
2811
2922
|
function captureToolCall(u, isNew, scratch, emitProgress2) {
|
|
2812
2923
|
const toolCallId = typeof u.toolCallId === "string" ? u.toolCallId : "";
|
|
2813
2924
|
if (!toolCallId) return;
|
|
@@ -2818,12 +2929,18 @@ function captureToolCall(u, isNew, scratch, emitProgress2) {
|
|
|
2818
2929
|
kind: typeof u.kind === "string" ? u.kind : prev?.kind,
|
|
2819
2930
|
status: typeof u.status === "string" ? u.status : prev?.status ?? (isNew ? "pending" : "in_progress"),
|
|
2820
2931
|
rawInput: isRecord(u.rawInput) ? u.rawInput : prev?.rawInput,
|
|
2821
|
-
rawOutput: isRecord(u.rawOutput) ? u.rawOutput : prev?.rawOutput
|
|
2932
|
+
rawOutput: isRecord(u.rawOutput) ? u.rawOutput : prev?.rawOutput,
|
|
2933
|
+
output: toolOutputText(u) ?? prev?.output
|
|
2822
2934
|
};
|
|
2823
2935
|
scratch.toolCalls.set(toolCallId, record);
|
|
2936
|
+
if (scratch.text) scratch.messageBreak = true;
|
|
2824
2937
|
if (Array.isArray(u.content)) {
|
|
2825
2938
|
for (const c of u.content) {
|
|
2826
2939
|
if (c && typeof c === "object" && c.type === "diff") {
|
|
2940
|
+
const key = `${toolCallId}\0${c.path}\0${c.oldText ?? ""}\0${c.newText}`;
|
|
2941
|
+
scratch.seenDiffs ??= /* @__PURE__ */ new Set();
|
|
2942
|
+
if (scratch.seenDiffs.has(key)) continue;
|
|
2943
|
+
scratch.seenDiffs.add(key);
|
|
2827
2944
|
const diff = {
|
|
2828
2945
|
path: c.path,
|
|
2829
2946
|
oldText: c.oldText,
|
|
@@ -2834,10 +2951,15 @@ function captureToolCall(u, isNew, scratch, emitProgress2) {
|
|
|
2834
2951
|
}
|
|
2835
2952
|
}
|
|
2836
2953
|
}
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2954
|
+
scratch.announced ??= /* @__PURE__ */ new Set();
|
|
2955
|
+
if (!scratch.announced.has(toolCallId)) {
|
|
2956
|
+
const hasInput = record.rawInput !== void 0 && Object.keys(record.rawInput).length > 0;
|
|
2957
|
+
if (isNew && !hasInput) return;
|
|
2958
|
+
scratch.announced.add(toolCallId);
|
|
2959
|
+
emitProgress2({ type: "tool_call", toolCall: record });
|
|
2960
|
+
if (isNew || record.status !== "completed" && record.status !== "failed") return;
|
|
2961
|
+
}
|
|
2962
|
+
emitProgress2({ type: "tool_call_update", toolCall: record });
|
|
2841
2963
|
}
|
|
2842
2964
|
|
|
2843
2965
|
// src/client/acp-session-messages.ts
|
|
@@ -2869,6 +2991,7 @@ function handleMessage(msg) {
|
|
|
2869
2991
|
}
|
|
2870
2992
|
return;
|
|
2871
2993
|
}
|
|
2994
|
+
touchIdleRequests(this.pending);
|
|
2872
2995
|
if (msg.method === "session/update") {
|
|
2873
2996
|
const updateSessionId = msg.params?.sessionId;
|
|
2874
2997
|
if (typeof updateSessionId === "string" && updateSessionId !== this.sessionId) return;
|
|
@@ -2925,6 +3048,7 @@ function handleMessage(msg) {
|
|
|
2925
3048
|
);
|
|
2926
3049
|
return;
|
|
2927
3050
|
}
|
|
3051
|
+
if (msg.method.startsWith("_")) return;
|
|
2928
3052
|
console.warn(
|
|
2929
3053
|
JSON.stringify({
|
|
2930
3054
|
level: "warn",
|
|
@@ -3034,7 +3158,9 @@ async function prompt(host, blocks, signal, onProgress) {
|
|
|
3034
3158
|
sessionId: host.sessionId,
|
|
3035
3159
|
prompt: blocks
|
|
3036
3160
|
},
|
|
3037
|
-
|
|
3161
|
+
// Timed by silence, not length: a working agent keeps it alive.
|
|
3162
|
+
host.promptIdleTimeoutMs,
|
|
3163
|
+
true
|
|
3038
3164
|
),
|
|
3039
3165
|
new Promise((_, reject) => {
|
|
3040
3166
|
rejectTurn = reject;
|
|
@@ -3050,6 +3176,17 @@ async function prompt(host, blocks, signal, onProgress) {
|
|
|
3050
3176
|
if (cancelled || abortedKind) {
|
|
3051
3177
|
return emptyRunResult("cancelled");
|
|
3052
3178
|
}
|
|
3179
|
+
if (err instanceof ACPSessionError && err.kind === "stalled") {
|
|
3180
|
+
if (host.sessionId) {
|
|
3181
|
+
host.transport.send({
|
|
3182
|
+
jsonrpc: "2.0",
|
|
3183
|
+
method: "session/cancel",
|
|
3184
|
+
params: { sessionId: host.sessionId }
|
|
3185
|
+
}).catch(() => {
|
|
3186
|
+
});
|
|
3187
|
+
}
|
|
3188
|
+
throw err;
|
|
3189
|
+
}
|
|
3053
3190
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3054
3191
|
if (signal.aborted) {
|
|
3055
3192
|
throw new ACPSessionError("aborted", "prompt was aborted by the parent", err);
|
|
@@ -3071,17 +3208,31 @@ async function prompt(host, blocks, signal, onProgress) {
|
|
|
3071
3208
|
}
|
|
3072
3209
|
const stopReason = response.stopReason ?? "end_turn";
|
|
3073
3210
|
const finalText = host.scratch.text;
|
|
3211
|
+
const tokens = readTokenUsage(response.usage);
|
|
3074
3212
|
return {
|
|
3075
3213
|
text: finalText,
|
|
3076
3214
|
stopReason,
|
|
3077
3215
|
hasText: finalText.length > 0,
|
|
3078
3216
|
usage: host.scratch.usage,
|
|
3217
|
+
...tokens ? { tokens } : {},
|
|
3079
3218
|
plan: host.scratch.plan,
|
|
3080
3219
|
toolCalls: [...host.scratch.toolCalls.values()],
|
|
3081
3220
|
diffs: host.scratch.diffs,
|
|
3082
3221
|
thoughts: host.scratch.thoughts
|
|
3083
3222
|
};
|
|
3084
3223
|
}
|
|
3224
|
+
function readTokenUsage(raw) {
|
|
3225
|
+
if (typeof raw !== "object" || raw === null) return void 0;
|
|
3226
|
+
const r = raw;
|
|
3227
|
+
const n = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : 0;
|
|
3228
|
+
if (typeof r.inputTokens !== "number" && typeof r.outputTokens !== "number") return void 0;
|
|
3229
|
+
return {
|
|
3230
|
+
input: n(r.inputTokens),
|
|
3231
|
+
output: n(r.outputTokens),
|
|
3232
|
+
cacheRead: n(r.cachedReadTokens),
|
|
3233
|
+
cacheWrite: n(r.cachedWriteTokens)
|
|
3234
|
+
};
|
|
3235
|
+
}
|
|
3085
3236
|
|
|
3086
3237
|
// src/client/permission.ts
|
|
3087
3238
|
function pickAllow(options) {
|
|
@@ -3731,6 +3882,7 @@ var ACPSession = class _ACPSession {
|
|
|
3731
3882
|
terminalServer;
|
|
3732
3883
|
permissionPolicy;
|
|
3733
3884
|
timeoutMs;
|
|
3885
|
+
promptIdleTimeoutMs;
|
|
3734
3886
|
opts;
|
|
3735
3887
|
transportOff = null;
|
|
3736
3888
|
callbackAbort = new AbortController();
|
|
@@ -3746,12 +3898,15 @@ var ACPSession = class _ACPSession {
|
|
|
3746
3898
|
agentCapabilities = {};
|
|
3747
3899
|
agentInfo = null;
|
|
3748
3900
|
authMethods = [];
|
|
3901
|
+
/** The agent accepts `_session/steering` (see executeSteer). */
|
|
3902
|
+
steeringSupported = false;
|
|
3749
3903
|
/** Protocol version negotiated with the agent during initialize. */
|
|
3750
3904
|
negotiatedVersion = ACP_PROTOCOL_VERSION;
|
|
3751
3905
|
constructor(opts, transport) {
|
|
3752
3906
|
this.opts = opts;
|
|
3753
3907
|
this.transport = transport;
|
|
3754
3908
|
this.timeoutMs = opts.timeoutMs ?? 5 * 6e4;
|
|
3909
|
+
this.promptIdleTimeoutMs = opts.promptIdleTimeoutMs ?? 10 * 6e4;
|
|
3755
3910
|
const fsOpts = {
|
|
3756
3911
|
projectRoot: opts.projectRoot
|
|
3757
3912
|
};
|
|
@@ -3906,6 +4061,8 @@ var ACPSession = class _ACPSession {
|
|
|
3906
4061
|
}
|
|
3907
4062
|
this.negotiatedVersion = r.protocolVersion;
|
|
3908
4063
|
this.agentCapabilities = r.agentCapabilities ?? {};
|
|
4064
|
+
const meta = result._meta;
|
|
4065
|
+
this.steeringSupported = meta?.steering?.supported === true;
|
|
3909
4066
|
this.agentInfo = r.agentInfo ?? null;
|
|
3910
4067
|
this.authMethods = r.authMethods ?? [];
|
|
3911
4068
|
this.state = "ready";
|
|
@@ -3950,6 +4107,10 @@ var ACPSession = class _ACPSession {
|
|
|
3950
4107
|
closeSession: () => this.closeSession()
|
|
3951
4108
|
};
|
|
3952
4109
|
}
|
|
4110
|
+
/** Start (or, with `resumeSessionId`, resume) the agent session now, not at the first prompt. */
|
|
4111
|
+
async openSession() {
|
|
4112
|
+
return executeOpenSession(this.opContext(), () => this.createSessionWithAuth());
|
|
4113
|
+
}
|
|
3953
4114
|
async loadSession(sessionId, mcpServers, cwd) {
|
|
3954
4115
|
return executeLoadSession(this.opContext(), sessionId, mcpServers, cwd);
|
|
3955
4116
|
}
|
|
@@ -3983,6 +4144,14 @@ var ACPSession = class _ACPSession {
|
|
|
3983
4144
|
async disableProvider() {
|
|
3984
4145
|
return executeDisableProvider(this.opContext());
|
|
3985
4146
|
}
|
|
4147
|
+
/** Whether {@link steer} can reach the agent. */
|
|
4148
|
+
canSteer() {
|
|
4149
|
+
return this.steeringSupported;
|
|
4150
|
+
}
|
|
4151
|
+
/** Inject a message into the agent's running turn. */
|
|
4152
|
+
async steer(text) {
|
|
4153
|
+
return executeSteer(this.opContext(), this.steeringSupported, text);
|
|
4154
|
+
}
|
|
3986
4155
|
// ──────────────────────────────────────────────────────────────────────
|
|
3987
4156
|
// Prompt
|
|
3988
4157
|
// ──────────────────────────────────────────────────────────────────────
|
|
@@ -4001,14 +4170,14 @@ var ACPSession = class _ACPSession {
|
|
|
4001
4170
|
cancelLateSession(createPromise) {
|
|
4002
4171
|
cancelLateAcpSession(this.transport, createPromise);
|
|
4003
4172
|
}
|
|
4004
|
-
async closeSession() {
|
|
4173
|
+
async closeSession(graceMs = 1e4) {
|
|
4005
4174
|
if (!this.sessionId) return;
|
|
4006
4175
|
const sid = this.sessionId;
|
|
4007
4176
|
this.sessionId = null;
|
|
4008
4177
|
if (this.agentCapabilities.sessionCapabilities?.close) {
|
|
4009
4178
|
const id = this.allocId();
|
|
4010
4179
|
try {
|
|
4011
|
-
await this.sendRequest(id, "session/close", { sessionId: sid },
|
|
4180
|
+
await this.sendRequest(id, "session/close", { sessionId: sid }, graceMs);
|
|
4012
4181
|
} catch {
|
|
4013
4182
|
}
|
|
4014
4183
|
}
|
|
@@ -4016,7 +4185,12 @@ var ACPSession = class _ACPSession {
|
|
|
4016
4185
|
// ──────────────────────────────────────────────────────────────────────
|
|
4017
4186
|
// Lifecycle — close
|
|
4018
4187
|
// ──────────────────────────────────────────────────────────────────────
|
|
4019
|
-
|
|
4188
|
+
/**
|
|
4189
|
+
* Close the session and stop the agent. `graceMs` bounds how long the
|
|
4190
|
+
* agent may take to answer `session/close` before it is stopped anyway —
|
|
4191
|
+
* shutdown passes a short one so a slow answer cannot outlive the process.
|
|
4192
|
+
*/
|
|
4193
|
+
async close(opts = {}) {
|
|
4020
4194
|
if (this.closed) return;
|
|
4021
4195
|
this.closed = true;
|
|
4022
4196
|
this.state = "closed";
|
|
@@ -4026,7 +4200,7 @@ var ACPSession = class _ACPSession {
|
|
|
4026
4200
|
this.terminalServer.dispose();
|
|
4027
4201
|
if (this.sessionId && this.agentCapabilities.sessionCapabilities?.close) {
|
|
4028
4202
|
try {
|
|
4029
|
-
await this.closeSession();
|
|
4203
|
+
await this.closeSession(opts.graceMs);
|
|
4030
4204
|
} catch {
|
|
4031
4205
|
}
|
|
4032
4206
|
}
|
|
@@ -4050,24 +4224,37 @@ var ACPSession = class _ACPSession {
|
|
|
4050
4224
|
}
|
|
4051
4225
|
throw new ACPSessionError("protocol_error", "no JSON-RPC request id is available");
|
|
4052
4226
|
}
|
|
4053
|
-
async sendRequest(id, method, params, timeoutMs) {
|
|
4227
|
+
async sendRequest(id, method, params, timeoutMs, idle = false) {
|
|
4054
4228
|
return new Promise((resolve5, reject) => {
|
|
4055
4229
|
const effectiveTimeout = timeoutMs ?? this.timeoutMs;
|
|
4056
|
-
const
|
|
4230
|
+
const expire = () => {
|
|
4057
4231
|
this.pending.delete(id);
|
|
4058
4232
|
reject(
|
|
4059
|
-
new ACPSessionError(
|
|
4233
|
+
idle ? new ACPSessionError(
|
|
4234
|
+
"stalled",
|
|
4235
|
+
`${method}: no activity from the agent for ${Math.round(effectiveTimeout / 1e3)}s`
|
|
4236
|
+
) : new ACPSessionError(
|
|
4237
|
+
"protocol_error",
|
|
4238
|
+
`${method} timed out after ${effectiveTimeout}ms`
|
|
4239
|
+
)
|
|
4060
4240
|
);
|
|
4061
|
-
}
|
|
4062
|
-
|
|
4241
|
+
};
|
|
4242
|
+
const entry = {
|
|
4063
4243
|
method,
|
|
4064
4244
|
resolve: resolve5,
|
|
4065
4245
|
reject,
|
|
4066
4246
|
timeoutMs: effectiveTimeout,
|
|
4067
|
-
timeoutHandle:
|
|
4068
|
-
}
|
|
4247
|
+
timeoutHandle: setTimeout(expire, effectiveTimeout)
|
|
4248
|
+
};
|
|
4249
|
+
if (idle) {
|
|
4250
|
+
entry.rearm = () => {
|
|
4251
|
+
clearTimeout(entry.timeoutHandle);
|
|
4252
|
+
entry.timeoutHandle = setTimeout(expire, effectiveTimeout);
|
|
4253
|
+
};
|
|
4254
|
+
}
|
|
4255
|
+
this.pending.set(id, entry);
|
|
4069
4256
|
this.transport.send({ jsonrpc: "2.0", id, method, params }).catch((err) => {
|
|
4070
|
-
clearTimeout(
|
|
4257
|
+
clearTimeout(entry.timeoutHandle);
|
|
4071
4258
|
this.pending.delete(id);
|
|
4072
4259
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4073
4260
|
reject(new ACPSessionError("protocol_error", `send ${method} failed: ${msg}`, err));
|
|
@@ -4171,7 +4358,7 @@ var ACPSession = class _ACPSession {
|
|
|
4171
4358
|
progressHandler: this.progressHandler,
|
|
4172
4359
|
allocId: this.allocId,
|
|
4173
4360
|
sendRequest: this.sendRequest,
|
|
4174
|
-
|
|
4361
|
+
promptIdleTimeoutMs: this.promptIdleTimeoutMs,
|
|
4175
4362
|
scratch: this.scratch
|
|
4176
4363
|
};
|
|
4177
4364
|
return this;
|
|
@@ -4256,6 +4443,67 @@ var ToolTranslator = class {
|
|
|
4256
4443
|
}
|
|
4257
4444
|
};
|
|
4258
4445
|
|
|
4446
|
+
// src/integration/acp-agent-failure.ts
|
|
4447
|
+
var USAGE_LIMIT_PREFIXES = [
|
|
4448
|
+
"You've hit your",
|
|
4449
|
+
"You've reached your",
|
|
4450
|
+
"You're out of usage credits",
|
|
4451
|
+
"Your org is out of usage",
|
|
4452
|
+
"Your seat type doesn't include usage",
|
|
4453
|
+
"Your seat type doesn't include extra usage",
|
|
4454
|
+
"Your usage allocation has been disabled",
|
|
4455
|
+
"Your group's usage limit is set to $0",
|
|
4456
|
+
"requires usage credits",
|
|
4457
|
+
"You're out of extra usage",
|
|
4458
|
+
"Claude AI usage limit reached"
|
|
4459
|
+
];
|
|
4460
|
+
var DEFAULT_QUOTA_HOLD_MS = 15 * 6e4;
|
|
4461
|
+
function parseQuotaResetAt(text, now = Date.now()) {
|
|
4462
|
+
const epoch = /usage limit reached\|(\d{9,11})/i.exec(text);
|
|
4463
|
+
if (epoch?.[1]) return Number(epoch[1]) * 1e3;
|
|
4464
|
+
const m = /\bresets?\s+(?:at\s+)?(\d{1,2})(?::(\d{2}))?\s*(am|pm)?\b/i.exec(text);
|
|
4465
|
+
if (!m?.[1]) return void 0;
|
|
4466
|
+
let hour = Number(m[1]);
|
|
4467
|
+
const minute = m[2] ? Number(m[2]) : 0;
|
|
4468
|
+
const meridiem = m[3]?.toLowerCase();
|
|
4469
|
+
if (meridiem === "pm" && hour < 12) hour += 12;
|
|
4470
|
+
if (meridiem === "am" && hour === 12) hour = 0;
|
|
4471
|
+
if (hour > 23 || minute > 59 || !meridiem && !m[2]) return void 0;
|
|
4472
|
+
const at = new Date(now);
|
|
4473
|
+
at.setHours(hour, minute, 0, 0);
|
|
4474
|
+
if (at.getTime() <= now) at.setDate(at.getDate() + 1);
|
|
4475
|
+
return at.getTime();
|
|
4476
|
+
}
|
|
4477
|
+
function classifyAgentFailure(rpc, agent, now = Date.now()) {
|
|
4478
|
+
const text = rpc.message.replace(/^Internal error:\s*/i, "").trim();
|
|
4479
|
+
const errorKind = rpc.data?.errorKind;
|
|
4480
|
+
const isQuota = USAGE_LIMIT_PREFIXES.some((p) => text.startsWith(p) || text.includes(p)) || errorKind === "billing_error" || errorKind === "account_on_hold";
|
|
4481
|
+
if (isQuota) {
|
|
4482
|
+
const resetAt = parseQuotaResetAt(text, now);
|
|
4483
|
+
return {
|
|
4484
|
+
kind: "provider_quota",
|
|
4485
|
+
message: `${agent}: usage quota spent \u2014 ${text || "the account has no usage left"}`,
|
|
4486
|
+
retryable: false,
|
|
4487
|
+
backoffMs: resetAt !== void 0 ? Math.max(0, resetAt - now) : DEFAULT_QUOTA_HOLD_MS
|
|
4488
|
+
};
|
|
4489
|
+
}
|
|
4490
|
+
const message = `${agent}: ${text}`;
|
|
4491
|
+
switch (errorKind) {
|
|
4492
|
+
case "rate_limit":
|
|
4493
|
+
return { kind: "provider_rate_limit", message, retryable: true, backoffMs: 3e4 };
|
|
4494
|
+
case "overloaded":
|
|
4495
|
+
case "server_error":
|
|
4496
|
+
return { kind: "provider_5xx", message, retryable: true, backoffMs: 1e4 };
|
|
4497
|
+
case "authentication_failed":
|
|
4498
|
+
case "oauth_org_not_allowed":
|
|
4499
|
+
case "verification_required":
|
|
4500
|
+
case "cloud_credential_error":
|
|
4501
|
+
return { kind: "provider_auth", message, retryable: false };
|
|
4502
|
+
default:
|
|
4503
|
+
return rpc.code === -32e3 ? { kind: "provider_auth", message, retryable: false } : void 0;
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
|
|
4259
4507
|
// src/integration/acp-bench.ts
|
|
4260
4508
|
import * as fsp3 from "node:fs/promises";
|
|
4261
4509
|
import * as path4 from "node:path";
|
|
@@ -4491,6 +4739,7 @@ var AGENTS_CATALOG = [
|
|
|
4491
4739
|
fs: true
|
|
4492
4740
|
},
|
|
4493
4741
|
integration: "adapter",
|
|
4742
|
+
contextWindow: 1e6,
|
|
4494
4743
|
docs: "https://docs.anthropic.com/en/docs/claude-code"
|
|
4495
4744
|
},
|
|
4496
4745
|
// ── Google ───────────────────────────────────────────────────────────
|
|
@@ -4745,13 +4994,37 @@ async function makeACPSubagentRunner(options) {
|
|
|
4745
4994
|
};
|
|
4746
4995
|
return wrappedRunner;
|
|
4747
4996
|
}
|
|
4997
|
+
var sessionCostSeen = /* @__PURE__ */ new WeakMap();
|
|
4998
|
+
function recordTurnUsage(ctx, session, result) {
|
|
4999
|
+
const cost = result.usage?.cost;
|
|
5000
|
+
const total = cost?.currency === "USD" && Number.isFinite(cost.amount) && cost.amount >= 0 ? cost.amount : void 0;
|
|
5001
|
+
const turnCost = total === void 0 ? 0 : Math.max(0, total - (sessionCostSeen.get(session) ?? 0));
|
|
5002
|
+
if (total !== void 0) sessionCostSeen.set(session, total);
|
|
5003
|
+
const t = result.tokens;
|
|
5004
|
+
if (!t && turnCost === 0) return void 0;
|
|
5005
|
+
try {
|
|
5006
|
+
ctx.budget.recordUsage(
|
|
5007
|
+
{
|
|
5008
|
+
input: t?.input ?? 0,
|
|
5009
|
+
output: t?.output ?? 0,
|
|
5010
|
+
cacheRead: t?.cacheRead ?? 0,
|
|
5011
|
+
cacheWrite: t?.cacheWrite ?? 0
|
|
5012
|
+
},
|
|
5013
|
+
turnCost
|
|
5014
|
+
);
|
|
5015
|
+
} catch {
|
|
5016
|
+
}
|
|
5017
|
+
return { type: "turn_usage", ...t ? { tokens: t } : {}, costUsd: turnCost };
|
|
5018
|
+
}
|
|
4748
5019
|
async function makeACPSubagentRunnerWithStop(options) {
|
|
4749
5020
|
const projectRoot = options.projectRoot ?? options.cwd ?? process.cwd();
|
|
4750
5021
|
const timeoutMs = options.timeoutMs ?? 5 * 6e4;
|
|
4751
5022
|
const persistent = options.persistent === true;
|
|
4752
5023
|
let shared = null;
|
|
4753
5024
|
let turns = Promise.resolve();
|
|
4754
|
-
const startSession = async () => {
|
|
5025
|
+
const startSession = async (setup) => {
|
|
5026
|
+
const mcpServers = setup?.mcpServers && setup.mcpServers.length > 0 ? [...options.mcpServers ?? [], ...setup.mcpServers] : options.mcpServers;
|
|
5027
|
+
const permissionPolicy = setup?.permissionPolicy ?? options.permissionPolicy;
|
|
4755
5028
|
return ACPSession.start({
|
|
4756
5029
|
command: options.command,
|
|
4757
5030
|
...options.args !== void 0 ? { args: options.args } : {},
|
|
@@ -4759,23 +5032,29 @@ async function makeACPSubagentRunnerWithStop(options) {
|
|
|
4759
5032
|
...options.cwd !== void 0 ? { cwd: options.cwd } : {},
|
|
4760
5033
|
projectRoot,
|
|
4761
5034
|
timeoutMs,
|
|
5035
|
+
...options.promptIdleTimeoutMs !== void 0 ? { promptIdleTimeoutMs: options.promptIdleTimeoutMs } : {},
|
|
4762
5036
|
role: options.role,
|
|
4763
|
-
...
|
|
4764
|
-
...
|
|
5037
|
+
...permissionPolicy !== void 0 ? { permissionPolicy } : {},
|
|
5038
|
+
...mcpServers !== void 0 ? { mcpServers } : {},
|
|
5039
|
+
...setup?.meta ? { sessionMeta: setup.meta } : {},
|
|
5040
|
+
...options.initialModeId ? { initialModeId: options.initialModeId } : {},
|
|
5041
|
+
...options.requireInitialMode ? { requireInitialMode: true } : {}
|
|
4765
5042
|
});
|
|
4766
5043
|
};
|
|
4767
5044
|
const runner = async (task, ctx) => {
|
|
4768
5045
|
let session;
|
|
5046
|
+
let setup;
|
|
4769
5047
|
try {
|
|
5048
|
+
setup = options.sessionSetup?.(task, ctx);
|
|
4770
5049
|
if (persistent) {
|
|
4771
|
-
shared ??= startSession();
|
|
5050
|
+
shared ??= startSession(setup);
|
|
4772
5051
|
const starting = shared;
|
|
4773
5052
|
session = await starting.catch((err) => {
|
|
4774
5053
|
if (shared === starting) shared = null;
|
|
4775
5054
|
throw err;
|
|
4776
5055
|
});
|
|
4777
5056
|
} else {
|
|
4778
|
-
session = await startSession();
|
|
5057
|
+
session = await startSession(setup);
|
|
4779
5058
|
}
|
|
4780
5059
|
} catch (err) {
|
|
4781
5060
|
throw acpErrorToSubagentError(err, options.role ?? "acp-subagent");
|
|
@@ -4792,14 +5071,20 @@ async function makeACPSubagentRunnerWithStop(options) {
|
|
|
4792
5071
|
}
|
|
4793
5072
|
};
|
|
4794
5073
|
let result;
|
|
5074
|
+
let endLive;
|
|
4795
5075
|
try {
|
|
4796
|
-
|
|
5076
|
+
if (session.canSteer()) endLive = options.onTurnLive?.(ctx, task, (t) => session.steer(t));
|
|
5077
|
+
const prompt2 = setup?.promptPrefix ? `${setup.promptPrefix}
|
|
5078
|
+
|
|
5079
|
+
${task.description}` : task.description;
|
|
5080
|
+
const turn = () => session.prompt([textContent(prompt2)], ctx.signal, onProgress);
|
|
4797
5081
|
const run = persistent ? turns.then(turn, turn) : turn();
|
|
4798
5082
|
if (persistent) turns = run;
|
|
4799
5083
|
result = await run;
|
|
4800
5084
|
} catch (err) {
|
|
4801
5085
|
throw acpErrorToSubagentError(err, options.role ?? "acp-subagent");
|
|
4802
5086
|
} finally {
|
|
5087
|
+
endLive?.();
|
|
4803
5088
|
if (!persistent) {
|
|
4804
5089
|
try {
|
|
4805
5090
|
await session.close();
|
|
@@ -4807,6 +5092,8 @@ async function makeACPSubagentRunnerWithStop(options) {
|
|
|
4807
5092
|
}
|
|
4808
5093
|
}
|
|
4809
5094
|
}
|
|
5095
|
+
const turnUsage = recordTurnUsage(ctx, session, result);
|
|
5096
|
+
if (turnUsage) onProgress(turnUsage);
|
|
4810
5097
|
const failure = acpTurnFailure(result, options.role ?? "acp-subagent");
|
|
4811
5098
|
if (failure) throw failure;
|
|
4812
5099
|
return {
|
|
@@ -4827,7 +5114,20 @@ async function makeACPSubagentRunnerWithStop(options) {
|
|
|
4827
5114
|
};
|
|
4828
5115
|
return { runner, stop };
|
|
4829
5116
|
}
|
|
5117
|
+
function agentRpcError(err) {
|
|
5118
|
+
let cur = err;
|
|
5119
|
+
for (let depth = 0; depth < 4 && cur; depth++) {
|
|
5120
|
+
if (isJsonRpcError(cur)) return cur;
|
|
5121
|
+
cur = cur.cause;
|
|
5122
|
+
}
|
|
5123
|
+
return void 0;
|
|
5124
|
+
}
|
|
4830
5125
|
function acpErrorToSubagentError(err, subagentId) {
|
|
5126
|
+
const rpc = agentRpcError(err);
|
|
5127
|
+
if (rpc) {
|
|
5128
|
+
const classified = classifyAgentFailure(rpc, subagentId);
|
|
5129
|
+
if (classified) return classified;
|
|
5130
|
+
}
|
|
4831
5131
|
if (err instanceof ACPSessionError) {
|
|
4832
5132
|
const kind = mapACPKind(err.kind);
|
|
4833
5133
|
return {
|
|
@@ -4895,6 +5195,9 @@ function mapACPKind(acpKind) {
|
|
|
4895
5195
|
return "bridge_failed";
|
|
4896
5196
|
case "aborted":
|
|
4897
5197
|
return "aborted_by_parent";
|
|
5198
|
+
// The agent went silent mid-turn and the turn was cancelled.
|
|
5199
|
+
case "stalled":
|
|
5200
|
+
return "budget_timeout";
|
|
4898
5201
|
case "closed":
|
|
4899
5202
|
case "unsupported_capability":
|
|
4900
5203
|
return "unknown";
|
|
@@ -5441,7 +5744,8 @@ async function runOneAcpTask(opts) {
|
|
|
5441
5744
|
role,
|
|
5442
5745
|
timeoutMs,
|
|
5443
5746
|
...opts.onProgress !== void 0 ? { onProgress: opts.onProgress } : {},
|
|
5444
|
-
...opts.permissionPolicy !== void 0 ? { permissionPolicy: opts.permissionPolicy } : {}
|
|
5747
|
+
...opts.permissionPolicy !== void 0 ? { permissionPolicy: opts.permissionPolicy } : {},
|
|
5748
|
+
...opts.sessionSetup !== void 0 ? { sessionSetup: opts.sessionSetup } : {}
|
|
5445
5749
|
});
|
|
5446
5750
|
try {
|
|
5447
5751
|
const budget = new SubagentBudget2({
|
|
@@ -5585,6 +5889,7 @@ export {
|
|
|
5585
5889
|
WrongStackACPServer,
|
|
5586
5890
|
assertNeverSessionUpdate,
|
|
5587
5891
|
audioContent,
|
|
5892
|
+
classifyAgentFailure,
|
|
5588
5893
|
defaultEnsembleCmdResolver,
|
|
5589
5894
|
defaultPermissionPolicy,
|
|
5590
5895
|
fetchAcpRegistry,
|