pi-subagents 0.11.0 → 0.11.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/index.ts +38 -19
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.11.1] - 2026-03-08
6
+
7
+ ### Changed
8
+ - **Session persistence**: Subagent sessions are now stored alongside the parent session file instead of in `/tmp`. If the parent session is `~/.pi/agent/sessions/abc123.jsonl`, subagent sessions go to `~/.pi/agent/sessions/abc123/{runId}/run-{N}/`. This enables tracking subagent performance over time, analyzing token usage patterns, and debugging past delegations. Falls back to a unique temp directory when no parent session exists (API/headless mode).
9
+
5
10
  ## [0.11.0] - 2026-02-23
6
11
 
7
12
  ### Added
package/index.ts CHANGED
@@ -57,6 +57,22 @@ import { handleManagementAction } from "./agent-management.js";
57
57
 
58
58
  // ExtensionConfig is now imported from ./types.js
59
59
 
60
+ /**
61
+ * Derive subagent session base directory from parent session file.
62
+ * If parent session is ~/.pi/agent/sessions/abc123.jsonl,
63
+ * returns ~/.pi/agent/sessions/abc123/ as the base.
64
+ * Callers add runId to create the actual session root: abc123/{runId}/
65
+ * Falls back to a unique temp directory if no parent session.
66
+ */
67
+ function getSubagentSessionRoot(parentSessionFile: string | null): string {
68
+ if (parentSessionFile) {
69
+ const baseName = path.basename(parentSessionFile, ".jsonl");
70
+ const sessionsDir = path.dirname(parentSessionFile);
71
+ return path.join(sessionsDir, baseName);
72
+ }
73
+ return fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-session-"));
74
+ }
75
+
60
76
  function loadConfig(): ExtensionConfig {
61
77
  const configPath = path.join(os.homedir(), ".pi", "agent", "extensions", "subagent", "config.json");
62
78
  try {
@@ -277,23 +293,22 @@ MANAGEMENT (use action field — omit agent/task/chain/tasks):
277
293
  }
278
294
 
279
295
  const scope: AgentScope = resolveExecutionAgentScope(params.agentScope);
280
- currentSessionId = ctx.sessionManager.getSessionFile() ?? `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
296
+ const parentSessionFile = ctx.sessionManager.getSessionFile() ?? null;
297
+ currentSessionId = parentSessionFile ?? `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
281
298
  const agents = discoverAgents(ctx.cwd, scope).agents;
282
299
  const runId = randomUUID().slice(0, 8);
283
300
  const shareEnabled = params.share === true;
284
- const sessionEnabled = shareEnabled || Boolean(params.sessionDir);
285
- const sessionRoot = sessionEnabled
286
- ? params.sessionDir
287
- ? path.resolve(params.sessionDir)
288
- : fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-session-"))
289
- : undefined;
290
- if (sessionRoot) {
291
- try {
292
- fs.mkdirSync(sessionRoot, { recursive: true });
293
- } catch {}
294
- }
301
+ // Session root: explicit param > derived from parent session > temp fallback
302
+ // Sessions are always enabled now - stored alongside parent session for tracking
303
+ // Include runId to ensure uniqueness across multiple subagent calls
304
+ const sessionRoot = params.sessionDir
305
+ ? path.resolve(params.sessionDir)
306
+ : path.join(getSubagentSessionRoot(parentSessionFile), runId);
307
+ try {
308
+ fs.mkdirSync(sessionRoot, { recursive: true });
309
+ } catch {}
295
310
  const sessionDirForIndex = (idx?: number) =>
296
- sessionRoot ? path.join(sessionRoot, `run-${idx ?? 0}`) : undefined;
311
+ path.join(sessionRoot, `run-${idx ?? 0}`);
297
312
 
298
313
  const hasChain = (params.chain?.length ?? 0) > 0;
299
314
  const hasTasks = (params.tasks?.length ?? 0) > 0;
@@ -315,8 +330,7 @@ MANAGEMENT (use action field — omit agent/task/chain/tasks):
315
330
  enabled: params.artifacts !== false,
316
331
  };
317
332
 
318
- const sessionFile = ctx.sessionManager.getSessionFile() ?? null;
319
- const artifactsDir = effectiveAsync ? tempArtifactsDir : getArtifactsDir(sessionFile);
333
+ const artifactsDir = effectiveAsync ? tempArtifactsDir : getArtifactsDir(parentSessionFile);
320
334
 
321
335
  if (Number(hasChain) + Number(hasTasks) + Number(hasSingle) !== 1) {
322
336
  return {
@@ -1019,12 +1033,16 @@ MANAGEMENT (use action field — omit agent/task/chain/tasks):
1019
1033
 
1020
1034
  const setupDirectRun = (ctx: ExtensionContext) => {
1021
1035
  const runId = randomUUID().slice(0, 8);
1022
- const sessionRoot = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-session-"));
1036
+ const parentSessionFile = ctx.sessionManager.getSessionFile() ?? null;
1037
+ const sessionRoot = path.join(getSubagentSessionRoot(parentSessionFile), runId);
1038
+ try {
1039
+ fs.mkdirSync(sessionRoot, { recursive: true });
1040
+ } catch {}
1023
1041
  return {
1024
1042
  runId,
1025
1043
  shareEnabled: false,
1026
1044
  sessionDirForIndex: (idx?: number) => path.join(sessionRoot, `run-${idx ?? 0}`),
1027
- artifactsDir: getArtifactsDir(ctx.sessionManager.getSessionFile() ?? null),
1045
+ artifactsDir: getArtifactsDir(parentSessionFile),
1028
1046
  artifactConfig: { ...DEFAULT_ARTIFACT_CONFIG } as ArtifactConfig,
1029
1047
  };
1030
1048
  };
@@ -1085,7 +1103,8 @@ MANAGEMENT (use action field — omit agent/task/chain/tasks):
1085
1103
  }
1086
1104
  const id = randomUUID();
1087
1105
  const asyncCtx = { pi, cwd: ctx.cwd, currentSessionId: ctx.sessionManager.getSessionId() ?? id };
1088
- const sessionRoot = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-session-"));
1106
+ const asyncSessionRoot = getSubagentSessionRoot(ctx.sessionManager.getSessionFile() ?? null);
1107
+ try { fs.mkdirSync(asyncSessionRoot, { recursive: true }); } catch {}
1089
1108
  executeAsyncChain(id, {
1090
1109
  chain: r.requestedAsync.chain,
1091
1110
  agents,
@@ -1094,7 +1113,7 @@ MANAGEMENT (use action field — omit agent/task/chain/tasks):
1094
1113
  artifactsDir: exec.artifactsDir,
1095
1114
  artifactConfig: exec.artifactConfig,
1096
1115
  shareEnabled: false,
1097
- sessionRoot,
1116
+ sessionRoot: asyncSessionRoot,
1098
1117
  chainSkills: r.requestedAsync.chainSkills,
1099
1118
  }).then((asyncResult) => {
1100
1119
  pi.sendUserMessage(asyncResult.content[0]?.text || "(launched in background)");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-subagents",
3
- "version": "0.11.0",
3
+ "version": "0.11.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",