@arhen/pi-core-subagent 1.3.8 → 1.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/package.json +1 -1
- package/src/index.ts +28 -0
- package/src/manager.ts +21 -1
- package/src/schemas.ts +5 -0
package/README.md
CHANGED
|
@@ -232,6 +232,8 @@ Background (default) + intercom — the run returns a runId immediately; you sta
|
|
|
232
232
|
}
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
+
**Steering a running child:** while a background run is active the leader stays responsive, and you can push a message into a live child's session mid-run with `steer_subagent` — e.g. `steer_subagent({ runId, taskId, message: "Ignore tests/, only audit runtime deps" })`. The message queues as a steer if the child is mid-turn and lands at its next model boundary. Omit `taskId` to steer every still-running task in the run. Combined with `notifyPerTask`, this makes a background run feel like a live team you can redirect, not a fire-and-forget blob.
|
|
236
|
+
|
|
235
237
|
## Tools
|
|
236
238
|
|
|
237
239
|
| Tool | Purpose |
|
|
@@ -241,6 +243,7 @@ Background (default) + intercom — the run returns a runId immediately; you sta
|
|
|
241
243
|
| `subagent_result` | full output of a run or one task |
|
|
242
244
|
| `await_subagent` | block until a run finishes (optional `timeoutMs`) |
|
|
243
245
|
| `reply_subagent` | answer a child's `ask_parent` question |
|
|
246
|
+
| `steer_subagent` | inject a steering message into a running child's session (queues as steer if mid-turn; lands at its next model boundary) |
|
|
244
247
|
| `subagent_cancel` | abort a running/queued run |
|
|
245
248
|
|
|
246
249
|
### Per-task fields
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arhen/pi-core-subagent",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "pi extension: fast in-process subagents with a dependency-graph scheduler (needs edges gate tasks and carry upstream output into dependent prompts), plus background runs, intercom and agent-to-agent mailbox. Leader defines agents inline.",
|
|
6
6
|
"license": "MIT",
|
package/src/index.ts
CHANGED
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
ReplyParam,
|
|
34
34
|
ResultParam,
|
|
35
35
|
RunIdParam,
|
|
36
|
+
SteerParam,
|
|
36
37
|
SubagentParams,
|
|
37
38
|
type SubagentParamsShape,
|
|
38
39
|
} from "./schemas.ts";
|
|
@@ -316,6 +317,33 @@ export default function (pi: ExtensionAPI) {
|
|
|
316
317
|
},
|
|
317
318
|
});
|
|
318
319
|
|
|
320
|
+
pi.registerTool<typeof SteerParam, { steered?: string[] }>({
|
|
321
|
+
name: "steer_subagent",
|
|
322
|
+
label: "Steer Subagent",
|
|
323
|
+
description:
|
|
324
|
+
"Inject a steering message into a running subagent's session (queues as steer if the child is mid-turn; delivered at its next model boundary).",
|
|
325
|
+
parameters: SteerParam,
|
|
326
|
+
async execute(_id, params) {
|
|
327
|
+
const { runId, taskId, message } = params as { runId: string; taskId?: string; message: string };
|
|
328
|
+
const ok = manager.steerTask(runId, taskId, message);
|
|
329
|
+
if (!ok)
|
|
330
|
+
return {
|
|
331
|
+
content: [{ type: "text", text: `No running task(s) for ${runId}${taskId ? `/${taskId}` : ""}.` }],
|
|
332
|
+
isError: true,
|
|
333
|
+
details: {},
|
|
334
|
+
};
|
|
335
|
+
return {
|
|
336
|
+
content: [
|
|
337
|
+
{
|
|
338
|
+
type: "text",
|
|
339
|
+
text: `Steering message queued for ${runId}${taskId ? `/${taskId}` : " (all running tasks)"}.`,
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
details: {},
|
|
343
|
+
};
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
|
|
319
347
|
pi.registerTool<typeof RunIdParam, { aborted?: number }>({
|
|
320
348
|
name: "subagent_cancel",
|
|
321
349
|
label: "Subagent Cancel",
|
package/src/manager.ts
CHANGED
|
@@ -193,7 +193,10 @@ export class SubagentManager {
|
|
|
193
193
|
private runs = new Map<string, RunSnapshot>();
|
|
194
194
|
private settlers = new Map<string, (run: RunSnapshot) => void>();
|
|
195
195
|
private pendingReplies = new Map<string, PendingReply>();
|
|
196
|
-
private liveChildren = new Map<
|
|
196
|
+
private liveChildren = new Map<
|
|
197
|
+
string,
|
|
198
|
+
{ abort: () => void; dispose: () => void; touchWatchdog: () => void; steer: (message: string) => void }
|
|
199
|
+
>();
|
|
197
200
|
private mailboxes: Mailbox = createMailbox();
|
|
198
201
|
private runControllers = new Map<string, AbortController>();
|
|
199
202
|
private widgetTimers = new Map<string, ReturnType<typeof setTimeout>>(); // per-run stream throttle
|
|
@@ -721,6 +724,13 @@ export class SubagentManager {
|
|
|
721
724
|
abort: () => void child?.abort(),
|
|
722
725
|
dispose: () => watchdog.dispose(),
|
|
723
726
|
touchWatchdog: () => watchdog.touch(),
|
|
727
|
+
// Inject a steering message mid-run; queues as steer if the child is streaming.
|
|
728
|
+
steer: (message) =>
|
|
729
|
+
void child?.prompt(message, { streamingBehavior: "steer" }).catch((err) =>
|
|
730
|
+
this.pi.sendUserMessage(`[steer_subagent] ${err instanceof Error ? err.message : String(err)}`, {
|
|
731
|
+
deliverAs: "followUp",
|
|
732
|
+
}),
|
|
733
|
+
),
|
|
724
734
|
});
|
|
725
735
|
|
|
726
736
|
const maxRuntimeMs = input.maxRuntimeMs ?? DEFAULT_RUNTIME_MS;
|
|
@@ -984,6 +994,16 @@ export class SubagentManager {
|
|
|
984
994
|
return { run: cloneRun(run), background: true };
|
|
985
995
|
}
|
|
986
996
|
|
|
997
|
+
/** Push a steering message into a live child's session. Returns false when unknown or not running. */
|
|
998
|
+
steerTask(runId: string, taskId: string | undefined, message: string): boolean {
|
|
999
|
+
const run = this.runs.get(runId);
|
|
1000
|
+
if (!run) return false;
|
|
1001
|
+
const ids = taskId ? [taskId] : run.tasks.map((t) => t.id).filter((id) => this.liveChildren.has(`${runId}:${id}`));
|
|
1002
|
+
if (ids.length === 0) return false;
|
|
1003
|
+
for (const id of ids) this.liveChildren.get(`${runId}:${id}`)?.steer(message);
|
|
1004
|
+
return true;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
987
1007
|
/** Abort ONE task; siblings keep running. Returns false when unknown or already finished. */
|
|
988
1008
|
cancelTask(runId: string, taskId: string, ctx?: ExtensionContext): boolean {
|
|
989
1009
|
const run = this.runs.get(runId);
|
package/src/schemas.ts
CHANGED
|
@@ -91,3 +91,8 @@ export const ReplyParam = Type.Object({
|
|
|
91
91
|
taskId: Type.String(),
|
|
92
92
|
message: Type.String({ description: "Answer for the child" }),
|
|
93
93
|
});
|
|
94
|
+
export const SteerParam = Type.Object({
|
|
95
|
+
runId: Type.String(),
|
|
96
|
+
taskId: Type.Optional(Type.String({ description: "Specific task id; defaults to all still-running tasks" })),
|
|
97
|
+
message: Type.String({ description: "Steering message to inject into the child's session" }),
|
|
98
|
+
});
|