pi-subagents 0.33.0 → 0.33.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/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.33.1] - 2026-07-03
6
+
7
+ ### Fixed
8
+ - Avoid native supervisor-channel tool conflicts when `pi-intercom` is also installed by deferring native tool registration until runtime startup and keeping a namespaced native supervisor reply tool.
9
+
5
10
  ## [0.33.0] - 2026-07-03
6
11
 
7
12
  ### Added
package/README.md CHANGED
@@ -267,7 +267,7 @@ Add `autofix` to `/parallel-review` or `/parallel-cleanup` to apply only the syn
267
267
 
268
268
  ## Native supervisor coordination
269
269
 
270
- Child agents can talk back to the parent Pi session without installing `pi-intercom`. `pi-subagents` now provides the child-facing `contact_supervisor` tool and the parent-facing `intercom({ action: "reply" })` path natively.
270
+ Child agents can talk back to the parent Pi session without installing `pi-intercom`. `pi-subagents` now provides the child-facing `contact_supervisor` tool and the parent-facing `subagent_supervisor({ action: "reply" })` path natively. If no external `pi-intercom` tool owns the `intercom` name, the native channel also exposes `intercom` as a compatibility fallback.
271
271
 
272
272
  Use it for work where the child might need a decision instead of guessing:
273
273
 
@@ -283,7 +283,7 @@ The child can use one dedicated coordination tool:
283
283
 
284
284
  - `contact_supervisor`: the child contacts the parent/supervisor session that delegated the task. Use `reason: "need_decision"` for blocking decisions or clarification, `reason: "interview_request"` for structured input, and `reason: "progress_update"` for short non-blocking updates when a discovery changes the plan. Do not ask for clarification when the only conflict is review-only/no-edit versus progress-writing or artifact-writing instructions; no-edit wins.
285
285
 
286
- Supervisor messages are scoped to the exact Pi session id that spawned the child. A second Pi session in the same repository does not receive those requests.
286
+ The parent replies with `subagent_supervisor({ action: "reply", replyTo, message })` or checks pending requests with `subagent_supervisor({ action: "pending" })`. Supervisor messages are scoped to the exact Pi session id that spawned the child. A second Pi session in the same repository does not receive those requests.
287
287
 
288
288
  Child-side routine completion handoffs are still not expected. If a child appears stalled, needs-attention notices can show up in the parent session with useful next actions, such as checking `subagent({ action: "status" })`, interrupting the run, or nudging the child.
289
289
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-subagents",
3
- "version": "0.33.0",
3
+ "version": "0.33.1",
4
4
  "description": "Pi extension for delegating tasks to subagents with chains, parallel execution, and TUI clarification",
5
5
  "author": "Nico Bailon",
6
6
  "license": "MIT",
@@ -550,18 +550,20 @@ contact_supervisor({
550
550
  })
551
551
  ```
552
552
 
553
- The parent replies with:
553
+ The parent replies with the native supervisor tool:
554
554
 
555
555
  ```typescript
556
- intercom({ action: "reply", message: "Optimize for readability." })
556
+ subagent_supervisor({ action: "reply", message: "Optimize for readability." })
557
557
  ```
558
558
 
559
559
  Or inspects unresolved asks first:
560
560
 
561
561
  ```typescript
