- @tokenvault/rtk-bridge: Reads ~/Library/Application Support/rtk/history.db and syncs new commands to /v1/rtk/stats (stateful, batched, idempotent) - Core: rtk_commands table + 4 endpoints (/v1/rtk/stats, /rtk/commands, /rtk/hosts) - Dashboard: new RTK Savings tab with 6 KPI cards + top commands + host breakdown - Multi-host aggregation: sync from Mac Studio, Mac Mini, MacBooks etc. - First sync: 753 commands, 3.5M tokens saved aggregated RTK is MIT-licensed (github.com/rtk-ai/rtk) — we use it as the compression engine and add the missing pieces: central tracking, team attribution, cross-machine dashboards, long-term trend analysis.
141 lines
5.0 KiB
TypeScript
141 lines
5.0 KiB
TypeScript
import type { FastifyInstance } from 'fastify';
|
|
import { query } from '../db/client.js';
|
|
import { logger } from '../observability/logger.js';
|
|
|
|
interface RtkStatsBody {
|
|
host: string;
|
|
commands: Array<{
|
|
rtk_id: number;
|
|
timestamp: string;
|
|
original_cmd: string;
|
|
rtk_cmd: string;
|
|
input_tokens: number;
|
|
output_tokens: number;
|
|
saved_tokens: number;
|
|
savings_pct: number;
|
|
exec_time_ms: number;
|
|
project_path: string;
|
|
}>;
|
|
}
|
|
|
|
export async function rtkRoutes(app: FastifyInstance): Promise<void> {
|
|
// ─── Ingest RTK stats from client machines ───────────────────────────
|
|
app.post<{ Body: RtkStatsBody }>('/v1/rtk/stats', async (req, reply) => {
|
|
const { host, commands } = req.body;
|
|
|
|
if (!host || !Array.isArray(commands)) {
|
|
reply.code(400);
|
|
return { error: 'host and commands array required' };
|
|
}
|
|
|
|
let inserted = 0;
|
|
for (const cmd of commands) {
|
|
try {
|
|
const result = await query(
|
|
`INSERT INTO rtk_commands (
|
|
rtk_id, host, timestamp, original_cmd, rtk_cmd,
|
|
input_tokens, output_tokens, saved_tokens, savings_pct,
|
|
exec_time_ms, project_path
|
|
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)
|
|
ON CONFLICT (host, rtk_id) DO NOTHING`,
|
|
[
|
|
cmd.rtk_id, host, cmd.timestamp, cmd.original_cmd, cmd.rtk_cmd,
|
|
cmd.input_tokens, cmd.output_tokens, cmd.saved_tokens, cmd.savings_pct,
|
|
cmd.exec_time_ms, cmd.project_path,
|
|
],
|
|
);
|
|
if (result.rowCount && result.rowCount > 0) inserted += 1;
|
|
} catch (err) {
|
|
logger.warn({ err, rtk_id: cmd.rtk_id }, 'Failed to insert RTK command');
|
|
}
|
|
}
|
|
|
|
logger.info({ host, received: commands.length, inserted }, 'RTK stats ingested');
|
|
return { received: commands.length, inserted };
|
|
});
|
|
|
|
// ─── Aggregate stats (all hosts) ──────────────────────────────────────
|
|
app.get<{ Querystring: { period?: string } }>('/v1/rtk/stats', async (req) => {
|
|
const intervals: Record<string, string> = {
|
|
today: "timestamp >= CURRENT_DATE",
|
|
week: "timestamp >= CURRENT_DATE - INTERVAL '7 days'",
|
|
month: "timestamp >= CURRENT_DATE - INTERVAL '30 days'",
|
|
all: '1=1',
|
|
};
|
|
const where = intervals[req.query.period ?? 'all'] ?? intervals['all']!;
|
|
|
|
const result = await query<{
|
|
total_commands: string; total_input: string; total_output: string;
|
|
total_saved: string; avg_savings: string; hosts: string; projects: string;
|
|
}>(`SELECT
|
|
COUNT(*) as total_commands,
|
|
COALESCE(SUM(input_tokens), 0) as total_input,
|
|
COALESCE(SUM(output_tokens), 0) as total_output,
|
|
COALESCE(SUM(saved_tokens), 0) as total_saved,
|
|
COALESCE(AVG(savings_pct), 0) as avg_savings,
|
|
COUNT(DISTINCT host) as hosts,
|
|
COUNT(DISTINCT project_path) as projects
|
|
FROM rtk_commands WHERE ${where}`);
|
|
|
|
const row = result.rows[0]!;
|
|
return {
|
|
period: req.query.period ?? 'all',
|
|
total_commands: parseInt(row.total_commands, 10),
|
|
total_input_tokens: parseInt(row.total_input, 10),
|
|
total_output_tokens: parseInt(row.total_output, 10),
|
|
total_saved_tokens: parseInt(row.total_saved, 10),
|
|
avg_savings_pct: parseFloat(row.avg_savings),
|
|
unique_hosts: parseInt(row.hosts, 10),
|
|
unique_projects: parseInt(row.projects, 10),
|
|
};
|
|
});
|
|
|
|
// ─── Top commands by savings ──────────────────────────────────────────
|
|
app.get('/v1/rtk/commands', async () => {
|
|
const result = await query<{
|
|
cmd: string; count: string; saved: string; avg_pct: string;
|
|
}>(`SELECT
|
|
split_part(rtk_cmd, ' ', 1) || ' ' || split_part(rtk_cmd, ' ', 2) as cmd,
|
|
COUNT(*) as count,
|
|
COALESCE(SUM(saved_tokens), 0) as saved,
|
|
COALESCE(AVG(savings_pct), 0) as avg_pct
|
|
FROM rtk_commands
|
|
WHERE timestamp >= CURRENT_DATE - INTERVAL '30 days'
|
|
GROUP BY cmd
|
|
ORDER BY saved DESC
|
|
LIMIT 20`);
|
|
|
|
return {
|
|
commands: result.rows.map(r => ({
|
|
cmd: r.cmd,
|
|
count: parseInt(r.count, 10),
|
|
saved_tokens: parseInt(r.saved, 10),
|
|
avg_savings_pct: parseFloat(r.avg_pct),
|
|
})),
|
|
};
|
|
});
|
|
|
|
// ─── Per-host breakdown ───────────────────────────────────────────────
|
|
app.get('/v1/rtk/hosts', async () => {
|
|
const result = await query<{
|
|
host: string; count: string; saved: string; last_seen: string;
|
|
}>(`SELECT
|
|
host,
|
|
COUNT(*) as count,
|
|
COALESCE(SUM(saved_tokens), 0) as saved,
|
|
MAX(timestamp) as last_seen
|
|
FROM rtk_commands
|
|
GROUP BY host
|
|
ORDER BY saved DESC`);
|
|
|
|
return {
|
|
hosts: result.rows.map(r => ({
|
|
host: r.host,
|
|
commands: parseInt(r.count, 10),
|
|
saved_tokens: parseInt(r.saved, 10),
|
|
last_seen: r.last_seen,
|
|
})),
|
|
};
|
|
});
|
|
}
|