agent-recorder 2.0.12 → 2.0.14
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/dist/bundle.js +4 -0
- package/dist/bundle.js.map +1 -1
- package/dist/embed.d.ts +21 -0
- package/dist/embed.d.ts.map +1 -0
- package/dist/embed.js +22 -0
- package/dist/embed.js.map +1 -0
- package/package.json +8 -1
- package/vendor/node_modules/@agent-recorder/cli/analytics/session-analytics.test.js +3 -0
- package/vendor/node_modules/@agent-recorder/cli/analytics/session-analytics.test.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/cli/commands/mcp-server.d.ts +11 -0
- package/vendor/node_modules/@agent-recorder/cli/commands/mcp-server.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/cli/commands/mcp-server.js +442 -0
- package/vendor/node_modules/@agent-recorder/cli/commands/mcp-server.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/cli/commands/sessions.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/cli/commands/sessions.js +8 -5
- package/vendor/node_modules/@agent-recorder/cli/commands/sessions.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/cli/config/claude-paths.d.ts +2 -51
- package/vendor/node_modules/@agent-recorder/cli/config/claude-paths.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/cli/config/claude-paths.js +2 -113
- package/vendor/node_modules/@agent-recorder/cli/config/claude-paths.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/cli/config/claude-paths.test.js +1 -1
- package/vendor/node_modules/@agent-recorder/cli/config/claude-paths.test.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/cli/index.js +10 -0
- package/vendor/node_modules/@agent-recorder/cli/index.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/cli/package.json +1 -1
- package/vendor/node_modules/@agent-recorder/cli/tui/components/EventInspectPanel.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/cli/tui/components/EventInspectPanel.js +1 -1
- package/vendor/node_modules/@agent-recorder/cli/tui/components/EventInspectPanel.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/claude-config.d.ts +23 -0
- package/vendor/node_modules/@agent-recorder/core/claude-config.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/claude-config.js +50 -0
- package/vendor/node_modules/@agent-recorder/core/claude-config.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/config.d.ts +10 -1
- package/vendor/node_modules/@agent-recorder/core/config.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/config.js +11 -1
- package/vendor/node_modules/@agent-recorder/core/config.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/db/events-complete.test.d.ts +5 -0
- package/vendor/node_modules/@agent-recorder/core/db/events-complete.test.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/core/db/events-complete.test.js +133 -0
- package/vendor/node_modules/@agent-recorder/core/db/events-complete.test.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/core/db/events.d.ts +23 -36
- package/vendor/node_modules/@agent-recorder/core/db/events.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/db/events.js +74 -3
- package/vendor/node_modules/@agent-recorder/core/db/events.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/db/events.test.js +62 -1
- package/vendor/node_modules/@agent-recorder/core/db/events.test.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/db/index.d.ts +2 -1
- package/vendor/node_modules/@agent-recorder/core/db/index.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/db/index.js +2 -1
- package/vendor/node_modules/@agent-recorder/core/db/index.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/db/sessions.d.ts +2 -5
- package/vendor/node_modules/@agent-recorder/core/db/sessions.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/db/sessions.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/db/token-metrics.d.ts +33 -0
- package/vendor/node_modules/@agent-recorder/core/db/token-metrics.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/core/db/token-metrics.js +88 -0
- package/vendor/node_modules/@agent-recorder/core/db/token-metrics.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/core/db/token-metrics.test.d.ts +5 -0
- package/vendor/node_modules/@agent-recorder/core/db/token-metrics.test.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/core/db/token-metrics.test.js +167 -0
- package/vendor/node_modules/@agent-recorder/core/db/token-metrics.test.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/core/index.d.ts +1 -1
- package/vendor/node_modules/@agent-recorder/core/index.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/index.js +1 -1
- package/vendor/node_modules/@agent-recorder/core/index.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/migrations/007_add_correlation_id.sql +11 -0
- package/vendor/node_modules/@agent-recorder/core/migrations/007_add_token_columns.sql +19 -0
- package/vendor/node_modules/@agent-recorder/core/package.json +1 -1
- package/vendor/node_modules/@agent-recorder/core/types/index.d.ts +4 -2
- package/vendor/node_modules/@agent-recorder/core/types/index.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/types/index.js +3 -0
- package/vendor/node_modules/@agent-recorder/core/types/index.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/utils/index.d.ts +1 -0
- package/vendor/node_modules/@agent-recorder/core/utils/index.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/utils/index.js +1 -0
- package/vendor/node_modules/@agent-recorder/core/utils/index.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/utils/redact.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/utils/redact.js +6 -3
- package/vendor/node_modules/@agent-recorder/core/utils/redact.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/core/utils/redact.test.d.ts +6 -0
- package/vendor/node_modules/@agent-recorder/core/utils/redact.test.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/core/utils/redact.test.js +82 -0
- package/vendor/node_modules/@agent-recorder/core/utils/redact.test.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/core/utils/tokens.d.ts +24 -0
- package/vendor/node_modules/@agent-recorder/core/utils/tokens.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/core/utils/tokens.js +31 -0
- package/vendor/node_modules/@agent-recorder/core/utils/tokens.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/core/utils/tokens.test.d.ts +5 -0
- package/vendor/node_modules/@agent-recorder/core/utils/tokens.test.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/core/utils/tokens.test.js +80 -0
- package/vendor/node_modules/@agent-recorder/core/utils/tokens.test.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/hooks/package.json +1 -1
- package/vendor/node_modules/@agent-recorder/service/daemon-context.d.ts +14 -0
- package/vendor/node_modules/@agent-recorder/service/daemon-context.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/daemon-context.js +15 -0
- package/vendor/node_modules/@agent-recorder/service/daemon-context.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/index.d.ts +1 -8
- package/vendor/node_modules/@agent-recorder/service/index.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/index.js +15 -22
- package/vendor/node_modules/@agent-recorder/service/index.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/mcp/proxy.d.ts +27 -0
- package/vendor/node_modules/@agent-recorder/service/mcp/proxy.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/mcp/proxy.js +141 -35
- package/vendor/node_modules/@agent-recorder/service/mcp/proxy.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/mcp/recorder.d.ts +4 -0
- package/vendor/node_modules/@agent-recorder/service/mcp/recorder.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/mcp/recorder.js +56 -14
- package/vendor/node_modules/@agent-recorder/service/mcp/recorder.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/mcp/recorder.test.d.ts +5 -0
- package/vendor/node_modules/@agent-recorder/service/mcp/recorder.test.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/mcp/recorder.test.js +143 -0
- package/vendor/node_modules/@agent-recorder/service/mcp/recorder.test.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/mcp/types.d.ts +5 -31
- package/vendor/node_modules/@agent-recorder/service/mcp/types.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/mcp/types.js +3 -1
- package/vendor/node_modules/@agent-recorder/service/mcp/types.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/mcp/upstreams-cache.test.d.ts +5 -0
- package/vendor/node_modules/@agent-recorder/service/mcp/upstreams-cache.test.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/mcp/upstreams-cache.test.js +66 -0
- package/vendor/node_modules/@agent-recorder/service/mcp/upstreams-cache.test.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/package.json +1 -1
- package/vendor/node_modules/@agent-recorder/service/routes/events.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/routes/events.js +42 -1
- package/vendor/node_modules/@agent-recorder/service/routes/events.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/routes/health.d.ts +6 -1
- package/vendor/node_modules/@agent-recorder/service/routes/health.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/routes/health.js +5 -6
- package/vendor/node_modules/@agent-recorder/service/routes/health.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/routes/hooks.d.ts +20 -0
- package/vendor/node_modules/@agent-recorder/service/routes/hooks.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/routes/hooks.js +403 -49
- package/vendor/node_modules/@agent-recorder/service/routes/hooks.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/routes/hooks.test.d.ts +9 -0
- package/vendor/node_modules/@agent-recorder/service/routes/hooks.test.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/routes/hooks.test.js +406 -0
- package/vendor/node_modules/@agent-recorder/service/routes/hooks.test.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/routes/isToolResponseError.test.d.ts +8 -0
- package/vendor/node_modules/@agent-recorder/service/routes/isToolResponseError.test.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/routes/isToolResponseError.test.js +65 -0
- package/vendor/node_modules/@agent-recorder/service/routes/isToolResponseError.test.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/routes/sessions.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/routes/sessions.js +19 -1
- package/vendor/node_modules/@agent-recorder/service/routes/sessions.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/routes/stdio.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/routes/stdio.js +20 -1
- package/vendor/node_modules/@agent-recorder/service/routes/stdio.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/routes/tokens.d.ts +12 -0
- package/vendor/node_modules/@agent-recorder/service/routes/tokens.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/routes/tokens.js +18 -0
- package/vendor/node_modules/@agent-recorder/service/routes/tokens.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/routes/tokens.test.d.ts +5 -0
- package/vendor/node_modules/@agent-recorder/service/routes/tokens.test.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/routes/tokens.test.js +88 -0
- package/vendor/node_modules/@agent-recorder/service/routes/tokens.test.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/service/server.d.ts +4 -0
- package/vendor/node_modules/@agent-recorder/service/server.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/service/server.js +33 -3
- package/vendor/node_modules/@agent-recorder/service/server.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/stdio-proxy/package.json +1 -1
- package/vendor/node_modules/@agent-recorder/stdio-proxy/types.d.ts +3 -19
- package/vendor/node_modules/@agent-recorder/stdio-proxy/types.d.ts.map +1 -1
- package/vendor/node_modules/@agent-recorder/stdio-proxy/types.js +2 -1
- package/vendor/node_modules/@agent-recorder/stdio-proxy/types.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/{core/types → types}/events.d.ts +9 -0
- package/vendor/node_modules/@agent-recorder/types/events.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/types/events.js +9 -0
- package/vendor/node_modules/@agent-recorder/types/events.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/types/index.d.ts +12 -0
- package/vendor/node_modules/@agent-recorder/types/index.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/types/index.js +9 -0
- package/vendor/node_modules/@agent-recorder/types/index.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/types/jsonrpc.d.ts +35 -0
- package/vendor/node_modules/@agent-recorder/types/jsonrpc.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/types/jsonrpc.js +6 -0
- package/vendor/node_modules/@agent-recorder/types/jsonrpc.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/types/package.json +12 -0
- package/vendor/node_modules/@agent-recorder/{core/types → types}/session.d.ts +6 -0
- package/vendor/node_modules/@agent-recorder/types/session.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/{core/types → types}/session.js.map +1 -1
- package/vendor/node_modules/@agent-recorder/types/storage.d.ts +80 -0
- package/vendor/node_modules/@agent-recorder/types/storage.d.ts.map +1 -0
- package/vendor/node_modules/@agent-recorder/types/storage.js +9 -0
- package/vendor/node_modules/@agent-recorder/types/storage.js.map +1 -0
- package/vendor/node_modules/@agent-recorder/core/types/events.d.ts.map +0 -1
- package/vendor/node_modules/@agent-recorder/core/types/events.js +0 -6
- package/vendor/node_modules/@agent-recorder/core/types/events.js.map +0 -1
- package/vendor/node_modules/@agent-recorder/core/types/session.d.ts.map +0 -1
- /package/vendor/node_modules/@agent-recorder/{core/types → types}/session.js +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token metrics DB operations.
|
|
3
|
+
* Upserts tool schema metrics and queries token summaries per session.
|
|
4
|
+
*/
|
|
5
|
+
import type Database from "better-sqlite3";
|
|
6
|
+
export interface UpsertToolSchemaMetricInput {
|
|
7
|
+
sessionId: string;
|
|
8
|
+
upstreamKey: string | null;
|
|
9
|
+
toolName: string;
|
|
10
|
+
schemaTokens: number;
|
|
11
|
+
}
|
|
12
|
+
/** Upsert a tool schema metric (one row per session+upstream+tool). */
|
|
13
|
+
export declare function upsertToolSchemaMetric(db: Database.Database, input: UpsertToolSchemaMetricInput): void;
|
|
14
|
+
export interface TokenSummary {
|
|
15
|
+
sessionId: string;
|
|
16
|
+
estimatedTotalTokens: number;
|
|
17
|
+
budgetTokens: number;
|
|
18
|
+
percentUsed: number;
|
|
19
|
+
budgetExceeded: boolean;
|
|
20
|
+
byUpstream: Record<string, {
|
|
21
|
+
callTokens: number;
|
|
22
|
+
schemaTokens: number;
|
|
23
|
+
}>;
|
|
24
|
+
byTool: Array<{
|
|
25
|
+
toolName: string;
|
|
26
|
+
calls: number;
|
|
27
|
+
totalInputTokens: number;
|
|
28
|
+
totalOutputTokens: number;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
/** Build a full token summary for a session. */
|
|
32
|
+
export declare function getTokenSummary(db: Database.Database, sessionId: string, budgetTokens: number): TokenSummary;
|
|
33
|
+
//# sourceMappingURL=token-metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-metrics.d.ts","sourceRoot":"","sources":["../../src/db/token-metrics.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,uEAAuE;AACvE,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,2BAA2B,GACjC,IAAI,CAkBN;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzE,MAAM,EAAE,KAAK,CAAC;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,gBAAgB,EAAE,MAAM,CAAC;QACzB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC,CAAC;CACJ;AAED,gDAAgD;AAChD,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,YAAY,CAoGd"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token metrics DB operations.
|
|
3
|
+
* Upserts tool schema metrics and queries token summaries per session.
|
|
4
|
+
*/
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
6
|
+
/** Upsert a tool schema metric (one row per session+upstream+tool). */
|
|
7
|
+
export function upsertToolSchemaMetric(db, input) {
|
|
8
|
+
// Use ON CONFLICT against the expression-based unique index
|
|
9
|
+
// (session_id, COALESCE(upstream_key, ''), tool_name) to handle NULL upstream_key.
|
|
10
|
+
db.prepare(`
|
|
11
|
+
INSERT INTO tool_schema_metrics (id, session_id, upstream_key, tool_name, schema_tokens)
|
|
12
|
+
VALUES (?, ?, ?, ?, ?)
|
|
13
|
+
ON CONFLICT(session_id, COALESCE(upstream_key, ''), tool_name) DO UPDATE SET
|
|
14
|
+
schema_tokens = excluded.schema_tokens,
|
|
15
|
+
recorded_at = datetime('now')
|
|
16
|
+
`).run(randomUUID(), input.sessionId, input.upstreamKey ?? null, input.toolName, input.schemaTokens);
|
|
17
|
+
}
|
|
18
|
+
/** Build a full token summary for a session. */
|
|
19
|
+
export function getTokenSummary(db, sessionId, budgetTokens) {
|
|
20
|
+
// Per-upstream call tokens.
|
|
21
|
+
// Intentionally filtered to tool_call only: agent_call/subagent_call events
|
|
22
|
+
// don't carry meaningful token payloads in the current schema.
|
|
23
|
+
const upstreamCallRows = db
|
|
24
|
+
.prepare(`
|
|
25
|
+
SELECT upstream_key, COALESCE(SUM(input_tokens), 0) + COALESCE(SUM(output_tokens), 0) AS call_tokens
|
|
26
|
+
FROM events
|
|
27
|
+
WHERE session_id = ? AND event_type = 'tool_call'
|
|
28
|
+
GROUP BY upstream_key
|
|
29
|
+
`)
|
|
30
|
+
.all(sessionId);
|
|
31
|
+
// Per-upstream schema tokens
|
|
32
|
+
const upstreamSchemaRows = db
|
|
33
|
+
.prepare(`
|
|
34
|
+
SELECT upstream_key, SUM(schema_tokens) AS schema_tokens
|
|
35
|
+
FROM tool_schema_metrics
|
|
36
|
+
WHERE session_id = ?
|
|
37
|
+
GROUP BY upstream_key
|
|
38
|
+
`)
|
|
39
|
+
.all(sessionId);
|
|
40
|
+
// Per-tool breakdown
|
|
41
|
+
const toolRows = db
|
|
42
|
+
.prepare(`
|
|
43
|
+
SELECT
|
|
44
|
+
tool_name,
|
|
45
|
+
COUNT(*) AS calls,
|
|
46
|
+
COALESCE(SUM(input_tokens), 0) AS total_input_tokens,
|
|
47
|
+
COALESCE(SUM(output_tokens), 0) AS total_output_tokens
|
|
48
|
+
FROM events
|
|
49
|
+
WHERE session_id = ? AND event_type = 'tool_call'
|
|
50
|
+
GROUP BY tool_name
|
|
51
|
+
ORDER BY (total_input_tokens + total_output_tokens) DESC
|
|
52
|
+
`)
|
|
53
|
+
.all(sessionId);
|
|
54
|
+
// Merge into byUpstream map
|
|
55
|
+
const byUpstream = {};
|
|
56
|
+
for (const row of upstreamCallRows) {
|
|
57
|
+
const key = row.upstream_key ?? "(built-in)";
|
|
58
|
+
byUpstream[key] = { callTokens: row.call_tokens, schemaTokens: 0 };
|
|
59
|
+
}
|
|
60
|
+
for (const row of upstreamSchemaRows) {
|
|
61
|
+
const key = row.upstream_key ?? "(built-in)";
|
|
62
|
+
if (!byUpstream[key])
|
|
63
|
+
byUpstream[key] = { callTokens: 0, schemaTokens: 0 };
|
|
64
|
+
byUpstream[key].schemaTokens = row.schema_tokens;
|
|
65
|
+
}
|
|
66
|
+
const totalCallTokens = Object.values(byUpstream).reduce((s, v) => s + v.callTokens, 0);
|
|
67
|
+
const totalSchemaTokens = Object.values(byUpstream).reduce((s, v) => s + v.schemaTokens, 0);
|
|
68
|
+
const estimatedTotalTokens = totalCallTokens + totalSchemaTokens;
|
|
69
|
+
// Guard against divide-by-zero when budget is 0 or not configured
|
|
70
|
+
const percentUsed = budgetTokens > 0
|
|
71
|
+
? Math.round((estimatedTotalTokens / budgetTokens) * 100)
|
|
72
|
+
: 0;
|
|
73
|
+
return {
|
|
74
|
+
sessionId,
|
|
75
|
+
estimatedTotalTokens,
|
|
76
|
+
budgetTokens,
|
|
77
|
+
percentUsed,
|
|
78
|
+
budgetExceeded: budgetTokens > 0 && estimatedTotalTokens > budgetTokens,
|
|
79
|
+
byUpstream,
|
|
80
|
+
byTool: toolRows.map((r) => ({
|
|
81
|
+
toolName: r.tool_name ?? "",
|
|
82
|
+
calls: r.calls,
|
|
83
|
+
totalInputTokens: r.total_input_tokens,
|
|
84
|
+
totalOutputTokens: r.total_output_tokens,
|
|
85
|
+
})),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=token-metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-metrics.js","sourceRoot":"","sources":["../../src/db/token-metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-metrics.test.d.ts","sourceRoot":"","sources":["../../src/db/token-metrics.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for token metrics DB operations.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
6
|
+
import { openMemoryDatabase, runMigrations, getDefaultMigrationsDir, createSession, insertEvent, upsertToolSchemaMetric, getTokenSummary, } from "../index.js";
|
|
7
|
+
describe("upsertToolSchemaMetric", () => {
|
|
8
|
+
let db;
|
|
9
|
+
let sessionId;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
db = openMemoryDatabase();
|
|
12
|
+
runMigrations(db, getDefaultMigrationsDir());
|
|
13
|
+
sessionId = randomUUID();
|
|
14
|
+
createSession(db, sessionId, new Date().toISOString());
|
|
15
|
+
});
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
db.close();
|
|
18
|
+
});
|
|
19
|
+
it("inserts a new row", () => {
|
|
20
|
+
upsertToolSchemaMetric(db, {
|
|
21
|
+
sessionId,
|
|
22
|
+
upstreamKey: "github",
|
|
23
|
+
toolName: "search_code",
|
|
24
|
+
schemaTokens: 120,
|
|
25
|
+
});
|
|
26
|
+
const rows = db
|
|
27
|
+
.prepare("SELECT * FROM tool_schema_metrics WHERE session_id = ?")
|
|
28
|
+
.all(sessionId);
|
|
29
|
+
expect(rows).toHaveLength(1);
|
|
30
|
+
expect(rows[0].tool_name).toBe("search_code");
|
|
31
|
+
expect(rows[0].schema_tokens).toBe(120);
|
|
32
|
+
});
|
|
33
|
+
it("updates schema_tokens on duplicate (session, upstream, tool)", () => {
|
|
34
|
+
upsertToolSchemaMetric(db, {
|
|
35
|
+
sessionId,
|
|
36
|
+
upstreamKey: "github",
|
|
37
|
+
toolName: "search_code",
|
|
38
|
+
schemaTokens: 120,
|
|
39
|
+
});
|
|
40
|
+
// Second call with updated count
|
|
41
|
+
upsertToolSchemaMetric(db, {
|
|
42
|
+
sessionId,
|
|
43
|
+
upstreamKey: "github",
|
|
44
|
+
toolName: "search_code",
|
|
45
|
+
schemaTokens: 200,
|
|
46
|
+
});
|
|
47
|
+
const rows = db
|
|
48
|
+
.prepare("SELECT * FROM tool_schema_metrics WHERE session_id = ?")
|
|
49
|
+
.all(sessionId);
|
|
50
|
+
// Must still be exactly one row, not two
|
|
51
|
+
expect(rows).toHaveLength(1);
|
|
52
|
+
expect(rows[0].schema_tokens).toBe(200);
|
|
53
|
+
});
|
|
54
|
+
it("treats null upstream_key correctly (no duplicate rows)", () => {
|
|
55
|
+
upsertToolSchemaMetric(db, {
|
|
56
|
+
sessionId,
|
|
57
|
+
upstreamKey: null,
|
|
58
|
+
toolName: "Glob",
|
|
59
|
+
schemaTokens: 50,
|
|
60
|
+
});
|
|
61
|
+
upsertToolSchemaMetric(db, {
|
|
62
|
+
sessionId,
|
|
63
|
+
upstreamKey: null,
|
|
64
|
+
toolName: "Glob",
|
|
65
|
+
schemaTokens: 60,
|
|
66
|
+
});
|
|
67
|
+
const rows = db
|
|
68
|
+
.prepare("SELECT * FROM tool_schema_metrics WHERE session_id = ? AND tool_name = 'Glob'")
|
|
69
|
+
.all(sessionId);
|
|
70
|
+
expect(rows).toHaveLength(1);
|
|
71
|
+
});
|
|
72
|
+
it("allows same tool name under different upstream keys", () => {
|
|
73
|
+
upsertToolSchemaMetric(db, {
|
|
74
|
+
sessionId,
|
|
75
|
+
upstreamKey: "github",
|
|
76
|
+
toolName: "search",
|
|
77
|
+
schemaTokens: 100,
|
|
78
|
+
});
|
|
79
|
+
upsertToolSchemaMetric(db, {
|
|
80
|
+
sessionId,
|
|
81
|
+
upstreamKey: "linear",
|
|
82
|
+
toolName: "search",
|
|
83
|
+
schemaTokens: 80,
|
|
84
|
+
});
|
|
85
|
+
const rows = db
|
|
86
|
+
.prepare("SELECT * FROM tool_schema_metrics WHERE session_id = ?")
|
|
87
|
+
.all(sessionId);
|
|
88
|
+
expect(rows).toHaveLength(2);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
describe("getTokenSummary", () => {
|
|
92
|
+
let db;
|
|
93
|
+
let sessionId;
|
|
94
|
+
beforeEach(() => {
|
|
95
|
+
db = openMemoryDatabase();
|
|
96
|
+
runMigrations(db, getDefaultMigrationsDir());
|
|
97
|
+
sessionId = randomUUID();
|
|
98
|
+
createSession(db, sessionId, new Date().toISOString());
|
|
99
|
+
});
|
|
100
|
+
afterEach(() => {
|
|
101
|
+
db.close();
|
|
102
|
+
});
|
|
103
|
+
it("returns zero totals for empty session", () => {
|
|
104
|
+
const summary = getTokenSummary(db, sessionId, 150000);
|
|
105
|
+
expect(summary.estimatedTotalTokens).toBe(0);
|
|
106
|
+
expect(summary.percentUsed).toBe(0);
|
|
107
|
+
expect(summary.budgetExceeded).toBe(false);
|
|
108
|
+
expect(summary.byTool).toHaveLength(0);
|
|
109
|
+
});
|
|
110
|
+
it("does not divide by zero when budgetTokens is 0", () => {
|
|
111
|
+
const summary = getTokenSummary(db, sessionId, 0);
|
|
112
|
+
expect(summary.percentUsed).toBe(0);
|
|
113
|
+
expect(summary.budgetExceeded).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
it("aggregates call tokens from events", () => {
|
|
116
|
+
insertEvent(db, {
|
|
117
|
+
id: randomUUID(),
|
|
118
|
+
sessionId,
|
|
119
|
+
sequence: 1,
|
|
120
|
+
eventType: "tool_call",
|
|
121
|
+
agentRole: "main",
|
|
122
|
+
agentName: "claude-code",
|
|
123
|
+
toolName: "execute_sql",
|
|
124
|
+
upstreamKey: "supabase",
|
|
125
|
+
startedAt: new Date().toISOString(),
|
|
126
|
+
status: "success",
|
|
127
|
+
inputTokens: 100,
|
|
128
|
+
outputTokens: 200,
|
|
129
|
+
});
|
|
130
|
+
const summary = getTokenSummary(db, sessionId, 150000);
|
|
131
|
+
expect(summary.estimatedTotalTokens).toBe(300);
|
|
132
|
+
expect(summary.byTool).toHaveLength(1);
|
|
133
|
+
expect(summary.byTool[0].toolName).toBe("execute_sql");
|
|
134
|
+
expect(summary.byTool[0].totalInputTokens).toBe(100);
|
|
135
|
+
expect(summary.byTool[0].totalOutputTokens).toBe(200);
|
|
136
|
+
});
|
|
137
|
+
it("includes schema tokens in total", () => {
|
|
138
|
+
upsertToolSchemaMetric(db, {
|
|
139
|
+
sessionId,
|
|
140
|
+
upstreamKey: "supabase",
|
|
141
|
+
toolName: "execute_sql",
|
|
142
|
+
schemaTokens: 50,
|
|
143
|
+
});
|
|
144
|
+
const summary = getTokenSummary(db, sessionId, 150000);
|
|
145
|
+
expect(summary.estimatedTotalTokens).toBe(50);
|
|
146
|
+
expect(summary.byUpstream["supabase"].schemaTokens).toBe(50);
|
|
147
|
+
});
|
|
148
|
+
it("flags budget exceeded when total exceeds budget", () => {
|
|
149
|
+
insertEvent(db, {
|
|
150
|
+
id: randomUUID(),
|
|
151
|
+
sessionId,
|
|
152
|
+
sequence: 1,
|
|
153
|
+
eventType: "tool_call",
|
|
154
|
+
agentRole: "main",
|
|
155
|
+
agentName: "claude-code",
|
|
156
|
+
toolName: "execute_sql",
|
|
157
|
+
startedAt: new Date().toISOString(),
|
|
158
|
+
status: "success",
|
|
159
|
+
inputTokens: 1000,
|
|
160
|
+
outputTokens: 500,
|
|
161
|
+
});
|
|
162
|
+
const summary = getTokenSummary(db, sessionId, 1000);
|
|
163
|
+
expect(summary.budgetExceeded).toBe(true);
|
|
164
|
+
expect(summary.percentUsed).toBeGreaterThan(100);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
//# sourceMappingURL=token-metrics.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-metrics.test.js","sourceRoot":"","sources":["../../src/db/token-metrics.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,uBAAuB,EACvB,aAAa,EACb,WAAW,EACX,sBAAsB,EACtB,eAAe,GAChB,MAAM,aAAa,CAAC;AAGrB,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,IAAI,EAAqB,CAAC;IAC1B,IAAI,SAAiB,CAAC;IAEtB,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,GAAG,kBAAkB,EAAE,CAAC;QAC1B,aAAa,CAAC,EAAE,EAAE,uBAAuB,EAAE,CAAC,CAAC;QAC7C,SAAS,GAAG,UAAU,EAAE,CAAC;QACzB,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,sBAAsB,CAAC,EAAE,EAAE;YACzB,SAAS;YACT,WAAW,EAAE,QAAQ;YACrB,QAAQ,EAAE,aAAa;YACvB,YAAY,EAAE,GAAG;SAClB,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,EAAE;aACZ,OAAO,CAAC,wDAAwD,CAAC;aACjE,GAAG,CAAC,SAAS,CAAwD,CAAC;QACzE,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,sBAAsB,CAAC,EAAE,EAAE;YACzB,SAAS;YACT,WAAW,EAAE,QAAQ;YACrB,QAAQ,EAAE,aAAa;YACvB,YAAY,EAAE,GAAG;SAClB,CAAC,CAAC;QACH,iCAAiC;QACjC,sBAAsB,CAAC,EAAE,EAAE;YACzB,SAAS;YACT,WAAW,EAAE,QAAQ;YACrB,QAAQ,EAAE,aAAa;YACvB,YAAY,EAAE,GAAG;SAClB,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,EAAE;aACZ,OAAO,CAAC,wDAAwD,CAAC;aACjE,GAAG,CAAC,SAAS,CAAqC,CAAC;QACtD,yCAAyC;QACzC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,sBAAsB,CAAC,EAAE,EAAE;YACzB,SAAS;YACT,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,MAAM;YAChB,YAAY,EAAE,EAAE;SACjB,CAAC,CAAC;QACH,sBAAsB,CAAC,EAAE,EAAE;YACzB,SAAS;YACT,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,MAAM;YAChB,YAAY,EAAE,EAAE;SACjB,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,EAAE;aACZ,OAAO,CACN,+EAA+E,CAChF;aACA,GAAG,CAAC,SAAS,CAAC,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,sBAAsB,CAAC,EAAE,EAAE;YACzB,SAAS;YACT,WAAW,EAAE,QAAQ;YACrB,QAAQ,EAAE,QAAQ;YAClB,YAAY,EAAE,GAAG;SAClB,CAAC,CAAC;QACH,sBAAsB,CAAC,EAAE,EAAE;YACzB,SAAS;YACT,WAAW,EAAE,QAAQ;YACrB,QAAQ,EAAE,QAAQ;YAClB,YAAY,EAAE,EAAE;SACjB,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,EAAE;aACZ,OAAO,CAAC,wDAAwD,CAAC;aACjE,GAAG,CAAC,SAAS,CAAC,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAI,EAAqB,CAAC;IAC1B,IAAI,SAAiB,CAAC;IAEtB,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,GAAG,kBAAkB,EAAE,CAAC;QAC1B,aAAa,CAAC,EAAE,EAAE,uBAAuB,EAAE,CAAC,CAAC;QAC7C,SAAS,GAAG,UAAU,EAAE,CAAC;QACzB,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,OAAO,GAAG,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACvD,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,OAAO,GAAG,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QAClD,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,WAAW,CAAC,EAAE,EAAE;YACd,EAAE,EAAE,UAAU,EAAE;YAChB,SAAS;YACT,QAAQ,EAAE,CAAC;YACX,SAAS,EAAE,WAAW;YACtB,SAAS,EAAE,MAAM;YACjB,SAAS,EAAE,aAAa;YACxB,QAAQ,EAAE,aAAa;YACvB,WAAW,EAAE,UAAU;YACvB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,MAAM,EAAE,SAAS;YACjB,WAAW,EAAE,GAAG;YAChB,YAAY,EAAE,GAAG;SAClB,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACvD,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACxD,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtD,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,sBAAsB,CAAC,EAAE,EAAE;YACzB,SAAS;YACT,WAAW,EAAE,UAAU;YACvB,QAAQ,EAAE,aAAa;YACvB,YAAY,EAAE,EAAE;SACjB,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACvD,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9C,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAE,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,WAAW,CAAC,EAAE,EAAE;YACd,EAAE,EAAE,UAAU,EAAE;YAChB,SAAS;YACT,QAAQ,EAAE,CAAC;YACX,SAAS,EAAE,WAAW;YACtB,SAAS,EAAE,MAAM;YACjB,SAAS,EAAE,aAAa;YACxB,QAAQ,EAAE,aAAa;YACvB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,MAAM,EAAE,SAAS;YACjB,WAAW,EAAE,IAAI;YACjB,YAAY,EAAE,GAAG;SAClB,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
export * from "./types/index.js";
|
|
8
8
|
export * from "./db/index.js";
|
|
9
9
|
export * from "./utils/index.js";
|
|
10
|
-
export { loadConfig, getActualListenPort, getDefaultUpstreamsPath, type Config, } from "./config.js";
|
|
10
|
+
export { loadConfig, getActualListenPort, getDefaultUpstreamsPath, DEFAULT_CONTEXT_BUDGET_TOKENS, type Config, } from "./config.js";
|
|
11
11
|
export * from "./daemon-paths.js";
|
|
12
12
|
export * from "./lockfile.js";
|
|
13
13
|
export * from "./wrap-utils.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,KAAK,MAAM,GACZ,MAAM,aAAa,CAAC;AACrB,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,6BAA6B,EAC7B,KAAK,MAAM,GACZ,MAAM,aAAa,CAAC;AACrB,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC"}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
export * from "./types/index.js";
|
|
8
8
|
export * from "./db/index.js";
|
|
9
9
|
export * from "./utils/index.js";
|
|
10
|
-
export { loadConfig, getActualListenPort, getDefaultUpstreamsPath, } from "./config.js";
|
|
10
|
+
export { loadConfig, getActualListenPort, getDefaultUpstreamsPath, DEFAULT_CONTEXT_BUDGET_TOKENS, } from "./config.js";
|
|
11
11
|
export * from "./daemon-paths.js";
|
|
12
12
|
export * from "./lockfile.js";
|
|
13
13
|
export * from "./wrap-utils.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,6BAA6B,GAE9B,MAAM,aAAa,CAAC;AACrB,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
-- Add correlation_id column for future parallel tool execution support.
|
|
2
|
+
-- Currently always NULL — no code path generates or assigns correlation IDs yet.
|
|
3
|
+
-- This column is scaffolding for when Claude Code's hook API exposes correlation
|
|
4
|
+
-- IDs. At that point, findRunningEvent() will prefer matching on this column
|
|
5
|
+
-- over the fallback tool-name-based lookup.
|
|
6
|
+
-- See also: findRunningEvent() in packages/core/src/db/events.ts
|
|
7
|
+
|
|
8
|
+
ALTER TABLE events ADD COLUMN correlation_id TEXT;
|
|
9
|
+
|
|
10
|
+
-- Index for correlation-based lookups (unused until IDs are generated)
|
|
11
|
+
CREATE INDEX IF NOT EXISTS idx_events_correlation_id ON events(correlation_id);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
-- Add token tracking columns to events table
|
|
2
|
+
ALTER TABLE events ADD COLUMN input_tokens INTEGER;
|
|
3
|
+
ALTER TABLE events ADD COLUMN output_tokens INTEGER;
|
|
4
|
+
|
|
5
|
+
-- Tool schema metrics: one row per (session, upstream, tool) from tools/list responses
|
|
6
|
+
CREATE TABLE IF NOT EXISTS tool_schema_metrics (
|
|
7
|
+
id TEXT PRIMARY KEY,
|
|
8
|
+
session_id TEXT NOT NULL,
|
|
9
|
+
upstream_key TEXT,
|
|
10
|
+
tool_name TEXT NOT NULL,
|
|
11
|
+
schema_tokens INTEGER NOT NULL,
|
|
12
|
+
recorded_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
13
|
+
);
|
|
14
|
+
CREATE INDEX IF NOT EXISTS idx_tsm_session ON tool_schema_metrics(session_id);
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_tsm_upstream ON tool_schema_metrics(upstream_key);
|
|
16
|
+
-- Expression-based unique index to handle NULL upstream_key correctly.
|
|
17
|
+
-- ON CONFLICT targeting this index requires SQLite >= 3.37.0 (2021-11-27).
|
|
18
|
+
-- better-sqlite3 bundles its own SQLite, so the version is always recent enough.
|
|
19
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_tsm_unique ON tool_schema_metrics(session_id, COALESCE(upstream_key, ''), tool_name);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Type re-exports from @agent-recorder/types (the canonical zero-dep source).
|
|
3
|
+
*/
|
|
4
|
+
export type { EventType, EventStatus, ErrorCategory, BaseEvent, AgentCallEvent, SubagentCallEvent, SkillCallEvent, ToolCallEvent, RecordedEvent, SessionStatus, Session, SessionWithActivity, StorageAdapter, } from "@agent-recorder/types";
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,SAAS,EACT,WAAW,EACX,aAAa,EACb,SAAS,EACT,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EACV,SAAS,EACT,WAAW,EACX,aAAa,EACb,SAAS,EACT,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,aAAa,EACb,aAAa,EACb,OAAO,EACP,mBAAmB,EACnB,cAAc,GACf,MAAM,uBAAuB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../src/utils/redact.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../src/utils/redact.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAGlE;AA2BD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,OAAO,EACd,SAAS,GAAE,MAA2B,GACrC,MAAM,CASR;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,EAAE,EACd,SAAS,GAAE,MAA2B,GACrC,MAAM,CAGR"}
|
|
@@ -8,21 +8,24 @@ const DEFAULT_MAX_LENGTH = 10240; // 10KB
|
|
|
8
8
|
* Keys are matched case-insensitively.
|
|
9
9
|
*/
|
|
10
10
|
export function redactJson(value, keys) {
|
|
11
|
+
const lowerKeys = new Set(keys.map((k) => k.toLowerCase()));
|
|
12
|
+
return redactJsonInternal(value, lowerKeys);
|
|
13
|
+
}
|
|
14
|
+
function redactJsonInternal(value, lowerKeys) {
|
|
11
15
|
if (value === null || value === undefined) {
|
|
12
16
|
return value;
|
|
13
17
|
}
|
|
14
18
|
if (Array.isArray(value)) {
|
|
15
|
-
return value.map((item) =>
|
|
19
|
+
return value.map((item) => redactJsonInternal(item, lowerKeys));
|
|
16
20
|
}
|
|
17
21
|
if (typeof value === "object") {
|
|
18
22
|
const result = {};
|
|
19
|
-
const lowerKeys = new Set(keys.map((k) => k.toLowerCase()));
|
|
20
23
|
for (const [k, v] of Object.entries(value)) {
|
|
21
24
|
if (lowerKeys.has(k.toLowerCase())) {
|
|
22
25
|
result[k] = REDACTED_VALUE;
|
|
23
26
|
}
|
|
24
27
|
else {
|
|
25
|
-
result[k] =
|
|
28
|
+
result[k] = redactJsonInternal(v, lowerKeys);
|
|
26
29
|
}
|
|
27
30
|
}
|
|
28
31
|
return result;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/utils/redact.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,cAAc,GAAG,YAAY,CAAC;AACpC,MAAM,kBAAkB,GAAG,KAAK,CAAC,CAAC,OAAO;AAEzC;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc,EAAE,IAAc;IACvD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/utils/redact.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,cAAc,GAAG,YAAY,CAAC;AACpC,MAAM,kBAAkB,GAAG,KAAK,CAAC,CAAC,OAAO;AAEzC;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc,EAAE,IAAc;IACvD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAC5D,OAAO,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc,EAAE,SAAsB;IAChE,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,MAAM,GAA4B,EAAE,CAAC;QAE3C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;YACtE,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;gBACnC,MAAM,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC;YAC7B,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAc,EACd,YAAoB,kBAAkB;IAEtC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAEnC,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,eAAe,GAAG,SAAS,GAAG,EAAE,CAAC,CAAC,6BAA6B;IACrE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,GAAG,gBAAgB,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAc,EACd,IAAc,EACd,YAAoB,kBAAkB;IAEtC,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACzC,OAAO,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.test.d.ts","sourceRoot":"","sources":["../../src/utils/redact.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for redaction and truncation utilities,
|
|
3
|
+
* including non-serializable edge cases.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect } from "vitest";
|
|
6
|
+
import { redactJson, truncateJson, redactAndTruncate } from "./redact.js";
|
|
7
|
+
describe("redactJson", () => {
|
|
8
|
+
it("redacts matching keys case-insensitively", () => {
|
|
9
|
+
const result = redactJson({ token: "secret", Token: "also-secret", safe: "ok" }, ["token"]);
|
|
10
|
+
expect(result).toEqual({
|
|
11
|
+
token: "[REDACTED]",
|
|
12
|
+
Token: "[REDACTED]",
|
|
13
|
+
safe: "ok",
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
it("handles null and undefined", () => {
|
|
17
|
+
expect(redactJson(null, ["key"])).toBeNull();
|
|
18
|
+
expect(redactJson(undefined, ["key"])).toBeUndefined();
|
|
19
|
+
});
|
|
20
|
+
it("handles arrays", () => {
|
|
21
|
+
const result = redactJson([{ password: "x" }, { safe: "y" }], ["password"]);
|
|
22
|
+
expect(result).toEqual([{ password: "[REDACTED]" }, { safe: "y" }]);
|
|
23
|
+
});
|
|
24
|
+
it("handles primitive values", () => {
|
|
25
|
+
expect(redactJson("hello", ["key"])).toBe("hello");
|
|
26
|
+
expect(redactJson(42, ["key"])).toBe(42);
|
|
27
|
+
expect(redactJson(true, ["key"])).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe("truncateJson", () => {
|
|
31
|
+
it("does not truncate short values", () => {
|
|
32
|
+
const result = truncateJson({ a: 1 });
|
|
33
|
+
expect(result).toBe('{"a":1}');
|
|
34
|
+
});
|
|
35
|
+
it("truncates long values with indicator", () => {
|
|
36
|
+
const long = { data: "x".repeat(20000) };
|
|
37
|
+
const result = truncateJson(long, 100);
|
|
38
|
+
expect(result.length).toBe(100);
|
|
39
|
+
expect(result).toMatch(/\.\.\.\[TRUNCATED\]$/);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe("redactAndTruncate", () => {
|
|
43
|
+
it("returns a string", () => {
|
|
44
|
+
const result = redactAndTruncate({ key: "value" }, []);
|
|
45
|
+
expect(typeof result).toBe("string");
|
|
46
|
+
});
|
|
47
|
+
it("redacts and truncates in one step", () => {
|
|
48
|
+
const result = redactAndTruncate({ password: "secret", data: "ok" }, [
|
|
49
|
+
"password",
|
|
50
|
+
]);
|
|
51
|
+
const parsed = JSON.parse(result);
|
|
52
|
+
expect(parsed.password).toBe("[REDACTED]");
|
|
53
|
+
expect(parsed.data).toBe("ok");
|
|
54
|
+
});
|
|
55
|
+
it("handles circular references by throwing", () => {
|
|
56
|
+
const circular = { a: 1 };
|
|
57
|
+
circular.self = circular;
|
|
58
|
+
// JSON.stringify throws on circular refs; redactAndTruncate should propagate
|
|
59
|
+
expect(() => redactAndTruncate(circular, [])).toThrow();
|
|
60
|
+
});
|
|
61
|
+
it("handles BigInt by throwing", () => {
|
|
62
|
+
const withBigInt = { value: BigInt(123) };
|
|
63
|
+
// JSON.stringify throws on BigInt; redactAndTruncate should propagate
|
|
64
|
+
expect(() => redactAndTruncate(withBigInt, [])).toThrow();
|
|
65
|
+
});
|
|
66
|
+
it("handles Symbol values (dropped by JSON.stringify)", () => {
|
|
67
|
+
const withSymbol = { sym: Symbol("test"), safe: "ok" };
|
|
68
|
+
const result = redactAndTruncate(withSymbol, []);
|
|
69
|
+
const parsed = JSON.parse(result);
|
|
70
|
+
// Symbols are dropped by JSON.stringify
|
|
71
|
+
expect(parsed.sym).toBeUndefined();
|
|
72
|
+
expect(parsed.safe).toBe("ok");
|
|
73
|
+
});
|
|
74
|
+
it("handles undefined values (dropped by JSON.stringify)", () => {
|
|
75
|
+
const withUndefined = { undef: undefined, safe: "ok" };
|
|
76
|
+
const result = redactAndTruncate(withUndefined, []);
|
|
77
|
+
const parsed = JSON.parse(result);
|
|
78
|
+
expect("undef" in parsed).toBe(false);
|
|
79
|
+
expect(parsed.safe).toBe("ok");
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
//# sourceMappingURL=redact.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.test.js","sourceRoot":"","sources":["../../src/utils/redact.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token estimation utility.
|
|
3
|
+
* Uses UTF-8 byte length / 4 approximation — no external dependencies.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Estimate token count for any value.
|
|
7
|
+
* Rough approximation: ~4 UTF-8 bytes per token.
|
|
8
|
+
* Uses TextEncoder for byte-accurate counting (handles non-ASCII correctly).
|
|
9
|
+
* Accurate enough for context-budget alerting; not suitable for exact billing.
|
|
10
|
+
*
|
|
11
|
+
* Pass raw values/objects only. For pre-serialized strings use
|
|
12
|
+
* `estimateSerializedTokens` directly — passing a string here will
|
|
13
|
+
* double-serialize it (JSON.stringify wraps strings in quotes), inflating
|
|
14
|
+
* the estimate.
|
|
15
|
+
*/
|
|
16
|
+
export declare function estimateTokens(value: unknown): number;
|
|
17
|
+
/**
|
|
18
|
+
* Estimate token count for an already-serialized JSON string.
|
|
19
|
+
* Uses byte-accurate UTF-8 counting, consistent with estimateTokens.
|
|
20
|
+
* Use this when the value has already been passed through redactAndTruncate
|
|
21
|
+
* (which returns a string) to avoid double-serialization.
|
|
22
|
+
*/
|
|
23
|
+
export declare function estimateSerializedTokens(json: string): number;
|
|
24
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/utils/tokens.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGrD;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7D"}
|