@arhen/pi-core-subagent 1.3.5 → 1.3.7

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 CHANGED
@@ -256,6 +256,11 @@ Background (default) + intercom — the run returns a runId immediately; you sta
256
256
  | `send_agent_message` | message to a sibling subagent's mailbox (`to` = its task id, or `"leader"`) |
257
257
  | `poll_agent_messages` | drain this subagent's mailbox |
258
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
+
259
264
  ## Peek — `/subagents peek` or `ctrl+shift+a`
260
265
 
261
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.5",
3
+ "version": "1.3.7",
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
- if (
82
- String(args ?? "")
83
- .trim()
84
- .toLowerCase() === "peek"
85
- )
86
- return openPeek(ctx);
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");
@@ -117,24 +125,26 @@ export default function (pi: ExtensionAPI) {
117
125
  pi.registerTool<typeof SubagentParams, RunDetails>({
118
126
  name: "subagent",
119
127
  label: "Subagent",
120
- // ponytail: this string is billed on every request. One example — the graph one —
121
- // covers ids, needs, write and Verify; the simpler shapes are subsets of it.
128
+ // ponytail: this string is billed on every request. No example block an example
129
+ // biases the model toward one shape; guidelines + JSON schema describe all of them.
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 is the default (returns a runId immediately); 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" }] })',
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.',
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.",
127
135
  "Put every sub-task in ONE call: subagent({ tasks: [...] }). Never make multiple parallel subagent calls — one call, one run, N tasks.",
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.",
137
+ "Prefer flat `tasks` (plain parallel) unless a real dependency exists — only add `needs` edges when ordering genuinely matters.",
129
138
  "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
139
  "Define each agent yourself: invented name, focused system prompt, and read-only (default) or write:true. Prefer read-only.",
131
- "Use background:true for long work; allowIntercom:true only when a child may need to ask you something.",
140
+ "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.",
141
+ "allowIntercom:true only when a child may need to ask you something.",
132
142
  ],
133
143
  parameters: SubagentParams,
134
144
  executionMode: "parallel", // sibling subagent calls run concurrently, not serialized
135
145
  async execute(_toolCallId, params, signal, onUpdate, ctx) {
136
146
  const typed = params as SubagentParamsShape;
137
- if (typed.background) {
147
+ if ((typed.background ?? manager.autoBgOn) && typed.background !== false) {
138
148
  const details = manager.startInBackground(typed, ctx);
139
149
  return {
140
150
  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,7 +819,7 @@ export class SubagentManager {
798
819
  id: newId("run"),
799
820
  mode,
800
821
  status: "queued",
801
- background: params.background ?? true,
822
+ background: params.background ?? this.autoBg,
802
823
  allowIntercom: Boolean(params.allowIntercom),
803
824
  notifyPerTask: params.notifyPerTask ?? true,
804
825
  createdAt: Date.now(),