feat(ui): AI Usage Sacred Valley card + /api/ai-usage proxy (Claude tokens + local model perf)

Summarises the Homelab Monitor (CT300 :8080) into a blackflame card: Claude Code
token usage today/week + top model, and OpenClaw/Ollama p50/p95 latency + error rate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
root
2026-06-04 23:40:28 +10:00
parent 6d01cb34a7
commit 5aba750102
6 changed files with 142 additions and 1 deletions

View File

@@ -0,0 +1,36 @@
import { describe, it, expect } from 'vitest';
import { summarizeUsage } from '../../lib/api/routes/ai_usage.js';
describe('summarizeUsage', () => {
it('sums today + week tokens, picks top model, condenses local perf', () => {
const data = {
generated_at: '2026-06-04T23:00:00Z',
daily_by_model: [
{ day: '2026-06-04', model: 'claude-opus-4-8', input: 100, output: 200, cache_read: 1000, cache_creation: 50, turns: 5 },
{ day: '2026-06-04', model: 'claude-sonnet-4-6', input: 10, output: 20, cache_read: 0, cache_creation: 0, turns: 2 },
{ day: '2026-06-03', model: 'claude-opus-4-8', input: 1, output: 1, cache_read: 0, cache_creation: 0, turns: 1 }
]
};
const openclaw = { summary: { by_model: [
{ model: 'ollama/qwen2.5-coder:7b', count: 165, errors: 0, error_rate: 0, p50_ms: 3540, p95_ms: 88749 },
{ model: 'ollama/llama3.1:8b', count: 50, errors: 2, error_rate: 0.04, p50_ms: 17443, p95_ms: 17991 }
] } };
const s = summarizeUsage(data, openclaw);
expect(s.ok).toBe(true);
expect(s.today).toBe('2026-06-04');
expect(s.claude.today).toEqual({ input: 110, output: 220, cache: 1050, turns: 7 });
expect(s.claude.week.turns).toBe(8); // includes 06-03
expect(s.claude.top_model).toBe('claude-opus-4-8'); // most tokens this week
expect(s.local.runs).toBe(215);
expect(s.local.top.model).toBe('qwen2.5-coder:7b'); // ollama/ stripped, highest count
expect(s.local.top.p95_ms).toBe(88749);
});
it('handles a missing openclaw payload', () => {
const s = summarizeUsage({ daily_by_model: [] }, null);
expect(s.ok).toBe(true);
expect(s.local.runs).toBe(0);
expect(s.local.top).toBeNull();
});
});