diff --git a/src/api.js b/src/api.js index 04a9d33..253c078 100644 --- a/src/api.js +++ b/src/api.js @@ -599,4 +599,5 @@ export const sendAgentCommand = (agent, action, params={}) => apiPost('/api/age export const approveAgentTask = (agent, task_id, approved, feedback='') => apiPost('/api/agent-office/approve', { agent, task_id, approved, feedback }); export const getAgentStates = () => apiGet('/api/agent-office/states'); export const getActivityFeed = (limit=50, offset=0) => apiGet(`/api/agent-office/activity?limit=${limit}&offset=${offset}`); +export const getAgentTokenUsage = (id, days=1) => apiGet(`/api/agent-office/agents/${id}/token-usage?days=${days}`); diff --git a/src/pages/agent-office/AgentOffice.css b/src/pages/agent-office/AgentOffice.css index 429ea3a..e8dc4c0 100644 --- a/src/pages/agent-office/AgentOffice.css +++ b/src/pages/agent-office/AgentOffice.css @@ -89,6 +89,18 @@ .ao-col-state--break { background: #4c1d95; color: #c4b5fd; } .ao-col-state--offline { background: #1f1f1f; color: #555; } +.ao-col-tokens { + font-size: 0.7rem; + color: #8b5cf6; + background: rgba(139, 92, 246, 0.12); + padding: 2px 8px; + border-radius: 8px; + margin-left: 6px; + cursor: help; + font-family: 'Courier New', monospace; + white-space: nowrap; +} + .ao-col-badge { background: #f43f5e; color: #fff; diff --git a/src/pages/agent-office/components/AgentColumn.jsx b/src/pages/agent-office/components/AgentColumn.jsx index e988ed7..ad59401 100644 --- a/src/pages/agent-office/components/AgentColumn.jsx +++ b/src/pages/agent-office/components/AgentColumn.jsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { getAgentTasks } from '../../../api'; +import { getAgentTasks, getAgentTokenUsage } from '../../../api'; const STATUS_BADGE = { pending: { label: '대기', bg: '#92400e' }, @@ -26,6 +26,7 @@ const AgentColumn = ({ agentId, meta, agentState, notification, onCommand, onApp const [tasks, setTasks] = useState([]); const [input, setInput] = useState(''); const [activeCommand, setActiveCommand] = useState(null); + const [tokenUsage, setTokenUsage] = useState(null); const state = agentState || { state: 'offline' }; const commands = AGENT_COMMANDS[agentId] || []; @@ -45,6 +46,22 @@ const AgentColumn = ({ agentId, meta, agentState, notification, onCommand, onApp } }, [agentId, state.state, state.detail]); + // 오늘자 AI 토큰 사용량 폴링 (30초 간격 + 작업 완료 시 즉시 갱신) + useEffect(() => { + let cancelled = false; + const fetchUsage = () => { + getAgentTokenUsage(agentId, 1) + .then(d => { if (!cancelled) setTokenUsage(d); }) + .catch(() => {}); + }; + fetchUsage(); + const interval = setInterval(fetchUsage, 30000); + return () => { + cancelled = true; + clearInterval(interval); + }; + }, [agentId, state.state, state.detail]); + const handleQuickAction = (cmd) => { if (cmd.needsInput) { setActiveCommand(cmd.action); @@ -67,6 +84,14 @@ const AgentColumn = ({ agentId, meta, agentState, notification, onCommand, onApp
{meta.name} + {tokenUsage && tokenUsage.total_tokens > 0 && ( + + 🧮 {tokenUsage.total_tokens.toLocaleString()} + + )} {state.state} {notification > 0 && {notification}}