use std::collections::BTreeMap;
use crate::config_edit::brazen::{NOT_REQUIRED, ProviderRow};
use crate::model_pick::WORKER_ROLE;
use super::Unready;
pub(super) fn say(unready: &Unready, rows: &[ProviderRow]) -> String {
match unready {
Unready::Undeclared { provider } => undeclared(provider, rows),
Unready::Uncredentialed { row } => uncredentialed(row),
Unready::Wall => wall(rows),
}
}
fn remedy(row: &ProviderRow) -> String {
if row.login_blocked().is_none() {
format!("/login {}", row.name)
} else {
"write its key into this wall with /config brazen".to_owned()
}
}
fn uncredentialed(row: &ProviderRow) -> String {
let (provider, act) = (&row.name, remedy(row));
format!(
"sign in first: `{WORKER_ROLE}` resolves provider `{provider}`, which holds no credential in \
this workspace's wall, so a conversation begun here would reach no model — {act}"
)
}
fn undeclared(provider: &str, rows: &[ProviderRow]) -> String {
format!(
"`{WORKER_ROLE}` resolves provider `{provider}`, and this workspace's wall declares no \
such row, so a conversation begun here would reach no model — a wall holds brazen's \
built-in rows plus its own config.toml and nothing else, so add the row with \
/config brazen, or point the role at one that is here with \
/model {WORKER_ROLE} <provider> <model-id> (rows here: {})",
names(rows)
)
}
#[derive(PartialEq, Eq, PartialOrd, Ord)]
enum Act {
SignIn,
WriteKey,
NameInRole,
Never,
}
fn act(row: &ProviderRow) -> Act {
if row.credential == NOT_REQUIRED {
if row.tools_blocked().is_none() {
Act::NameInRole
} else {
Act::Never
}
} else if row.login_blocked().is_none() {
Act::SignIn
} else {
Act::WriteKey
}
}
fn phrase(act: &Act) -> &'static str {
match act {
Act::SignIn => "sign in with /login",
Act::WriteKey => "write a key with /config brazen",
Act::NameInRole => "name in a role with /model <role> <provider> <model-id>",
Act::Never => "can serve no role",
}
}
fn wall(rows: &[ProviderRow]) -> String {
let mut by_act: BTreeMap<Act, Vec<&str>> = BTreeMap::new();
for row in rows {
by_act.entry(act(row)).or_default().push(&row.name);
}
let offers: Vec<String> = by_act
.iter()
.map(|(act, names)| format!("{}: {}", phrase(act), names.join(", ")))
.collect();
format!(
"sign in first: no provider in this workspace's wall holds a credential, so a \
conversation begun here would reach no model — {}",
offers.join("; ")
)
}
fn names(rows: &[ProviderRow]) -> String {
rows.iter()
.map(|row| row.name.as_str())
.collect::<Vec<&str>>()
.join(", ")
}