@ryan_nookpi/pi-extension-subagent 0.5.1 → 0.5.2

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/activity.ts CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
9
9
  import type { CommandRunState } from "./types.js";
10
+ import { getUsedContextPercent } from "./utils/format-utils.js";
10
11
 
11
12
  export const SUBAGENT_ACTIVITY_CUSTOM_TYPE = "subagent-activity";
12
13
  export const SUBAGENT_ACTIVITY_SCHEMA_VERSION = 1;
@@ -24,6 +25,7 @@ export interface ActivitySnapshot {
24
25
  toolCallCount: number;
25
26
  lastLine?: string;
26
27
  contextTokens?: number;
28
+ contextWindow?: number;
27
29
  }
28
30
 
29
31
  export interface ActivityPayload {
@@ -36,12 +38,15 @@ export interface ActivityPayload {
36
38
  toolCallCount: number;
37
39
  lastLine?: string;
38
40
  contextTokens?: number;
41
+ contextWindow?: number;
42
+ contextPercent?: number;
39
43
  }
40
44
 
41
45
  export interface ActivityThrottleState {
42
46
  lastEmittedAt: number;
43
47
  lastEmittedToolName?: string;
44
48
  lastEmittedToolCallCount?: number;
49
+ lastEmittedContextPercent?: number;
45
50
  }
46
51
 
47
52
  export function createActivityThrottleState(): ActivityThrottleState {
@@ -69,8 +74,8 @@ export function normalizeActivityLine(text: string | undefined): string | undefi
69
74
  /**
70
75
  * Change-driven throttle policy. Returns a payload to emit, or null.
71
76
  *
72
- * Emits only while the run is `running`, only when `lastToolName` or
73
- * `toolCallCount` changed since the last emission, and at most once per
77
+ * Emits only while the run is `running`, when tool metadata or the displayed
78
+ * context percentage changes, and at most once per
74
79
  * `ACTIVITY_MIN_INTERVAL_MS` per run. A change suppressed by the interval
75
80
  * stays pending and emits on a later evaluation.
76
81
  */
@@ -84,14 +89,18 @@ export function evaluateActivityEmission(
84
89
  // on the run state, so a positive count is required regardless of the name.
85
90
  if (snapshot.toolCallCount <= 0) return null;
86
91
 
92
+ const contextPercent = getUsedContextPercent(snapshot.contextTokens, snapshot.contextWindow);
87
93
  const changed =
88
- snapshot.lastToolName !== state.lastEmittedToolName || snapshot.toolCallCount !== state.lastEmittedToolCallCount;
94
+ snapshot.lastToolName !== state.lastEmittedToolName ||
95
+ snapshot.toolCallCount !== state.lastEmittedToolCallCount ||
96
+ contextPercent !== state.lastEmittedContextPercent;
89
97
  if (!changed) return null;
90
98
  if (state.lastEmittedAt !== 0 && now - state.lastEmittedAt < ACTIVITY_MIN_INTERVAL_MS) return null;
91
99
 
92
100
  state.lastEmittedAt = now;
93
101
  state.lastEmittedToolName = snapshot.lastToolName;
94
102
  state.lastEmittedToolCallCount = snapshot.toolCallCount;
103
+ state.lastEmittedContextPercent = contextPercent;
95
104
 
96
105
  const payload: ActivityPayload = {
97
106
  runId: snapshot.runId,
@@ -105,10 +114,12 @@ export function evaluateActivityEmission(
105
114
  const lastLine = normalizeActivityLine(snapshot.lastLine);
106
115
  if (lastLine) payload.lastLine = lastLine;
107
116
  if (snapshot.contextTokens != null && snapshot.contextTokens > 0) payload.contextTokens = snapshot.contextTokens;
117
+ if (snapshot.contextWindow != null && snapshot.contextWindow > 0) payload.contextWindow = snapshot.contextWindow;
118
+ if (contextPercent !== undefined) payload.contextPercent = contextPercent;
108
119
  return payload;
109
120
  }
110
121
 
111
- export function snapshotFromRunState(runState: CommandRunState): ActivitySnapshot {
122
+ export function snapshotFromRunState(runState: CommandRunState, contextWindow?: number): ActivitySnapshot {
112
123
  return {
113
124
  status: runState.status,
114
125
  runId: runState.id,
@@ -120,6 +131,7 @@ export function snapshotFromRunState(runState: CommandRunState): ActivitySnapsho
120
131
  toolCallCount: runState.toolCalls,
121
132
  lastLine: runState.lastLine,
122
133
  contextTokens: runState.usage?.contextTokens,
134
+ contextWindow,
123
135
  };
124
136
  }
125
137
 
@@ -130,11 +142,16 @@ export function snapshotFromRunState(runState: CommandRunState): ActivitySnapsho
130
142
  export function createRunActivityRecorder(
131
143
  pi: Pick<ExtensionAPI, "appendEntry">,
132
144
  runState: CommandRunState,
145
+ resolveContextWindow?: (model?: string) => number | undefined,
133
146
  ): () => void {
134
147
  const throttleState = createActivityThrottleState();
135
148
  return () => {
136
149
  try {
137
- const payload = evaluateActivityEmission(throttleState, snapshotFromRunState(runState), Date.now());
150
+ const payload = evaluateActivityEmission(
151
+ throttleState,
152
+ snapshotFromRunState(runState, resolveContextWindow?.(runState.model)),
153
+ Date.now(),
154
+ );
138
155
  if (!payload) return;
139
156
  pi.appendEntry(SUBAGENT_ACTIVITY_CUSTOM_TYPE, {
140
157
  schemaVersion: SUBAGENT_ACTIVITY_SCHEMA_VERSION,
package/commands.ts CHANGED
@@ -35,7 +35,14 @@ import {
35
35
  shouldSummarizeSubagentTask,
36
36
  summarizeSubagentDisplayTask,
37
37
  } from "./display-task.js";
38
- import { AGENT_NAME_PALETTE, agentBgIndex, formatUsageStats, truncateLines, truncatePlainToWidth } from "./format.js";
38
+ import {
39
+ AGENT_NAME_PALETTE,
40
+ agentBgIndex,
41
+ formatUsageStats,
42
+ resolveContextWindow,
43
+ truncateLines,
44
+ truncatePlainToWidth,
45
+ } from "./format.js";
39
46
  import {
40
47
  clearPendingGroupCompletion,
41
48
  consumePendingGroupCompletionsForSession,
@@ -1402,7 +1409,9 @@ export function registerAll(pi: ExtensionAPI, store: SubagentStore): SubagentReg
1402
1409
  }, RUN_TICK_INTERVAL_MS);
1403
1410
 
1404
1411
  let claudeCheckpointSent = !!runState.claudeSessionId;
1405
- const recordActivity = hiddenFromMain ? () => {} : createRunActivityRecorder(pi, runState);
1412
+ const recordActivity = hiddenFromMain
1413
+ ? () => {}
1414
+ : createRunActivityRecorder(pi, runState, (model) => resolveContextWindow(ctx, model));
1406
1415
  void (async () => {
1407
1416
  try {
1408
1417
  const { result, retryCount } = await invokeWithAutoRetry({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryan_nookpi/pi-extension-subagent",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Asynchronous subagent delegation for pi with run, batch, chain, and continuation workflows.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/tool-execute.ts CHANGED
@@ -1319,7 +1319,7 @@ export function createSubagentToolExecute(pi: ExtensionAPI, store: SubagentStore
1319
1319
 
1320
1320
  function launchRunInBackground(runState: CommandRunState, taskForAgent: string): Promise<FinalizedRun> {
1321
1321
  let claudeCheckpointSent = !!runState.claudeSessionId;
1322
- const recordActivity = createRunActivityRecorder(pi, runState);
1322
+ const recordActivity = createRunActivityRecorder(pi, runState, (model) => resolveContextWindow(ctx, model));
1323
1323
  return enqueueSubagentInvocation(() =>
1324
1324
  runSingleAgent(
1325
1325
  ctx.cwd,