From 49d0435f2cb34d65d1c77a8bea6fdb094176b81b Mon Sep 17 00:00:00 2001 From: Agent Date: Thu, 2 Jul 2026 19:27:10 +0200 Subject: [PATCH] fix(server): reconcile alias_to_name on reload (#150) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit load_models() reload rebuilds each non-running model's meta.aliases but never updated the global alias_to_name map (the pre-loop cleanup only drops entries whose target model is gone). get_meta() consults alias_to_name before the authoritative meta.aliases scan, so an alias removed from — or moved off — a still-existing model kept resolving to the old model (has_model, which skips the map, disagreed). After re-parsing a model's aliases, reconcile the map: erase that model's own entries, then register its current aliases. Scoped to the (non-running) model being re-parsed, so a running instance's entries — which #135 deliberately keeps when its meta.aliases are shadowed/lost — are left untouched. Correct for add/remove/move regardless of iteration order. --- tools/server/server-models.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/server/server-models.cpp b/tools/server/server-models.cpp index 5f6496e82983..3010819321c6 100644 --- a/tools/server/server-models.cpp +++ b/tools/server/server-models.cpp @@ -633,6 +633,25 @@ void server_models::load_models() { if (!conflict) inst.meta.aliases.insert(alias); } + // Keep the global alias_to_name map in sync with this model's re-parsed aliases (#150). + // Without this, an alias removed from (or moved off) a still-existing model leaves a + // stale alias_to_name entry, and get_meta() — which consults alias_to_name before the + // authoritative meta.aliases scan — mis-resolves the alias to the old model. + // Scoped to the (non-running) model being re-parsed: erase only its own entries, then + // register its current aliases. Running models' entries (which #135 deliberately keeps + // when a loaded instance's meta.aliases are shadowed/lost) are left untouched. Correct + // for add/remove/move regardless of the iteration order over models. + for (auto ait = alias_to_name.begin(); ait != alias_to_name.end(); ) { + if (ait->second == name) { + ait = alias_to_name.erase(ait); + } else { + ++ait; + } + } + for (const auto & alias : inst.meta.aliases) { + alias_to_name[alias] = name; + } + // re-parse tags inst.meta.tags.clear(); std::string tags_str;