diff --git a/lib/crates/fabro-config/src/lib.rs b/lib/crates/fabro-config/src/lib.rs index 24af07e32..451de1e82 100644 --- a/lib/crates/fabro-config/src/lib.rs +++ b/lib/crates/fabro-config/src/lib.rs @@ -37,10 +37,10 @@ pub use load::{ }; pub use parse::{ParseError, parse_settings_layer}; pub use resolve::{ - ResolveError, dev_token_auth_enabled, resolve_cli, resolve_cli_from_file, resolve_features, - resolve_features_from_file, resolve_project, resolve_project_from_file, resolve_run, - resolve_run_from_file, resolve_server, resolve_server_from_file, resolve_storage_root, - resolve_workflow, resolve_workflow_from_file, + ResolveError, dev_token_auth_enabled, render_resolve_errors, resolve_cli, + resolve_cli_from_file, resolve_features, resolve_features_from_file, resolve_project, + resolve_project_from_file, resolve_run, resolve_run_from_file, resolve_server, + resolve_server_from_file, resolve_storage_root, resolve_workflow, resolve_workflow_from_file, }; use serde::de::DeserializeOwned; pub use storage::{RunScratch, RuntimeDirectory, Storage}; diff --git a/lib/crates/fabro-config/src/resolve/mod.rs b/lib/crates/fabro-config/src/resolve/mod.rs index c72ca5930..a93f2faf2 100644 --- a/lib/crates/fabro-config/src/resolve/mod.rs +++ b/lib/crates/fabro-config/src/resolve/mod.rs @@ -100,6 +100,17 @@ pub fn resolve_workflow_from_file( } } +/// Render a list of [`ResolveError`]s as a single semicolon-separated message +/// suitable for surfacing through `anyhow!` / `Error::Precondition` / similar +/// human-facing error envelopes. +pub fn render_resolve_errors(errors: &[ResolveError]) -> String { + errors + .iter() + .map(ToString::to_string) + .collect::>() + .join("; ") +} + pub(crate) fn require_interp( value: Option<&InterpString>, path: &str, diff --git a/lib/crates/fabro-server/src/run_manifest.rs b/lib/crates/fabro-server/src/run_manifest.rs index f4ed75a3d..cae7fd3e3 100644 --- a/lib/crates/fabro-server/src/run_manifest.rs +++ b/lib/crates/fabro-server/src/run_manifest.rs @@ -361,7 +361,7 @@ async fn build_preflight_report( &configured_providers, ); let resolved_run = fabro_config::resolve_run_from_file(&materialized) - .map_err(|errors| anyhow!(render_resolve_errors(&errors)))?; + .map_err(|errors| anyhow!(fabro_config::render_resolve_errors(&errors)))?; let server_settings = state.server_settings(); let github_integration = &server_settings.server.integrations.github; let sandbox_provider = resolve_sandbox_provider(&resolved_run)?; @@ -701,14 +701,6 @@ fn resolve_model_provider( } } -fn render_resolve_errors(errors: &[fabro_config::ResolveError]) -> String { - errors - .iter() - .map(ToString::to_string) - .collect::>() - .join("; ") -} - fn runtime_daytona_config(settings: &DaytonaSettings) -> DaytonaConfig { DaytonaConfig { auto_stop_interval: settings.auto_stop_interval, diff --git a/lib/crates/fabro-workflow/src/operations/create.rs b/lib/crates/fabro-workflow/src/operations/create.rs index 0b26760d1..ba6ced33b 100644 --- a/lib/crates/fabro-workflow/src/operations/create.rs +++ b/lib/crates/fabro-workflow/src/operations/create.rs @@ -284,23 +284,15 @@ fn store_error(err: impl std::fmt::Display) -> Error { Error::engine(err.to_string()) } -fn render_resolve_errors(errors: &[fabro_config::ResolveError]) -> String { - errors - .iter() - .map(ToString::to_string) - .collect::>() - .join("; ") -} - fn resolve_settings_tree(settings: &SettingsLayer) -> Result { Ok(ResolvedSettingsTree { server_storage_root: fabro_config::resolve_storage_root(settings), project: fabro_config::resolve_project_from_file(settings) - .map_err(|errors| Error::Precondition(render_resolve_errors(&errors)))?, + .map_err(|errors| Error::Precondition(fabro_config::render_resolve_errors(&errors)))?, workflow: fabro_config::resolve_workflow_from_file(settings) - .map_err(|errors| Error::Precondition(render_resolve_errors(&errors)))?, + .map_err(|errors| Error::Precondition(fabro_config::render_resolve_errors(&errors)))?, run: fabro_config::resolve_run_from_file(settings) - .map_err(|errors| Error::Precondition(render_resolve_errors(&errors)))?, + .map_err(|errors| Error::Precondition(fabro_config::render_resolve_errors(&errors)))?, }) } @@ -313,7 +305,7 @@ fn combined_labels(settings: &ResolvedSettingsTree) -> HashMap { fn validate_sandbox_provider(settings: &SettingsLayer) -> Result<(), Error> { let resolved = fabro_config::resolve_run_from_file(settings) - .map_err(|errors| Error::Precondition(render_resolve_errors(&errors)))?; + .map_err(|errors| Error::Precondition(fabro_config::render_resolve_errors(&errors)))?; resolved .sandbox .provider diff --git a/lib/crates/fabro-workflow/src/operations/start.rs b/lib/crates/fabro-workflow/src/operations/start.rs index bcd030dcd..7a087b34a 100644 --- a/lib/crates/fabro-workflow/src/operations/start.rs +++ b/lib/crates/fabro-workflow/src/operations/start.rs @@ -310,7 +310,7 @@ impl RunSession { .map_or((None, None), |(url, branch)| (Some(url), branch)); let resolved = fabro_config::resolve_run_from_file(settings) - .map_err(|errors| Error::Precondition(render_resolve_errors(&errors)))?; + .map_err(|errors| Error::Precondition(fabro_config::render_resolve_errors(&errors)))?; let sandbox_provider = resolve_sandbox_provider(&resolved)?; let sandbox_provider = @@ -518,14 +518,6 @@ fn resolve_fallback_chain( Catalog::builtin().build_fallback_chain(provider, model, &by_provider) } -fn render_resolve_errors(errors: &[fabro_config::ResolveError]) -> String { - errors - .iter() - .map(ToString::to_string) - .collect::>() - .join("; ") -} - fn runtime_mcp_server(settings: &ResolvedMcpServerSettings) -> McpServerSettings { McpServerSettings { name: settings.name.clone(),