@arhen/pi-core-subagent 1.3.4 → 1.3.6
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 +16 -10
- package/package.json +1 -1
- package/src/index.ts +19 -10
- package/src/manager.ts +24 -3
- package/src/schemas.ts +7 -2
package/README.md
CHANGED
|
@@ -5,6 +5,15 @@
|
|
|
5
5
|
[](./LICENSE)
|
|
6
6
|
[](https://github.com/earendil-works/pi)
|
|
7
7
|
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
Requires the [pi coding agent](https://github.com/earendil-works/pi) — install it first: `npm install -g @earendil-works/pi-coding-agent`.
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
pi install npm:@arhen/pi-core-subagent
|
|
14
|
+
# or locally: pi install /path/to/pi-subagents
|
|
15
|
+
```
|
|
16
|
+
|
|
8
17
|
Minimalist pi extension: **fast in-process subagents** with single / parallel / graph modes, background runs, cancellation, intercom (child↔leader) and an agent↔agent mailbox.
|
|
9
18
|
|
|
10
19
|
Built for one job: delegate work to isolated subagents **without bloating the parent context**.
|
|
@@ -72,13 +81,6 @@ flowchart TB
|
|
|
72
81
|
|
|
73
82
|
The dotted arrows are the whole point: a child may burn 200k tokens reading files, and the leader receives only its final answer.
|
|
74
83
|
|
|
75
|
-
## Install
|
|
76
|
-
|
|
77
|
-
```sh
|
|
78
|
-
pi install npm:@arhen/pi-core-subagent
|
|
79
|
-
# or locally: pi install /path/to/pi-subagents
|
|
80
|
-
```
|
|
81
|
-
|
|
82
84
|
## Usage — the leader invents the agents
|
|
83
85
|
|
|
84
86
|
Define agents inline per call — never creates or reads agent files. Model resolution: explicit `provider/model-id` (or bare id) via the pi model registry → agent-file `model` → the parent's current model → settings default.
|
|
@@ -219,14 +221,13 @@ flowchart LR
|
|
|
219
221
|
|
|
220
222
|
And the rule that keeps this from becoming ceremony: **zero `needs` anywhere = plain parallel.** No waves, no gates, no graph vocabulary imposed on flat work.
|
|
221
223
|
|
|
222
|
-
Background + intercom:
|
|
224
|
+
Background (default) + intercom — the run returns a runId immediately; you stay steerable while it works:
|
|
223
225
|
|
|
224
226
|
```json
|
|
225
227
|
{
|
|
226
228
|
"agent": "auditor",
|
|
227
229
|
"prompt": "You audit dependencies.",
|
|
228
230
|
"task": "Audit package.json for outdated deps",
|
|
229
|
-
"background": true,
|
|
230
231
|
"allowIntercom": true
|
|
231
232
|
}
|
|
232
233
|
```
|
|
@@ -235,7 +236,7 @@ Background + intercom:
|
|
|
235
236
|
|
|
236
237
|
| Tool | Purpose |
|
|
237
238
|
|---|---|
|
|
238
|
-
| `subagent` | single / `tasks` (parallel or graph via `needs`) / `chain` (`{previous}`); `background:
|
|
239
|
+
| `subagent` | single / `tasks` (parallel or graph via `needs`) / `chain` (`{previous}`); background is the default (`background:false` for inline result in this turn); `allowIntercom:true` enables child talk tools; `notifyPerTask` (default true) wakes you as each task completes (background runs only) |
|
|
239
240
|
| `subagent_status` | live per-task snapshot (non-blocking), including each child's session file path |
|
|
240
241
|
| `subagent_result` | full output of a run or one task |
|
|
241
242
|
| `await_subagent` | block until a run finishes (optional `timeoutMs`) |
|
|
@@ -255,6 +256,11 @@ Background + intercom:
|
|
|
255
256
|
| `send_agent_message` | message to a sibling subagent's mailbox (`to` = its task id, or `"leader"`) |
|
|
256
257
|
| `poll_agent_messages` | drain this subagent's mailbox |
|
|
257
258
|
|
|
259
|
+
## Commands
|
|
260
|
+
|
|
261
|
+
- `/subagents` — list runs; `/subagents peek` (or `ctrl+shift+a`) — browsable pane
|
|
262
|
+
- `/subagents auto-bg on|off` — toggle background-by-default for subagent calls (persists to `~/.pi/agent/subagents-config.json`; default on). `off` makes calls block until the run finishes, result inline in the same turn. Bare `/subagents auto-bg` shows the current state.
|
|
263
|
+
|
|
258
264
|
## Peek — `/subagents peek` or `ctrl+shift+a`
|
|
259
265
|
|
|
260
266
|
Read-only pane over the session's subagents:
|
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.6",
|
|
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
|
@@ -76,14 +76,22 @@ export default function (pi: ExtensionAPI) {
|
|
|
76
76
|
);
|
|
77
77
|
};
|
|
78
78
|
pi.registerCommand("subagents", {
|
|
79
|
-
description: "List subagent runs. `/subagents peek` opens the browsable pane.",
|
|
79
|
+
description: "List subagent runs. `/subagents peek` opens the browsable pane; `/subagents auto-bg on|off` toggles background-by-default.",
|
|
80
80
|
handler: async (args, ctx) => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
)
|
|
86
|
-
|
|
81
|
+
const arg = String(args ?? "")
|
|
82
|
+
.trim()
|
|
83
|
+
.toLowerCase();
|
|
84
|
+
if (arg === "peek") return openPeek(ctx);
|
|
85
|
+
if (arg === "auto-bg" || arg.startsWith("auto-bg ")) {
|
|
86
|
+
const value = arg.split(/\s+/)[1];
|
|
87
|
+
if (value === "on" || value === "off") {
|
|
88
|
+
const next = manager.setAutoBg(value === "on");
|
|
89
|
+
ctx.ui.notify(`auto-bg ${next ? "on" : "off"} — subagent calls default to ${next ? "background" : "blocking (inline result)"}.`, "info");
|
|
90
|
+
} else {
|
|
91
|
+
ctx.ui.notify(`auto-bg is ${manager.autoBgOn ? "on" : "off"} — use \`/subagents auto-bg on|off\` to change it.`, "info");
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
87
95
|
const runs = manager.listRuns().slice(0, 10);
|
|
88
96
|
if (runs.length === 0) {
|
|
89
97
|
ctx.ui.notify("No subagent runs in this session.", "info");
|
|
@@ -120,7 +128,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
120
128
|
// ponytail: this string is billed on every request. One example — the graph one —
|
|
121
129
|
// covers ids, needs, write and Verify; the simpler shapes are subsets of it.
|
|
122
130
|
description:
|
|
123
|
-
'Run isolated subagents (own context, own session). You invent each agent: name, optional system prompt, toolset (read-only default, write:true to edit). Use `agent`+`task` for one, `tasks` for many. `needs` declares dependency edges: a task waits for its needs and receives their outputs prepended to its prompt. background
|
|
131
|
+
'Run isolated subagents (own context, own session). You invent each agent: name, optional system prompt, toolset (read-only default, write:true to edit). Use `agent`+`task` for one, `tasks` for many. `needs` declares dependency edges: a task waits for its needs and receives their outputs prepended to its prompt. background is the default (returns a runId immediately; toggle via `/subagents auto-bg off`); set background:false when you need the result inline in this turn. allowIntercom:true lets children talk to you and each other.\n\nsubagent({ tasks: [{ id: "api", agent: "api-mapper", task: "Map API routes" }, { id: "db", agent: "db-mapper", task: "Map DB schema" }, { id: "doc", agent: "writer", needs: ["api", "db"], write: true, task: "Write ARCHITECTURE.md. Verify: test -s ARCHITECTURE.md" }] })',
|
|
124
132
|
promptSnippet: "Define and delegate work to specialized subagents.",
|
|
125
133
|
promptGuidelines: [
|
|
126
134
|
"Use subagent when independent review, testing, research, or parallel analysis improves quality.",
|
|
@@ -128,13 +136,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
128
136
|
"Order comes from `needs`, not from separate calls: give tasks an `id`, list the ids each depends on. Tasks with no unmet needs run in parallel; dependents receive their upstream outputs automatically — do not restate them.",
|
|
129
137
|
"End each task with a runnable check, e.g. 'Verify: npx tsc --noEmit && bun test'. A subagent's claim of success is not evidence.",
|
|
130
138
|
"Define each agent yourself: invented name, focused system prompt, and read-only (default) or write:true. Prefer read-only.",
|
|
131
|
-
"
|
|
139
|
+
"Prefer blocking (background:false) whenever the run's result is something you must wait for before your next step — do not default to background for work you depend on inline. When a background run is active, settle its pending results and task dependencies (await_subagent / subagent_result, then continue dependent work) before starting unrelated work.",
|
|
140
|
+
"allowIntercom:true only when a child may need to ask you something.",
|
|
132
141
|
],
|
|
133
142
|
parameters: SubagentParams,
|
|
134
143
|
executionMode: "parallel", // sibling subagent calls run concurrently, not serialized
|
|
135
144
|
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
136
145
|
const typed = params as SubagentParamsShape;
|
|
137
|
-
if (typed.background) {
|
|
146
|
+
if ((typed.background ?? manager.autoBgOn) && typed.background !== false) {
|
|
138
147
|
const details = manager.startInBackground(typed, ctx);
|
|
139
148
|
return {
|
|
140
149
|
content: [
|
package/src/manager.ts
CHANGED
|
@@ -200,9 +200,30 @@ export class SubagentManager {
|
|
|
200
200
|
private widgetRuns: RunSnapshot[] = [];
|
|
201
201
|
private eventSeq = 0;
|
|
202
202
|
|
|
203
|
+
/** Default for `background` when the agent doesn't say — toggle via `/subagents auto-bg on|off`. */
|
|
204
|
+
private autoBg = true;
|
|
205
|
+
|
|
203
206
|
turnActivity = false;
|
|
204
207
|
|
|
205
|
-
constructor(private readonly pi: ExtensionAPI) {
|
|
208
|
+
constructor(private readonly pi: ExtensionAPI) {
|
|
209
|
+
try {
|
|
210
|
+
const cfg = JSON.parse(readFileSync(join(getAgentDir(), "subagents-config.json"), "utf8"));
|
|
211
|
+
if (typeof cfg.autoBg === "boolean") this.autoBg = cfg.autoBg;
|
|
212
|
+
} catch {
|
|
213
|
+
/* no config yet — default true */
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Flip the background-by-default flag; persists to the agent dir. Returns the new value. */
|
|
218
|
+
setAutoBg(on: boolean): boolean {
|
|
219
|
+
this.autoBg = on;
|
|
220
|
+
void writeFile(join(getAgentDir(), "subagents-config.json"), JSON.stringify({ autoBg: on }, null, 2)).catch(() => {});
|
|
221
|
+
return on;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
get autoBgOn(): boolean {
|
|
225
|
+
return this.autoBg;
|
|
226
|
+
}
|
|
206
227
|
|
|
207
228
|
/** Any run still has queued/running tasks? */
|
|
208
229
|
hasActiveRun(): boolean {
|
|
@@ -798,9 +819,9 @@ export class SubagentManager {
|
|
|
798
819
|
id: newId("run"),
|
|
799
820
|
mode,
|
|
800
821
|
status: "queued",
|
|
801
|
-
background:
|
|
822
|
+
background: params.background ?? this.autoBg,
|
|
802
823
|
allowIntercom: Boolean(params.allowIntercom),
|
|
803
|
-
notifyPerTask: params.notifyPerTask ??
|
|
824
|
+
notifyPerTask: params.notifyPerTask ?? true,
|
|
804
825
|
createdAt: Date.now(),
|
|
805
826
|
concurrency: Math.max(1, Math.min(params.concurrency ?? DEFAULT_CONCURRENCY, MAX_CONCURRENCY)),
|
|
806
827
|
tasks: inputs.map((input, index) => ({
|
package/src/schemas.ts
CHANGED
|
@@ -55,12 +55,17 @@ export const SubagentParams = Type.Object({
|
|
|
55
55
|
}),
|
|
56
56
|
),
|
|
57
57
|
background: Type.Optional(
|
|
58
|
-
Type.Boolean({
|
|
58
|
+
Type.Boolean({
|
|
59
|
+
description:
|
|
60
|
+
"Fire-and-forget: return immediately with a runId; you'll be notified on completion. Default true — set false when you need the result inline in this turn.",
|
|
61
|
+
default: true,
|
|
62
|
+
}),
|
|
59
63
|
),
|
|
60
64
|
notifyPerTask: Type.Optional(
|
|
61
65
|
Type.Boolean({
|
|
62
66
|
description:
|
|
63
|
-
"Wake you (queued follow-up turn) as each task completes — background runs only, since blocking runs can't be woken mid-tool. Default
|
|
67
|
+
"Wake you (queued follow-up turn) as each task completes — background runs only, since blocking runs can't be woken mid-tool. Default true.",
|
|
68
|
+
default: true,
|
|
64
69
|
}),
|
|
65
70
|
),
|
|
66
71
|
allowIntercom: Type.Optional(
|