import React, { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useAppContext } from '../context/AppContext'; import { useUI } from '../context/UIContext'; type SubagentTask = { id: string; status?: string; label?: string; role?: string; agent_id?: string; session_key?: string; memory_ns?: string; tool_allowlist?: string[]; max_retries?: number; retry_count?: number; retry_backoff?: number; timeout_sec?: number; max_task_chars?: number; max_result_chars?: number; created?: number; updated?: number; task?: string; result?: string; }; const Subagents: React.FC = () => { const { t } = useTranslation(); const { q } = useAppContext(); const ui = useUI(); const [items, setItems] = useState([]); const [selectedId, setSelectedId] = useState(''); const [spawnTask, setSpawnTask] = useState(''); const [spawnAgentID, setSpawnAgentID] = useState(''); const [spawnRole, setSpawnRole] = useState(''); const [spawnLabel, setSpawnLabel] = useState(''); const [steerMessage, setSteerMessage] = useState(''); const apiPath = '/webui/api/subagents_runtime'; const withAction = (action: string) => `${apiPath}${q}${q ? '&' : '?'}action=${encodeURIComponent(action)}`; const load = async () => { const r = await fetch(withAction('list')); if (!r.ok) throw new Error(await r.text()); const j = await r.json(); const arr = Array.isArray(j?.result?.items) ? j.result.items : []; setItems(arr); if (arr.length === 0) { setSelectedId(''); return; } if (!arr.find((x: SubagentTask) => x.id === selectedId)) { setSelectedId(arr[0].id || ''); } }; useEffect(() => { load().catch(() => {}); }, [q]); const selected = useMemo(() => items.find((x) => x.id === selectedId) || null, [items, selectedId]); const callAction = async (payload: Record) => { const r = await fetch(`${apiPath}${q}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); if (!r.ok) { await ui.notify({ title: t('requestFailed'), message: await r.text() }); return null; } return r.json(); }; const spawn = async () => { if (!spawnTask.trim()) { await ui.notify({ title: t('requestFailed'), message: 'task is required' }); return; } const data = await callAction({ action: 'spawn', task: spawnTask, agent_id: spawnAgentID, role: spawnRole, label: spawnLabel, }); if (!data) return; setSpawnTask(''); await load(); }; const kill = async () => { if (!selected?.id) return; await callAction({ action: 'kill', id: selected.id }); await load(); }; const resume = async () => { if (!selected?.id) return; await callAction({ action: 'resume', id: selected.id }); await load(); }; const steer = async () => { if (!selected?.id || !steerMessage.trim()) return; await callAction({ action: 'steer', id: selected.id, message: steerMessage }); setSteerMessage(''); await load(); }; return (

{t('subagentsRuntime')}

{t('subagentsRuntime')}
{items.map((it) => ( ))} {items.length === 0 &&
No subagents.
}
{t('subagentDetail')}
{!selected &&
{t('selectTask')}
} {selected && ( <>
ID: {selected.id}
Status: {selected.status}
Agent ID: {selected.agent_id || '-'}
Role: {selected.role || '-'}
Session: {selected.session_key || '-'}
Memory NS: {selected.memory_ns || '-'}
Retries: {selected.retry_count || 0}/{selected.max_retries || 0}
Timeout: {selected.timeout_sec || 0}s
Task
{selected.task || '-'}
Result
{selected.result || '-'}
setSteerMessage(e.target.value)} placeholder={t('steerMessage')} className="flex-1 px-2 py-1 text-xs bg-zinc-900 border border-zinc-700 rounded" />
)}
{t('spawnSubagent')}