Skip to content

Commit 8a20112

Browse files
authored
Merge pull request #292 from syncable-dev/develop
Develop
2 parents abcfe26 + 55a4613 commit 8a20112

20 files changed

Lines changed: 3628 additions & 129 deletions

src/agent/mod.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -757,12 +757,13 @@ pub async fn run_interactive(
757757
.tool(ListHetznerAvailabilityTool::new())
758758
// Deployment tools for service management
759759
.tool(CreateDeploymentConfigTool::new())
760-
.tool(DeployServiceTool::new(project_path_buf.clone()))
760+
.tool(DeployServiceTool::with_context(project_path_buf.clone(), ExecutionContext::InteractiveCli))
761761
.tool(ListDeploymentConfigsTool::new())
762762
.tool(TriggerDeploymentTool::new())
763763
.tool(GetDeploymentStatusTool::new())
764764
.tool(ListDeploymentsTool::new())
765-
.tool(GetServiceLogsTool::new());
765+
.tool(GetServiceLogsTool::new())
766+
.tool(SetDeploymentSecretsTool::with_context(ExecutionContext::InteractiveCli));
766767

767768
// Add tools based on mode
768769
if is_planning {
@@ -875,12 +876,13 @@ pub async fn run_interactive(
875876
.tool(ListHetznerAvailabilityTool::new())
876877
// Deployment tools for service management
877878
.tool(CreateDeploymentConfigTool::new())
878-
.tool(DeployServiceTool::new(project_path_buf.clone()))
879+
.tool(DeployServiceTool::with_context(project_path_buf.clone(), ExecutionContext::InteractiveCli))
879880
.tool(ListDeploymentConfigsTool::new())
880881
.tool(TriggerDeploymentTool::new())
881882
.tool(GetDeploymentStatusTool::new())
882883
.tool(ListDeploymentsTool::new())
883-
.tool(GetServiceLogsTool::new());
884+
.tool(GetServiceLogsTool::new())
885+
.tool(SetDeploymentSecretsTool::with_context(ExecutionContext::InteractiveCli));
884886

885887
// Add tools based on mode
886888
if is_planning {
@@ -984,12 +986,13 @@ pub async fn run_interactive(
984986
.tool(ListHetznerAvailabilityTool::new())
985987
// Deployment tools for service management
986988
.tool(CreateDeploymentConfigTool::new())
987-
.tool(DeployServiceTool::new(project_path_buf.clone()))
989+
.tool(DeployServiceTool::with_context(project_path_buf.clone(), ExecutionContext::InteractiveCli))
988990
.tool(ListDeploymentConfigsTool::new())
989991
.tool(TriggerDeploymentTool::new())
990992
.tool(GetDeploymentStatusTool::new())
991993
.tool(ListDeploymentsTool::new())
992-
.tool(GetServiceLogsTool::new());
994+
.tool(GetServiceLogsTool::new())
995+
.tool(SetDeploymentSecretsTool::with_context(ExecutionContext::InteractiveCli));
993996

994997
// Add tools based on mode
995998
if is_planning {
@@ -2479,12 +2482,13 @@ pub async fn run_query(
24792482
.tool(ListHetznerAvailabilityTool::new())
24802483
// Deployment tools for service management
24812484
.tool(CreateDeploymentConfigTool::new())
2482-
.tool(DeployServiceTool::new(project_path_buf.clone()))
2485+
.tool(DeployServiceTool::with_context(project_path_buf.clone(), ExecutionContext::InteractiveCli))
24832486
.tool(ListDeploymentConfigsTool::new())
24842487
.tool(TriggerDeploymentTool::new())
24852488
.tool(GetDeploymentStatusTool::new())
24862489
.tool(ListDeploymentsTool::new())
2487-
.tool(GetServiceLogsTool::new());
2490+
.tool(GetServiceLogsTool::new())
2491+
.tool(SetDeploymentSecretsTool::with_context(ExecutionContext::InteractiveCli));
24882492

24892493
// Add generation tools if this is a generation query
24902494
if is_generation {
@@ -2565,12 +2569,13 @@ pub async fn run_query(
25652569
.tool(ListHetznerAvailabilityTool::new())
25662570
// Deployment tools for service management
25672571
.tool(CreateDeploymentConfigTool::new())
2568-
.tool(DeployServiceTool::new(project_path_buf.clone()))
2572+
.tool(DeployServiceTool::with_context(project_path_buf.clone(), ExecutionContext::InteractiveCli))
25692573
.tool(ListDeploymentConfigsTool::new())
25702574
.tool(TriggerDeploymentTool::new())
25712575
.tool(GetDeploymentStatusTool::new())
25722576
.tool(ListDeploymentsTool::new())
2573-
.tool(GetServiceLogsTool::new());
2577+
.tool(GetServiceLogsTool::new())
2578+
.tool(SetDeploymentSecretsTool::with_context(ExecutionContext::InteractiveCli));
25742579

25752580
// Add generation tools if this is a generation query
25762581
if is_generation {
@@ -2640,12 +2645,13 @@ pub async fn run_query(
26402645
.tool(ListHetznerAvailabilityTool::new())
26412646
// Deployment tools for service management
26422647
.tool(CreateDeploymentConfigTool::new())
2643-
.tool(DeployServiceTool::new(project_path_buf.clone()))
2648+
.tool(DeployServiceTool::with_context(project_path_buf.clone(), ExecutionContext::InteractiveCli))
26442649
.tool(ListDeploymentConfigsTool::new())
26452650
.tool(TriggerDeploymentTool::new())
26462651
.tool(GetDeploymentStatusTool::new())
26472652
.tool(ListDeploymentsTool::new())
2648-
.tool(GetServiceLogsTool::new());
2653+
.tool(GetServiceLogsTool::new())
2654+
.tool(SetDeploymentSecretsTool::with_context(ExecutionContext::InteractiveCli));
26492655

26502656
// Add generation tools if this is a generation query
26512657
if is_generation {

src/agent/tools/mod.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,21 @@
112112
//!
113113
//! See `response.rs` for the complete response formatting infrastructure.
114114
115+
/// Execution context for tools that behave differently in CLI vs server mode.
116+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117+
pub enum ExecutionContext {
118+
/// Interactive CLI — terminal available, inquire prompts work
119+
InteractiveCli,
120+
/// AG-UI server — no terminal, prompts would hang
121+
HeadlessServer,
122+
}
123+
124+
impl ExecutionContext {
125+
pub fn has_terminal(&self) -> bool {
126+
matches!(self, Self::InteractiveCli)
127+
}
128+
}
129+
115130
mod analyze;
116131
pub mod background;
117132
pub mod compression;
@@ -175,7 +190,8 @@ pub use platform::{
175190
DeployServiceTool, GetDeploymentStatusTool, GetServiceLogsTool,
176191
ListDeploymentCapabilitiesTool, ListDeploymentConfigsTool, ListDeploymentsTool,
177192
ListHetznerAvailabilityTool, ListOrganizationsTool, ListProjectsTool,
178-
OpenProviderSettingsTool, SelectProjectTool, TriggerDeploymentTool,
193+
OpenProviderSettingsTool, SelectProjectTool, SetDeploymentSecretsTool,
194+
TriggerDeploymentTool,
179195
};
180196
pub use prometheus_connect::PrometheusConnectTool;
181197
pub use prometheus_discover::PrometheusDiscoverTool;

src/agent/tools/platform/create_deployment_config.rs

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ use serde::{Deserialize, Serialize};
88
use serde_json::json;
99

1010
use crate::agent::tools::error::{ErrorCategory, format_error_for_llm};
11-
use crate::platform::api::types::CreateDeploymentConfigRequest;
11+
use crate::platform::api::types::{CloudProvider, CloudRunnerConfigInput, CreateDeploymentConfigRequest, build_cloud_runner_config_v2};
1212
use crate::platform::api::{PlatformApiClient, PlatformApiError};
13+
use std::str::FromStr;
1314

1415
/// Arguments for the create deployment config tool
1516
#[derive(Debug, Deserialize)]
@@ -28,7 +29,7 @@ pub struct CreateDeploymentConfigArgs {
2829
pub branch: String,
2930
/// Target type: "kubernetes" or "cloud_runner"
3031
pub target_type: String,
31-
/// Cloud provider: "gcp" or "hetzner"
32+
/// Cloud provider: "gcp", "hetzner", or "azure"
3233
pub provider: String,
3334
/// Environment ID for deployment
3435
pub environment_id: String,
@@ -43,6 +44,16 @@ pub struct CreateDeploymentConfigArgs {
4344
/// Enable auto-deploy on push (defaults to true)
4445
#[serde(default = "default_auto_deploy")]
4546
pub auto_deploy_enabled: bool,
47+
/// CPU allocation (for GCP Cloud Run or Azure Container Apps)
48+
pub cpu: Option<String>,
49+
/// Memory allocation (for GCP Cloud Run or Azure Container Apps)
50+
pub memory: Option<String>,
51+
/// Minimum instances/replicas
52+
pub min_instances: Option<i32>,
53+
/// Maximum instances/replicas
54+
pub max_instances: Option<i32>,
55+
/// Whether the service should be publicly accessible
56+
pub is_public: Option<bool>,
4657
}
4758

4859
fn default_auto_deploy() -> bool {
@@ -84,6 +95,7 @@ A deployment config defines how to build and deploy a service, including:
8495
- Dockerfile location and build context
8596
- Target (Cloud Runner or Kubernetes)
8697
- Port configuration
98+
- CPU/memory allocation (for Cloud Runner deployments)
8799
- Auto-deploy settings
88100
89101
**Required Parameters:**
@@ -94,7 +106,7 @@ A deployment config defines how to build and deploy a service, including:
94106
- port: Port the service listens on
95107
- branch: Git branch to deploy from (e.g., "main")
96108
- target_type: "kubernetes" or "cloud_runner"
97-
- provider: "gcp" or "hetzner"
109+
- provider: "gcp", "hetzner", or "azure"
98110
- environment_id: Environment to deploy to
99111
100112
**Optional Parameters:**
@@ -103,6 +115,11 @@ A deployment config defines how to build and deploy a service, including:
103115
- cluster_id: Required for kubernetes target
104116
- registry_id: Container registry ID (provisions new if not provided)
105117
- auto_deploy_enabled: Enable auto-deploy on push (default: true)
118+
- cpu: CPU allocation (e.g., "1" for GCP Cloud Run, "0.5" for Azure ACA)
119+
- memory: Memory allocation (e.g., "512Mi" for GCP, "1.0Gi" for Azure)
120+
- min_instances: Minimum instances/replicas (default: 0)
121+
- max_instances: Maximum instances/replicas (default: 10)
122+
- is_public: Whether the service should be publicly accessible (default: true)
106123
107124
**Prerequisites:**
108125
- User must be authenticated
@@ -149,7 +166,7 @@ A deployment config defines how to build and deploy a service, including:
149166
},
150167
"provider": {
151168
"type": "string",
152-
"enum": ["gcp", "hetzner"],
169+
"enum": ["gcp", "hetzner", "azure"],
153170
"description": "Cloud provider"
154171
},
155172
"environment_id": {
@@ -175,6 +192,26 @@ A deployment config defines how to build and deploy a service, including:
175192
"auto_deploy_enabled": {
176193
"type": "boolean",
177194
"description": "Enable auto-deploy on push (default: true)"
195+
},
196+
"cpu": {
197+
"type": "string",
198+
"description": "CPU allocation (e.g., '1' for GCP Cloud Run, '0.5' for Azure ACA)"
199+
},
200+
"memory": {
201+
"type": "string",
202+
"description": "Memory allocation (e.g., '512Mi' for GCP, '1.0Gi' for Azure)"
203+
},
204+
"min_instances": {
205+
"type": "integer",
206+
"description": "Minimum instances/replicas (default: 0)"
207+
},
208+
"max_instances": {
209+
"type": "integer",
210+
"description": "Maximum instances/replicas (default: 10)"
211+
},
212+
"is_public": {
213+
"type": "boolean",
214+
"description": "Whether the service should be publicly accessible (default: true)"
178215
}
179216
},
180217
"required": [
@@ -222,20 +259,20 @@ A deployment config defines how to build and deploy a service, including:
222259
args.target_type
223260
),
224261
Some(vec![
225-
"Use 'cloud_runner' for GCP Cloud Run or Hetzner containers",
262+
"Use 'cloud_runner' for GCP Cloud Run, Hetzner containers, or Azure Container Apps",
226263
"Use 'kubernetes' for deploying to a K8s cluster",
227264
]),
228265
));
229266
}
230267

231268
// Validate provider
232-
let valid_providers = ["gcp", "hetzner"];
269+
let valid_providers = ["gcp", "hetzner", "azure"];
233270
if !valid_providers.contains(&args.provider.as_str()) {
234271
return Ok(format_error_for_llm(
235272
"create_deployment_config",
236273
ErrorCategory::ValidationFailed,
237274
&format!(
238-
"Invalid provider '{}'. Must be 'gcp' or 'hetzner'",
275+
"Invalid provider '{}'. Must be 'gcp', 'hetzner', or 'azure'",
239276
args.provider
240277
),
241278
Some(vec![
@@ -266,6 +303,44 @@ A deployment config defines how to build and deploy a service, including:
266303
}
267304
};
268305

306+
// Build cloud runner config if deploying to cloud_runner
307+
let cloud_runner_config = if args.target_type == "cloud_runner" {
308+
let provider_enum = CloudProvider::from_str(&args.provider).ok();
309+
310+
// Fetch provider_account_id from credentials when provider is azure or gcp
311+
let mut gcp_project_id = None;
312+
let mut subscription_id = None;
313+
if let Some(ref provider) = provider_enum {
314+
if matches!(provider, CloudProvider::Gcp | CloudProvider::Azure) {
315+
if let Ok(credential) = client.check_provider_connection(provider, &args.project_id).await {
316+
if let Some(cred) = credential {
317+
match provider {
318+
CloudProvider::Gcp => gcp_project_id = cred.provider_account_id,
319+
CloudProvider::Azure => subscription_id = cred.provider_account_id,
320+
_ => {}
321+
}
322+
}
323+
}
324+
}
325+
}
326+
327+
let config_input = CloudRunnerConfigInput {
328+
provider: provider_enum,
329+
region: None, // Region is set at environment level or by deploy_service
330+
gcp_project_id,
331+
cpu: args.cpu.clone(),
332+
memory: args.memory.clone(),
333+
min_instances: args.min_instances,
334+
max_instances: args.max_instances,
335+
is_public: args.is_public,
336+
subscription_id,
337+
..Default::default()
338+
};
339+
Some(build_cloud_runner_config_v2(&config_input))
340+
} else {
341+
None
342+
};
343+
269344
// Build the request
270345
// Note: Send both field name variants (dockerfile/dockerfilePath, context/buildContext)
271346
// for backend compatibility - different endpoints may expect different field names
@@ -286,8 +361,9 @@ A deployment config defines how to build and deploy a service, including:
286361
cluster_id: args.cluster_id.clone(),
287362
registry_id: args.registry_id.clone(),
288363
auto_deploy_enabled: args.auto_deploy_enabled,
289-
is_public: None,
290-
cloud_runner_config: None,
364+
is_public: args.is_public,
365+
cloud_runner_config,
366+
secrets: None,
291367
};
292368

293369
// Create the deployment config

0 commit comments

Comments
 (0)