harn_vm/llm_config/
resolution.rs1use serde::Serialize;
5
6use super::*;
7
8#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
9pub struct ResolvedModel {
10 pub id: String,
11 pub provider: String,
12 pub alias: Option<String>,
13 pub tool_format: String,
14 pub tier: String,
15 pub family: String,
16 pub lineage: String,
17}
18
19pub fn resolve_model(alias: &str) -> (String, Option<String>) {
21 let config = effective_config();
22 if let Some(a) = config.aliases.get(alias) {
23 return (a.id.clone(), Some(a.provider.clone()));
24 }
25 (normalize_model_id(alias), None)
26}
27
28pub fn normalize_model_id(raw: &str) -> String {
35 for prefix in PROVIDER_SELECTOR_PREFIXES {
36 if let Some(stripped) = raw.strip_prefix(prefix) {
37 return stripped.to_string();
38 }
39 }
40 raw.to_string()
41}
42
43const PROVIDER_SELECTOR_PREFIXES: &[&str] =
44 &["ollama:", "local:", "huggingface:", "hf:", "cerebras/"];
45
46pub fn resolve_model_info(selector: &str) -> ResolvedModel {
49 let config = effective_config();
50 if let Some(alias) = config.aliases.get(selector) {
51 let id = alias.id.clone();
52 let provider = alias.provider.clone();
53 let requested = alias
54 .tool_format
55 .clone()
56 .unwrap_or_else(|| default_tool_format_with_config(&config, &id, &provider));
57 let tool_format = guard_tool_format(&provider, &id, &requested, Some(selector));
58 return ResolvedModel {
59 tier: model_tier_with_config(&config, &id),
60 family: model_family_with_config(&config, &provider, &id),
61 lineage: model_lineage_with_config(&config, &provider, &id),
62 id,
63 provider,
64 alias: Some(selector.to_string()),
65 tool_format,
66 };
67 }
68
69 let id = normalize_model_id(selector);
70 let inference = infer_provider_with_config(&config, selector);
71 let source = inference.source;
72 let provider = inference.provider;
73 let requested = default_tool_format_with_config(&config, &id, &provider);
74 let tool_format = guard_tool_format(&provider, &id, &requested, None);
75 let tier = model_tier_with_config(&config, &id);
76 let family = model_family_with_inference_source(&config, &provider, &id, source);
77 let lineage = model_lineage_with_inference_source(&config, &provider, &id, source);
78 ResolvedModel {
79 id,
80 provider,
81 alias: None,
82 tool_format,
83 tier,
84 family,
85 lineage,
86 }
87}
88
89fn guard_tool_format(provider: &str, model: &str, requested: &str, alias: Option<&str>) -> String {
96 let decision = crate::llm::capabilities::validate_tool_format(provider, model, requested);
97 if let Some(reason) = &decision.correction {
98 tracing::warn!(
99 target: "harn::llm::tool_format",
100 alias = alias.unwrap_or(""),
101 "{reason}"
102 );
103 }
104 decision.effective
105}