@aexol/spectral 0.9.198 → 0.9.200

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.
@@ -19,6 +19,8 @@
19
19
  *
20
20
  * Flag surface:
21
21
  * - `--machine-name <name>` — display name used at registration time.
22
+ * - `SPECTRAL_MACHINE_NAME` — fallback display name used when the flag is
23
+ * not supplied. The flag takes precedence over the environment variable.
22
24
  * - `--port <n>` / `-p <n>` / `SPECTRAL_PORT` — accepted but warned-and-ignored
23
25
  * so users updating from the pre-relay version don't get a hard error.
24
26
  *
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAwBH,OAAO,EAAE,WAAW,EAAmB,MAAM,oBAAoB,CAAC;AAWlE,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAYrE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAazD;AAED,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,CA6B9D;AAED,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,uCAAuC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;CAC/E;AAED,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,KAAK,EAAE,YAAY,CAAC;IACpB,wDAAwD;IACxD,OAAO,EAAE,oBAAoB,CAAC;IAC9B,4CAA4C;IAC5C,KAAK,EAAE,WAAW,CAAC;IACnB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAsB,QAAQ,CAAC,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAiiBlF;AA+DD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAa5E"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAwBH,OAAO,EAAE,WAAW,EAAmB,MAAM,oBAAoB,CAAC;AAYlE,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAYrE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAazD;AAED,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,CA6B9D;AAED,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,uCAAuC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;CAC/E;AAED,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,KAAK,EAAE,YAAY,CAAC;IACpB,wDAAwD;IACxD,OAAO,EAAE,oBAAoB,CAAC;IAC9B,4CAA4C;IAC5C,KAAK,EAAE,WAAW,CAAC;IACnB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAsB,QAAQ,CAAC,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAwiBlF;AA+DD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAc5E"}
@@ -19,6 +19,8 @@
19
19
  *
20
20
  * Flag surface:
21
21
  * - `--machine-name <name>` — display name used at registration time.
22
+ * - `SPECTRAL_MACHINE_NAME` — fallback display name used when the flag is
23
+ * not supplied. The flag takes precedence over the environment variable.
22
24
  * - `--port <n>` / `-p <n>` / `SPECTRAL_PORT` — accepted but warned-and-ignored
23
25
  * so users updating from the pre-relay version don't get a hard error.
24
26
  *
@@ -37,6 +39,7 @@ import { getAgentDir } from "../sdk/coding-agent/config.js";
37
39
  import { refreshCloudAgents as refreshCloudAgentsImpl } from "../agent/agents.js";
38
40
  import { requireLogin } from "../preflight.js";
39
41
  import { RelayClient } from "../relay/client.js";
42
+ import { getFanoutManager } from "../server/fanout/fanout-manager.js";
40
43
  import { detachAllSubscribers, handleAutoOptimizeFrame, handleAutoResearchFrame, handleCancelTurn, handleClientMessage, handleRestRequest, handleSubscribe, } from "../relay/dispatcher.js";
41
44
  import { ensureMachineRegistered } from "../relay/registration.js";
42
45
  import { saveMachine } from "../relay/machine-store.js";
@@ -240,6 +243,12 @@ export async function runServe(opts = {}) {
240
243
  onCloudAgentsAuthRejected: (reason) => forceReRegister(reason),
241
244
  });
242
245
  managerRef.current = manager;