562
- intercom({ action: "pending" })
562
+ subagent_supervisor({ action: "pending" })
563
563
  ```
564
564
 
565
+ If no external `pi-intercom` tool owns the `intercom` name, native supervisor coordination may also expose `intercom` as a compatibility fallback. Prefer `subagent_supervisor` for parent replies because it never overrides installed `pi-intercom`.
566
+
565
567
  If intercom messages do not show up, run `subagent({ action: "doctor" })` or `/subagents-doctor`.
566
568
 
567
569
  ## Management Mode
@@ -18,6 +18,7 @@ import { writeAtomicJson } from "../shared/atomic-json.ts";
18
18
  const SUPERVISOR_CHANNEL_ROOT = path.join(TEMP_ROOT_DIR, "supervisor-channels");
19
19
  const REQUESTS_DIR = "requests";
20
20
  const REPLIES_DIR = "replies";
21
+ export const NATIVE_SUPERVISOR_TOOL_NAME = "subagent_supervisor";
21
22
  const MAX_MESSAGE_BYTES = 64 * 1024;
22
23
  const DEFAULT_ASK_TIMEOUT_MS = 10 * 60 * 1000;
23
24
  const CHANNEL_POLL_MS = Math.min(POLL_INTERVAL_MS, 500);
@@ -275,8 +276,9 @@ function hasTool(pi: ExtensionAPI, name: string): boolean {
275
276
  }
276
277
  }
277
278
 
278
- export function registerNativeSupervisorClient(pi: ExtensionAPI): void {
279
+ export function registerNativeSupervisorClient(pi: ExtensionAPI, options: { includeIntercomFallback?: boolean } = {}): void {
279
280
  if (!readChildMetadata()) return;
281
+ const includeIntercomFallback = options.includeIntercomFallback !== false;
280
282
  if (!hasTool(pi, "contact_supervisor")) {
281
283
  const tool: ToolDefinition<typeof ContactSupervisorParamsSchema, Record<string, unknown>> = {
282
284
  name: "contact_supervisor",
@@ -289,7 +291,7 @@ export function registerNativeSupervisorClient(pi: ExtensionAPI): void {
289
291
  };
290
292
  pi.registerTool(tool);
291
293
  }
292
- if (!hasTool(pi, "intercom")) {
294
+ if (includeIntercomFallback && !hasTool(pi, "intercom")) {
293
295
  const tool: ToolDefinition<typeof IntercomParamsSchema, Record<string, unknown>> = {
294
296
  name: "intercom",
295
297
  label: "Intercom",
@@ -349,12 +351,13 @@ function listRequestFiles(): Array<{ channelDir: string; file: string }> {
349
351
  }
350
352
 
351
353
  function currentContextSessionId(state: Pick<SubagentState, "currentSessionId">, ctx: ExtensionContext): string | undefined {
352
- if (state.currentSessionId) return state.currentSessionId;
353
354
  try {
354
- return ctx.sessionManager.getSessionId();
355
+ const sessionId = ctx.sessionManager.getSessionId();
356
+ if (sessionId) return sessionId;
355
357
  } catch {
356
- return undefined;
358
+ // Fall through to the last known identity.
357
359
  }
360
+ return state.currentSessionId ?? undefined;
358
361
  }
359
362
 
360
363
  function requestMatchesContext(request: SupervisorRequest, state: Pick<SubagentState, "currentSessionId">, ctx: ExtensionContext): boolean {
@@ -363,14 +366,14 @@ function requestMatchesContext(request: SupervisorRequest, state: Pick<SubagentS
363
366
  }
364
367
 
365
368
  function formatPendingLine(request: PendingSupervisorRequest): string {
366
- const replyHint = request.expectsReply ? ` Reply: intercom({ action: "reply", replyTo: "${request.id}", message: "..." })` : "";
369
+ const replyHint = request.expectsReply ? ` Reply: ${NATIVE_SUPERVISOR_TOOL_NAME}({ action: "reply", replyTo: "${request.id}", message: "..." })` : "";
367
370
  return `- ${request.id}: ${request.agent} [${request.runId}#${request.childIndex}] ${request.reason}.${replyHint}`;
368
371
  }
369
372
 
370
373
  function requestVisibleText(request: PendingSupervisorRequest): string {
371
374
  const lines = [request.message];
372
375
  if (request.expectsReply) {
373
- lines.push("", `Reply with: intercom({ action: "reply", replyTo: "${request.id}", message: "..." })`);
376
+ lines.push("", `Reply with: ${NATIVE_SUPERVISOR_TOOL_NAME}({ action: "reply", replyTo: "${request.id}", message: "..." })`);
374
377
  }
375
378
  return lines.join("\n");
376
379
  }
@@ -424,11 +427,13 @@ function publicPendingRequests(pending: Map<string, PendingSupervisorRequest>):
424
427
  }));
425
428
  }
426
429
 
