mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-27 01:21:25 +00:00
## Summary This PR moves Fabro’s provider/model catalog toward settings-driven provider identity by replacing the closed provider schema at the API/auth/model boundary with `ProviderId`, then loading built-in provider and model metadata from embedded per-provider TOML files. The immediate result is that built-ins now use the same settings-shaped catalog data that custom providers will use later, while request-serving paths still keep the existing bootstrap/default catalog behavior until the resolved-catalog plumbing lands. ## Changes - Replaces API-facing provider enum usage with string-backed `ProviderId`, including OpenAPI/progenitor replacements and regenerated TypeScript client models. - Routes model, auth, billing, CLI, server, and workflow call sites through provider IDs where they cross product identity boundaries. - Builds `Catalog` from settings-shaped provider/model data with validation for adapter keys, OpenAI-compatible `base_url`, duplicate aliases, provider defaults, disabled entries, model controls, and per-speed cost rows. - Replaces `catalog.json` with embedded provider TOML files under `lib/crates/fabro-model/src/catalog/providers/`. - Adds an explicit `fabro_model::bootstrap_catalog` hatch for setup/install paths and extends the dev policy test to keep bootstrap access contained. - Preserves public training and knowledge-cutoff labels in LLM model settings while still accepting bare TOML dates. ## Verification - `cargo nextest run -p fabro-model -p fabro-config -p fabro-api` — 416 passed - `cargo nextest run -p fabro-dev --features dev bootstrap_catalog_references_stay_in_allowlist` — 1 passed - `cargo +nightly-2026-04-14 fmt --check --all` - `cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D warnings` - `cargo build --workspace` - `git diff --check` --- [](https://github.com/EveryInc/compound-engineering-plugin) 🤖 Generated with GPT-5 via [Codex](https://openai.com/codex)
91 lines
2.4 KiB
Rust
91 lines
2.4 KiB
Rust
use fabro_graphviz::graph::Graph;
|
|
use fabro_graphviz::parser;
|
|
use fabro_model::{Catalog, Provider};
|
|
use fabro_types::WorkflowSettings;
|
|
use fabro_types::settings::InterpString;
|
|
use fabro_types::settings::run::{PullRequestSettings, RunGoal, RunModelSettings, RunNamespace};
|
|
use fabro_workflow::run_materialization::materialize_run;
|
|
|
|
fn graph(source: &str) -> Graph {
|
|
parser::parse(source).expect("graph should parse")
|
|
}
|
|
|
|
#[test]
|
|
fn materialize_run_applies_graph_and_catalog_defaults() {
|
|
let source = r#"digraph Test {
|
|
graph [goal="Build feature"]
|
|
start [shape=Mdiamond]
|
|
exit [shape=Msquare]
|
|
start -> exit
|
|
}"#;
|
|
|
|
let settings = WorkflowSettings {
|
|
run: RunNamespace {
|
|
model: RunModelSettings {
|
|
name: Some(InterpString::parse("sonnet")),
|
|
..RunModelSettings::default()
|
|
},
|
|
pull_request: Some(PullRequestSettings {
|
|
enabled: false,
|
|
..PullRequestSettings::default()
|
|
}),
|
|
..RunNamespace::default()
|
|
},
|
|
..WorkflowSettings::default()
|
|
};
|
|
|
|
let materialized = materialize_run(settings, &graph(source), Catalog::builtin(), &[]);
|
|
let resolved = &materialized.run;
|
|
|
|
assert_eq!(
|
|
resolved
|
|
.model
|
|
.name
|
|
.as_ref()
|
|
.map(InterpString::as_source)
|
|
.as_deref(),
|
|
Some("claude-sonnet-4-6")
|
|
);
|
|
assert_eq!(
|
|
resolved
|
|
.model
|
|
.provider
|
|
.as_ref()
|
|
.map(InterpString::as_source)
|
|
.as_deref(),
|
|
Some("anthropic")
|
|
);
|
|
assert_eq!(
|
|
materialized.run.goal.as_ref(),
|
|
Some(&RunGoal::Inline(InterpString::parse("Build feature")))
|
|
);
|
|
assert!(resolved.pull_request.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn materialize_run_uses_configured_provider_defaults() {
|
|
let source = r#"digraph Test {
|
|
graph [goal="Build feature"]
|
|
start [shape=Mdiamond]
|
|
exit [shape=Msquare]
|
|
start -> exit
|
|
}"#;
|
|
|
|
let materialized = materialize_run(
|
|
WorkflowSettings::default(),
|
|
&graph(source),
|
|
Catalog::builtin(),
|
|
&[Provider::OpenAi.id()],
|
|
);
|
|
let resolved = &materialized.run;
|
|
|
|
assert_eq!(
|
|
resolved
|
|
.model
|
|
.provider
|
|
.as_ref()
|
|
.map(InterpString::as_source)
|
|
.as_deref(),
|
|
Some("openai")
|
|
);
|
|
}
|