pi-subagents 0.34.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -9
- package/README.md +213 -32
- package/index.ts +1 -0
- package/install.mjs +1 -1
- package/package.json +23 -8
- package/prompts/review-loop.md +3 -1
- package/skills/pi-subagents/SKILL.md +87 -25
- package/src/agents/agent-management.ts +82 -15
- package/src/agents/agent-serializer.ts +19 -0
- package/src/agents/agents.ts +91 -49
- package/src/agents/frontmatter.ts +67 -13
- package/src/agents/skills.ts +25 -12
- package/src/api/background-work.ts +197 -0
- package/src/api/delegation.ts +158 -0
- package/src/extension/chain-validation.ts +165 -0
- package/src/extension/doctor.ts +15 -0
- package/src/extension/fanout-child.ts +3 -1
- package/src/extension/index.ts +65 -124
- package/src/extension/rpc.ts +10 -2
- package/src/extension/schemas.ts +18 -14
- package/src/extension/steering-notices.ts +35 -0
- package/src/extension/tool-description.ts +20 -9
- package/src/intercom/intercom-bridge.ts +3 -2
- package/src/intercom/native-supervisor-channel.ts +9 -1
- package/src/intercom/result-intercom.ts +4 -0
- package/src/runs/background/async-execution.ts +293 -44
- package/src/runs/background/async-job-tracker.ts +56 -9
- package/src/runs/background/async-resume.ts +159 -52
- package/src/runs/background/async-status.ts +25 -18
- package/src/runs/background/auto-drain.ts +67 -0
- package/src/runs/background/chain-root-attachment.ts +16 -8
- package/src/runs/background/control-channel.ts +260 -13
- package/src/runs/background/fleet-view.ts +23 -2
- package/src/runs/background/notify.ts +79 -10
- package/src/runs/background/result-watcher.ts +12 -9
- package/src/runs/background/run-id-resolver.ts +14 -2
- package/src/runs/background/run-status.ts +23 -15
- package/src/runs/background/scheduled-runs.ts +3 -0
- package/src/runs/background/stale-run-reconciler.ts +32 -10
- package/src/runs/background/steering.ts +237 -0
- package/src/runs/background/subagent-runner.ts +898 -236
- package/src/runs/background/subagent-wait.ts +484 -0
- package/src/runs/background/top-level-async.ts +2 -1
- package/src/runs/background/wait-config.ts +36 -0
- package/src/runs/background/wait-tool.ts +26 -0
- package/src/runs/foreground/async-steering-action.ts +230 -0
- package/src/runs/foreground/chain-clarify.ts +22 -6
- package/src/runs/foreground/chain-execution.ts +50 -32
- package/src/runs/foreground/execution.ts +308 -94
- package/src/runs/foreground/subagent-executor.ts +592 -268
- package/src/runs/shared/acceptance.ts +355 -97
- package/src/runs/shared/child-protocol.ts +121 -0
- package/src/runs/shared/completion-guard.ts +8 -127
- package/src/runs/shared/dynamic-fanout.ts +6 -4
- package/src/runs/shared/model-fallback.ts +36 -0
- package/src/runs/shared/nested-events.ts +9 -4
- package/src/runs/shared/nested-render.ts +4 -1
- package/src/runs/shared/parallel-utils.ts +7 -0
- package/src/runs/shared/pi-args.ts +34 -7
- package/src/runs/shared/pi-spawn.ts +18 -12
- package/src/runs/shared/session-lease.ts +279 -0
- package/src/runs/shared/single-output.ts +61 -6
- package/src/runs/shared/spawn-budget.ts +128 -0
- package/src/runs/shared/subagent-control.ts +10 -6
- package/src/runs/shared/subagent-prompt-runtime.ts +127 -26
- package/src/runs/shared/task-intent.ts +176 -0
- package/src/runs/shared/tool-availability.ts +65 -0
- package/src/runs/shared/turn-budget.ts +49 -4
- package/src/shared/atomic-json.ts +4 -1
- package/src/shared/fork-context.ts +28 -3
- package/src/shared/model-info.ts +7 -4
- package/src/shared/status-format.ts +7 -1
- package/src/shared/types.ts +203 -25
- package/src/shared/utils.ts +35 -7
- package/src/slash/delegation-adapters.ts +457 -0
- package/src/slash/delegation-request.ts +103 -0
- package/src/slash/prompt-template-bridge.ts +167 -344
- package/src/slash/slash-commands.ts +239 -6
- package/src/slash/subagents-admin.ts +428 -0
- package/src/slash/subagents-editor.ts +86 -0
- package/src/tui/fleet.ts +405 -0
- package/src/tui/render.ts +90 -16
- package/src/watchdog/change-signature.ts +127 -0
- package/src/watchdog/child-status.ts +205 -0
- package/src/watchdog/emission-guard.ts +123 -0
- package/src/watchdog/lsp-diagnostics.ts +532 -0
- package/src/watchdog/model-selection.ts +167 -0
- package/src/watchdog/register-child.ts +117 -0
- package/src/watchdog/register-main.ts +433 -0
- package/src/watchdog/render.ts +54 -0
- package/src/watchdog/review.ts +293 -0
- package/src/watchdog/runtime.ts +712 -0
- package/src/watchdog/settings.ts +528 -0
- package/src/watchdog/tool-actions.ts +155 -0
- package/src/watchdog/turn-delta.ts +161 -0
- package/src/watchdog/types.ts +188 -0
- package/src/watchdog/warning-format.ts +73 -0
- package/src/runs/background/wait.ts +0 -394
|
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { keyText, type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
5
|
-
import { Key, matchesKey } from "@earendil-works/pi-tui";
|
|
5
|
+
import { Key, matchesKey, type Component, type TUI } from "@earendil-works/pi-tui";
|
|
6
6
|
import { BUILTIN_AGENT_NAMES, discoverAgents, discoverAgentsAll, type ChainConfig } from "../agents/agents.ts";
|
|
7
7
|
import {
|
|
8
8
|
DEFAULT_PROVIDER_MODELS_MAX_AGE_DAYS,
|
|
@@ -16,11 +16,16 @@ import {
|
|
|
16
16
|
import type { SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
|
|
17
17
|
import { isDynamicParallelStep, isParallelStep, type ChainStep } from "../shared/settings.ts";
|
|
18
18
|
import { findModelInfo, toModelInfo } from "../shared/model-info.ts";
|
|
19
|
-
import { formatTokens } from "../shared/formatters.ts";
|
|
19
|
+
import { formatTokens, shortenPath } from "../shared/formatters.ts";
|
|
20
|
+
import { listAsyncRuns, formatAsyncRunProgressLabel, type AsyncRunSummary } from "../runs/background/async-status.ts";
|
|
21
|
+
import { scheduledRunStorePath } from "../runs/background/scheduled-runs.ts";
|
|
22
|
+
import { SUBAGENT_FANOUT_CHILD_ENV } from "../runs/shared/pi-args.ts";
|
|
20
23
|
import { assertJsonSchemaObject } from "../runs/shared/structured-output.ts";
|
|
21
24
|
import { validateAcceptanceInput } from "../runs/shared/acceptance.ts";
|
|
22
25
|
import type { SlashSubagentResponse, SlashSubagentUpdate } from "./slash-bridge.ts";
|
|
23
26
|
import { registerPromptWorkflowCommands } from "./prompt-workflows.ts";
|
|
27
|
+
import { openSubagentsAdmin } from "./subagents-admin.ts";
|
|
28
|
+
import { openSubagentFleet } from "../tui/fleet.ts";
|
|
24
29
|
import {
|
|
25
30
|
applySlashUpdate,
|
|
26
31
|
buildSlashInitialResult,
|
|
@@ -36,6 +41,7 @@ import {
|
|
|
36
41
|
SLASH_SUBAGENT_RESPONSE_EVENT,
|
|
37
42
|
SLASH_SUBAGENT_STARTED_EVENT,
|
|
38
43
|
SLASH_SUBAGENT_UPDATE_EVENT,
|
|
44
|
+
ASYNC_DIR,
|
|
39
45
|
type Details,
|
|
40
46
|
type JsonSchemaObject,
|
|
41
47
|
type SingleResult,
|
|
@@ -221,6 +227,160 @@ async function withSlashStatus<T>(
|
|
|
221
227
|
}
|
|
222
228
|
}
|
|
223
229
|
|
|
230
|
+
type Theme = ExtensionContext["ui"]["theme"];
|
|
231
|
+
|
|
232
|
+
type StopSelectorTarget = {
|
|
233
|
+
kind: "async" | "scheduled";
|
|
234
|
+
id: string;
|
|
235
|
+
label: string;
|
|
236
|
+
detail: string;
|
|
237
|
+
actionLabel: string;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
type StopSelectorResult = { confirmed: boolean; target?: StopSelectorTarget };
|
|
241
|
+
|
|
242
|
+
function commandForTarget(target: StopSelectorTarget): string {
|
|
243
|
+
return target.kind === "scheduled"
|
|
244
|
+
? `subagent({ action: "schedule-cancel", id: ${JSON.stringify(target.id)} })`
|
|
245
|
+
: `subagent({ action: "stop", id: ${JSON.stringify(target.id)} })`;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function formatAsyncStopTarget(run: AsyncRunSummary): StopSelectorTarget {
|
|
249
|
+
const progress = formatAsyncRunProgressLabel(run);
|
|
250
|
+
const cwd = run.cwd ? shortenPath(run.cwd) : shortenPath(run.asyncDir);
|
|
251
|
+
return {
|
|
252
|
+
kind: "async",
|
|
253
|
+
id: run.id,
|
|
254
|
+
label: `${run.id} · ${run.mode} · ${progress}`,
|
|
255
|
+
detail: `${run.state} · ${cwd}`,
|
|
256
|
+
actionLabel: "stop async run",
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function scheduledStopTargets(ctx: ExtensionContext, state: SubagentState): StopSelectorTarget[] {
|
|
261
|
+
const sessionId = state.currentSessionId ?? ctx.sessionManager.getSessionId();
|
|
262
|
+
if (!sessionId) return [];
|
|
263
|
+
const storePath = scheduledRunStorePath(ctx.cwd, sessionId);
|
|
264
|
+
if (!fs.existsSync(storePath)) return [];
|
|
265
|
+
let parsed: unknown;
|
|
266
|
+
try {
|
|
267
|
+
parsed = JSON.parse(fs.readFileSync(storePath, "utf-8"));
|
|
268
|
+
} catch {
|
|
269
|
+
return [];
|
|
270
|
+
}
|
|
271
|
+
const jobs = parsed && typeof parsed === "object" && Array.isArray((parsed as { jobs?: unknown }).jobs)
|
|
272
|
+
? (parsed as { jobs: Array<Record<string, unknown>> }).jobs
|
|
273
|
+
: [];
|
|
274
|
+
return jobs
|
|
275
|
+
.filter((job) => job.state === "scheduled" && typeof job.id === "string" && typeof job.name === "string" && typeof job.runAt === "number")
|
|
276
|
+
.sort((left, right) => Number(left.runAt) - Number(right.runAt))
|
|
277
|
+
.map((job) => ({
|
|
278
|
+
kind: "scheduled" as const,
|
|
279
|
+
id: String(job.id),
|
|
280
|
+
label: `${String(job.id)} · ${String(job.name)}`,
|
|
281
|
+
detail: `scheduled · ${new Date(Number(job.runAt)).toISOString()}`,
|
|
282
|
+
actionLabel: "cancel scheduled run",
|
|
283
|
+
}));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function discoverStopTargets(ctx: ExtensionContext, state: SubagentState): StopSelectorTarget[] {
|
|
287
|
+
const sessionId = state.currentSessionId ?? ctx.sessionManager.getSessionId() ?? undefined;
|
|
288
|
+
const asyncTargets = listAsyncRuns(ASYNC_DIR, {
|
|
289
|
+
states: ["queued", "running"],
|
|
290
|
+
...(sessionId ? { sessionId } : {}),
|
|
291
|
+
}).map(formatAsyncStopTarget);
|
|
292
|
+
return [...asyncTargets, ...scheduledStopTargets(ctx, state)];
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function stopFallbackText(targets: StopSelectorTarget[]): string {
|
|
296
|
+
if (targets.length === 0) return "No active current-session async runs or scheduled subagent runs to stop.";
|
|
297
|
+
const lines = ["Subagent stop targets:", ""];
|
|
298
|
+
for (const target of targets) {
|
|
299
|
+
lines.push(`- ${target.label}`);
|
|
300
|
+
lines.push(` ${target.detail}`);
|
|
301
|
+
lines.push(` ${target.actionLabel}: ${commandForTarget(target)}`);
|
|
302
|
+
if (target.kind === "async") lines.push(` slash: /subagents-stop ${target.id}`);
|
|
303
|
+
}
|
|
304
|
+
return lines.join("\n");
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
class SubagentsStopSelector implements Component {
|
|
308
|
+
readonly width = 84;
|
|
309
|
+
private selected = 0;
|
|
310
|
+
private confirming = false;
|
|
311
|
+
private readonly tui: TUI;
|
|
312
|
+
private readonly theme: Theme;
|
|
313
|
+
private readonly targets: StopSelectorTarget[];
|
|
314
|
+
private readonly done: (result: StopSelectorResult) => void;
|
|
315
|
+
|
|
316
|
+
constructor(tui: TUI, theme: Theme, targets: StopSelectorTarget[], done: (result: StopSelectorResult) => void) {
|
|
317
|
+
this.tui = tui;
|
|
318
|
+
this.theme = theme;
|
|
319
|
+
this.targets = targets;
|
|
320
|
+
this.done = done;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
handleInput(data: string): void {
|
|
324
|
+
if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
|
|
325
|
+
this.done({ confirmed: false });
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (this.confirming) {
|
|
329
|
+
if (matchesKey(data, "return") || data.toLowerCase() === "y") {
|
|
330
|
+
this.done({ confirmed: true, target: this.targets[this.selected] });
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (data.toLowerCase() === "n" || matchesKey(data, "backspace")) {
|
|
334
|
+
this.confirming = false;
|
|
335
|
+
this.tui.requestRender();
|
|
336
|
+
}
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (matchesKey(data, "up")) {
|
|
340
|
+
this.selected = Math.max(0, this.selected - 1);
|
|
341
|
+
this.tui.requestRender();
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (matchesKey(data, "down")) {
|
|
345
|
+
this.selected = Math.min(this.targets.length - 1, this.selected + 1);
|
|
346
|
+
this.tui.requestRender();
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (matchesKey(data, "return")) {
|
|
350
|
+
this.confirming = true;
|
|
351
|
+
this.tui.requestRender();
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
render(width: number): string[] {
|
|
356
|
+
const contentWidth = Math.max(40, Math.min(this.width, width || this.width));
|
|
357
|
+
const lines = [this.theme.bold("Stop subagent run"), this.theme.fg("dim", "Select a current-session async run to stop, or a scheduled run to cancel."), ""];
|
|
358
|
+
const maxRows = 10;
|
|
359
|
+
const start = Math.max(0, Math.min(this.selected - maxRows + 1, Math.max(0, this.targets.length - maxRows)));
|
|
360
|
+
for (let index = start; index < Math.min(this.targets.length, start + maxRows); index++) {
|
|
361
|
+
const target = this.targets[index]!;
|
|
362
|
+
const selected = index === this.selected;
|
|
363
|
+
const marker = selected ? "›" : " ";
|
|
364
|
+
const actionLabel = target.actionLabel;
|
|
365
|
+
const action = target.kind === "scheduled" ? this.theme.fg("warning", actionLabel) : this.theme.fg("accent", actionLabel);
|
|
366
|
+
const labelWidth = Math.max(0, contentWidth - marker.length - actionLabel.length - 2);
|
|
367
|
+
lines.push(`${marker} ${action} ${target.label.slice(0, labelWidth)}`);
|
|
368
|
+
if (selected) lines.push(this.theme.fg("dim", ` ${target.detail}`.slice(0, contentWidth)));
|
|
369
|
+
}
|
|
370
|
+
if (this.targets.length > maxRows) lines.push(this.theme.fg("dim", `Showing ${start + 1}-${Math.min(this.targets.length, start + maxRows)} of ${this.targets.length}`));
|
|
371
|
+
lines.push("");
|
|
372
|
+
if (this.confirming) {
|
|
373
|
+
const target = this.targets[this.selected]!;
|
|
374
|
+
lines.push(this.theme.fg("warning", `Confirm: ${target.actionLabel} ${target.id}?`));
|
|
375
|
+
if (target.kind === "async") lines.push(this.theme.fg("dim", "Stop ends this run; use interrupt for a resumable pause."));
|
|
376
|
+
lines.push(this.theme.fg("dim", "Enter/Y confirms · N returns · Esc cancels"));
|
|
377
|
+
} else {
|
|
378
|
+
lines.push(this.theme.fg("dim", "↑/↓ select · Enter confirm · Esc cancel"));
|
|
379
|
+
}
|
|
380
|
+
return lines;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
224
384
|
function emptyUsage(): Usage {
|
|
225
385
|
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };
|
|
226
386
|
}
|
|
@@ -841,7 +1001,7 @@ function validateInlineAcceptanceInput(value: string, agent: string): void {
|
|
|
841
1001
|
const errors = validateAcceptanceInput(value, `acceptance for step '${agent}'`);
|
|
842
1002
|
if (errors.length > 0) throw new SlashParseError(errors[0]!);
|
|
843
1003
|
if (!INLINE_ACCEPTANCE_LEVELS.has(value)) {
|
|
844
|
-
throw new SlashParseError(`Inline acceptance for step '${agent}' supports auto, attested, or checked. Use the subagent tool API or a saved .chain.json file for none
|
|
1004
|
+
throw new SlashParseError(`Inline acceptance for step '${agent}' supports auto, attested, or checked. Use the subagent tool API or a saved .chain.json file for none or verified acceptance contracts; reviewed is inferred-only.`);
|
|
845
1005
|
}
|
|
846
1006
|
}
|
|
847
1007
|
|
|
@@ -977,6 +1137,32 @@ export function registerSlashCommands(
|
|
|
977
1137
|
pi: ExtensionAPI,
|
|
978
1138
|
state: SubagentState,
|
|
979
1139
|
): void {
|
|
1140
|
+
let fleetOpen = false;
|
|
1141
|
+
const showFleet = async (ctx: ExtensionContext) => {
|
|
1142
|
+
state.lastUiContext = ctx;
|
|
1143
|
+
if (!ctx.hasUI) {
|
|
1144
|
+
await runSlashSubagent(pi, ctx, { action: "status", view: "fleet" });
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
if (fleetOpen) {
|
|
1148
|
+
ctx.ui.notify("Subagent fleet inspector is already open.", "info");
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
fleetOpen = true;
|
|
1152
|
+
try {
|
|
1153
|
+
await openSubagentFleet(ctx, state);
|
|
1154
|
+
} finally {
|
|
1155
|
+
fleetOpen = false;
|
|
1156
|
+
}
|
|
1157
|
+
};
|
|
1158
|
+
|
|
1159
|
+
pi.registerCommand("subagents", {
|
|
1160
|
+
description: "Administer subagents: inspect metadata and update models, thinking, or prompts",
|
|
1161
|
+
handler: async (args, ctx) => {
|
|
1162
|
+
await openSubagentsAdmin(pi, ctx, args);
|
|
1163
|
+
},
|
|
1164
|
+
});
|
|
1165
|
+
|
|
980
1166
|
pi.registerCommand("run", {
|
|
981
1167
|
description: "Run a subagent directly: /run agent[output=file] [task] [--bg] [--fork]",
|
|
982
1168
|
getArgumentCompletions: makeAgentCompletions(state, false),
|
|
@@ -1090,9 +1276,56 @@ export function registerSlashCommands(
|
|
|
1090
1276
|
});
|
|
1091
1277
|
|
|
1092
1278
|
pi.registerCommand("subagents-fleet", {
|
|
1093
|
-
description: "
|
|
1094
|
-
handler: async (_args, ctx) =>
|
|
1095
|
-
|
|
1279
|
+
description: "Open the live, inspection-only subagent fleet",
|
|
1280
|
+
handler: async (_args, ctx) => showFleet(ctx),
|
|
1281
|
+
});
|
|
1282
|
+
|
|
1283
|
+
pi.registerShortcut(Key.ctrlAlt("f"), {
|
|
1284
|
+
description: "Open subagent fleet inspector",
|
|
1285
|
+
handler: async (ctx) => showFleet(ctx),
|
|
1286
|
+
});
|
|
1287
|
+
|
|
1288
|
+
pi.registerCommand("subagents-stop", {
|
|
1289
|
+
description: "Stop a current-session async subagent run",
|
|
1290
|
+
handler: async (args, ctx) => {
|
|
1291
|
+
const id = args.trim();
|
|
1292
|
+
if (id) {
|
|
1293
|
+
await runSlashSubagent(pi, ctx, { action: "stop", id });
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
if (process.env[SUBAGENT_FANOUT_CHILD_ENV] === "1") {
|
|
1298
|
+
sendSlashText(pi, "Selector unavailable in child-safe fanout mode. Pass an explicit current-session top-level async run id, for example `/subagents-stop <run-id>` or `subagent({ action: \"stop\", id: \"<run-id>\" })`.");
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
let targets: StopSelectorTarget[];
|
|
1303
|
+
try {
|
|
1304
|
+
targets = discoverStopTargets(ctx, state);
|
|
1305
|
+
} catch (error) {
|
|
1306
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1307
|
+
ctx.ui.notify(message, "error");
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
if (!ctx.hasUI) {
|
|
1311
|
+
sendSlashText(pi, stopFallbackText(targets));
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1314
|
+
if (targets.length === 0) {
|
|
1315
|
+
ctx.ui.notify("No active current-session async runs or scheduled subagent runs to stop.", "info");
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
const result = await ctx.ui.custom<StopSelectorResult>(
|
|
1320
|
+
(tui, theme, _kb, done) => new SubagentsStopSelector(tui, theme, targets, done),
|
|
1321
|
+
{ overlay: true, overlayOptions: { anchor: "center", width: 88, maxHeight: "80%" } },
|
|
1322
|
+
);
|
|
1323
|
+
if (!result?.confirmed || !result.target) return;
|
|
1324
|
+
if (result.target.kind === "scheduled") {
|
|
1325
|
+
await runSlashSubagent(pi, ctx, { action: "schedule-cancel", id: result.target.id });
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
await runSlashSubagent(pi, ctx, { action: "stop", id: result.target.id });
|
|
1096
1329
|
},
|
|
1097
1330
|
});
|
|
1098
1331
|
|