@ferris1225/pi-subagents 4.3.14 → 4.3.15
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 +9 -0
- package/README.md +7 -1
- package/package.json +1 -1
- package/src/presentation/cost-footer.ts +6 -7
- package/src/presentation/cost-ledger.ts +6 -23
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
Release notes for `@ferris1225/pi-subagents`. Only the most recent releases
|
|
4
4
|
are kept here; every published version is preserved as a GitHub Release.
|
|
5
5
|
|
|
6
|
+
## 4.3.15
|
|
7
|
+
|
|
8
|
+
- Fix the cost footer's stale-context crash after reload, new session, resume,
|
|
9
|
+
or fork. Remove the module-global event context cache and render against
|
|
10
|
+
the installed footer's own live session context. Existing shutdown cleanup
|
|
11
|
+
removes the footer and its subscriptions before that context is invalidated.
|
|
12
|
+
- Cover replacement-session rendering with Pi's real context invalidation,
|
|
13
|
+
subscription cleanup, and live model/thinking/context/session-name updates.
|
|
14
|
+
|
|
6
15
|
## 4.3.13
|
|
7
16
|
|
|
8
17
|
- Remove the `subagents N running · …` activity-count line from the footer.
|
package/README.md
CHANGED
|
@@ -12,6 +12,10 @@ once and your main agent delegates on its own.
|
|
|
12
12
|
|
|
13
13
|
## What's new
|
|
14
14
|
|
|
15
|
+
**4.3.15** — fix the cost footer crash after `/reload`, `/new`, `/resume`, or
|
|
16
|
+
`/fork`: each footer now reads only its own session's live context, never an
|
|
17
|
+
event context retained from the previous session.
|
|
18
|
+
|
|
15
19
|
**4.3.13** — the footer is reserved for the per-model cost tally: the
|
|
16
20
|
`subagents N running` activity-count line is gone, leaving the widget,
|
|
17
21
|
completion notifications, and `subagent_status` for live progress.
|
|
@@ -389,7 +393,9 @@ under width pressure a settled row drops its token flow before truncating, so
|
|
|
389
393
|
children report their own usage per run when they settle, and pi would
|
|
390
394
|
otherwise attribute it to one session total — exactly the cross-model merge
|
|
391
395
|
this footer exists to avoid. The ledger reseeds from the session file on
|
|
392
|
-
reload
|
|
396
|
+
reload or session replacement. The footer is removed at session shutdown and
|
|
397
|
+
reinstalled with the new session's live context, so switching or reloading
|
|
398
|
+
never reuses a stale context from the previous session.
|
|
393
399
|
|
|
394
400
|
Completions resume the main agent on their own, with a compact block of at most 40
|
|
395
401
|
lines by default; longer output lands unchanged in a Markdown artifact whose path
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ferris1225/pi-subagents",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.15",
|
|
4
4
|
"description": "A managed sub-agent team for pi: scout, artisan, steward, and sentinel roles, one-shot runs, read-only status, and Git worktree isolation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,7 +14,7 @@ import type { ExtensionContext, Theme } from "@earendil-works/pi-coding-agent";
|
|
|
14
14
|
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
15
15
|
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
16
16
|
import { stripVTControlCharacters } from "node:util";
|
|
17
|
-
import { costLedger,
|
|
17
|
+
import { costLedger, type ModelSpendRow } from "./cost-ledger.ts";
|
|
18
18
|
import { formatTokens, formatUsageTokens } from "./monitor.ts";
|
|
19
19
|
import type { UsageStats } from "../execution/rpc-control.ts";
|
|
20
20
|
|
|
@@ -26,8 +26,7 @@ interface FooterData {
|
|
|
26
26
|
onBranchChange(callback: () => void): () => void;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
/**
|
|
30
|
-
* context so a fresh install still sees live session state. */
|
|
29
|
+
/** Live context owned by the installed footer's session. */
|
|
31
30
|
type RenderContext = Partial<Pick<ExtensionContext, "sessionManager" | "getContextUsage" | "model" | "thinkingLevel">>;
|
|
32
31
|
|
|
33
32
|
/** Minimum gap between the stats left side and the right-aligned model. */
|
|
@@ -135,8 +134,7 @@ export function renderCostFooter(
|
|
|
135
134
|
footerData: FooterData | undefined,
|
|
136
135
|
ctx: RenderContext,
|
|
137
136
|
): string[] {
|
|
138
|
-
const
|
|
139
|
-
const sessionManager = live.sessionManager ?? ctx.sessionManager;
|
|
137
|
+
const sessionManager = ctx.sessionManager;
|
|
140
138
|
const lines: string[] = [];
|
|
141
139
|
|
|
142
140
|
let project = formatProjectPath(sessionManager?.getCwd() ?? "", process.env.HOME || process.env.USERPROFILE);
|
|
@@ -149,7 +147,7 @@ export function renderCostFooter(
|
|
|
149
147
|
const rows = costLedger.snapshot();
|
|
150
148
|
if (rows.length > 0) {
|
|
151
149
|
const current = rows.find((row) => row.current);
|
|
152
|
-
if (current) lines.push(currentModelLine(current, theme, width,
|
|
150
|
+
if (current) lines.push(currentModelLine(current, theme, width, ctx));
|
|
153
151
|
const settled = rows
|
|
154
152
|
.filter((row) => !row.current)
|
|
155
153
|
.sort((left, right) => right.spend.cost - left.spend.cost);
|
|
@@ -176,7 +174,8 @@ export function renderCostFooter(
|
|
|
176
174
|
/**
|
|
177
175
|
* Replace pi's built-in footer with the per-model cost footer. The factory
|
|
178
176
|
* re-renders on ledger updates and git branch changes; context, model, and
|
|
179
|
-
* thinking state
|
|
177
|
+
* thinking state use Pi's live getters for this session. Shutdown clears the
|
|
178
|
+
* footer before Pi invalidates its context.
|
|
180
179
|
*/
|
|
181
180
|
export function installCostFooter(ctx: Pick<ExtensionContext, "mode" | "ui"> & RenderContext): void {
|
|
182
181
|
if (ctx.mode !== "tui") return;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* each model keeps its own tally — plus its live token throughput.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type { ExtensionAPI
|
|
12
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
13
13
|
import { modelRef } from "../configuration/models.ts";
|
|
14
14
|
|
|
15
15
|
export interface ModelSpend {
|
|
@@ -198,28 +198,18 @@ export class CostLedger {
|
|
|
198
198
|
|
|
199
199
|
export const costLedger = new CostLedger();
|
|
200
200
|
|
|
201
|
-
/** Latest event context, so the footer renders against live session state
|
|
202
|
-
* (context usage, cwd, session name) without holding a stale install-time ctx. */
|
|
203
|
-
let latestContext: ExtensionContext | undefined;
|
|
204
|
-
|
|
205
201
|
/** Wire the main window's own generation into the ledger: assistant messages
|
|
206
202
|
* carry the serving model and exact usage, model switches re-key the current
|
|
207
203
|
* row, and compaction calls land on the model that made them. */
|
|
208
204
|
export function registerMainCostTracking(pi: ExtensionAPI): void {
|
|
209
|
-
|
|
210
|
-
latestContext = ctx;
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
pi.on("message_start", async (event, ctx) => {
|
|
214
|
-
remember(ctx);
|
|
205
|
+
pi.on("message_start", async (event) => {
|
|
215
206
|
const message = (event as { message?: { role?: string } }).message;
|
|
216
207
|
if (message?.role !== "assistant") return;
|
|
217
208
|
const ref = messageModelRef(message as { provider?: string; model?: string });
|
|
218
209
|
if (ref) costLedger.noteStreamStart(ref);
|
|
219
210
|
});
|
|
220
211
|
|
|
221
|
-
pi.on("message_update", async (event
|
|
222
|
-
remember(ctx);
|
|
212
|
+
pi.on("message_update", async (event) => {
|
|
223
213
|
const delta = (event as { assistantMessageEvent?: { type?: string; delta?: string } }).assistantMessageEvent;
|
|
224
214
|
if (delta?.type !== "text_delta" && delta?.type !== "thinking_delta") return;
|
|
225
215
|
// `message_start` does not always carry the model yet; the first delta
|
|
@@ -234,8 +224,7 @@ export function registerMainCostTracking(pi: ExtensionAPI): void {
|
|
|
234
224
|
costLedger.noteStreamDelta(delta.delta?.length ?? 0);
|
|
235
225
|
});
|
|
236
226
|
|
|
237
|
-
pi.on("message_end", async (event
|
|
238
|
-
remember(ctx);
|
|
227
|
+
pi.on("message_end", async (event) => {
|
|
239
228
|
const message = (event as { message?: { role?: string; provider?: string; model?: string; usage?: UsageLike } }).message;
|
|
240
229
|
if (message?.role !== "assistant") return;
|
|
241
230
|
const ref = messageModelRef(message) ?? costLedger.getCurrentModel();
|
|
@@ -245,15 +234,13 @@ export function registerMainCostTracking(pi: ExtensionAPI): void {
|
|
|
245
234
|
costLedger.record(ref, usage);
|
|
246
235
|
});
|
|
247
236
|
|
|
248
|
-
pi.on("model_select", async (event
|
|
249
|
-
remember(ctx);
|
|
237
|
+
pi.on("model_select", async (event) => {
|
|
250
238
|
costLedger.markCurrentModel(modelRef(event.model));
|
|
251
239
|
});
|
|
252
240
|
|
|
253
241
|
pi.on("session_compact", async (event, ctx) => {
|
|
254
|
-
remember(ctx);
|
|
255
242
|
const usage = (event as { compactionEntry?: { usage?: UsageLike } }).compactionEntry?.usage;
|
|
256
|
-
const ref = costLedger.getCurrentModel() ?? (
|
|
243
|
+
const ref = costLedger.getCurrentModel() ?? (ctx.model ? modelRef(ctx.model) : undefined);
|
|
257
244
|
if (usage && ref) costLedger.record(ref, finiteUsage(usage));
|
|
258
245
|
});
|
|
259
246
|
}
|
|
@@ -280,7 +267,3 @@ export function seedCostLedgerFromSession(ctx: {
|
|
|
280
267
|
}
|
|
281
268
|
}
|
|
282
269
|
}
|
|
283
|
-
|
|
284
|
-
export function latestTrackedContext(): ExtensionContext | undefined {
|
|
285
|
-
return latestContext;
|
|
286
|
-
}
|