246
+ // Fanout worker sessions are created directly in the store, outside the
247
+ // REST dispatcher, so nothing would notify connected tabs — they only
248
+ // appeared after a manual refresh. Publish `session_created` through the
249
+ // same deferred wrapper the dispatcher uses (no-ops until the relay is
250
+ // up, then fans out to every subscribed client).
251
+ getFanoutManager()?.setMetaEventPublisher(deferredPublishMetaEvent);
243
252
  if (!silent) {
244
253
  const action = registration.reused ? "Reusing" : "Registered";
245
254
  process.stdout.write(`${action} machine "${registration.record.machineName}" (${registration.record.machineId})\n`);
@@ -670,11 +679,12 @@ async function handleConfigPatch(frame, deps) {
670
679
  */
671
680
  export async function runServeCli(rawArgs) {
672
681
  const parsed = parseServeArgs(rawArgs);
682
+ const machineName = parsed.machineName ?? process.env.SPECTRAL_MACHINE_NAME;
673
683
  if (parsed.deprecatedPort || process.env.SPECTRAL_PORT) {
674
684
  process.stderr.write(`warning: --port / SPECTRAL_PORT are no longer used. ` +
675
685
  `spectral serve now connects outbound to the Aexol relay; there is no local port to bind.\n`);
676
686
  }
677
687
  return runServe({
678
- machineName: parsed.machineName,
688
+ machineName,
679
689
  });
680
690
  }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Session Fanout — native spectral extension.
3
+ *
4
+ * Registers a single tool, `session_fanout`, that spawns multiple parallel
5
+ * worker sessions in the current project — one real session per task, each
6
+ * running the given prompt autonomously. Sessions appear immediately in the
7
+ * Studio session list; each worker's final message is its report.
8
+ *
9
+ * Fire-and-forget by design: no progress API, no result collection. The
10
+ * orchestrating agent only reports which sessions were created.
11
+ *
12
+ * Guardrails live in FanoutManager (src/server/fanout/fanout-manager.ts):
13
+ * recursion block, 20-task hard cap, concurrency semaphore, one active run
14
+ * per project, prompt dedupe/length limits.
15
+ */
16
+ import type { ExtensionAPI } from "../../sdk/coding-agent/index.js";
17
+ export declare const SESSION_FANOUT_TOOL_NAME = "session_fanout";
18
+ export default function sessionFanoutExtension(ext: ExtensionAPI): Promise<void>;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/session-fanout/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAEX,YAAY,EAEZ,MAAM,iCAAiC,CAAC;AASzC,eAAO,MAAM,wBAAwB,mBAAmB,CAAC;AAuCzD,wBAA8B,sBAAsB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA+GrF"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Session Fanout — native spectral extension.
3
+ *
4
+ * Registers a single tool, `session_fanout`, that spawns multiple parallel
5
+ * worker sessions in the current project — one real session per task, each
6
+ * running the given prompt autonomously. Sessions appear immediately in the
7
+ * Studio session list; each worker's final message is its report.
8
+ *
9
+ * Fire-and-forget by design: no progress API, no result collection. The
10
+ * orchestrating agent only reports which sessions were created.
11
+ *
12
+ * Guardrails live in FanoutManager (src/server/fanout/fanout-manager.ts):
13
+ * recursion block, 20-task hard cap, concurrency semaphore, one active run
14
+ * per project, prompt dedupe/length limits.
15
+ */
16
+ import { getFanoutManager, MAX_TASKS_PER_FANOUT, FanoutError, } from "../../server/fanout/fanout-manager.js";
17
+ export const SESSION_FANOUT_TOOL_NAME = "session_fanout";
18
+ function fail(message) {
19
+ return {
20
+ content: [{ type: "text", text: `❌ session_fanout: ${message}` }],
21
+ details: { status: "error" },
22
+ };
23
+ }
24
+ function renderResult(result) {
25
+ const lines = [
26
+ `✅ Fanout ${result.runLabel} started: ${result.sessions.length} worker session(s) created ` +
27
+ `(max ${result.maxConcurrent} running at once).`,
28
+ "",
29
+ ];
30
+ for (const session of result.sessions) {
31
+ lines.push(`- ${session.key} → ${session.sessionId} "${session.title}"`);
32
+ }
33
+ if (result.skipped.length > 0) {
34
+ lines.push("", "Skipped tasks:");
35
+ for (const s of result.skipped) {
36
+ lines.push(`- ${s.key}: ${s.reason}`);
37
+ }
38
+ }
39
+ lines.push("", "The worker sessions are now visible in the session list. Each worker writes its report " +
40
+ "as the final message of its own session. Do not wait for them and do not poll — " +
41
+ "just tell the user the fanout is running and where to look.");
42
+ return lines.join("\n");
43
+ }
44
+ export default async function sessionFanoutExtension(ext) {
45
+ const tool = {
46
+ name: SESSION_FANOUT_TOOL_NAME,
47
+ label: "Session Fanout",
48
+ description: "Spawn multiple parallel worker sessions in the current project — one real session per task, " +
49
+ "each executing its own prompt autonomously. Sessions appear in the session list immediately. " +
50
+ `Use for batches of INDEPENDENT research/analysis tasks (e.g. gap analysis of up to ` +
51
+ `${MAX_TASKS_PER_FANOUT} well-described tasks against the codebase). Fire-and-forget: there is no ` +
52
+ "result collection — the user reads each worker's report in its own session, so each task prompt " +
53
+ "must be fully self-contained. Limits: max 20 tasks per call, 4 concurrent by default (hard cap 8), " +
54
+ "one active fanout per project, worker sessions cannot spawn further fanouts. " +
55
+ "Do NOT use for fewer than 2 tasks, and do NOT use it to run code edits in parallel.",
56
+ promptSnippet: "`session_fanout` — spawn parallel worker sessions for a batch of independent tasks (fire-and-forget; use sparingly)",
57
+ promptGuidelines: [
58
+ "Not a default tool: prefer doing the work in the current session, or the subagent tool when you need results returned to you; reach for session_fanout only for large batches (roughly 5 or more) of genuinely independent tasks, or when the user explicitly asks for parallel sessions.",
59
+ "Never for a single task, and never for quick lookups you can do yourself with grep/read — each spawned session is a real agent run that costs tokens and clutters the user's session list.",
60
+ "Never for code edits in parallel — worker sessions run in the same project without coordination.",
61
+ "Each task prompt must be self-contained — worker sessions share no context with you.",
62
+ "After spawning, report the created session ids/titles to the user and stop; results are read in the worker sessions themselves.",
63
+ ],
64
+ parameters: {
65
+ type: "object",
66
+ properties: {
67
+ tasks: {
68
+ type: "array",
69
+ description: `1-${MAX_TASKS_PER_FANOUT} tasks; one worker session is created per task.`,
70
+ items: {
71
+ type: "object",
72
+ properties: {
73
+ key: {
74
+ type: "string",
75
+ description: "Short stable identifier of the task, e.g. 'task-3'.",
76
+ },
77
+ title: {
78
+ type: "string",
79
+ description: "Human-readable session title (shown in the session list).",
80
+ },
81
+ prompt: {
82
+ type: "string",
83
+ description: "Full, self-contained prompt for the worker session (goal, scope, what the final report must contain).",
84
+ },
85
+ },
86
+ required: ["key", "title", "prompt"],
87
+ },
88
+ },
89
+ maxConcurrent: {
90
+ type: "number",
91
+ description: "Max worker prompts running at the same time (1-8, default 4).",
92
+ },
93
+ },
94
+ required: ["tasks"],
95
+ },
96
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
97
+ const fanout = getFanoutManager();
98
+ if (!fanout) {
99
+ return fail("session_fanout needs the server-side session manager, which only exists in sessions " +
100
+ "hosted by a `spectral serve` process. Standalone CLI sessions have no session store, " +
101
+ "so there is nothing to spawn worker sessions into.");
102
+ }
103
+ const sessionId = ctx?.sessionManager?.getSessionId?.() ?? "";
104
+ if (!sessionId) {
105
+ return fail("no session context.");
106
+ }
107
+ if (fanout.isFanoutChild(sessionId)) {
108
+ return fail("worker sessions cannot spawn further fanouts (recursion blocked).");
109
+ }
110
+ const cwd = ctx?.cwd ?? process.cwd();
111
+ const projectId = fanout.resolveProjectId(cwd);
112
+ if (!projectId) {
113
+ return fail(`no project is registered for working directory ${cwd}.`);
114
+ }
115
+ const rawTasks = params.tasks;
116
+ if (!Array.isArray(rawTasks)) {
117
+ return fail("`tasks` must be an array of {key, title, prompt}.");
118
+ }
119
+ const tasks = rawTasks.map((t) => ({
120
+ key: typeof t?.key === "string" ? t.key : "",
121
+ title: typeof t?.title === "string" ? t.title : "",
122
+ prompt: typeof t?.prompt === "string" ? t.prompt : "",
123
+ }));
124
+ const maxConcurrent = typeof params.maxConcurrent === "number" ? params.maxConcurrent : undefined;
125
+ try {
126
+ const result = fanout.start({ parentSessionId: sessionId, projectId, tasks, maxConcurrent });
127
+ return {
128
+ content: [{ type: "text", text: renderResult(result) }],
129
+ details: { status: "started", ...result },
130
+ };
131
+ }
132
+ catch (err) {
133
+ const msg = err instanceof FanoutError ? err.message : err instanceof Error ? err.message : String(err);
134
+ return fail(msg);
135
+ }
136
+ },
137
+ };
138
+ ext.registerTool(tool);
139
+ }
@@ -143,6 +143,7 @@ export declare class RelayClient extends EventEmitter {
143
143
  private stopWatchdog;
144
144
  private startHeartbeat;
145
145
  private stopHeartbeat;
146
+ private isRestResponseWire;
146
147
  private enqueueWire;
147
148
  private clearSendInFlight;
148
149
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/relay/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/relay/client.ts"],"names":[],"mappings":"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"}
@@ -49,6 +49,8 @@ import WebSocket from "ws";
49
49
  import { getMachineFile } from "./machine-store.js";
50
50
  /** Maximum outbound queue size while disconnected. */
51
51
  const SEND_QUEUE_CAP = 100;
52
+ /** History chunks are large but low-priority — drop before any rest_response. */
53
+ const HISTORY_CHUNK_DROP_PRIORITY = true;
52
54
  /** Backoff schedule (ms). The last value is the cap and is reused indefinitely. */
53
55
  const RECONNECT_SCHEDULE = [1000, 2000, 5000, 15000, 30000];
54
56
  /** ±20% jitter on each scheduled delay. */
@@ -327,13 +329,40 @@ export class RelayClient extends EventEmitter {
327
329
  this.heartbeatPending = false;
328
330
  }
329
331
  // --- outbound send safety ---------------------------------------------------
332
+ isRestResponseWire(wire) {
333
+ return wire.includes('"kind":"rest_response"');
334
+ }
330
335
  enqueueWire(wire) {
331
336
  if (this.sendQueue.length >= SEND_QUEUE_CAP) {
332
- // Never evict the frame currently awaiting a write callback — it is
333
- // still at the front of the queue and must survive a reconnect.
334
- const dropIndex = this.sendInFlight !== null ? 1 : 0;
335
- if (this.sendQueue.length > dropIndex) {
336
- this.sendQueue.splice(dropIndex, 1);
337
+ const isRest = this.isRestResponseWire(wire);
338
+ if (HISTORY_CHUNK_DROP_PRIORITY) {
339
+ const start = this.sendInFlight !== null ? 1 : 0;
340
+ let victim = -1;
341
+ for (let i = this.sendQueue.length - 1; i >= start; i--) {
342
+ if (!this.isRestResponseWire(this.sendQueue[i])) {
343
+ victim = i;
344
+ break;
345
+ }
346
+ }
347
+ if (victim >= 0) {
348
+ this.sendQueue.splice(victim, 1);
349
+ }
350
+ else if (!isRest) {
351
+ // Queue is full of rest_responses — fall back to oldest-dropped.
352
+ this.sendQueue.splice(start, 1);
353
+ }
354
+ else {
355
+ // Enqueueing a rest_response when every queued frame is a
356
+ // rest_response: still drop the oldest — REST must not be lost
357
+ // to non-REST, but one REST may yield to a newer one.
358
+ this.sendQueue.splice(start, 1);
359
+ }
360
+ }
361
+ else {
362
+ const dropIndex = this.sendInFlight !== null ? 1 : 0;
363
+ if (this.sendQueue.length > dropIndex) {
364
+ this.sendQueue.splice(dropIndex, 1);
365
+ }
337
366
  }
338
367
  }
339
368
  this.sendQueue.push(wire);
@@ -1 +1 @@
1
- {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/relay/dispatcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/relay/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAQH,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACf,MAAM,uBAAuB,CAAC;AAK/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAkDzD,OAAO,KAAK,EAEV,oBAAoB,EACpB,UAAU,EACX,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAS5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAW/C;;;GAGG;AACH,UAAU,UAAU;IAClB,KAAK,EACD,eAAe,GACf,gBAAgB,GAChB,gBAAgB,GAChB,gBAAgB,GAChB,aAAa,GACb,eAAe,GACf,0BAA0B,GAC1B,uBAAuB,GACvB,0BAA0B,GAC1B,gBAAgB,GAChB,aAAa,GACb,0BAA0B,GAC1B,6BAA6B,GAC7B,sBAAsB,GACtB,gBAAgB,GAChB,gBAAgB,GAChB,oBAAoB,GACpB,4BAA4B,GAC5B,iBAAiB,GACjB,6BAA6B,GAC7B,cAAc,GACd,wBAAwB,GACxB,gBAAgB,GAChB,gBAAgB,GAChB,oBAAoB,GACpB,sBAAsB,GACtB,gBAAgB,GAChB,kBAAkB,GAClB,eAAe,GACf,oBAAoB,GACpB,iBAAiB,GACjB,mBAAmB,GACnB,2BAA2B,GAC3B,sBAAsB,GACtB,cAAc,GACd,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,8BAA8B,GAC9B,8BAA8B,GAC9B,cAAc,GACd,aAAa,GACb,oBAAoB,GACpB,mBAAmB,GACnB,kBAAkB,GAClB,qBAAqB,GACrB,kBAAkB,GAClB,iBAAiB,CAAC;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gEAAgE;IAChE,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,UAAU,GAAG,IAAI,CAsPnB;AAMD;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,6FAA6F;IAC7F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uGAAuG;IACvG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QACrC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;KACrC,CAAC;IACF;;;;OAIG;IACH,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,wEAAwE;IACxE,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EACF,YAAY,GACZ,oBAAoB,GACpB,SAAS,GACT,WAAW,GACX,iBAAiB,GACjB,qBAAqB,GACrB,cAAc,GACd,QAAQ,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAuUD,wBAAsB,gBAAgB,CAAC,SAAS,SAAY,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuBxF;AA8GD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAoE5B;AA2eD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,oBAAoB,CAAC;IAC9B,2DAA2D;IAC3D,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACjC;;;;;;;;;OASG;IACH,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,yEAAyE;IACzE,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;CAClD;AA0HD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,kBAAkB,EACzB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,IAAI,CAAC,CA2Lf;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,IAAI,CAAC,CAmDf;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE;IAAE,OAAO,EAAE,oBAAoB,CAAC;IAAC,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAA;CAAE,GACxF,IAAI,CAEN;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,oBAAoB,EAC7B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,GACnC,IAAI,CASN;AAMD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACjC,sDAAsD;IACtD,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;CAClD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,iBAAiB,EACxB,IAAI,EAAE,gBAAgB,GACrB,IAAI,CAQN;AAED,oEAAoE;AACpE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;CAClD;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,iBAAiB,EACxB,IAAI,EAAE,gBAAgB,GACrB,IAAI,CAUN"}
@@ -1104,18 +1104,20 @@ async function dispatchRoute(match, body, deps) {
1104
1104
  case "list_agents": {
1105
1105
  const agentCwd = match.query?.get("cwd") || deps.cwd || homedir();
1106
1106
  const teamId = match.query?.get("teamId") || undefined;
1107
- // Ensure cloud agents are fresh before listing. The bridge's cache is
1108
- // only populated when a session starts a message; without this refresh
1109
- // backend agents don't appear in the picker until the first message.
1107
+ // Kick off cloud refresh in the background without blocking the response.
1108
+ // The previous version awaited refreshCloudAgents (network backend GraphQL)
1109
+ // before returning, so every page refresh stalled the entire REST queue
1110
+ // behind this one slow call while 5-7 other rest_requests timed out.
1111
+ // Background refresh self-dedupes via CloudAgentCacheEntry.inFlight, so
1112
+ // bursts coalesce; stale cache renders immediately and the picker catches
1113
+ // up on the next meta_event/live refresh.
1110
1114
  if (teamId && deps.refreshCloudAgents) {
1111
- try {
1112
- await deps.refreshCloudAgents(teamId);
1113
- }
1114
- catch (err) {
1115
+ void deps.refreshCloudAgents(teamId).catch((err) => {
1115
1116
  logger?.error?.(`[dispatcher] cloud agent refresh failed:`, err);
1116
- }
1117
+ });
1117
1118
  }
1118
- return handleListAgents(agentCwd, deps.agentDir, teamId);
1119
+ const agents = handleListAgents(agentCwd, deps.agentDir, teamId);
1120
+ return agents;
1119
1121
  }
1120
1122
  case "list_dev_processes":
1121
1123
  return handleListDevProcesses(deps.devProcessRegistry);
@@ -1 +1 @@
1
- {"version":3,"file":"native-extensions.d.ts","sourceRoot":"","sources":["../../../../../src/sdk/coding-agent/core/extensions/native-extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,aAAa,CAAC;IAChD;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,cAAc,EAAE,OAAO,CAAC;IACxB,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,uBAAuB,EAuItD,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS,CAElF;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAI1G;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;IAClG,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC,CAUD"}
1
+ {"version":3,"file":"native-extensions.d.ts","sourceRoot":"","sources":["../../../../../src/sdk/coding-agent/core/extensions/native-extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,aAAa,CAAC;IAChD;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,cAAc,EAAE,OAAO,CAAC;IACxB,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,uBAAuB,EAkJtD,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS,CAElF;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAI1G;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;IAClG,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC,CAUD"}
@@ -141,6 +141,16 @@ export const NATIVE_EXTENSIONS = [
141
141
  defaultEnabled: true,
142
142
  tags: ["ports", "devops", "services", "collision", "docker", "network"],
143
143
  },
144
+ {
145
+ id: "session-fanout",
146
+ label: "Session Fanout",
147
+ description: "Spawns parallel worker sessions for batches of independent tasks (e.g. research or gap analysis). " +
148
+ "One real session per task, fire-and-forget; reports are read in each worker session.",
149
+ category: "automation",
150
+ entryPath: "src/extensions/session-fanout/index.ts",
151
+ defaultEnabled: true,
152
+ tags: ["sessions", "parallel", "fanout", "orchestration"],
153
+ },
144
154
  ];
145
155
  /**
146
156
  * Look up a native extension by id. Returns undefined for unknown ids.
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../../../src/sdk/coding-agent/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,6FAA6F;IAC7F,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CA2L3E"}
1
+ {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../../../src/sdk/coding-agent/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,6FAA6F;IAC7F,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CA4L3E"}
@@ -95,7 +95,8 @@ export function buildSystemPrompt(options) {
95
95
  const head = customPrompt
96
96
  ? customPrompt
97
97
  : `You are an expert coding agent operating inside spectral, a coding agent harness. ${delegationIntro} When discussing effort, frame each enhancement around a ~20-hour coding scope tied to a concrete feature boundary, avoiding calendar-day or week-based estimates.
98
- Prefer taking action over over-analyzing. If you have a reasonable next step, take it; don't loop on planning or re-reading the same files. Rely on error feedback from commands/tests to correct course rather than trying to predict every failure in advance.
98
+ Be direct, helpful, and knowledgeable, and prioritize being genuinely useful over being verbose.
99
+ Be targeted and efficient in your exploration and investigation: search first, read only the files you need to act, and don't loop on planning or re-reading the same files. Prefer taking action over over-analyzing — if you have a reasonable next step, take it, and rely on error feedback from commands/tests to correct course rather than trying to predict every failure in advance.
99
100
 
100
101
  ## Recommended workflow
101
102
  Work in short, verifiable steps and iterate:
@@ -211,6 +211,13 @@ export declare class AgentBridge {
211
211
  private boundProjectId;
212
212
  private bindingWatcher?;
213
213
  private bindingWatcherTimer?;
214
+ /**
215
+ * Per-toolCallId trailing-edge throttle for `subagent_progress`. Keyed by
216
+ * the parent subagent tool call id so parallel/chain delegations coalesce
217
+ * independently. The pending event is the latest accumulated snapshot; the
218
+ * timer flushes it once the minimum interval has elapsed.
219
+ */
220
+ private subagentProgressThrottle;
214
221
  constructor(opts: AgentBridgeOptions);
215
222
  /**
216
223
  * Create the spectral session, wire up subscription, and return.
@@ -441,6 +448,24 @@ export declare class AgentBridge {
441
448
  * `events_jsonl` for the current assistant message.
442
449
  */
443
450
  private emitAndBuffer;
451
+ /**
452
+ * Live-only `subagent_progress` relay with a per-toolCallId trailing-edge
453
+ * throttle. The bridge receives `tool_execution_update` on every subagent
454
+ * token/thinking delta, each carrying the full accumulated snapshot. We
455
+ * coalesce those into at most one frame per
456
+ * `SUBAGENT_PROGRESS_MIN_INTERVAL_MS`, always keeping (and eventually
457
+ * flushing) the latest snapshot so the frontend's delta extraction still
458
+ * sees the complete transcript.
459
+ */
460
+ private emitSubagentProgressThrottled;
461
+ /**
462
+ * Flush any pending throttled `subagent_progress` frame immediately (used at
463
+ * subagent completion and prompt teardown so the latest state is not lost),
464
+ * then drop the throttle state for that tool call.
465
+ */
466
+ private flushSubagentProgress;
467
+ /** Flush and clear every pending throttled subagent progress frame. */
468
+ private flushAllSubagentProgress;
444
469
  /**
445
470
  * Finalize the current `pending` assistant message: persist its assembled
446
471
  * content + wire events (including any tool_call / tool_result events that
@@ -1 +1 @@
1
- {"version":3,"file":"agent-bridge.d.ts","sourceRoot":"","sources":["../../src/server/agent-bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-bridge.d.ts","sourceRoot":"","sources":["../../src/server/agent-bridge.ts"],"names":[],"mappings":"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"}
@@ -527,6 +527,17 @@ const PROMPT_INACTIVITY_TIMEOUT_MS = Number(process.env.SPECTRAL_PROMPT_INACTIVI
527
527
  * watchdog) with a descriptive message.
528
528
  */
529
529
  const TOOL_EXECUTION_TIMEOUT_MS = Number(process.env.SPECTRAL_TOOL_EXECUTION_TIMEOUT_MS) || 60 * 60 * 1000;
530
+ /**
531
+ * Minimum interval between live `subagent_progress` websocket frames for a
532
+ * single subagent tool invocation. Subagent streaming emits
533
+ * `tool_execution_update` on every token/thinking delta, and the bridge
534
+ * mirrors each one as a full accumulated snapshot. Relaying every delta
535
+ * floods the websocket with redundant O(n²) frames; we coalesce to at most
536
+ * one live frame per interval (trailing edge still flushes the latest state).
537
+ *
538
+ * Overridable via `SPECTRAL_SUBAGENT_PROGRESS_INTERVAL_MS`.
539
+ */
540
+ const SUBAGENT_PROGRESS_MIN_INTERVAL_MS = Number(process.env.SPECTRAL_SUBAGENT_PROGRESS_INTERVAL_MS) || 100;
530
541
  export class AgentBridge {
531
542
  session;
532
543
  suppressNextAgentEndForGeneration;
@@ -582,6 +593,13 @@ export class AgentBridge {
582
593
  boundProjectId = null;
583
594
  bindingWatcher;
584
595
  bindingWatcherTimer;
596
+ /**
597
+ * Per-toolCallId trailing-edge throttle for `subagent_progress`. Keyed by
598
+ * the parent subagent tool call id so parallel/chain delegations coalesce
599
+ * independently. The pending event is the latest accumulated snapshot; the
600
+ * timer flushes it once the minimum interval has elapsed.
601
+ */
602
+ subagentProgressThrottle = new Map();
585
603
  constructor(opts) {
586
604
  this.opts = opts;
587
605
  }
@@ -1502,6 +1520,10 @@ export class AgentBridge {
1502
1520
  this.promptActivityTimer = undefined;
1503
1521
  }
1504
1522
  this.clearToolExecutionTimer();
1523
+ // Flush any trailing throttled subagent progress so a turn that ends
1524
+ // (including via abort) never drops the last live snapshot, and clear
1525
+ // stale throttle timers so they can't fire into the next turn.
1526
+ this.flushAllSubagentProgress();
1505
1527
  this.promptReject = undefined;
1506
1528
  this.activeSubagents = 0;
1507
1529
  }
@@ -1595,6 +1617,74 @@ export class AgentBridge {
1595
1617
  this.pending.wireEvents.push(event);
1596
1618
  this.opts.emit(event);
1597
1619
  }
1620
+ /**
1621
+ * Live-only `subagent_progress` relay with a per-toolCallId trailing-edge
1622
+ * throttle. The bridge receives `tool_execution_update` on every subagent
1623
+ * token/thinking delta, each carrying the full accumulated snapshot. We
1624
+ * coalesce those into at most one frame per
1625
+ * `SUBAGENT_PROGRESS_MIN_INTERVAL_MS`, always keeping (and eventually
1626
+ * flushing) the latest snapshot so the frontend's delta extraction still
1627
+ * sees the complete transcript.
1628
+ */
1629
+ emitSubagentProgressThrottled(se) {
1630
+ const id = se.toolCallId;
1631
+ const now = Date.now();
1632
+ const slot = this.subagentProgressThrottle.get(id) ?? { lastEmitAt: 0 };
1633
+ slot.pending = se;
1634
+ this.subagentProgressThrottle.set(id, slot);
1635
+ const flush = () => {
1636
+ const current = this.subagentProgressThrottle.get(id);
1637
+ if (!current?.pending)
1638
+ return;
1639
+ const pending = current.pending;
1640
+ current.pending = undefined;
1641
+ current.timer = undefined;
1642
+ current.lastEmitAt = Date.now();
1643
+ this.subagentProgressThrottle.set(id, current);
1644
+ this.opts.emit(pending);
1645
+ };
1646
+ const elapsed = now - slot.lastEmitAt;
1647
+ if (elapsed >= SUBAGENT_PROGRESS_MIN_INTERVAL_MS) {
1648
+ if (slot.timer) {
1649
+ clearTimeout(slot.timer);
1650
+ slot.timer = undefined;
1651
+ }
1652
+ flush();
1653
+ }
1654
+ else if (!slot.timer) {
1655
+ slot.timer = setTimeout(flush, SUBAGENT_PROGRESS_MIN_INTERVAL_MS - elapsed);
1656
+ this.subagentProgressThrottle.set(id, slot);
1657
+ }
1658
+ }
1659
+ /**
1660
+ * Flush any pending throttled `subagent_progress` frame immediately (used at
1661
+ * subagent completion and prompt teardown so the latest state is not lost),
1662
+ * then drop the throttle state for that tool call.
1663
+ */
1664
+ flushSubagentProgress(toolCallId) {
1665
+ const slot = this.subagentProgressThrottle.get(toolCallId);
1666
+ if (!slot)
1667
+ return;
1668
+ if (slot.timer) {
1669
+ clearTimeout(slot.timer);
1670
+ slot.timer = undefined;
1671
+ }
1672
+ if (slot.pending) {
1673
+ const pending = slot.pending;
1674
+ slot.pending = undefined;
1675
+ this.subagentProgressThrottle.delete(toolCallId);
1676
+ this.opts.emit(pending);
1677
+ }
1678
+ else {
1679
+ this.subagentProgressThrottle.delete(toolCallId);
1680
+ }
1681
+ }
1682
+ /** Flush and clear every pending throttled subagent progress frame. */
1683
+ flushAllSubagentProgress() {
1684
+ for (const toolCallId of Array.from(this.subagentProgressThrottle.keys())) {
1685
+ this.flushSubagentProgress(toolCallId);
1686
+ }
1687
+ }
1598
1688
  /**
1599
1689
  * Finalize the current `pending` assistant message: persist its assembled
1600
1690
  * content + wire events (including any tool_call / tool_result events that
@@ -1856,7 +1946,7 @@ export class AgentBridge {
1856
1946
  // aborted by PROMPT_INACTIVITY_TIMEOUT_MS (default 10 min) even
1857
1947
  // though they are actively making progress.
1858
1948
  this.bumpPromptActivity();
1859
- this.opts.emit(se);
1949
+ this.emitSubagentProgressThrottled(se);
1860
1950
  }
1861
1951
  }
1862
1952
  return;
@@ -1874,6 +1964,10 @@ export class AgentBridge {
1874
1964
  // finishes. The subagent's own timeout already governed the child;
1875
1965
  // the parent resumes normal silence-based protection from here.
1876
1966
  this.resumePromptActivityAfterSubagent();
1967
+ // Flush any throttled progress that hasn't hit its interval yet so
1968
+ // the frontend never misses the final accumulated state before the
1969
+ // terminal subagent_end/tool_result frames.
1970
+ this.flushSubagentProgress(ev.toolCallId);
1877
1971
  const result = ev.result;
1878
1972
  const details = result?.details;
1879
1973
  if (details?.results && details.results.length > 0) {
@@ -0,0 +1,126 @@
1
+ /**
2
+ * FanoutManager — spawns parallel "worker" sessions for a batch of tasks.
3
+ *
4
+ * The main agent calls the `session_fanout` tool with a list of independent
5
+ * tasks (e.g. gap analysis of 20 well-described tasks against the codebase).
6
+ * Each task becomes a REAL session in the current project: a record is
7
+ * created in SQLite up front (so it appears in the Studio session list
8
+ * immediately) and the task prompt is sent through the existing
9
+ * SessionStreamManager, subject to a concurrency semaphore.
10
+ *
11
+ * Fire-and-forget: the manager does not collect results — the user reads
12
+ * each worker's final message directly in its session. State is process-
13
+ * local (no new tables); after a restart of `spectral serve` pending worker
14
+ * turns simply finish like any other session, and the in-memory recursion
15
+ * guard resets (recursion stays blocked at the tool-registration level
16
+ * because spawned sessions never outlive the manager's knowledge of them —
17
+ * see the session-fanout extension).
18
+ *
19
+ * Wiring: `configureFanout()` is called once from the SessionStreamManager
20
+ * constructor (next to `setInterAgentBroker`), which is the single place
21
+ * where both the manager and the SessionStore are available.
22
+ */
23
+ import type { MetaEvent } from "@aexol/relay-protocol";
24
+ import type { SessionStore } from "../storage.js";
25
+ import type { SessionStreamManager } from "../session-stream.js";
26
+ /** Hard cap on tasks accepted per `start()` call. */
27
+ export declare const MAX_TASKS_PER_FANOUT = 20;
28
+ /** Default number of worker prompts running at the same time. */
29
+ export declare const DEFAULT_MAX_CONCURRENT = 4;
30
+ /** Hard cap on the per-run concurrency requested by the caller. */
31
+ export declare const HARD_CAP_CONCURRENT = 8;
32
+ /** Maximum length of a single task prompt. Longer tasks are skipped. */
33
+ export declare const MAX_PROMPT_LENGTH = 12000;
34
+ /** Maximum length of a task title. */
35
+ export declare const MAX_TITLE_LENGTH = 120;
36
+ /** Maximum length of a task key. */
37
+ export declare const MAX_KEY_LENGTH = 80;
38
+ export interface FanoutTask {
39
+ key: string;
40
+ title: string;
41
+ prompt: string;
42
+ }
43
+ export interface FanoutStartInput {
44
+ parentSessionId: string;
45
+ projectId: string;
46
+ tasks: FanoutTask[];
47
+ maxConcurrent?: number;
48
+ }
49
+ export interface FanoutSessionRef {
50
+ key: string;
51
+ sessionId: string;
52
+ title: string;
53
+ }
54
+ export interface FanoutStartResult {
55
+ runId: string;
56
+ runLabel: string;
57
+ /** Concurrency actually applied after clamping. */
58
+ maxConcurrent: number;
59
+ sessions: FanoutSessionRef[];
60
+ /** Tasks rejected during validation, with a human-readable reason. */
61
+ skipped: Array<{
62
+ key: string;
63
+ reason: string;
64
+ }>;
65
+ }
66
+ /** Minimal surface of SessionStreamManager used by the fanout. */
67
+ export interface FanoutManagerDeps {
68
+ manager: Pick<SessionStreamManager, "attach" | "prompt">;
69
+ store: Pick<SessionStore, "createSession" | "getProjectByCwd" | "appendMessage">;
70
+ /**
71
+ * Optional meta-event publisher — the same channel the REST dispatcher
72
+ * uses. Publishing `session_created` after each store.createSession is
73
+ * what makes fanout-spawned sessions appear live in connected UIs;
74
+ * without it they only show up after a manual refresh.
75
+ */
76
+ publishMetaEvent?: (event: MetaEvent) => void;
77
+ }
78
+ /** Error carrying a user-readable reason (surfaced verbatim in the tool result). */
79
+ export declare class FanoutError extends Error {
80
+ }
81
+ export declare class FanoutManager {
82
+ private deps;
83
+ private readonly runs;
84
+ private readonly activeRunsByProject;
85
+ /** Every session ever spawned by a fanout in this process (recursion guard). */
86
+ private readonly spawnedSessionIds;
87
+ private runCounter;
88
+ /** Global concurrency cap across all runs (protects multi-project usage). */
89
+ private readonly globalSemaphore;
90
+ private readonly logger;
91
+ constructor(logger?: {
92
+ error: (...args: unknown[]) => void;
93
+ });
94
+ configure(deps: FanoutManagerDeps): void;
95
+ /**
96
+ * Wire the meta-event publisher (serve.ts, after the manager exists —
97
+ * the deferred wrapper no-ops until the relay is up, so ordering is
98
+ * safe). Without a publisher the tool still works; clients just don't
99
+ * get live session-list updates.
100
+ */
101
+ setMetaEventPublisher(publish: NonNullable<FanoutManagerDeps["publishMetaEvent"]>): void;
102
+ /** Resolve the project id for a working directory, or null. */
103
+ resolveProjectId(cwd: string): string | null;
104
+ /** True if the session was ever spawned as a fanout worker in this process. */
105
+ isFanoutChild(sessionId: string): boolean;
106
+ /**
107
+ * Validate input, create one session per accepted task (immediately
108
+ * visible in the session list) and kick off prompt dispatch in the
109
+ * background. Returns as soon as records exist — never awaits turns.
110
+ */
111
+ start(input: FanoutStartInput): FanoutStartResult;
112
+ private createWorkerSessions;
113
+ /**
114
+ * Publish `session_created` over the relay meta channel so every
115
+ * subscribed tab refreshes its session list immediately. Mirrors the
116
+ * dispatcher's safePublish: failures are logged, never propagated —
117
+ * the session record already exists.
118
+ */
119
+ private publishSessionCreated;
120
+ private executeRun;
121
+ }
122
+ export declare function configureFanout(deps: FanoutManagerDeps): FanoutManager;
123
+ export declare function getFanoutManager(): FanoutManager | null;
124
+ /** Test-only: drop the configured singleton. */
125
+ export declare function resetFanoutManager(): void;
126
+ //# sourceMappingURL=fanout-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fanout-manager.d.ts","sourceRoot":"","sources":["../../../src/server/fanout/fanout-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,344 @@
1
+ /**
2
+ * FanoutManager — spawns parallel "worker" sessions for a batch of tasks.
3
+ *
4
+ * The main agent calls the `session_fanout` tool with a list of independent
5
+ * tasks (e.g. gap analysis of 20 well-described tasks against the codebase).
6
+ * Each task becomes a REAL session in the current project: a record is
7
+ * created in SQLite up front (so it appears in the Studio session list
8
+ * immediately) and the task prompt is sent through the existing
9
+ * SessionStreamManager, subject to a concurrency semaphore.
10
+ *
11
+ * Fire-and-forget: the manager does not collect results — the user reads
12
+ * each worker's final message directly in its session. State is process-
13
+ * local (no new tables); after a restart of `spectral serve` pending worker
14
+ * turns simply finish like any other session, and the in-memory recursion
15
+ * guard resets (recursion stays blocked at the tool-registration level
16
+ * because spawned sessions never outlive the manager's knowledge of them —
17
+ * see the session-fanout extension).
18
+ *
19
+ * Wiring: `configureFanout()` is called once from the SessionStreamManager
20
+ * constructor (next to `setInterAgentBroker`), which is the single place
21
+ * where both the manager and the SessionStore are available.
22
+ */
23
+ // ---------------------------------------------------------------------------
24
+ // Guardrail constants
25
+ // ---------------------------------------------------------------------------
26
+ /** Hard cap on tasks accepted per `start()` call. */
27
+ export const MAX_TASKS_PER_FANOUT = 20;
28
+ /** Default number of worker prompts running at the same time. */
29
+ export const DEFAULT_MAX_CONCURRENT = 4;
30
+ /** Hard cap on the per-run concurrency requested by the caller. */
31
+ export const HARD_CAP_CONCURRENT = 8;
32
+ /** Maximum length of a single task prompt. Longer tasks are skipped. */
33
+ export const MAX_PROMPT_LENGTH = 12_000;
34
+ /** Maximum length of a task title. */
35
+ export const MAX_TITLE_LENGTH = 120;
36
+ /** Maximum length of a task key. */
37
+ export const MAX_KEY_LENGTH = 80;
38
+ /** Error carrying a user-readable reason (surfaced verbatim in the tool result). */
39
+ export class FanoutError extends Error {
40
+ }
41
+ // ---------------------------------------------------------------------------
42
+ // Semaphore
43
+ // ---------------------------------------------------------------------------
44
+ class Semaphore {
45
+ capacity;
46
+ active = 0;
47
+ waiters = [];
48
+ constructor(capacity) {
49
+ this.capacity = capacity;
50
+ }
51
+ /** Resolves with the release function once a slot is available. */
52
+ async acquire() {
53
+ if (this.active < this.capacity) {
54
+ this.active++;
55
+ return () => this.release();
56
+ }
57
+ return new Promise((resolve) => {
58
+ this.waiters.push(() => {
59
+ this.active++;
60
+ resolve(() => this.release());
61
+ });
62
+ });
63
+ }
64
+ release() {
65
+ this.active--;
66
+ const next = this.waiters.shift();
67
+ if (next)
68
+ next();
69
+ }
70
+ }
71
+ // ---------------------------------------------------------------------------
72
+ // Manager
73
+ // ---------------------------------------------------------------------------
74
+ const noopSubscriber = {
75
+ send: () => { },
76
+ isOpen: () => false,
77
+ };
78
+ export class FanoutManager {
79
+ deps = null;
80
+ runs = new Map();
81
+ activeRunsByProject = new Map();
82
+ /** Every session ever spawned by a fanout in this process (recursion guard). */
83
+ spawnedSessionIds = new Set();
84
+ runCounter = 0;
85
+ /** Global concurrency cap across all runs (protects multi-project usage). */
86
+ globalSemaphore = new Semaphore(HARD_CAP_CONCURRENT);
87
+ logger;
88
+ constructor(logger) {
89
+ this.logger = logger ?? console;
90
+ }
91
+ configure(deps) {
92
+ this.deps = deps;
93
+ }
94
+ /**
95
+ * Wire the meta-event publisher (serve.ts, after the manager exists —
96
+ * the deferred wrapper no-ops until the relay is up, so ordering is
97
+ * safe). Without a publisher the tool still works; clients just don't
98
+ * get live session-list updates.
99
+ */
100
+ setMetaEventPublisher(publish) {
101
+ if (!this.deps)
102
+ return; // not configured yet — nothing would receive it
103
+ this.deps.publishMetaEvent = publish;
104
+ }
105
+ /** Resolve the project id for a working directory, or null. */
106
+ resolveProjectId(cwd) {
107
+ return this.deps?.store.getProjectByCwd(cwd) ?? null;
108
+ }
109
+ /** True if the session was ever spawned as a fanout worker in this process. */
110
+ isFanoutChild(sessionId) {
111
+ return this.spawnedSessionIds.has(sessionId);
112
+ }
113
+ /**
114
+ * Validate input, create one session per accepted task (immediately
115
+ * visible in the session list) and kick off prompt dispatch in the
116
+ * background. Returns as soon as records exist — never awaits turns.
117
+ */
118
+ start(input) {
119
+ if (!this.deps) {
120
+ throw new FanoutError("session_fanout is only available while `spectral serve` is running.");
121
+ }
122
+ if (typeof input.parentSessionId !== "string" || input.parentSessionId.length === 0) {
123
+ throw new FanoutError("parentSessionId is required.");
124
+ }
125
+ if (typeof input.projectId !== "string" || input.projectId.length === 0) {
126
+ throw new FanoutError("projectId is required.");
127
+ }
128
+ if (this.isFanoutChild(input.parentSessionId)) {
129
+ throw new FanoutError("Recursion blocked: fanout worker sessions cannot spawn further fanouts.");
130
+ }
131
+ const activeRunId = this.activeRunsByProject.get(input.projectId);
132
+ if (activeRunId) {
133
+ throw new FanoutError(`A fanout run is already active in this project (${activeRunId}). ` +
134
+ "Wait for its workers to finish before starting another one.");
135
+ }
136
+ if (!Array.isArray(input.tasks) || input.tasks.length === 0) {
137
+ throw new FanoutError("`tasks` must be a non-empty array of {key, title, prompt}.");
138
+ }
139
+ if (input.tasks.length > MAX_TASKS_PER_FANOUT) {
140
+ throw new FanoutError(`Too many tasks: ${input.tasks.length} (hard cap ${MAX_TASKS_PER_FANOUT}). ` +
141
+ "Split the work into multiple smaller fanouts over several turns.");
142
+ }
143
+ this.runCounter++;
144
+ const runLabel = `F${this.runCounter}`;
145
+ const { sessions, skipped } = this.createWorkerSessions(input.tasks, input.projectId, runLabel);
146
+ if (sessions.length === 0) {
147
+ this.runCounter--;
148
+ throw new FanoutError("No valid tasks: " + (skipped.map((s) => `${s.key}: ${s.reason}`).join("; ") || "empty input."));
149
+ }
150
+ const maxConcurrent = clampConcurrency(input.maxConcurrent);
151
+ const runId = `fanout_${Date.now()}_${this.runCounter}`;
152
+ const run = {
153
+ runId,
154
+ runLabel,
155
+ projectId: input.projectId,
156
+ parentSessionId: input.parentSessionId,
157
+ childSessionIds: new Set(sessions.map((s) => s.sessionId)),
158
+ finished: false,
159
+ };
160
+ for (const session of sessions) {
161
+ this.spawnedSessionIds.add(session.sessionId);
162
+ }
163
+ this.runs.set(runId, run);
164
+ this.activeRunsByProject.set(input.projectId, runId);
165
+ // Background dispatch — never awaited by the tool (fire-and-forget).
166
+ void this.executeRun(run, input.tasks, sessions, maxConcurrent);
167
+ return { runId, runLabel, maxConcurrent, sessions, skipped };
168
+ }
169
+ // -------------------------------------------------------------------------
170
+ // Internals
171
+ // -------------------------------------------------------------------------
172
+ createWorkerSessions(tasks, projectId, runLabel) {
173
+ const store = this.deps?.store;
174
+ if (!store)
175
+ throw new FanoutError("FanoutManager is not configured.");
176
+ const seenPrompts = new Set();
177
+ const seenKeys = new Set();
178
+ const sessions = [];
179
+ const skipped = [];
180
+ for (const task of tasks) {
181
+ const key = typeof task?.key === "string" ? task.key.trim() : "";
182
+ const title = typeof task?.title === "string" ? task.title.trim() : "";
183
+ const prompt = typeof task?.prompt === "string" ? task.prompt.trim() : "";
184
+ if (!key) {
185
+ skipped.push({ key: "(missing)", reason: "missing key" });
186
+ continue;
187
+ }
188
+ if (!title || !prompt) {
189
+ skipped.push({ key, reason: "missing title or prompt" });
190
+ continue;
191
+ }
192
+ if (key.length > MAX_KEY_LENGTH) {
193
+ skipped.push({ key, reason: `key longer than ${MAX_KEY_LENGTH} chars` });
194
+ continue;
195
+ }
196
+ if (title.length > MAX_TITLE_LENGTH) {
197
+ skipped.push({ key, reason: `title longer than ${MAX_TITLE_LENGTH} chars` });
198
+ continue;
199
+ }
200
+ if (prompt.length > MAX_PROMPT_LENGTH) {
201
+ skipped.push({ key, reason: `prompt longer than ${MAX_PROMPT_LENGTH} chars` });
202
+ continue;
203
+ }
204
+ if (seenPrompts.has(prompt)) {
205
+ skipped.push({ key, reason: "duplicate prompt" });
206
+ continue;
207
+ }
208
+ if (seenKeys.has(key)) {
209
+ skipped.push({ key, reason: "duplicate key" });
210
+ continue;
211
+ }
212
+ seenPrompts.add(prompt);
213
+ seenKeys.add(key);
214
+ try {
215
+ const summary = store.createSession({
216
+ projectId,
217
+ title: `[${runLabel}] ${title}`,
218
+ });
219
+ sessions.push({ key, sessionId: summary.id, title: summary.title });
220
+ this.publishSessionCreated(projectId, summary.id);
221
+ }
222
+ catch (err) {
223
+ const msg = err instanceof Error ? err.message : String(err);
224
+ skipped.push({ key, reason: `session creation failed: ${msg}` });
225
+ }
226
+ }
227
+ return { sessions, skipped };
228
+ }
229
+ /**
230
+ * Publish `session_created` over the relay meta channel so every
231
+ * subscribed tab refreshes its session list immediately. Mirrors the
232
+ * dispatcher's safePublish: failures are logged, never propagated —
233
+ * the session record already exists.
234
+ */
235
+ publishSessionCreated(projectId, sessionId) {
236
+ const publish = this.deps?.publishMetaEvent;
237
+ if (!publish)
238
+ return;
239
+ try {
240
+ publish({ type: "session_created", projectId, sessionId });
241
+ }
242
+ catch (err) {
243
+ this.logger.error("[fanout] publishMetaEvent(session_created) failed:", err);
244
+ }
245
+ }
246
+ async executeRun(run, tasks, sessions, maxConcurrent) {
247
+ const deps = this.deps;
248
+ if (!deps)
249
+ return;
250
+ // Prompt lookup: sessions[] is parallel to the accepted (non-skipped) tasks.
251
+ const accepted = new Map();
252
+ for (const ref of sessions)
253
+ accepted.set(ref.key, ref);
254
+ const runSemaphore = new Semaphore(maxConcurrent);
255
+ await Promise.all(sessions.map(async (ref) => {
256
+ const task = tasks.find((t) => t.key === ref.key);
257
+ if (!task)
258
+ return;
259
+ const releaseRun = await runSemaphore.acquire();
260
+ const releaseGlobal = await this.globalSemaphore.acquire();
261
+ try {
262
+ await deps.manager.attach(ref.sessionId, noopSubscriber);
263
+ const content = buildWorkerPrompt(run.runLabel, ref.key, task.prompt, sessions.length);
264
+ // Persist the task message here, not inside prompt(): prompt()
265
+ // waits for the agent bridge to become ready first (bootstrap
266
+ // can take minutes when creation is queued) and only then
267
+ // writes the user message — until that moment the worker
268
+ // session shows an empty message list in Studio even though
269
+ // it is already in the session list. The prompt below then
270
+ // runs with skipPersistence (auto-research pattern) so the
271
+ // message is not written twice.
272
+ let persisted = false;
273
+ try {
274
+ deps.store.appendMessage(ref.sessionId, { role: "user", content });
275
+ persisted = true;
276
+ }
277
+ catch (err) {
278
+ this.logger.error(`[fanout:${run.runId}] worker ${ref.key}: pre-persisting the task message failed: ${err instanceof Error ? err.message : String(err)}`);
279
+ }
280
+ await deps.manager.prompt(ref.sessionId, content, undefined, undefined, undefined, persisted ? { skipPersistence: true } : undefined);
281
+ }
282
+ catch (err) {
283
+ const msg = err instanceof Error ? err.message : String(err);
284
+ this.logger.error(`[fanout:${run.runId}] worker ${ref.key} (${ref.sessionId}) failed: ${msg}`);
285
+ }
286
+ finally {
287
+ releaseGlobal();
288
+ releaseRun();
289
+ }
290
+ }));
291
+ run.finished = true;
292
+ if (this.activeRunsByProject.get(run.projectId) === run.runId) {
293
+ this.activeRunsByProject.delete(run.projectId);
294
+ }
295
+ }
296
+ }
297
+ // ---------------------------------------------------------------------------
298
+ // Prompt building
299
+ // ---------------------------------------------------------------------------
300
+ function buildWorkerPrompt(runLabel, key, prompt, total) {
301
+ return [
302
+ `You are a focused worker session spawned by \`session_fanout\` (run ${runLabel}, task ${key}, 1 of ${total}).`,
303
+ "",
304
+ "Work autonomously on the task below. Do not ask questions — make reasonable assumptions and state them.",
305
+ "Your final message is the report the user will read in this session, so make it self-contained.",
306
+ "",
307
+ "--- TASK ---",
308
+ prompt,
309
+ ].join("\n");
310
+ }
311
+ function clampConcurrency(raw) {
312
+ const n = typeof raw === "number" ? Math.floor(raw) : DEFAULT_MAX_CONCURRENT;
313
+ if (!Number.isFinite(n))
314
+ return DEFAULT_MAX_CONCURRENT;
315
+ return Math.max(1, Math.min(HARD_CAP_CONCURRENT, n));
316
+ }
317
+ // ---------------------------------------------------------------------------
318
+ // Singleton (wired from SessionStreamManager's constructor)
319
+ //
320
+ // Stored on globalThis under a registered symbol instead of a module-level
321
+ // variable. In the repo/dev layout the session-fanout extension is loaded
322
+ // from src/ via jiti while the server runs from dist/, so this module exists
323
+ // as TWO instances in one process. A module-level singleton would be set in
324
+ // the dist instance but read as null in the jiti instance; a globalThis slot
325
+ // is shared by both.
326
+ // ---------------------------------------------------------------------------
327
+ const FANOUT_SINGLETON_KEY = Symbol.for("aexol.sessionFanoutManager");
328
+ function holder() {
329
+ return globalThis;
330
+ }
331
+ export function configureFanout(deps) {
332
+ const h = holder();
333
+ if (!h[FANOUT_SINGLETON_KEY])
334
+ h[FANOUT_SINGLETON_KEY] = new FanoutManager();
335
+ h[FANOUT_SINGLETON_KEY].configure(deps);
336
+ return h[FANOUT_SINGLETON_KEY];
337
+ }
338
+ export function getFanoutManager() {
339
+ return holder()[FANOUT_SINGLETON_KEY] ?? null;
340
+ }
341
+ /** Test-only: drop the configured singleton. */
342
+ export function resetFanoutManager() {
343
+ delete holder()[FANOUT_SINGLETON_KEY];
344
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"session-stream.d.ts","sourceRoot":"","sources":["../../src/server/session-stream.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-stream.d.ts","sourceRoot":"","sources":["../../src/server/session-stream.ts"],"names":[],"mappings":"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"}
@@ -41,6 +41,7 @@ import { AgentBridge } from "./agent-bridge.js";
41
41
  import { SettingsManager, } from "../sdk/coding-agent/index.js";
42
42
  import { InterAgentBroker } from "./inter-agent-broker.js";
43
43
  import { setInterAgentBroker } from "../memory/inter-agent-broker-singleton.js";
44
+ import { configureFanout } from "./fanout/fanout-manager.js";
44
45
  import { CONTEXT_LIMIT_RATIO, DEFAULT_COMPACTION_POLICY, getAutoOlderHistoryContextThresholdTokens, } from "../sdk/coding-agent/core/compaction/policy.js";
45
46
  import { getMemoryState, isSourceEntry, rawTokensSinceLastBound, rawTokensSinceLastCompaction, } from "../memory/branch.js";
46
47
  import { observationPoolTokens, renderSummary } from "../memory/compaction.js";
@@ -116,7 +117,7 @@ const STREAMING_MEANINGFUL_EVENT_TYPES = new Set([
116
117
  * so the actual context inflation is 3-8× the stored token estimate.
117
118
  */
118
119
  const REHYDRATION_TAIL_TOKEN_BUDGET = 20_000;
119
- const UI_HISTORY_TAIL_MESSAGE_LIMIT = 120;
120
+ const UI_HISTORY_TAIL_MESSAGE_LIMIT = 60;
120
121
  /**
121
122
  * Number of accumulated wire events before flushing the in-flight turn
122
123
  * to SQLite. Batch-persisting means a server crash mid-turn only loses
@@ -541,6 +542,9 @@ export class SessionStreamManager {
541
542
  // Wire the inter-agent broker singleton so the memory extension can send
542
543
  // and receive live observation messages between active sessions.
543
544
  setInterAgentBroker(this.broker);
545
+ // Wire the fanout manager singleton so the session-fanout extension can
546
+ // spawn parallel worker sessions through this manager.
547
+ configureFanout({ manager: this, store: this.store });
544
548
  }
545
549
  /**
546
550
  * Update the machine JWT used by all future AgentBridge instances.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aexol/spectral",
3
- "version": "0.9.198",
3
+ "version": "0.9.200",
4
4
  "description": "AI coding agent for Aexol with relay-based browser access.",
5
5
  "type": "module",
6
6
  "private": false,