Skip to main content

systemprompt_agent/models/
agent.rs

1use anyhow::{Result, anyhow};
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use systemprompt_database::JsonRow;
5use systemprompt_identifiers::{AgentId, CategoryId, SourceId};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Agent {
9    #[serde(rename = "agent_id")]
10    pub id: AgentId,
11    pub name: String,
12    pub display_name: String,
13    pub description: String,
14    pub version: String,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub system_prompt: Option<String>,
17    pub enabled: bool,
18    pub port: i32,
19    pub endpoint: String,
20    pub dev_only: bool,
21    pub is_primary: bool,
22    pub is_default: bool,
23    pub tags: Vec<String>,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub category_id: Option<CategoryId>,
26    pub source_id: SourceId,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub provider: Option<String>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub model: Option<String>,
31    pub mcp_servers: Vec<String>,
32    pub skills: Vec<String>,
33    pub card_json: serde_json::Value,
34    pub created_at: DateTime<Utc>,
35    pub updated_at: DateTime<Utc>,
36}
37
38impl Agent {
39    pub fn from_json_row(row: &JsonRow) -> Result<Self> {
40        let id = AgentId::new(
41            row.get("agent_id")
42                .and_then(|v| v.as_str())
43                .ok_or_else(|| anyhow!("Missing agent_id"))?,
44        );
45
46        let name = row
47            .get("name")
48            .and_then(|v| v.as_str())
49            .ok_or_else(|| anyhow!("Missing name"))?
50            .to_string();
51
52        let display_name = row
53            .get("display_name")
54            .and_then(|v| v.as_str())
55            .ok_or_else(|| anyhow!("Missing display_name"))?
56            .to_string();
57
58        let description = row
59            .get("description")
60            .and_then(|v| v.as_str())
61            .ok_or_else(|| anyhow!("Missing description"))?
62            .to_string();
63
64        let version = row
65            .get("version")
66            .and_then(|v| v.as_str())
67            .ok_or_else(|| anyhow!("Missing version"))?
68            .to_string();
69
70        let system_prompt = row
71            .get("system_prompt")
72            .and_then(|v| v.as_str())
73            .map(String::from);
74
75        let enabled = row
76            .get("enabled")
77            .and_then(serde_json::Value::as_bool)
78            .ok_or_else(|| anyhow!("Missing enabled"))?;
79
80        let port = row
81            .get("port")
82            .and_then(serde_json::Value::as_i64)
83            .ok_or_else(|| anyhow!("Missing port"))? as i32;
84
85        let endpoint = row
86            .get("endpoint")
87            .and_then(|v| v.as_str())
88            .ok_or_else(|| anyhow!("Missing endpoint"))?
89            .to_string();
90
91        let dev_only = row
92            .get("dev_only")
93            .and_then(serde_json::Value::as_bool)
94            .unwrap_or(false);
95
96        let is_primary = row
97            .get("is_primary")
98            .and_then(serde_json::Value::as_bool)
99            .unwrap_or(false);
100
101        let is_default = row
102            .get("is_default")
103            .and_then(serde_json::Value::as_bool)
104            .unwrap_or(false);
105
106        let tags = row
107            .get("tags")
108            .and_then(|v| v.as_array())
109            .map_or_else(Vec::new, |arr| {
110                arr.iter()
111                    .filter_map(|v| v.as_str().map(String::from))
112                    .collect()
113            });
114
115        let category_id = row
116            .get("category_id")
117            .and_then(|v| v.as_str())
118            .map(CategoryId::new);
119
120        let source_id = SourceId::new(
121            row.get("source_id")
122                .and_then(|v| v.as_str())
123                .ok_or_else(|| anyhow!("Missing source_id"))?,
124        );
125
126        let provider = row
127            .get("provider")
128            .and_then(|v| v.as_str())
129            .map(String::from);
130
131        let model = row.get("model").and_then(|v| v.as_str()).map(String::from);
132
133        let mcp_servers = row
134            .get("mcp_servers")
135            .and_then(|v| v.as_array())
136            .map_or_else(Vec::new, |arr| {
137                arr.iter()
138                    .filter_map(|v| v.as_str().map(String::from))
139                    .collect()
140            });
141
142        let skills = row
143            .get("skills")
144            .and_then(|v| v.as_array())
145            .map_or_else(Vec::new, |arr| {
146                arr.iter()
147                    .filter_map(|v| v.as_str().map(String::from))
148                    .collect()
149            });
150
151        let card_json = row
152            .get("card_json")
153            .cloned()
154            .ok_or_else(|| anyhow!("Missing card_json"))?;
155
156        let created_at = row
157            .get("created_at")
158            .and_then(systemprompt_database::parse_database_datetime)
159            .ok_or_else(|| anyhow!("Missing or invalid created_at"))?;
160
161        let updated_at = row
162            .get("updated_at")
163            .and_then(systemprompt_database::parse_database_datetime)
164            .ok_or_else(|| anyhow!("Missing or invalid updated_at"))?;
165
166        Ok(Self {
167            id,
168            name,
169            display_name,
170            description,
171            version,
172            system_prompt,
173            enabled,
174            port,
175            endpoint,
176            dev_only,
177            is_primary,
178            is_default,
179            tags,
180            category_id,
181            source_id,
182            provider,
183            model,
184            mcp_servers,
185            skills,
186            card_json,
187            created_at,
188            updated_at,
189        })
190    }
191}