mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
style: apply pinned rustfmt
This commit is contained in:
parent
53efde3930
commit
cfa8ae92c0
13 changed files with 526 additions and 571 deletions
|
|
@ -12,9 +12,8 @@ use fabro_model::{Catalog, ProviderId};
|
|||
use fabro_redact::redact_string;
|
||||
use fabro_sandbox::{DockerSandboxProvider, daytona};
|
||||
use fabro_static::EnvVars;
|
||||
use fabro_types::settings::SearchProvider;
|
||||
use fabro_types::settings::ServerAuthMethod;
|
||||
use fabro_types::settings::server::GithubIntegrationStrategy;
|
||||
use fabro_types::settings::{SearchProvider, ServerAuthMethod};
|
||||
use fabro_util::check_report::{CheckDetail, CheckResult, CheckSection, CheckStatus};
|
||||
use fabro_util::dev_token::validate_dev_token_format;
|
||||
use fabro_util::session_secret;
|
||||
|
|
@ -44,21 +43,21 @@ fn http_client_or_check(
|
|||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct DiagnosticsReport {
|
||||
pub version: String,
|
||||
pub version: String,
|
||||
pub sections: Vec<CheckSection>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub(crate) struct ProviderProbeReport {
|
||||
pub data: Vec<ProviderProbeResult>,
|
||||
pub data: Vec<ProviderProbeResult>,
|
||||
pub summary: ProviderProbeSummary,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub(crate) struct ProviderProbeResult {
|
||||
pub provider: ProviderId,
|
||||
pub model_id: Option<String>,
|
||||
pub status: ProviderProbeStatus,
|
||||
pub provider: ProviderId,
|
||||
pub model_id: Option<String>,
|
||||
pub status: ProviderProbeStatus,
|
||||
pub error_message: Option<String>,
|
||||
#[serde(skip)]
|
||||
diagnostic_detail: Option<String>,
|
||||
|
|
@ -67,7 +66,7 @@ pub(crate) struct ProviderProbeResult {
|
|||
#[derive(Debug, Clone, Serialize)]
|
||||
pub(crate) struct ProviderProbeSummary {
|
||||
pub status: ProviderProbeStatus,
|
||||
pub total: u32,
|
||||
pub total: u32,
|
||||
pub passed: u32,
|
||||
pub failed: u32,
|
||||
}
|
||||
|
|
@ -105,14 +104,14 @@ pub async fn run_all(state: &AppState) -> DiagnosticsReport {
|
|||
);
|
||||
|
||||
DiagnosticsReport {
|
||||
version: FABRO_VERSION.to_string(),
|
||||
version: FABRO_VERSION.to_string(),
|
||||
sections: vec![
|
||||
CheckSection {
|
||||
title: "Credentials".to_string(),
|
||||
title: "Credentials".to_string(),
|
||||
checks: vec![llm, github, docker_sandbox, cloud_sandbox, web_search],
|
||||
},
|
||||
CheckSection {
|
||||
title: "Configuration".to_string(),
|
||||
title: "Configuration".to_string(),
|
||||
checks: vec![crypto, check_storage_dir(state)],
|
||||
},
|
||||
],
|
||||
|
|
@ -124,20 +123,20 @@ async fn check_llm_providers(state: &AppState) -> CheckResult {
|
|||
Ok(report) => report,
|
||||
Err(err) => {
|
||||
return CheckResult {
|
||||
name: "LLM Providers".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "failed to initialize".to_string(),
|
||||
details: vec![CheckDetail::new(format!("{err:#}"))],
|
||||
name: "LLM Providers".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "failed to initialize".to_string(),
|
||||
details: vec![CheckDetail::new(format!("{err:#}"))],
|
||||
remediation: Some("Check configured provider credentials".to_string()),
|
||||
};
|
||||
}
|
||||
};
|
||||
if report.data.is_empty() {
|
||||
return CheckResult {
|
||||
name: "LLM Providers".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "none configured".to_string(),
|
||||
details: Vec::new(),
|
||||
name: "LLM Providers".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "none configured".to_string(),
|
||||
details: Vec::new(),
|
||||
remediation: Some("Set at least one provider API key".to_string()),
|
||||
};
|
||||
}
|
||||
|
|
@ -159,7 +158,7 @@ async fn check_llm_providers(state: &AppState) -> CheckResult {
|
|||
.clone()
|
||||
.unwrap_or_else(|| format!("{}: {message}", result.provider));
|
||||
failures.push(ProviderFailure {
|
||||
provider: result.provider.to_string(),
|
||||
provider: result.provider.to_string(),
|
||||
summary_line: short_error_line(message),
|
||||
});
|
||||
details.push(CheckDetail::new(detail));
|
||||
|
|
@ -198,7 +197,7 @@ async fn check_llm_providers(state: &AppState) -> CheckResult {
|
|||
}
|
||||
|
||||
struct ProviderFailure {
|
||||
provider: String,
|
||||
provider: String,
|
||||
summary_line: String,
|
||||
}
|
||||
|
||||
|
|
@ -355,10 +354,10 @@ async fn check_github_app(state: &AppState) -> CheckResult {
|
|||
Ok(token) => token.to_string(),
|
||||
Err(err) => {
|
||||
return CheckResult {
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "token expired".to_string(),
|
||||
details: vec![CheckDetail::new(err.to_string())],
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "token expired".to_string(),
|
||||
details: vec![CheckDetail::new(err.to_string())],
|
||||
remediation: Some(
|
||||
"Run fabro install or run `fabro secret set GITHUB_TOKEN`"
|
||||
.to_string(),
|
||||
|
|
@ -370,10 +369,10 @@ async fn check_github_app(state: &AppState) -> CheckResult {
|
|||
Ok(Some(_)) => unreachable!("token strategy should not return app credentials"),
|
||||
Ok(None) => {
|
||||
return CheckResult {
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
remediation: Some(
|
||||
"Run fabro install or run `fabro secret set GITHUB_TOKEN`".to_string(),
|
||||
),
|
||||
|
|
@ -382,10 +381,10 @@ async fn check_github_app(state: &AppState) -> CheckResult {
|
|||
Err(err) => {
|
||||
let rendered = format!("{err:#}");
|
||||
return CheckResult {
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "missing token".to_string(),
|
||||
details: vec![CheckDetail::new(rendered.clone())],
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "missing token".to_string(),
|
||||
details: vec![CheckDetail::new(rendered.clone())],
|
||||
remediation: Some(rendered),
|
||||
};
|
||||
}
|
||||
|
|
@ -407,18 +406,18 @@ async fn check_github_app(state: &AppState) -> CheckResult {
|
|||
|
||||
return match probe {
|
||||
Ok(Ok(response)) if response.status().is_success() => CheckResult {
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Pass,
|
||||
summary: "configured".to_string(),
|
||||
details: Vec::new(),
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Pass,
|
||||
summary: "configured".to_string(),
|
||||
details: Vec::new(),
|
||||
remediation: None,
|
||||
},
|
||||
Ok(Ok(response)) if response.status() == fabro_http::StatusCode::UNAUTHORIZED => {
|
||||
CheckResult {
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "token invalid".to_string(),
|
||||
details: vec![CheckDetail::new(format!(
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "token invalid".to_string(),
|
||||
details: vec![CheckDetail::new(format!(
|
||||
"GitHub returned {}",
|
||||
response.status()
|
||||
))],
|
||||
|
|
@ -428,10 +427,10 @@ async fn check_github_app(state: &AppState) -> CheckResult {
|
|||
}
|
||||
}
|
||||
Ok(Ok(response)) => CheckResult {
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "connectivity error".to_string(),
|
||||
details: vec![CheckDetail::new(format!(
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "connectivity error".to_string(),
|
||||
details: vec![CheckDetail::new(format!(
|
||||
"GitHub returned {}",
|
||||
response.status()
|
||||
))],
|
||||
|
|
@ -440,19 +439,19 @@ async fn check_github_app(state: &AppState) -> CheckResult {
|
|||
),
|
||||
},
|
||||
Ok(Err(err)) => CheckResult {
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "connectivity error".to_string(),
|
||||
details: vec![CheckDetail::new(err.to_string())],
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "connectivity error".to_string(),
|
||||
details: vec![CheckDetail::new(err.to_string())],
|
||||
remediation: Some(
|
||||
"Check GitHub connectivity and the vault GITHUB_TOKEN".to_string(),
|
||||
),
|
||||
},
|
||||
Err(_) => CheckResult {
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "timeout".to_string(),
|
||||
details: vec![CheckDetail::new("GitHub probe timed out".to_string())],
|
||||
name: "GitHub Token".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "timeout".to_string(),
|
||||
details: vec![CheckDetail::new("GitHub probe timed out".to_string())],
|
||||
remediation: Some(
|
||||
"Check GitHub connectivity and the vault GITHUB_TOKEN".to_string(),
|
||||
),
|
||||
|
|
@ -486,20 +485,20 @@ async fn check_github_app(state: &AppState) -> CheckResult {
|
|||
&& !webhook_secret
|
||||
{
|
||||
return CheckResult {
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
remediation: Some("Configure GitHub App settings and secrets".to_string()),
|
||||
};
|
||||
}
|
||||
|
||||
let Some(app_id) = app_id else {
|
||||
return CheckResult {
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "missing app_id".to_string(),
|
||||
details: Vec::new(),
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "missing app_id".to_string(),
|
||||
details: Vec::new(),
|
||||
remediation: Some(
|
||||
"Set [server.integrations.github].app_id in settings.toml".to_string(),
|
||||
),
|
||||
|
|
@ -507,10 +506,10 @@ async fn check_github_app(state: &AppState) -> CheckResult {
|
|||
};
|
||||
let Some(private_key_raw) = private_key_raw else {
|
||||
return CheckResult {
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "missing private key".to_string(),
|
||||
details: Vec::new(),
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "missing private key".to_string(),
|
||||
details: Vec::new(),
|
||||
remediation: Some("Run `fabro secret set GITHUB_APP_PRIVATE_KEY`".to_string()),
|
||||
};
|
||||
};
|
||||
|
|
@ -519,10 +518,10 @@ async fn check_github_app(state: &AppState) -> CheckResult {
|
|||
Ok(value) => value,
|
||||
Err(err) => {
|
||||
return CheckResult {
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "private key invalid".to_string(),
|
||||
details: vec![CheckDetail::new(err.clone())],
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "private key invalid".to_string(),
|
||||
details: vec![CheckDetail::new(err.clone())],
|
||||
remediation: Some(err),
|
||||
};
|
||||
}
|
||||
|
|
@ -532,10 +531,10 @@ async fn check_github_app(state: &AppState) -> CheckResult {
|
|||
Ok(jwt) => jwt,
|
||||
Err(err) => {
|
||||
return CheckResult {
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "JWT signing failed".to_string(),
|
||||
details: vec![CheckDetail::new(format!("{err:#}"))],
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "JWT signing failed".to_string(),
|
||||
details: vec![CheckDetail::new(format!("{err:#}"))],
|
||||
remediation: Some(err.to_string()),
|
||||
};
|
||||
}
|
||||
|
|
@ -552,24 +551,24 @@ async fn check_github_app(state: &AppState) -> CheckResult {
|
|||
.await;
|
||||
match auth_result {
|
||||
Ok(Ok(_app)) => CheckResult {
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Pass,
|
||||
summary: slug.unwrap_or_else(|| "configured".to_string()),
|
||||
details: Vec::new(),
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Pass,
|
||||
summary: slug.unwrap_or_else(|| "configured".to_string()),
|
||||
details: Vec::new(),
|
||||
remediation: None,
|
||||
},
|
||||
Ok(Err(err)) => CheckResult {
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "connectivity error".to_string(),
|
||||
details: vec![CheckDetail::new(format!("{err:#}"))],
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "connectivity error".to_string(),
|
||||
details: vec![CheckDetail::new(format!("{err:#}"))],
|
||||
remediation: Some("Check GitHub App credentials and network connectivity".to_string()),
|
||||
},
|
||||
Err(_) => CheckResult {
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "timeout".to_string(),
|
||||
details: vec![CheckDetail::new("GitHub probe timed out".to_string())],
|
||||
name: "GitHub App".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "timeout".to_string(),
|
||||
details: vec![CheckDetail::new("GitHub probe timed out".to_string())],
|
||||
remediation: Some("Check GitHub connectivity and credentials".to_string()),
|
||||
},
|
||||
}
|
||||
|
|
@ -605,10 +604,10 @@ where
|
|||
{
|
||||
if !enabled {
|
||||
return CheckResult {
|
||||
name: "Docker Sandbox".to_string(),
|
||||
status: CheckStatus::Pass,
|
||||
summary: "disabled".to_string(),
|
||||
details: vec![CheckDetail::new(
|
||||
name: "Docker Sandbox".to_string(),
|
||||
status: CheckStatus::Pass,
|
||||
summary: "disabled".to_string(),
|
||||
details: vec![CheckDetail::new(
|
||||
"server.sandbox.providers.docker.enabled = false".to_string(),
|
||||
)],
|
||||
remediation: None,
|
||||
|
|
@ -653,10 +652,10 @@ async fn check_cloud_sandbox(state: &AppState) -> CheckResult {
|
|||
};
|
||||
let Some(api_key) = api_key else {
|
||||
return CheckResult {
|
||||
name: "Cloud Sandbox".to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "recommended, not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
name: "Cloud Sandbox".to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "recommended, not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
remediation: Some(
|
||||
"Run `fabro secret set DAYTONA_API_KEY` to enable cloud sandbox execution"
|
||||
.to_string(),
|
||||
|
|
@ -673,17 +672,17 @@ async fn check_cloud_sandbox(state: &AppState) -> CheckResult {
|
|||
fn cloud_sandbox_probe_check(probe: anyhow::Result<daytona::DaytonaKeyCheck>) -> CheckResult {
|
||||
match probe {
|
||||
Ok(check) if check.ok() => CheckResult {
|
||||
name: "Cloud Sandbox".to_string(),
|
||||
status: CheckStatus::Pass,
|
||||
summary: format!("Daytona configured ({})", check.key_name),
|
||||
details: Vec::new(),
|
||||
name: "Cloud Sandbox".to_string(),
|
||||
status: CheckStatus::Pass,
|
||||
summary: format!("Daytona configured ({})", check.key_name),
|
||||
details: Vec::new(),
|
||||
remediation: None,
|
||||
},
|
||||
Ok(check) => CheckResult {
|
||||
name: "Cloud Sandbox".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "Daytona API key is missing required scopes".to_string(),
|
||||
details: vec![CheckDetail::new(format!(
|
||||
name: "Cloud Sandbox".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "Daytona API key is missing required scopes".to_string(),
|
||||
details: vec![CheckDetail::new(format!(
|
||||
"missing: {}",
|
||||
check.missing_display()
|
||||
))],
|
||||
|
|
@ -696,10 +695,10 @@ fn cloud_sandbox_probe_check(probe: anyhow::Result<daytona::DaytonaKeyCheck>) ->
|
|||
Err(err) => {
|
||||
if let Some(timeout) = err.downcast_ref::<daytona::DaytonaCredentialProbeTimeout>() {
|
||||
return CheckResult {
|
||||
name: "Cloud Sandbox".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: format!("timeout ({:?})", timeout.timeout()),
|
||||
details: vec![CheckDetail::new("Daytona probe timed out".to_string())],
|
||||
name: "Cloud Sandbox".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: format!("timeout ({:?})", timeout.timeout()),
|
||||
details: vec![CheckDetail::new("Daytona probe timed out".to_string())],
|
||||
remediation: Some(
|
||||
"Verify DAYTONA_API_KEY value and Daytona reachability".to_string(),
|
||||
),
|
||||
|
|
@ -707,10 +706,10 @@ fn cloud_sandbox_probe_check(probe: anyhow::Result<daytona::DaytonaKeyCheck>) ->
|
|||
}
|
||||
|
||||
CheckResult {
|
||||
name: "Cloud Sandbox".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "Daytona credential rejected".to_string(),
|
||||
details: vec![CheckDetail::new(format!("{err:#}"))],
|
||||
name: "Cloud Sandbox".to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "Daytona credential rejected".to_string(),
|
||||
details: vec![CheckDetail::new(format!("{err:#}"))],
|
||||
remediation: Some(
|
||||
"Verify DAYTONA_API_KEY value and Daytona reachability".to_string(),
|
||||
),
|
||||
|
|
@ -781,10 +780,10 @@ async fn check_brave_search(state: &AppState) -> CheckResult {
|
|||
};
|
||||
let Some(api_key) = api_key else {
|
||||
return CheckResult {
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "brave: optional, not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "brave: optional, not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
remediation: Some(
|
||||
"Run `fabro secret set BRAVE_SEARCH_API_KEY` to enable web search".to_string(),
|
||||
),
|
||||
|
|
@ -816,10 +815,10 @@ async fn check_venice_search(state: &AppState) -> CheckResult {
|
|||
};
|
||||
let Some(api_key) = api_key else {
|
||||
return CheckResult {
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "venice: optional, not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "venice: optional, not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
remediation: Some(
|
||||
"Run `fabro secret set VENICE_API_KEY` to enable web search".to_string(),
|
||||
),
|
||||
|
|
@ -851,31 +850,31 @@ fn match_web_search_probe(
|
|||
) -> CheckResult {
|
||||
match probe {
|
||||
Ok(Ok(response)) if response.status().is_success() => CheckResult {
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Pass,
|
||||
summary: format!("{provider}: configured and reachable"),
|
||||
details: Vec::new(),
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Pass,
|
||||
summary: format!("{provider}: configured and reachable"),
|
||||
details: Vec::new(),
|
||||
remediation: None,
|
||||
},
|
||||
Ok(Ok(response)) => CheckResult {
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: format!("{provider}: HTTP {}", response.status()),
|
||||
details: Vec::new(),
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: format!("{provider}: HTTP {}", response.status()),
|
||||
details: Vec::new(),
|
||||
remediation: Some(format!("Check {secret_name} and network connectivity")),
|
||||
},
|
||||
Ok(Err(err)) => CheckResult {
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: format!("{provider}: connectivity error"),
|
||||
details: vec![CheckDetail::new(format!("{err:#}"))],
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: format!("{provider}: connectivity error"),
|
||||
details: vec![CheckDetail::new(format!("{err:#}"))],
|
||||
remediation: Some(format!("Check {secret_name} and network connectivity")),
|
||||
},
|
||||
Err(_) => CheckResult {
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: format!("{provider}: timeout"),
|
||||
details: vec![CheckDetail::new(format!(
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: format!("{provider}: timeout"),
|
||||
details: vec![CheckDetail::new(format!(
|
||||
"Web Search ({provider}) probe timed out"
|
||||
))],
|
||||
remediation: Some(format!("Check {secret_name} and network connectivity")),
|
||||
|
|
@ -956,10 +955,10 @@ async fn diagnostic_secret(
|
|||
name: &str,
|
||||
) -> Result<Option<String>, CheckResult> {
|
||||
state.vault_secret(name).await.map_err(|err| CheckResult {
|
||||
name: check_name.to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "secret store unavailable".to_string(),
|
||||
details: vec![CheckDetail::new(err.to_string())],
|
||||
name: check_name.to_string(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "secret store unavailable".to_string(),
|
||||
details: vec![CheckDetail::new(err.to_string())],
|
||||
remediation: Some("Check the Fabro database and retry".to_string()),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ use crate::{
|
|||
fn cli_tool_secrets() -> ToolSecrets {
|
||||
ToolSecrets {
|
||||
brave_search_api_key: std::env::var(EnvVars::BRAVE_SEARCH_API_KEY).ok(),
|
||||
venice_api_key: std::env::var(EnvVars::VENICE_API_KEY).ok(),
|
||||
search: search_settings_from_disk(),
|
||||
venice_api_key: std::env::var(EnvVars::VENICE_API_KEY).ok(),
|
||||
search: search_settings_from_disk(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,8 +104,8 @@ impl ToolHookCallback for ToolApprovalAdapter {
|
|||
#[derive(Clone, Default, PartialEq, Eq)]
|
||||
pub struct ToolSecrets {
|
||||
pub brave_search_api_key: Option<String>,
|
||||
pub venice_api_key: Option<String>,
|
||||
pub search: SearchIntegrationSettings,
|
||||
pub venice_api_key: Option<String>,
|
||||
pub search: SearchIntegrationSettings,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ToolSecrets {
|
||||
|
|
@ -125,8 +125,8 @@ impl std::fmt::Debug for ToolSecrets {
|
|||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct NativeToolOptions {
|
||||
pub default_command_timeout_ms: u64,
|
||||
pub max_command_timeout_ms: u64,
|
||||
pub secrets: ToolSecrets,
|
||||
pub max_command_timeout_ms: u64,
|
||||
pub secrets: ToolSecrets,
|
||||
}
|
||||
|
||||
impl NativeToolOptions {
|
||||
|
|
@ -157,8 +157,8 @@ impl Default for NativeToolOptions {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
default_command_timeout_ms: 10_000,
|
||||
max_command_timeout_ms: 600_000,
|
||||
secrets: ToolSecrets::default(),
|
||||
max_command_timeout_ms: 600_000,
|
||||
secrets: ToolSecrets::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -447,12 +447,9 @@ mod tests {
|
|||
let approval: ToolApprovalFn = Arc::new(|_name, _args| Err("denied".to_string()));
|
||||
let adapter = ToolApprovalAdapter(approval);
|
||||
let decision = adapter.pre_tool_use("shell", &serde_json::json!({})).await;
|
||||
assert_eq!(
|
||||
decision,
|
||||
ToolHookDecision::Block {
|
||||
reason: "denied".to_string(),
|
||||
}
|
||||
);
|
||||
assert_eq!(decision, ToolHookDecision::Block {
|
||||
reason: "denied".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
|||
|
|
@ -174,20 +174,17 @@ mod tests {
|
|||
let profile = Claude5Profile::new("claude-sonnet-5");
|
||||
let mut names = profile.tool_registry().names();
|
||||
names.sort();
|
||||
assert_eq!(
|
||||
names,
|
||||
vec![
|
||||
"Bash",
|
||||
"Edit",
|
||||
"Read",
|
||||
"TaskCreate",
|
||||
"TaskGet",
|
||||
"TaskList",
|
||||
"TaskUpdate",
|
||||
"WebFetch",
|
||||
"Write",
|
||||
]
|
||||
);
|
||||
assert_eq!(names, vec![
|
||||
"Bash",
|
||||
"Edit",
|
||||
"Read",
|
||||
"TaskCreate",
|
||||
"TaskGet",
|
||||
"TaskList",
|
||||
"TaskUpdate",
|
||||
"WebFetch",
|
||||
"Write",
|
||||
]);
|
||||
assert!(!names.iter().any(|name| name == "Grep" || name == "Glob"));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ pub(crate) fn make_bash_tool(options: &NativeToolOptions) -> RegisteredTool {
|
|||
"additionalProperties": false
|
||||
}),
|
||||
),
|
||||
executor: Arc::new(move |args, ctx| {
|
||||
executor: Arc::new(move |args, ctx| {
|
||||
Box::pin(async move {
|
||||
let command = tools::required_str(&args, "command")?;
|
||||
let timeout_ms = args
|
||||
|
|
@ -110,7 +110,7 @@ pub(crate) fn make_bash_tool(options: &NativeToolOptions) -> RegisteredTool {
|
|||
tools::run_shell_command(&ctx, command, timeout_ms, None).await
|
||||
})
|
||||
}),
|
||||
source: ToolSource::Native,
|
||||
source: ToolSource::Native,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ pub(crate) fn make_agent_tool(
|
|||
"additionalProperties": false
|
||||
}),
|
||||
),
|
||||
executor: Arc::new(move |args, ctx| {
|
||||
executor: Arc::new(move |args, ctx| {
|
||||
let supervisor = supervisor.clone();
|
||||
let session_factory = session_factory.clone();
|
||||
Box::pin(async move {
|
||||
|
|
@ -259,7 +259,7 @@ pub(crate) fn make_agent_tool(
|
|||
}
|
||||
})
|
||||
}),
|
||||
source: ToolSource::Native,
|
||||
source: ToolSource::Native,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -330,7 +330,7 @@ pub(crate) fn make_task_output_tool(supervisor: SubAgentSupervisor) -> Registere
|
|||
"additionalProperties": false
|
||||
}),
|
||||
),
|
||||
executor: Arc::new(move |args, ctx| {
|
||||
executor: Arc::new(move |args, ctx| {
|
||||
let supervisor = supervisor.clone();
|
||||
Box::pin(async move {
|
||||
let task_id = tools::required_str(&args, "task_id")?;
|
||||
|
|
@ -384,7 +384,7 @@ pub(crate) fn make_task_output_tool(supervisor: SubAgentSupervisor) -> Registere
|
|||
}
|
||||
})
|
||||
}),
|
||||
source: ToolSource::Native,
|
||||
source: ToolSource::Native,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -406,7 +406,7 @@ pub(crate) fn make_task_stop_tool(supervisor: SubAgentSupervisor) -> RegisteredT
|
|||
"additionalProperties": false
|
||||
}),
|
||||
),
|
||||
executor: Arc::new(move |args, _ctx| {
|
||||
executor: Arc::new(move |args, _ctx| {
|
||||
let supervisor = supervisor.clone();
|
||||
Box::pin(async move {
|
||||
let task_id = tools::required_str(&args, "task_id")?;
|
||||
|
|
@ -417,7 +417,7 @@ pub(crate) fn make_task_stop_tool(supervisor: SubAgentSupervisor) -> RegisteredT
|
|||
Ok(format!("Agent {task_id} stopped."))
|
||||
})
|
||||
}),
|
||||
source: ToolSource::Native,
|
||||
source: ToolSource::Native,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -448,7 +448,7 @@ pub(crate) fn make_send_message_tool(supervisor: SubAgentSupervisor) -> Register
|
|||
"additionalProperties": false
|
||||
}),
|
||||
),
|
||||
executor: Arc::new(move |args, _ctx| {
|
||||
executor: Arc::new(move |args, _ctx| {
|
||||
let supervisor = supervisor.clone();
|
||||
Box::pin(async move {
|
||||
let recipient = tools::required_str(&args, "to")?;
|
||||
|
|
@ -459,7 +459,7 @@ pub(crate) fn make_send_message_tool(supervisor: SubAgentSupervisor) -> Register
|
|||
Ok(format!("Message sent to agent {recipient}."))
|
||||
})
|
||||
}),
|
||||
source: ToolSource::Native,
|
||||
source: ToolSource::Native,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -468,6 +468,7 @@ mod tests {
|
|||
use std::collections::BTreeSet;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use fabro_types::settings::VeniceSearchEngine;
|
||||
use serde_json::json;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
|
|
@ -478,7 +479,6 @@ mod tests {
|
|||
use crate::todo_tools::{
|
||||
make_task_create_tool, make_task_get_tool, make_task_list_tool, make_task_update_tool,
|
||||
};
|
||||
use fabro_types::settings::VeniceSearchEngine;
|
||||
|
||||
fn property_names(tool: &RegisteredTool) -> BTreeSet<&str> {
|
||||
tool.definition.parameters["properties"]
|
||||
|
|
@ -513,12 +513,12 @@ mod tests {
|
|||
|
||||
fn context() -> ToolContext {
|
||||
ToolContext {
|
||||
env: Arc::new(MockSandbox::default()) as Arc<dyn Sandbox>,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: Some("root".to_string()),
|
||||
root_session_id: Some("root".to_string()),
|
||||
tool_call_id: Some("call".to_string()),
|
||||
env: Arc::new(MockSandbox::default()) as Arc<dyn Sandbox>,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: Some("root".to_string()),
|
||||
root_session_id: Some("root".to_string()),
|
||||
tool_call_id: Some("call".to_string()),
|
||||
agent_event_emitter: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -526,16 +526,13 @@ mod tests {
|
|||
#[test]
|
||||
fn core_adapter_schemas_match_the_claude5_contract() {
|
||||
let options = NativeToolOptions::for_profile(fabro_model::AgentProfileKind::Claude5);
|
||||
assert_schema(
|
||||
&make_read_tool(),
|
||||
&["file_path", "limit", "offset"],
|
||||
&["file_path"],
|
||||
);
|
||||
assert_schema(
|
||||
&make_write_tool(),
|
||||
&["content", "file_path"],
|
||||
&["content", "file_path"],
|
||||
);
|
||||
assert_schema(&make_read_tool(), &["file_path", "limit", "offset"], &[
|
||||
"file_path",
|
||||
]);
|
||||
assert_schema(&make_write_tool(), &["content", "file_path"], &[
|
||||
"content",
|
||||
"file_path",
|
||||
]);
|
||||
assert_schema(
|
||||
&make_edit_tool(),
|
||||
&["file_path", "new_string", "old_string", "replace_all"],
|
||||
|
|
@ -547,11 +544,9 @@ mod tests {
|
|||
bash.definition.parameters["properties"]["timeout"]["maximum"],
|
||||
600_000
|
||||
);
|
||||
assert_schema(
|
||||
&make_web_fetch_tool(None),
|
||||
&["prompt", "url"],
|
||||
&["prompt", "url"],
|
||||
);
|
||||
assert_schema(&make_web_fetch_tool(None), &["prompt", "url"], &[
|
||||
"prompt", "url",
|
||||
]);
|
||||
assert_schema(
|
||||
&make_web_search_tool(SearchBackend::brave("key".to_string())),
|
||||
&["query"],
|
||||
|
|
@ -613,17 +608,13 @@ mod tests {
|
|||
&["block", "task_id", "timeout"],
|
||||
&["block", "task_id", "timeout"],
|
||||
);
|
||||
assert_schema(
|
||||
&make_task_stop_tool(supervisor.clone()),
|
||||
&["task_id"],
|
||||
&["task_id"],
|
||||
);
|
||||
assert_schema(&make_task_stop_tool(supervisor.clone()), &["task_id"], &[
|
||||
"task_id",
|
||||
]);
|
||||
let send_message = make_send_message_tool(supervisor);
|
||||
assert_schema(
|
||||
&send_message,
|
||||
&["message", "summary", "to"],
|
||||
&["message", "to"],
|
||||
);
|
||||
assert_schema(&send_message, &["message", "summary", "to"], &[
|
||||
"message", "to",
|
||||
]);
|
||||
assert!(
|
||||
send_message
|
||||
.definition
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ use tokio::task;
|
|||
|
||||
use crate::config::NativeToolOptions;
|
||||
use crate::sandbox::{ExecStreamingResult, GrepOptions};
|
||||
use crate::web_search::{SearchBackend, make_web_search_tool};
|
||||
use crate::tool_registry::{RegisteredTool, ToolContext, ToolRegistry, ToolSource};
|
||||
use crate::types::AgentEvent;
|
||||
use crate::web_search::{SearchBackend, make_web_search_tool};
|
||||
|
||||
const MAX_WEB_FETCH_BYTES: usize = 100 * 1024;
|
||||
const MAX_READ_MANY_FILES_CONCURRENCY: usize = 8;
|
||||
|
|
@ -23,7 +23,7 @@ pub(crate) const DEFAULT_READ_LINES: usize = 2000;
|
|||
/// Configuration for the optional LLM-based summarizer used by `web_fetch`.
|
||||
#[derive(Clone)]
|
||||
pub struct WebFetchSummarizer {
|
||||
pub client: Client,
|
||||
pub client: Client,
|
||||
pub model_id: ModelHandle,
|
||||
}
|
||||
|
||||
|
|
@ -512,9 +512,9 @@ pub fn make_glob_tool() -> RegisteredTool {
|
|||
pub(crate) fn make_read_many_files_tool() -> RegisteredTool {
|
||||
RegisteredTool {
|
||||
definition: ToolDefinition {
|
||||
name: "read_many_files".into(),
|
||||
name: "read_many_files".into(),
|
||||
description: "Read multiple files at once".into(),
|
||||
parameters: serde_json::json!({
|
||||
parameters: serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"paths": {
|
||||
|
|
@ -526,7 +526,7 @@ pub(crate) fn make_read_many_files_tool() -> RegisteredTool {
|
|||
"required": ["paths"]
|
||||
}),
|
||||
},
|
||||
executor: Arc::new(|args, ctx| {
|
||||
executor: Arc::new(|args, ctx| {
|
||||
Box::pin(async move {
|
||||
let paths: Vec<String> = args["paths"]
|
||||
.as_array()
|
||||
|
|
@ -565,7 +565,7 @@ pub(crate) fn make_read_many_files_tool() -> RegisteredTool {
|
|||
Ok(output)
|
||||
})
|
||||
}),
|
||||
source: ToolSource::Native,
|
||||
source: ToolSource::Native,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -573,9 +573,9 @@ pub(crate) fn make_read_many_files_tool() -> RegisteredTool {
|
|||
pub(crate) fn make_list_dir_tool() -> RegisteredTool {
|
||||
RegisteredTool {
|
||||
definition: ToolDefinition {
|
||||
name: "list_dir".into(),
|
||||
name: "list_dir".into(),
|
||||
description: "List directory contents with depth control".into(),
|
||||
parameters: serde_json::json!({
|
||||
parameters: serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {"type": "string", "description": "Directory path to list"},
|
||||
|
|
@ -584,7 +584,7 @@ pub(crate) fn make_list_dir_tool() -> RegisteredTool {
|
|||
"required": ["path"]
|
||||
}),
|
||||
},
|
||||
executor: Arc::new(|args, ctx| {
|
||||
executor: Arc::new(|args, ctx| {
|
||||
Box::pin(async move {
|
||||
let path = required_str(&args, "path")?;
|
||||
let depth = optional_usize_arg(&args, "depth")?;
|
||||
|
|
@ -607,7 +607,7 @@ pub(crate) fn make_list_dir_tool() -> RegisteredTool {
|
|||
Ok(lines.join("\n"))
|
||||
})
|
||||
}),
|
||||
source: ToolSource::Native,
|
||||
source: ToolSource::Native,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -725,7 +725,6 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::config::{NativeToolOptions, SessionOptions, ToolSecrets};
|
||||
use crate::web_search::make_web_search_tool_with_api_key;
|
||||
use crate::event::{Emitter, SessionBoundEmitter};
|
||||
use crate::local_sandbox::LocalSandbox;
|
||||
use crate::sandbox::*;
|
||||
|
|
@ -733,6 +732,7 @@ mod tests {
|
|||
use crate::tool_registry::ToolContext;
|
||||
use crate::truncation;
|
||||
use crate::types::SessionEvent;
|
||||
use crate::web_search::make_web_search_tool_with_api_key;
|
||||
|
||||
#[test]
|
||||
fn core_tool_descriptions_include_actionable_guidance() {
|
||||
|
|
@ -823,18 +823,15 @@ mod tests {
|
|||
files,
|
||||
..Default::default()
|
||||
});
|
||||
let result = (tool.executor)(
|
||||
serde_json::json!({"file_path": "/test.txt"}),
|
||||
ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
let result = (tool.executor)(serde_json::json!({"file_path": "/test.txt"}), ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
})
|
||||
.await;
|
||||
assert_eq!(result.unwrap(), "1 | hello\n2 | world\n");
|
||||
}
|
||||
|
|
@ -851,18 +848,15 @@ mod tests {
|
|||
..Default::default()
|
||||
});
|
||||
|
||||
let result = (tool.executor)(
|
||||
serde_json::json!({"file_path": "/test.txt"}),
|
||||
ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
let result = (tool.executor)(serde_json::json!({"file_path": "/test.txt"}), ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -903,12 +897,12 @@ mod tests {
|
|||
let result = (tool.executor)(
|
||||
serde_json::json!({"file_path": "/out.txt", "content": "hello"}),
|
||||
ToolContext {
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
|
|
@ -938,12 +932,12 @@ mod tests {
|
|||
"new_string": "goodbye"
|
||||
}),
|
||||
ToolContext {
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
|
|
@ -1033,12 +1027,12 @@ mod tests {
|
|||
"replace_all": true
|
||||
}),
|
||||
ToolContext {
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
|
|
@ -1066,12 +1060,12 @@ mod tests {
|
|||
"new_string": "goodbye"
|
||||
}),
|
||||
ToolContext {
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
|
|
@ -1100,8 +1094,8 @@ mod tests {
|
|||
root_session_id: Some("test-session".to_string()),
|
||||
tool_call_id: Some("call_1".to_string()),
|
||||
agent_event_emitter: Some(Arc::new(SessionBoundEmitter {
|
||||
emitter: emitter.clone(),
|
||||
session_id: "test-session".to_string(),
|
||||
emitter: emitter.clone(),
|
||||
session_id: "test-session".to_string(),
|
||||
tool_call_id: Some("call_1".to_string()),
|
||||
})),
|
||||
..shell_context(env)
|
||||
|
|
@ -1130,9 +1124,9 @@ mod tests {
|
|||
async fn shell_success_returns_ok_with_metadata_and_separate_streams() {
|
||||
let tool = make_shell_tool();
|
||||
let env: Arc<dyn Sandbox> = mock_sandbox_with(ExecResult {
|
||||
stdout: "hello".into(),
|
||||
stderr: "a warning".into(),
|
||||
exit_code: Some(0),
|
||||
stdout: "hello".into(),
|
||||
stderr: "a warning".into(),
|
||||
exit_code: Some(0),
|
||||
termination: CommandTermination::Exited,
|
||||
duration_ms: 10,
|
||||
});
|
||||
|
|
@ -1154,9 +1148,9 @@ mod tests {
|
|||
async fn shell_forwards_command_without_stream_redirection_wrapper() {
|
||||
let tool = make_shell_tool();
|
||||
let env = mock_sandbox_with(ExecResult {
|
||||
stdout: String::new(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
stdout: String::new(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
termination: CommandTermination::Exited,
|
||||
duration_ms: 1,
|
||||
});
|
||||
|
|
@ -1182,12 +1176,12 @@ mod tests {
|
|||
let _result = (tool.executor)(
|
||||
serde_json::json!({"command": "sleep 1", "timeout_ms": 5000}),
|
||||
ToolContext {
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
|
|
@ -1200,9 +1194,9 @@ mod tests {
|
|||
let tool = make_shell_tool();
|
||||
let env: Arc<dyn Sandbox> = Arc::new(MockSandbox {
|
||||
exec_result: ExecResult {
|
||||
stdout: "error".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(1),
|
||||
stdout: "error".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(1),
|
||||
termination: CommandTermination::Exited,
|
||||
duration_ms: 10,
|
||||
},
|
||||
|
|
@ -1221,9 +1215,9 @@ mod tests {
|
|||
async fn shell_timeout_returns_error_with_partial_output() {
|
||||
let tool = make_shell_tool();
|
||||
let env: Arc<dyn Sandbox> = mock_sandbox_with(ExecResult {
|
||||
stdout: "partial".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: None,
|
||||
stdout: "partial".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: None,
|
||||
termination: CommandTermination::TimedOut,
|
||||
duration_ms: 10000,
|
||||
});
|
||||
|
|
@ -1243,9 +1237,9 @@ mod tests {
|
|||
async fn shell_cancellation_returns_error_with_partial_output() {
|
||||
let tool = make_shell_tool();
|
||||
let env: Arc<dyn Sandbox> = mock_sandbox_with(ExecResult {
|
||||
stdout: "partial".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: None,
|
||||
stdout: "partial".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: None,
|
||||
termination: CommandTermination::Cancelled,
|
||||
duration_ms: 42,
|
||||
});
|
||||
|
|
@ -1297,9 +1291,9 @@ mod tests {
|
|||
async fn shell_emits_process_event_with_typed_outcome_and_redacted_tails() {
|
||||
let tool = make_shell_tool();
|
||||
let env: Arc<dyn Sandbox> = mock_sandbox_with(ExecResult {
|
||||
stdout: "out".into(),
|
||||
stderr: "boom key=AKIAYRWQG5EJLPZLBYNP".into(),
|
||||
exit_code: Some(7),
|
||||
stdout: "out".into(),
|
||||
stderr: "boom key=AKIAYRWQG5EJLPZLBYNP".into(),
|
||||
exit_code: Some(7),
|
||||
termination: CommandTermination::Exited,
|
||||
duration_ms: 12,
|
||||
});
|
||||
|
|
@ -1339,9 +1333,9 @@ mod tests {
|
|||
let tool = make_shell_tool();
|
||||
let env: Arc<dyn Sandbox> = Arc::new(MockSandbox {
|
||||
exec_result: ExecResult {
|
||||
stdout: "interleaved".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
stdout: "interleaved".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
termination: CommandTermination::Exited,
|
||||
duration_ms: 5,
|
||||
},
|
||||
|
|
@ -1457,12 +1451,12 @@ mod tests {
|
|||
let _result = (tool.executor)(
|
||||
serde_json::json!({"command": "echo $MY_KEY"}),
|
||||
ToolContext {
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: Some(Arc::new(crate::StaticEnvProvider(tool_env.clone()))),
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: Some(Arc::new(crate::StaticEnvProvider(tool_env.clone()))),
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
|
|
@ -1505,12 +1499,12 @@ mod tests {
|
|||
let _result = (tool.executor)(
|
||||
serde_json::json!({"command": "echo $GITHUB_TOKEN"}),
|
||||
ToolContext {
|
||||
env: env.clone(),
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: Some(provider.clone()),
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
env: env.clone(),
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: Some(provider.clone()),
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
|
|
@ -1526,12 +1520,12 @@ mod tests {
|
|||
let _result = (tool.executor)(
|
||||
serde_json::json!({"command": "echo $GITHUB_TOKEN"}),
|
||||
ToolContext {
|
||||
env: env.clone(),
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: Some(provider),
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
env: env.clone(),
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: Some(provider),
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
|
|
@ -1581,18 +1575,15 @@ mod tests {
|
|||
..Default::default()
|
||||
});
|
||||
|
||||
let result = (tool.executor)(
|
||||
serde_json::json!({"file_path": "/test.txt"}),
|
||||
ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: Some(Arc::new(FailingToolEnvProvider)),
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
let result = (tool.executor)(serde_json::json!({"file_path": "/test.txt"}), ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: Some(Arc::new(FailingToolEnvProvider)),
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
})
|
||||
.await;
|
||||
|
||||
assert_eq!(result.unwrap(), "1 | hello\n");
|
||||
|
|
@ -1603,18 +1594,15 @@ mod tests {
|
|||
let tool = make_shell_tool();
|
||||
let env = Arc::new(MockSandbox::default());
|
||||
let env_clone: Arc<dyn Sandbox> = env.clone();
|
||||
let _result = (tool.executor)(
|
||||
serde_json::json!({"command": "echo hello"}),
|
||||
ToolContext {
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
let _result = (tool.executor)(serde_json::json!({"command": "echo hello"}), ToolContext {
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
})
|
||||
.await;
|
||||
let captured = env.captured_env_vars.lock().unwrap().clone();
|
||||
assert_eq!(captured, None);
|
||||
|
|
@ -1625,9 +1613,9 @@ mod tests {
|
|||
let tool = make_web_fetch_tool(None);
|
||||
let env = Arc::new(MockSandbox {
|
||||
exec_result: ExecResult {
|
||||
stdout: "fetched content".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
stdout: "fetched content".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
termination: CommandTermination::Exited,
|
||||
duration_ms: 100,
|
||||
},
|
||||
|
|
@ -1639,12 +1627,12 @@ mod tests {
|
|||
let _result = (tool.executor)(
|
||||
serde_json::json!({"url": "https://example.com"}),
|
||||
ToolContext {
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: Some(Arc::new(crate::StaticEnvProvider(tool_env.clone()))),
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: Some(Arc::new(crate::StaticEnvProvider(tool_env.clone()))),
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
|
|
@ -1663,18 +1651,15 @@ mod tests {
|
|||
],
|
||||
..Default::default()
|
||||
});
|
||||
let result = (tool.executor)(
|
||||
serde_json::json!({"pattern": "fn"}),
|
||||
ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
let result = (tool.executor)(serde_json::json!({"pattern": "fn"}), ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
})
|
||||
.await;
|
||||
let output = result.unwrap();
|
||||
assert!(output.contains("src/main.rs:10:fn main()"));
|
||||
|
|
@ -1688,18 +1673,15 @@ mod tests {
|
|||
glob_results: vec!["src/main.rs".into(), "src/lib.rs".into()],
|
||||
..Default::default()
|
||||
});
|
||||
let result = (tool.executor)(
|
||||
serde_json::json!({"pattern": "src/**/*.rs"}),
|
||||
ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
let result = (tool.executor)(serde_json::json!({"pattern": "src/**/*.rs"}), ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
})
|
||||
.await;
|
||||
let output = result.unwrap();
|
||||
assert!(output.contains("src/main.rs"));
|
||||
|
|
@ -1719,18 +1701,15 @@ mod tests {
|
|||
async fn web_search_missing_query_returns_error() {
|
||||
let tool = make_web_search_tool_with_api_key("fake-key".into());
|
||||
let env: Arc<dyn Sandbox> = Arc::new(MockSandbox::default());
|
||||
let result = (tool.executor)(
|
||||
serde_json::json!({}),
|
||||
ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
let result = (tool.executor)(serde_json::json!({}), ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
})
|
||||
.await;
|
||||
let err = result.unwrap_err();
|
||||
assert!(
|
||||
|
|
@ -1756,18 +1735,15 @@ mod tests {
|
|||
.get("web_search")
|
||||
.expect("web_search should be registered");
|
||||
let env: Arc<dyn Sandbox> = Arc::new(MockSandbox::default());
|
||||
let result = (tool.executor)(
|
||||
serde_json::json!({}),
|
||||
ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
let result = (tool.executor)(serde_json::json!({}), ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
})
|
||||
.await;
|
||||
|
||||
let err = result.unwrap_err();
|
||||
|
|
@ -1782,9 +1758,9 @@ mod tests {
|
|||
let tool = make_web_fetch_tool(None);
|
||||
let env = Arc::new(MockSandbox {
|
||||
exec_result: ExecResult {
|
||||
stdout: "<html><body><h1>hello</h1></body></html>".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
stdout: "<html><body><h1>hello</h1></body></html>".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
termination: CommandTermination::Exited,
|
||||
duration_ms: 100,
|
||||
},
|
||||
|
|
@ -1794,12 +1770,12 @@ mod tests {
|
|||
let result = (tool.executor)(
|
||||
serde_json::json!({"url": "https://example.com"}),
|
||||
ToolContext {
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
|
|
@ -1860,12 +1836,12 @@ mod tests {
|
|||
let _result = (tool.executor)(
|
||||
serde_json::json!({"url": "https://example.com", "timeout_ms": 15000}),
|
||||
ToolContext {
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
|
|
@ -1886,12 +1862,12 @@ mod tests {
|
|||
let _result = (tool.executor)(
|
||||
serde_json::json!({"url": "https://example.com", "timeout_ms": 120_000}),
|
||||
ToolContext {
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
env: env_clone,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
|
|
@ -1910,9 +1886,9 @@ mod tests {
|
|||
let tool = make_web_fetch_tool(None);
|
||||
let env: Arc<dyn Sandbox> = Arc::new(MockSandbox {
|
||||
exec_result: ExecResult {
|
||||
stdout: large_content,
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
stdout: large_content,
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
termination: CommandTermination::Exited,
|
||||
duration_ms: 100,
|
||||
},
|
||||
|
|
@ -1941,9 +1917,9 @@ mod tests {
|
|||
let tool = make_web_fetch_tool(None);
|
||||
let env: Arc<dyn Sandbox> = Arc::new(MockSandbox {
|
||||
exec_result: ExecResult {
|
||||
stdout: String::new(),
|
||||
stderr: "curl: (6) Could not resolve host".into(),
|
||||
exit_code: Some(6),
|
||||
stdout: String::new(),
|
||||
stderr: "curl: (6) Could not resolve host".into(),
|
||||
exit_code: Some(6),
|
||||
termination: CommandTermination::Exited,
|
||||
duration_ms: 100,
|
||||
},
|
||||
|
|
@ -1985,16 +1961,17 @@ mod tests {
|
|||
client,
|
||||
model_id: ModelHandle::ByName {
|
||||
provider: ProviderId::anthropic(),
|
||||
model: "mock-model".to_string(),
|
||||
model: "mock-model".to_string(),
|
||||
},
|
||||
};
|
||||
|
||||
let tool = make_web_fetch_tool(Some(summarizer));
|
||||
let env: Arc<dyn Sandbox> = Arc::new(MockSandbox {
|
||||
exec_result: ExecResult {
|
||||
stdout: "<html><body><p>Lots of content about Rust...</p></body></html>".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
stdout: "<html><body><p>Lots of content about Rust...</p></body></html>"
|
||||
.into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
termination: CommandTermination::Exited,
|
||||
duration_ms: 100,
|
||||
},
|
||||
|
|
@ -2025,10 +2002,11 @@ mod tests {
|
|||
let tool = make_web_fetch_tool(None);
|
||||
let env: Arc<dyn Sandbox> = Arc::new(MockSandbox {
|
||||
exec_result: ExecResult {
|
||||
stdout: "<html><body><p>Rust is a systems programming language.</p></body></html>"
|
||||
.into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
stdout:
|
||||
"<html><body><p>Rust is a systems programming language.</p></body></html>"
|
||||
.into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
termination: CommandTermination::Exited,
|
||||
duration_ms: 100,
|
||||
},
|
||||
|
|
@ -2068,7 +2046,7 @@ mod tests {
|
|||
// "other_provider" is the default — it rejects all requests.
|
||||
let default_provider: Arc<dyn ProviderAdapter> = Arc::new(MockErrorProvider {
|
||||
error: LlmError::Provider {
|
||||
kind: ProviderErrorKind::NotFound,
|
||||
kind: ProviderErrorKind::NotFound,
|
||||
detail: Box::new(ProviderErrorDetail::new(
|
||||
"model not found",
|
||||
"other_provider",
|
||||
|
|
@ -2092,16 +2070,16 @@ mod tests {
|
|||
client,
|
||||
model_id: ModelHandle::ByName {
|
||||
provider: ProviderId::anthropic(),
|
||||
model: "target-model".to_string(),
|
||||
model: "target-model".to_string(),
|
||||
},
|
||||
};
|
||||
|
||||
let tool = make_web_fetch_tool(Some(summarizer));
|
||||
let env: Arc<dyn Sandbox> = Arc::new(MockSandbox {
|
||||
exec_result: ExecResult {
|
||||
stdout: "<html><body><p>Page content</p></body></html>".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
stdout: "<html><body><p>Page content</p></body></html>".into(),
|
||||
stderr: String::new(),
|
||||
exit_code: Some(0),
|
||||
termination: CommandTermination::Exited,
|
||||
duration_ms: 100,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -24,12 +24,12 @@ const MAX_RESULTS: u64 = 20;
|
|||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum SearchBackend {
|
||||
Brave {
|
||||
api_key: String,
|
||||
api_key: String,
|
||||
search_url: String,
|
||||
},
|
||||
Venice {
|
||||
api_key: String,
|
||||
engine: VeniceSearchEngine,
|
||||
api_key: String,
|
||||
engine: VeniceSearchEngine,
|
||||
search_url: String,
|
||||
},
|
||||
}
|
||||
|
|
@ -207,10 +207,10 @@ fn format_brave_results(body: &serde_json::Value) -> String {
|
|||
results
|
||||
.iter()
|
||||
.map(|result| SearchHit {
|
||||
title: json_str(result, "title"),
|
||||
url: json_str(result, "url"),
|
||||
title: json_str(result, "title"),
|
||||
url: json_str(result, "url"),
|
||||
description: json_str(result, "description"),
|
||||
date: None,
|
||||
date: None,
|
||||
})
|
||||
.collect()
|
||||
}))
|
||||
|
|
@ -222,20 +222,20 @@ fn format_venice_results(body: &serde_json::Value) -> String {
|
|||
results
|
||||
.iter()
|
||||
.map(|result| SearchHit {
|
||||
title: json_str(result, "title"),
|
||||
url: json_str(result, "url"),
|
||||
title: json_str(result, "title"),
|
||||
url: json_str(result, "url"),
|
||||
description: json_str(result, "content"),
|
||||
date: optional_json_str(result, "date"),
|
||||
date: optional_json_str(result, "date"),
|
||||
})
|
||||
.collect()
|
||||
}))
|
||||
}
|
||||
|
||||
struct SearchHit {
|
||||
title: String,
|
||||
url: String,
|
||||
title: String,
|
||||
url: String,
|
||||
description: String,
|
||||
date: Option<String>,
|
||||
date: Option<String>,
|
||||
}
|
||||
|
||||
fn format_hits(hits: Option<Vec<SearchHit>>) -> String {
|
||||
|
|
@ -364,8 +364,8 @@ mod tests {
|
|||
fn secrets(brave: Option<&str>, venice: Option<&str>, provider: SearchProvider) -> ToolSecrets {
|
||||
ToolSecrets {
|
||||
brave_search_api_key: brave.map(str::to_string),
|
||||
venice_api_key: venice.map(str::to_string),
|
||||
search: SearchIntegrationSettings {
|
||||
venice_api_key: venice.map(str::to_string),
|
||||
search: SearchIntegrationSettings {
|
||||
provider,
|
||||
venice_engine: VeniceSearchEngine::Brave,
|
||||
},
|
||||
|
|
@ -374,18 +374,15 @@ mod tests {
|
|||
|
||||
async fn execute(tool: &RegisteredTool, args: serde_json::Value) -> Result<String, String> {
|
||||
let env: Arc<dyn Sandbox> = Arc::new(MockSandbox::default());
|
||||
(tool.executor)(
|
||||
args,
|
||||
ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
},
|
||||
)
|
||||
(tool.executor)(args, ToolContext {
|
||||
env,
|
||||
cancel: CancellationToken::new(),
|
||||
tool_env_provider: None,
|
||||
session_id: None,
|
||||
root_session_id: None,
|
||||
tool_call_id: None,
|
||||
agent_event_emitter: None,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,22 +26,22 @@ type Provider = ProviderId;
|
|||
#[derive(Clone)]
|
||||
struct OpenAiTwinOptions {
|
||||
base_url: String,
|
||||
api_key: String,
|
||||
api_key: String,
|
||||
}
|
||||
|
||||
fn summarizer_model_id(provider: &Provider) -> ModelHandle {
|
||||
match provider.as_str() {
|
||||
ProviderId::OPENAI | "moonshot" | "zai" | "minimax" | "inception" => ModelHandle::ByName {
|
||||
provider: ProviderId::openai(),
|
||||
model: "gpt-5.4-mini".to_string(),
|
||||
model: "gpt-5.4-mini".to_string(),
|
||||
},
|
||||
ProviderId::GEMINI => ModelHandle::ByName {
|
||||
provider: ProviderId::gemini(),
|
||||
model: "gemini-3-flash-preview".to_string(),
|
||||
model: "gemini-3-flash-preview".to_string(),
|
||||
},
|
||||
ProviderId::ANTHROPIC => ModelHandle::ByName {
|
||||
provider: ProviderId::anthropic(),
|
||||
model: "claude-haiku-4-5".to_string(),
|
||||
model: "claude-haiku-4-5".to_string(),
|
||||
},
|
||||
other => panic!("unexpected provider {other}"),
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ fn summarizer_model_id(provider: &Provider) -> ModelHandle {
|
|||
|
||||
fn build_summarizer(provider: &Provider, client: &Client) -> WebFetchSummarizer {
|
||||
WebFetchSummarizer {
|
||||
client: client.clone(),
|
||||
client: client.clone(),
|
||||
model_id: summarizer_model_id(provider),
|
||||
}
|
||||
}
|
||||
|
|
@ -170,13 +170,12 @@ fn make_openai_compatible_twin_session(
|
|||
// twin fixture so the profile can resolve the same OpenAI-compatible
|
||||
// codec that the manually registered adapter uses.
|
||||
let mut settings = LlmCatalogSettings::default();
|
||||
settings.providers.insert(
|
||||
provider.to_string(),
|
||||
ProviderCatalogSettings {
|
||||
settings
|
||||
.providers
|
||||
.insert(provider.to_string(), ProviderCatalogSettings {
|
||||
enabled: Some(true),
|
||||
..ProviderCatalogSettings::default()
|
||||
},
|
||||
);
|
||||
});
|
||||
let catalog = Arc::new(
|
||||
Catalog::from_builtin_with_overrides(&settings)
|
||||
.expect("OpenAI-compatible twin catalog should build"),
|
||||
|
|
|
|||
|
|
@ -238,8 +238,8 @@ async fn tool_secrets_from_configured_sources(vault: &Arc<AsyncRwLock<Vault>>) -
|
|||
let vault = vault.read().await;
|
||||
ToolSecrets {
|
||||
brave_search_api_key: vault.get(EnvVars::BRAVE_SEARCH_API_KEY).map(str::to_string),
|
||||
venice_api_key: vault.get(EnvVars::VENICE_API_KEY).map(str::to_string),
|
||||
search: fabro_agent::search_settings_from_disk(),
|
||||
venice_api_key: vault.get(EnvVars::VENICE_API_KEY).map(str::to_string),
|
||||
search: fabro_agent::search_settings_from_disk(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -691,11 +691,8 @@ fn main() {
|
|||
("AskFabro", "fabro_types::AskFabro", &[]),
|
||||
("Automation", "fabro_automation::Automation", &[]),
|
||||
("AutomationRef", "fabro_types::AutomationRef", &[]),
|
||||
(
|
||||
"AutomationTarget",
|
||||
"fabro_automation::AutomationTarget",
|
||||
&[],
|
||||
),
|
||||
("AutomationTarget", "fabro_automation::AutomationTarget", &[
|
||||
]),
|
||||
(
|
||||
"AutomationTrigger",
|
||||
"fabro_automation::AutomationTrigger",
|
||||
|
|
|
|||
|
|
@ -13,25 +13,25 @@ use super::LogFilter;
|
|||
#[serde(deny_unknown_fields)]
|
||||
pub struct ServerLayer {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub listen: Option<ServerListenLayer>,
|
||||
pub listen: Option<ServerListenLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub api: Option<ServerApiLayer>,
|
||||
pub api: Option<ServerApiLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub web: Option<ServerWebLayer>,
|
||||
pub web: Option<ServerWebLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub auth: Option<ServerAuthLayer>,
|
||||
pub auth: Option<ServerAuthLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub sandbox: Option<ServerSandboxLayer>,
|
||||
pub sandbox: Option<ServerSandboxLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub storage: Option<ServerStorageLayer>,
|
||||
pub storage: Option<ServerStorageLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub artifacts: Option<ServerArtifactsLayer>,
|
||||
pub artifacts: Option<ServerArtifactsLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub slatedb: Option<ServerSlateDbLayer>,
|
||||
pub slatedb: Option<ServerSlateDbLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub scheduler: Option<ServerSchedulerLayer>,
|
||||
pub scheduler: Option<ServerSchedulerLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub logging: Option<ServerLoggingLayer>,
|
||||
pub logging: Option<ServerLoggingLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub integrations: Option<ServerIntegrationsLayer>,
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@ pub struct ServerWebLayer {
|
|||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub enabled: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub url: Option<String>,
|
||||
pub url: Option<String>,
|
||||
}
|
||||
|
||||
/// `[server.auth]` — cohesive server auth surface.
|
||||
|
|
@ -81,7 +81,7 @@ pub struct ServerAuthLayer {
|
|||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub methods: Option<Vec<ServerAuthMethod>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub github: Option<ServerAuthGithubLayer>,
|
||||
pub github: Option<ServerAuthGithubLayer>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
|
|
@ -103,9 +103,9 @@ pub struct ServerSandboxLayer {
|
|||
#[serde(deny_unknown_fields)]
|
||||
pub struct ServerSandboxProvidersLayer {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub local: Option<ServerSandboxProviderLayer>,
|
||||
pub local: Option<ServerSandboxProviderLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub docker: Option<ServerSandboxProviderLayer>,
|
||||
pub docker: Option<ServerSandboxProviderLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub daytona: Option<ServerSandboxProviderLayer>,
|
||||
}
|
||||
|
|
@ -132,11 +132,11 @@ pub struct ServerArtifactsLayer {
|
|||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub provider: Option<ObjectStoreProvider>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub prefix: Option<String>,
|
||||
pub prefix: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub local: Option<ObjectStoreLocalLayer>,
|
||||
pub local: Option<ObjectStoreLocalLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub s3: Option<ObjectStoreS3Layer>,
|
||||
pub s3: Option<ObjectStoreS3Layer>,
|
||||
}
|
||||
|
||||
/// `[server.slatedb]` — SlateDB bottomless storage plus tunables.
|
||||
|
|
@ -144,17 +144,17 @@ pub struct ServerArtifactsLayer {
|
|||
#[serde(deny_unknown_fields)]
|
||||
pub struct ServerSlateDbLayer {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub provider: Option<ObjectStoreProvider>,
|
||||
pub provider: Option<ObjectStoreProvider>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub prefix: Option<String>,
|
||||
pub prefix: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub flush_interval: Option<Duration>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub local: Option<ObjectStoreLocalLayer>,
|
||||
pub local: Option<ObjectStoreLocalLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub s3: Option<ObjectStoreS3Layer>,
|
||||
pub s3: Option<ObjectStoreS3Layer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub disk_cache: Option<bool>,
|
||||
pub disk_cache: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
|
|
@ -170,11 +170,11 @@ pub struct ObjectStoreLocalLayer {
|
|||
#[serde(deny_unknown_fields)]
|
||||
pub struct ObjectStoreS3Layer {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub bucket: Option<String>,
|
||||
pub bucket: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub region: Option<String>,
|
||||
pub region: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub endpoint: Option<String>,
|
||||
pub endpoint: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub path_style: Option<bool>,
|
||||
}
|
||||
|
|
@ -192,7 +192,7 @@ pub struct ServerSchedulerLayer {
|
|||
#[serde(deny_unknown_fields)]
|
||||
pub struct ServerLoggingLayer {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub level: Option<LogFilter>,
|
||||
pub level: Option<LogFilter>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub destination: Option<LogDestination>,
|
||||
}
|
||||
|
|
@ -205,7 +205,7 @@ pub struct ServerIntegrationsLayer {
|
|||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub github: Option<GithubIntegrationLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub slack: Option<SlackIntegrationLayer>,
|
||||
pub slack: Option<SlackIntegrationLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub search: Option<SearchIntegrationLayer>,
|
||||
}
|
||||
|
|
@ -216,17 +216,17 @@ pub struct ServerIntegrationsLayer {
|
|||
#[serde(deny_unknown_fields)]
|
||||
pub struct GithubIntegrationLayer {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub enabled: Option<bool>,
|
||||
pub enabled: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub strategy: Option<GithubIntegrationStrategy>,
|
||||
pub strategy: Option<GithubIntegrationStrategy>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub app_id: Option<String>,
|
||||
pub app_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub client_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub slug: Option<String>,
|
||||
pub slug: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub webhooks: Option<IntegrationWebhooksLayer>,
|
||||
pub webhooks: Option<IntegrationWebhooksLayer>,
|
||||
}
|
||||
|
||||
/// `[server.integrations.slack]` — Slack workspace credentials and defaults.
|
||||
|
|
@ -234,7 +234,7 @@ pub struct GithubIntegrationLayer {
|
|||
#[serde(deny_unknown_fields)]
|
||||
pub struct SlackIntegrationLayer {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub enabled: Option<bool>,
|
||||
pub enabled: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub default_channel: Option<String>,
|
||||
}
|
||||
|
|
@ -244,7 +244,7 @@ pub struct SlackIntegrationLayer {
|
|||
#[serde(deny_unknown_fields)]
|
||||
pub struct SearchIntegrationLayer {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub provider: Option<SearchProvider>,
|
||||
pub provider: Option<SearchProvider>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub venice_engine: Option<VeniceSearchEngine>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ pub fn resolve_server(layer: &ServerLayer, errors: &mut Vec<ResolveError>) -> Se
|
|||
.expect("defaults.toml should provide server.scheduler.max_concurrent_runs"),
|
||||
},
|
||||
logging: ServerLoggingSettings {
|
||||
level: layer
|
||||
level: layer
|
||||
.logging
|
||||
.as_ref()
|
||||
.and_then(|logging| logging.level.as_ref())
|
||||
|
|
@ -70,10 +70,10 @@ fn resolve_sandbox(layer: Option<&ServerSandboxLayer>) -> ServerSandboxSettings
|
|||
let providers = layer.and_then(|sandbox| sandbox.providers.as_ref());
|
||||
ServerSandboxSettings {
|
||||
providers: ServerSandboxProvidersSettings {
|
||||
local: resolve_sandbox_provider(
|
||||
local: resolve_sandbox_provider(
|
||||
providers.and_then(|providers| providers.local.as_ref()),
|
||||
),
|
||||
docker: resolve_sandbox_provider(
|
||||
docker: resolve_sandbox_provider(
|
||||
providers.and_then(|providers| providers.docker.as_ref()),
|
||||
),
|
||||
daytona: resolve_sandbox_provider(
|
||||
|
|
@ -150,7 +150,7 @@ fn resolve_auth(
|
|||
let methods = if let Some(mut methods) = layer.and_then(|auth| auth.methods.clone()) {
|
||||
if methods.is_empty() {
|
||||
errors.push(ResolveError::Invalid {
|
||||
path: "server.auth.methods".to_string(),
|
||||
path: "server.auth.methods".to_string(),
|
||||
reason: "must not be empty".to_string(),
|
||||
});
|
||||
}
|
||||
|
|
@ -169,7 +169,7 @@ fn resolve_auth(
|
|||
.unwrap_or_default();
|
||||
if methods.contains(&ServerAuthMethod::Github) && github.allowed_usernames.is_empty() {
|
||||
errors.push(ResolveError::Invalid {
|
||||
path: "server.auth.github.allowed_usernames".to_string(),
|
||||
path: "server.auth.github.allowed_usernames".to_string(),
|
||||
reason: "must not be empty when github auth is enabled".to_string(),
|
||||
});
|
||||
}
|
||||
|
|
@ -198,7 +198,7 @@ fn validate_github_webhook_strategy(
|
|||
&& github.app_id.is_none()
|
||||
{
|
||||
errors.push(ResolveError::Invalid {
|
||||
path: "server.integrations.github.app_id".to_string(),
|
||||
path: "server.integrations.github.app_id".to_string(),
|
||||
reason: "must be set when server.integrations.github.webhooks.strategy is configured"
|
||||
.to_string(),
|
||||
});
|
||||
|
|
@ -208,7 +208,7 @@ fn validate_github_webhook_strategy(
|
|||
&& api_layer.and_then(|api| api.url.as_ref()).is_none()
|
||||
{
|
||||
errors.push(ResolveError::Invalid {
|
||||
path: "server.api.url".to_string(),
|
||||
path: "server.api.url".to_string(),
|
||||
reason:
|
||||
"must be set when server.integrations.github.webhooks.strategy = \"server_url\""
|
||||
.to_string(),
|
||||
|
|
@ -348,20 +348,20 @@ fn resolve_integrations(layer: Option<&ServerIntegrationsLayer>) -> ServerIntegr
|
|||
);
|
||||
warn_if_demoted_template("server.integrations.github.slug", github.slug.as_deref());
|
||||
GithubIntegrationSettings {
|
||||
enabled: github.enabled.unwrap_or(true),
|
||||
strategy: github.strategy.unwrap_or_default(),
|
||||
app_id: github.app_id.clone(),
|
||||
enabled: github.enabled.unwrap_or(true),
|
||||
strategy: github.strategy.unwrap_or_default(),
|
||||
app_id: github.app_id.clone(),
|
||||
client_id: github.client_id.clone(),
|
||||
slug: github.slug.clone(),
|
||||
webhooks: github.webhooks.as_ref().map(resolve_github_webhooks),
|
||||
slug: github.slug.clone(),
|
||||
webhooks: github.webhooks.as_ref().map(resolve_github_webhooks),
|
||||
}
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
slack: layer
|
||||
slack: layer
|
||||
.and_then(|integrations| integrations.slack.as_ref())
|
||||
.map_or(
|
||||
SlackIntegrationSettings {
|
||||
enabled: false,
|
||||
enabled: false,
|
||||
default_channel: None,
|
||||
},
|
||||
|slack| {
|
||||
|
|
@ -370,7 +370,7 @@ fn resolve_integrations(layer: Option<&ServerIntegrationsLayer>) -> ServerIntegr
|
|||
slack.default_channel.as_deref(),
|
||||
);
|
||||
SlackIntegrationSettings {
|
||||
enabled: slack.enabled.unwrap_or(true),
|
||||
enabled: slack.enabled.unwrap_or(true),
|
||||
default_channel: slack.default_channel.clone(),
|
||||
}
|
||||
},
|
||||
|
|
@ -378,7 +378,7 @@ fn resolve_integrations(layer: Option<&ServerIntegrationsLayer>) -> ServerIntegr
|
|||
search: layer
|
||||
.and_then(|integrations| integrations.search.as_ref())
|
||||
.map(|search| SearchIntegrationSettings {
|
||||
provider: search.provider.unwrap_or_default(),
|
||||
provider: search.provider.unwrap_or_default(),
|
||||
venice_engine: search.venice_engine.unwrap_or_default(),
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
|
|
|
|||
|
|
@ -22,16 +22,16 @@ use super::duration::Duration;
|
|||
/// (tests).
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ServerNamespace {
|
||||
pub listen: ServerListenSettings,
|
||||
pub api: ServerApiSettings,
|
||||
pub web: ServerWebSettings,
|
||||
pub auth: ServerAuthSettings,
|
||||
pub sandbox: ServerSandboxSettings,
|
||||
pub storage: ServerStorageSettings,
|
||||
pub artifacts: ServerArtifactsSettings,
|
||||
pub slatedb: ServerSlateDbSettings,
|
||||
pub scheduler: ServerSchedulerSettings,
|
||||
pub logging: ServerLoggingSettings,
|
||||
pub listen: ServerListenSettings,
|
||||
pub api: ServerApiSettings,
|
||||
pub web: ServerWebSettings,
|
||||
pub auth: ServerAuthSettings,
|
||||
pub sandbox: ServerSandboxSettings,
|
||||
pub storage: ServerStorageSettings,
|
||||
pub artifacts: ServerArtifactsSettings,
|
||||
pub slatedb: ServerSlateDbSettings,
|
||||
pub scheduler: ServerSchedulerSettings,
|
||||
pub logging: ServerLoggingSettings,
|
||||
pub integrations: ServerIntegrationsSettings,
|
||||
}
|
||||
|
||||
|
|
@ -43,16 +43,16 @@ impl ServerNamespace {
|
|||
#[must_use]
|
||||
pub fn test_default() -> Self {
|
||||
Self {
|
||||
listen: ServerListenSettings::default(),
|
||||
api: ServerApiSettings::default(),
|
||||
web: ServerWebSettings::default(),
|
||||
auth: ServerAuthSettings::default(),
|
||||
sandbox: ServerSandboxSettings::default(),
|
||||
storage: ServerStorageSettings::default(),
|
||||
artifacts: ServerArtifactsSettings::default(),
|
||||
slatedb: ServerSlateDbSettings::default(),
|
||||
scheduler: ServerSchedulerSettings::default(),
|
||||
logging: ServerLoggingSettings::default(),
|
||||
listen: ServerListenSettings::default(),
|
||||
api: ServerApiSettings::default(),
|
||||
web: ServerWebSettings::default(),
|
||||
auth: ServerAuthSettings::default(),
|
||||
sandbox: ServerSandboxSettings::default(),
|
||||
storage: ServerStorageSettings::default(),
|
||||
artifacts: ServerArtifactsSettings::default(),
|
||||
slatedb: ServerSlateDbSettings::default(),
|
||||
scheduler: ServerSchedulerSettings::default(),
|
||||
logging: ServerLoggingSettings::default(),
|
||||
integrations: ServerIntegrationsSettings::default(),
|
||||
}
|
||||
}
|
||||
|
|
@ -89,13 +89,13 @@ pub struct ServerApiSettings {
|
|||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ServerWebSettings {
|
||||
pub enabled: bool,
|
||||
pub url: String,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ServerAuthSettings {
|
||||
pub methods: Vec<ServerAuthMethod>,
|
||||
pub github: ServerAuthGithubSettings,
|
||||
pub github: ServerAuthGithubSettings,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
|
@ -117,8 +117,8 @@ pub struct ServerSandboxSettings {
|
|||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ServerSandboxProvidersSettings {
|
||||
pub local: ServerSandboxProviderSettings,
|
||||
pub docker: ServerSandboxProviderSettings,
|
||||
pub local: ServerSandboxProviderSettings,
|
||||
pub docker: ServerSandboxProviderSettings,
|
||||
pub daytona: ServerSandboxProviderSettings,
|
||||
}
|
||||
|
||||
|
|
@ -158,28 +158,28 @@ pub struct ServerStorageSettings {
|
|||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ServerArtifactsSettings {
|
||||
pub prefix: String,
|
||||
pub store: ObjectStoreSettings,
|
||||
pub store: ObjectStoreSettings,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ServerSlateDbSettings {
|
||||
pub prefix: String,
|
||||
pub store: ObjectStoreSettings,
|
||||
pub prefix: String,
|
||||
pub store: ObjectStoreSettings,
|
||||
#[serde(
|
||||
serialize_with = "serialize_std_duration",
|
||||
deserialize_with = "deserialize_std_duration"
|
||||
)]
|
||||
pub flush_interval: StdDuration,
|
||||
pub disk_cache: bool,
|
||||
pub disk_cache: bool,
|
||||
}
|
||||
|
||||
impl Default for ServerSlateDbSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
prefix: String::new(),
|
||||
store: ObjectStoreSettings::default(),
|
||||
prefix: String::new(),
|
||||
store: ObjectStoreSettings::default(),
|
||||
flush_interval: StdDuration::ZERO,
|
||||
disk_cache: false,
|
||||
disk_cache: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -191,9 +191,9 @@ pub enum ObjectStoreSettings {
|
|||
root: String,
|
||||
},
|
||||
S3 {
|
||||
bucket: String,
|
||||
region: String,
|
||||
endpoint: Option<String>,
|
||||
bucket: String,
|
||||
region: String,
|
||||
endpoint: Option<String>,
|
||||
path_style: bool,
|
||||
},
|
||||
}
|
||||
|
|
@ -233,7 +233,7 @@ pub enum LogDestination {
|
|||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ServerLoggingSettings {
|
||||
pub level: Option<String>,
|
||||
pub level: Option<String>,
|
||||
#[serde(default)]
|
||||
pub destination: LogDestination,
|
||||
}
|
||||
|
|
@ -241,30 +241,30 @@ pub struct ServerLoggingSettings {
|
|||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ServerIntegrationsSettings {
|
||||
pub github: GithubIntegrationSettings,
|
||||
pub slack: SlackIntegrationSettings,
|
||||
pub slack: SlackIntegrationSettings,
|
||||
pub search: SearchIntegrationSettings,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct GithubIntegrationSettings {
|
||||
pub enabled: bool,
|
||||
pub strategy: GithubIntegrationStrategy,
|
||||
pub app_id: Option<String>,
|
||||
pub enabled: bool,
|
||||
pub strategy: GithubIntegrationStrategy,
|
||||
pub app_id: Option<String>,
|
||||
pub client_id: Option<String>,
|
||||
pub slug: Option<String>,
|
||||
pub webhooks: Option<IntegrationWebhooksSettings>,
|
||||
pub slug: Option<String>,
|
||||
pub webhooks: Option<IntegrationWebhooksSettings>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SlackIntegrationSettings {
|
||||
pub enabled: bool,
|
||||
pub enabled: bool,
|
||||
pub default_channel: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for SlackIntegrationSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
enabled: true,
|
||||
default_channel: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -335,7 +335,7 @@ impl VeniceSearchEngine {
|
|||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SearchIntegrationSettings {
|
||||
pub provider: SearchProvider,
|
||||
pub provider: SearchProvider,
|
||||
pub venice_engine: VeniceSearchEngine,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue