pub mod grammar;
pub mod header;
pub mod query;
pub mod remedy;
#[cfg(test)]
pub(crate) mod tests;
pub use grammar::{GrammarError, RoleModel};
pub use header::{
ConfigPoint, ModelRow, NEW_CONVERSATION_EXIT, birth_row, conversation_row, row_role,
};
pub use remedy::{Remedy, remedy};
pub const WORKER_ROLE: &str = "worker";
pub const BRANCH: &str = "default";
pub const PROVIDERS: &str = "providers.yaml";
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum PickError {
#[error("{0}")]
Grammar(GrammarError),
#[error(
"brazen's table has no provider row `{provider}` — pick a live row here, \
or add the row to brazen's own config"
)]
UnknownProvider { provider: String },
#[error(
"`{model}` is not a plain model id — yog writes it as a block key in \
both models.yaml and providers.yaml; use the Config editors for \
anything else"
)]
NotAnId { model: String },
}
fn is_plain_id(model: &str) -> bool {
!model.is_empty() && !model.contains([' ', '\t', ':', '#'])
}
pub fn default_row(current: &str, rows: &[String]) -> String {
match rows.first() {
Some(first) if !rows.iter().any(|r| r == current) => first.clone(),
_ => current.to_owned(),
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Plan {
pub models_yaml: Option<String>,
pub providers_yaml: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Pick {
pub role: String,
pub provider: String,
pub model: String,
}
impl Pick {
pub fn of(role: &str, provider: &str, model: &str) -> Self {
Self {
role: role.to_owned(),
provider: provider.to_owned(),
model: model.to_owned(),
}
}
}
pub fn plan(
models_yaml: &str,
providers_yaml: &str,
rows: &[String],
pick: &Pick,
) -> Result<Plan, PickError> {
if grammar::is_unknown_row(&pick.provider, rows) {
return Err(PickError::UnknownProvider {
provider: pick.provider.clone(),
});
}
if !is_plain_id(&pick.model) {
return Err(PickError::NotAnId {
model: pick.model.clone(),
});
}
let declared = grammar::declare_model(models_yaml, &pick.model, &pick.provider)
.map_err(PickError::Grammar)?;
let assigned = grammar::set_role_model(providers_yaml, &pick.role, &pick.provider, &pick.model)
.map_err(PickError::Grammar)?;
Ok(Plan {
models_yaml: declared,
providers_yaml: assigned,
})
}
pub fn scope_sentence(workspace_leaf: &str, branch: &str, short_oid: &str) -> String {
format!(
"changes config/{branch} for the whole {workspace_leaf} workspace — \
it governs the NEXT conversation started here; this one stays frozen \
at {short_oid}"
)
}
pub fn birth_sentence(workspace_leaf: &str, branch: &str) -> String {
format!(
"this moves the {workspace_leaf} workspace default too: picking here \
advances config/{branch}, and every conversation started next — \
including the one you are about to start — is born on it"
)
}
pub const WRITE_NOTE: &str = "writes models.yaml first (capabilities and context window are declared \
defaults — brazen publishes neither), then providers.yaml through `lernie \
config`";