tokenlens-cli 1.0.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/README.md +164 -0
- package/dist/analyzer/index.d.ts +44 -0
- package/dist/analyzer/index.d.ts.map +1 -0
- package/dist/analyzer/index.js +280 -0
- package/dist/analyzer/index.js.map +1 -0
- package/dist/cli/commands.d.ts +3 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +430 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/config.d.ts +29 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +106 -0
- package/dist/config.js.map +1 -0
- package/dist/dashboard/server.d.ts +12 -0
- package/dist/dashboard/server.d.ts.map +1 -0
- package/dist/dashboard/server.js +195 -0
- package/dist/dashboard/server.js.map +1 -0
- package/dist/db/schema.d.ts +34 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +118 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/store.d.ts +62 -0
- package/dist/db/store.d.ts.map +1 -0
- package/dist/db/store.js +110 -0
- package/dist/db/store.js.map +1 -0
- package/dist/importers/logs.d.ts +11 -0
- package/dist/importers/logs.d.ts.map +1 -0
- package/dist/importers/logs.js +243 -0
- package/dist/importers/logs.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy/server.d.ts +11 -0
- package/dist/proxy/server.d.ts.map +1 -0
- package/dist/proxy/server.js +153 -0
- package/dist/proxy/server.js.map +1 -0
- package/package.json +51 -0
- package/patches/http-mitm-proxy+1.1.0.patch +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# TokenLens
|
|
2
|
+
|
|
3
|
+
TokenLens is a local CLI that imports AI token usage, captures live API usage
|
|
4
|
+
through a proxy, finds wasted tokens, and tells you where to cut them.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
For local development:
|
|
9
|
+
|
|
10
|
+
```powershell
|
|
11
|
+
npm install
|
|
12
|
+
npm run build
|
|
13
|
+
npm link
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Then use the installed binary directly:
|
|
17
|
+
|
|
18
|
+
```powershell
|
|
19
|
+
tl init
|
|
20
|
+
tl doctor
|
|
21
|
+
tl quickstart
|
|
22
|
+
tl analyze
|
|
23
|
+
tl start
|
|
24
|
+
tl watch
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
For package users, the publishable npm package name is `tokenlens-cli`, while
|
|
28
|
+
the installed commands are `tokenlens` and `tl`:
|
|
29
|
+
|
|
30
|
+
```powershell
|
|
31
|
+
npm install -g tokenlens-cli
|
|
32
|
+
tl init
|
|
33
|
+
tl quickstart
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Legacy `tg` still works as a compatibility alias.
|
|
37
|
+
|
|
38
|
+
## What it measures
|
|
39
|
+
|
|
40
|
+
- Codex session logs from `~/.codex/sessions`
|
|
41
|
+
- Claude Code logs from `~/.claude/projects`
|
|
42
|
+
- OpenAI, Anthropic, Gemini, Groq, DeepSeek, Together, Perplexity, xAI,
|
|
43
|
+
Mistral, Cohere, Ollama, and LM Studio traffic routed through the proxy
|
|
44
|
+
- Custom JSON or JSONL exports containing OpenAI-, Anthropic-, Gemini-, or
|
|
45
|
+
Ollama-style usage fields
|
|
46
|
+
|
|
47
|
+
## Commands
|
|
48
|
+
|
|
49
|
+
`tl init`
|
|
50
|
+
- Saves local config in `~/.tokenlens/config.json`
|
|
51
|
+
- Lets users set DB path, proxy port, import paths, tool name, and watch interval
|
|
52
|
+
|
|
53
|
+
`tl doctor`
|
|
54
|
+
- Checks config, import paths, database state, and whether live capture is running
|
|
55
|
+
- Prints the next useful command
|
|
56
|
+
|
|
57
|
+
`tl quickstart`
|
|
58
|
+
- Imports logs from configured paths
|
|
59
|
+
- Prints total usage and the top waste finding
|
|
60
|
+
|
|
61
|
+
`tl scan`
|
|
62
|
+
- Imports historical logs
|
|
63
|
+
- Safe to rerun
|
|
64
|
+
|
|
65
|
+
`tl watch`
|
|
66
|
+
- Re-imports changed log files on a timer
|
|
67
|
+
- Good for Codex and Claude Code local usage
|
|
68
|
+
|
|
69
|
+
`tl analyze`
|
|
70
|
+
- Shows waste findings for the last 7 days by default
|
|
71
|
+
- Use `tl analyze --json` for machine-readable output
|
|
72
|
+
|
|
73
|
+
`tl stats`
|
|
74
|
+
- Shows totals for the last 24 hours by default
|
|
75
|
+
|
|
76
|
+
`tl start`
|
|
77
|
+
- Starts live capture on the configured proxy port
|
|
78
|
+
- Point supported tools or SDKs at `http://127.0.0.1:8080` unless you changed it
|
|
79
|
+
|
|
80
|
+
`tl list`
|
|
81
|
+
- Shows recent calls
|
|
82
|
+
|
|
83
|
+
`tl summary`
|
|
84
|
+
- Shows lifetime totals
|
|
85
|
+
|
|
86
|
+
Short aliases:
|
|
87
|
+
|
|
88
|
+
```powershell
|
|
89
|
+
tl a
|
|
90
|
+
tl s
|
|
91
|
+
tl ls
|
|
92
|
+
tl up
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Typical flows
|
|
96
|
+
|
|
97
|
+
Historical analysis only:
|
|
98
|
+
|
|
99
|
+
```powershell
|
|
100
|
+
tl quickstart
|
|
101
|
+
tl analyze
|
|
102
|
+
tl stats
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Keep local logs up to date:
|
|
106
|
+
|
|
107
|
+
```powershell
|
|
108
|
+
tl watch
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Live capture for SDK and proxyable API usage:
|
|
112
|
+
|
|
113
|
+
```powershell
|
|
114
|
+
tl start
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Configuration
|
|
118
|
+
|
|
119
|
+
Saved config lives at:
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
~/.tokenlens/config.json
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
TokenLens automatically migrates the old `~/.token-guard` config and database
|
|
126
|
+
into `~/.tokenlens` on first run.
|
|
127
|
+
|
|
128
|
+
Environment variables:
|
|
129
|
+
|
|
130
|
+
```powershell
|
|
131
|
+
$env:TL_PROXY_PORT = "8080"
|
|
132
|
+
$env:TL_DB_PATH = "C:\path\tokenlens.db"
|
|
133
|
+
$env:TL_UPSTREAM_PROXY = "http://proxy.example:8080"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Legacy `TG_*` environment variables are still accepted.
|
|
137
|
+
|
|
138
|
+
## Waste analysis quality
|
|
139
|
+
|
|
140
|
+
The analyzer reports:
|
|
141
|
+
|
|
142
|
+
- exact duplicate retries when the same prompt fingerprint repeats
|
|
143
|
+
- lower-bound repeated context across a session
|
|
144
|
+
- exact cache-miss evidence where providers expose cached token counts
|
|
145
|
+
- exact reasoning-token overhead where providers expose reasoning counts
|
|
146
|
+
- heuristic low-yield prompts when large context produces tiny answers
|
|
147
|
+
|
|
148
|
+
## Constraints
|
|
149
|
+
|
|
150
|
+
No tool can recover universal token usage after the fact.
|
|
151
|
+
|
|
152
|
+
TokenLens cannot measure a tool when all of these are true:
|
|
153
|
+
|
|
154
|
+
- The tool does not expose token counts in logs or exports.
|
|
155
|
+
- Its traffic is not routed through the local proxy.
|
|
156
|
+
- Its encrypted connection does not trust the proxy certificate.
|
|
157
|
+
- The provider response omits usage metadata.
|
|
158
|
+
|
|
159
|
+
CommandCode prompt history, Gemini/Antigravity transcripts, and Ollama shell
|
|
160
|
+
history on this machine did not contain token counters during validation. For
|
|
161
|
+
those tools, route traffic through TokenLens or export structured usage logs.
|
|
162
|
+
|
|
163
|
+
Costs are estimates based on the bundled pricing table. Subscription usage,
|
|
164
|
+
cached-token discounts, and newly released model prices may not match billing.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { TokenStore } from "../db/store.js";
|
|
2
|
+
export interface FindingExample {
|
|
3
|
+
sessionId: string;
|
|
4
|
+
toolName: string;
|
|
5
|
+
provider: string;
|
|
6
|
+
model: string;
|
|
7
|
+
calls: number;
|
|
8
|
+
tokens: number;
|
|
9
|
+
estimatedWasteTokens: number;
|
|
10
|
+
promptPreview: string;
|
|
11
|
+
}
|
|
12
|
+
export interface Finding {
|
|
13
|
+
kind: string;
|
|
14
|
+
severity: "high" | "medium" | "low";
|
|
15
|
+
confidence: "exact" | "lower-bound" | "heuristic";
|
|
16
|
+
title: string;
|
|
17
|
+
reason: string;
|
|
18
|
+
recommendation: string;
|
|
19
|
+
calls: number;
|
|
20
|
+
tokens: number;
|
|
21
|
+
estimatedWasteTokens: number;
|
|
22
|
+
examples: FindingExample[];
|
|
23
|
+
}
|
|
24
|
+
export interface TopSession {
|
|
25
|
+
sessionId: string;
|
|
26
|
+
toolName: string;
|
|
27
|
+
provider: string;
|
|
28
|
+
model: string;
|
|
29
|
+
calls: number;
|
|
30
|
+
totalTokens: number;
|
|
31
|
+
totalCost: number;
|
|
32
|
+
}
|
|
33
|
+
export interface AnalysisReport {
|
|
34
|
+
periodHours: number;
|
|
35
|
+
calls: number;
|
|
36
|
+
totalTokens: number;
|
|
37
|
+
estimatedWasteTokens: number;
|
|
38
|
+
wastePercent: number;
|
|
39
|
+
findings: Finding[];
|
|
40
|
+
topSessions: TopSession[];
|
|
41
|
+
coverage: string[];
|
|
42
|
+
}
|
|
43
|
+
export declare function analyzeUsage(store: TokenStore, hours?: number): AnalysisReport;
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGjD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACpC,UAAU,EAAE,OAAO,GAAG,aAAa,GAAG,WAAW,CAAC;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA4TD,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,SAAM,GAAG,cAAc,CA0C3E"}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { createHash } from "crypto";
|
|
2
|
+
function sessionKey(call) {
|
|
3
|
+
if (call.session_id)
|
|
4
|
+
return call.session_id;
|
|
5
|
+
return `${call.tool_name}:${providerName(call)}:${call.model}`;
|
|
6
|
+
}
|
|
7
|
+
function sessionLabel(group) {
|
|
8
|
+
return group.sessionId || `${group.toolName}/${group.model}`;
|
|
9
|
+
}
|
|
10
|
+
function cleanPreview(value) {
|
|
11
|
+
return value.replace(/\s+/g, " ").trim().slice(0, 160);
|
|
12
|
+
}
|
|
13
|
+
function normalizePrompt(value) {
|
|
14
|
+
return value.toLowerCase().replace(/\s+/g, " ").trim();
|
|
15
|
+
}
|
|
16
|
+
function hashPrompt(value) {
|
|
17
|
+
const normalized = normalizePrompt(value);
|
|
18
|
+
if (!normalized)
|
|
19
|
+
return null;
|
|
20
|
+
return createHash("sha1").update(normalized).digest("hex");
|
|
21
|
+
}
|
|
22
|
+
function hashPromptFamily(value) {
|
|
23
|
+
const normalized = normalizePrompt(value);
|
|
24
|
+
if (!normalized)
|
|
25
|
+
return null;
|
|
26
|
+
const family = normalized.split(" ").slice(0, 40).join(" ");
|
|
27
|
+
if (!family)
|
|
28
|
+
return null;
|
|
29
|
+
return createHash("sha1").update(family).digest("hex");
|
|
30
|
+
}
|
|
31
|
+
function effectivePromptHash(call) {
|
|
32
|
+
return call.prompt_hash ?? hashPrompt(call.prompt_preview);
|
|
33
|
+
}
|
|
34
|
+
function effectivePromptFamilyHash(call) {
|
|
35
|
+
return call.prompt_family_hash ?? hashPromptFamily(call.prompt_preview);
|
|
36
|
+
}
|
|
37
|
+
function providerName(call) {
|
|
38
|
+
if (call.provider && call.provider !== "unknown")
|
|
39
|
+
return call.provider;
|
|
40
|
+
if (call.source === "claude")
|
|
41
|
+
return "Anthropic";
|
|
42
|
+
if (call.source === "codex")
|
|
43
|
+
return "OpenAI";
|
|
44
|
+
if (call.endpoint)
|
|
45
|
+
return call.endpoint;
|
|
46
|
+
return "unknown";
|
|
47
|
+
}
|
|
48
|
+
function sum(items, pick) {
|
|
49
|
+
return items.reduce((total, item) => total + pick(item), 0);
|
|
50
|
+
}
|
|
51
|
+
function groupBySession(calls) {
|
|
52
|
+
const groups = new Map();
|
|
53
|
+
for (const call of [...calls].sort((a, b) => a.created_at.localeCompare(b.created_at))) {
|
|
54
|
+
const key = sessionKey(call);
|
|
55
|
+
const existing = groups.get(key);
|
|
56
|
+
if (existing) {
|
|
57
|
+
existing.calls.push(call);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
groups.set(key, {
|
|
61
|
+
key,
|
|
62
|
+
sessionId: call.session_id ?? `${call.tool_name}/${call.provider}/${call.model}`,
|
|
63
|
+
toolName: call.tool_name,
|
|
64
|
+
provider: providerName(call),
|
|
65
|
+
model: call.model,
|
|
66
|
+
calls: [call],
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return [...groups.values()];
|
|
70
|
+
}
|
|
71
|
+
function toExample(group, calls, estimatedWasteTokens) {
|
|
72
|
+
const sample = calls.find((call) => cleanPreview(call.prompt_preview)) ?? calls[0];
|
|
73
|
+
return {
|
|
74
|
+
sessionId: sessionLabel(group),
|
|
75
|
+
toolName: group.toolName,
|
|
76
|
+
provider: group.provider,
|
|
77
|
+
model: group.model,
|
|
78
|
+
calls: calls.length,
|
|
79
|
+
tokens: sum(calls, (call) => call.total_tokens),
|
|
80
|
+
estimatedWasteTokens,
|
|
81
|
+
promptPreview: cleanPreview(sample.prompt_preview),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function buildFinding(groups, kind, severity, confidence, title, reason, recommendation) {
|
|
85
|
+
if (!groups.length)
|
|
86
|
+
return null;
|
|
87
|
+
return {
|
|
88
|
+
kind,
|
|
89
|
+
severity,
|
|
90
|
+
confidence,
|
|
91
|
+
title,
|
|
92
|
+
reason,
|
|
93
|
+
recommendation,
|
|
94
|
+
calls: sum(groups, (group) => group.calls),
|
|
95
|
+
tokens: sum(groups, (group) => group.tokens),
|
|
96
|
+
estimatedWasteTokens: sum(groups, (group) => group.estimatedWasteTokens),
|
|
97
|
+
examples: groups
|
|
98
|
+
.sort((a, b) => b.estimatedWasteTokens - a.estimatedWasteTokens)
|
|
99
|
+
.slice(0, 3)
|
|
100
|
+
.map((group) => group.example),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function analyzeDuplicateRetries(groups) {
|
|
104
|
+
const offenders = [];
|
|
105
|
+
for (const group of groups) {
|
|
106
|
+
const byPrompt = new Map();
|
|
107
|
+
for (const call of group.calls) {
|
|
108
|
+
if (!call.prompt_hash)
|
|
109
|
+
continue;
|
|
110
|
+
const key = effectivePromptHash(call);
|
|
111
|
+
if (!key)
|
|
112
|
+
continue;
|
|
113
|
+
byPrompt.set(key, [...(byPrompt.get(key) ?? []), call]);
|
|
114
|
+
}
|
|
115
|
+
for (const calls of byPrompt.values()) {
|
|
116
|
+
if (calls.length < 2)
|
|
117
|
+
continue;
|
|
118
|
+
const ordered = [...calls].sort((a, b) => a.created_at.localeCompare(b.created_at));
|
|
119
|
+
const duplicates = ordered.slice(1);
|
|
120
|
+
const waste = sum(duplicates, (call) => call.prompt_tokens);
|
|
121
|
+
if (waste <= 0)
|
|
122
|
+
continue;
|
|
123
|
+
offenders.push({
|
|
124
|
+
calls: ordered.length,
|
|
125
|
+
tokens: sum(ordered, (call) => call.total_tokens),
|
|
126
|
+
estimatedWasteTokens: waste,
|
|
127
|
+
example: toExample(group, ordered, waste),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const top = offenders.sort((a, b) => b.estimatedWasteTokens - a.estimatedWasteTokens)[0];
|
|
132
|
+
const recommendation = top
|
|
133
|
+
? `In ${top.example.sessionId}, collapse retries into one corrective turn. Include the failure output once, ask for a diff or next action, and avoid resending the same request verbatim.`
|
|
134
|
+
: "";
|
|
135
|
+
return buildFinding(offenders, "duplicate-retries", "high", "exact", "Exact duplicate retries", "Identical prompts were sent more than once in the same session. The repeated prompt tokens are counted directly from the duplicated calls.", recommendation);
|
|
136
|
+
}
|
|
137
|
+
function analyzeRepeatedContext(groups) {
|
|
138
|
+
const offenders = [];
|
|
139
|
+
for (const group of groups) {
|
|
140
|
+
const byFamily = new Map();
|
|
141
|
+
for (const call of group.calls) {
|
|
142
|
+
const family = effectivePromptFamilyHash(call);
|
|
143
|
+
if (!family || call.prompt_tokens < 4_000)
|
|
144
|
+
continue;
|
|
145
|
+
byFamily.set(family, [...(byFamily.get(family) ?? []), call]);
|
|
146
|
+
}
|
|
147
|
+
for (const calls of byFamily.values()) {
|
|
148
|
+
if (calls.length < 2)
|
|
149
|
+
continue;
|
|
150
|
+
const distinctPrompts = new Set(calls.map((call) => effectivePromptHash(call)).filter(Boolean));
|
|
151
|
+
if (distinctPrompts.size <= 1)
|
|
152
|
+
continue;
|
|
153
|
+
const ordered = [...calls].sort((a, b) => a.created_at.localeCompare(b.created_at));
|
|
154
|
+
const repeatedSharedTokens = Math.min(...ordered.map((call) => call.prompt_tokens)) * (ordered.length - 1);
|
|
155
|
+
if (repeatedSharedTokens <= 0)
|
|
156
|
+
continue;
|
|
157
|
+
offenders.push({
|
|
158
|
+
calls: ordered.length,
|
|
159
|
+
tokens: sum(ordered, (call) => call.total_tokens),
|
|
160
|
+
estimatedWasteTokens: repeatedSharedTokens,
|
|
161
|
+
example: toExample(group, ordered, repeatedSharedTokens),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const top = offenders.sort((a, b) => b.estimatedWasteTokens - a.estimatedWasteTokens)[0];
|
|
166
|
+
const recommendation = top
|
|
167
|
+
? `In ${top.example.sessionId}, the same leading context kept coming back with new turns. Move stable repo or project instructions into a short reusable file, then reference it instead of pasting the same setup on every turn.`
|
|
168
|
+
: "";
|
|
169
|
+
return buildFinding(offenders, "repeated-leading-context", "high", "lower-bound", "Repeated leading context across a session", "Multiple large prompts in the same session shared the same leading prompt family. The waste estimate is a lower bound based on the smallest repeated prompt sent again.", recommendation);
|
|
170
|
+
}
|
|
171
|
+
function analyzeCacheMiss(groups) {
|
|
172
|
+
const offenders = [];
|
|
173
|
+
for (const group of groups) {
|
|
174
|
+
const largeCalls = group.calls.filter((call) => call.prompt_tokens >= 6_000);
|
|
175
|
+
if (largeCalls.length < 2)
|
|
176
|
+
continue;
|
|
177
|
+
const repeated = largeCalls.filter((call) => effectivePromptFamilyHash(call));
|
|
178
|
+
if (repeated.length < 2)
|
|
179
|
+
continue;
|
|
180
|
+
const repeatedPromptTokens = sum(repeated, (call) => call.prompt_tokens);
|
|
181
|
+
const cachedTokens = sum(repeated, (call) => call.cached_tokens);
|
|
182
|
+
const cacheRatio = cachedTokens / Math.max(repeatedPromptTokens, 1);
|
|
183
|
+
if (cacheRatio >= 0.2)
|
|
184
|
+
continue;
|
|
185
|
+
const waste = Math.max(0, repeatedPromptTokens - cachedTokens);
|
|
186
|
+
offenders.push({
|
|
187
|
+
calls: repeated.length,
|
|
188
|
+
tokens: sum(repeated, (call) => call.total_tokens),
|
|
189
|
+
estimatedWasteTokens: waste,
|
|
190
|
+
example: toExample(group, repeated, waste),
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
const top = offenders.sort((a, b) => b.estimatedWasteTokens - a.estimatedWasteTokens)[0];
|
|
194
|
+
const recommendation = top
|
|
195
|
+
? `In ${top.example.sessionId}, keep the stable instructions first and unchanged. Put volatile details after them so provider caching can hit instead of rebuilding the whole prompt each time.`
|
|
196
|
+
: "";
|
|
197
|
+
return buildFinding(offenders, "cache-miss", "medium", "exact", "Large prompts got little cache reuse", "These sessions repeatedly sent large prompts while reporting very few cached tokens. The avoidable tokens are counted as repeated prompt tokens that did not come from cache.", recommendation);
|
|
198
|
+
}
|
|
199
|
+
function analyzeLowYield(groups) {
|
|
200
|
+
const offenders = [];
|
|
201
|
+
for (const group of groups) {
|
|
202
|
+
const calls = group.calls.filter((call) => call.prompt_tokens >= 5_000 && call.completion_tokens <= 250);
|
|
203
|
+
if (!calls.length)
|
|
204
|
+
continue;
|
|
205
|
+
const waste = sum(calls, (call) => Math.max(0, call.prompt_tokens - call.completion_tokens));
|
|
206
|
+
offenders.push({
|
|
207
|
+
calls: calls.length,
|
|
208
|
+
tokens: sum(calls, (call) => call.total_tokens),
|
|
209
|
+
estimatedWasteTokens: waste,
|
|
210
|
+
example: toExample(group, calls, waste),
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
const top = offenders.sort((a, b) => b.estimatedWasteTokens - a.estimatedWasteTokens)[0];
|
|
214
|
+
const recommendation = top
|
|
215
|
+
? `In ${top.example.sessionId}, tighten the ask to one deliverable. Give exact paths, expected output shape, and acceptance criteria so the model does not spend thousands of input tokens to return a tiny clarification.`
|
|
216
|
+
: "";
|
|
217
|
+
return buildFinding(offenders, "low-yield", "medium", "heuristic", "Large prompts produced very small answers", "These calls spent substantial input tokens but yielded minimal output. This usually indicates broad discovery, underspecified asks, or asking the model to inspect context it does not need.", recommendation);
|
|
218
|
+
}
|
|
219
|
+
function analyzeReasoning(groups) {
|
|
220
|
+
const offenders = [];
|
|
221
|
+
for (const group of groups) {
|
|
222
|
+
const calls = group.calls.filter((call) => call.reasoning_tokens >= 1_500);
|
|
223
|
+
if (!calls.length)
|
|
224
|
+
continue;
|
|
225
|
+
const waste = sum(calls, (call) => call.reasoning_tokens);
|
|
226
|
+
offenders.push({
|
|
227
|
+
calls: calls.length,
|
|
228
|
+
tokens: sum(calls, (call) => call.total_tokens),
|
|
229
|
+
estimatedWasteTokens: waste,
|
|
230
|
+
example: toExample(group, calls, waste),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
const top = offenders.sort((a, b) => b.estimatedWasteTokens - a.estimatedWasteTokens)[0];
|
|
234
|
+
const recommendation = top
|
|
235
|
+
? `In ${top.example.sessionId}, split the work into smaller verifiable steps and reserve the high-reasoning model for the one step that actually needs it.`
|
|
236
|
+
: "";
|
|
237
|
+
return buildFinding(offenders, "reasoning-overhead", "low", "exact", "High reasoning-token overhead", "The provider reported substantial hidden reasoning tokens for these calls. The estimated waste is the reported reasoning-token total itself.", recommendation);
|
|
238
|
+
}
|
|
239
|
+
export function analyzeUsage(store, hours = 168) {
|
|
240
|
+
const calls = store.getCalls(hours);
|
|
241
|
+
const groups = groupBySession(calls);
|
|
242
|
+
const findings = [
|
|
243
|
+
analyzeDuplicateRetries(groups),
|
|
244
|
+
analyzeRepeatedContext(groups),
|
|
245
|
+
analyzeCacheMiss(groups),
|
|
246
|
+
analyzeLowYield(groups),
|
|
247
|
+
analyzeReasoning(groups),
|
|
248
|
+
].filter((item) => item !== null);
|
|
249
|
+
const totalTokens = sum(calls, (call) => call.total_tokens);
|
|
250
|
+
const estimatedWasteTokens = Math.min(totalTokens, sum(findings, (item) => item.estimatedWasteTokens));
|
|
251
|
+
return {
|
|
252
|
+
periodHours: hours,
|
|
253
|
+
calls: calls.length,
|
|
254
|
+
totalTokens,
|
|
255
|
+
estimatedWasteTokens,
|
|
256
|
+
wastePercent: totalTokens ? (estimatedWasteTokens / totalTokens) * 100 : 0,
|
|
257
|
+
findings: findings.sort((a, b) => b.estimatedWasteTokens - a.estimatedWasteTokens),
|
|
258
|
+
topSessions: groups
|
|
259
|
+
.map((group) => ({
|
|
260
|
+
sessionId: sessionLabel(group),
|
|
261
|
+
toolName: group.toolName,
|
|
262
|
+
provider: group.provider,
|
|
263
|
+
model: group.model,
|
|
264
|
+
calls: group.calls.length,
|
|
265
|
+
totalTokens: sum(group.calls, (call) => call.total_tokens),
|
|
266
|
+
totalCost: sum(group.calls, (call) => call.cost),
|
|
267
|
+
}))
|
|
268
|
+
.sort((a, b) => b.totalTokens - a.totalTokens)
|
|
269
|
+
.slice(0, 5),
|
|
270
|
+
coverage: [
|
|
271
|
+
"Exact: duplicate retries are counted from identical prompt fingerprints in the same session.",
|
|
272
|
+
"Lower bound: repeated context is counted from repeated leading prompt families across large prompts.",
|
|
273
|
+
"Exact where available: cache and reasoning findings use provider-reported cached and reasoning token fields.",
|
|
274
|
+
"Imported logs and proxy traffic without full prompt bodies still rely on prompt fingerprints, not semantic intent.",
|
|
275
|
+
"Not measurable: tools that expose neither logs nor API token metadata.",
|
|
276
|
+
"Token counts are provider-reported; cost estimates still depend on the bundled pricing table.",
|
|
277
|
+
],
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":""}
|