@xynogen/pix-subagent 0.1.0

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/src/usage.ts ADDED
@@ -0,0 +1,71 @@
1
+ /** usage.ts — Token usage: shapes, accumulator operators, session-stats readers. */
2
+
3
+ /**
4
+ * Lifetime usage components, accumulated via `message_end` events. Survives
5
+ * compaction (which replaces session.state.messages and would reset any
6
+ * stats-derived sum). cacheRead is excluded because each turn's cacheRead is
7
+ * the cumulative cached prefix re-read on that one call — summing across
8
+ * turns counts the prefix N times. See issue #38.
9
+ */
10
+ export type LifetimeUsage = {
11
+ input: number;
12
+ output: number;
13
+ cacheWrite: number;
14
+ };
15
+
16
+ /** Sum of lifetime usage components, or 0 if undefined. */
17
+ export function getLifetimeTotal(u?: LifetimeUsage): number {
18
+ return u ? u.input + u.output + u.cacheWrite : 0;
19
+ }
20
+
21
+ /** Add a usage delta into a target accumulator (mutates target). */
22
+ export function addUsage(into: LifetimeUsage, delta: LifetimeUsage): void {
23
+ into.input += delta.input;
24
+ into.output += delta.output;
25
+ into.cacheWrite += delta.cacheWrite;
26
+ }
27
+
28
+ /** Minimal shape we read from upstream `getSessionStats()`. */
29
+ export type SessionStatsLike = {
30
+ tokens: { input: number; output: number; cacheWrite: number };
31
+ contextUsage?: { percent: number | null };
32
+ };
33
+ export type SessionLike = { getSessionStats(): SessionStatsLike };
34
+
35
+ /**
36
+ * Session-scoped token count: input + output + cacheWrite as reported by
37
+ * upstream `getSessionStats().tokens` for the *current* session window.
38
+ *
39
+ * RESETS at compaction — upstream replaces `session.state.messages` and the
40
+ * stats are derived from that array. For a lifetime total that survives
41
+ * compaction, use `getLifetimeTotal(lifetimeUsage)` instead, which reads
42
+ * from an independent accumulator fed by `message_end` events.
43
+ *
44
+ * Avoids upstream's `tokens.total` field, which sums per-turn `cacheRead`
45
+ * and so counts the cumulative cached prefix N times across N turns
46
+ * (issue #38).
47
+ */
48
+ export function getSessionTokens(session: SessionLike | undefined): number {
49
+ if (!session) return 0;
50
+ try {
51
+ const t = session.getSessionStats().tokens;
52
+ return t.input + t.output + t.cacheWrite;
53
+ } catch {
54
+ return 0;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Context-window utilization (0–100), or null when unavailable
60
+ * (no model contextWindow, or post-compaction before the next response).
61
+ */
62
+ export function getSessionContextPercent(
63
+ session: SessionLike | undefined,
64
+ ): number | null {
65
+ if (!session) return null;
66
+ try {
67
+ return session.getSessionStats().contextUsage?.percent ?? null;
68
+ } catch {
69
+ return null;
70
+ }
71
+ }