1use serde::{Deserialize, Serialize};
2use serde_json::Value as JsonValue;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct OsStatus {
6 pub runtime: RuntimeStatus,
7 pub postgres: PostgresStatus,
8 pub forge: ForgeStatus,
9}
10
11impl OsStatus {
12 pub fn offline() -> Self {
13 Self {
14 runtime: RuntimeStatus { version: String::new(), state: ServiceState::Offline },
15 postgres: PostgresStatus { state: ServiceState::Offline, port: None, data_dir: None },
16 forge: ForgeStatus { state: ServiceState::Offline, port: None },
17 }
18 }
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct ForgeStatus {
23 pub state: ServiceState,
24 pub port: Option<u16>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct RuntimeStatus {
29 pub version: String,
30 pub state: ServiceState,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct PostgresStatus {
35 pub state: ServiceState,
36 pub port: Option<u16>,
37 pub data_dir: Option<String>,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
41#[serde(rename_all = "lowercase")]
42pub enum ServiceState {
43 Online,
44 Offline,
45 Starting,
46 Stopping,
47 Error,
48}
49
50#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
51#[serde(rename_all = "lowercase")]
52pub enum AppType {
53 #[default]
54 App,
55 Integration,
56 Agent,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60#[serde(rename_all = "camelCase")]
61pub struct ActionDefinition {
62 pub id: String,
63 pub name: String,
64 #[serde(default)]
65 pub description: String,
66 #[serde(default)]
67 pub input_schema: Option<JsonValue>,
68 #[serde(default)]
69 pub output_schema: Option<JsonValue>,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize)]
73#[serde(rename_all = "camelCase")]
74pub struct AppManifest {
75 pub app_id: String,
76 pub name: String,
77 #[serde(default = "default_version")]
78 pub version: String,
79 #[serde(default)]
80 pub description: String,
81 #[serde(default, rename = "type")]
82 pub app_type: AppType,
83 #[serde(default)]
84 pub permissions: Option<PermissionsContract>,
85 #[serde(default)]
86 pub data_contract: Vec<EntityContract>,
87 #[serde(default, skip_serializing_if = "Vec::is_empty")]
88 pub actions: Vec<ActionDefinition>,
89 #[serde(default, skip_serializing_if = "Option::is_none")]
90 pub config_schema: Option<JsonValue>,
91 #[serde(default, skip_serializing_if = "Option::is_none")]
92 pub user_auth: Option<JsonValue>,
93 #[serde(default, skip_serializing_if = "Vec::is_empty")]
94 pub webhooks: Vec<String>,
95 #[serde(default, skip_serializing_if = "Option::is_none")]
97 pub instructions: Option<String>,
98 #[serde(default, skip_serializing_if = "Option::is_none")]
100 pub trigger: Option<TriggerConfig>,
101 #[serde(default, skip_serializing_if = "Vec::is_empty")]
103 pub crons: Vec<CronDefinition>,
104 #[serde(default, skip_serializing_if = "Option::is_none")]
105 pub icon: Option<String>,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
109#[serde(rename_all = "camelCase")]
110pub struct CronDefinition {
111 pub name: String,
112 pub schedule: String,
113 #[serde(default, skip_serializing_if = "Option::is_none")]
114 pub timezone: Option<String>,
115 #[serde(default, skip_serializing_if = "Option::is_none")]
116 pub method: Option<String>,
117 #[serde(default, skip_serializing_if = "Option::is_none")]
118 pub payload: Option<JsonValue>,
119 #[serde(default = "default_overlap_policy")]
120 pub overlap_policy: String,
121}
122
123fn default_overlap_policy() -> String { "skip".into() }
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
126#[serde(rename_all = "camelCase")]
127pub struct TriggerConfig {
128 pub app_id: String,
129 pub entity: String,
130 pub on: Vec<String>,
131}
132
133fn default_version() -> String {
134 "0.0.1".to_string()
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
138#[serde(rename_all = "camelCase")]
139pub struct EntityContract {
140 pub entity_name: String,
141 pub fields: Vec<FieldContract>,
142 #[serde(default, skip_serializing_if = "Option::is_none")]
143 pub identity_kind: Option<String>,
144 #[serde(default, skip_serializing_if = "Option::is_none")]
145 pub identity_key: Option<String>,
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
149#[serde(rename_all = "camelCase")]
150pub struct FieldContract {
151 pub name: String,
152 #[serde(rename = "type")]
153 pub field_type: String,
154 #[serde(default)]
155 pub required: bool,
156 #[serde(default)]
157 pub default_value: Option<JsonValue>,
158 #[serde(default)]
159 pub enum_values: Option<Vec<String>>,
160 #[serde(default)]
161 pub references: Option<FieldReference>,
162 #[serde(default)]
163 pub is_primary_key: Option<bool>,
164 #[serde(default, skip_serializing_if = "Option::is_none")]
165 pub on_delete: Option<OnDeletePolicy>,
166}
167
168#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
169#[serde(rename_all = "snake_case")]
170pub enum OnDeletePolicy {
171 Cascade,
172 Restrict,
173 SetNull,
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
177pub struct FieldReference {
178 pub entity: String,
179 pub field: String,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
183#[serde(rename_all = "camelCase")]
184pub struct InstalledApp {
185 pub id: String,
186 pub name: String,
187 pub version: String,
188 pub status: String,
189 #[serde(rename = "type", default)]
190 pub app_type: AppType,
191 pub entities: Vec<String>,
192 #[serde(default)]
193 pub has_frontend: bool,
194 #[serde(default, skip_serializing_if = "Option::is_none")]
195 pub icon: Option<String>,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
199#[serde(rename_all = "camelCase")]
200pub struct PermissionsContract {
201 #[serde(default)]
202 pub permissions: Vec<PermissionDeclaration>,
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
206pub struct PermissionDeclaration {
207 pub key: String,
208 #[serde(default)]
209 pub description: String,
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
213pub struct SchemaChange {
214 pub entity: String,
215 pub change_type: String,
216 pub column: String,
217 pub detail: Option<String>,
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct SchemaVerification {
222 pub compliant: bool,
223 pub changes: Vec<SchemaChange>,
224}
225
226#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
227#[serde(rename_all = "lowercase")]
228pub enum ProviderType {
229 Anthropic,
230 OpenAI,
231 Bedrock,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
235#[serde(rename_all = "camelCase")]
236pub struct AgentDefinition {
237 pub name: String,
238 #[serde(default)]
239 pub description: Option<String>,
240 #[serde(default)]
241 pub system_prompt: Option<String>,
242 #[serde(default)]
243 pub memory: Option<AgentMemory>,
244 #[serde(default)]
245 pub limits: Option<AgentLimits>,
246 #[serde(default)]
247 pub supervision: Option<SupervisionConfig>,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize)]
251pub struct AgentMemory {
252 pub enabled: bool,
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
256#[serde(rename_all = "camelCase")]
257pub struct AgentLimits {
258 #[serde(default)]
259 pub max_turns: Option<u32>,
260 #[serde(default)]
261 pub max_context_tokens: Option<u64>,
262 #[serde(default)]
263 pub keep_recent_messages: Option<u32>,
264}
265
266#[derive(Debug, Clone, Serialize, Deserialize)]
267#[serde(rename_all = "camelCase")]
268pub struct SupervisionConfig {
269 pub mode: SupervisionMode,
270 #[serde(default)]
271 pub policies: Vec<SupervisionPolicy>,
272}
273
274#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
275#[serde(rename_all = "lowercase")]
276pub enum SupervisionMode {
277 Autonomous,
278 Supervised,
279 Strict,
280}
281
282#[derive(Debug, Clone, Serialize, Deserialize)]
283#[serde(rename_all = "camelCase")]
284pub struct SupervisionPolicy {
285 pub action: String,
286 #[serde(default)]
287 pub entity: Option<String>,
288 #[serde(default)]
289 pub requires: Option<String>,
290 #[serde(default)]
291 pub rate_limit: Option<RateLimit>,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct RateLimit {
296 pub max: u32,
297 pub window: String,
298}
299
300#[derive(Debug, Clone, Serialize, Deserialize)]
301#[serde(rename_all = "camelCase")]
302pub struct McpServerConfig {
303 pub name: String,
304 pub transport: McpTransport,
305}
306
307#[derive(Debug, Clone, Serialize, Deserialize)]
308#[serde(tag = "type", rename_all = "lowercase")]
309pub enum McpTransport {
310 Stdio { command: String, #[serde(default)] args: Vec<String> },
311 Http { url: String, #[serde(default)] headers: std::collections::HashMap<String, String> },
312 #[deprecated = "use Http"]
313 Sse { url: String, #[serde(default)] headers: std::collections::HashMap<String, String> },
314 Cli { install: String },
315}
316
317#[derive(Debug, Clone, Serialize, Deserialize)]
318#[serde(rename_all = "camelCase")]
319pub struct ToolDescriptor {
320 pub name: String,
321 pub description: String,
322 pub input_schema: serde_json::Value,
323}
324
325#[derive(Debug, Clone, Serialize, Deserialize)]
326#[serde(rename_all = "lowercase")]
327pub enum Role {
328 User,
329 Assistant,
330}
331
332#[derive(Debug, Clone, Serialize, Deserialize)]
333#[serde(tag = "type", rename_all = "snake_case")]
334pub enum ContentBlock {
335 Text { text: String },
336 ToolUse { id: String, name: String, input: serde_json::Value },
337 ToolResult { tool_use_id: String, content: String, #[serde(default)] is_error: bool },
338}
339
340#[derive(Debug, Clone, Serialize, Deserialize)]
341pub struct ChatMessage {
342 pub role: Role,
343 pub content: Vec<ContentBlock>,
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct ToolDef {
348 pub name: String,
349 pub description: String,
350 pub input_schema: serde_json::Value,
351}
352