@clanker-code/pi-subagents 0.10.8 → 0.11.1
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/AGENTS.md +2 -0
- package/CHANGELOG.md +29 -0
- package/README.md +22 -2
- package/dist/agent-manager.d.ts +11 -0
- package/dist/agent-manager.js +55 -22
- package/dist/agent-runner.d.ts +14 -0
- package/dist/agent-runner.js +50 -4
- package/dist/agent-tool-description.d.ts +7 -1
- package/dist/agent-tool-description.js +3 -3
- package/dist/cross-extension-rpc.d.ts +4 -0
- package/dist/cross-extension-rpc.js +11 -1
- package/dist/dashboard-ui.d.ts +15 -0
- package/dist/dashboard-ui.js +231 -0
- package/dist/default-agents.js +0 -1
- package/dist/index.js +104 -13
- package/dist/peek.js +8 -2
- package/dist/schedule.d.ts +9 -1
- package/dist/schedule.js +7 -1
- package/dist/subagent-list-clear.d.ts +57 -0
- package/dist/subagent-list-clear.js +331 -0
- package/dist/ui/agent-tool-rendering.js +1 -1
- package/dist/ui/agent-widget-tree.js +19 -2
- package/dist/ui/agent-widget.d.ts +7 -1
- package/dist/ui/agent-widget.js +52 -10
- package/package.json +1 -1
- package/src/agent-manager.ts +48 -13
- package/src/agent-runner.ts +59 -3
- package/src/agent-tool-description.ts +10 -4
- package/src/cross-extension-rpc.ts +14 -1
- package/src/dashboard-ui.ts +291 -0
- package/src/default-agents.ts +0 -1
- package/src/index.ts +121 -17
- package/src/peek.ts +7 -2
- package/src/schedule.ts +20 -1
- package/src/subagent-list-clear.ts +405 -0
- package/src/ui/agent-tool-rendering.ts +1 -1
- package/src/ui/agent-widget-tree.ts +16 -2
- package/src/ui/agent-widget.ts +50 -10
package/src/default-agents.ts
CHANGED
|
@@ -34,7 +34,6 @@ export const DEFAULT_AGENTS: Map<string, AgentConfig> = new Map([
|
|
|
34
34
|
builtinToolNames: READ_ONLY_TOOLS,
|
|
35
35
|
extensions: true,
|
|
36
36
|
skills: true,
|
|
37
|
-
model: "anthropic/claude-haiku-4-5-20251001",
|
|
38
37
|
systemPrompt: `# CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS
|
|
39
38
|
You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
|
|
40
39
|
Your role is EXCLUSIVELY to search and analyze existing code. You do NOT have access to file editing tools.
|
package/src/index.ts
CHANGED
|
@@ -24,8 +24,10 @@ import { getAgentConversation, getCurrentExtensionAgentId, getCurrentExtensionDe
|
|
|
24
24
|
import { buildAgentToolDescription, getModelLabelFromConfig } from "./agent-tool-description.js";
|
|
25
25
|
import { BUILTIN_TOOL_NAMES, getAgentConfig, getAllTypes, getAvailableTypes, isDefaultsDisabled, registerAgents, resolveType, setDefaultsDisabled } from "./agent-types.js";
|
|
26
26
|
import { formatOutputFileHint, limitText, MAX_RESULT_CHARS, MAX_VERBOSE_CHARS } from "./bounded-output.js";
|
|
27
|
+
import { extractText } from "./context.js";
|
|
27
28
|
import { registerRpcHandlers } from "./cross-extension-rpc.js";
|
|
28
29
|
import { loadCustomAgents } from "./custom-agents.js";
|
|
30
|
+
import { registerDashboardModules } from "./dashboard-ui.js";
|
|
29
31
|
import { isModelInScope, readEnabledModels, resolveEnabledModels } from "./enabled-models.js";
|
|
30
32
|
import { GroupJoinManager } from "./group-join.js";
|
|
31
33
|
import { resolveAgentInvocationConfig, resolveJoinMode } from "./invocation-config.js";
|
|
@@ -37,11 +39,11 @@ import { SubagentScheduler } from "./schedule.js";
|
|
|
37
39
|
import { resolveStorePath, ScheduleStore } from "./schedule-store.js";
|
|
38
40
|
import { applyAndEmitLoaded, DEFAULT_WAIT_TIMEOUT_SECONDS, type SubagentsSettings, saveAndEmitChanged, type ToolDescriptionMode } from "./settings.js";
|
|
39
41
|
import { getStatusNote } from "./status-note.js";
|
|
42
|
+
import { registerSubagentListClearTools } from "./subagent-list-clear.js";
|
|
40
43
|
import { type AgentConfig, type AgentInvocation, type AgentRecord, type JoinMode, MAX_RECURSIVE_DEPTH, type NotificationDetails, type SubagentType } from "./types.js";
|
|
41
|
-
import { renderAgentCall, renderAgentResult, renderSteerCall, tailPreview } from "./ui/agent-tool-rendering.js";
|
|
44
|
+
import { renderAgentCall, renderAgentResult, renderSteerCall, snipMiddleLines, tailPreview } from "./ui/agent-tool-rendering.js";
|
|
42
45
|
import {
|
|
43
46
|
type AgentActivity,
|
|
44
|
-
type AgentDetails,
|
|
45
47
|
AgentWidget,
|
|
46
48
|
buildInvocationTags,
|
|
47
49
|
describeActivity,
|
|
@@ -60,10 +62,21 @@ import { formatWaitTimeout, pollPendingMessages, raceWait, type WaitOutcome, wai
|
|
|
60
62
|
// ---- Shared helpers ----
|
|
61
63
|
|
|
62
64
|
/** Tool execute return value for a text response. */
|
|
63
|
-
function textResult(msg: string, details?:
|
|
65
|
+
function textResult(msg: string, details?: unknown) {
|
|
64
66
|
return { content: [{ type: "text" as const, text: msg }], details: details as any };
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
/** Metadata attached to get_subagent_result for compact UI rendering. */
|
|
70
|
+
interface GetResultDetails {
|
|
71
|
+
status: AgentRecord["status"];
|
|
72
|
+
description: string;
|
|
73
|
+
toolUses: number;
|
|
74
|
+
tokens: string | null;
|
|
75
|
+
contextPercent: number | null;
|
|
76
|
+
duration: string;
|
|
77
|
+
outputFile?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
67
80
|
/**
|
|
68
81
|
* Create an AgentActivity state and spawn callbacks for tracking tool usage.
|
|
69
82
|
* Used by the background spawn path to track tool usage.
|
|
@@ -431,7 +444,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
431
444
|
if (!sessionId) return; // sessionId not yet available — try again on next event
|
|
432
445
|
const path = resolveStorePath(ctx.cwd, sessionId);
|
|
433
446
|
const store = new ScheduleStore(path);
|
|
434
|
-
scheduler.start(pi, ctx, manager, store);
|
|
447
|
+
scheduler.start(pi, ctx, manager, store, { depth: nextSubagentDepth, parentAgentId: extensionAgentId });
|
|
435
448
|
pi.events.emit("subagents:scheduler_ready", { sessionId, jobCount: store.list().length });
|
|
436
449
|
} catch (err) {
|
|
437
450
|
// Scheduling is non-essential — log and move on so the rest of the
|
|
@@ -443,6 +456,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
443
456
|
// Capture ctx from session_start for RPC spawn handler + start the scheduler.
|
|
444
457
|
pi.on("session_start", async (_event, ctx) => {
|
|
445
458
|
currentCtx = ctx;
|
|
459
|
+
clearBatchState();
|
|
460
|
+
groupJoin.dispose();
|
|
446
461
|
manager.clearCompleted();
|
|
447
462
|
widget.clearSnapshots();
|
|
448
463
|
retryStash.clear();
|
|
@@ -450,8 +465,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
450
465
|
});
|
|
451
466
|
|
|
452
467
|
pi.on("session_before_switch", () => {
|
|
468
|
+
clearBatchState();
|
|
469
|
+
groupJoin.dispose();
|
|
453
470
|
manager.clearCompleted();
|
|
454
|
-
widget.
|
|
471
|
+
widget.dispose();
|
|
455
472
|
retryStash.clear();
|
|
456
473
|
scheduler.stop();
|
|
457
474
|
});
|
|
@@ -461,6 +478,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
461
478
|
pi,
|
|
462
479
|
getCtx: () => currentCtx,
|
|
463
480
|
manager,
|
|
481
|
+
depth: nextSubagentDepth,
|
|
482
|
+
parentAgentId: extensionAgentId,
|
|
464
483
|
});
|
|
465
484
|
|
|
466
485
|
// Broadcast readiness so extensions loaded after us can discover us
|
|
@@ -472,13 +491,17 @@ export default function (pi: ExtensionAPI) {
|
|
|
472
491
|
unsubSpawnRpc();
|
|
473
492
|
unsubStopRpc();
|
|
474
493
|
unsubPingRpc();
|
|
494
|
+
unsubWidgetCreated?.();
|
|
475
495
|
unsubWidgetStarted?.();
|
|
476
496
|
unsubWidgetCompleted?.();
|
|
477
497
|
unsubWidgetFailed?.();
|
|
478
498
|
currentCtx = undefined;
|
|
479
499
|
delete (globalThis as any)[MANAGER_KEY];
|
|
480
500
|
scheduler.stop();
|
|
501
|
+
clearBatchState();
|
|
502
|
+
groupJoin.dispose();
|
|
481
503
|
manager.abortAll();
|
|
504
|
+
widget.dispose();
|
|
482
505
|
for (const timer of pendingNudges.values()) clearTimeout(timer);
|
|
483
506
|
pendingNudges.clear();
|
|
484
507
|
retryStash.clear();
|
|
@@ -491,6 +514,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
491
514
|
const snapshot = widgetSnapshotFromEvent(payload);
|
|
492
515
|
if (snapshot) widget.upsertSnapshot(snapshot);
|
|
493
516
|
};
|
|
517
|
+
const unsubWidgetCreated = pi.events.on("subagents:created", upsertWidgetEventSnapshot);
|
|
494
518
|
const unsubWidgetStarted = pi.events.on("subagents:started", upsertWidgetEventSnapshot);
|
|
495
519
|
const unsubWidgetCompleted = pi.events.on("subagents:completed", upsertWidgetEventSnapshot);
|
|
496
520
|
const unsubWidgetFailed = pi.events.on("subagents:failed", upsertWidgetEventSnapshot);
|
|
@@ -567,6 +591,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
567
591
|
let batchFinalizeTimer: ReturnType<typeof setTimeout> | undefined;
|
|
568
592
|
let batchCounter = 0;
|
|
569
593
|
|
|
594
|
+
function clearBatchState() {
|
|
595
|
+
if (batchFinalizeTimer) {
|
|
596
|
+
clearTimeout(batchFinalizeTimer);
|
|
597
|
+
batchFinalizeTimer = undefined;
|
|
598
|
+
}
|
|
599
|
+
currentBatchAgents = [];
|
|
600
|
+
}
|
|
601
|
+
|
|
570
602
|
/** Finalize the current batch: if 2+ smart-mode agents, register as a group. */
|
|
571
603
|
function finalizeBatch() {
|
|
572
604
|
batchFinalizeTimer = undefined;
|
|
@@ -653,7 +685,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
653
685
|
|
|
654
686
|
const agentToolDescription = buildAgentToolDescription({
|
|
655
687
|
mode: getToolDescriptionMode(),
|
|
656
|
-
|
|
688
|
+
nextSubagentDepth,
|
|
657
689
|
schedulingEnabled: isSchedulingEnabled(),
|
|
658
690
|
});
|
|
659
691
|
|
|
@@ -679,7 +711,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
679
711
|
}),
|
|
680
712
|
subagent_type: Type.Optional(
|
|
681
713
|
Type.String({
|
|
682
|
-
description: `The type of specialized agent to use. Available types: ${getAvailableTypes().join(", ")}. Custom agents from .pi/agents/*.md (project) or ${getAgentDir()}/agents/*.md (global) are also available. OMIT when retrying (preserved by the handle) unless you want to override it.`,
|
|
714
|
+
description: `The type of specialized agent to use. Defaults to general-purpose when omitted. Available types: ${getAvailableTypes().join(", ")}. Custom agents from .pi/agents/*.md (project) or ${getAgentDir()}/agents/*.md (global) are also available. OMIT when retrying (preserved by the handle) unless you want to override it.`,
|
|
683
715
|
}),
|
|
684
716
|
),
|
|
685
717
|
model: Type.Optional(
|
|
@@ -782,18 +814,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
782
814
|
const { retry: _omit, ...overrides } = params;
|
|
783
815
|
P = { ...stashed.params, ...overrides } as typeof params;
|
|
784
816
|
}
|
|
785
|
-
|
|
817
|
+
const requestedSubagentType = (P.subagent_type ?? "general-purpose") as SubagentType;
|
|
818
|
+
emitPromptPreview(P.prompt, P.description, requestedSubagentType);
|
|
786
819
|
|
|
787
|
-
// Retry supplied the prompt
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
[!P.prompt && "prompt", !P.subagent_type && "subagent_type"].filter(Boolean).join(", ") +
|
|
792
|
-
".",
|
|
793
|
-
);
|
|
820
|
+
// Retry supplied the prompt from the stash; otherwise prompt is required.
|
|
821
|
+
// subagent_type defaults to general-purpose when omitted.
|
|
822
|
+
if (!retryHandle && !P.prompt) {
|
|
823
|
+
return textResult("Missing required argument: prompt.");
|
|
794
824
|
}
|
|
795
825
|
|
|
796
|
-
const rawType =
|
|
826
|
+
const rawType = requestedSubagentType;
|
|
797
827
|
const resolved = resolveType(rawType);
|
|
798
828
|
if (!resolved) {
|
|
799
829
|
// Unknown agent type — recoverable. List valid types so the orchestrator
|
|
@@ -988,6 +1018,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
988
1018
|
invocation: agentInvocation,
|
|
989
1019
|
depth: nextSubagentDepth,
|
|
990
1020
|
parentAgentId: extensionAgentId,
|
|
1021
|
+
eventBus: pi.events,
|
|
991
1022
|
outputFileForAgent: (agentId) => createOutputFilePath(ctx.cwd, agentId, ctx.sessionManager.getSessionId()),
|
|
992
1023
|
onOutputFileCreated: (outputFile, agentId) => writeInitialEntry(outputFile, agentId, P.prompt!, ctx.cwd),
|
|
993
1024
|
...bgCallbacks,
|
|
@@ -1032,6 +1063,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
1032
1063
|
isBackground: true,
|
|
1033
1064
|
depth: record?.depth ?? nextSubagentDepth,
|
|
1034
1065
|
parentAgentId: extensionAgentId,
|
|
1066
|
+
status: record?.status ?? "running",
|
|
1067
|
+
startedAt: record?.startedAt,
|
|
1068
|
+
toolUses: record?.toolUses ?? 0,
|
|
1069
|
+
invocation: record?.invocation,
|
|
1035
1070
|
});
|
|
1036
1071
|
|
|
1037
1072
|
const isQueued = record?.status === "queued";
|
|
@@ -1077,6 +1112,57 @@ export default function (pi: ExtensionAPI) {
|
|
|
1077
1112
|
}),
|
|
1078
1113
|
),
|
|
1079
1114
|
}),
|
|
1115
|
+
renderResult(result, { expanded }, theme) {
|
|
1116
|
+
const details = result.details as GetResultDetails | undefined;
|
|
1117
|
+
const text = extractText(result.content);
|
|
1118
|
+
|
|
1119
|
+
// Header: status + stats + description
|
|
1120
|
+
let line = "";
|
|
1121
|
+
if (details) {
|
|
1122
|
+
const icon = details.status === "error" || details.status === "stopped" || details.status === "aborted"
|
|
1123
|
+
? theme.fg("error", "✗")
|
|
1124
|
+
: details.status === "running" || details.status === "queued"
|
|
1125
|
+
? theme.fg("accent", "◌")
|
|
1126
|
+
: theme.fg("success", "✓");
|
|
1127
|
+
|
|
1128
|
+
const parts: string[] = [];
|
|
1129
|
+
if (details.toolUses > 0) parts.push(`${details.toolUses} tool use${details.toolUses === 1 ? "" : "s"}`);
|
|
1130
|
+
if (details.tokens) parts.push(details.tokens);
|
|
1131
|
+
if (details.contextPercent !== null) parts.push(`ctx ${Math.round(details.contextPercent)}%`);
|
|
1132
|
+
if (details.duration) parts.push(details.duration);
|
|
1133
|
+
const stats = parts.map(p => theme.fg("dim", p)).join(" " + theme.fg("dim", "·") + " ");
|
|
1134
|
+
|
|
1135
|
+
line = `${icon} ${theme.bold(details.description)} ${theme.fg("dim", details.status)}`;
|
|
1136
|
+
if (stats) line += "\n " + stats;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
// Body: snip when collapsed, full when expanded
|
|
1140
|
+
// Extract the body portion (after the first blank line) to keep the
|
|
1141
|
+
// tool-output header always visible and only snip the actual result.
|
|
1142
|
+
if (text.trim()) {
|
|
1143
|
+
const firstBlank = text.indexOf("\n\n");
|
|
1144
|
+
const body = firstBlank >= 0 ? text.slice(firstBlank + 2) : text;
|
|
1145
|
+
|
|
1146
|
+
if (expanded) {
|
|
1147
|
+
for (const l of text.split("\n")) {
|
|
1148
|
+
line += "\n" + theme.fg("dim", ` ${l}`);
|
|
1149
|
+
}
|
|
1150
|
+
} else {
|
|
1151
|
+
// Show the tool-output header verbatim, then snip only the body
|
|
1152
|
+
if (firstBlank >= 0) {
|
|
1153
|
+
for (const l of text.slice(0, firstBlank).split("\n")) {
|
|
1154
|
+
line += "\n" + theme.fg("dim", ` ${l}`);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
for (const l of snipMiddleLines(body, 20)) {
|
|
1158
|
+
line += "\n" + theme.fg("dim", ` ${l}`);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
return new Text(line, 0, 0);
|
|
1164
|
+
},
|
|
1165
|
+
|
|
1080
1166
|
execute: async (_toolCallId, params, signal, _onUpdate, ctx) => {
|
|
1081
1167
|
const record = manager.getRecord(params.agent_id);
|
|
1082
1168
|
if (!record) {
|
|
@@ -1125,6 +1211,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
1125
1211
|
if (record.compactionCount) statsParts.push(`Compactions: ${record.compactionCount}`);
|
|
1126
1212
|
statsParts.push(`Duration: ${duration}`);
|
|
1127
1213
|
|
|
1214
|
+
const details: GetResultDetails = {
|
|
1215
|
+
status: record.status,
|
|
1216
|
+
description: record.description,
|
|
1217
|
+
toolUses: record.toolUses,
|
|
1218
|
+
tokens: tokens || null,
|
|
1219
|
+
contextPercent,
|
|
1220
|
+
duration,
|
|
1221
|
+
outputFile: record.outputFile,
|
|
1222
|
+
};
|
|
1223
|
+
|
|
1128
1224
|
let output =
|
|
1129
1225
|
`Agent: ${record.id}\n` +
|
|
1130
1226
|
`Type: ${displayName} | Status: ${record.status}${getStatusNote(record.status)} | ${statsParts.join(" | ")}\n` +
|
|
@@ -1168,7 +1264,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1168
1264
|
}
|
|
1169
1265
|
}
|
|
1170
1266
|
|
|
1171
|
-
return textResult(output);
|
|
1267
|
+
return textResult(output, details);
|
|
1172
1268
|
},
|
|
1173
1269
|
}));
|
|
1174
1270
|
|
|
@@ -1228,6 +1324,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
1228
1324
|
},
|
|
1229
1325
|
}));
|
|
1230
1326
|
|
|
1327
|
+
// ---- list_subagents / clear_subagents tools ----
|
|
1328
|
+
|
|
1329
|
+
registerSubagentListClearTools(pi, manager);
|
|
1330
|
+
registerDashboardModules(pi, manager);
|
|
1331
|
+
|
|
1231
1332
|
// ---- list_models tool ----
|
|
1232
1333
|
|
|
1233
1334
|
pi.registerTool(defineTool({
|
|
@@ -1728,6 +1829,9 @@ Write the file using the write tool. Only write the file, nothing else.`;
|
|
|
1728
1829
|
const record = await manager.spawnAndWait(pi, ctx, "general-purpose", generatePrompt, {
|
|
1729
1830
|
description: `Generate ${name} agent`,
|
|
1730
1831
|
maxTurns: 5,
|
|
1832
|
+
eventBus: pi.events,
|
|
1833
|
+
depth: nextSubagentDepth,
|
|
1834
|
+
parentAgentId: extensionAgentId,
|
|
1731
1835
|
});
|
|
1732
1836
|
|
|
1733
1837
|
if (record.status === "error") {
|
package/src/peek.ts
CHANGED
|
@@ -112,6 +112,11 @@ function parseOutputFileLines(path: string): string[] {
|
|
|
112
112
|
return [];
|
|
113
113
|
}
|
|
114
114
|
const out: string[] = [];
|
|
115
|
+
const pushRenderedLines = (text: string) => {
|
|
116
|
+
for (const renderedLine of text.trimEnd().split("\n")) {
|
|
117
|
+
if (renderedLine.trim()) out.push(renderedLine);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
115
120
|
for (const line of raw.split("\n")) {
|
|
116
121
|
const trimmed = line.trim();
|
|
117
122
|
if (!trimmed) continue;
|
|
@@ -124,12 +129,12 @@ function parseOutputFileLines(path: string): string[] {
|
|
|
124
129
|
const content = entry?.message?.content;
|
|
125
130
|
if (!Array.isArray(content)) {
|
|
126
131
|
// Some entries may carry a plain string content.
|
|
127
|
-
if (typeof content === "string" && content.trim())
|
|
132
|
+
if (typeof content === "string" && content.trim()) pushRenderedLines(content);
|
|
128
133
|
continue;
|
|
129
134
|
}
|
|
130
135
|
for (const block of content) {
|
|
131
136
|
if (block?.type === "text" && typeof block.text === "string" && block.text.trim()) {
|
|
132
|
-
|
|
137
|
+
pushRenderedLines(block.text);
|
|
133
138
|
}
|
|
134
139
|
}
|
|
135
140
|
}
|
package/src/schedule.ts
CHANGED
|
@@ -45,6 +45,13 @@ export interface NewJobInput {
|
|
|
45
45
|
isolation?: IsolationMode;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
interface SchedulerSpawnDefaults {
|
|
49
|
+
/** Recursive depth for scheduled subagents fired from this session. */
|
|
50
|
+
depth?: number;
|
|
51
|
+
/** Parent subagent id for scheduled subagents fired from this session. */
|
|
52
|
+
parentAgentId?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
48
55
|
export class SubagentScheduler {
|
|
49
56
|
private jobs = new Map<string, Cron>();
|
|
50
57
|
private intervals = new Map<string, NodeJS.Timeout>();
|
|
@@ -52,13 +59,21 @@ export class SubagentScheduler {
|
|
|
52
59
|
private pi: ExtensionAPI | undefined;
|
|
53
60
|
private ctx: ExtensionContext | undefined;
|
|
54
61
|
private manager: AgentManager | undefined;
|
|
62
|
+
private spawnDefaults: SchedulerSpawnDefaults = {};
|
|
55
63
|
|
|
56
64
|
/** Start the scheduler: bind to a session's store and arm enabled jobs. */
|
|
57
|
-
start(
|
|
65
|
+
start(
|
|
66
|
+
pi: ExtensionAPI,
|
|
67
|
+
ctx: ExtensionContext,
|
|
68
|
+
manager: AgentManager,
|
|
69
|
+
store: ScheduleStore,
|
|
70
|
+
spawnDefaults: SchedulerSpawnDefaults = {},
|
|
71
|
+
): void {
|
|
58
72
|
this.pi = pi;
|
|
59
73
|
this.ctx = ctx;
|
|
60
74
|
this.manager = manager;
|
|
61
75
|
this.store = store;
|
|
76
|
+
this.spawnDefaults = spawnDefaults;
|
|
62
77
|
|
|
63
78
|
for (const job of store.list()) {
|
|
64
79
|
if (job.enabled) this.scheduleJob(job);
|
|
@@ -75,6 +90,7 @@ export class SubagentScheduler {
|
|
|
75
90
|
this.pi = undefined;
|
|
76
91
|
this.ctx = undefined;
|
|
77
92
|
this.manager = undefined;
|
|
93
|
+
this.spawnDefaults = {};
|
|
78
94
|
}
|
|
79
95
|
|
|
80
96
|
/** True if start() has bound a store and the scheduler is active. */
|
|
@@ -247,6 +263,9 @@ export class SubagentScheduler {
|
|
|
247
263
|
isolated: job.isolated,
|
|
248
264
|
thinkingLevel: job.thinking,
|
|
249
265
|
isolation: job.isolation,
|
|
266
|
+
eventBus: pi.events,
|
|
267
|
+
depth: this.spawnDefaults.depth,
|
|
268
|
+
parentAgentId: this.spawnDefaults.parentAgentId,
|
|
250
269
|
});
|
|
251
270
|
} catch (err) {
|
|
252
271
|
const error = err instanceof Error ? err.message : String(err);
|