Skip to main content

adk_studio/schema/
project.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use uuid::Uuid;
4
5use super::{AgentSchema, ToolConfig, ToolSchema, WorkflowSchema};
6use crate::codegen::action_nodes::ActionNodeConfig;
7
8const DEFAULT_ADK_VERSION: &str = "0.6.0";
9
10/// Complete project schema
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct ProjectSchema {
13    pub id: Uuid,
14    pub version: String,
15    pub name: String,
16    #[serde(default)]
17    pub description: String,
18    #[serde(default)]
19    pub settings: ProjectSettings,
20    #[serde(default)]
21    pub agents: HashMap<String, AgentSchema>,
22    #[serde(default)]
23    pub tools: HashMap<String, ToolSchema>,
24    #[serde(default)]
25    pub tool_configs: HashMap<String, ToolConfig>,
26    /// Action nodes for non-LLM programmatic operations (v2.0)
27    #[serde(default, rename = "actionNodes")]
28    pub action_nodes: HashMap<String, ActionNodeConfig>,
29    #[serde(default)]
30    pub workflow: WorkflowSchema,
31    #[serde(default)]
32    pub created_at: chrono::DateTime<chrono::Utc>,
33    #[serde(default)]
34    pub updated_at: chrono::DateTime<chrono::Utc>,
35}
36
37impl ProjectSchema {
38    pub fn new(name: impl Into<String>) -> Self {
39        let now = chrono::Utc::now();
40        Self {
41            id: Uuid::new_v4(),
42            version: "1.0".to_string(),
43            name: name.into(),
44            description: String::new(),
45            settings: ProjectSettings::default(),
46            agents: HashMap::new(),
47            tools: HashMap::new(),
48            tool_configs: HashMap::new(),
49            action_nodes: HashMap::new(),
50            workflow: WorkflowSchema::default(),
51            created_at: now,
52            updated_at: now,
53        }
54    }
55}
56
57/// Project-level settings
58#[derive(Debug, Clone, Serialize, Deserialize)]
59#[serde(rename_all = "camelCase")]
60pub struct ProjectSettings {
61    #[serde(default = "default_model")]
62    pub default_model: String,
63    #[serde(default)]
64    pub env_vars: HashMap<String, String>,
65    // Layout settings (v2.0)
66    #[serde(default)]
67    pub layout_mode: Option<String>,
68    #[serde(default = "default_layout_direction")]
69    pub layout_direction: Option<String>,
70    #[serde(default)]
71    pub show_data_flow_overlay: Option<bool>,
72    // Code generation settings
73    #[serde(default = "default_adk_version")]
74    pub adk_version: Option<String>,
75    #[serde(default = "default_rust_edition")]
76    pub rust_edition: Option<String>,
77    // Default provider
78    #[serde(default)]
79    pub default_provider: Option<String>,
80    // Build settings
81    #[serde(default = "default_true")]
82    pub autobuild_enabled: Option<bool>,
83    #[serde(default)]
84    pub autobuild_triggers: Option<AutobuildTriggers>,
85    // UI preferences
86    #[serde(default)]
87    pub show_minimap: Option<bool>,
88    #[serde(default)]
89    pub show_timeline: Option<bool>,
90    #[serde(default)]
91    pub console_position: Option<String>,
92    // Debug mode (v2.0) - controls visibility of StateInspector and Timeline
93    #[serde(default)]
94    pub debug_mode: Option<bool>,
95}
96
97impl Default for ProjectSettings {
98    fn default() -> Self {
99        Self {
100            default_model: default_model(),
101            env_vars: HashMap::new(),
102            layout_mode: None,
103            layout_direction: default_layout_direction(),
104            show_data_flow_overlay: None,
105            adk_version: default_adk_version(),
106            rust_edition: default_rust_edition(),
107            default_provider: None,
108            autobuild_enabled: default_true(),
109            autobuild_triggers: None,
110            show_minimap: None,
111            show_timeline: None,
112            console_position: None,
113            debug_mode: None,
114        }
115    }
116}
117
118/// Autobuild trigger configuration
119#[derive(Debug, Clone, Serialize, Deserialize, Default)]
120#[serde(rename_all = "camelCase")]
121pub struct AutobuildTriggers {
122    #[serde(default = "default_true")]
123    pub on_agent_add: Option<bool>,
124    #[serde(default = "default_true")]
125    pub on_agent_delete: Option<bool>,
126    #[serde(default = "default_true")]
127    pub on_agent_update: Option<bool>,
128    #[serde(default = "default_true")]
129    pub on_tool_add: Option<bool>,
130    #[serde(default = "default_true")]
131    pub on_tool_update: Option<bool>,
132    #[serde(default = "default_true")]
133    pub on_edge_add: Option<bool>,
134    #[serde(default = "default_true")]
135    pub on_edge_delete: Option<bool>,
136}
137
138fn default_model() -> String {
139    "gemini-3.1-flash-lite-preview".to_string()
140}
141
142fn default_adk_version() -> Option<String> {
143    Some(DEFAULT_ADK_VERSION.to_string())
144}
145
146fn default_rust_edition() -> Option<String> {
147    Some("2024".to_string())
148}
149
150fn default_layout_direction() -> Option<String> {
151    Some("LR".to_string())
152}
153
154fn default_true() -> Option<bool> {
155    Some(true)
156}
157
158/// Project metadata for listing
159#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct ProjectMeta {
161    pub id: Uuid,
162    pub name: String,
163    pub description: String,
164    pub updated_at: chrono::DateTime<chrono::Utc>,
165}
166
167impl From<&ProjectSchema> for ProjectMeta {
168    fn from(p: &ProjectSchema) -> Self {
169        Self {
170            id: p.id,
171            name: p.name.clone(),
172            description: p.description.clone(),
173            updated_at: p.updated_at,
174        }
175    }
176}