Release 0.2.0 #4

Merged
dguiducci merged 96 commits from main into release 2026-08-17 18:07:20 +01:00
5 changed files with 31 additions and 9 deletions
Showing only changes of commit ea31fad188 - Show all commits
+1 -1
View File
@@ -284,7 +284,7 @@ impl Compaction {
let request = ModelRequest { let request = ModelRequest {
messages: vec![json!({ "role": "user", "content": body })], messages: vec![json!({ "role": "user", "content": body })],
tools: Vec::new(), tools: Vec::new(),
model: handle.id.clone(), model: handle.wire_model().to_string(),
max_tokens: None, max_tokens: None,
temperature: self.temperature, temperature: self.temperature,
request_id: uuid_like(), request_id: uuid_like(),
+1 -1
View File
@@ -149,7 +149,7 @@ pub(crate) async fn run(
let req = ModelRequest { let req = ModelRequest {
messages: messages.clone(), messages: messages.clone(),
tools: defs.clone(), tools: defs.clone(),
model: handle.id.clone(), model: handle.wire_model().to_string(),
max_tokens: None, max_tokens: None,
temperature: None, temperature: None,
request_id: mint_request_id(), request_id: mint_request_id(),
+16 -3
View File
@@ -262,6 +262,18 @@ pub struct ModelHandle {
pub id: ModelId, pub id: ModelId,
pub model: Arc<dyn Model>, pub model: Arc<dyn Model>,
pub info: ModelInfo, pub info: ModelInfo,
/// Wire model name when it differs from `id`: a selector whose `id` is a
/// bookkeeping key (Skald: the user-facing alias keying its model
/// registry) sets this to the provider's API model id. `None` ⇒ `id`
/// goes on the wire.
pub wire_id: Option<ModelId>,
}
impl ModelHandle {
/// The model identifier to put on the wire.
pub fn wire_model(&self) -> &str {
self.wire_id.as_deref().unwrap_or(&self.id)
}
} }
// ── ModelHint ──────────────────────────────────────────────────────────────── // ── ModelHint ────────────────────────────────────────────────────────────────
@@ -347,9 +359,10 @@ pub trait NamedModel: Model + 'static {
Self: Sized, Self: Sized,
{ {
ModelHandle { ModelHandle {
id: self.default_model().to_string(), id: self.default_model().to_string(),
model: Arc::new(self), model: Arc::new(self),
info: ModelInfo::default(), info: ModelInfo::default(),
wire_id: None,
} }
} }
} }
+4 -3
View File
@@ -118,9 +118,10 @@ impl Model for FakeModel {
/// `requests()` afterwards). /// `requests()` afterwards).
pub fn handle(fake: &std::sync::Arc<FakeModel>, id: &str) -> crate::model::ModelHandle { pub fn handle(fake: &std::sync::Arc<FakeModel>, id: &str) -> crate::model::ModelHandle {
crate::model::ModelHandle { crate::model::ModelHandle {
id: id.to_string(), id: id.to_string(),
model: fake.clone(), model: fake.clone(),
info: crate::model::ModelInfo::default(), info: crate::model::ModelInfo::default(),
wire_id: None,
} }
} }
@@ -91,7 +91,12 @@ impl ModelSelector for SkaldSelector {
}; };
let model = self.instrument(&name, &entry); let model = self.instrument(&name, &entry);
Ok(ModelHandle { Ok(ModelHandle {
id: name, // `id` is the registry alias: health, fallback exclusion and the
// chat's model pin all key on it. `wire_id` is what the provider
// API must see (`llm_models.model_id`) — an alias renamed in the
// UI must never change the request's model field.
id: name,
wire_id: Some(entry.model.clone()),
model, model,
info: model_info_of(&entry), info: model_info_of(&entry),
}) })
@@ -157,7 +162,10 @@ mod tests {
let sel = SkaldSelector::new(manager, None); let sel = SkaldSelector::new(manager, None);
let h = sel.select(&ModelHint::name("weak-model"), &[]).await.unwrap(); let h = sel.select(&ModelHint::name("weak-model"), &[]).await.unwrap();
// The handle keys on the alias; the wire carries the provider model id.
assert_eq!(h.id, "weak-model"); assert_eq!(h.id, "weak-model");
assert_eq!(h.wire_id.as_deref(), Some("weak-id"));
assert_eq!(h.wire_model(), "weak-id");
assert!(sel.select(&ModelHint::name("nope"), &[]).await.is_err()); assert!(sel.select(&ModelHint::name("nope"), &[]).await.is_err());