import { rpcCall } from "./rpc"; export type AgentStatusValue = "pending" | "running" | "completed" | "failed"; export interface AgentInfo { story_id: string; agent_name: string; status: AgentStatusValue; session_id: string | null; worktree_path: string | null; base_branch: string | null; log_session_id: string | null; } export interface AgentEvent { type: | "status" | "output" | "thinking" | "agent_json" | "done" | "error" | "warning"; story_id?: string; agent_name?: string; status?: string; text?: string; data?: unknown; session_id?: string | null; message?: string; } export interface AgentConfigInfo { name: string; role: string; stage: string | null; model: string | null; allowed_tools: string[] | null; max_turns: number | null; max_budget_usd: number | null; } export const agentsApi = { startAgent(storyId: string, agentName?: string) { return rpcCall("agents.start", { story_id: storyId, agent_name: agentName, }); }, stopAgent(storyId: string, agentName: string) { return rpcCall("agents.stop", { story_id: storyId, agent_name: agentName, }); }, listAgents(_baseUrl?: string) { return rpcCall("active_agents.list"); }, getAgentConfig(_baseUrl?: string) { return rpcCall("agent_config.list"); }, reloadConfig() { return rpcCall("agent_config.list"); }, getAgentOutput(storyId: string, agentName: string, _baseUrl?: string) { return rpcCall<{ output: string }>("agents.get_output", { story_id: storyId, agent_name: agentName, }); }, }; /** * Subscribe to SSE events for a running agent. * Returns a cleanup function to close the connection. */ export function subscribeAgentStream( storyId: string, agentName: string, onEvent: (event: AgentEvent) => void, onError?: (error: Event) => void, ): () => void { const url = `/agents/${encodeURIComponent(storyId)}/${encodeURIComponent(agentName)}/stream`; const eventSource = new EventSource(url); eventSource.onmessage = (e) => { try { const data = JSON.parse(e.data) as AgentEvent; onEvent(data); // Close on terminal events if ( data.type === "done" || data.type === "error" || (data.type === "status" && data.status === "stopped") ) { eventSource.close(); } } catch (err) { console.error("Failed to parse agent event:", err); } }; eventSource.onerror = (e) => { onError?.(e); eventSource.close(); }; return () => { eventSource.close(); }; }