mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-11 22:53:00 +00:00
Name built-in providers through lithos catalog::builtin
lithos-llm now ships the built-in provider ids and constructors, so fabro-types drops its provider_ids module and every caller uses lithos_llm::catalog::builtin directly. The crates that name a provider now depend on lithos-llm themselves. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
f8df58966b
commit
fa3e485c95
66 changed files with 317 additions and 326 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
|
@ -2292,6 +2292,7 @@ dependencies = [
|
|||
"insta",
|
||||
"jsonschema",
|
||||
"libc",
|
||||
"lithos-llm",
|
||||
"paste",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -2318,6 +2319,7 @@ dependencies = [
|
|||
"fabro-config",
|
||||
"fabro-environment",
|
||||
"fabro-types",
|
||||
"lithos-llm",
|
||||
"openapiv3",
|
||||
"prettyplease",
|
||||
"progenitor",
|
||||
|
|
@ -2463,6 +2465,7 @@ dependencies = [
|
|||
"insta",
|
||||
"jsonwebtoken",
|
||||
"libc",
|
||||
"lithos-llm",
|
||||
"miette",
|
||||
"nix 0.30.1",
|
||||
"object_store",
|
||||
|
|
@ -2692,6 +2695,7 @@ dependencies = [
|
|||
"fabro-types",
|
||||
"fabro-util",
|
||||
"httpmock",
|
||||
"lithos-llm",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -3034,6 +3038,7 @@ dependencies = [
|
|||
"http-body-util",
|
||||
"httpmock",
|
||||
"jsonwebtoken",
|
||||
"lithos-llm",
|
||||
"mime_guess",
|
||||
"multer",
|
||||
"object_store",
|
||||
|
|
@ -3372,6 +3377,7 @@ dependencies = [
|
|||
"hex",
|
||||
"httpmock",
|
||||
"jsonschema",
|
||||
"lithos-llm",
|
||||
"md5",
|
||||
"miette",
|
||||
"mime_guess",
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ use std::sync::Arc;
|
|||
use fabro_agent::{AgentProfile, AgentProfileBuilder, LocalSandbox, Session, SessionOptions};
|
||||
use fabro_auth::VaultCredentialSource;
|
||||
use fabro_llm::ClientOptions;
|
||||
use fabro_types::{AgentProfileKind, provider_ids};
|
||||
use fabro_types::AgentProfileKind;
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
@ -48,7 +49,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let profile: Arc<dyn AgentProfile> = Arc::from(
|
||||
AgentProfileBuilder::new(
|
||||
AgentProfileKind::Anthropic,
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
"claude-sonnet-4.5",
|
||||
Arc::clone(&catalog),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ fabro-telemetry = { path = "../../foundation/fabro-telemetry" }
|
|||
fabro-store = { path = "../../components/fabro-store" }
|
||||
fabro-vault = { path = "../../foundation/fabro-vault" }
|
||||
fabro-types = { path = "../../foundation/fabro-types", features = ["clap"] }
|
||||
lithos-llm = { workspace = true, features = ["runtime"] }
|
||||
fabro-redact.workspace = true
|
||||
fabro-util = { path = "../../foundation/fabro-util" }
|
||||
fabro-http.workspace = true
|
||||
|
|
|
|||
|
|
@ -39,13 +39,14 @@ use fabro_server::serve;
|
|||
use fabro_store::ArtifactStore;
|
||||
use fabro_types::settings::server::ServerAuthMethod;
|
||||
use fabro_types::settings::validate_public_url_with_label;
|
||||
use fabro_types::{ProviderId, ServerSettings, provider_ids};
|
||||
use fabro_types::{ProviderId, ServerSettings};
|
||||
use fabro_util::printer::Printer;
|
||||
use fabro_util::terminal::Styles;
|
||||
use fabro_util::version::FABRO_VERSION;
|
||||
use fabro_util::{browser, dev_token, path, session_secret};
|
||||
use fabro_vault::SecretType as VaultSecretType;
|
||||
use futures::future::BoxFuture;
|
||||
use lithos_llm::catalog::builtin;
|
||||
use rand::Rng;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::process::Command as TokioCommand;
|
||||
|
|
@ -429,14 +430,14 @@ impl InstallInputSource for InteractiveInstallInputSource {
|
|||
|
||||
if use_device_auth {
|
||||
let credential = authenticate_provider_with_method(
|
||||
provider_ids::openai(),
|
||||
builtin::openai(),
|
||||
AuthMethod::CodexDevice(codex_oauth_config()),
|
||||
s,
|
||||
printer,
|
||||
)
|
||||
.await?;
|
||||
credentials.push(credential);
|
||||
configured_providers.push(provider_ids::openai());
|
||||
configured_providers.push(builtin::openai());
|
||||
openai_configured = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2698,7 +2699,7 @@ client_id = "client-id"
|
|||
description: None,
|
||||
},
|
||||
credential_secret_request(&LoginResult::ApiKey {
|
||||
provider: fabro_types::provider_ids::anthropic(),
|
||||
provider: lithos_llm::catalog::builtin::anthropic(),
|
||||
key: "anthropic-key".to_string(),
|
||||
})
|
||||
.unwrap(),
|
||||
|
|
@ -3504,9 +3505,9 @@ root = "{}"
|
|||
fn install_llm_providers_come_from_catalog_api_key_providers() {
|
||||
let ids = install_llm_provider_ids(&INSTALL_CATALOG);
|
||||
|
||||
assert!(ids.contains(&fabro_types::provider_ids::anthropic()));
|
||||
assert!(ids.contains(&fabro_types::provider_ids::openai()));
|
||||
assert!(ids.contains(&fabro_types::provider_ids::gemini()));
|
||||
assert!(ids.contains(&lithos_llm::catalog::builtin::anthropic()));
|
||||
assert!(ids.contains(&lithos_llm::catalog::builtin::openai()));
|
||||
assert!(ids.contains(&lithos_llm::catalog::builtin::gemini()));
|
||||
assert!(ids.contains(&ProviderId::new("moonshot")));
|
||||
assert!(ids.contains(&ProviderId::new("zai")));
|
||||
assert!(ids.contains(&ProviderId::new("minimax")));
|
||||
|
|
@ -3531,7 +3532,7 @@ root = "{}"
|
|||
#[test]
|
||||
fn non_interactive_source_rejects_hidden_args_without_switch() {
|
||||
let args = install_args(false, InstallNonInteractiveArgs {
|
||||
llm_provider: Some(fabro_types::provider_ids::anthropic()),
|
||||
llm_provider: Some(lithos_llm::catalog::builtin::anthropic()),
|
||||
..InstallNonInteractiveArgs::default()
|
||||
});
|
||||
let err = NonInteractiveInstallInputSource::new(&args).unwrap_err();
|
||||
|
|
@ -3544,7 +3545,7 @@ root = "{}"
|
|||
#[test]
|
||||
fn non_interactive_source_rejects_conflicting_api_key_inputs() {
|
||||
let args = install_args(true, InstallNonInteractiveArgs {
|
||||
llm_provider: Some(fabro_types::provider_ids::anthropic()),
|
||||
llm_provider: Some(lithos_llm::catalog::builtin::anthropic()),
|
||||
llm_api_key_stdin: true,
|
||||
llm_api_key_env: Some("ANTHROPIC_API_KEY".to_string()),
|
||||
github_strategy: Some(InstallGitHubStrategyArg::Token),
|
||||
|
|
@ -3640,7 +3641,7 @@ root = "{}"
|
|||
fn non_interactive_source_rejects_missing_github_strategy() {
|
||||
let source = NonInteractiveInstallInputSource {
|
||||
args: InstallNonInteractiveArgs {
|
||||
llm_provider: Some(fabro_types::provider_ids::anthropic()),
|
||||
llm_provider: Some(lithos_llm::catalog::builtin::anthropic()),
|
||||
llm_api_key_env: Some("ANTHROPIC_API_KEY".to_string()),
|
||||
github_username: Some("brynary".to_string()),
|
||||
..InstallNonInteractiveArgs::default()
|
||||
|
|
@ -3658,7 +3659,7 @@ root = "{}"
|
|||
fn non_interactive_source_rejects_missing_github_username_for_new_config() {
|
||||
let source = NonInteractiveInstallInputSource {
|
||||
args: InstallNonInteractiveArgs {
|
||||
llm_provider: Some(fabro_types::provider_ids::anthropic()),
|
||||
llm_provider: Some(lithos_llm::catalog::builtin::anthropic()),
|
||||
llm_api_key_env: Some("ANTHROPIC_API_KEY".to_string()),
|
||||
github_strategy: Some(InstallGitHubStrategyArg::Token),
|
||||
..InstallNonInteractiveArgs::default()
|
||||
|
|
@ -3675,7 +3676,7 @@ root = "{}"
|
|||
fn non_interactive_source_allows_keep_existing_settings_without_username() {
|
||||
let source = NonInteractiveInstallInputSource {
|
||||
args: InstallNonInteractiveArgs {
|
||||
llm_provider: Some(fabro_types::provider_ids::anthropic()),
|
||||
llm_provider: Some(lithos_llm::catalog::builtin::anthropic()),
|
||||
llm_api_key_env: Some("ANTHROPIC_API_KEY".to_string()),
|
||||
github_strategy: Some(InstallGitHubStrategyArg::Token),
|
||||
keep_existing_settings: true,
|
||||
|
|
@ -3690,7 +3691,7 @@ root = "{}"
|
|||
fn non_interactive_source_rejects_missing_github_owner_for_app() {
|
||||
let source = NonInteractiveInstallInputSource {
|
||||
args: InstallNonInteractiveArgs {
|
||||
llm_provider: Some(fabro_types::provider_ids::anthropic()),
|
||||
llm_provider: Some(lithos_llm::catalog::builtin::anthropic()),
|
||||
llm_api_key_env: Some("ANTHROPIC_API_KEY".to_string()),
|
||||
github_strategy: Some(InstallGitHubStrategyArg::App),
|
||||
..InstallNonInteractiveArgs::default()
|
||||
|
|
@ -3709,7 +3710,7 @@ root = "{}"
|
|||
fn non_interactive_source_rejects_github_owner_for_token() {
|
||||
let source = NonInteractiveInstallInputSource {
|
||||
args: InstallNonInteractiveArgs {
|
||||
llm_provider: Some(fabro_types::provider_ids::anthropic()),
|
||||
llm_provider: Some(lithos_llm::catalog::builtin::anthropic()),
|
||||
llm_api_key_env: Some("ANTHROPIC_API_KEY".to_string()),
|
||||
github_strategy: Some(InstallGitHubStrategyArg::Token),
|
||||
github_owner: Some("personal".to_string()),
|
||||
|
|
@ -3729,7 +3730,7 @@ root = "{}"
|
|||
fn non_interactive_source_rejects_github_username_for_app() {
|
||||
let source = NonInteractiveInstallInputSource {
|
||||
args: InstallNonInteractiveArgs {
|
||||
llm_provider: Some(fabro_types::provider_ids::anthropic()),
|
||||
llm_provider: Some(lithos_llm::catalog::builtin::anthropic()),
|
||||
llm_api_key_env: Some("ANTHROPIC_API_KEY".to_string()),
|
||||
github_strategy: Some(InstallGitHubStrategyArg::App),
|
||||
github_owner: Some("personal".to_string()),
|
||||
|
|
@ -3749,7 +3750,7 @@ root = "{}"
|
|||
fn non_interactive_source_allows_github_app_setup() {
|
||||
let source = NonInteractiveInstallInputSource {
|
||||
args: InstallNonInteractiveArgs {
|
||||
llm_provider: Some(fabro_types::provider_ids::anthropic()),
|
||||
llm_provider: Some(lithos_llm::catalog::builtin::anthropic()),
|
||||
llm_api_key_env: Some("ANTHROPIC_API_KEY".to_string()),
|
||||
github_strategy: Some(InstallGitHubStrategyArg::App),
|
||||
github_owner: Some("personal".to_string()),
|
||||
|
|
@ -3764,7 +3765,7 @@ root = "{}"
|
|||
async fn non_interactive_source_requires_config_choice_when_settings_exist() {
|
||||
let source = NonInteractiveInstallInputSource {
|
||||
args: InstallNonInteractiveArgs {
|
||||
llm_provider: Some(fabro_types::provider_ids::anthropic()),
|
||||
llm_provider: Some(lithos_llm::catalog::builtin::anthropic()),
|
||||
llm_api_key_env: Some("ANTHROPIC_API_KEY".to_string()),
|
||||
github_strategy: Some(InstallGitHubStrategyArg::Token),
|
||||
github_username: Some("brynary".to_string()),
|
||||
|
|
|
|||
|
|
@ -513,9 +513,8 @@ impl Default for ModelsCommand {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use fabro_types::{
|
||||
ModelControls, ModelCosts, ModelFeatures, ModelLimits, ReasoningEffort, provider_ids,
|
||||
};
|
||||
use fabro_types::{ModelControls, ModelCosts, ModelFeatures, ModelLimits, ReasoningEffort};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -902,7 +901,7 @@ mod tests {
|
|||
.header("Content-Type", "application/json")
|
||||
.body(
|
||||
serde_json::json!({
|
||||
"data": [test_model_json("test-model", provider_ids::anthropic())],
|
||||
"data": [test_model_json("test-model", builtin::anthropic())],
|
||||
"meta": { "has_more": false }
|
||||
})
|
||||
.to_string(),
|
||||
|
|
@ -916,7 +915,7 @@ mod tests {
|
|||
mock.assert_async().await;
|
||||
assert_eq!(models.len(), 1);
|
||||
assert_eq!(models[0].id.as_str(), "test-model");
|
||||
assert_eq!(models[0].provider, provider_ids::anthropic());
|
||||
assert_eq!(models[0].provider, builtin::anthropic());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -933,7 +932,7 @@ mod tests {
|
|||
.header("Content-Type", "application/json")
|
||||
.body(
|
||||
serde_json::json!({
|
||||
"data": [test_model_json("model-a", provider_ids::anthropic())],
|
||||
"data": [test_model_json("model-a", builtin::anthropic())],
|
||||
"meta": { "has_more": false }
|
||||
})
|
||||
.to_string(),
|
||||
|
|
@ -961,12 +960,12 @@ mod tests {
|
|||
then.status(200)
|
||||
.header("Content-Type", "application/json")
|
||||
.body(
|
||||
serde_json::json!({
|
||||
"data": [test_model_json("claude-sonnet-4-5", provider_ids::anthropic())],
|
||||
"meta": { "has_more": false }
|
||||
})
|
||||
.to_string(),
|
||||
);
|
||||
serde_json::json!({
|
||||
"data": [test_model_json("claude-sonnet-4-5", builtin::anthropic())],
|
||||
"meta": { "has_more": false }
|
||||
})
|
||||
.to_string(),
|
||||
);
|
||||
})
|
||||
.await;
|
||||
|
||||
|
|
@ -991,7 +990,7 @@ mod tests {
|
|||
.header("Content-Type", "application/json")
|
||||
.body(
|
||||
serde_json::json!({
|
||||
"data": [test_model_json("model-a", provider_ids::anthropic())],
|
||||
"data": [test_model_json("model-a", builtin::anthropic())],
|
||||
"meta": { "has_more": true }
|
||||
})
|
||||
.to_string(),
|
||||
|
|
@ -1008,7 +1007,7 @@ mod tests {
|
|||
.header("Content-Type", "application/json")
|
||||
.body(
|
||||
serde_json::json!({
|
||||
"data": [test_model_json("model-b", provider_ids::openai())],
|
||||
"data": [test_model_json("model-b", builtin::openai())],
|
||||
"meta": { "has_more": false }
|
||||
})
|
||||
.to_string(),
|
||||
|
|
|
|||
|
|
@ -461,10 +461,11 @@ mod tests {
|
|||
use fabro_types::run_event::CliEnsureCompletedProps;
|
||||
use fabro_types::{
|
||||
MetadataSnapshotFailureKind, MetadataSnapshotPhase, ModelId, ModelRef, ParallelBranchId,
|
||||
SandboxProviderKind, StageId, TokenCounts, fixtures, provider_ids,
|
||||
SandboxProviderKind, StageId, TokenCounts, fixtures,
|
||||
};
|
||||
use fabro_workflow::event::{Event, RunNoticeLevel, to_run_event, to_run_event_at};
|
||||
use fabro_workflow::outcome::billed_model_usage_from_llm;
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::*;
|
||||
use crate::commands::run::run_progress::stage_display::ToolCallStatus;
|
||||
|
|
@ -570,7 +571,7 @@ mod tests {
|
|||
fn assistant_event(model: &str, text: &str) -> AgentEvent {
|
||||
AgentEvent::AssistantMessage {
|
||||
text: text.into(),
|
||||
model: ModelRef::new(provider_ids::openai(), ModelId::new(model)),
|
||||
model: ModelRef::new(builtin::openai(), ModelId::new(model)),
|
||||
usage: TokenCounts::default(),
|
||||
cost: None,
|
||||
tool_call_count: 0,
|
||||
|
|
@ -589,7 +590,7 @@ mod tests {
|
|||
|
||||
fn llm_request_started(stage: &str, model: &str) -> Event {
|
||||
agent_event(stage, AgentEvent::LlmRequestStarted {
|
||||
requested_model: ModelRef::new(provider_ids::anthropic(), ModelId::new(model)),
|
||||
requested_model: ModelRef::new(builtin::anthropic(), ModelId::new(model)),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -605,7 +606,7 @@ mod tests {
|
|||
billing: Some(
|
||||
billed_model_usage_from_llm(
|
||||
&fabro_llm::test_support::test_catalog(),
|
||||
&ModelRef::new(provider_ids::openai(), ModelId::new("gpt-5.4")),
|
||||
&ModelRef::new(builtin::openai(), ModelId::new("gpt-5.4")),
|
||||
TokenCounts {
|
||||
input: 1200,
|
||||
output: 300,
|
||||
|
|
|
|||
|
|
@ -586,7 +586,7 @@ mod tests {
|
|||
ProviderCommand, ProviderNamespace,
|
||||
};
|
||||
use clap::error::ErrorKind;
|
||||
use fabro_types::provider_ids;
|
||||
use lithos_llm::catalog::builtin;
|
||||
use temp_env::with_var;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
|
|
@ -658,7 +658,7 @@ destination = "{destination}"
|
|||
Commands::Provider(ProviderNamespace {
|
||||
command: ProviderCommand::Login(args),
|
||||
}) => {
|
||||
assert_eq!(args.provider, provider_ids::openai());
|
||||
assert_eq!(args.provider, builtin::openai());
|
||||
}
|
||||
_ => panic!("unexpected command variant"),
|
||||
}
|
||||
|
|
@ -672,7 +672,7 @@ destination = "{destination}"
|
|||
Commands::Provider(ProviderNamespace {
|
||||
command: ProviderCommand::Login(args),
|
||||
}) => {
|
||||
assert_eq!(args.provider, provider_ids::anthropic());
|
||||
assert_eq!(args.provider, builtin::anthropic());
|
||||
}
|
||||
_ => panic!("unexpected command variant"),
|
||||
}
|
||||
|
|
@ -693,7 +693,7 @@ destination = "{destination}"
|
|||
Commands::Provider(ProviderNamespace {
|
||||
command: ProviderCommand::Login(args),
|
||||
}) => {
|
||||
assert_eq!(args.provider, provider_ids::anthropic());
|
||||
assert_eq!(args.provider, builtin::anthropic());
|
||||
assert!(args.api_key_stdin);
|
||||
}
|
||||
_ => panic!("unexpected command variant"),
|
||||
|
|
|
|||
|
|
@ -20,9 +20,10 @@ use fabro_auth::{
|
|||
};
|
||||
use fabro_llm::lithos_catalog::{Catalog, CatalogProvider};
|
||||
use fabro_llm::probe::{self, ApiKeyProbeError, ModelTestStatus};
|
||||
use fabro_types::{ProviderId, provider_ids};
|
||||
use fabro_types::ProviderId;
|
||||
use fabro_util::printer::Printer;
|
||||
use fabro_util::terminal::Styles;
|
||||
use lithos_llm::catalog::builtin;
|
||||
use tokio::task::spawn_blocking;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -184,7 +185,7 @@ async fn read_and_validate_api_key(
|
|||
}
|
||||
|
||||
pub(crate) async fn pick_auth_method(provider: &ProviderId) -> Result<AuthMethod> {
|
||||
if provider != &provider_ids::openai() {
|
||||
if provider != &builtin::openai() {
|
||||
return Ok(AuthMethod::ApiKey);
|
||||
}
|
||||
|
||||
|
|
@ -374,9 +375,9 @@ mod tests {
|
|||
fn builtin_api_key_providers_have_key_urls() {
|
||||
let catalog = fabro_llm::default_catalog();
|
||||
for provider in [
|
||||
provider_ids::anthropic(),
|
||||
provider_ids::openai(),
|
||||
provider_ids::gemini(),
|
||||
builtin::anthropic(),
|
||||
builtin::openai(),
|
||||
builtin::gemini(),
|
||||
ProviderId::new("moonshot"),
|
||||
ProviderId::new("zai"),
|
||||
ProviderId::new("minimax"),
|
||||
|
|
@ -408,7 +409,7 @@ mod tests {
|
|||
#[fabro_macros::e2e_test(live("ANTHROPIC_API_KEY"))]
|
||||
async fn validate_api_key_rejects_invalid_key() {
|
||||
let result = validate_api_key(
|
||||
&provider_ids::anthropic(),
|
||||
&builtin::anthropic(),
|
||||
"sk-invalid-key-12345",
|
||||
default_catalog_for_provider_auth(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ fabro-proc = { path = "../../foundation/fabro-proc" }
|
|||
fabro-template = { path = "../../foundation/fabro-template" }
|
||||
fabro-tool = { path = "../../components/fabro-tool" }
|
||||
fabro-types = { path = "../../foundation/fabro-types" }
|
||||
lithos-llm = { workspace = true, features = ["runtime"] }
|
||||
fabro-util = { path = "../../foundation/fabro-util" }
|
||||
fabro-api = { path = "../../foundation/fabro-api" }
|
||||
fabro-client = { path = "../../foundation/fabro-client" }
|
||||
|
|
|
|||
|
|
@ -1495,7 +1495,7 @@ mod runs {
|
|||
EventBody::AgentMessage(AgentMessageProps {
|
||||
text: "I'll start by loading the environment configurations for both production and staging to compare them.".into(),
|
||||
model: fabro_types::ModelRef::new(
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
fabro_types::ModelId::new("claude-opus-4.6"),
|
||||
),
|
||||
billing: BilledTokenCounts::default(),
|
||||
|
|
@ -1571,7 +1571,7 @@ mod runs {
|
|||
EventBody::AgentMessage(AgentMessageProps {
|
||||
text: "I've detected drift in 3 resources between production and staging:\n\n1. **redis.max_connections** — production has 200, staging has 100\n2. **redis.tls** — enabled in production, disabled in staging\n3. **iam.session_duration** — production uses 3600s, staging uses 1800s".into(),
|
||||
model: fabro_types::ModelRef::new(
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
fabro_types::ModelId::new("claude-opus-4.6"),
|
||||
),
|
||||
billing: BilledTokenCounts::default(),
|
||||
|
|
@ -1595,7 +1595,7 @@ mod runs {
|
|||
name: "Detect Drift".into(),
|
||||
},
|
||||
model: Some(billing_model(
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
"claude-opus-4-6",
|
||||
)),
|
||||
billing: BilledTokenCounts {
|
||||
|
|
@ -1617,7 +1617,7 @@ mod runs {
|
|||
name: "Propose Changes".into(),
|
||||
},
|
||||
model: Some(billing_model(
|
||||
fabro_types::provider_ids::gemini(),
|
||||
lithos_llm::catalog::builtin::gemini(),
|
||||
"gemini-3.1-pro-preview",
|
||||
)),
|
||||
billing: BilledTokenCounts {
|
||||
|
|
@ -1639,7 +1639,7 @@ mod runs {
|
|||
name: "Review Changes".into(),
|
||||
},
|
||||
model: Some(billing_model(
|
||||
fabro_types::provider_ids::openai(),
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
"gpt-5.3-codex",
|
||||
)),
|
||||
billing: BilledTokenCounts {
|
||||
|
|
@ -1661,7 +1661,7 @@ mod runs {
|
|||
name: "Apply Changes".into(),
|
||||
},
|
||||
model: Some(billing_model(
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
"claude-opus-4-6",
|
||||
)),
|
||||
billing: BilledTokenCounts {
|
||||
|
|
@ -1700,7 +1700,7 @@ mod runs {
|
|||
total_usd_micros: Some(1_350_000),
|
||||
},
|
||||
model: billing_model(
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
"claude-opus-4-6",
|
||||
),
|
||||
stages: 2,
|
||||
|
|
@ -1716,7 +1716,7 @@ mod runs {
|
|||
total_usd_micros: Some(720_000),
|
||||
},
|
||||
model: billing_model(
|
||||
fabro_types::provider_ids::gemini(),
|
||||
lithos_llm::catalog::builtin::gemini(),
|
||||
"gemini-3.1-pro-preview",
|
||||
),
|
||||
stages: 1,
|
||||
|
|
@ -1731,7 +1731,7 @@ mod runs {
|
|||
total_tokens: 11760,
|
||||
total_usd_micros: Some(190_000),
|
||||
},
|
||||
model: billing_model(fabro_types::provider_ids::openai(), "gpt-5.3-codex"),
|
||||
model: billing_model(lithos_llm::catalog::builtin::openai(), "gpt-5.3-codex"),
|
||||
stages: 1,
|
||||
},
|
||||
],
|
||||
|
|
@ -2108,7 +2108,7 @@ mod billing {
|
|||
total_usd_micros: Some(12_150_000),
|
||||
},
|
||||
model: billing_model(
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
"claude-opus-4-6",
|
||||
),
|
||||
stages: 18,
|
||||
|
|
@ -2124,7 +2124,7 @@ mod billing {
|
|||
total_usd_micros: Some(6_480_000),
|
||||
},
|
||||
model: billing_model(
|
||||
fabro_types::provider_ids::gemini(),
|
||||
lithos_llm::catalog::builtin::gemini(),
|
||||
"gemini-3.1-pro-preview",
|
||||
),
|
||||
stages: 9,
|
||||
|
|
@ -2139,7 +2139,7 @@ mod billing {
|
|||
total_tokens: 105_840,
|
||||
total_usd_micros: Some(1_710_000),
|
||||
},
|
||||
model: billing_model(fabro_types::provider_ids::openai(), "gpt-5.3-codex"),
|
||||
model: billing_model(lithos_llm::catalog::builtin::openai(), "gpt-5.3-codex"),
|
||||
stages: 9,
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -2567,7 +2567,7 @@ mod tests {
|
|||
#[test]
|
||||
fn install_provider_base_url_falls_back_to_catalog_base_url() {
|
||||
let state = InstallAppState::for_test("expected");
|
||||
let provider = install_catalog_provider(&fabro_types::provider_ids::openai()).unwrap();
|
||||
let provider = install_catalog_provider(&lithos_llm::catalog::builtin::openai()).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
provider_base_url_override(&state, provider),
|
||||
|
|
@ -2578,10 +2578,10 @@ mod tests {
|
|||
#[test]
|
||||
fn install_provider_base_url_prefers_state_override() {
|
||||
let state = InstallAppState::for_test("expected").with_provider_base_url(
|
||||
fabro_types::provider_ids::openai(),
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
"https://proxy.example.com/v1",
|
||||
);
|
||||
let provider = install_catalog_provider(&fabro_types::provider_ids::openai()).unwrap();
|
||||
let provider = install_catalog_provider(&lithos_llm::catalog::builtin::openai()).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
provider_base_url_override(&state, provider),
|
||||
|
|
|
|||
|
|
@ -2017,7 +2017,7 @@ enabled = {clone_enabled}
|
|||
prepared.settings.clone(),
|
||||
validated.graph(),
|
||||
test_catalog().as_ref(),
|
||||
&[fabro_types::provider_ids::anthropic()],
|
||||
&[lithos_llm::catalog::builtin::anthropic()],
|
||||
)
|
||||
.unwrap()
|
||||
.run;
|
||||
|
|
|
|||
|
|
@ -195,7 +195,8 @@ mod tests {
|
|||
use fabro_llm::adapter::{ProviderAdapter, ResolvedCall};
|
||||
use fabro_llm::lithos_catalog::AdapterId;
|
||||
use fabro_llm::{Error as LlmError, Response, ResponseStream};
|
||||
use fabro_types::{RunId, provider_ids};
|
||||
use fabro_types::RunId;
|
||||
use lithos_llm::catalog::builtin;
|
||||
use toml::Value as TomlValue;
|
||||
|
||||
use super::*;
|
||||
|
|
@ -358,7 +359,7 @@ mod tests {
|
|||
let title = generate_title_or_current(GenerateTitleInput {
|
||||
client,
|
||||
model_id: "gpt-5.4".to_string(),
|
||||
provider_id: provider_ids::openai(),
|
||||
provider_id: builtin::openai(),
|
||||
prompt: TitlePromptInput {
|
||||
run_id: &run_id,
|
||||
current_title: "Current",
|
||||
|
|
|
|||
|
|
@ -1574,7 +1574,7 @@ enabled = true
|
|||
#[test]
|
||||
fn canonical_session_model_uses_readiness_priority_and_explicit_pins() {
|
||||
let catalog = portable_session_catalog();
|
||||
let openai = fabro_types::provider_ids::openai();
|
||||
let openai = lithos_llm::catalog::builtin::openai();
|
||||
let openrouter = ProviderId::new("openrouter");
|
||||
|
||||
assert_eq!(
|
||||
|
|
@ -1621,7 +1621,7 @@ enabled = true
|
|||
#[test]
|
||||
fn canonical_session_model_preserves_unknown_passthrough_on_selected_provider() {
|
||||
let catalog = portable_session_catalog();
|
||||
let openai = fabro_types::provider_ids::openai();
|
||||
let openai = lithos_llm::catalog::builtin::openai();
|
||||
let openrouter = ProviderId::new("openrouter");
|
||||
let both = std::collections::HashSet::from([openai.clone(), openrouter.clone()]);
|
||||
|
||||
|
|
@ -1641,7 +1641,7 @@ enabled = true
|
|||
#[test]
|
||||
fn canonical_session_model_passes_through_colon_bearing_model_ids() {
|
||||
let catalog = portable_session_catalog();
|
||||
let openai = fabro_types::provider_ids::openai();
|
||||
let openai = lithos_llm::catalog::builtin::openai();
|
||||
let openrouter = ProviderId::new("openrouter");
|
||||
let both = std::collections::HashSet::from([openai.clone(), openrouter.clone()]);
|
||||
|
||||
|
|
@ -1666,7 +1666,7 @@ enabled = true
|
|||
let catalog = portable_session_catalog();
|
||||
let error = canonical_session_model(
|
||||
&catalog,
|
||||
&std::collections::HashSet::from([fabro_types::provider_ids::openai()]),
|
||||
&std::collections::HashSet::from([lithos_llm::catalog::builtin::openai()]),
|
||||
Some("gpt-56-sol"),
|
||||
Some(&ProviderId::new("openrouter")),
|
||||
)
|
||||
|
|
@ -1678,7 +1678,7 @@ enabled = true
|
|||
#[test]
|
||||
fn canonical_session_model_normalizes_legacy_builtin_selector_before_qualification() {
|
||||
let catalog = portable_session_catalog();
|
||||
let openai = fabro_types::provider_ids::openai();
|
||||
let openai = lithos_llm::catalog::builtin::openai();
|
||||
let openrouter = ProviderId::new("openrouter");
|
||||
let both = std::collections::HashSet::from([openai.clone(), openrouter.clone()]);
|
||||
|
||||
|
|
@ -1732,7 +1732,7 @@ enabled = true
|
|||
&catalog,
|
||||
&catalog.enabled_provider_ids().into_iter().collect(),
|
||||
Some("openrouter:gpt-56-sol"),
|
||||
Some(&fabro_types::provider_ids::openai()),
|
||||
Some(&lithos_llm::catalog::builtin::openai()),
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
|
|
|
|||
|
|
@ -1787,7 +1787,7 @@ async fn resolve_llm_client_reads_openai_token_from_vault() {
|
|||
let llm_result = state.resolve_llm_client().await.unwrap();
|
||||
|
||||
assert_eq!(llm_result.provider_ids(), vec![
|
||||
fabro_types::provider_ids::openai()
|
||||
lithos_llm::catalog::builtin::openai()
|
||||
]);
|
||||
assert!(llm_result.auth_issues.is_empty());
|
||||
}
|
||||
|
|
@ -1861,7 +1861,7 @@ async fn llm_source_configured_providers_reads_openai_token_from_vault() {
|
|||
.unwrap();
|
||||
|
||||
assert_eq!(state.configured_llm_provider_ids().await, vec![
|
||||
fabro_types::provider_ids::openai()
|
||||
lithos_llm::catalog::builtin::openai()
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -6121,7 +6121,7 @@ fn context_window_event(
|
|||
event: fabro_agent::AgentEvent::AssistantMessage {
|
||||
text: "assistant response".to_string(),
|
||||
model: ModelRef::new(
|
||||
fabro_types::provider_ids::openai(),
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
ModelId::new("gpt-5.4"),
|
||||
),
|
||||
usage: TokenCounts::default(),
|
||||
|
|
@ -7201,7 +7201,10 @@ fn test_billed_usage(
|
|||
output_tokens: u64,
|
||||
) -> fabro_types::BilledModelUsage {
|
||||
let mut usage = fabro_types::BilledModelUsage::new(
|
||||
ModelRef::new(fabro_types::provider_ids::openai(), ModelId::new(model_id)),
|
||||
ModelRef::new(
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
ModelId::new(model_id),
|
||||
),
|
||||
TokenCounts {
|
||||
input: input_tokens,
|
||||
output: output_tokens,
|
||||
|
|
@ -16768,7 +16771,7 @@ async fn get_aggregate_billing_returns_provider_model_speed_identity() {
|
|||
agg.total_runs = 1;
|
||||
agg.by_model.insert(
|
||||
ModelRef::new(
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
ModelId::new("claude-opus-4-6"),
|
||||
),
|
||||
ModelBillingTotals {
|
||||
|
|
@ -16786,7 +16789,7 @@ async fn get_aggregate_billing_returns_provider_model_speed_identity() {
|
|||
);
|
||||
agg.by_model.insert(
|
||||
ModelRef::new(
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
ModelId::new("claude-opus-4-6"),
|
||||
)
|
||||
.with_speed(Some(Speed::Fast)),
|
||||
|
|
@ -16846,7 +16849,10 @@ async fn get_aggregate_billing_saturates_total_cost_across_models() {
|
|||
.expect("aggregate billing lock");
|
||||
for (model_id, total_usd_micros) in [("maximum", i64::MAX), ("one", 1)] {
|
||||
agg.by_model.insert(
|
||||
ModelRef::new(fabro_types::provider_ids::openai(), ModelId::new(model_id)),
|
||||
ModelRef::new(
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
ModelId::new(model_id),
|
||||
),
|
||||
ModelBillingTotals {
|
||||
stages: 1,
|
||||
billing: BilledTokenCounts {
|
||||
|
|
@ -16891,7 +16897,7 @@ fn aggregate_billing_counts_projection_rollup_usage_visits() {
|
|||
by_model: vec![
|
||||
fabro_workflow::ProjectionBillingByModel {
|
||||
model: ModelRef::new(
|
||||
fabro_types::provider_ids::openai(),
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
ModelId::new("gpt-5.4"),
|
||||
),
|
||||
stages: 1,
|
||||
|
|
@ -16907,7 +16913,7 @@ fn aggregate_billing_counts_projection_rollup_usage_visits() {
|
|||
},
|
||||
fabro_workflow::ProjectionBillingByModel {
|
||||
model: ModelRef::new(
|
||||
fabro_types::provider_ids::openai(),
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
ModelId::new("gpt-5.4"),
|
||||
)
|
||||
.with_speed(Some(Speed::Fast)),
|
||||
|
|
@ -16933,21 +16939,25 @@ fn aggregate_billing_counts_projection_rollup_usage_visits() {
|
|||
assert_eq!(accumulator.total_timing.wall_time_ms, 2000);
|
||||
assert_eq!(accumulator.by_model.len(), 2);
|
||||
assert_eq!(
|
||||
accumulator.by_model
|
||||
[&ModelRef::new(fabro_types::provider_ids::openai(), ModelId::new("gpt-5.4"))]
|
||||
accumulator.by_model[&ModelRef::new(
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
ModelId::new("gpt-5.4")
|
||||
)]
|
||||
.stages,
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
accumulator.by_model
|
||||
[&ModelRef::new(fabro_types::provider_ids::openai(), ModelId::new("gpt-5.4"))]
|
||||
accumulator.by_model[&ModelRef::new(
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
ModelId::new("gpt-5.4")
|
||||
)]
|
||||
.billing
|
||||
.input_tokens,
|
||||
100
|
||||
);
|
||||
assert_eq!(
|
||||
accumulator.by_model[&ModelRef::new(
|
||||
fabro_types::provider_ids::openai(),
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
ModelId::new("gpt-5.4")
|
||||
)
|
||||
.with_speed(Some(Speed::Fast))]
|
||||
|
|
@ -16956,7 +16966,7 @@ fn aggregate_billing_counts_projection_rollup_usage_visits() {
|
|||
);
|
||||
assert_eq!(
|
||||
accumulator.by_model[&ModelRef::new(
|
||||
fabro_types::provider_ids::openai(),
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
ModelId::new("gpt-5.4")
|
||||
)
|
||||
.with_speed(Some(Speed::Fast))]
|
||||
|
|
@ -18300,7 +18310,7 @@ async fn attach_stream_replays_agent_message_reasoning() {
|
|||
event: fabro_agent::AgentEvent::AssistantMessage {
|
||||
text: String::new(),
|
||||
model: ModelRef::new(
|
||||
fabro_types::provider_ids::openai(),
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
ModelId::new("gpt-5.4"),
|
||||
),
|
||||
usage: TokenCounts::default(),
|
||||
|
|
|
|||
|
|
@ -1416,7 +1416,7 @@ async fn install_validation_endpoints_validate_credentials_and_github_token() {
|
|||
let app = build_install_router(
|
||||
InstallAppState::for_test("test-install-token")
|
||||
.with_provider_base_url(
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
format!("{}/v1", llm_mock.url("")),
|
||||
)
|
||||
.with_github_api_base_url(github_mock.url("")),
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ fn test_app_with_openai_agent_backend(openai_base_url: String, api_key: String)
|
|||
Some(Box::new(
|
||||
fabro_workflow::handler::llm::AgentApiBackend::new_with_catalog(
|
||||
OPENAI_AGENT_MODEL.to_string(),
|
||||
fabro_types::provider_ids::openai(),
|
||||
lithos_llm::catalog::builtin::openai(),
|
||||
fabro_workflow::model_fallback::ModelFallbackPolicy::default(),
|
||||
Arc::clone(&llm_source),
|
||||
Arc::clone(&steering_hub),
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ anyhow.workspace = true
|
|||
fabro-auth = { path = "../../foundation/fabro-auth" }
|
||||
fabro-config = { path = "../../foundation/fabro-config", features = ["clap"] }
|
||||
fabro-types = { path = "../../foundation/fabro-types", features = ["clap"] }
|
||||
lithos-llm = { workspace = true, features = ["runtime"] }
|
||||
fabro-llm = { path = "../fabro-llm" }
|
||||
fabro-mcp = { path = "../fabro-mcp" }
|
||||
fabro-sandbox = { path = "../fabro-sandbox" }
|
||||
|
|
|
|||
|
|
@ -91,7 +91,8 @@ pub trait AgentProfile: Send + Sync {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use fabro_types::{AgentProfileKind, provider_ids};
|
||||
use fabro_types::AgentProfileKind;
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::*;
|
||||
use crate::test_support::{MockSandbox, TestProfile};
|
||||
|
|
@ -100,7 +101,7 @@ mod tests {
|
|||
fn profile_provider_and_model() {
|
||||
let profile = TestProfile::new();
|
||||
assert_eq!(profile.profile_kind(), AgentProfileKind::Anthropic);
|
||||
assert_eq!(profile.provider_id(), provider_ids::anthropic());
|
||||
assert_eq!(profile.provider_id(), builtin::anthropic());
|
||||
assert_eq!(profile.model(), "mock-model");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -822,7 +822,7 @@ mod tests {
|
|||
use fabro_llm::test_support::{
|
||||
client_with_adapters, test_catalog as fabro_test_catalog, test_catalog_with_overlay,
|
||||
};
|
||||
use fabro_types::provider_ids;
|
||||
use lithos_llm::catalog::builtin;
|
||||
use serde_json::json;
|
||||
|
||||
use super::*;
|
||||
|
|
@ -1027,7 +1027,7 @@ profile = "openai"
|
|||
#[test]
|
||||
fn ensure_provider_registered_reports_missing_credentials() {
|
||||
let client = client_with_adapters(Vec::new(), ClientOptions::default());
|
||||
let error = ensure_provider_registered(&client, &provider_ids::anthropic()).unwrap_err();
|
||||
let error = ensure_provider_registered(&client, &builtin::anthropic()).unwrap_err();
|
||||
assert_eq!(
|
||||
error.to_string(),
|
||||
"LLM credentials not configured for provider 'anthropic'"
|
||||
|
|
@ -1098,9 +1098,9 @@ profile = "openai"
|
|||
#[test]
|
||||
fn summarizer_model_id_prefers_the_provider_small_default() {
|
||||
let catalog = test_catalog();
|
||||
let model_id = summarizer_model_id(&provider_ids::openai(), &catalog, "gpt-5.4");
|
||||
let model_id = summarizer_model_id(&builtin::openai(), &catalog, "gpt-5.4");
|
||||
|
||||
assert_eq!(model_id.provider(), &provider_ids::openai());
|
||||
assert_eq!(model_id.provider(), &builtin::openai());
|
||||
assert_eq!(model_id.model().as_str(), "gpt-5.4-mini");
|
||||
}
|
||||
|
||||
|
|
@ -1110,7 +1110,7 @@ profile = "openai"
|
|||
fn build_profile_can_register_subagent_tools() {
|
||||
let mut profile = AgentProfileBuilder::new(
|
||||
AgentProfileKind::Anthropic,
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
"model",
|
||||
test_catalog(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -86,8 +86,8 @@ mod tests {
|
|||
use std::time::Duration;
|
||||
|
||||
use fabro_llm::{ErrorKind, RetryClassification};
|
||||
use fabro_types::provider_ids;
|
||||
use fabro_util::error;
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -180,7 +180,7 @@ mod tests {
|
|||
fn serde_roundtrip_llm_provider() {
|
||||
let err = Error::from(ErrorData::from(
|
||||
fabro_llm::Error::new(ErrorKind::RateLimit, "too fast")
|
||||
.with_provider(provider_ids::openai())
|
||||
.with_provider(builtin::openai())
|
||||
.with_status(429)
|
||||
.with_retry(RetryClassification::after(Duration::from_secs(2))),
|
||||
));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use fabro_llm::lithos_catalog::Catalog;
|
||||
use fabro_types::{AgentProfileKind, ProviderId, provider_ids};
|
||||
use fabro_types::{AgentProfileKind, ProviderId};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::EnvContext;
|
||||
use crate::agent_profile::AgentProfile;
|
||||
|
|
@ -48,7 +49,7 @@ impl AnthropicProfile {
|
|||
Self {
|
||||
base: BaseProfile {
|
||||
profile_kind: AgentProfileKind::Anthropic,
|
||||
provider_id: provider_ids::anthropic(),
|
||||
provider_id: builtin::anthropic(),
|
||||
model: model.into(),
|
||||
catalog: None,
|
||||
registry,
|
||||
|
|
@ -116,7 +117,7 @@ mod tests {
|
|||
fn anthropic_profile_identity() {
|
||||
let profile = AnthropicProfile::new("claude-sonnet-4-20250514");
|
||||
assert_eq!(profile.profile_kind(), AgentProfileKind::Anthropic);
|
||||
assert_eq!(profile.provider_id(), provider_ids::anthropic());
|
||||
assert_eq!(profile.provider_id(), builtin::anthropic());
|
||||
assert_eq!(profile.model(), "claude-sonnet-4-20250514");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use fabro_llm::lithos_catalog::Catalog;
|
||||
use fabro_types::{AgentProfileKind, ProviderId, provider_ids};
|
||||
use fabro_types::{AgentProfileKind, ProviderId};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::EnvContext;
|
||||
use crate::agent_profile::AgentProfile;
|
||||
|
|
@ -65,7 +66,7 @@ impl Claude5Profile {
|
|||
Self {
|
||||
base: BaseProfile {
|
||||
profile_kind: AgentProfileKind::Claude5,
|
||||
provider_id: provider_ids::anthropic(),
|
||||
provider_id: builtin::anthropic(),
|
||||
model: model.into(),
|
||||
catalog: None,
|
||||
registry,
|
||||
|
|
@ -166,7 +167,7 @@ mod tests {
|
|||
fn profile_identity() {
|
||||
let profile = Claude5Profile::new("claude-fable-5");
|
||||
assert_eq!(profile.profile_kind(), AgentProfileKind::Claude5);
|
||||
assert_eq!(profile.provider_id(), provider_ids::anthropic());
|
||||
assert_eq!(profile.provider_id(), builtin::anthropic());
|
||||
assert_eq!(profile.model(), "claude-fable-5");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use fabro_llm::lithos_catalog::Catalog;
|
||||
use fabro_types::{AgentProfileKind, ProviderId, provider_ids};
|
||||
use fabro_types::{AgentProfileKind, ProviderId};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::EnvContext;
|
||||
use crate::agent_profile::AgentProfile;
|
||||
|
|
@ -42,7 +43,7 @@ impl GeminiProfile {
|
|||
Self {
|
||||
base: BaseProfile {
|
||||
profile_kind: AgentProfileKind::Gemini,
|
||||
provider_id: provider_ids::gemini(),
|
||||
provider_id: builtin::gemini(),
|
||||
model: model.into(),
|
||||
catalog: None,
|
||||
registry,
|
||||
|
|
@ -108,7 +109,7 @@ mod tests {
|
|||
fn gemini_profile_identity() {
|
||||
let profile = GeminiProfile::new("gemini-2.0-flash");
|
||||
assert_eq!(profile.profile_kind(), AgentProfileKind::Gemini);
|
||||
assert_eq!(profile.provider_id(), provider_ids::gemini());
|
||||
assert_eq!(profile.provider_id(), builtin::gemini());
|
||||
assert_eq!(profile.model(), "gemini-2.0-flash");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use fabro_llm::lithos_catalog::Catalog;
|
||||
use fabro_types::{AgentProfileKind, ProviderId, ToolDefinition, provider_ids};
|
||||
use fabro_types::{AgentProfileKind, ProviderId, ToolDefinition};
|
||||
use lithos_llm::catalog::builtin;
|
||||
use serde_json::Value;
|
||||
|
||||
use super::EnvContext;
|
||||
|
|
@ -69,7 +70,7 @@ impl Gpt56Profile {
|
|||
Self {
|
||||
base: BaseProfile {
|
||||
profile_kind: AgentProfileKind::Gpt56,
|
||||
provider_id: provider_ids::openai(),
|
||||
provider_id: builtin::openai(),
|
||||
model: model.into(),
|
||||
catalog: None,
|
||||
registry,
|
||||
|
|
@ -252,7 +253,7 @@ enabled = true
|
|||
fn gpt56_profile_identity() {
|
||||
let profile = Gpt56Profile::new("gpt-5.6-sol");
|
||||
assert_eq!(profile.profile_kind(), AgentProfileKind::Gpt56);
|
||||
assert_eq!(profile.provider_id(), provider_ids::openai());
|
||||
assert_eq!(profile.provider_id(), builtin::openai());
|
||||
assert_eq!(profile.model(), "gpt-5.6-sol");
|
||||
}
|
||||
|
||||
|
|
@ -327,8 +328,7 @@ enabled = true
|
|||
/// it points 5.6 at a tool it was never given.
|
||||
#[test]
|
||||
fn shell_description_names_the_editor_actually_registered() {
|
||||
let direct =
|
||||
Gpt56Profile::new("gpt-5.6-sol").with_route(provider_ids::openai(), test_catalog());
|
||||
let direct = Gpt56Profile::new("gpt-5.6-sol").with_route(builtin::openai(), test_catalog());
|
||||
let shell = direct.tool_registry().get("shell_command").unwrap();
|
||||
assert!(shell.definition.description.contains("`apply_patch`"));
|
||||
assert!(!shell.definition.description.contains("`edit_file`"));
|
||||
|
|
@ -349,8 +349,7 @@ enabled = true
|
|||
assert!(!rendered.contains("apply_patch"));
|
||||
assert!(!rendered.contains("*** Begin Patch"));
|
||||
|
||||
let direct =
|
||||
Gpt56Profile::new("gpt-5.6-sol").with_route(provider_ids::openai(), test_catalog());
|
||||
let direct = Gpt56Profile::new("gpt-5.6-sol").with_route(builtin::openai(), test_catalog());
|
||||
let rendered = prompt(&direct);
|
||||
assert!(rendered.contains("Use `apply_patch` for local file edits"));
|
||||
assert!(rendered.contains("*** Begin Patch"));
|
||||
|
|
@ -427,8 +426,7 @@ enabled = true
|
|||
|
||||
#[test]
|
||||
fn provider_prompt_uses_catalog_display_name() {
|
||||
let direct =
|
||||
Gpt56Profile::new("gpt-5.6-sol").with_route(provider_ids::openai(), test_catalog());
|
||||
let direct = Gpt56Profile::new("gpt-5.6-sol").with_route(builtin::openai(), test_catalog());
|
||||
assert!(prompt(&direct).contains("powered by OpenAI"));
|
||||
|
||||
let gateway = Gpt56Profile::new("gpt-5.6-sol")
|
||||
|
|
@ -465,7 +463,7 @@ enabled = true
|
|||
#[test]
|
||||
fn catalog_reports_the_5_6_context_window() {
|
||||
let profile =
|
||||
Gpt56Profile::new("gpt-5.6-sol").with_route(provider_ids::openai(), test_catalog());
|
||||
Gpt56Profile::new("gpt-5.6-sol").with_route(builtin::openai(), test_catalog());
|
||||
assert_eq!(profile.context_window_size(), 1_050_000);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ use std::collections::HashMap;
|
|||
use std::sync::Arc;
|
||||
|
||||
use fabro_llm::lithos_catalog::Catalog;
|
||||
#[cfg(test)]
|
||||
use fabro_types::provider_ids;
|
||||
use fabro_types::{AgentProfileKind, ProviderId};
|
||||
#[cfg(test)]
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
pub mod anthropic;
|
||||
pub mod claude5;
|
||||
|
|
@ -701,31 +701,23 @@ mod tests {
|
|||
let catalog = Arc::new(test_catalog());
|
||||
let env = MockSandbox::linux();
|
||||
let cases = [
|
||||
(
|
||||
AgentProfileKind::OpenAi,
|
||||
provider_ids::openai(),
|
||||
"gpt-5.4-mini",
|
||||
),
|
||||
(AgentProfileKind::OpenAi, builtin::openai(), "gpt-5.4-mini"),
|
||||
(
|
||||
AgentProfileKind::Anthropic,
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
"claude-haiku-4-5",
|
||||
),
|
||||
(
|
||||
AgentProfileKind::Gemini,
|
||||
provider_ids::gemini(),
|
||||
builtin::gemini(),
|
||||
"gemini-3-flash-preview",
|
||||
),
|
||||
(
|
||||
AgentProfileKind::Claude5,
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
"claude-sonnet-5",
|
||||
),
|
||||
(
|
||||
AgentProfileKind::Gpt56,
|
||||
provider_ids::openai(),
|
||||
"gpt-5.6-sol",
|
||||
),
|
||||
(AgentProfileKind::Gpt56, builtin::openai(), "gpt-5.6-sol"),
|
||||
];
|
||||
|
||||
for (profile_kind, provider_id, model) in cases {
|
||||
|
|
@ -782,7 +774,7 @@ mod tests {
|
|||
) {
|
||||
let builder = AgentProfileBuilder::new(
|
||||
profile_kind,
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
model,
|
||||
Arc::new(test_catalog()),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use fabro_llm::lithos_catalog::Catalog;
|
||||
use fabro_types::{AgentProfileKind, ProviderId, provider_ids};
|
||||
use fabro_types::{AgentProfileKind, ProviderId};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::EnvContext;
|
||||
use crate::agent_profile::AgentProfile;
|
||||
|
|
@ -43,7 +44,7 @@ impl OpenAiProfile {
|
|||
Self {
|
||||
base: BaseProfile {
|
||||
profile_kind: AgentProfileKind::OpenAi,
|
||||
provider_id: provider_ids::openai(),
|
||||
provider_id: builtin::openai(),
|
||||
model: model.into(),
|
||||
catalog: None,
|
||||
registry,
|
||||
|
|
@ -117,7 +118,7 @@ mod tests {
|
|||
fn openai_profile_identity() {
|
||||
let profile = OpenAiProfile::new("o3-mini");
|
||||
assert_eq!(profile.profile_kind(), AgentProfileKind::OpenAi);
|
||||
assert_eq!(profile.provider_id(), provider_ids::openai());
|
||||
assert_eq!(profile.provider_id(), builtin::openai());
|
||||
assert_eq!(profile.model(), "o3-mini");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2250,9 +2250,10 @@ mod tests {
|
|||
use fabro_llm::{ErrorKind, ResponseStream, RetryPolicy};
|
||||
use fabro_types::{
|
||||
ContentPart, Cost, CostSource, ReasoningOutput, StageContextWindowCountMethod,
|
||||
ToolDefinition, provider_ids, text_of, tool_result_to_json,
|
||||
ToolDefinition, text_of, tool_result_to_json,
|
||||
};
|
||||
use futures::stream;
|
||||
use lithos_llm::catalog::builtin;
|
||||
use tokio::time::{sleep, timeout};
|
||||
|
||||
use super::*;
|
||||
|
|
@ -2386,7 +2387,7 @@ mod tests {
|
|||
impl ScriptedError {
|
||||
fn build(&self) -> fabro_llm::Error {
|
||||
fabro_llm::Error::new(self.kind.clone(), self.message.clone())
|
||||
.with_provider(provider_ids::anthropic())
|
||||
.with_provider(builtin::anthropic())
|
||||
.with_retry(self.retry)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,8 @@ use fabro_llm::{
|
|||
Client, ClientOptions, Error as LlmError, FinishReason, Request, Response, ResponseStream,
|
||||
};
|
||||
pub use fabro_sandbox::test_support::{MockSandbox, MutableMockSandbox};
|
||||
use fabro_types::{
|
||||
AgentProfileKind, ContentPart, ModelId, ProviderId, TokenCounts, ToolCall, provider_ids,
|
||||
};
|
||||
use fabro_types::{AgentProfileKind, ContentPart, ModelId, ProviderId, TokenCounts, ToolCall};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use crate::agent_profile::AgentProfile;
|
||||
use crate::config::SessionOptions;
|
||||
|
|
@ -24,7 +23,7 @@ use crate::skills::{Skill, format_skills_prompt_section};
|
|||
use crate::tool_registry::{RegisteredTool, ToolRegistry, ToolSource};
|
||||
|
||||
/// The provider every test profile routes to.
|
||||
pub const TEST_PROVIDER: &str = provider_ids::ANTHROPIC;
|
||||
pub const TEST_PROVIDER: &str = builtin::ids::ANTHROPIC;
|
||||
/// The model every test profile requests. It is not in the catalog, so the
|
||||
/// provider's passthrough route serves it.
|
||||
pub const TEST_MODEL: &str = "mock-model";
|
||||
|
|
@ -65,7 +64,7 @@ impl AgentProfile for TestProfile {
|
|||
}
|
||||
|
||||
fn provider_id(&self) -> ProviderId {
|
||||
provider_ids::anthropic()
|
||||
builtin::anthropic()
|
||||
}
|
||||
|
||||
fn model(&self) -> &'static str {
|
||||
|
|
|
|||
|
|
@ -732,7 +732,8 @@ mod tests {
|
|||
use std::collections::HashMap;
|
||||
|
||||
use fabro_llm::adapter::ProviderAdapter;
|
||||
use fabro_types::{CommandTermination, ModelId, provider_ids};
|
||||
use fabro_types::{CommandTermination, ModelId};
|
||||
use lithos_llm::catalog::builtin;
|
||||
use tokio::sync::broadcast;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
|
|
@ -1978,7 +1979,7 @@ mod tests {
|
|||
let client = make_client(provider).await;
|
||||
let summarizer = WebFetchSummarizer {
|
||||
client,
|
||||
model_id: ModelHandle::new(provider_ids::anthropic(), ModelId::new("mock-model")),
|
||||
model_id: ModelHandle::new(builtin::anthropic(), ModelId::new("mock-model")),
|
||||
};
|
||||
|
||||
let tool = make_web_fetch_tool(Some(summarizer));
|
||||
|
|
@ -2075,7 +2076,7 @@ mod tests {
|
|||
|
||||
let summarizer = WebFetchSummarizer {
|
||||
client,
|
||||
model_id: ModelHandle::new(provider_ids::anthropic(), ModelId::new("target-model")),
|
||||
model_id: ModelHandle::new(builtin::anthropic(), ModelId::new("target-model")),
|
||||
};
|
||||
|
||||
let tool = make_web_fetch_tool(Some(summarizer));
|
||||
|
|
|
|||
|
|
@ -817,7 +817,8 @@ pub struct SessionEvent {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use fabro_llm::{ErrorKind, RetryClassification};
|
||||
use fabro_types::{CostSource, ModelId, ProviderId, provider_ids};
|
||||
use fabro_types::{CostSource, ModelId, ProviderId};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -1102,7 +1103,7 @@ mod tests {
|
|||
};
|
||||
let event = AgentEvent::AssistantMessage {
|
||||
text: "Hello".into(),
|
||||
model: ModelRef::new(provider_ids::openai(), ModelId::new("test-model")),
|
||||
model: ModelRef::new(builtin::openai(), ModelId::new("test-model")),
|
||||
usage,
|
||||
cost: Some(Cost {
|
||||
usd_micros: 125_000,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ use fabro_llm::lithos_catalog::Catalog;
|
|||
use fabro_llm::test_support::client_from_env;
|
||||
use fabro_llm::{Client, ClientOptions, catalog};
|
||||
use fabro_test::{EnvVars, TwinScenario, TwinScenarios, TwinToolCall, twin_openai};
|
||||
use fabro_types::{ModelHandle, ModelId, ProviderId, provider_ids};
|
||||
use fabro_types::{ModelHandle, ModelId, ProviderId};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
type Provider = ProviderId;
|
||||
|
||||
|
|
@ -30,11 +31,11 @@ struct OpenAiTwinOptions {
|
|||
|
||||
fn summarizer_model_id(provider: &Provider) -> ModelHandle {
|
||||
let (provider, model) = match provider.as_str() {
|
||||
provider_ids::OPENAI | "moonshot" | "zai" | "minimax" | "inception" => {
|
||||
(provider_ids::openai(), "gpt-5.4-mini")
|
||||
builtin::ids::OPENAI | "moonshot" | "zai" | "minimax" | "inception" => {
|
||||
(builtin::openai(), "gpt-5.4-mini")
|
||||
}
|
||||
provider_ids::GEMINI => (provider_ids::gemini(), "gemini-3-flash-preview"),
|
||||
provider_ids::ANTHROPIC => (provider_ids::anthropic(), "claude-haiku-4.5"),
|
||||
builtin::ids::GEMINI => (builtin::gemini(), "gemini-3-flash-preview"),
|
||||
builtin::ids::ANTHROPIC => (builtin::anthropic(), "claude-haiku-4.5"),
|
||||
other => panic!("unexpected provider {other}"),
|
||||
};
|
||||
ModelHandle::new(provider, ModelId::new(model))
|
||||
|
|
@ -142,7 +143,7 @@ fn twin_catalog(base_url: &str, overlay: &str) -> Catalog {
|
|||
}
|
||||
|
||||
async fn make_client(provider: &Provider, twin: Option<&OpenAiTwinOptions>) -> Client {
|
||||
if provider == &provider_ids::openai() && fabro_test::TestMode::from_env().is_twin() {
|
||||
if provider == &builtin::openai() && fabro_test::TestMode::from_env().is_twin() {
|
||||
return make_twin_client(twin.expect("openai twin config should be provided")).await;
|
||||
}
|
||||
|
||||
|
|
@ -261,7 +262,7 @@ macro_rules! openai_twin_provider_test {
|
|||
.await;
|
||||
}
|
||||
let mut session = make_session(
|
||||
provider_ids::openai(),
|
||||
builtin::openai(),
|
||||
"gpt-5.4-mini",
|
||||
tmp.path(),
|
||||
ToolSecrets::default(),
|
||||
|
|
@ -278,14 +279,14 @@ macro_rules! provider_tests {
|
|||
($scenario:ident) => {
|
||||
provider_test!(
|
||||
$scenario,
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
"claude-haiku-4.5",
|
||||
anthropic,
|
||||
keys = ["ANTHROPIC_API_KEY"]
|
||||
);
|
||||
provider_test!(
|
||||
$scenario,
|
||||
provider_ids::gemini(),
|
||||
builtin::gemini(),
|
||||
"gemini-3-flash-preview",
|
||||
gemini,
|
||||
keys = ["GEMINI_API_KEY"]
|
||||
|
|
@ -406,21 +407,21 @@ provider_tests!(subagent_spawn);
|
|||
|
||||
provider_test!(
|
||||
web_fetch,
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
"claude-haiku-4-5",
|
||||
anthropic,
|
||||
keys = ["ANTHROPIC_API_KEY"]
|
||||
);
|
||||
provider_test!(
|
||||
web_fetch,
|
||||
provider_ids::openai(),
|
||||
builtin::openai(),
|
||||
"gpt-5.4-mini",
|
||||
openai,
|
||||
keys = ["OPENAI_API_KEY"]
|
||||
);
|
||||
provider_test!(
|
||||
web_fetch,
|
||||
provider_ids::gemini(),
|
||||
builtin::gemini(),
|
||||
"gemini-3-flash-preview",
|
||||
gemini,
|
||||
keys = ["GEMINI_API_KEY"]
|
||||
|
|
@ -457,19 +458,19 @@ provider_test!(
|
|||
);
|
||||
|
||||
web_search_provider_test!(
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
"claude-haiku-4-5",
|
||||
anthropic,
|
||||
keys = ["ANTHROPIC_API_KEY", "BRAVE_SEARCH_API_KEY"]
|
||||
);
|
||||
web_search_provider_test!(
|
||||
provider_ids::openai(),
|
||||
builtin::openai(),
|
||||
"gpt-5.4-mini",
|
||||
openai,
|
||||
keys = ["OPENAI_API_KEY", "BRAVE_SEARCH_API_KEY"]
|
||||
);
|
||||
web_search_provider_test!(
|
||||
provider_ids::gemini(),
|
||||
builtin::gemini(),
|
||||
"gemini-3-flash-preview",
|
||||
gemini,
|
||||
keys = ["GEMINI_API_KEY", "BRAVE_SEARCH_API_KEY"]
|
||||
|
|
@ -518,14 +519,14 @@ macro_rules! non_openai_provider_tests {
|
|||
($scenario:ident) => {
|
||||
provider_test!(
|
||||
$scenario,
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
"claude-haiku-4.5",
|
||||
anthropic,
|
||||
keys = ["ANTHROPIC_API_KEY"]
|
||||
);
|
||||
provider_test!(
|
||||
$scenario,
|
||||
provider_ids::gemini(),
|
||||
builtin::gemini(),
|
||||
"gemini-3-flash-preview",
|
||||
gemini,
|
||||
keys = ["GEMINI_API_KEY"]
|
||||
|
|
@ -800,7 +801,7 @@ macro_rules! reasoning_effort_tests {
|
|||
}
|
||||
|
||||
reasoning_effort_tests!(
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
"claude-haiku-4.5",
|
||||
anthropic_reasoning_effort,
|
||||
keys = ["ANTHROPIC_API_KEY"]
|
||||
|
|
@ -808,7 +809,7 @@ reasoning_effort_tests!(
|
|||
// gpt-5-mini does not support the reasoning.effort parameter, so no OpenAI
|
||||
// test.
|
||||
reasoning_effort_tests!(
|
||||
provider_ids::gemini(),
|
||||
builtin::gemini(),
|
||||
"gemini-3-flash-preview",
|
||||
gemini_reasoning_effort,
|
||||
keys = ["GEMINI_API_KEY"]
|
||||
|
|
@ -878,19 +879,19 @@ macro_rules! loop_detection_tests {
|
|||
}
|
||||
|
||||
loop_detection_tests!(
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
"claude-haiku-4-5",
|
||||
anthropic_loop_detection,
|
||||
keys = ["ANTHROPIC_API_KEY"]
|
||||
);
|
||||
loop_detection_tests!(
|
||||
provider_ids::openai(),
|
||||
builtin::openai(),
|
||||
"gpt-5.4-mini",
|
||||
openai_loop_detection,
|
||||
keys = ["OPENAI_API_KEY"]
|
||||
);
|
||||
loop_detection_tests!(
|
||||
provider_ids::gemini(),
|
||||
builtin::gemini(),
|
||||
"gemini-3-flash-preview",
|
||||
gemini_loop_detection,
|
||||
keys = ["GEMINI_API_KEY"]
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ fabro-auth = { path = "../../foundation/fabro-auth" }
|
|||
fabro-llm = { path = "../fabro-llm" }
|
||||
fabro-redact.workspace = true
|
||||
fabro-types = { path = "../../foundation/fabro-types" }
|
||||
lithos-llm = { workspace = true, features = ["runtime"] }
|
||||
fabro-util = { path = "../../foundation/fabro-util" }
|
||||
fabro-http.workspace = true
|
||||
serde.workspace = true
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ fn saturating_i64(value: u64) -> i64 {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use fabro_types::provider_ids;
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::*;
|
||||
use crate::test_support::test_catalog;
|
||||
|
|
@ -125,17 +125,17 @@ mod tests {
|
|||
#[test]
|
||||
fn models_are_stamped_with_configured_providers() {
|
||||
let catalog = test_catalog();
|
||||
let configured = HashSet::from([provider_ids::openai()]);
|
||||
let configured = HashSet::from([builtin::openai()]);
|
||||
let models = models(&catalog, &configured);
|
||||
let openai = models
|
||||
.iter()
|
||||
.find(|model| model.provider == provider_ids::openai())
|
||||
.find(|model| model.provider == builtin::openai())
|
||||
.expect("openai models listed");
|
||||
assert!(openai.configured);
|
||||
assert!(openai.limits.context_window > 0);
|
||||
let anthropic = models
|
||||
.iter()
|
||||
.find(|model| model.provider == provider_ids::anthropic())
|
||||
.find(|model| model.provider == builtin::anthropic())
|
||||
.expect("anthropic models listed");
|
||||
assert!(!anthropic.configured);
|
||||
assert!(models.iter().any(|model| model.default));
|
||||
|
|
@ -145,12 +145,12 @@ mod tests {
|
|||
fn providers_skip_stand_ins_and_disabled_entries() {
|
||||
let catalog = test_catalog();
|
||||
let providers = providers(&catalog, &HashSet::new());
|
||||
assert!(providers.iter().any(|p| p.id == provider_ids::openai()));
|
||||
assert!(providers.iter().any(|p| p.id == builtin::openai()));
|
||||
assert!(providers.iter().all(|p| p.id.as_str() != "openai-codex"));
|
||||
assert!(providers.iter().all(|p| p.id.as_str() != "ollama"));
|
||||
let openai = providers
|
||||
.iter()
|
||||
.find(|p| p.id == provider_ids::openai())
|
||||
.find(|p| p.id == builtin::openai())
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
openai.expected_secret_name.as_deref(),
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ fn canonical_eligible(catalog: &Catalog, eligible: &HashSet<ProviderId>) -> Hash
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use fabro_types::provider_ids;
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::*;
|
||||
use crate::test_support::{test_catalog, test_catalog_with_overlay};
|
||||
|
|
@ -291,7 +291,7 @@ mod tests {
|
|||
let selected =
|
||||
resolve_selection(&catalog, Some("sonnet"), None, &eligible(&["anthropic"])).unwrap();
|
||||
assert_eq!(selected, SelectedModel {
|
||||
provider: provider_ids::anthropic(),
|
||||
provider: builtin::anthropic(),
|
||||
model: "claude-sonnet-5".to_string(),
|
||||
});
|
||||
}
|
||||
|
|
@ -306,7 +306,7 @@ mod tests {
|
|||
&eligible(&["openai", "anthropic"]),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(selected.provider, provider_ids::anthropic());
|
||||
assert_eq!(selected.provider, builtin::anthropic());
|
||||
assert_eq!(selected.model, "totally-new-model");
|
||||
}
|
||||
|
||||
|
|
@ -321,7 +321,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
assert_eq!(selected, SelectedModel {
|
||||
provider: provider_ids::openai(),
|
||||
provider: builtin::openai(),
|
||||
model: "gpt-5.6-sol".to_string(),
|
||||
});
|
||||
|
||||
|
|
@ -333,7 +333,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
assert_eq!(unknown, SelectedModel {
|
||||
provider: provider_ids::openai(),
|
||||
provider: builtin::openai(),
|
||||
model: "brand-new-model".to_string(),
|
||||
});
|
||||
|
||||
|
|
@ -346,7 +346,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
unavailable,
|
||||
Err(ModelSelectionError::ProviderUnavailable {
|
||||
provider: provider_ids::openai(),
|
||||
provider: builtin::openai(),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
@ -373,13 +373,13 @@ mod tests {
|
|||
let error = resolve_selection(
|
||||
&catalog,
|
||||
Some("gpt-5.4"),
|
||||
Some(&provider_ids::openai()),
|
||||
Some(&builtin::openai()),
|
||||
&eligible(&["anthropic"]),
|
||||
)
|
||||
.unwrap_err();
|
||||
assert!(matches!(
|
||||
error,
|
||||
ModelSelectionError::ProviderUnavailable { provider } if provider == provider_ids::openai()
|
||||
ModelSelectionError::ProviderUnavailable { provider } if provider == builtin::openai()
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -389,11 +389,11 @@ mod tests {
|
|||
let selected = resolve_selection_with_catalog_fallback(
|
||||
&catalog,
|
||||
Some("gpt-5.4"),
|
||||
Some(&provider_ids::openai()),
|
||||
Some(&builtin::openai()),
|
||||
&eligible(&["anthropic"]),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(selected.provider, provider_ids::openai());
|
||||
assert_eq!(selected.provider, builtin::openai());
|
||||
let error = resolve_selection_with_catalog_fallback(
|
||||
&catalog,
|
||||
None,
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ fabro-core = { path = "../../foundation/fabro-core" }
|
|||
fabro-store = { path = "../fabro-store" }
|
||||
fabro-static.workspace = true
|
||||
fabro-types = { path = "../../foundation/fabro-types" }
|
||||
lithos-llm = { workspace = true, features = ["runtime"] }
|
||||
fabro-http.workspace = true
|
||||
thiserror.workspace = true
|
||||
strum.workspace = true
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ pub use fabro_types::billing_rollup::{
|
|||
mod tests {
|
||||
use fabro_types::{
|
||||
AttrValue, BilledTokenCounts, Graph, ModelId, ModelRef, Node, RunProjection, RunSpec,
|
||||
StageCompletion, StageOutcome, first_event_seq, provider_ids, test_support,
|
||||
StageCompletion, StageOutcome, first_event_seq, test_support,
|
||||
};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::billing_rollup_from_projection;
|
||||
use crate::test_support::test_usage;
|
||||
|
|
@ -134,7 +135,7 @@ mod tests {
|
|||
#[test]
|
||||
fn rollup_keeps_in_flight_stage_usage_unpriced() {
|
||||
let mut projection = test_projection();
|
||||
let model = ModelRef::new(provider_ids::openai(), ModelId::new("gpt-5.4"));
|
||||
let model = ModelRef::new(builtin::openai(), ModelId::new("gpt-5.4"));
|
||||
let stage = projection.stage_entry("agent", 1, first_event_seq(1));
|
||||
stage.started_at = Some(chrono::Utc::now());
|
||||
stage.usage = BilledTokenCounts {
|
||||
|
|
|
|||
|
|
@ -751,7 +751,8 @@ mod tests {
|
|||
/// A stored LLM error of `kind` from the `openai` provider.
|
||||
fn sdk_error(kind: ErrorKind, message: &str) -> ErrorData {
|
||||
ErrorData::from(
|
||||
fabro_llm::Error::new(kind, message).with_provider(fabro_types::provider_ids::openai()),
|
||||
fabro_llm::Error::new(kind, message)
|
||||
.with_provider(lithos_llm::catalog::builtin::openai()),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -759,7 +760,7 @@ mod tests {
|
|||
fn transient_error(kind: ErrorKind, message: &str) -> ErrorData {
|
||||
ErrorData::from(
|
||||
fabro_llm::Error::new(kind, message)
|
||||
.with_provider(fabro_types::provider_ids::openai())
|
||||
.with_provider(lithos_llm::catalog::builtin::openai())
|
||||
.with_retry(RetryClassification::Safe),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1463,14 +1463,14 @@ mod tests {
|
|||
use ::fabro_types::{
|
||||
AutomationRef, EventBody, FailureReason, ModelId, ModelRef, ParallelBranchId, Principal,
|
||||
ProviderId, RunNoticeCode, RunNoticeLevel, RunProvenance, StageId, SystemActorKind,
|
||||
TokenCounts as LlmTokenCounts, fixtures, provider_ids, run_event as fabro_types,
|
||||
test_support,
|
||||
TokenCounts as LlmTokenCounts, fixtures, run_event as fabro_types, test_support,
|
||||
};
|
||||
use chrono::Utc;
|
||||
use fabro_agent::{
|
||||
AgentEvent, McpToolSummary, MemoryFileSummary, SandboxEvent, SkillActivationSource,
|
||||
SkillSummary,
|
||||
};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::*;
|
||||
use crate::error::Error;
|
||||
|
|
@ -2522,10 +2522,7 @@ mod tests {
|
|||
visit: 1,
|
||||
event: AgentEvent::AssistantMessage {
|
||||
text: "ok".to_string(),
|
||||
model: ModelRef::new(
|
||||
provider_ids::anthropic(),
|
||||
ModelId::new("claude-sonnet"),
|
||||
),
|
||||
model: ModelRef::new(builtin::anthropic(), ModelId::new("claude-sonnet")),
|
||||
usage: LlmTokenCounts::default(),
|
||||
cost: None,
|
||||
tool_call_count: 0,
|
||||
|
|
@ -2644,7 +2641,7 @@ mod tests {
|
|||
visit: 1,
|
||||
event: AgentEvent::AssistantMessage {
|
||||
text: "ok".to_string(),
|
||||
model: ModelRef::new(provider_ids::openai(), ModelId::new("gpt-5.4")),
|
||||
model: ModelRef::new(builtin::openai(), ModelId::new("gpt-5.4")),
|
||||
usage: LlmTokenCounts::default(),
|
||||
cost: None,
|
||||
tool_call_count: 0,
|
||||
|
|
@ -2674,7 +2671,7 @@ mod tests {
|
|||
visit: 1,
|
||||
event: AgentEvent::AssistantMessage {
|
||||
text: String::new(),
|
||||
model: ModelRef::new(provider_ids::openai(), ModelId::new("gpt-5.4")),
|
||||
model: ModelRef::new(builtin::openai(), ModelId::new("gpt-5.4")),
|
||||
usage: LlmTokenCounts::default(),
|
||||
cost: None,
|
||||
tool_call_count: 1,
|
||||
|
|
|
|||
|
|
@ -31,10 +31,11 @@ pub fn event_payload_from_redacted_json(line: &str, run_id: &RunId) -> Result<Ev
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ::fabro_types::{
|
||||
ModelId, ModelRef, ReasoningOutput, TokenCounts as LlmTokenCounts, fixtures, provider_ids,
|
||||
ModelId, ModelRef, ReasoningOutput, TokenCounts as LlmTokenCounts, fixtures,
|
||||
run_event as fabro_types,
|
||||
};
|
||||
use fabro_agent::AgentEvent;
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::*;
|
||||
use crate::event::{Event, to_run_event};
|
||||
|
|
@ -125,7 +126,7 @@ mod tests {
|
|||
visit: 1,
|
||||
event: AgentEvent::AssistantMessage {
|
||||
text: "done".to_string(),
|
||||
model: ModelRef::new(provider_ids::openai(), ModelId::new("gpt-5.4")),
|
||||
model: ModelRef::new(builtin::openai(), ModelId::new("gpt-5.4")),
|
||||
usage: LlmTokenCounts::default(),
|
||||
cost: None,
|
||||
tool_call_count: 0,
|
||||
|
|
|
|||
|
|
@ -390,7 +390,7 @@ mod tests {
|
|||
event: fabro_agent::AgentEvent::AssistantMessage {
|
||||
text: String::new(),
|
||||
model: ::fabro_types::ModelRef::new(
|
||||
::fabro_types::provider_ids::openai(),
|
||||
::lithos_llm::catalog::builtin::openai(),
|
||||
ModelId::new("gpt-5.4"),
|
||||
),
|
||||
usage: ::fabro_types::TokenCounts::default(),
|
||||
|
|
|
|||
|
|
@ -1901,12 +1901,13 @@ mod tests {
|
|||
use fabro_types::{
|
||||
ContentPart, EventEnvelope, FailureReason, Run, RunId, RunLifecycle, RunLinks, RunOrigin,
|
||||
RunPairStatusResponse, RunProjection, RunStatus, RunTimestamps, SuccessReason, WorkflowRef,
|
||||
provider_ids, test_support,
|
||||
test_support,
|
||||
};
|
||||
use fabro_vault::{SecretType, Vault};
|
||||
use futures::stream;
|
||||
use httpmock::Method::POST;
|
||||
use httpmock::MockServer;
|
||||
use lithos_llm::catalog::builtin;
|
||||
use tokio::sync::RwLock as AsyncRwLock;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
|
|
@ -1932,7 +1933,7 @@ mod tests {
|
|||
}
|
||||
|
||||
fn provider_id(&self) -> ProviderId {
|
||||
provider_ids::openai()
|
||||
builtin::openai()
|
||||
}
|
||||
|
||||
fn model(&self) -> &str {
|
||||
|
|
@ -2250,20 +2251,20 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
fn agent_backend_stores_config() {
|
||||
let backend = AgentApiBackend::new(
|
||||
"claude-opus-4-6".to_string(),
|
||||
provider_ids::openai(),
|
||||
builtin::openai(),
|
||||
ModelFallbackPolicy::default(),
|
||||
auth_test_support::vault_only_credential_source(),
|
||||
SteeringHub::for_tests(),
|
||||
);
|
||||
assert_eq!(backend.model, "claude-opus-4-6");
|
||||
assert_eq!(backend.provider_id, provider_ids::openai());
|
||||
assert_eq!(backend.provider_id, builtin::openai());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn agent_backend_initializes_empty_sessions() {
|
||||
let backend = AgentApiBackend::new(
|
||||
"claude-opus-4-6".to_string(),
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
ModelFallbackPolicy::default(),
|
||||
auth_test_support::vault_only_credential_source(),
|
||||
SteeringHub::for_tests(),
|
||||
|
|
@ -2952,7 +2953,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
fn build_profile_can_register_subagent_tools() {
|
||||
let mut profile = AgentProfileBuilder::new(
|
||||
AgentProfileKind::Anthropic,
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
"claude-opus-4-6",
|
||||
Arc::new(test_catalog()),
|
||||
)
|
||||
|
|
@ -3130,7 +3131,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
.resolve_provider_context("gpt-5.4", Some("openai"))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(provider.provider_id, provider_ids::openai());
|
||||
assert_eq!(provider.provider_id, builtin::openai());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -3175,7 +3176,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
fn api_backend_selects_claude5_profile_for_sonnet5() {
|
||||
let backend = AgentApiBackend::new_with_catalog(
|
||||
"claude-sonnet-5".to_string(),
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
ModelFallbackPolicy::default(),
|
||||
auth_test_support::vault_only_credential_source(),
|
||||
SteeringHub::for_tests(),
|
||||
|
|
@ -3186,7 +3187,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
.resolve_provider_context("claude-sonnet-5", None)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(provider.provider_id, provider_ids::anthropic());
|
||||
assert_eq!(provider.provider_id, builtin::anthropic());
|
||||
assert_eq!(provider.profile_kind, AgentProfileKind::Claude5);
|
||||
}
|
||||
|
||||
|
|
@ -3214,7 +3215,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
fn run_model_controls_apply_when_node_omits_controls() {
|
||||
let backend = AgentApiBackend::new(
|
||||
"gpt-5.4".to_string(),
|
||||
provider_ids::openai(),
|
||||
builtin::openai(),
|
||||
ModelFallbackPolicy::default(),
|
||||
auth_test_support::vault_only_credential_source(),
|
||||
SteeringHub::for_tests(),
|
||||
|
|
@ -3235,7 +3236,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
fn node_controls_override_run_model_controls() {
|
||||
let backend = AgentApiBackend::new(
|
||||
"gpt-5.4".to_string(),
|
||||
provider_ids::openai(),
|
||||
builtin::openai(),
|
||||
ModelFallbackPolicy::default(),
|
||||
auth_test_support::vault_only_credential_source(),
|
||||
SteeringHub::for_tests(),
|
||||
|
|
@ -3264,7 +3265,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
fn omitted_reasoning_effort_stays_unset() {
|
||||
let backend = AgentApiBackend::new(
|
||||
"gpt-5.4".to_string(),
|
||||
provider_ids::openai(),
|
||||
builtin::openai(),
|
||||
ModelFallbackPolicy::default(),
|
||||
auth_test_support::vault_only_credential_source(),
|
||||
SteeringHub::for_tests(),
|
||||
|
|
@ -3332,7 +3333,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
]));
|
||||
let backend = AgentApiBackend::new_with_catalog(
|
||||
"claude-fable-5".to_string(),
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
policy,
|
||||
auth_test_support::vault_only_credential_source(),
|
||||
SteeringHub::for_tests(),
|
||||
|
|
@ -3340,7 +3341,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
);
|
||||
let (mut plan, notices) = backend.fallback_plan(
|
||||
"claude-fable-5",
|
||||
&provider_ids::anthropic(),
|
||||
&builtin::anthropic(),
|
||||
EffectiveRequestControls::default(),
|
||||
);
|
||||
|
||||
|
|
@ -3375,7 +3376,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
.unwrap();
|
||||
let backend = AgentApiBackend::new(
|
||||
"claude-opus-4-6".to_string(),
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
ModelFallbackPolicy::default(),
|
||||
Arc::new(VaultCredentialSource::with_env_lookup(
|
||||
Arc::new(AsyncRwLock::new(vault)),
|
||||
|
|
@ -3390,7 +3391,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
|
||||
assert_eq!(
|
||||
client.available_providers().iter().collect::<Vec<_>>(),
|
||||
vec![&provider_ids::anthropic()]
|
||||
vec![&builtin::anthropic()]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -3403,7 +3404,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
)]));
|
||||
let backend = AgentApiBackend::new(
|
||||
"claude-fable-5".to_string(),
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
fallback_policy,
|
||||
auth_test_support::vault_only_credential_source(),
|
||||
SteeringHub::for_tests(),
|
||||
|
|
@ -3440,7 +3441,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
.unwrap();
|
||||
let (mut fallback_plan, notices) = backend.fallback_plan(
|
||||
"claude-fable-5",
|
||||
&provider_ids::anthropic(),
|
||||
&builtin::anthropic(),
|
||||
EffectiveRequestControls::default(),
|
||||
);
|
||||
assert!(notices.is_empty());
|
||||
|
|
@ -3458,7 +3459,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
.unwrap();
|
||||
|
||||
assert_eq!(completion.response.text(), "fallback ok");
|
||||
assert_eq!(completion.model.provider, provider_ids::openai());
|
||||
assert_eq!(completion.model.provider, builtin::openai());
|
||||
assert_eq!(completion.model.model_id.as_str(), "gpt-5.5");
|
||||
let failover = emitted_failover
|
||||
.lock()
|
||||
|
|
@ -3907,7 +3908,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
async fn api_backend_shutdown_closes_cached_sessions_once() {
|
||||
let backend = AgentApiBackend::new(
|
||||
"gpt-5.4".to_string(),
|
||||
provider_ids::openai(),
|
||||
builtin::openai(),
|
||||
ModelFallbackPolicy::default(),
|
||||
auth_test_support::vault_only_credential_source(),
|
||||
SteeringHub::for_tests(),
|
||||
|
|
@ -3940,7 +3941,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
);
|
||||
let (fallback_plan, notices) = backend.fallback_plan(
|
||||
"gpt-5.4",
|
||||
&provider_ids::openai(),
|
||||
&builtin::openai(),
|
||||
EffectiveRequestControls::default(),
|
||||
);
|
||||
assert!(notices.is_empty());
|
||||
|
|
@ -4032,7 +4033,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
fn failover_eligible_llm_error() -> ErrorData {
|
||||
ErrorData::from(
|
||||
fabro_llm::Error::new(ErrorKind::Network, "boom")
|
||||
.with_provider(provider_ids::openai())
|
||||
.with_provider(builtin::openai())
|
||||
.with_retry(RetryClassification::Safe),
|
||||
)
|
||||
}
|
||||
|
|
@ -4040,7 +4041,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
fn non_failover_llm_error() -> ErrorData {
|
||||
ErrorData::from(
|
||||
fabro_llm::Error::new(ErrorKind::InvalidRequest, "bad key")
|
||||
.with_provider(provider_ids::openai())
|
||||
.with_provider(builtin::openai())
|
||||
.with_status(401),
|
||||
)
|
||||
}
|
||||
|
|
@ -4050,7 +4051,7 @@ capabilities = {{ text = true, tools = true, response_format = {{ json_object =
|
|||
ErrorKind::ContentFilter,
|
||||
"claude-fable-5 refused the request",
|
||||
)
|
||||
.with_provider(provider_ids::anthropic())
|
||||
.with_provider(builtin::anthropic())
|
||||
.with_provider_code("refusal")
|
||||
.with_raw_data(serde_json::json!({
|
||||
"stop_reason": "refusal",
|
||||
|
|
|
|||
|
|
@ -589,7 +589,8 @@ fn build_summary_preamble(
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use fabro_graphviz::graph::AttrValue;
|
||||
use fabro_types::{ModelId, ModelRef, TokenCounts, provider_ids};
|
||||
use fabro_types::{ModelId, ModelRef, TokenCounts};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::*;
|
||||
use crate::outcome::{BilledModelUsage, billed_model_usage_from_llm};
|
||||
|
|
@ -597,7 +598,7 @@ mod tests {
|
|||
fn stage_usage(model: &str, input: u64, output: u64) -> BilledModelUsage {
|
||||
billed_model_usage_from_llm(
|
||||
&fabro_llm::test_support::test_catalog(),
|
||||
&ModelRef::new(provider_ids::anthropic(), ModelId::new(model)),
|
||||
&ModelRef::new(builtin::anthropic(), ModelId::new(model)),
|
||||
TokenCounts {
|
||||
input,
|
||||
output,
|
||||
|
|
|
|||
|
|
@ -1306,7 +1306,7 @@ mod tests {
|
|||
None,
|
||||
finalize_locations,
|
||||
tokio_util::sync::CancellationToken::new(),
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
"claude-sonnet-4-6".to_string(),
|
||||
auth_test_support::vault_only_credential_source(),
|
||||
Arc::new(fabro_llm::test_support::test_catalog()),
|
||||
|
|
|
|||
|
|
@ -688,9 +688,10 @@ mod tests {
|
|||
use fabro_store::Database;
|
||||
use fabro_types::settings::InterpString;
|
||||
use fabro_types::settings::run::RunMode;
|
||||
use fabro_types::{EventBody, WorkflowSettings, fixtures, provider_ids, test_support};
|
||||
use fabro_types::{EventBody, WorkflowSettings, fixtures, test_support};
|
||||
use fabro_util::error::collect_chain;
|
||||
use fabro_validate::Severity;
|
||||
use lithos_llm::catalog::builtin;
|
||||
use object_store::local::LocalFileSystem;
|
||||
use object_store::memory::InMemory;
|
||||
|
||||
|
|
@ -2028,19 +2029,19 @@ mod tests {
|
|||
}"#;
|
||||
let catalog = portable_model_catalog();
|
||||
let cases = [
|
||||
(vec![provider_ids::openai()], None, provider_ids::openai()),
|
||||
(vec![builtin::openai()], None, builtin::openai()),
|
||||
(
|
||||
vec![ProviderId::new("openrouter")],
|
||||
None,
|
||||
ProviderId::new("openrouter"),
|
||||
),
|
||||
(
|
||||
vec![provider_ids::openai(), ProviderId::new("openrouter")],
|
||||
vec![builtin::openai(), ProviderId::new("openrouter")],
|
||||
None,
|
||||
provider_ids::openai(),
|
||||
builtin::openai(),
|
||||
),
|
||||
(
|
||||
vec![provider_ids::openai(), ProviderId::new("openrouter")],
|
||||
vec![builtin::openai(), ProviderId::new("openrouter")],
|
||||
Some("openrouter"),
|
||||
ProviderId::new("openrouter"),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1310,9 +1310,10 @@ mod tests {
|
|||
};
|
||||
use fabro_types::{
|
||||
BilledModelUsage, GitContext, ManifestPath, RunTarget, StageTiming, WorkflowSettings,
|
||||
fixtures, provider_ids, test_support,
|
||||
fixtures, test_support,
|
||||
};
|
||||
use fabro_vault::SecretType;
|
||||
use lithos_llm::catalog::builtin;
|
||||
use object_store::memory::InMemory;
|
||||
|
||||
use super::*;
|
||||
|
|
@ -1475,7 +1476,7 @@ mod tests {
|
|||
error,
|
||||
Error::ModelSelection(fabro_llm::ModelSelectionError::ProviderUnavailable {
|
||||
provider
|
||||
}) if provider == provider_ids::openai()
|
||||
}) if provider == builtin::openai()
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,8 @@ pub fn format_cost(cost: f64) -> String {
|
|||
mod tests {
|
||||
use fabro_llm::lithos_catalog::Catalog;
|
||||
use fabro_llm::test_support::{test_catalog, test_catalog_with_overlay};
|
||||
use fabro_types::{ModelId, ModelRef, ProviderId, Speed, TokenCounts, UsdMicros, provider_ids};
|
||||
use fabro_types::{ModelId, ModelRef, ProviderId, Speed, TokenCounts, UsdMicros};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
use super::{OutcomeExt, billed_model_usage_from_llm};
|
||||
|
||||
|
|
@ -149,7 +150,7 @@ mod tests {
|
|||
};
|
||||
let billed = billed_model_usage_from_llm(
|
||||
&catalog(),
|
||||
&model_ref(provider_ids::openai(), "gpt-5.4", None),
|
||||
&model_ref(builtin::openai(), "gpt-5.4", None),
|
||||
usage,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
@ -169,7 +170,7 @@ mod tests {
|
|||
};
|
||||
let billed = billed_model_usage_from_llm(
|
||||
&catalog(),
|
||||
&model_ref(provider_ids::openai(), "gpt-5.4", None),
|
||||
&model_ref(builtin::openai(), "gpt-5.4", None),
|
||||
usage,
|
||||
)
|
||||
.unwrap()
|
||||
|
|
@ -199,11 +200,7 @@ mod tests {
|
|||
};
|
||||
let billed = billed_model_usage_from_llm(
|
||||
&catalog(),
|
||||
&model_ref(
|
||||
provider_ids::anthropic(),
|
||||
"claude-opus-5",
|
||||
Some(Speed::Fast),
|
||||
),
|
||||
&model_ref(builtin::anthropic(), "claude-opus-5", Some(Speed::Fast)),
|
||||
usage,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
@ -253,7 +250,7 @@ pricing = { input_usd_micros_per_million = 1000000, output_usd_micros_per_millio
|
|||
fn passthrough_model_on_known_provider_has_no_cost() {
|
||||
let billed = billed_model_usage_from_llm(
|
||||
&catalog(),
|
||||
&model_ref(provider_ids::openai(), "brand-new-model", None),
|
||||
&model_ref(builtin::openai(), "brand-new-model", None),
|
||||
TokenCounts {
|
||||
input: 10,
|
||||
output: 5,
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ async fn execute_test_run_with_options(
|
|||
},
|
||||
llm: LlmSpec {
|
||||
model: "test-model".to_string(),
|
||||
provider_id: fabro_types::provider_ids::anthropic(),
|
||||
provider_id: lithos_llm::catalog::builtin::anthropic(),
|
||||
fallbacks: ModelFallbackPolicy::default(),
|
||||
mcp_servers: Vec::new(),
|
||||
model_controls: RunModelControls::default(),
|
||||
|
|
@ -325,7 +325,7 @@ async fn execute_runs_start_to_exit_and_returns_final_context() {
|
|||
},
|
||||
llm: LlmSpec {
|
||||
model: "test-model".to_string(),
|
||||
provider_id: fabro_types::provider_ids::anthropic(),
|
||||
provider_id: lithos_llm::catalog::builtin::anthropic(),
|
||||
fallbacks: ModelFallbackPolicy::default(),
|
||||
mcp_servers: Vec::new(),
|
||||
model_controls: RunModelControls::default(),
|
||||
|
|
@ -466,7 +466,7 @@ async fn resumed_in_flight_node_starts_a_new_stage_execution() {
|
|||
},
|
||||
llm: LlmSpec {
|
||||
model: "test-model".to_string(),
|
||||
provider_id: fabro_types::provider_ids::anthropic(),
|
||||
provider_id: lithos_llm::catalog::builtin::anthropic(),
|
||||
fallbacks: ModelFallbackPolicy::default(),
|
||||
mcp_servers: Vec::new(),
|
||||
model_controls: RunModelControls::default(),
|
||||
|
|
@ -580,7 +580,7 @@ async fn run_with_lifecycle(
|
|||
},
|
||||
llm: LlmSpec {
|
||||
model: "test-model".to_string(),
|
||||
provider_id: fabro_types::provider_ids::anthropic(),
|
||||
provider_id: lithos_llm::catalog::builtin::anthropic(),
|
||||
fallbacks: ModelFallbackPolicy::default(),
|
||||
mcp_servers: Vec::new(),
|
||||
model_controls: RunModelControls::default(),
|
||||
|
|
|
|||
|
|
@ -996,7 +996,7 @@ mod tests {
|
|||
None,
|
||||
locations,
|
||||
tokio_util::sync::CancellationToken::new(),
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
"claude-sonnet-4-6".to_string(),
|
||||
auth_test_support::vault_only_credential_source(),
|
||||
Arc::new(fabro_llm::test_support::test_catalog()),
|
||||
|
|
@ -1029,7 +1029,7 @@ mod tests {
|
|||
None,
|
||||
locations,
|
||||
tokio_util::sync::CancellationToken::new(),
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
"claude-sonnet-4-6".to_string(),
|
||||
auth_test_support::vault_only_credential_source(),
|
||||
Arc::new(fabro_llm::test_support::test_catalog()),
|
||||
|
|
|
|||
|
|
@ -901,7 +901,7 @@ mod tests {
|
|||
sandbox: SandboxSpec::Local { working_directory },
|
||||
llm: LlmSpec {
|
||||
model: "test-model".to_string(),
|
||||
provider_id: fabro_types::provider_ids::anthropic(),
|
||||
provider_id: lithos_llm::catalog::builtin::anthropic(),
|
||||
fallbacks: ModelFallbackPolicy::default(),
|
||||
mcp_servers: Vec::new(),
|
||||
model_controls: RunModelControls::default(),
|
||||
|
|
@ -1091,7 +1091,7 @@ mod tests {
|
|||
assert_eq!(initialized.model, "test-model");
|
||||
assert_eq!(
|
||||
initialized.engine.run.provider_id,
|
||||
fabro_types::provider_ids::anthropic()
|
||||
lithos_llm::catalog::builtin::anthropic()
|
||||
);
|
||||
assert!(
|
||||
readiness(
|
||||
|
|
@ -1217,7 +1217,7 @@ mod tests {
|
|||
let (_registry, effective_dry_run) = build_registry(
|
||||
&LlmSpec {
|
||||
model: "claude-opus-4-6".to_string(),
|
||||
provider_id: fabro_types::provider_ids::anthropic(),
|
||||
provider_id: lithos_llm::catalog::builtin::anthropic(),
|
||||
fallbacks: ModelFallbackPolicy::default(),
|
||||
mcp_servers: Vec::new(),
|
||||
model_controls: RunModelControls::default(),
|
||||
|
|
@ -1344,7 +1344,7 @@ mod tests {
|
|||
},
|
||||
llm: LlmSpec {
|
||||
model: "fake-acp".to_string(),
|
||||
provider_id: fabro_types::provider_ids::openai(),
|
||||
provider_id: lithos_llm::catalog::builtin::openai(),
|
||||
fallbacks: ModelFallbackPolicy::default(),
|
||||
mcp_servers: Vec::new(),
|
||||
model_controls: RunModelControls::default(),
|
||||
|
|
@ -1447,7 +1447,7 @@ mod tests {
|
|||
},
|
||||
llm: LlmSpec {
|
||||
model: "test-model".to_string(),
|
||||
provider_id: fabro_types::provider_ids::anthropic(),
|
||||
provider_id: lithos_llm::catalog::builtin::anthropic(),
|
||||
fallbacks: ModelFallbackPolicy::default(),
|
||||
mcp_servers: Vec::new(),
|
||||
model_controls: RunModelControls::default(),
|
||||
|
|
@ -1589,7 +1589,7 @@ mod tests {
|
|||
},
|
||||
llm: LlmSpec {
|
||||
model: "test-model".to_string(),
|
||||
provider_id: fabro_types::provider_ids::anthropic(),
|
||||
provider_id: lithos_llm::catalog::builtin::anthropic(),
|
||||
fallbacks: ModelFallbackPolicy::default(),
|
||||
mcp_servers: Vec::new(),
|
||||
model_controls: RunModelControls::default(),
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ impl EngineServices {
|
|||
None,
|
||||
locations,
|
||||
CancellationToken::new(),
|
||||
fabro_types::provider_ids::anthropic(),
|
||||
lithos_llm::catalog::builtin::anthropic(),
|
||||
"claude-sonnet-4.6".to_string(),
|
||||
Arc::new(StubCredentialSource),
|
||||
Arc::new(fabro_llm::default_catalog()),
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ use fabro_llm::test_support::test_catalog;
|
|||
use fabro_store::{ArtifactStore, RunProjection, test_support as store_test_support};
|
||||
#[cfg(feature = "test-support")]
|
||||
use fabro_types::ProviderId;
|
||||
use fabro_types::{ModelId, ModelRef, provider_ids};
|
||||
use fabro_types::{ModelId, ModelRef};
|
||||
use lithos_llm::catalog::builtin;
|
||||
use object_store::local::LocalFileSystem;
|
||||
|
||||
use crate::artifact_upload::ArtifactSink;
|
||||
|
|
@ -89,7 +90,7 @@ pub fn test_usage(
|
|||
output_tokens: u64,
|
||||
) -> fabro_types::BilledModelUsage {
|
||||
let mut usage = fabro_types::BilledModelUsage::new(
|
||||
ModelRef::new(provider_ids::openai(), ModelId::new(model_id)),
|
||||
ModelRef::new(builtin::openai(), ModelId::new(model_id)),
|
||||
fabro_types::TokenCounts {
|
||||
input: input_tokens,
|
||||
output: output_tokens,
|
||||
|
|
@ -269,7 +270,7 @@ async fn initialized(
|
|||
options.hook_runner,
|
||||
locations,
|
||||
run_options.cancel_token.clone(),
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
"claude-sonnet-4-6".to_string(),
|
||||
options
|
||||
.llm_source
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use fabro_graphviz::graph::Graph;
|
||||
use fabro_graphviz::parser;
|
||||
use fabro_llm::test_support::test_catalog;
|
||||
use fabro_types::WorkflowSettings;
|
||||
use fabro_types::settings::InterpString;
|
||||
use fabro_types::settings::run::{PullRequestSettings, RunGoal, RunModelSettings, RunNamespace};
|
||||
use fabro_types::{WorkflowSettings, provider_ids};
|
||||
use fabro_workflow::run_materialization::materialize_run;
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
fn graph(source: &str) -> Graph {
|
||||
parser::parse(source).expect("graph should parse")
|
||||
|
|
@ -35,7 +36,7 @@ fn materialize_run_applies_graph_and_catalog_defaults() {
|
|||
};
|
||||
|
||||
let materialized = materialize_run(settings, &graph(source), &test_catalog(), &[
|
||||
provider_ids::anthropic(),
|
||||
builtin::anthropic(),
|
||||
])
|
||||
.unwrap();
|
||||
let resolved = &materialized.run;
|
||||
|
|
@ -62,7 +63,7 @@ fn materialize_run_uses_configured_provider_defaults() {
|
|||
WorkflowSettings::default(),
|
||||
&graph(source),
|
||||
&test_catalog(),
|
||||
&[provider_ids::openai()],
|
||||
&[builtin::openai()],
|
||||
)
|
||||
.unwrap();
|
||||
let resolved = &materialized.run;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ fabro-automation = { path = "../../components/fabro-automation" }
|
|||
fabro-config = { path = "../fabro-config" }
|
||||
fabro-environment.workspace = true
|
||||
fabro-types = { path = "../fabro-types" }
|
||||
lithos-llm = { workspace = true, features = ["runtime"] }
|
||||
progenitor-client = "0.13"
|
||||
regress = "0.10"
|
||||
reqwest.workspace = true
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use std::any::{TypeId, type_name};
|
||||
|
||||
use fabro_api::types::{Model as ApiModel, ModelControls as ApiModelControls};
|
||||
use fabro_types::{
|
||||
Model, ModelControls, ModelCosts, ModelFeatures, ModelLimits, ReasoningEffort, provider_ids,
|
||||
};
|
||||
use fabro_types::{Model, ModelControls, ModelCosts, ModelFeatures, ModelLimits, ReasoningEffort};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
#[test]
|
||||
fn model_reuses_canonical_type() {
|
||||
|
|
@ -15,7 +14,7 @@ fn model_reuses_canonical_type() {
|
|||
fn model_json_matches_openapi_shape() {
|
||||
let model = Model {
|
||||
id: "claude-opus-4.7".into(),
|
||||
provider: provider_ids::anthropic(),
|
||||
provider: builtin::anthropic(),
|
||||
family: "claude-4".to_string(),
|
||||
display_name: "Claude Opus 4.7".to_string(),
|
||||
limits: ModelLimits {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use std::any::{TypeId, type_name};
|
||||
|
||||
use fabro_api::types::{ModelHandle as ApiModelHandle, ProviderId as ApiProviderId};
|
||||
use fabro_types::{ModelHandle, ModelId, ProviderId, provider_ids};
|
||||
use fabro_types::{ModelHandle, ModelId, ProviderId};
|
||||
use lithos_llm::catalog::builtin;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
|
|
@ -13,7 +14,7 @@ fn provider_id_and_model_handle_reuse_lithos_types() {
|
|||
#[test]
|
||||
fn provider_id_json_is_a_bare_string() {
|
||||
assert_eq!(
|
||||
serde_json::to_value(provider_ids::anthropic()).unwrap(),
|
||||
serde_json::to_value(builtin::anthropic()).unwrap(),
|
||||
json!("anthropic")
|
||||
);
|
||||
assert_eq!(
|
||||
|
|
@ -24,7 +25,7 @@ fn provider_id_json_is_a_bare_string() {
|
|||
|
||||
#[test]
|
||||
fn model_handle_json_matches_openapi_shape() {
|
||||
let handle = ModelHandle::new(provider_ids::openai(), ModelId::new("gpt-5.4"));
|
||||
let handle = ModelHandle::new(builtin::openai(), ModelId::new("gpt-5.4"));
|
||||
let json = serde_json::to_value(&handle).unwrap();
|
||||
assert_eq!(json, json!({"provider": "openai", "model": "gpt-5.4"}));
|
||||
let round_trip: ApiModelHandle = serde_json::from_value(json).unwrap();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use std::any::{TypeId, type_name};
|
||||
|
||||
use fabro_api::types::Provider as ApiProvider;
|
||||
use fabro_types::{Provider, ProviderId, provider_ids};
|
||||
use fabro_types::{Provider, ProviderId};
|
||||
use lithos_llm::catalog::builtin;
|
||||
|
||||
#[test]
|
||||
fn provider_reuses_canonical_type() {
|
||||
|
|
@ -11,7 +12,7 @@ fn provider_reuses_canonical_type() {
|
|||
#[test]
|
||||
fn provider_json_matches_openapi_shape() {
|
||||
let provider = Provider {
|
||||
id: provider_ids::anthropic(),
|
||||
id: builtin::anthropic(),
|
||||
display_name: "Anthropic".to_string(),
|
||||
adapter: "anthropic".to_string(),
|
||||
base_url: "https://api.anthropic.test".to_string(),
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ fn session_detail_round_trips_messages_active_turn_and_last_seq() {
|
|||
title: Some("Ask Fabro".to_string()),
|
||||
status: SessionStatus::Running,
|
||||
model: Some("gpt-5.4".to_string()),
|
||||
provider: Some(fabro_types::provider_ids::openai()),
|
||||
provider: Some(lithos_llm::catalog::builtin::openai()),
|
||||
active_turn: Some(SessionTurn {
|
||||
id: turn_id,
|
||||
started_at: turn_started_at,
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@
|
|||
//! vault under those same names, so the vault entry an operator creates and
|
||||
//! the environment variable a shell exports are spelled alike.
|
||||
|
||||
use fabro_types::provider_ids;
|
||||
use lithos_llm::catalog::{AuthScheme, CatalogProvider, ProviderId};
|
||||
use lithos_llm::catalog::{AuthScheme, CatalogProvider, ProviderId, builtin};
|
||||
use lithos_llm::credentials::ConventionalCredentials;
|
||||
|
||||
use crate::OPENAI_CODEX_VAULT_SECRET_NAME;
|
||||
|
|
@ -43,5 +42,5 @@ pub fn accepts_api_key(provider: &CatalogProvider) -> bool {
|
|||
/// The vault entry holding `provider`'s OAuth credential, for the providers
|
||||
/// Fabro can log into with a browser flow.
|
||||
pub(crate) fn oauth_secret_name(provider: &ProviderId) -> Option<&'static str> {
|
||||
(provider.as_str() == provider_ids::OPENAI_CODEX).then_some(OPENAI_CODEX_VAULT_SECRET_NAME)
|
||||
(provider.as_str() == builtin::ids::OPENAI_CODEX).then_some(OPENAI_CODEX_VAULT_SECRET_NAME)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use base64::Engine;
|
|||
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
|
||||
use chrono::{DateTime, Utc};
|
||||
use fabro_http::HttpClient;
|
||||
use fabro_types::provider_ids;
|
||||
use lithos_llm::catalog::builtin;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use tokio::time::sleep;
|
||||
|
|
@ -299,7 +299,7 @@ impl AuthStrategy for CodexDeviceStrategy {
|
|||
.map_err(anyhow::Error::msg)?;
|
||||
|
||||
Ok(LoginResult::OAuth {
|
||||
provider: provider_ids::openai(),
|
||||
provider: builtin::openai(),
|
||||
credential: OAuthCredential {
|
||||
tokens: OAuthTokens {
|
||||
access_token: token_response.access_token,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use fabro_types::provider_ids;
|
||||
use lithos_llm::catalog::{Catalog, ProviderId};
|
||||
use lithos_llm::catalog::{Catalog, ProviderId, builtin};
|
||||
|
||||
use crate::context::{AuthContextRequest, AuthContextResponse};
|
||||
use crate::credential::{OAuthConfig, OAuthCredential};
|
||||
|
|
@ -74,7 +73,7 @@ pub fn strategy_for(
|
|||
// forgets the constraint.
|
||||
assert_eq!(
|
||||
provider_id.as_str(),
|
||||
provider_ids::OPENAI,
|
||||
builtin::ids::OPENAI,
|
||||
"CodexDevice auth is only constructed by CLI code for the \
|
||||
OpenAI provider; all existing call sites enforce this pairing: \
|
||||
got provider_id={provider_id}"
|
||||
|
|
|
|||
|
|
@ -19,10 +19,9 @@ use std::sync::Arc;
|
|||
|
||||
use async_trait::async_trait;
|
||||
use fabro_static::EnvVars;
|
||||
use fabro_types::provider_ids;
|
||||
use fabro_types::settings::{InterpString, ResolveCtx};
|
||||
use fabro_vault::{SecretType, Vault};
|
||||
use lithos_llm::catalog::{CatalogProvider, ProviderId};
|
||||
use lithos_llm::catalog::{CatalogProvider, ProviderId, builtin};
|
||||
use lithos_llm::credentials::{
|
||||
ConventionalCredentials, CredentialError, CredentialHeader, CredentialProvider, Credentials,
|
||||
HttpAuthentication, HttpCredentials, SecretValue,
|
||||
|
|
@ -184,7 +183,7 @@ impl VaultCredentialSource {
|
|||
) -> Credentials {
|
||||
if let Credentials::Http(http) = &mut credentials {
|
||||
http.extra_headers.extend(interpolated);
|
||||
if provider.id().as_str() == provider_ids::OPENAI {
|
||||
if provider.id().as_str() == builtin::ids::OPENAI {
|
||||
for (variable, header) in [
|
||||
(EnvVars::OPENAI_ORG_ID, OPENAI_ORGANIZATION_HEADER),
|
||||
(EnvVars::OPENAI_PROJECT_ID, OPENAI_PROJECT_HEADER),
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ pub mod outcome;
|
|||
pub mod pair;
|
||||
pub mod parallel;
|
||||
pub mod principal;
|
||||
pub mod provider_ids;
|
||||
pub mod pull_request;
|
||||
pub mod repository;
|
||||
pub mod run;
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
//! Well-known provider identifiers.
|
||||
//!
|
||||
//! Provider identity is open-ended catalog data, so [`ProviderId`] is a plain
|
||||
//! string newtype. The first-party providers are named here because code
|
||||
//! paths such as Codex login and the install flow refer to them directly.
|
||||
|
||||
use lithos_llm::catalog::ProviderId;
|
||||
|
||||
pub const ANTHROPIC: &str = "anthropic";
|
||||
pub const OPENAI: &str = "openai";
|
||||
/// The ChatGPT-subscription deployment that stands in for [`OPENAI`] when a
|
||||
/// Codex OAuth credential is present.
|
||||
pub const OPENAI_CODEX: &str = "openai-codex";
|
||||
pub const GEMINI: &str = "gemini";
|
||||
|
||||
#[must_use]
|
||||
pub fn anthropic() -> ProviderId {
|
||||
ProviderId::new(ANTHROPIC)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn openai() -> ProviderId {
|
||||
ProviderId::new(OPENAI)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn openai_codex() -> ProviderId {
|
||||
ProviderId::new(OPENAI_CODEX)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn gemini() -> ProviderId {
|
||||
ProviderId::new(GEMINI)
|
||||
}
|
||||
|
|
@ -523,16 +523,16 @@ pub struct AgentSkillActivatedProps {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use lithos_llm::catalog::builtin;
|
||||
use serde_json::json;
|
||||
|
||||
use super::*;
|
||||
use crate::provider_ids;
|
||||
use crate::transcript::{
|
||||
ContentPart, MessageKind, MessageSource, TranscriptMessage, tool_result_from_json,
|
||||
};
|
||||
|
||||
fn sample_model_ref() -> ModelRef {
|
||||
ModelRef::new(provider_ids::openai(), "gpt-5".into())
|
||||
ModelRef::new(builtin::openai(), "gpt-5".into())
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -1036,12 +1036,13 @@ impl<'de> Deserialize<'de> for RunEvent {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use lithos_llm::catalog::builtin;
|
||||
use serde_json::json;
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
AuthMethod, BlobHash, CommandTermination, Edge, Graph, IdpIdentity, ModelRef, Node,
|
||||
PendingReason, WorkflowSettings, fixtures, provider_ids, test_support,
|
||||
PendingReason, WorkflowSettings, fixtures, test_support,
|
||||
};
|
||||
|
||||
fn user_principal(login: &str) -> Principal {
|
||||
|
|
@ -2364,7 +2365,7 @@ mod tests {
|
|||
fn agent_message_omits_context_window_when_absent() {
|
||||
let body = EventBody::AgentMessage(AgentMessageProps {
|
||||
text: "ok".to_string(),
|
||||
model: ModelRef::new(provider_ids::openai(), "gpt-5.4".into()),
|
||||
model: ModelRef::new(builtin::openai(), "gpt-5.4".into()),
|
||||
billing: BilledTokenCounts::default(),
|
||||
cost_source: None,
|
||||
tool_call_count: 0,
|
||||
|
|
@ -2391,7 +2392,7 @@ mod tests {
|
|||
fn agent_message_omits_reasoning_when_absent() {
|
||||
let body = EventBody::AgentMessage(AgentMessageProps {
|
||||
text: "ok".to_string(),
|
||||
model: ModelRef::new(provider_ids::openai(), "gpt-5.4".into()),
|
||||
model: ModelRef::new(builtin::openai(), "gpt-5.4".into()),
|
||||
billing: BilledTokenCounts::default(),
|
||||
cost_source: None,
|
||||
tool_call_count: 0,
|
||||
|
|
@ -2415,7 +2416,7 @@ mod tests {
|
|||
fn agent_message_carries_reasoning_through_canonical_json() {
|
||||
let body = EventBody::AgentMessage(AgentMessageProps {
|
||||
text: String::new(),
|
||||
model: ModelRef::new(provider_ids::openai(), "gpt-5.4".into()),
|
||||
model: ModelRef::new(builtin::openai(), "gpt-5.4".into()),
|
||||
billing: BilledTokenCounts::default(),
|
||||
cost_source: None,
|
||||
tool_call_count: 1,
|
||||
|
|
@ -2468,7 +2469,7 @@ mod tests {
|
|||
};
|
||||
let body = EventBody::AgentMessage(AgentMessageProps {
|
||||
text: "ok".to_string(),
|
||||
model: ModelRef::new(provider_ids::openai(), "gpt-5.4".into()),
|
||||
model: ModelRef::new(builtin::openai(), "gpt-5.4".into()),
|
||||
billing: BilledTokenCounts::default(),
|
||||
cost_source: None,
|
||||
tool_call_count: 0,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue