use std::fmt::Write as _;
use crate::types::{CORE_DIMENSION_NAMES, CapabilityProfile, DIMENSION_NAMES};
const MISSING_MODEL_ID_PREVIEW: usize = 8;
impl CapabilityProfile {
pub fn format_human_table(&self, verbose: bool) -> String {
self.format_human_table_with(verbose, None)
}
pub fn format_human_table_with(&self, verbose: bool, advertised: Option<u32>) -> String {
let mut out = String::new();
let _ = writeln!(out, "=== Probe Results ===");
let _ = writeln!(out, "Weak < 0.4 Medium >= 0.4 Strong >= 0.8");
if !verbose {
let _ = writeln!(out, "(Showing core dimensions; use --verbose for all.)");
}
let _ = writeln!(out);
let dims: &[&str] = if verbose {
DIMENSION_NAMES
} else {
CORE_DIMENSION_NAMES
};
for &dim in dims {
if let Some(probe) = self.dimension_result(dim) {
let _ = writeln!(
out,
"{:<28}{:?} {:.1} / {:.1}",
format!("{}:", display_name(dim)),
probe.completed_level(),
if probe.is_skipped()
|| probe.is_synthesized_error()
|| probe.is_unprobed_default()
{
0.0
} else {
probe.score
},
probe.max_score
);
let _ = writeln!(out, "{:<28}{}", "", probe.details);
}
}
let _ = writeln!(out);
let _ = writeln!(out, "{:<28}{:?}", "Overall:", self.overall_level());
let _ = writeln!(
out,
"{:<28}{:?}",
"Edit format (probe ladder):",
self.best_edit_format()
);
let _ = writeln!(
out,
"{:<28}{}",
"Can use tools:",
if self.can_use_tools() { "yes" } else { "no" }
);
let _ = writeln!(
out,
"{:<28}{}",
"Vision:",
if self.supports_vision() {
"supported"
} else {
"not supported"
}
);
match self.max_tools() {
Some(n) => {
let _ = writeln!(out, "{:<28}{n}", "Max tools:");
}
None => {
let _ = writeln!(out, "{:<28}unlimited", "Max tools:");
}
}
if let Some(n) = self.recommended_context_tokens(advertised) {
let _ = writeln!(out, "{:<28}{n}", "Recommended context tokens:");
}
if let Some(n) = self.effective_context_tokens {
let _ = writeln!(out, "{:<28}{n}", "Effective context tokens:");
} else if let Some(n) = self.probed_context_floor {
let _ = writeln!(out, "{:<28}{n}", "Probed context floor:");
}
if self.needs_xml_fallback() {
let _ = writeln!(out, "{:<28}XML fallback needed", "");
}
if self.needs_json_repair() {
let _ = writeln!(out, "{:<28}JSON repair needed", "");
}
out
}
pub fn tool_gate_error(&self) -> Option<&'static str> {
if self.can_use_tools() {
None
} else {
Some("error: cannot use tools (native and XML both failed to complete)")
}
}
}
fn display_name(dim: &str) -> String {
dim.split('_')
.map(|word| {
let mut chars = word.chars();
match chars.next() {
None => String::new(),
Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
}
})
.collect::<Vec<_>>()
.join(" ")
}
pub fn missing_model_message<S: AsRef<str>>(ids: &[S]) -> String {
let n = ids.len();
let mut msg =
format!("error: --model is required unless GET /models returns exactly one id (got {n}");
if n == 0 {
msg.push(')');
return msg;
}
msg.push_str(": ");
for (i, id) in ids.iter().take(MISSING_MODEL_ID_PREVIEW).enumerate() {
if i > 0 {
msg.push_str(", ");
}
msg.push_str(id.as_ref());
}
if n > MISSING_MODEL_ID_PREVIEW {
msg.push_str(", ...");
}
msg.push(')');
msg
}