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}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
107#[serde(rename_all = "camelCase")]
108pub struct CronDefinition {
109 pub name: String,
110 pub schedule: String,
111 #[serde(default, skip_serializing_if = "Option::is_none")]
112 pub timezone: Option<String>,
113 #[serde(default, skip_serializing_if = "Option::is_none")]
114 pub method: Option<String>,
115 #[serde(default, skip_serializing_if = "Option::is_none")]
116 pub payload: Option<JsonValue>,
117 #[serde(default = "default_overlap_policy")]
118 pub overlap_policy: String,
119}
120
121fn default_overlap_policy() -> String { "skip".into() }
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124#[serde(rename_all = "camelCase")]
125pub struct TriggerConfig {
126 pub app_id: String,
127 pub entity: String,
128 pub on: Vec<String>,
129}
130
131fn default_version() -> String {
132 "0.0.1".to_string()
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
136#[serde(rename_all = "camelCase")]
137pub struct EntityContract {
138 pub entity_name: String,
139 pub fields: Vec<FieldContract>,
140 #[serde(default, skip_serializing_if = "Option::is_none")]
141 pub identity_kind: Option<String>,
142 #[serde(default, skip_serializing_if = "Option::is_none")]
143 pub identity_key: Option<String>,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147#[serde(rename_all = "camelCase")]
148pub struct FieldContract {
149 pub name: String,
150 #[serde(rename = "type")]
151 pub field_type: String,
152 #[serde(default)]
153 pub required: bool,
154 #[serde(default)]
155 pub default_value: Option<JsonValue>,
156 #[serde(default)]
157 pub enum_values: Option<Vec<String>>,
158 #[serde(default)]
159 pub references: Option<FieldReference>,
160 #[serde(default)]
161 pub is_primary_key: Option<bool>,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct FieldReference {
166 pub entity: String,
167 pub field: String,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
171#[serde(rename_all = "camelCase")]
172pub struct InstalledApp {
173 pub id: String,
174 pub name: String,
175 pub version: String,
176 pub status: String,
177 #[serde(rename = "type", default)]
178 pub app_type: AppType,
179 pub entities: Vec<String>,
180 #[serde(default)]
181 pub has_frontend: bool,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
185#[serde(rename_all = "camelCase")]
186pub struct PermissionsContract {
187 #[serde(default)]
188 pub permissions: Vec<PermissionDeclaration>,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct PermissionDeclaration {
193 pub key: String,
194 #[serde(default)]
195 pub description: String,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct SchemaChange {
200 pub entity: String,
201 pub change_type: String,
202 pub column: String,
203 pub detail: Option<String>,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct SchemaVerification {
208 pub compliant: bool,
209 pub changes: Vec<SchemaChange>,
210}
211
212#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
213#[serde(rename_all = "lowercase")]
214pub enum ProviderType {
215 Anthropic,
216 OpenAI,
217 Bedrock,
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
221#[serde(rename_all = "camelCase")]
222pub struct AgentDefinition {
223 pub name: String,
224 #[serde(default)]
225 pub description: Option<String>,
226 #[serde(default)]
227 pub system_prompt: Option<String>,
228 #[serde(default)]
229 pub memory: Option<AgentMemory>,
230 #[serde(default)]
231 pub limits: Option<AgentLimits>,
232 #[serde(default)]
233 pub supervision: Option<SupervisionConfig>,
234}
235
236#[derive(Debug, Clone, Serialize, Deserialize)]
237pub struct AgentMemory {
238 pub enabled: bool,
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize)]
242#[serde(rename_all = "camelCase")]
243pub struct AgentLimits {
244 #[serde(default)]
245 pub max_turns: Option<u32>,
246 #[serde(default)]
247 pub max_context_tokens: Option<u64>,
248 #[serde(default)]
249 pub keep_recent_messages: Option<u32>,
250}
251
252#[derive(Debug, Clone, Serialize, Deserialize)]
253#[serde(rename_all = "camelCase")]
254pub struct SupervisionConfig {
255 pub mode: SupervisionMode,
256 #[serde(default)]
257 pub policies: Vec<SupervisionPolicy>,
258}
259
260#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
261#[serde(rename_all = "lowercase")]
262pub enum SupervisionMode {
263 Autonomous,
264 Supervised,
265 Strict,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
269#[serde(rename_all = "camelCase")]
270pub struct SupervisionPolicy {
271 pub action: String,
272 #[serde(default)]
273 pub entity: Option<String>,
274 #[serde(default)]
275 pub requires: Option<String>,
276 #[serde(default)]
277 pub rate_limit: Option<RateLimit>,
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct RateLimit {
282 pub max: u32,
283 pub window: String,
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize)]
287#[serde(rename_all = "camelCase")]
288pub struct McpServerConfig {
289 pub name: String,
290 pub transport: McpTransport,
291}
292
293#[derive(Debug, Clone, Serialize, Deserialize)]
294#[serde(tag = "type", rename_all = "lowercase")]
295pub enum McpTransport {
296 Stdio { command: String, #[serde(default)] args: Vec<String> },
297 Http { url: String, #[serde(default)] headers: std::collections::HashMap<String, String> },
298 #[deprecated = "use Http"]
299 Sse { url: String, #[serde(default)] headers: std::collections::HashMap<String, String> },
300 Cli { install: String },
301}
302
303#[derive(Debug, Clone, Serialize, Deserialize)]
304#[serde(rename_all = "camelCase")]
305pub struct ToolDescriptor {
306 pub name: String,
307 pub description: String,
308 pub input_schema: serde_json::Value,
309}
310
311#[derive(Debug, Clone, Serialize, Deserialize)]
312#[serde(rename_all = "lowercase")]
313pub enum Role {
314 User,
315 Assistant,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
319#[serde(tag = "type", rename_all = "snake_case")]
320pub enum ContentBlock {
321 Text { text: String },
322 ToolUse { id: String, name: String, input: serde_json::Value },
323 ToolResult { tool_use_id: String, content: String, #[serde(default)] is_error: bool },
324}
325
326#[derive(Debug, Clone, Serialize, Deserialize)]
327pub struct ChatMessage {
328 pub role: Role,
329 pub content: Vec<ContentBlock>,
330}
331
332#[derive(Debug, Clone, Serialize, Deserialize)]
333pub struct ToolDef {
334 pub name: String,
335 pub description: String,
336 pub input_schema: serde_json::Value,
337}
338