Skip to main content

rootcx_types/
lib.rs

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}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
59#[serde(rename_all = "camelCase")]
60pub struct ActionDefinition {
61    pub id: String,
62    pub name: String,
63    #[serde(default)]
64    pub description: String,
65    #[serde(default)]
66    pub input_schema: Option<JsonValue>,
67    #[serde(default)]
68    pub output_schema: Option<JsonValue>,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
72#[serde(rename_all = "camelCase")]
73pub struct AppManifest {
74    pub app_id: String,
75    pub name: String,
76    #[serde(default = "default_version")]
77    pub version: String,
78    #[serde(default)]
79    pub description: String,
80    #[serde(default, rename = "type")]
81    pub app_type: AppType,
82    #[serde(default)]
83    pub permissions: Option<PermissionsContract>,
84    #[serde(default)]
85    pub data_contract: Vec<EntityContract>,
86    #[serde(default, skip_serializing_if = "Vec::is_empty")]
87    pub actions: Vec<ActionDefinition>,
88    #[serde(default, skip_serializing_if = "Option::is_none")]
89    pub config_schema: Option<JsonValue>,
90    #[serde(default, skip_serializing_if = "Option::is_none")]
91    pub user_auth: Option<JsonValue>,
92    #[serde(default, skip_serializing_if = "Vec::is_empty")]
93    pub webhooks: Vec<String>,
94    /// Free-form usage instructions surfaced to AI via list_integrations tool
95    #[serde(default, skip_serializing_if = "Option::is_none")]
96    pub instructions: Option<String>,
97}
98
99fn default_version() -> String {
100    "0.0.1".to_string()
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize)]
104#[serde(rename_all = "camelCase")]
105pub struct EntityContract {
106    pub entity_name: String,
107    pub fields: Vec<FieldContract>,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
111#[serde(rename_all = "camelCase")]
112pub struct FieldContract {
113    pub name: String,
114    #[serde(rename = "type")]
115    pub field_type: String,
116    #[serde(default)]
117    pub required: bool,
118    #[serde(default)]
119    pub default_value: Option<JsonValue>,
120    #[serde(default)]
121    pub enum_values: Option<Vec<String>>,
122    #[serde(default)]
123    pub references: Option<FieldReference>,
124    #[serde(default)]
125    pub is_primary_key: Option<bool>,
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct FieldReference {
130    pub entity: String,
131    pub field: String,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct InstalledApp {
136    pub id: String,
137    pub name: String,
138    pub version: String,
139    pub status: String,
140    pub entities: Vec<String>,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
144#[serde(rename_all = "camelCase")]
145pub struct PermissionsContract {
146    #[serde(default)]
147    pub permissions: Vec<PermissionDeclaration>,
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct PermissionDeclaration {
152    pub key: String,
153    #[serde(default)]
154    pub description: String,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
158pub struct SchemaChange {
159    pub entity: String,
160    pub change_type: String,
161    pub column: String,
162    pub detail: Option<String>,
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct SchemaVerification {
167    pub compliant: bool,
168    pub changes: Vec<SchemaChange>,
169}
170
171pub const DEFAULT_MODEL: &str = "claude-sonnet-4-6";
172
173#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
174#[serde(rename_all = "lowercase")]
175pub enum ProviderType {
176    Anthropic,
177    OpenAI,
178    Bedrock,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct AiConfig {
183    pub provider: ProviderType,
184    pub model: String,
185    #[serde(default, skip_serializing_if = "Option::is_none")]
186    pub region: Option<String>,
187}
188
189impl Default for AiConfig {
190    fn default() -> Self {
191        Self { provider: ProviderType::Anthropic, model: DEFAULT_MODEL.into(), region: None }
192    }
193}
194
195impl AiConfig {
196    pub fn forge_model_string(&self) -> String {
197        match self.provider {
198            ProviderType::Bedrock => format!("amazon-bedrock/anthropic.{}", self.model),
199            ProviderType::Anthropic => format!("anthropic/{}", self.model),
200            ProviderType::OpenAI => format!("openai/{}", self.model),
201        }
202    }
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
206#[serde(rename_all = "camelCase")]
207pub struct AgentDefinition {
208    pub name: String,
209    #[serde(default)]
210    pub description: Option<String>,
211    #[serde(default)]
212    pub system_prompt: Option<String>,
213    #[serde(default)]
214    pub memory: Option<AgentMemory>,
215    #[serde(default)]
216    pub limits: Option<AgentLimits>,
217    #[serde(default)]
218    pub supervision: Option<SupervisionConfig>,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct AgentMemory {
223    pub enabled: bool,
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize)]
227#[serde(rename_all = "camelCase")]
228pub struct AgentLimits {
229    #[serde(default)]
230    pub max_turns: Option<u32>,
231    #[serde(default)]
232    pub max_context_tokens: Option<u64>,
233    #[serde(default)]
234    pub keep_recent_messages: Option<u32>,
235}
236
237#[derive(Debug, Clone, Serialize, Deserialize)]
238#[serde(rename_all = "camelCase")]
239pub struct SupervisionConfig {
240    pub mode: SupervisionMode,
241    #[serde(default)]
242    pub policies: Vec<SupervisionPolicy>,
243}
244
245#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
246#[serde(rename_all = "lowercase")]
247pub enum SupervisionMode {
248    Autonomous,
249    Supervised,
250    Strict,
251}
252
253#[derive(Debug, Clone, Serialize, Deserialize)]
254#[serde(rename_all = "camelCase")]
255pub struct SupervisionPolicy {
256    pub action: String,
257    #[serde(default)]
258    pub entity: Option<String>,
259    #[serde(default)]
260    pub requires: Option<String>,
261    #[serde(default)]
262    pub rate_limit: Option<RateLimit>,
263}
264
265#[derive(Debug, Clone, Serialize, Deserialize)]
266pub struct RateLimit {
267    pub max: u32,
268    pub window: String,
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize)]
272#[serde(rename_all = "camelCase")]
273pub struct McpServerConfig {
274    pub name: String,
275    pub transport: McpTransport,
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize)]
279#[serde(tag = "type", rename_all = "lowercase")]
280pub enum McpTransport {
281    Stdio { command: String, #[serde(default)] args: Vec<String> },
282    Sse { url: String, #[serde(default)] headers: std::collections::HashMap<String, String> },
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
286#[serde(rename_all = "camelCase")]
287pub struct ToolDescriptor {
288    pub name: String,
289    pub description: String,
290    pub input_schema: serde_json::Value,
291}
292
293#[derive(Debug, Clone, Serialize, Deserialize)]
294#[serde(rename_all = "lowercase")]
295pub enum Role {
296    User,
297    Assistant,
298}
299
300#[derive(Debug, Clone, Serialize, Deserialize)]
301#[serde(tag = "type", rename_all = "snake_case")]
302pub enum ContentBlock {
303    Text { text: String },
304    ToolUse { id: String, name: String, input: serde_json::Value },
305    ToolResult { tool_use_id: String, content: String, #[serde(default)] is_error: bool },
306}
307
308#[derive(Debug, Clone, Serialize, Deserialize)]
309pub struct ChatMessage {
310    pub role: Role,
311    pub content: Vec<ContentBlock>,
312}
313
314#[derive(Debug, Clone, Serialize, Deserialize)]
315pub struct ToolDef {
316    pub name: String,
317    pub description: String,
318    pub input_schema: serde_json::Value,
319}
320
321impl ProviderType {
322    pub fn secret_key_name(&self) -> &'static str {
323        match self {
324            Self::Anthropic => "ANTHROPIC_API_KEY",
325            Self::OpenAI => "OPENAI_API_KEY",
326            Self::Bedrock => "AWS_BEARER_TOKEN_BEDROCK",
327        }
328    }
329}