427
- function buildParentIntercomTool(pending: Map<string, PendingSupervisorRequest>): ToolDefinition<typeof IntercomParamsSchema, Record<string, unknown>> {
430
+ function buildParentIntercomTool(pending: Map<string, PendingSupervisorRequest>, name = "intercom"): ToolDefinition<typeof IntercomParamsSchema, Record<string, unknown>> {
428
431
  return {
429
- name: "intercom",
430
- label: "Intercom",
431
- description: "Native pi-subagents supervisor channel. Use reply/pending/status to answer child subagent requests.",
432
+ name,
433
+ label: name === "intercom" ? "Intercom" : "Subagent Supervisor",
434
+ description: name === "intercom"
435
+ ? "Native pi-subagents supervisor channel. Use reply/pending/status to answer child subagent requests."
436
+ : "Native pi-subagents supervisor channel. Use reply/pending/status to answer child subagent requests without overriding pi-intercom.",
432
437
  parameters: IntercomParamsSchema,
433
438
  async execute(_id, params) {
434
439
  const input = params as IntercomParams;
@@ -458,7 +463,10 @@ export function createNativeSupervisorChannel(pi: ExtensionAPI, state: SubagentS
458
463
  const seenFiles = new Set<string>();
459
464
  let poller: ReturnType<typeof setInterval> | undefined;
460
465
 
461
- if (!hasTool(pi, "intercom")) pi.registerTool(buildParentIntercomTool(pending));
466
+ const registerParentTools = (): void => {
467
+ if (!hasTool(pi, NATIVE_SUPERVISOR_TOOL_NAME)) pi.registerTool(buildParentIntercomTool(pending, NATIVE_SUPERVISOR_TOOL_NAME));
468
+ if (!hasTool(pi, "intercom")) pi.registerTool(buildParentIntercomTool(pending));
469
+ };
462
470
 
463
471
  const poll = (): void => {
464
472
  const ctx = state.lastUiContext;
@@ -495,6 +503,7 @@ export function createNativeSupervisorChannel(pi: ExtensionAPI, state: SubagentS
495
503
  return {
496
504
  start: () => {
497
505
  if (poller) return;
506
+ registerParentTools();
498
507
  poll();
499
508
  poller = setInterval(poll, CHANNEL_POLL_MS);
500
509
  poller.unref?.();
@@ -261,7 +261,21 @@ function registerSteeringInbox(pi: ExtensionAPI): void {
261
261
  export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
262
262
  registerSteeringInbox(pi);
263
263
  registerToolBudget(pi, decodeToolBudgetEnv(process.env[TOOL_BUDGET_ENV]));
264
- registerNativeSupervisorClient(pi);
264
+ let nativeSupervisorClientRegistered = false;
265
+ let nativeSupervisorFallbackRegistered = false;
266
+ const registerNativeSupervisorClientOnce = (): void => {
267
+ if (nativeSupervisorClientRegistered) return;
268
+ nativeSupervisorClientRegistered = true;
269
+ registerNativeSupervisorClient(pi, { includeIntercomFallback: false });
270
+ };
271
+ const registerNativeSupervisorFallbackOnce = (): void => {
272
+ registerNativeSupervisorClientOnce();
273
+ if (nativeSupervisorFallbackRegistered) return;
274
+ nativeSupervisorFallbackRegistered = true;
275
+ registerNativeSupervisorClient(pi);
276
+ };
277
+ const onRuntimeEvent = pi.on as unknown as (event: string, handler: (event: unknown) => unknown) => void;
278
+ onRuntimeEvent("session_start", registerNativeSupervisorClientOnce);
265
279
  const structuredOutputPath = process.env[STRUCTURED_OUTPUT_CAPTURE_ENV];
266
280
  const structuredSchemaPath = process.env[STRUCTURED_OUTPUT_SCHEMA_ENV];
267
281
  if (structuredOutputPath && structuredSchemaPath) {
@@ -300,7 +314,6 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
300
314
  });
301
315
  }
302
316
 
303
- const onRuntimeEvent = pi.on as unknown as (event: string, handler: (event: unknown) => unknown) => void;
304
317
  onRuntimeEvent("context", (event: { messages: unknown[] }) => {
305
318
  const messages = stripParentOnlySubagentMessages(event.messages);
306
319
  if (messages === event.messages) return undefined;
@@ -308,6 +321,7 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
308
321
  });
309
322
 
310
323
  onRuntimeEvent("before_agent_start", async (event: { systemPrompt: string }) => {
324
+ registerNativeSupervisorFallbackOnce();
311
325
  const intercomSessionName = process.env[SUBAGENT_INTERCOM_SESSION_NAME_ENV]?.trim();
312
326
  if (intercomSessionName && typeof pi.setSessionName === "function") {
313
327
  pi.setSessionName(intercomSessionName);