From 263b799ad4aa2c2f52fe661f7d88a8cf3a6f8d01 Mon Sep 17 00:00:00 2001 From: Fabro Date: Mon, 4 May 2026 18:54:15 +0000 Subject: [PATCH] fabro(01KQT1TNZ0QXK0QHP10G0V5X84): simplify_gpt (succeeded) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fabro-Run: 01KQT1TNZ0QXK0QHP10G0V5X84 Fabro-Completed: 7 ⚒️ Generated with [Fabro](https://fabro.sh) --- lib/crates/fabro-config/src/layers/combine.rs | 18 +++- lib/crates/fabro-config/src/layers/llm.rs | 94 ++++++++----------- .../fabro-config/src/layers/settings.rs | 9 ++ lib/crates/fabro-llm/src/adapter_registry.rs | 11 ++- 4 files changed, 71 insertions(+), 61 deletions(-) diff --git a/lib/crates/fabro-config/src/layers/combine.rs b/lib/crates/fabro-config/src/layers/combine.rs index 58a0f2a03..a3ce2e70c 100644 --- a/lib/crates/fabro-config/src/layers/combine.rs +++ b/lib/crates/fabro-config/src/layers/combine.rs @@ -1,5 +1,6 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; +use chrono::NaiveDate; use fabro_types::settings::cli::{CliAuthStrategy, OutputFormat, OutputVerbosity}; use fabro_types::settings::run::{ AgentPermissions, ApprovalMode, DaytonaNetworkLayer, MergeStrategy, RunMode, WorktreeMode, @@ -13,6 +14,7 @@ use fabro_types::settings::{Duration, InterpString, Size}; use super::LogFilter; use super::cli::{CliAuthLayer, CliLoggingLayer, CliTargetLayer}; use super::features::FeaturesLayer; +use super::llm::{CostRates, CredentialRef}; use super::run::{ DaytonaSnapshotLayer, HookAgentMarker, HookEntry, HookTlsMode, InterviewProviderLayer, LocalSandboxLayer, ModelRefOrSplice, NotificationProviderLayer, RunArtifactsLayer, @@ -57,6 +59,7 @@ macro_rules! impl_combine_or_option { impl_combine_or_option!( String, bool, + f64, u16, u32, u64, @@ -78,6 +81,7 @@ impl_combine_or_option!( WorktreeMode, GithubIntegrationStrategy, LogDestination, + NaiveDate, ObjectStoreProvider, ServerAuthMethod, WebhookStrategy, @@ -90,12 +94,24 @@ impl Combine for Option> { } } +impl Combine for Option> { + fn combine(self, other: Self) -> Self { + self.or(other) + } +} + impl Combine for Option> { fn combine(self, other: Self) -> Self { self.or(other) } } +impl Combine for Option> { + fn combine(self, other: Self) -> Self { + self.or(other) + } +} + impl Combine for Option> { fn combine(self, other: Self) -> Self { self.or(other) diff --git a/lib/crates/fabro-config/src/layers/llm.rs b/lib/crates/fabro-config/src/layers/llm.rs index 8f3d13ae9..109b98143 100644 --- a/lib/crates/fabro-config/src/layers/llm.rs +++ b/lib/crates/fabro-config/src/layers/llm.rs @@ -33,6 +33,9 @@ use serde::{Deserialize, Deserializer, Serialize}; use super::maps::MergeMap; +const CREDENTIAL_REF_PREFIX: &str = "credential:"; +const ENV_REF_PREFIX: &str = "env:"; + /// Top-level `[llm]` settings layer. #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, fabro_macros::Combine)] #[serde(deny_unknown_fields)] @@ -233,8 +236,8 @@ impl std::fmt::Display for CredentialRef { // any resolved secret value. Env names and credential IDs are not // themselves secret. match self { - Self::Credential(id) => write!(f, "credential:{id}"), - Self::Env(name) => write!(f, "env:{name}"), + Self::Credential(id) => write!(f, "{CREDENTIAL_REF_PREFIX}{id}"), + Self::Env(name) => write!(f, "{ENV_REF_PREFIX}{name}"), } } } @@ -247,17 +250,31 @@ impl From for String { /// Error returned when a credential string is neither `credential:` nor /// `env:`. Literal secret strings always fall into this branch and -/// fail deserialization — by design. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CredentialRefParseError { - /// Reason the input was rejected. Never echoes the input itself, since - /// it could be a literal secret. - message: String, +/// fail deserialization — by design. Variants deliberately never carry the +/// rejected input, since it could be a literal secret. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CredentialRefParseError(CredentialRefParseErrorKind); + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum CredentialRefParseErrorKind { + MissingCredentialId, + MissingEnvName, + InvalidForm, } impl std::fmt::Display for CredentialRefParseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.message) + match self.0 { + CredentialRefParseErrorKind::MissingCredentialId => { + f.write_str("credential reference is missing an ID after `credential:`") + } + CredentialRefParseErrorKind::MissingEnvName => { + f.write_str("credential reference is missing a name after `env:`") + } + CredentialRefParseErrorKind::InvalidForm => f.write_str( + "credential reference must be `credential:` or `env:`; literal secret strings are rejected", + ), + } } } @@ -267,28 +284,25 @@ impl std::str::FromStr for CredentialRef { type Err = CredentialRefParseError; fn from_str(s: &str) -> Result { - if let Some(id) = s.strip_prefix("credential:") { + if let Some(id) = s.strip_prefix(CREDENTIAL_REF_PREFIX) { if id.is_empty() { - return Err(CredentialRefParseError { - message: "credential reference is missing an ID after `credential:`" - .to_string(), - }); + return Err(CredentialRefParseError( + CredentialRefParseErrorKind::MissingCredentialId, + )); } return Ok(Self::Credential(id.to_string())); } - if let Some(name) = s.strip_prefix("env:") { + if let Some(name) = s.strip_prefix(ENV_REF_PREFIX) { if name.is_empty() { - return Err(CredentialRefParseError { - message: "credential reference is missing a name after `env:`".to_string(), - }); + return Err(CredentialRefParseError( + CredentialRefParseErrorKind::MissingEnvName, + )); } return Ok(Self::Env(name.to_string())); } - Err(CredentialRefParseError { - message: "credential reference must be `credential:` or `env:`; literal \ - secret strings are rejected" - .to_string(), - }) + Err(CredentialRefParseError( + CredentialRefParseErrorKind::InvalidForm, + )) } } @@ -300,44 +314,12 @@ impl TryFrom for CredentialRef { } } -// --------------------------------------------------------------------------- -// Combine glue for primitives that don't already have it. -// --------------------------------------------------------------------------- - -use super::combine::Combine; - -// `Option`, `Option`, etc. already have `Combine` impls in -// `combine.rs`. Only add the impls that are unique to the LLM layer types. - -impl Combine for Option { - fn combine(self, other: Self) -> Self { - self.or(other) - } -} - -impl Combine for Option { - fn combine(self, other: Self) -> Self { - self.or(other) - } -} - -impl Combine for Option> { - fn combine(self, other: Self) -> Self { - self.or(other) - } -} - -impl Combine for Option> { - fn combine(self, other: Self) -> Self { - self.or(other) - } -} - #[cfg(test)] mod tests { use std::str::FromStr; use super::*; + use crate::layers::Combine; // ---- CredentialRef ---------------------------------------------------- diff --git a/lib/crates/fabro-config/src/layers/settings.rs b/lib/crates/fabro-config/src/layers/settings.rs index 273470ac7..4864ff5ae 100644 --- a/lib/crates/fabro-config/src/layers/settings.rs +++ b/lib/crates/fabro-config/src/layers/settings.rs @@ -65,6 +65,15 @@ impl From for SettingsLayer { } } +impl From for SettingsLayer { + fn from(llm: LlmLayer) -> Self { + Self { + llm: Some(llm), + ..Self::default() + } + } +} + impl From for SettingsLayer { fn from(project: ProjectLayer) -> Self { Self { diff --git a/lib/crates/fabro-llm/src/adapter_registry.rs b/lib/crates/fabro-llm/src/adapter_registry.rs index 6e99f1d81..2707022c0 100644 --- a/lib/crates/fabro-llm/src/adapter_registry.rs +++ b/lib/crates/fabro-llm/src/adapter_registry.rs @@ -132,10 +132,13 @@ fn build_openai_compatible(config: AdapterConfig) -> Arc { /// Single source of truth pairing every adapter key with its factory. Both /// `factory_for` and `registered_keys` derive from this table. const FACTORIES: &[(&str, AdapterFactory)] = &[ - ("anthropic", build_anthropic), - ("openai", build_openai), - ("gemini", build_gemini), - ("openai_compatible", build_openai_compatible), + (model_adapter::ANTHROPIC.key, build_anthropic), + (model_adapter::OPENAI.key, build_openai), + (model_adapter::GEMINI.key, build_gemini), + ( + model_adapter::OPENAI_COMPATIBLE.key, + build_openai_compatible, + ), ]; /// Look up a factory by adapter key. Returns `None` if the key has no factory