Skip to main content

routa_core/rpc/methods/
agents.rs

1//! RPC methods for agent management.
2//!
3//! Methods:
4//! - `agents.list`         — list agents with optional filters
5//! - `agents.get`          — get a single agent by id
6//! - `agents.create`       — create a new agent
7//! - `agents.delete`       — delete an agent
8//! - `agents.updateStatus` — update an agent's status
9
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13use crate::models::agent::{Agent, AgentRole, AgentStatus, ModelTier};
14use crate::rpc::error::RpcError;
15use crate::state::AppState;
16
17// ---------------------------------------------------------------------------
18// agents.list
19// ---------------------------------------------------------------------------
20
21#[derive(Debug, Deserialize)]
22#[serde(rename_all = "camelCase")]
23pub struct ListParams {
24    #[serde(default = "default_workspace_id")]
25    pub workspace_id: String,
26    pub role: Option<String>,
27    pub status: Option<String>,
28    pub parent_id: Option<String>,
29}
30
31fn default_workspace_id() -> String {
32    "default".into()
33}
34
35#[derive(Debug, Serialize)]
36pub struct ListResult {
37    pub agents: Vec<Agent>,
38}
39
40pub async fn list(state: &AppState, params: ListParams) -> Result<ListResult, RpcError> {
41    let agents = if let Some(parent_id) = &params.parent_id {
42        state.agent_store.list_by_parent(parent_id).await?
43    } else if let Some(role_str) = &params.role {
44        let role = AgentRole::from_str(role_str)
45            .ok_or_else(|| RpcError::BadRequest(format!("Invalid role: {role_str}")))?;
46        state
47            .agent_store
48            .list_by_role(&params.workspace_id, &role)
49            .await?
50    } else if let Some(status_str) = &params.status {
51        let status = AgentStatus::from_str(status_str)
52            .ok_or_else(|| RpcError::BadRequest(format!("Invalid status: {status_str}")))?;
53        state
54            .agent_store
55            .list_by_status(&params.workspace_id, &status)
56            .await?
57    } else {
58        state
59            .agent_store
60            .list_by_workspace(&params.workspace_id)
61            .await?
62    };
63
64    Ok(ListResult { agents })
65}
66
67// ---------------------------------------------------------------------------
68// agents.get
69// ---------------------------------------------------------------------------
70
71#[derive(Debug, Deserialize)]
72#[serde(rename_all = "camelCase")]
73pub struct GetParams {
74    pub id: String,
75}
76
77pub async fn get(state: &AppState, params: GetParams) -> Result<Agent, RpcError> {
78    state
79        .agent_store
80        .get(&params.id)
81        .await?
82        .ok_or_else(|| RpcError::NotFound(format!("Agent {} not found", params.id)))
83}
84
85// ---------------------------------------------------------------------------
86// agents.create
87// ---------------------------------------------------------------------------
88
89#[derive(Debug, Deserialize)]
90#[serde(rename_all = "camelCase")]
91pub struct CreateParams {
92    pub name: String,
93    pub role: String,
94    #[serde(default = "default_workspace_id")]
95    pub workspace_id: String,
96    pub parent_id: Option<String>,
97    pub model_tier: Option<String>,
98    pub metadata: Option<HashMap<String, String>>,
99}
100
101#[derive(Debug, Serialize)]
102#[serde(rename_all = "camelCase")]
103pub struct CreateResult {
104    pub agent_id: String,
105    pub agent: Agent,
106}
107
108pub async fn create(state: &AppState, params: CreateParams) -> Result<CreateResult, RpcError> {
109    let role = AgentRole::from_str(&params.role)
110        .ok_or_else(|| RpcError::BadRequest(format!("Invalid role: {}", params.role)))?;
111    let model_tier = params.model_tier.as_deref().and_then(ModelTier::from_str);
112
113    state.workspace_store.ensure_default().await?;
114
115    let agent = Agent::new(
116        uuid::Uuid::new_v4().to_string(),
117        params.name,
118        role,
119        params.workspace_id,
120        params.parent_id,
121        model_tier,
122        params.metadata,
123    );
124
125    state.agent_store.save(&agent).await?;
126
127    Ok(CreateResult {
128        agent_id: agent.id.clone(),
129        agent,
130    })
131}
132
133// ---------------------------------------------------------------------------
134// agents.delete
135// ---------------------------------------------------------------------------
136
137#[derive(Debug, Deserialize)]
138#[serde(rename_all = "camelCase")]
139pub struct DeleteParams {
140    pub id: String,
141}
142
143#[derive(Debug, Serialize)]
144pub struct DeleteResult {
145    pub deleted: bool,
146}
147
148pub async fn delete(state: &AppState, params: DeleteParams) -> Result<DeleteResult, RpcError> {
149    state.agent_store.delete(&params.id).await?;
150    Ok(DeleteResult { deleted: true })
151}
152
153// ---------------------------------------------------------------------------
154// agents.updateStatus
155// ---------------------------------------------------------------------------
156
157#[derive(Debug, Deserialize)]
158#[serde(rename_all = "camelCase")]
159pub struct UpdateStatusParams {
160    pub id: String,
161    pub status: String,
162}
163
164#[derive(Debug, Serialize)]
165pub struct UpdateStatusResult {
166    pub updated: bool,
167}
168
169pub async fn update_status(
170    state: &AppState,
171    params: UpdateStatusParams,
172) -> Result<UpdateStatusResult, RpcError> {
173    let status = AgentStatus::from_str(&params.status)
174        .ok_or_else(|| RpcError::BadRequest(format!("Invalid status: {}", params.status)))?;
175    state.agent_store.update_status(&params.id, &status).await?;
176    Ok(UpdateStatusResult { updated: true })
177}