diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index 0fc3370b..1a5ba58d 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -1,4 +1,4 @@ -import type { APIResponse, Server, Tool, ToolApproval, SearchResult, StatusUpdate, SecretRef, MigrationAnalysis, ConfigSecretsResponse, GetToolCallsResponse, GetToolCallDetailResponse, GetServerToolCallsResponse, GetConfigResponse, ValidateConfigResponse, ConfigApplyResult, ServerTokenMetrics, GetRegistriesResponse, SearchRegistryServersResponse, GetSessionsResponse, GetSessionDetailResponse, InfoResponse, ActivityListResponse, ActivityDetailResponse, ActivitySummaryResponse, ImportResponse, AgentTokenInfo, CreateAgentTokenRequest, CreateAgentTokenResponse, RoutingInfo, ConnectStatusResponse, ConnectResult, OnboardingStateResponse, OnboardingMarkRequest, DiagnosticFixResponse, GlobalToolsResponse } from '@/types' +import type { APIResponse, Server, Tool, ToolApproval, SearchResult, StatusUpdate, SecretRef, MigrationAnalysis, ConfigSecretsResponse, GetToolCallsResponse, GetToolCallDetailResponse, GetServerToolCallsResponse, GetConfigResponse, ValidateConfigResponse, ConfigApplyResult, ServerTokenMetrics, GetRegistriesResponse, SearchRegistryServersResponse, GetSessionsResponse, GetSessionDetailResponse, InfoResponse, ActivityListResponse, ActivityDetailResponse, ActivitySummaryResponse, ImportResponse, AgentTokenInfo, CreateAgentTokenRequest, CreateAgentTokenResponse, RoutingInfo, ConnectStatusResponse, ConnectResult, OnboardingStateResponse, OnboardingMarkRequest, DiagnosticFixResponse, GlobalToolsResponse, UsageQueryParams, UsageAggregateResponse } from '@/types' // Event types for API service export interface APIAuthEvent { @@ -758,6 +758,21 @@ class APIService { return this.request(`/api/v1/activity/summary?period=${period}`) } + // Spec 069 (T017): actor-owned usage aggregate backing the Usage panel. + // Only the supplied params are forwarded; unset filters are omitted so the + // daemon applies its documented defaults (window=24h, sort=resp_bytes, top=20). + async getActivityUsage(params: UsageQueryParams = {}): Promise> { + const searchParams = new URLSearchParams() + if (params.window) searchParams.append('window', params.window) + if (params.server) searchParams.append('server', params.server) + if (params.tool) searchParams.append('tool', params.tool) + if (params.status) searchParams.append('status', params.status) + if (params.top !== undefined) searchParams.append('top', String(params.top)) + if (params.sort) searchParams.append('sort', params.sort) + const qs = searchParams.toString() + return this.request(`/api/v1/activity/usage${qs ? '?' + qs : ''}`) + } + getActivityExportUrl(params: { format: 'json' | 'csv' type?: string diff --git a/frontend/src/types/api.ts b/frontend/src/types/api.ts index 6a341f46..4530d9e6 100644 --- a/frontend/src/types/api.ts +++ b/frontend/src/types/api.ts @@ -631,6 +631,68 @@ export interface ActivitySummaryResponse { end_time: string } +// Usage aggregate types (Spec 069 — GET /api/v1/activity/usage) + +export type UsageWindow = '24h' | '7d' | 'all' +export type UsageSort = 'calls' | 'resp_bytes' | 'error_rate' | 'p95' +export type UsageStatus = 'success' | 'error' | 'blocked' + +export interface UsageQueryParams { + window?: UsageWindow + server?: string + tool?: string + status?: UsageStatus + top?: number + sort?: UsageSort +} + +// Per-(server,tool) rollup row. `avg_resp_bytes`/`avg_req_bytes` are null when +// there are no sized (non-zero-byte) calls. `blocked` counts policy-prevented +// attempts that never executed (excluded from `calls`, latency and bytes). +export interface UsageToolStat { + server: string + tool: string + calls: number + errors: number + error_rate: number + blocked: number + total_resp_bytes: number + avg_resp_bytes: number | null + total_req_bytes: number + avg_req_bytes: number | null + sized_calls: number + p50_ms: number + p95_ms: number + last_used: string +} + +// Present only when the tool list was truncated to `top`. +export interface UsageOtherBucket { + tools_folded: number + calls: number + total_resp_bytes: number +} + +// One timeline bar (executed calls only; blocked attempts excluded). +export interface UsageTimeBucket { + start: string + calls: number + errors: number + total_resp_bytes: number +} + +export interface UsageAggregateResponse { + window: UsageWindow + generated_at: string + freshness_ms: number + token_source: string + tokens_saved: number + tokens_saved_percentage: number + tools: UsageToolStat[] + other?: UsageOtherBucket + timeline: UsageTimeBucket[] +} + // Agent Token types (Spec 028) export interface AgentTokenInfo { diff --git a/frontend/src/views/Dashboard.vue b/frontend/src/views/Dashboard.vue index 379674ed..875595bf 100644 --- a/frontend/src/views/Dashboard.vue +++ b/frontend/src/views/Dashboard.vue @@ -1,5 +1,35 @@