systemprompt_agent/models/
agent.rs1use 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}