oira666_pi-subagent 0.3.17 → 0.3.18

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 (4) hide show
  1. package/index.ts +93 -62
  2. package/package.json +1 -1
  3. package/render.ts +294 -260
  4. package/tree.ts +704 -685
package/index.ts CHANGED
@@ -41,6 +41,7 @@ import {
41
41
  SUBAGENT_NAMES_CUSTOM_TYPE,
42
42
  } from "./names.js";
43
43
  import {
44
+ clearRenderCaches,
44
45
  recordToolCallStart,
45
46
  renderCall,
46
47
  renderResult,
@@ -73,6 +74,7 @@ import {
73
74
  type SingleResult,
74
75
  type SubagentDetails,
75
76
  type SubagentUsageSummary,
77
+ type UsageStats,
76
78
  DEFAULT_DELEGATION_MODE,
77
79
  buildLiveSubagentDetails,
78
80
  buildSubagentDetails,
@@ -507,44 +509,63 @@ function collectLiveUsageSummary(details: SubagentDetails): SubagentUsageSummary
507
509
  return summary;
508
510
  }
509
511
 
512
+ type PersistedUsageTotals = {
513
+ leafId: unknown;
514
+ hasEntries: boolean;
515
+ parentUsage: UsageStats;
516
+ subagents: SubagentUsageSummary;
517
+ };
518
+
519
+ // SessionManager owns the history; a WeakMap lets its one current aggregate be
520
+ // reclaimed with the manager. Repeated progress/heartbeat updates no longer
521
+ // rescan a week-long branch when its leaf has not changed.
522
+ const persistedUsageCache = new WeakMap<object, PersistedUsageTotals>();
523
+
510
524
  function collectCombinedUsageStatusLine(
511
525
  ctx: any,
512
526
  liveSummaries: SubagentUsageSummary[] = [],
513
527
  ): string | undefined {
514
- const entries = typeof ctx?.sessionManager?.getEntries === "function" || typeof ctx?.sessionManager?.getBranch === "function"
515
- ? branchEntries(ctx)
516
- : [];
517
- if (entries.length === 0 && liveSummaries.length === 0) return undefined;
518
-
519
- const parentUsage = emptyUsage();
520
- const subagents = emptyUsageSummary();
521
- for (const entry of entries as any[]) {
522
- if (entry?.type !== "message") continue;
523
- const msg = entry.message;
524
- if (!msg) continue;
525
- if (msg.role === "assistant" && msg.provider !== RESUME_PROVIDER) {
526
- const usage = msg.usage;
527
- if (usage) {
528
- parentUsage.input += usage.input || 0;
529
- parentUsage.output += usage.output || 0;
530
- parentUsage.cacheRead += usage.cacheRead || 0;
531
- parentUsage.cacheWrite += usage.cacheWrite || 0;
532
- parentUsage.cost += typeof usage.cost === "number" ? usage.cost : usage.cost?.total || 0;
533
- parentUsage.turns += 1;
528
+ const manager = ctx?.sessionManager;
529
+ const canReadEntries = typeof manager?.getEntries === "function" || typeof manager?.getBranch === "function";
530
+ const leafId = typeof manager?.getLeafId === "function" ? manager.getLeafId() : undefined;
531
+ const cacheKey = manager !== null && typeof manager === "object" ? manager as object : undefined;
532
+ let persisted = cacheKey && leafId !== undefined ? persistedUsageCache.get(cacheKey) : undefined;
533
+
534
+ if (!persisted || persisted.leafId !== leafId) {
535
+ const entries = canReadEntries ? branchEntries(ctx) : [];
536
+ const parentUsage = emptyUsage();
537
+ const subagents = emptyUsageSummary();
538
+ for (const entry of entries as any[]) {
539
+ if (entry?.type !== "message") continue;
540
+ const msg = entry.message;
541
+ if (!msg) continue;
542
+ if (msg.role === "assistant" && msg.provider !== RESUME_PROVIDER) {
543
+ const usage = msg.usage;
544
+ if (usage) {
545
+ parentUsage.input += usage.input || 0;
546
+ parentUsage.output += usage.output || 0;
547
+ parentUsage.cacheRead += usage.cacheRead || 0;
548
+ parentUsage.cacheWrite += usage.cacheWrite || 0;
549
+ parentUsage.cost += typeof usage.cost === "number" ? usage.cost : usage.cost?.total || 0;
550
+ parentUsage.turns += 1;
551
+ }
552
+ }
553
+ if (msg.role === "toolResult" && isSubagentToolName(msg.toolName) && isSubagentDetails(msg.details)) {
554
+ addUsageSummary(
555
+ subagents,
556
+ msg.details.usageSummary ?? usageSummaryFromUsage(msg.details.aggregatedUsage),
557
+ );
534
558
  }
535
559
  }
536
- if (msg.role === "toolResult" && isSubagentToolName(msg.toolName) && isSubagentDetails(msg.details)) {
537
- addUsageSummary(
538
- subagents,
539
- msg.details.usageSummary ?? usageSummaryFromUsage(msg.details.aggregatedUsage),
540
- );
541
- }
542
- }
543
- for (const liveSummary of liveSummaries) {
544
- addUsageSummary(subagents, liveSummary);
560
+ persisted = { leafId, hasEntries: entries.length > 0, parentUsage, subagents };
561
+ if (cacheKey && leafId !== undefined) persistedUsageCache.set(cacheKey, persisted);
545
562
  }
546
- const subagentUsage = usageSummaryToUsageStats(subagents) ?? emptyUsage();
547
- addUsage(parentUsage, subagentUsage);
563
+
564
+ if (!persisted.hasEntries && liveSummaries.length === 0) return undefined;
565
+ const parentUsage = { ...persisted.parentUsage };
566
+ const subagents = { ...persisted.subagents };
567
+ for (const liveSummary of liveSummaries) addUsageSummary(subagents, liveSummary);
568
+ addUsage(parentUsage, usageSummaryToUsageStats(subagents) ?? emptyUsage());
548
569
  return formatCombinedUsageStatusLine(parentUsage, subagents.subagentCount);
549
570
  }
550
571
 
@@ -1464,6 +1485,11 @@ export default function (pi: ExtensionAPI) {
1464
1485
  activeSubagentUsageSummaries.clear();
1465
1486
  forcedErrorToolCallIds.clear();
1466
1487
  activeSubagents.clear();
1488
+ activeResumeNames.clear();
1489
+ approvedProjectAgentDirsForSession.clear();
1490
+ latestBroadcastTargets.all = [];
1491
+ latestBroadcastTargets.youngest = [];
1492
+ clearRenderCaches();
1467
1493
  });
1468
1494
 
1469
1495
  /**
@@ -1942,8 +1968,8 @@ ${agentList}\n\n${subagentsGuidance}\n\n${delegationGuardGuidance}${resumeGuidan
1942
1968
  },
1943
1969
 
1944
1970
  renderCall: (args, theme, context) => renderCall(args, theme, context),
1945
- renderResult: (result, { expanded }, theme) =>
1946
- renderResult(result, expanded, theme),
1971
+ renderResult: (result, { expanded }, theme, context) =>
1972
+ renderResult(result, expanded, theme, context),
1947
1973
  });
1948
1974
  };
1949
1975
 
@@ -2158,8 +2184,8 @@ ${agentList}\n\n${subagentsGuidance}\n\n${delegationGuardGuidance}${resumeGuidan
2158
2184
  },
2159
2185
 
2160
2186
  renderCall: (args, theme, context) => renderResumeCall(args, theme, context),
2161
- renderResult: (result, { expanded }, theme) =>
2162
- renderResult(result, expanded, theme),
2187
+ renderResult: (result, { expanded }, theme, context) =>
2188
+ renderResult(result, expanded, theme, context),
2163
2189
  });
2164
2190
  };
2165
2191
 
@@ -2225,34 +2251,38 @@ ${agentList}\n\n${subagentsGuidance}\n\n${delegationGuardGuidance}${resumeGuidan
2225
2251
  }
2226
2252
 
2227
2253
  let activeId: number | undefined;
2228
- const result = await runAgentSubprocess({
2229
- cwd: defaultCwd,
2230
- agents,
2231
- agentName,
2232
- task,
2233
- subagentName,
2234
- parentDepth: currentDepth,
2235
- parentAgentStack: ancestorAgentStack,
2236
- maxDepth,
2237
- preventCycles,
2238
- signal,
2239
- onUpdate,
2240
- makeDetails: makeDetails("single"),
2241
- sessionDir: previousResult?.sessionDir ?? sessionDir,
2242
- sessionRoot: currentSubagentSessionRoot,
2243
- namesFile: currentNamesFile || undefined,
2244
- resumeSession: resumeExistingSession,
2245
- initialResult: previousResult,
2246
- fallbackModel,
2247
- onHandle: (handle) => {
2248
- activeId = topLevelBaseId;
2249
- activeSubagents.set(activeId, { agent: agentName, task, handle, name: subagentName });
2254
+ let result: SingleResult;
2255
+ try {
2256
+ result = await runAgentSubprocess({
2257
+ cwd: defaultCwd,
2258
+ agents,
2259
+ agentName,
2260
+ task,
2261
+ subagentName,
2262
+ parentDepth: currentDepth,
2263
+ parentAgentStack: ancestorAgentStack,
2264
+ maxDepth,
2265
+ preventCycles,
2266
+ signal,
2267
+ onUpdate,
2268
+ makeDetails: makeDetails("single"),
2269
+ sessionDir: previousResult?.sessionDir ?? sessionDir,
2270
+ sessionRoot: currentSubagentSessionRoot,
2271
+ namesFile: currentNamesFile || undefined,
2272
+ resumeSession: resumeExistingSession,
2273
+ initialResult: previousResult,
2274
+ fallbackModel,
2275
+ onHandle: (handle) => {
2276
+ activeId = topLevelBaseId;
2277
+ activeSubagents.set(activeId, { agent: agentName, task, handle, name: subagentName });
2278
+ updateLatestBroadcastTargets(undefined);
2279
+ },
2280
+ });
2281
+ } finally {
2282
+ if (activeId !== undefined) {
2283
+ activeSubagents.delete(activeId);
2250
2284
  updateLatestBroadcastTargets(undefined);
2251
- },
2252
- });
2253
- if (activeId !== undefined) {
2254
- activeSubagents.delete(activeId);
2255
- updateLatestBroadcastTargets(undefined);
2285
+ }
2256
2286
  }
2257
2287
 
2258
2288
  if (isResultError(result)) {
@@ -2332,6 +2362,7 @@ ${agentList}\n\n${subagentsGuidance}\n\n${delegationGuardGuidance}${resumeGuidan
2332
2362
  );
2333
2363
  } finally {
2334
2364
  for (const id of taskIds.values()) activeSubagents.delete(id);
2365
+ updateLatestBroadcastTargets(undefined);
2335
2366
  }
2336
2367
  }
2337
2368
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oira666_pi-subagent",
3
- "version": "0.3.17",
3
+ "version": "0.3.18",
4
4
  "description": "Subagent extension for Pi coding agent. Delegate tasks to specialized agents.",
5
5
  "type": "module",
6
6
  "main": "index.ts",