use crate::http::context::{AppContext, OpenApiResult, bad_request}; use poem_openapi::{Object, OpenApi, Tags, payload::Json}; use serde::Serialize; use std::sync::Arc; #[derive(Tags)] enum AgentsTags { Agents, } #[derive(Object)] struct StoryIdPayload { story_id: String, } #[derive(Object, Serialize)] struct AgentInfoResponse { story_id: String, status: String, session_id: Option, worktree_path: Option, } pub struct AgentsApi { pub ctx: Arc, } #[OpenApi(tag = "AgentsTags::Agents")] impl AgentsApi { /// Start an agent for a given story (creates worktree, runs setup, spawns agent). #[oai(path = "/agents/start", method = "post")] async fn start_agent( &self, payload: Json, ) -> OpenApiResult> { let project_root = self .ctx .agents .get_project_root(&self.ctx.state) .map_err(bad_request)?; let info = self .ctx .agents .start_agent(&project_root, &payload.0.story_id) .await .map_err(bad_request)?; Ok(Json(AgentInfoResponse { story_id: info.story_id, status: info.status.to_string(), session_id: info.session_id, worktree_path: info.worktree_path, })) } /// Stop a running agent and clean up its worktree. #[oai(path = "/agents/stop", method = "post")] async fn stop_agent(&self, payload: Json) -> OpenApiResult> { let project_root = self .ctx .agents .get_project_root(&self.ctx.state) .map_err(bad_request)?; self.ctx .agents .stop_agent(&project_root, &payload.0.story_id) .await .map_err(bad_request)?; Ok(Json(true)) } /// List all agents with their status. #[oai(path = "/agents", method = "get")] async fn list_agents(&self) -> OpenApiResult>> { let agents = self.ctx.agents.list_agents().map_err(bad_request)?; Ok(Json( agents .into_iter() .map(|info| AgentInfoResponse { story_id: info.story_id, status: info.status.to_string(), session_id: info.session_id, worktree_path: info.worktree_path, }) .collect(), )) } }