import { defineStore } from 'pinia'; import { useUiStore } from './ui'; interface SubAgent { task_id: string; agent_id?: string | number; status?: string; summary?: string; last_tool?: string; conversation_id?: string; notice_pending?: boolean; display_name?: string; current_context_tokens?: number; } interface SubAgentActivityEntry { id?: string; tool?: string; status?: string; args?: Record; ts?: number; error?: string; } interface SubAgentState { subAgents: SubAgent[]; pollTimer: ReturnType | null; activityTimer: ReturnType | null; activeAgent: SubAgent | null; stoppingTaskIds: Record; activityEntries: SubAgentActivityEntry[]; activityLoading: boolean; activityError: string | null; } const TERMINAL_STATUSES = new Set(['completed', 'failed', 'timeout', 'terminated']); export const useSubAgentStore = defineStore('subAgent', { state: (): SubAgentState => ({ subAgents: [], pollTimer: null, activityTimer: null, activeAgent: null, stoppingTaskIds: {}, activityEntries: [], activityLoading: false, activityError: null }), actions: { async fetchSubAgents() { try { const resp = await fetch('/api/sub_agents'); if (!resp.ok) { throw new Error(await resp.text()); } const data = await resp.json(); if (data.success) { this.subAgents = Array.isArray(data.data) ? data.data : []; const activeTaskId = this.activeAgent?.task_id; if (activeTaskId) { const latest = this.subAgents.find((item) => item.task_id === activeTaskId); if (latest) { this.activeAgent = { ...latest }; } } } } catch (error) { console.error('获取子智能体列表失败:', error); } }, startPolling() { if (this.pollTimer) { return; } const uiStore = useUiStore(); this.pollTimer = setInterval(() => { if (uiStore.panelMode === 'subAgents') { this.fetchSubAgents(); } }, 5000); }, stopPolling() { if (this.pollTimer) { clearInterval(this.pollTimer); this.pollTimer = null; } }, openSubAgent(agent: SubAgent) { if (!agent || !agent.task_id) { return; } this.activeAgent = agent; this.activityEntries = []; this.activityError = null; this.fetchSubAgentActivity(agent.task_id); this.startActivityPolling(); }, closeSubAgent() { this.stopActivityPolling(); this.activeAgent = null; this.activityEntries = []; this.activityError = null; this.activityLoading = false; }, startActivityPolling() { if (this.activityTimer) { return; } this.activityTimer = setInterval(() => { const taskId = this.activeAgent?.task_id; if (taskId) { this.fetchSubAgentActivity(taskId); } }, 2000); }, stopActivityPolling() { if (this.activityTimer) { clearInterval(this.activityTimer); this.activityTimer = null; } }, async fetchSubAgentActivity(taskId: string) { if (!taskId) return; this.activityLoading = true; try { const resp = await fetch(`/api/sub_agents/${taskId}/activity?limit=100000`); if (!resp.ok) { throw new Error(await resp.text()); } const data = await resp.json(); if (data && data.success && data.data) { const entries = Array.isArray(data.data.entries) ? data.data.entries : []; this.activityEntries = entries; if (this.activeAgent && this.activeAgent.task_id === taskId) { this.activeAgent = { ...this.activeAgent, status: data.data.status || this.activeAgent.status }; } const status = (data.data.status || '').toString(); if (TERMINAL_STATUSES.has(status)) { this.stopActivityPolling(); } } } catch (error: any) { this.activityError = error?.message || String(error); console.error('获取子智能体活动失败:', error); } finally { this.activityLoading = false; } }, async terminateSubAgent(taskId: string) { const normalizedId = (taskId || '').toString().trim(); if (!normalizedId) { return { success: false, error: 'task_id 不能为空' }; } this.stoppingTaskIds = { ...this.stoppingTaskIds, [normalizedId]: true }; try { const resp = await fetch(`/api/sub_agents/${encodeURIComponent(normalizedId)}/terminate`, { method: 'POST' }); const data = await resp.json().catch(() => ({})); if (!resp.ok || !data?.success) { throw new Error(data?.error || `HTTP ${resp.status}`); } await this.fetchSubAgents(); if (this.activeAgent?.task_id === normalizedId) { await this.fetchSubAgentActivity(normalizedId); this.activeAgent = { ...this.activeAgent, status: 'terminated' }; } return { success: true, data: data?.data || null }; } catch (error: any) { const message = error?.message || String(error); return { success: false, error: message }; } finally { const next = { ...this.stoppingTaskIds }; delete next[normalizedId]; this.stoppingTaskIds = next; } }, async stopAllAgents(mode: 'terminate' | 'soft_stop'): Promise<{ success: boolean; stoppedCount?: number; error?: string }> { try { const resp = await fetch('/api/sub_agents/stop_all', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ mode }) }); const data = await resp.json().catch(() => ({})); if (!resp.ok || !data?.success) { throw new Error(data?.error || `HTTP ${resp.status}`); } await this.fetchSubAgents(); return { success: true, stoppedCount: data?.data?.stopped_count || 0 }; } catch (error: any) { const message = error?.message || String(error); return { success: false, error: message }; } }, stripConversationPrefix(conversationId: string) { if (!conversationId) return ''; return conversationId.startsWith('conv_') ? conversationId.slice(5) : conversationId; }, getBaseUrl() { const override = (window as any).SUB_AGENT_BASE_URL || (window as any).__SUB_AGENT_BASE_URL__; if (override && typeof override === 'string') { return override.replace(/\/$/, ''); } const { protocol, hostname } = window.location; if (hostname && hostname.includes('agent.')) { const mappedHost = hostname.replace('agent.', 'subagent.'); return `${protocol}//${mappedHost}`; } return `${protocol}//${hostname}:8092`; } } });