Phase 5.2+: per-agent usage лимиты на AgentCard
This commit is contained in:
parent
cfa37e1723
commit
98ad890286
3 changed files with 52 additions and 11 deletions
|
|
@ -8,6 +8,12 @@ class Agent(BaseModel):
|
|||
runtime: str = "?"
|
||||
model: str = "?"
|
||||
healthy: bool = True
|
||||
cpu: float = 0
|
||||
active_runs: int = 0
|
||||
tokens_used: int = 0
|
||||
tokens_limit: int = 100000
|
||||
budget_used: float = 0
|
||||
budget_limit: float = 50
|
||||
|
||||
class AgentUpdate(BaseModel):
|
||||
status: Literal["online", "offline", "busy"]
|
||||
|
|
|
|||
|
|
@ -1,20 +1,24 @@
|
|||
import { motion } from 'framer-motion'
|
||||
import { Cpu, Activity, Zap } from 'lucide-react'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Cpu, Activity, Zap, Wallet } from 'lucide-react'
|
||||
import { Progress } from '@/components/ui/progress'
|
||||
|
||||
export function AgentCard({ agent }: { agent: any }) {
|
||||
const statusColor = {
|
||||
online: 'bg-emerald-500',
|
||||
busy: 'bg-amber-500',
|
||||
offline: 'bg-zinc-500',
|
||||
}[agent.status] || 'bg-zinc-500'
|
||||
}[agent.status] || 'bg-emerald-500'
|
||||
|
||||
const tokenPercent = Math.round((agent.tokens_used / agent.tokens_limit) * 100)
|
||||
const budgetPercent = Math.round((agent.budget_used / agent.budget_limit) * 100)
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.02, y: -4 }}
|
||||
className="group bg-card/80 border border-border hover:border-primary/50 rounded-3xl p-6 transition-all duration-300 backdrop-blur-xl"
|
||||
>
|
||||
<div className="flex items-start justify-between">
|
||||
{/* Header */}
|
||||
<div className="flex items-start justify-between mb-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`w-5 h-5 rounded-2xl ${statusColor} flex-shrink-0 ring-4 ring-background`} />
|
||||
<div>
|
||||
|
|
@ -22,10 +26,11 @@ export function AgentCard({ agent }: { agent: any }) {
|
|||
<div className="text-muted-foreground text-sm">{agent.runtime} · {agent.model}</div>
|
||||
</div>
|
||||
</div>
|
||||
<Badge variant="outline">{agent.status}</Badge>
|
||||
<div className="text-xs uppercase tracking-widest text-emerald-500 font-medium">{agent.status}</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 flex gap-8">
|
||||
{/* Main metrics */}
|
||||
<div className="grid grid-cols-2 gap-6 mb-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<Cpu className="w-6 h-6 text-muted-foreground" />
|
||||
<div>
|
||||
|
|
@ -33,16 +38,42 @@ export function AgentCard({ agent }: { agent: any }) {
|
|||
<div className="text-[10px] uppercase tracking-widest text-muted-foreground -mt-1">CPU %</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<Activity className="w-6 h-6 text-muted-foreground" />
|
||||
<div>
|
||||
<div className="text-3xl font-mono font-semibold tabular-nums">{agent.activeRuns}</div>
|
||||
<div className="text-3xl font-mono font-semibold tabular-nums">{agent.active_runs || agent.activeRuns}</div>
|
||||
<div className="text-[10px] uppercase tracking-widest text-muted-foreground -mt-1">RUNS</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Per-agent Usage Limits */}
|
||||
<div className="space-y-4 text-sm border-t border-border pt-5">
|
||||
<div>
|
||||
<div className="flex justify-between mb-1.5">
|
||||
<span className="flex items-center gap-1.5 text-muted-foreground">
|
||||
<Zap className="w-4 h-4" /> Tokens
|
||||
</span>
|
||||
<span className="font-mono text-muted-foreground text-xs">
|
||||
{agent.tokens_used?.toLocaleString()} / {agent.tokens_limit?.toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
<Progress value={tokenPercent} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex justify-between mb-1.5">
|
||||
<span className="flex items-center gap-1.5 text-muted-foreground">
|
||||
<Wallet className="w-4 h-4" /> Budget
|
||||
</span>
|
||||
<span className="font-mono text-muted-foreground text-xs">
|
||||
${agent.budget_used} / ${agent.budget_limit}
|
||||
</span>
|
||||
</div>
|
||||
<Progress value={budgetPercent} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => alert('Handoff started for ' + agent.name)}
|
||||
className="mt-6 w-full bg-indigo-600 hover:bg-indigo-700 text-white py-3 rounded-2xl text-sm font-medium transition-colors flex items-center justify-center gap-2"
|
||||
|
|
|
|||
|
|
@ -10,15 +10,19 @@ export function AgentGrid() {
|
|||
queryFn: async () => {
|
||||
const r = await fetch('/api/v1/agents/health')
|
||||
const raw = await r.json()
|
||||
const mapped = Object.entries(raw).map(([id, info]: [string, any]) => ({
|
||||
const mapped = Object.entries(raw).map(([id, info]: [string, any], i: number) => ({
|
||||
id,
|
||||
name: id.replace('worker-', ''),
|
||||
status: info.healthy ? ('online' as const) : ('busy' as const),
|
||||
runtime: info.model?.split('/')[0] || '?',
|
||||
model: info.model?.split('/').pop() || '?',
|
||||
healthy: info.healthy,
|
||||
cpu: Math.floor(Math.random() * 60 + 10),
|
||||
activeRuns: Math.floor(Math.random() * 5),
|
||||
cpu: [31, 60, 18, 72][i] || 50,
|
||||
activeRuns: [4, 0, 2, 1][i] || 0,
|
||||
tokens_used: [45800, 124800, 22000, 89000][i] || 50000,
|
||||
tokens_limit: 200000,
|
||||
budget_used: [12.4, 42.5, 5.2, 28.0][i] || 20,
|
||||
budget_limit: 100,
|
||||
}))
|
||||
setAgents(mapped)
|
||||
return mapped
|
||||
|
|
|
|||
Loading…
Reference in a new issue