mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-06 02:48:25 +00:00
fabro(01KQT1TNZ0QXK0QHP10G0V5X84): simplify_gpt (succeeded)
Fabro-Run: 01KQT1TNZ0QXK0QHP10G0V5X84 Fabro-Completed: 7 ⚒️ Generated with [Fabro](https://fabro.sh)
This commit is contained in:
parent
6be8b42da5
commit
263b799ad4
4 changed files with 71 additions and 61 deletions
|
|
@ -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<Vec<String>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Combine for Option<Vec<CredentialRef>> {
|
||||
fn combine(self, other: Self) -> Self {
|
||||
self.or(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Combine for Option<Vec<ServerAuthMethod>> {
|
||||
fn combine(self, other: Self) -> Self {
|
||||
self.or(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Combine for Option<BTreeMap<String, CostRates>> {
|
||||
fn combine(self, other: Self) -> Self {
|
||||
self.or(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Combine for Option<HashMap<String, toml::Value>> {
|
||||
fn combine(self, other: Self) -> Self {
|
||||
self.or(other)
|
||||
|
|
|
|||
|
|
@ -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<CredentialRef> for String {
|
|||
|
||||
/// Error returned when a credential string is neither `credential:<id>` nor
|
||||
/// `env:<NAME>`. 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:<id>` or `env:<NAME>`; literal secret strings are rejected",
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -267,28 +284,25 @@ impl std::str::FromStr for CredentialRef {
|
|||
type Err = CredentialRefParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
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:<id>` or `env:<NAME>`; literal \
|
||||
secret strings are rejected"
|
||||
.to_string(),
|
||||
})
|
||||
Err(CredentialRefParseError(
|
||||
CredentialRefParseErrorKind::InvalidForm,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -300,44 +314,12 @@ impl TryFrom<String> for CredentialRef {
|
|||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Combine glue for primitives that don't already have it.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
use super::combine::Combine;
|
||||
|
||||
// `Option<i32>`, `Option<i64>`, etc. already have `Combine` impls in
|
||||
// `combine.rs`. Only add the impls that are unique to the LLM layer types.
|
||||
|
||||
impl Combine for Option<f64> {
|
||||
fn combine(self, other: Self) -> Self {
|
||||
self.or(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Combine for Option<NaiveDate> {
|
||||
fn combine(self, other: Self) -> Self {
|
||||
self.or(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Combine for Option<Vec<CredentialRef>> {
|
||||
fn combine(self, other: Self) -> Self {
|
||||
self.or(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Combine for Option<BTreeMap<String, CostRates>> {
|
||||
fn combine(self, other: Self) -> Self {
|
||||
self.or(other)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
|
||||
use super::*;
|
||||
use crate::layers::Combine;
|
||||
|
||||
// ---- CredentialRef ----------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,15 @@ impl From<FeaturesLayer> for SettingsLayer {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<LlmLayer> for SettingsLayer {
|
||||
fn from(llm: LlmLayer) -> Self {
|
||||
Self {
|
||||
llm: Some(llm),
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProjectLayer> for SettingsLayer {
|
||||
fn from(project: ProjectLayer) -> Self {
|
||||
Self {
|
||||
|
|
|
|||
|
|
@ -132,10 +132,13 @@ fn build_openai_compatible(config: AdapterConfig) -> Arc<dyn ProviderAdapter> {
|
|||
/// 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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue