/** * Telemetry API Client * Handles telemetry data fetching for the usage dashboard. * * NOTE: Currently returns mock/placeholder data since the telemetry API * aggregation endpoints don't exist yet. The important thing is the UI structure. * When the backend endpoints are ready, replace mock calls with real apiGet() calls. */ import { apiGet, type ApiResponse } from "./client"; // ─── Types ─────────────────────────────────────────────────────────── export type TimeRange = "7d" | "30d" | "90d"; export interface UsageSummary { totalTokens: number; totalCost: number; taskCount: number; avgQualityGatePassRate: number; } export interface TokenUsagePoint { date: string; inputTokens: number; outputTokens: number; totalTokens: number; } export interface CostBreakdownItem { model: string; provider: string; cost: number; taskCount: number; } export interface TaskOutcomeItem { outcome: string; count: number; color: string; } export interface EstimateParams { taskType: string; model: string; provider: string; complexity: string; } export interface EstimateResponse { prediction: { input_tokens: { median: number; p75: number; p90: number }; output_tokens: { median: number; p75: number; p90: number }; cost_usd_micros: Record; quality: { gate_pass_rate: number; success_rate: number }; } | null; metadata: { sample_size: number; confidence: "none" | "low" | "medium" | "high"; }; } // ─── Mock Data Generators ──────────────────────────────────────────── function generateDateRange(range: TimeRange): string[] { const days = range === "7d" ? 7 : range === "30d" ? 30 : 90; const dates: string[] = []; const now = new Date(); for (let i = days - 1; i >= 0; i--) { const d = new Date(now); d.setDate(d.getDate() - i); dates.push(d.toISOString().split("T")[0] ?? ""); } return dates; } function generateMockTokenUsage(range: TimeRange): TokenUsagePoint[] { const dates = generateDateRange(range); return dates.map((date) => { const baseInput = 8000 + Math.floor(Math.random() * 12000); const baseOutput = 3000 + Math.floor(Math.random() * 7000); return { date, inputTokens: baseInput, outputTokens: baseOutput, totalTokens: baseInput + baseOutput, }; }); } function generateMockSummary(range: TimeRange): UsageSummary { const multiplier = range === "7d" ? 1 : range === "30d" ? 4 : 12; return { totalTokens: 245_800 * multiplier, totalCost: 3.42 * multiplier, taskCount: 47 * multiplier, avgQualityGatePassRate: 0.87, }; } function generateMockCostBreakdown(): CostBreakdownItem[] { return [ { model: "claude-sonnet-4-5", provider: "anthropic", cost: 18.5, taskCount: 124 }, { model: "gpt-4o", provider: "openai", cost: 12.3, taskCount: 89 }, { model: "claude-haiku-3.5", provider: "anthropic", cost: 4.2, taskCount: 156 }, { model: "llama-3.3-70b", provider: "ollama", cost: 0, taskCount: 67 }, { model: "gemini-2.0-flash", provider: "google", cost: 2.8, taskCount: 42 }, ]; } // PDA-friendly colors: calm, no aggressive reds function generateMockTaskOutcomes(): TaskOutcomeItem[] { return [ { outcome: "Success", count: 312, color: "#6EBF8B" }, { outcome: "Partial", count: 48, color: "#F5C862" }, { outcome: "Timeout", count: 18, color: "#94A3B8" }, { outcome: "Incomplete", count: 22, color: "#C4A5DE" }, ]; } // ─── API Functions ─────────────────────────────────────────────────── /** * Fetch usage summary data (total tokens, cost, task count, quality rate) */ export async function fetchUsageSummary(timeRange: TimeRange): Promise { // TODO: Replace with real API call when backend aggregation endpoints are ready // const response = await apiGet>(`/api/telemetry/summary?range=${timeRange}`); // return response.data; void apiGet; // suppress unused import warning in the meantime await new Promise((resolve) => setTimeout(resolve, 200)); return generateMockSummary(timeRange); } /** * Fetch token usage time series for charts */ export async function fetchTokenUsage(timeRange: TimeRange): Promise { // TODO: Replace with real API call // const response = await apiGet>(`/api/telemetry/tokens?range=${timeRange}`); // return response.data; await new Promise((resolve) => setTimeout(resolve, 250)); return generateMockTokenUsage(timeRange); } /** * Fetch cost breakdown by model */ export async function fetchCostBreakdown(timeRange: TimeRange): Promise { // TODO: Replace with real API call // const response = await apiGet>(`/api/telemetry/costs?range=${timeRange}`); // return response.data; await new Promise((resolve) => setTimeout(resolve, 200)); void timeRange; return generateMockCostBreakdown(); } /** * Fetch task outcome distribution */ export async function fetchTaskOutcomes(timeRange: TimeRange): Promise { // TODO: Replace with real API call // const response = await apiGet>(`/api/telemetry/outcomes?range=${timeRange}`); // return response.data; await new Promise((resolve) => setTimeout(resolve, 150)); void timeRange; return generateMockTaskOutcomes(); } /** * Fetch cost/token estimate for a given task configuration. * Uses the real GET /api/telemetry/estimate endpoint from TEL-006. */ export async function fetchEstimate(params: EstimateParams): Promise { const query = new URLSearchParams({ taskType: params.taskType, model: params.model, provider: params.provider, complexity: params.complexity, }).toString(); const response = await apiGet>(`/api/telemetry/estimate?${query}`); return response.data; }