context-lens 0.2.0 → 0.3.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 +120 -25
- package/dist/cli-utils.d.ts +2 -1
- package/dist/cli-utils.d.ts.map +1 -1
- package/dist/cli-utils.js +40 -13
- package/dist/cli-utils.js.map +1 -1
- package/dist/cli.js +184 -68
- package/dist/cli.js.map +1 -1
- package/dist/core/conversation.d.ts +63 -0
- package/dist/core/conversation.d.ts.map +1 -0
- package/dist/core/conversation.js +305 -0
- package/dist/core/conversation.js.map +1 -0
- package/dist/core/health.d.ts +7 -0
- package/dist/core/health.d.ts.map +1 -0
- package/dist/core/health.js +311 -0
- package/dist/core/health.js.map +1 -0
- package/dist/core/models.d.ts +36 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +111 -0
- package/dist/core/models.js.map +1 -0
- package/dist/core/parse.d.ts +17 -0
- package/dist/core/parse.d.ts.map +1 -0
- package/dist/core/parse.js +349 -0
- package/dist/core/parse.js.map +1 -0
- package/dist/core/routing.d.ts +47 -0
- package/dist/core/routing.d.ts.map +1 -0
- package/dist/core/routing.js +132 -0
- package/dist/core/routing.js.map +1 -0
- package/dist/core/security.d.ts +8 -0
- package/dist/core/security.d.ts.map +1 -0
- package/dist/core/security.js +222 -0
- package/dist/core/security.js.map +1 -0
- package/dist/core/source.d.ts +22 -0
- package/dist/core/source.d.ts.map +1 -0
- package/dist/core/source.js +56 -0
- package/dist/core/source.js.map +1 -0
- package/dist/core/tokens.d.ts +29 -0
- package/dist/core/tokens.d.ts.map +1 -0
- package/dist/core/tokens.js +163 -0
- package/dist/core/tokens.js.map +1 -0
- package/dist/core.d.ts +14 -22
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +14 -471
- package/dist/core.js.map +1 -1
- package/dist/http/headers.d.ts +25 -0
- package/dist/http/headers.d.ts.map +1 -0
- package/dist/http/headers.js +54 -0
- package/dist/http/headers.js.map +1 -0
- package/dist/lhar/composition.d.ts +12 -0
- package/dist/lhar/composition.d.ts.map +1 -0
- package/dist/lhar/composition.js +258 -0
- package/dist/lhar/composition.js.map +1 -0
- package/dist/lhar/export.d.ts +5 -0
- package/dist/lhar/export.d.ts.map +1 -0
- package/dist/lhar/export.js +59 -0
- package/dist/lhar/export.js.map +1 -0
- package/dist/lhar/record.d.ts +6 -0
- package/dist/lhar/record.d.ts.map +1 -0
- package/dist/lhar/record.js +216 -0
- package/dist/lhar/record.js.map +1 -0
- package/dist/lhar/response.d.ts +11 -0
- package/dist/lhar/response.d.ts.map +1 -0
- package/dist/lhar/response.js +132 -0
- package/dist/lhar/response.js.map +1 -0
- package/dist/lhar-types.generated.d.ts +24 -3
- package/dist/lhar-types.generated.d.ts.map +1 -1
- package/dist/lhar.d.ts +12 -19
- package/dist/lhar.d.ts.map +1 -1
- package/dist/lhar.js +16 -473
- package/dist/lhar.js.map +1 -1
- package/dist/server/api.d.ts +8 -0
- package/dist/server/api.d.ts.map +1 -0
- package/dist/server/api.js +292 -0
- package/dist/server/api.js.map +1 -0
- package/dist/server/config.d.ts +13 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +36 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/projection.d.ts +9 -0
- package/dist/server/projection.d.ts.map +1 -0
- package/dist/server/projection.js +47 -0
- package/dist/server/projection.js.map +1 -0
- package/dist/server/proxy.d.ts +13 -0
- package/dist/server/proxy.d.ts.map +1 -0
- package/dist/server/proxy.js +218 -0
- package/dist/server/proxy.js.map +1 -0
- package/dist/server/static.d.ts +9 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +78 -0
- package/dist/server/static.js.map +1 -0
- package/dist/server/store.d.ts +81 -0
- package/dist/server/store.d.ts.map +1 -0
- package/dist/server/store.js +632 -0
- package/dist/server/store.js.map +1 -0
- package/dist/server/webui.d.ts +5 -0
- package/dist/server/webui.d.ts.map +1 -0
- package/dist/server/webui.js +42 -0
- package/dist/server/webui.js.map +1 -0
- package/dist/server-utils.d.ts +2 -2
- package/dist/server-utils.d.ts.map +1 -1
- package/dist/server-utils.js +12 -21
- package/dist/server-utils.js.map +1 -1
- package/dist/server.js +31 -697
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +94 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/version.generated.d.ts +2 -0
- package/dist/version.generated.d.ts.map +1 -0
- package/dist/version.generated.js +2 -0
- package/dist/version.generated.js.map +1 -0
- package/findings-screenshot.png +0 -0
- package/messages-screenshot.png +0 -0
- package/package.json +23 -10
- package/schema/lhar.schema.json +58 -4
- package/screenshot-overview.png +0 -0
- package/sessions-screenshot.png +0 -0
- package/timeline-screenshot.png +0 -0
- package/diff.png +0 -0
- package/overview-sidebar.png +0 -0
- package/public/index.html +0 -2804
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { computeAgentKey, computeFingerprint, computeHealthScore, detectSource, estimateCost, estimateTokens, extractConversationLabel, extractSessionId, extractToolsUsed, extractWorkingDirectory, getContextLimit, rescaleContextTokens, scanSecurity, } from "../core.js";
|
|
4
|
+
import { analyzeComposition, buildLharRecord, buildSessionLine, normalizeComposition, parseResponseUsage, } from "../lhar.js";
|
|
5
|
+
import { safeFilenamePart } from "../server-utils.js";
|
|
6
|
+
import { projectEntry } from "./projection.js";
|
|
7
|
+
export class Store {
|
|
8
|
+
dataDir;
|
|
9
|
+
stateFile;
|
|
10
|
+
detailDir;
|
|
11
|
+
maxSessions;
|
|
12
|
+
maxCompactMessages;
|
|
13
|
+
privacy;
|
|
14
|
+
capturedRequests = [];
|
|
15
|
+
conversations = new Map(); // fingerprint -> conversation
|
|
16
|
+
responseIdToConvo = new Map(); // response_id -> conversationId
|
|
17
|
+
diskSessionsWritten = new Set();
|
|
18
|
+
dataRevision = 0;
|
|
19
|
+
nextEntryId = 1;
|
|
20
|
+
// SSE change listeners
|
|
21
|
+
changeListeners = new Set();
|
|
22
|
+
constructor(opts) {
|
|
23
|
+
this.dataDir = opts.dataDir;
|
|
24
|
+
this.stateFile = opts.stateFile;
|
|
25
|
+
this.detailDir = path.join(opts.dataDir, "details");
|
|
26
|
+
this.maxSessions = opts.maxSessions;
|
|
27
|
+
this.maxCompactMessages = opts.maxCompactMessages;
|
|
28
|
+
this.privacy = opts.privacy ?? "standard";
|
|
29
|
+
try {
|
|
30
|
+
fs.mkdirSync(this.dataDir, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
/* Directory may already exist */
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
fs.mkdirSync(this.detailDir, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
/* Directory may already exist */
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
getRevision() {
|
|
43
|
+
return this.dataRevision;
|
|
44
|
+
}
|
|
45
|
+
getPrivacy() {
|
|
46
|
+
return this.privacy;
|
|
47
|
+
}
|
|
48
|
+
// --- SSE event emitter ---
|
|
49
|
+
on(_event, listener) {
|
|
50
|
+
this.changeListeners.add(listener);
|
|
51
|
+
}
|
|
52
|
+
off(_event, listener) {
|
|
53
|
+
this.changeListeners.delete(listener);
|
|
54
|
+
}
|
|
55
|
+
emitChange(type, conversationId) {
|
|
56
|
+
const event = {
|
|
57
|
+
type,
|
|
58
|
+
revision: this.dataRevision,
|
|
59
|
+
conversationId,
|
|
60
|
+
};
|
|
61
|
+
for (const listener of this.changeListeners) {
|
|
62
|
+
try {
|
|
63
|
+
listener(event);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Don't let a broken SSE connection crash the store
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
getCapturedRequests() {
|
|
71
|
+
return this.capturedRequests;
|
|
72
|
+
}
|
|
73
|
+
getConversations() {
|
|
74
|
+
return this.conversations;
|
|
75
|
+
}
|
|
76
|
+
loadState() {
|
|
77
|
+
let content;
|
|
78
|
+
try {
|
|
79
|
+
content = fs.readFileSync(this.stateFile, "utf8");
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return; // No state file, fresh start
|
|
83
|
+
}
|
|
84
|
+
const lines = content.split("\n").filter((l) => l.length > 0);
|
|
85
|
+
let loadedEntries = 0;
|
|
86
|
+
let maxId = 0;
|
|
87
|
+
for (const line of lines) {
|
|
88
|
+
try {
|
|
89
|
+
const record = JSON.parse(line);
|
|
90
|
+
if (record.type === "conversation") {
|
|
91
|
+
const c = record.data;
|
|
92
|
+
this.conversations.set(c.id, c);
|
|
93
|
+
this.diskSessionsWritten.add(c.id);
|
|
94
|
+
}
|
|
95
|
+
else if (record.type === "entry") {
|
|
96
|
+
const projected = record.data;
|
|
97
|
+
const entry = {
|
|
98
|
+
...projected,
|
|
99
|
+
response: projected.response || { raw: true },
|
|
100
|
+
requestHeaders: {},
|
|
101
|
+
responseHeaders: {},
|
|
102
|
+
rawBody: undefined,
|
|
103
|
+
healthScore: projected.healthScore ?? null,
|
|
104
|
+
securityAlerts: projected.securityAlerts || [],
|
|
105
|
+
};
|
|
106
|
+
this.capturedRequests.push(entry);
|
|
107
|
+
if (entry.id > maxId)
|
|
108
|
+
maxId = entry.id;
|
|
109
|
+
loadedEntries++;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
console.error("State parse error:", err instanceof Error ? err.message : String(err));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (loadedEntries > 0) {
|
|
117
|
+
this.nextEntryId = maxId + 1;
|
|
118
|
+
this.dataRevision = 1;
|
|
119
|
+
// Loaded entries are already compact (projectEntry strips heavy data before saving).
|
|
120
|
+
// Do NOT call compactEntry here. It would destroy the preserved response usage data.
|
|
121
|
+
// TODO: Consider introducing a formal versioned migration system (schema version
|
|
122
|
+
// tracking, ordered migration list, "already applied" checks) if the number of
|
|
123
|
+
// ad hoc migrations here keeps growing. For now each migration is idempotent and
|
|
124
|
+
// detects whether it needs to run by inspecting the data.
|
|
125
|
+
//
|
|
126
|
+
// Order matters: image migration fixes inflated per-message tokens from base64 data
|
|
127
|
+
// BEFORE the usage backfill rescales everything proportionally.
|
|
128
|
+
const migrated = this.migrateImageTokenCounts();
|
|
129
|
+
this.backfillTotalTokensFromUsage();
|
|
130
|
+
this.backfillHealthScores();
|
|
131
|
+
if (migrated > 0) {
|
|
132
|
+
this.saveState();
|
|
133
|
+
}
|
|
134
|
+
console.log(`Restored ${loadedEntries} entries from ${this.conversations.size} conversations`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Store captured request
|
|
138
|
+
storeRequest(contextInfo, responseData, source, rawBody, meta, requestHeaders) {
|
|
139
|
+
const resolvedSource = detectSource(contextInfo, source, requestHeaders);
|
|
140
|
+
const fingerprint = computeFingerprint(contextInfo, rawBody ?? null, this.responseIdToConvo);
|
|
141
|
+
const rawSessionId = extractSessionId(rawBody ?? null);
|
|
142
|
+
// Register or look up conversation
|
|
143
|
+
let conversationId = null;
|
|
144
|
+
if (fingerprint) {
|
|
145
|
+
if (!this.conversations.has(fingerprint)) {
|
|
146
|
+
this.conversations.set(fingerprint, {
|
|
147
|
+
id: fingerprint,
|
|
148
|
+
label: extractConversationLabel(contextInfo),
|
|
149
|
+
source: resolvedSource || "unknown",
|
|
150
|
+
workingDirectory: extractWorkingDirectory(contextInfo, rawBody ?? null),
|
|
151
|
+
firstSeen: new Date().toISOString(),
|
|
152
|
+
sessionId: rawSessionId,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
const convo = this.conversations.get(fingerprint);
|
|
157
|
+
// Backfill source if first request couldn't detect it
|
|
158
|
+
if (convo.source === "unknown" &&
|
|
159
|
+
resolvedSource &&
|
|
160
|
+
resolvedSource !== "unknown") {
|
|
161
|
+
convo.source = resolvedSource;
|
|
162
|
+
}
|
|
163
|
+
// Backfill working directory if first request didn't have it
|
|
164
|
+
if (!convo.workingDirectory) {
|
|
165
|
+
const wd = extractWorkingDirectory(contextInfo, rawBody ?? null);
|
|
166
|
+
if (wd)
|
|
167
|
+
convo.workingDirectory = wd;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
conversationId = fingerprint;
|
|
171
|
+
}
|
|
172
|
+
// Agent key: distinguishes agents within a session (main vs subagents)
|
|
173
|
+
const agentKey = computeAgentKey(contextInfo);
|
|
174
|
+
const agentLabel = extractConversationLabel(contextInfo);
|
|
175
|
+
// Compute composition and cost
|
|
176
|
+
const composition = analyzeComposition(contextInfo, rawBody);
|
|
177
|
+
const usage = parseResponseUsage(responseData);
|
|
178
|
+
// Validate estimation accuracy before overriding with actuals
|
|
179
|
+
const actualInputTokens = usage.inputTokens + usage.cacheReadTokens + usage.cacheWriteTokens;
|
|
180
|
+
if (actualInputTokens > 0) {
|
|
181
|
+
const estimated = contextInfo.totalTokens;
|
|
182
|
+
const actual = actualInputTokens;
|
|
183
|
+
const diff = Math.abs(actual - estimated);
|
|
184
|
+
const pct = estimated > 0 ? (diff / estimated) * 100 : 0;
|
|
185
|
+
// Log significant estimation errors (>20% off or >10K tokens off)
|
|
186
|
+
if (pct > 20 || diff > 10_000) {
|
|
187
|
+
console.warn(`Token estimation off by ${pct.toFixed(1)}% (estimated: ${estimated.toLocaleString()}, actual: ${actual.toLocaleString()}) for ${contextInfo.model}`);
|
|
188
|
+
}
|
|
189
|
+
// Rescale all sub-totals and per-message tokens to match the
|
|
190
|
+
// authoritative API usage. This preserves relative proportions while
|
|
191
|
+
// ensuring totalTokens === systemTokens + toolsTokens + messagesTokens.
|
|
192
|
+
rescaleContextTokens(contextInfo, actualInputTokens);
|
|
193
|
+
}
|
|
194
|
+
// Normalize composition so sum(composition[].tokens) === totalTokens.
|
|
195
|
+
// This must happen after the totalTokens override so both systems agree.
|
|
196
|
+
normalizeComposition(composition, contextInfo.totalTokens);
|
|
197
|
+
// Calculate cost with proper cache token pricing
|
|
198
|
+
const inputTok = usage.inputTokens || contextInfo.totalTokens;
|
|
199
|
+
const outputTok = usage.outputTokens;
|
|
200
|
+
const costUsd = estimateCost(contextInfo.model, inputTok, outputTok, usage.cacheReadTokens, usage.cacheWriteTokens);
|
|
201
|
+
const entry = {
|
|
202
|
+
id: this.nextEntryId++,
|
|
203
|
+
timestamp: new Date().toISOString(),
|
|
204
|
+
contextInfo,
|
|
205
|
+
response: responseData,
|
|
206
|
+
contextLimit: getContextLimit(contextInfo.model),
|
|
207
|
+
source: resolvedSource || "unknown",
|
|
208
|
+
conversationId,
|
|
209
|
+
agentKey,
|
|
210
|
+
agentLabel,
|
|
211
|
+
httpStatus: meta?.httpStatus ?? null,
|
|
212
|
+
timings: meta?.timings ?? null,
|
|
213
|
+
requestBytes: meta?.requestBytes ?? 0,
|
|
214
|
+
responseBytes: meta?.responseBytes ?? 0,
|
|
215
|
+
targetUrl: meta?.targetUrl ?? null,
|
|
216
|
+
requestHeaders: meta?.requestHeaders ?? {},
|
|
217
|
+
responseHeaders: meta?.responseHeaders ?? {},
|
|
218
|
+
rawBody,
|
|
219
|
+
composition,
|
|
220
|
+
costUsd,
|
|
221
|
+
healthScore: null,
|
|
222
|
+
securityAlerts: [],
|
|
223
|
+
};
|
|
224
|
+
// Compute health score
|
|
225
|
+
const sameConvo = conversationId
|
|
226
|
+
? this.capturedRequests.filter((e) => e.conversationId === conversationId)
|
|
227
|
+
: [];
|
|
228
|
+
const prevMain = sameConvo
|
|
229
|
+
.filter((e) => !e.agentKey)
|
|
230
|
+
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())[0];
|
|
231
|
+
// Collect all tools used across the conversation (including current entry)
|
|
232
|
+
const sessionToolsUsed = new Set();
|
|
233
|
+
for (const e of sameConvo) {
|
|
234
|
+
for (const tool of extractToolsUsed(e.contextInfo.messages)) {
|
|
235
|
+
sessionToolsUsed.add(tool);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Also scan current entry (not yet in capturedRequests)
|
|
239
|
+
for (const tool of extractToolsUsed(contextInfo.messages)) {
|
|
240
|
+
sessionToolsUsed.add(tool);
|
|
241
|
+
}
|
|
242
|
+
const turnCount = sameConvo.filter((e) => !e.agentKey).length + 1;
|
|
243
|
+
entry.healthScore = computeHealthScore(entry, prevMain ? prevMain.contextInfo.totalTokens : null, sessionToolsUsed, turnCount);
|
|
244
|
+
// Security scanning must happen before compaction strips message content
|
|
245
|
+
const securityResult = scanSecurity(contextInfo);
|
|
246
|
+
entry.securityAlerts = securityResult.alerts;
|
|
247
|
+
// Track response IDs for Responses API chaining
|
|
248
|
+
const respId = responseData.id ||
|
|
249
|
+
responseData.response_id;
|
|
250
|
+
if (respId && conversationId) {
|
|
251
|
+
this.responseIdToConvo.set(respId, conversationId);
|
|
252
|
+
}
|
|
253
|
+
this.capturedRequests.unshift(entry);
|
|
254
|
+
// Evict oldest sessions when we exceed the session limit
|
|
255
|
+
if (this.conversations.size > this.maxSessions) {
|
|
256
|
+
// Find the oldest session by its most recent entry timestamp
|
|
257
|
+
const sessionLatest = new Map();
|
|
258
|
+
for (const r of this.capturedRequests) {
|
|
259
|
+
if (r.conversationId) {
|
|
260
|
+
const t = new Date(r.timestamp).getTime();
|
|
261
|
+
const cur = sessionLatest.get(r.conversationId) || 0;
|
|
262
|
+
if (t > cur)
|
|
263
|
+
sessionLatest.set(r.conversationId, t);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Sort sessions oldest-first, evict until we're at the limit
|
|
267
|
+
const sorted = [...sessionLatest.entries()].sort((a, b) => a[1] - b[1]);
|
|
268
|
+
const toEvict = sorted
|
|
269
|
+
.slice(0, sorted.length - this.maxSessions)
|
|
270
|
+
.map((s) => s[0]);
|
|
271
|
+
const evictSet = new Set(toEvict);
|
|
272
|
+
// Remove all entries belonging to evicted sessions
|
|
273
|
+
for (let i = this.capturedRequests.length - 1; i >= 0; i--) {
|
|
274
|
+
const evictEntry = this.capturedRequests[i];
|
|
275
|
+
if (evictEntry.conversationId &&
|
|
276
|
+
evictSet.has(evictEntry.conversationId)) {
|
|
277
|
+
// Remove detail file
|
|
278
|
+
const detailPath = path.join(this.detailDir, `${evictEntry.id}.json`);
|
|
279
|
+
try {
|
|
280
|
+
fs.unlinkSync(detailPath);
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
/* may not exist */
|
|
284
|
+
}
|
|
285
|
+
this.capturedRequests.splice(i, 1);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
for (const cid of toEvict) {
|
|
289
|
+
this.conversations.delete(cid);
|
|
290
|
+
this.diskSessionsWritten.delete(cid);
|
|
291
|
+
for (const [rid, rcid] of this.responseIdToConvo) {
|
|
292
|
+
if (rcid === cid)
|
|
293
|
+
this.responseIdToConvo.delete(rid);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
this.dataRevision++;
|
|
298
|
+
this.emitChange("entry-added", conversationId);
|
|
299
|
+
this.logToDisk(entry);
|
|
300
|
+
this.saveEntryDetail(entry);
|
|
301
|
+
this.compactEntry(entry);
|
|
302
|
+
this.saveState();
|
|
303
|
+
return entry;
|
|
304
|
+
}
|
|
305
|
+
deleteConversation(convoId) {
|
|
306
|
+
this.removeConversationDetails(convoId);
|
|
307
|
+
this.conversations.delete(convoId);
|
|
308
|
+
for (let i = this.capturedRequests.length - 1; i >= 0; i--) {
|
|
309
|
+
if (this.capturedRequests[i].conversationId === convoId)
|
|
310
|
+
this.capturedRequests.splice(i, 1);
|
|
311
|
+
}
|
|
312
|
+
this.diskSessionsWritten.delete(convoId);
|
|
313
|
+
for (const [rid, cid] of this.responseIdToConvo) {
|
|
314
|
+
if (cid === convoId)
|
|
315
|
+
this.responseIdToConvo.delete(rid);
|
|
316
|
+
}
|
|
317
|
+
this.dataRevision++;
|
|
318
|
+
this.emitChange("conversation-deleted", convoId);
|
|
319
|
+
this.saveState();
|
|
320
|
+
}
|
|
321
|
+
resetAll() {
|
|
322
|
+
// Remove all detail files
|
|
323
|
+
try {
|
|
324
|
+
const files = fs.readdirSync(this.detailDir);
|
|
325
|
+
for (const f of files) {
|
|
326
|
+
try {
|
|
327
|
+
fs.unlinkSync(path.join(this.detailDir, f));
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
/* ignore */
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
/* directory may not exist */
|
|
336
|
+
}
|
|
337
|
+
this.capturedRequests.length = 0;
|
|
338
|
+
this.conversations.clear();
|
|
339
|
+
this.diskSessionsWritten.clear();
|
|
340
|
+
this.responseIdToConvo.clear();
|
|
341
|
+
this.nextEntryId = 1;
|
|
342
|
+
this.dataRevision++;
|
|
343
|
+
this.emitChange("reset");
|
|
344
|
+
this.saveState();
|
|
345
|
+
}
|
|
346
|
+
// ----- Internals -----
|
|
347
|
+
/** Backfill health scores for entries loaded from state that don't have one. */
|
|
348
|
+
backfillHealthScores() {
|
|
349
|
+
// Process oldest-first so previousTokens lookups work correctly.
|
|
350
|
+
const sorted = [...this.capturedRequests].sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
351
|
+
for (const entry of sorted) {
|
|
352
|
+
if (entry.healthScore)
|
|
353
|
+
continue;
|
|
354
|
+
const sameConvo = entry.conversationId
|
|
355
|
+
? sorted.filter((e) => e.conversationId === entry.conversationId &&
|
|
356
|
+
new Date(e.timestamp).getTime() <
|
|
357
|
+
new Date(entry.timestamp).getTime())
|
|
358
|
+
: [];
|
|
359
|
+
const prevMain = sameConvo
|
|
360
|
+
.filter((e) => !e.agentKey)
|
|
361
|
+
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())[0];
|
|
362
|
+
// Collect all tools used across the conversation (up to this entry)
|
|
363
|
+
const sessionToolsUsed = new Set();
|
|
364
|
+
for (const e of [...sameConvo, entry]) {
|
|
365
|
+
for (const tool of extractToolsUsed(e.contextInfo.messages)) {
|
|
366
|
+
sessionToolsUsed.add(tool);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const turnCount = sameConvo.filter((e) => !e.agentKey).length + (entry.agentKey ? 0 : 1);
|
|
370
|
+
entry.healthScore = computeHealthScore(entry, prevMain ? prevMain.contextInfo.totalTokens : null, sessionToolsUsed, turnCount);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Recalculate token counts for messages that contain image blocks.
|
|
375
|
+
*
|
|
376
|
+
* Before the image token fix, estimateTokens() would stringify base64 image
|
|
377
|
+
* data, producing millions of phantom tokens. Persisted entries still have
|
|
378
|
+
* those inflated counts. This migration recalculates from the compacted
|
|
379
|
+
/**
|
|
380
|
+
* Backfill totalTokens from API usage data for entries that only have estimates.
|
|
381
|
+
* The estimate (chars/4) can be wildly inaccurate; the API's real token count
|
|
382
|
+
* (input + cacheRead + cacheWrite) is authoritative.
|
|
383
|
+
*/
|
|
384
|
+
backfillTotalTokensFromUsage() {
|
|
385
|
+
let fixed = 0;
|
|
386
|
+
for (const entry of this.capturedRequests) {
|
|
387
|
+
const usage = parseResponseUsage(entry.response);
|
|
388
|
+
const actual = usage.inputTokens + usage.cacheReadTokens + usage.cacheWriteTokens;
|
|
389
|
+
if (actual > 0 && actual !== entry.contextInfo.totalTokens) {
|
|
390
|
+
rescaleContextTokens(entry.contextInfo, actual);
|
|
391
|
+
fixed++;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (fixed > 0) {
|
|
395
|
+
console.log(`Fixed totalTokens from API usage for ${fixed} entries`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Migrate image token counts: re-estimate token counts for messages containing
|
|
400
|
+
* contentBlocks (which have no base64 data) using the fixed estimateTokens().
|
|
401
|
+
*/
|
|
402
|
+
migrateImageTokenCounts() {
|
|
403
|
+
let migrated = 0;
|
|
404
|
+
const updateTotals = (ci, messagesTokens) => {
|
|
405
|
+
ci.messagesTokens = messagesTokens;
|
|
406
|
+
ci.totalTokens = ci.systemTokens + ci.toolsTokens + ci.messagesTokens;
|
|
407
|
+
};
|
|
408
|
+
for (const entry of this.capturedRequests) {
|
|
409
|
+
const ci = entry.contextInfo;
|
|
410
|
+
let messagesTokens = 0;
|
|
411
|
+
let changed = false;
|
|
412
|
+
for (const msg of ci.messages) {
|
|
413
|
+
if (!msg.contentBlocks || msg.contentBlocks.length === 0) {
|
|
414
|
+
messagesTokens += msg.tokens;
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
// Check if any block (or nested content in tool_result) is an image
|
|
418
|
+
const hasImage = msg.contentBlocks.some((b) => {
|
|
419
|
+
if (b.type === "image")
|
|
420
|
+
return true;
|
|
421
|
+
if (b.type === "tool_result" && Array.isArray(b.content)) {
|
|
422
|
+
return b.content.some((inner) => inner?.type === "image");
|
|
423
|
+
}
|
|
424
|
+
return false;
|
|
425
|
+
});
|
|
426
|
+
if (!hasImage) {
|
|
427
|
+
messagesTokens += msg.tokens;
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
// Recalculate from compacted contentBlocks (no base64 data)
|
|
431
|
+
const newTokens = estimateTokens(msg.contentBlocks);
|
|
432
|
+
if (newTokens < msg.tokens) {
|
|
433
|
+
msg.tokens = newTokens;
|
|
434
|
+
changed = true;
|
|
435
|
+
}
|
|
436
|
+
messagesTokens += msg.tokens;
|
|
437
|
+
}
|
|
438
|
+
if (changed) {
|
|
439
|
+
updateTotals(ci, messagesTokens);
|
|
440
|
+
migrated++;
|
|
441
|
+
}
|
|
442
|
+
else if (ci.messagesTokens !== messagesTokens) {
|
|
443
|
+
// Messages with images may have been truncated during compaction,
|
|
444
|
+
// leaving messagesTokens inflated even though no image blocks remain.
|
|
445
|
+
// Fix by recalculating from the actual per-message token counts.
|
|
446
|
+
updateTotals(ci, messagesTokens);
|
|
447
|
+
migrated++;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
if (migrated > 0) {
|
|
451
|
+
console.log(`Migrated ${migrated} entries with inflated image token counts`);
|
|
452
|
+
}
|
|
453
|
+
return migrated;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Save full contextInfo for an entry to disk so the UI can retrieve
|
|
457
|
+
* uncompacted message content on demand.
|
|
458
|
+
*/
|
|
459
|
+
saveEntryDetail(entry) {
|
|
460
|
+
const detailPath = path.join(this.detailDir, `${entry.id}.json`);
|
|
461
|
+
try {
|
|
462
|
+
fs.writeFileSync(detailPath, JSON.stringify({
|
|
463
|
+
contextInfo: entry.contextInfo,
|
|
464
|
+
}));
|
|
465
|
+
}
|
|
466
|
+
catch (err) {
|
|
467
|
+
console.error("Detail save error:", err instanceof Error ? err.message : String(err));
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Load full contextInfo for an entry from disk.
|
|
472
|
+
* Returns null if the detail file doesn't exist (old entries before this feature).
|
|
473
|
+
*/
|
|
474
|
+
getEntryDetail(entryId) {
|
|
475
|
+
const detailPath = path.join(this.detailDir, `${entryId}.json`);
|
|
476
|
+
try {
|
|
477
|
+
const data = JSON.parse(fs.readFileSync(detailPath, "utf-8"));
|
|
478
|
+
return data.contextInfo ?? null;
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Remove detail files for entries belonging to a conversation.
|
|
486
|
+
*/
|
|
487
|
+
removeConversationDetails(convoId) {
|
|
488
|
+
for (const entry of this.capturedRequests) {
|
|
489
|
+
if (entry.conversationId === convoId) {
|
|
490
|
+
const detailPath = path.join(this.detailDir, `${entry.id}.json`);
|
|
491
|
+
try {
|
|
492
|
+
fs.unlinkSync(detailPath);
|
|
493
|
+
}
|
|
494
|
+
catch {
|
|
495
|
+
/* file may not exist */
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
logToDisk(entry) {
|
|
501
|
+
const safeSource = safeFilenamePart(entry.source || "unknown");
|
|
502
|
+
const safeConvo = entry.conversationId
|
|
503
|
+
? safeFilenamePart(entry.conversationId)
|
|
504
|
+
: null;
|
|
505
|
+
const filename = safeConvo
|
|
506
|
+
? `${safeSource}-${safeConvo}.lhar`
|
|
507
|
+
: "ungrouped.lhar";
|
|
508
|
+
const filePath = path.join(this.dataDir, filename);
|
|
509
|
+
let output = "";
|
|
510
|
+
// Write session preamble on first entry for this conversation
|
|
511
|
+
if (entry.conversationId &&
|
|
512
|
+
!this.diskSessionsWritten.has(entry.conversationId)) {
|
|
513
|
+
this.diskSessionsWritten.add(entry.conversationId);
|
|
514
|
+
const convo = this.conversations.get(entry.conversationId);
|
|
515
|
+
if (convo) {
|
|
516
|
+
const sessionLine = buildSessionLine(entry.conversationId, convo, entry.contextInfo.model);
|
|
517
|
+
output += `${JSON.stringify(sessionLine)}\n`;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
const record = buildLharRecord(entry, this.capturedRequests, this.privacy);
|
|
521
|
+
output += `${JSON.stringify(record)}\n`;
|
|
522
|
+
try {
|
|
523
|
+
fs.appendFileSync(filePath, output);
|
|
524
|
+
}
|
|
525
|
+
catch (err) {
|
|
526
|
+
console.error("Log write error:", err instanceof Error ? err.message : String(err));
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
// Compact a content block: keep tool metadata, truncate text.
|
|
530
|
+
// Full content is available via the detail API (per-entry files on disk).
|
|
531
|
+
compactBlock(b) {
|
|
532
|
+
const limit = 200;
|
|
533
|
+
switch (b.type) {
|
|
534
|
+
case "tool_use":
|
|
535
|
+
return { type: "tool_use", id: b.id, name: b.name, input: {} };
|
|
536
|
+
case "tool_result": {
|
|
537
|
+
const rc = typeof b.content === "string"
|
|
538
|
+
? b.content.slice(0, limit)
|
|
539
|
+
: Array.isArray(b.content)
|
|
540
|
+
? b.content.map((bb) => this.compactBlock(bb))
|
|
541
|
+
: "";
|
|
542
|
+
return { type: "tool_result", tool_use_id: b.tool_use_id, content: rc };
|
|
543
|
+
}
|
|
544
|
+
case "text":
|
|
545
|
+
return { type: "text", text: (b.text || "").slice(0, limit) };
|
|
546
|
+
case "input_text":
|
|
547
|
+
return { type: "input_text", text: (b.text || "").slice(0, limit) };
|
|
548
|
+
case "image":
|
|
549
|
+
return { type: "image" };
|
|
550
|
+
default: {
|
|
551
|
+
// Handle thinking blocks and other unknown types; truncate text-like fields
|
|
552
|
+
const any = b;
|
|
553
|
+
if (any.thinking)
|
|
554
|
+
return {
|
|
555
|
+
...any,
|
|
556
|
+
thinking: any.thinking.slice(0, limit),
|
|
557
|
+
};
|
|
558
|
+
if (any.text)
|
|
559
|
+
return { ...any, text: any.text.slice(0, limit) };
|
|
560
|
+
return b;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
compactMessages(messages) {
|
|
565
|
+
const limit = 200;
|
|
566
|
+
const msgs = messages.length > this.maxCompactMessages
|
|
567
|
+
? messages.slice(-this.maxCompactMessages)
|
|
568
|
+
: messages;
|
|
569
|
+
return msgs.map((m) => ({
|
|
570
|
+
role: m.role,
|
|
571
|
+
content: typeof m.content === "string" ? m.content.slice(0, limit) : "",
|
|
572
|
+
tokens: m.tokens,
|
|
573
|
+
contentBlocks: m.contentBlocks?.map((b) => this.compactBlock(b)) ?? null,
|
|
574
|
+
}));
|
|
575
|
+
}
|
|
576
|
+
// Compact contextInfo: keep metadata and token counts, drop large text payloads
|
|
577
|
+
compactContextInfo(ci) {
|
|
578
|
+
return {
|
|
579
|
+
provider: ci.provider,
|
|
580
|
+
apiFormat: ci.apiFormat,
|
|
581
|
+
model: ci.model,
|
|
582
|
+
systemTokens: ci.systemTokens,
|
|
583
|
+
toolsTokens: ci.toolsTokens,
|
|
584
|
+
messagesTokens: ci.messagesTokens,
|
|
585
|
+
totalTokens: ci.totalTokens,
|
|
586
|
+
systemPrompts: [],
|
|
587
|
+
tools: [],
|
|
588
|
+
messages: this.compactMessages(ci.messages),
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
// Release heavy data from an entry after it's been logged to disk
|
|
592
|
+
compactEntry(entry) {
|
|
593
|
+
// Extract and preserve usage data from response before dropping it
|
|
594
|
+
const usage = parseResponseUsage(entry.response);
|
|
595
|
+
entry.response = {
|
|
596
|
+
usage: {
|
|
597
|
+
input_tokens: usage.inputTokens,
|
|
598
|
+
output_tokens: usage.outputTokens,
|
|
599
|
+
cache_read_input_tokens: usage.cacheReadTokens,
|
|
600
|
+
cache_creation_input_tokens: usage.cacheWriteTokens,
|
|
601
|
+
},
|
|
602
|
+
model: usage.model,
|
|
603
|
+
stop_reason: usage.finishReasons[0] || null,
|
|
604
|
+
};
|
|
605
|
+
entry.rawBody = undefined;
|
|
606
|
+
entry.requestHeaders = {};
|
|
607
|
+
entry.responseHeaders = {};
|
|
608
|
+
// Compact contextInfo in-place
|
|
609
|
+
entry.contextInfo.systemPrompts = [];
|
|
610
|
+
entry.contextInfo.tools = [];
|
|
611
|
+
entry.contextInfo.messages = this.compactMessages(entry.contextInfo.messages);
|
|
612
|
+
}
|
|
613
|
+
saveState() {
|
|
614
|
+
let lines = "";
|
|
615
|
+
for (const [, convo] of this.conversations) {
|
|
616
|
+
lines += `${JSON.stringify({ type: "conversation", data: convo })}\n`;
|
|
617
|
+
}
|
|
618
|
+
for (const entry of this.capturedRequests) {
|
|
619
|
+
lines += `${JSON.stringify({
|
|
620
|
+
type: "entry",
|
|
621
|
+
data: projectEntry(entry, this.compactContextInfo(entry.contextInfo)),
|
|
622
|
+
})}\n`;
|
|
623
|
+
}
|
|
624
|
+
try {
|
|
625
|
+
fs.writeFileSync(this.stateFile, lines);
|
|
626
|
+
}
|
|
627
|
+
catch (err) {
|
|
628
|
+
console.error("State save error:", err instanceof Error ? err.message : String(err));
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/server/store.ts"],"names":[],"mappings":"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"}
|