119 lines
2.5 KiB
TypeScript
119 lines
2.5 KiB
TypeScript
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<AgentInfo>("agents.start", {
|
|
story_id: storyId,
|
|
agent_name: agentName,
|
|
});
|
|
},
|
|
|
|
stopAgent(storyId: string, agentName: string) {
|
|
return rpcCall<boolean>("agents.stop", {
|
|
story_id: storyId,
|
|
agent_name: agentName,
|
|
});
|
|
},
|
|
|
|
listAgents(_baseUrl?: string) {
|
|
return rpcCall<AgentInfo[]>("active_agents.list");
|
|
},
|
|
|
|
getAgentConfig(_baseUrl?: string) {
|
|
return rpcCall<AgentConfigInfo[]>("agent_config.list");
|
|
},
|
|
|
|
reloadConfig() {
|
|
return rpcCall<AgentConfigInfo[]>("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();
|
|
};
|
|
}
|