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<WebhookDefinition>,
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 #[serde(default, skip_serializing_if = "Option::is_none")]
110 pub public: Option<PublicSurface>,
111}
112
113#[derive(Debug, Clone, Default, Serialize, Deserialize)]
120#[serde(rename_all = "camelCase")]
121pub struct PublicSurface {
122 #[serde(default, skip_serializing_if = "Vec::is_empty")]
126 pub rpcs: Vec<PublicRpc>,
127 #[serde(default, skip_serializing_if = "Vec::is_empty")]
130 pub collections: Vec<PublicCollection>,
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize)]
134#[serde(rename_all = "camelCase")]
135pub struct PublicRpc {
136 pub name: String,
137 #[serde(default, skip_serializing_if = "Vec::is_empty")]
142 pub scope: Vec<String>,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
146#[serde(rename_all = "camelCase")]
147pub struct PublicCollection {
148 pub entity: String,
149 pub actions: Vec<String>,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
154#[serde(rename_all = "camelCase")]
155pub struct CronDefinition {
156 pub name: String,
157 pub schedule: String,
158 #[serde(default, skip_serializing_if = "Option::is_none")]
159 pub timezone: Option<String>,
160 #[serde(default, skip_serializing_if = "Option::is_none")]
161 pub method: Option<String>,
162 #[serde(default, skip_serializing_if = "Option::is_none")]
163 pub payload: Option<JsonValue>,
164 #[serde(default = "default_overlap_policy")]
165 pub overlap_policy: String,
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize)]
169#[serde(rename_all = "camelCase")]
170pub struct WebhookDefinition {
171 pub name: String,
172 pub method: String,
173}
174
175fn default_overlap_policy() -> String { "skip".into() }
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
178#[serde(rename_all = "camelCase")]
179pub struct TriggerConfig {
180 pub app_id: String,
181 pub entity: String,
182 pub on: Vec<String>,
183}
184
185fn default_version() -> String {
186 "0.0.1".to_string()
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize)]
190#[serde(rename_all = "camelCase")]
191pub struct EntityContract {
192 pub entity_name: String,
193 pub fields: Vec<FieldContract>,
194 #[serde(default, skip_serializing_if = "Option::is_none")]
195 pub identity_kind: Option<String>,
196 #[serde(default, skip_serializing_if = "Option::is_none")]
197 pub identity_key: Option<String>,
198}
199
200#[derive(Debug, Clone, Serialize, Deserialize)]
201#[serde(rename_all = "camelCase")]
202pub struct FieldContract {
203 pub name: String,
204 #[serde(rename = "type")]
205 pub field_type: String,
206 #[serde(default)]
207 pub required: bool,
208 #[serde(default)]
209 pub default_value: Option<JsonValue>,
210 #[serde(default)]
211 pub enum_values: Option<Vec<String>>,
212 #[serde(default)]
213 pub references: Option<FieldReference>,
214 #[serde(default)]
215 pub is_primary_key: Option<bool>,
216 #[serde(default, skip_serializing_if = "Option::is_none")]
217 pub on_delete: Option<OnDeletePolicy>,
218}
219
220#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
221#[serde(rename_all = "snake_case")]
222pub enum OnDeletePolicy {
223 Cascade,
224 Restrict,
225 SetNull,
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
229pub struct FieldReference {
230 pub entity: String,
231 pub field: String,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
235#[serde(rename_all = "camelCase")]
236pub struct InstalledApp {
237 pub id: String,
238 pub name: String,
239 pub version: String,
240 pub status: String,
241 #[serde(rename = "type", default)]
242 pub app_type: AppType,
243 pub entities: Vec<String>,
244 #[serde(default)]
245 pub has_frontend: bool,
246 #[serde(default, skip_serializing_if = "Option::is_none")]
247 pub icon: Option<String>,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize)]
251#[serde(rename_all = "camelCase")]
252pub struct PermissionsContract {
253 #[serde(default)]
254 pub permissions: Vec<PermissionDeclaration>,
255}
256
257#[derive(Debug, Clone, Serialize, Deserialize)]
258pub struct PermissionDeclaration {
259 pub key: String,
260 #[serde(default)]
261 pub description: String,
262}
263
264#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct SchemaChange {
266 pub entity: String,
267 pub change_type: String,
268 pub column: String,
269 pub detail: Option<String>,
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize)]
273pub struct SchemaVerification {
274 pub compliant: bool,
275 pub changes: Vec<SchemaChange>,
276}
277
278#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
279#[serde(rename_all = "lowercase")]
280pub enum ProviderType {
281 Anthropic,
282 OpenAI,
283 Bedrock,
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize)]
287#[serde(rename_all = "camelCase")]
288pub struct AgentDefinition {
289 pub name: String,
290 #[serde(default)]
291 pub description: Option<String>,
292 #[serde(default)]
293 pub system_prompt: Option<String>,
294 #[serde(default)]
295 pub memory: Option<AgentMemory>,
296 #[serde(default)]
297 pub limits: Option<AgentLimits>,
298 #[serde(default)]
299 pub supervision: Option<SupervisionConfig>,
300}
301
302#[derive(Debug, Clone, Serialize, Deserialize)]
303pub struct AgentMemory {
304 pub enabled: bool,
305}
306
307#[derive(Debug, Clone, Serialize, Deserialize)]
308#[serde(rename_all = "camelCase")]
309pub struct AgentLimits {
310 #[serde(default)]
311 pub max_turns: Option<u32>,
312 #[serde(default)]
313 pub max_context_tokens: Option<u64>,
314 #[serde(default)]
315 pub keep_recent_messages: Option<u32>,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
319#[serde(rename_all = "camelCase")]
320pub struct SupervisionConfig {
321 pub mode: SupervisionMode,
322 #[serde(default)]
323 pub policies: Vec<SupervisionPolicy>,
324}
325
326#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
327#[serde(rename_all = "lowercase")]
328pub enum SupervisionMode {
329 Autonomous,
330 Supervised,
331 Strict,
332}
333
334#[derive(Debug, Clone, Serialize, Deserialize)]
335#[serde(rename_all = "camelCase")]
336pub struct SupervisionPolicy {
337 pub action: String,
338 #[serde(default)]
339 pub entity: Option<String>,
340 #[serde(default)]
341 pub requires: Option<String>,
342 #[serde(default)]
343 pub rate_limit: Option<RateLimit>,
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct RateLimit {
348 pub max: u32,
349 pub window: String,
350}
351
352#[derive(Debug, Clone, Serialize, Deserialize)]
353#[serde(rename_all = "camelCase")]
354pub struct McpServerConfig {
355 pub name: String,
356 pub transport: McpTransport,
357}
358
359#[derive(Debug, Clone, Serialize, Deserialize)]
360#[serde(tag = "type", rename_all = "lowercase")]
361pub enum McpTransport {
362 Stdio { command: String, #[serde(default)] args: Vec<String> },
363 Http { url: String, #[serde(default)] headers: std::collections::HashMap<String, String> },
364 #[deprecated = "use Http"]
365 Sse { url: String, #[serde(default)] headers: std::collections::HashMap<String, String> },
366 Cli { install: String },
367}
368
369#[derive(Debug, Clone, Serialize, Deserialize)]
370#[serde(rename_all = "camelCase")]
371pub struct ToolDescriptor {
372 pub name: String,
373 pub description: String,
374 pub input_schema: serde_json::Value,
375}
376
377#[derive(Debug, Clone, Serialize, Deserialize)]
378#[serde(rename_all = "lowercase")]
379pub enum Role {
380 User,
381 Assistant,
382}
383
384#[derive(Debug, Clone, Serialize, Deserialize)]
385#[serde(tag = "type", rename_all = "snake_case")]
386pub enum ContentBlock {
387 Text { text: String },
388 ToolUse { id: String, name: String, input: serde_json::Value },
389 ToolResult { tool_use_id: String, content: String, #[serde(default)] is_error: bool },
390}
391
392#[derive(Debug, Clone, Serialize, Deserialize)]
393pub struct ChatMessage {
394 pub role: Role,
395 pub content: Vec<ContentBlock>,
396}
397
398#[derive(Debug, Clone, Serialize, Deserialize)]
399pub struct ToolDef {
400 pub name: String,
401 pub description: String,
402 pub input_schema: serde_json::Value,
403}
404