zcode-acp-server 0.47.6 → 0.47.8
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 +1 -1
- package/dist/backend/resolve.d.ts +0 -14
- package/dist/backend/resolve.d.ts.map +1 -1
- package/dist/backend/resolve.js +20 -2
- package/dist/backend/resolve.js.map +1 -1
- package/dist/code-fingerprint.json +2 -2
- package/dist/config/auto-compact.d.ts.map +1 -1
- package/dist/config/auto-compact.js +6 -42
- package/dist/config/auto-compact.js.map +1 -1
- package/dist/config/model-cache.js +1 -1
- package/dist/config/model-cache.js.map +1 -1
- package/dist/config/options.js +2 -2
- package/dist/config/options.js.map +1 -1
- package/dist/config/runtime-model.js +1 -1
- package/dist/config/runtime-model.js.map +1 -1
- package/dist/goal-loop/driver.d.ts.map +1 -1
- package/dist/goal-loop/driver.js +6 -8
- package/dist/goal-loop/driver.js.map +1 -1
- package/dist/handlers/extensions.d.ts +17 -5
- package/dist/handlers/extensions.d.ts.map +1 -1
- package/dist/handlers/extensions.js +43 -23
- package/dist/handlers/extensions.js.map +1 -1
- package/dist/handlers/io.d.ts +11 -0
- package/dist/handlers/io.d.ts.map +1 -1
- package/dist/handlers/io.js +22 -1
- package/dist/handlers/io.js.map +1 -1
- package/dist/handlers/replay.js +1 -1
- package/dist/handlers/replay.js.map +1 -1
- package/dist/handlers/session.d.ts +0 -9
- package/dist/handlers/session.d.ts.map +1 -1
- package/dist/handlers/session.js +40 -58
- package/dist/handlers/session.js.map +1 -1
- package/dist/handlers/slash.js +2 -6
- package/dist/handlers/slash.js.map +1 -1
- package/dist/i18n.js +6 -6
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/remote/endpoint.d.ts.map +1 -1
- package/dist/remote/endpoint.js +12 -10
- package/dist/remote/endpoint.js.map +1 -1
- package/dist/remote/hub-server.d.ts.map +1 -1
- package/dist/remote/hub-server.js +4 -2
- package/dist/remote/hub-server.js.map +1 -1
- package/dist/remote/login-shell-env.d.ts +14 -7
- package/dist/remote/login-shell-env.d.ts.map +1 -1
- package/dist/remote/login-shell-env.js +59 -27
- package/dist/remote/login-shell-env.js.map +1 -1
- package/dist/remote/settings-endpoint.d.ts.map +1 -1
- package/dist/remote/settings-endpoint.js +31 -23
- package/dist/remote/settings-endpoint.js.map +1 -1
- package/dist/server.d.ts +15 -7
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +17 -9
- package/dist/server.js.map +1 -1
- package/dist/settings/app-update.d.ts.map +1 -1
- package/dist/settings/app-update.js +5 -4
- package/dist/settings/app-update.js.map +1 -1
- package/dist/settings/atomic-write.d.ts.map +1 -1
- package/dist/settings/atomic-write.js +5 -4
- package/dist/settings/atomic-write.js.map +1 -1
- package/dist/settings/coding-plan.d.ts.map +1 -1
- package/dist/settings/coding-plan.js +3 -2
- package/dist/settings/coding-plan.js.map +1 -1
- package/dist/settings/errors.d.ts +27 -0
- package/dist/settings/errors.d.ts.map +1 -0
- package/dist/settings/errors.js +27 -0
- package/dist/settings/errors.js.map +1 -0
- package/docs/REMOTE-CLIENTS.md +11 -0
- package/package.json +1 -1
package/dist/handlers/session.js
CHANGED
|
@@ -30,7 +30,7 @@ import { refreshTerminalTabTitle } from "../terminal-title.js";
|
|
|
30
30
|
import { buildDiffContent, EventTranslator, extractLocations, formatTurnError, isBackendLostError, isTransientTurnError, ProjectionDiffer, } from "../translators/index.js";
|
|
31
31
|
import { clientConnectionRoot, log, warn } from "../utils.js";
|
|
32
32
|
import { dispatchEvent } from "./dispatch.js";
|
|
33
|
-
import { sendSessionUpdate, sendTextChunk, withReplayBatch } from "./io.js";
|
|
33
|
+
import { emitSessionTurnState, sendSessionUpdate, sendTextChunk, withReplayBatch } from "./io.js";
|
|
34
34
|
import { EDIT_DIFF_READ_LIMIT, fetchMessages, fetchMessagesSinceAnchor, fullSlice, readTailLimit, REPLY_READ_LIMIT, replayMessages, sliceTail, TURN_READ, } from "./replay.js";
|
|
35
35
|
import { extractPermDeniedPath, extractSandboxDenial, GENERIC_HINT_KEY, handleSandboxDenial, READ_ONLY_TOOLS, } from "./sandbox-allow.js";
|
|
36
36
|
import { handleServerRequests } from "./server-requests.js";
|
|
@@ -114,7 +114,7 @@ async function syncProviderRegistry(server, cwd) {
|
|
|
114
114
|
// models the user's config selects never reach `settings.model.available`
|
|
115
115
|
// (verified 2026-09 — switches then fail with "Provider Registry 中不存在
|
|
116
116
|
// Model"). Pushing the snapshot restores desktop parity. Best-effort.
|
|
117
|
-
await pushAccountProviderConfig(server.ensureBackend(), () => server.nextId());
|
|
117
|
+
await pushAccountProviderConfig(await server.ensureBackend(), () => server.nextId());
|
|
118
118
|
const registry = buildProviderRegistry();
|
|
119
119
|
if (registry.providers.length === 0) {
|
|
120
120
|
// Every configured provider lacks models (or none are configured). The
|
|
@@ -125,9 +125,7 @@ async function syncProviderRegistry(server, cwd) {
|
|
|
125
125
|
log("provider-registry: no usable providers — skipping sync");
|
|
126
126
|
return;
|
|
127
127
|
}
|
|
128
|
-
const resp = await server
|
|
129
|
-
.ensureBackend()
|
|
130
|
-
.request(server.nextId(), "workspace/updateProviderRegistry", { workspace: workspaceFor(cwd), registry }, 10000);
|
|
128
|
+
const resp = await (await server.ensureBackend()).request(server.nextId(), "workspace/updateProviderRegistry", { workspace: workspaceFor(cwd), registry }, 10000);
|
|
131
129
|
if (resp.error) {
|
|
132
130
|
// 3.12+ removed the method (the registry is built from the bundled table,
|
|
133
131
|
// personal config, and the account snapshot) — a no-op, not a failure.
|
|
@@ -372,7 +370,7 @@ function emitBootUsageUpdate(server, acpSid) {
|
|
|
372
370
|
const zcodeSid = server.resolveSid(acpSid);
|
|
373
371
|
let used = 0;
|
|
374
372
|
if (zcodeSid) {
|
|
375
|
-
const backend = server.ensureBackend();
|
|
373
|
+
const backend = await server.ensureBackend();
|
|
376
374
|
const resp = await backend.request(server.nextId(), "session/read",
|
|
377
375
|
// messageLimit: only the projection is read; the cap keeps the
|
|
378
376
|
// backend from serializing the whole message array for it.
|
|
@@ -398,25 +396,6 @@ function emitBootUsageUpdate(server, acpSid) {
|
|
|
398
396
|
})();
|
|
399
397
|
});
|
|
400
398
|
}
|
|
401
|
-
/**
|
|
402
|
-
* Broadcast turn liveness to attached clients ($/zcode/turnState): `running:true`
|
|
403
|
-
* at turn start, `running:false` at completion (or on any early-return path).
|
|
404
|
-
*
|
|
405
|
-
* Emitted per attached alias (see server.sessionAliases) so every client holding
|
|
406
|
-
* this conversation under its own ACP id updates its running indicator.
|
|
407
|
-
* Clients that don't recognize the notification simply drop it.
|
|
408
|
-
*/
|
|
409
|
-
export async function emitSessionTurnState(server, acpSid, running, cx) {
|
|
410
|
-
const targetCx = cx ?? server.clients.broadcast();
|
|
411
|
-
const results = await Promise.allSettled(server
|
|
412
|
-
.sessionAliases(acpSid)
|
|
413
|
-
.map((sid) => targetCx.notify("$/zcode/turnState", { sessionId: sid, running })));
|
|
414
|
-
for (const r of results) {
|
|
415
|
-
if (r.status === "rejected") {
|
|
416
|
-
log(`turnState notify failed: ${r.reason instanceof Error ? r.reason.message : String(r.reason)}`);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
399
|
/**
|
|
421
400
|
* Reload the session into the backend when the resident verification went
|
|
422
401
|
* stale — the backend evicts idle resident runtimes (~10min idle + LRU), and
|
|
@@ -542,7 +521,7 @@ export async function ensureRealSession(server, acpSid, opts = {}) {
|
|
|
542
521
|
// The create body runs synchronously up to its first await, so the `creating`
|
|
543
522
|
// promise is stored before any concurrent caller can observe the entry.
|
|
544
523
|
const creating = (async () => {
|
|
545
|
-
const backend = server.ensureBackend();
|
|
524
|
+
const backend = await server.ensureBackend();
|
|
546
525
|
// Push the provider registry BEFORE session/create: the backend resolves
|
|
547
526
|
// the session's default model against the registry, and without the
|
|
548
527
|
// provider's reasoning/model definitions it falls back to the bare
|
|
@@ -609,7 +588,7 @@ export async function ensureRealSession(server, acpSid, opts = {}) {
|
|
|
609
588
|
// resume this session via the placeholder id.
|
|
610
589
|
recordMaterializedSession(acpSid, sid, pending.cwd);
|
|
611
590
|
log(`session/new ${acpSid} → created ${sid} (lazy, on first use)`);
|
|
612
|
-
server.ensureBackgroundListener(sid);
|
|
591
|
+
await server.ensureBackgroundListener(sid);
|
|
613
592
|
// Sync to the App's tasks-index.sqlite so the App UI shows this session.
|
|
614
593
|
// Best-effort; failures are logged inside upsertSessionTask and swallowed.
|
|
615
594
|
const { upsertSessionTask } = await import("../tasks-index.js");
|
|
@@ -633,7 +612,7 @@ export async function ensureRealSession(server, acpSid, opts = {}) {
|
|
|
633
612
|
}
|
|
634
613
|
/** `session/list` → zcode `session/list`. */
|
|
635
614
|
export async function listSessions(server, params) {
|
|
636
|
-
const backend = server.ensureBackend();
|
|
615
|
+
const backend = await server.ensureBackend();
|
|
637
616
|
const zcParams = {};
|
|
638
617
|
// Serve mode (ADR-0014) pins the workspace: a remote client must not use a
|
|
639
618
|
// client-supplied cwd to enumerate the machine's sessions in OTHER projects
|
|
@@ -669,7 +648,7 @@ async function adoptStoredTitle(server, acpSid, zcodeSid) {
|
|
|
669
648
|
if (server.sessionTitles.has(acpSid))
|
|
670
649
|
return;
|
|
671
650
|
try {
|
|
672
|
-
const backend = server.ensureBackend();
|
|
651
|
+
const backend = await server.ensureBackend();
|
|
673
652
|
const resp = await backend.request(server.nextId(), "session/list", {}, 15000);
|
|
674
653
|
if (resp.error)
|
|
675
654
|
return;
|
|
@@ -870,7 +849,7 @@ export async function resumeSession(server, params, cx) {
|
|
|
870
849
|
// above); without this, a loaded session has no readable root.
|
|
871
850
|
server.sessionCwds.set(acpSid, cwd);
|
|
872
851
|
log(`session/resume -> ${zcodeSid}`);
|
|
873
|
-
server.ensureBackgroundListener(zcodeSid);
|
|
852
|
+
await server.ensureBackgroundListener(zcodeSid);
|
|
874
853
|
await adoptStoredTitle(server, acpSid, zcodeSid);
|
|
875
854
|
// Martty's /resume rides session/resume (no history by ACP design) and only
|
|
876
855
|
// folds updates addressed to a session id it has already adopted — i.e.
|
|
@@ -937,7 +916,7 @@ export async function resumeIntoSession(server, cx, acpSid, zcodeTarget) {
|
|
|
937
916
|
// Materialized but empty: discard the orphan backend session and the
|
|
938
917
|
// stale mappings before adopting the target.
|
|
939
918
|
try {
|
|
940
|
-
server.ensureBackend().send("session/close", { sessionId: current });
|
|
919
|
+
(await server.ensureBackend()).send("session/close", { sessionId: current });
|
|
941
920
|
}
|
|
942
921
|
catch (e) {
|
|
943
922
|
log(`/resume: closing empty session ${current} failed (ignored): ` +
|
|
@@ -983,7 +962,7 @@ export async function resumeIntoSession(server, cx, acpSid, zcodeTarget) {
|
|
|
983
962
|
const finalCwd = backendWs && !server.serveMode ? backendWs : cwd;
|
|
984
963
|
server.sessionCwds.set(acpSid, finalCwd);
|
|
985
964
|
recordMaterializedSession(acpSid, zcodeTarget, finalCwd);
|
|
986
|
-
server.ensureBackgroundListener(zcodeTarget);
|
|
965
|
+
await server.ensureBackgroundListener(zcodeTarget);
|
|
987
966
|
await adoptStoredTitle(server, acpSid, zcodeTarget);
|
|
988
967
|
}
|
|
989
968
|
catch (e) {
|
|
@@ -1086,7 +1065,7 @@ export async function loadSession(server, params, cx, opts = {}) {
|
|
|
1086
1065
|
// Same as resumeSession: backend-authoritative session root for file access.
|
|
1087
1066
|
server.sessionCwds.set(acpSid, cwd);
|
|
1088
1067
|
log(`session/load → ${zcodeSid}`);
|
|
1089
|
-
server.ensureBackgroundListener(zcodeSid);
|
|
1068
|
+
await server.ensureBackgroundListener(zcodeSid);
|
|
1090
1069
|
await adoptStoredTitle(server, acpSid, zcodeSid);
|
|
1091
1070
|
// Goal-loop restart recovery (ADR-0022 §6): surface a recovery hint at most
|
|
1092
1071
|
// once per bridge process per session — never auto-resume a spend-incurring
|
|
@@ -1349,7 +1328,7 @@ export async function runOneTurn(server, opts) {
|
|
|
1349
1328
|
// reconcile the differ baseline so the retried turn's new messages
|
|
1350
1329
|
// aren't treated as already-seen, surface a retry hint, then back off.
|
|
1351
1330
|
if (turn.cancelled) {
|
|
1352
|
-
stopBackendTurn(server, zcodeSid, turn);
|
|
1331
|
+
void stopBackendTurn(server, zcodeSid, turn);
|
|
1353
1332
|
return { stopReason: "cancelled" };
|
|
1354
1333
|
}
|
|
1355
1334
|
differ.markSeen(await fetchMessagesSinceAnchor(server, zcodeSid, differ.historyAnchor));
|
|
@@ -1415,7 +1394,7 @@ export async function runOneTurn(server, opts) {
|
|
|
1415
1394
|
let queuedNoticeSent = false;
|
|
1416
1395
|
while (true) {
|
|
1417
1396
|
if (turn.cancelled) {
|
|
1418
|
-
stopBackendTurn(server, zcodeSid, turn);
|
|
1397
|
+
void stopBackendTurn(server, zcodeSid, turn);
|
|
1419
1398
|
return { stopReason: "cancelled" };
|
|
1420
1399
|
}
|
|
1421
1400
|
sendAttempt++;
|
|
@@ -1433,7 +1412,7 @@ export async function runOneTurn(server, opts) {
|
|
|
1433
1412
|
if (expectBusy) {
|
|
1434
1413
|
await sleep(SEND_RETRY_INTERVAL_MS);
|
|
1435
1414
|
if (turn.cancelled) {
|
|
1436
|
-
stopBackendTurn(server, zcodeSid, turn);
|
|
1415
|
+
void stopBackendTurn(server, zcodeSid, turn);
|
|
1437
1416
|
return { stopReason: "cancelled" };
|
|
1438
1417
|
}
|
|
1439
1418
|
}
|
|
@@ -1608,7 +1587,7 @@ export async function runOneTurn(server, opts) {
|
|
|
1608
1587
|
.catch((err) => warn(`recover: backend kill failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
1609
1588
|
}
|
|
1610
1589
|
try {
|
|
1611
|
-
backend = server.ensureBackend();
|
|
1590
|
+
backend = await server.ensureBackend();
|
|
1612
1591
|
listener = new EventStreamListener(backend, zcodeSid);
|
|
1613
1592
|
monitor = new TurnMonitor(backend, zcodeSid, () => server.nextId());
|
|
1614
1593
|
await reloadBackendSession(server, acpSid, zcodeSid);
|
|
@@ -1695,7 +1674,7 @@ async function runPrompt(server, params, cx, requestId, continuationRound = fals
|
|
|
1695
1674
|
// respawns under the profile and the subscribe-recovery path reloads the
|
|
1696
1675
|
// session. No-op unless the config appeared mid-run.
|
|
1697
1676
|
await server.applySandboxFlip();
|
|
1698
|
-
const backend = server.ensureBackend();
|
|
1677
|
+
const backend = await server.ensureBackend();
|
|
1699
1678
|
// Extract prompt text + image attachments from ACP ContentBlock[].
|
|
1700
1679
|
const text = extractPromptText(params.prompt);
|
|
1701
1680
|
const attachments = extractAttachments(params.prompt);
|
|
@@ -1730,7 +1709,7 @@ async function runPrompt(server, params, cx, requestId, continuationRound = fals
|
|
|
1730
1709
|
// titles): a mid-session backend respawn (sandbox flip, dynamic allow
|
|
1731
1710
|
// batches, dead-reader recovery) replaces the instance the listeners were
|
|
1732
1711
|
// registered on — ensureBackgroundListener re-registers on the current one.
|
|
1733
|
-
server.ensureBackgroundListener(zcodeSid);
|
|
1712
|
+
await server.ensureBackgroundListener(zcodeSid);
|
|
1734
1713
|
// Slash-command interception: dispatches directly to ZCode methods and
|
|
1735
1714
|
// returns end_turn without entering the turn loop. Known passthrough
|
|
1736
1715
|
// commands and unknown /x both return null for the normal turn loop.
|
|
@@ -1962,7 +1941,7 @@ export async function cancel(server, params) {
|
|
|
1962
1941
|
matched = true;
|
|
1963
1942
|
turn.cancelled = true;
|
|
1964
1943
|
if (!turn.stopSent) {
|
|
1965
|
-
stopBackendTurn(server, zcodeSid, turn);
|
|
1944
|
+
void stopBackendTurn(server, zcodeSid, turn);
|
|
1966
1945
|
turn.stopSent = true;
|
|
1967
1946
|
}
|
|
1968
1947
|
// Record cancel time so a prompt arriving in the backend's ~20s
|
|
@@ -2069,7 +2048,7 @@ export function isBackendLostRequestError(e) {
|
|
|
2069
2048
|
* backend's prompt lock releases when ITS finalisation completes — that,
|
|
2070
2049
|
* not any bridge-side signal, is what the next prompt's send-retry waits on.
|
|
2071
2050
|
*/
|
|
2072
|
-
function stopBackendTurn(server, zcodeSid, turn) {
|
|
2051
|
+
async function stopBackendTurn(server, zcodeSid, turn) {
|
|
2073
2052
|
const foregroundExecutionId = turn.foregroundExecutionId;
|
|
2074
2053
|
// A turn whose send was NEVER accepted owns no generation of its own; while
|
|
2075
2054
|
// our detached compaction runs, the only thing foreground on this session
|
|
@@ -2084,7 +2063,8 @@ function stopBackendTurn(server, zcodeSid, turn) {
|
|
|
2084
2063
|
return;
|
|
2085
2064
|
}
|
|
2086
2065
|
try {
|
|
2087
|
-
server.ensureBackend()
|
|
2066
|
+
const backend = await server.ensureBackend();
|
|
2067
|
+
backend.send("session/stop", { sessionId: zcodeSid });
|
|
2088
2068
|
}
|
|
2089
2069
|
catch (e) {
|
|
2090
2070
|
log(` [stop] session/stop send failed (ignored): ${e instanceof Error ? e.message : String(e)}`);
|
|
@@ -2101,7 +2081,8 @@ function stopBackendTurn(server, zcodeSid, turn) {
|
|
|
2101
2081
|
// at cancel time, letting the backend guard against stopping a newer one.
|
|
2102
2082
|
// Omitted when unknown, targeting whatever is currently foreground.
|
|
2103
2083
|
try {
|
|
2104
|
-
server.ensureBackend()
|
|
2084
|
+
const backend = await server.ensureBackend();
|
|
2085
|
+
backend.send("v4/command", {
|
|
2105
2086
|
commandId: randomUUID(),
|
|
2106
2087
|
clientId: "zcode-acp-server",
|
|
2107
2088
|
sessionId: zcodeSid,
|
|
@@ -2130,9 +2111,10 @@ function stopBackendTurn(server, zcodeSid, turn) {
|
|
|
2130
2111
|
* history). Callers reload the session on next use — prompt()'s subscribe
|
|
2131
2112
|
* recovery and the drain gate's reload both handle the closed window.
|
|
2132
2113
|
*/
|
|
2133
|
-
function closeBackendSession(server, zcodeSid) {
|
|
2114
|
+
async function closeBackendSession(server, zcodeSid) {
|
|
2134
2115
|
try {
|
|
2135
|
-
server.ensureBackend()
|
|
2116
|
+
const backend = await server.ensureBackend();
|
|
2117
|
+
backend.send("session/close", { sessionId: zcodeSid });
|
|
2136
2118
|
log(` [stop] session/close fired for ${zcodeSid} (backend ignores session/stop)`);
|
|
2137
2119
|
}
|
|
2138
2120
|
catch (e) {
|
|
@@ -2176,7 +2158,7 @@ export async function drainBackendAfterCancel(server, deps) {
|
|
|
2176
2158
|
let escalated = false;
|
|
2177
2159
|
while (Date.now() - drainT0 < DRAIN_TIMEOUT_MS) {
|
|
2178
2160
|
if (turn.cancelled) {
|
|
2179
|
-
stopBackendTurn(server, zcodeSid, turn);
|
|
2161
|
+
void stopBackendTurn(server, zcodeSid, turn);
|
|
2180
2162
|
return "cancelled";
|
|
2181
2163
|
}
|
|
2182
2164
|
const proj = await monitor.pollOnce();
|
|
@@ -2198,7 +2180,7 @@ export async function drainBackendAfterCancel(server, deps) {
|
|
|
2198
2180
|
break;
|
|
2199
2181
|
if (proj.status === "running" && !escalated && Date.now() - drainT0 > escalateAfterMs) {
|
|
2200
2182
|
escalated = true;
|
|
2201
|
-
closeBackendSession(server, zcodeSid);
|
|
2183
|
+
void closeBackendSession(server, zcodeSid);
|
|
2202
2184
|
}
|
|
2203
2185
|
if (!noticed) {
|
|
2204
2186
|
noticed = true;
|
|
@@ -2283,7 +2265,7 @@ export function preemptInFlightTurn(server, zcodeSid, selfRequestId) {
|
|
|
2283
2265
|
continue;
|
|
2284
2266
|
turn.cancelled = true; // signal the old turn to stop its retry loops
|
|
2285
2267
|
if (!turn.stopSent) {
|
|
2286
|
-
stopBackendTurn(server, zcodeSid, turn);
|
|
2268
|
+
void stopBackendTurn(server, zcodeSid, turn);
|
|
2287
2269
|
turn.stopSent = true;
|
|
2288
2270
|
}
|
|
2289
2271
|
// Record cancel time so the prompt()'s send-retry can use the recovery
|
|
@@ -2419,7 +2401,7 @@ function fileUriToPath(uri) {
|
|
|
2419
2401
|
* backend-authoritative session workspace from it. Throws on failure.
|
|
2420
2402
|
*/
|
|
2421
2403
|
async function resumeBackendSession(server, zcParams) {
|
|
2422
|
-
const backend = server.ensureBackend();
|
|
2404
|
+
const backend = await server.ensureBackend();
|
|
2423
2405
|
const MAX_ATTEMPTS = 2;
|
|
2424
2406
|
const ATTEMPT_TIMEOUT_MS = 15_000;
|
|
2425
2407
|
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
@@ -2738,7 +2720,7 @@ async function fetchMessagesForReplay(server, zcodeSid) {
|
|
|
2738
2720
|
*/
|
|
2739
2721
|
async function repairUnavailableModel(server, zcodeSid) {
|
|
2740
2722
|
try {
|
|
2741
|
-
const backend = server.ensureBackend();
|
|
2723
|
+
const backend = await server.ensureBackend();
|
|
2742
2724
|
const resp = await backend.request(server.nextId(), "session/read",
|
|
2743
2725
|
// messageLimit: only settings.model.current is read; the cap keeps the
|
|
2744
2726
|
// backend from serializing the whole message array for it.
|
|
@@ -2871,7 +2853,7 @@ export function turnResult(translator, stopReason) {
|
|
|
2871
2853
|
* Commit 6 — for now they're polled to keep the inbox clear.
|
|
2872
2854
|
*/
|
|
2873
2855
|
export async function runEventTurn(server, listener, monitor, differ, cx, acpSid, chunkMsgId, turn, gateArmed) {
|
|
2874
|
-
const backend = server.ensureBackend();
|
|
2856
|
+
const backend = await server.ensureBackend();
|
|
2875
2857
|
const translator = new EventTranslator();
|
|
2876
2858
|
differ.resetTurn();
|
|
2877
2859
|
const NO_PROGRESS_MS = 120_000;
|
|
@@ -3051,7 +3033,7 @@ export async function runEventTurn(server, listener, monitor, differ, cx, acpSid
|
|
|
3051
3033
|
}
|
|
3052
3034
|
else if (!emittedOutput) {
|
|
3053
3035
|
// No text and no output → suspected failure.
|
|
3054
|
-
stopBackendTurn(server, turn.zcodeSid, turn);
|
|
3036
|
+
void stopBackendTurn(server, turn.zcodeSid, turn);
|
|
3055
3037
|
throw new RequestError(-32603, "turn produced no output");
|
|
3056
3038
|
}
|
|
3057
3039
|
}
|
|
@@ -3068,7 +3050,7 @@ export async function runEventTurn(server, listener, monitor, differ, cx, acpSid
|
|
|
3068
3050
|
else if (turn.cancelled) {
|
|
3069
3051
|
// Preserve the pre-existing bounded cancel behaviour. A stuck prompt
|
|
3070
3052
|
// lock after stop must not keep a user-cancelled turn alive forever.
|
|
3071
|
-
stopBackendTurn(server, turn.zcodeSid, turn);
|
|
3053
|
+
void stopBackendTurn(server, turn.zcodeSid, turn);
|
|
3072
3054
|
return turnResult(translator, "max_turn_requests");
|
|
3073
3055
|
}
|
|
3074
3056
|
else {
|
|
@@ -3109,7 +3091,7 @@ export async function runEventTurn(server, listener, monitor, differ, cx, acpSid
|
|
|
3109
3091
|
return turnResult(translator, "end_turn");
|
|
3110
3092
|
}
|
|
3111
3093
|
log(` [stall] watermark frozen ${Math.round(frozenMs / 1000)}s with no output; stopping backend turn`);
|
|
3112
|
-
stopBackendTurn(server, turn.zcodeSid, turn);
|
|
3094
|
+
void stopBackendTurn(server, turn.zcodeSid, turn);
|
|
3113
3095
|
return turnResult(translator, "max_turn_requests");
|
|
3114
3096
|
}
|
|
3115
3097
|
}
|
|
@@ -3142,7 +3124,7 @@ export async function runEventTurn(server, listener, monitor, differ, cx, acpSid
|
|
|
3142
3124
|
// to no turn listener, and the next turn's turn-attribution gate
|
|
3143
3125
|
// discards any residue that slipped into the queue meanwhile.
|
|
3144
3126
|
if (!turn.stopSent) {
|
|
3145
|
-
stopBackendTurn(server, turn.zcodeSid, turn);
|
|
3127
|
+
void stopBackendTurn(server, turn.zcodeSid, turn);
|
|
3146
3128
|
turn.stopSent = true;
|
|
3147
3129
|
}
|
|
3148
3130
|
return turnResult(translator, "cancelled");
|
|
@@ -3408,7 +3390,7 @@ export async function runEventTurn(server, listener, monitor, differ, cx, acpSid
|
|
|
3408
3390
|
}
|
|
3409
3391
|
if (translator.turnFailed) {
|
|
3410
3392
|
// Best-effort stop in case the failed turn left a residual lock.
|
|
3411
|
-
stopBackendTurn(server, turn.zcodeSid, turn);
|
|
3393
|
+
void stopBackendTurn(server, turn.zcodeSid, turn);
|
|
3412
3394
|
// Throw a TurnFailedError carrying the structured error so the caller
|
|
3413
3395
|
// (prompt's retry loop) can classify transient vs fatal. The error
|
|
3414
3396
|
// message is formatted for display when it ultimately reaches the user.
|
|
@@ -3564,7 +3546,7 @@ export function flattenTodos(todos, todoGroups) {
|
|
|
3564
3546
|
}
|
|
3565
3547
|
/** Build a {projection, messages, todos} snapshot from session/messages + session/read. */
|
|
3566
3548
|
async function buildSnapshot(server, zcodeSid, opts = {}) {
|
|
3567
|
-
const backend = server.ensureBackend();
|
|
3549
|
+
const backend = await server.ensureBackend();
|
|
3568
3550
|
const [msgs, readResp] = await Promise.all([
|
|
3569
3551
|
fetchMessages(server, zcodeSid, opts),
|
|
3570
3552
|
backend.request(server.nextId(), "session/read", { sessionId: zcodeSid }, 8000),
|
|
@@ -3669,7 +3651,7 @@ const PLAN_RECHECK_DELAY_MS = 600;
|
|
|
3669
3651
|
// Exported for unit tests (plan recheck timing).
|
|
3670
3652
|
export async function dispatchPlanIfChanged(server, cx, acpSid, zcodeSid, differ, chunkMsgId, recheck = true) {
|
|
3671
3653
|
try {
|
|
3672
|
-
const backend = server.ensureBackend();
|
|
3654
|
+
const backend = await server.ensureBackend();
|
|
3673
3655
|
const readResp = await backend.request(server.nextId(), "session/read", { sessionId: zcodeSid }, 8000);
|
|
3674
3656
|
const read = (readResp.result ?? {});
|
|
3675
3657
|
const todos = flattenTodos(read.todos, read.todoGroups);
|