19#include <nlohmann/json.hpp>
75 const std::string& name,
76 const std::filesystem::path& adapter_path,
80 std::lock_guard<std::mutex> lock(adapter_mutex_);
86 auto existing = adapters_.find(name);
88 &&
existing->second.handle ==
nullptr;
92 logger->error(
"Cannot load adapter '{}': {}",
93 name, !model ?
"base model is null" :
"duplicate name");
100 logger->error(
"llama_adapter_lora_init failed for '{}' at {}",
101 name, adapter_path.string());
107 AdapterEntry& entry = adapters_[name];
109 entry.path = adapter_path;
115 logger->info(
"Loaded adapter '{}' from {} in {:.1f}ms (scale={:.2f})",
116 name, adapter_path.string(),
135 std::lock_guard<std::mutex> lock(adapter_mutex_);
137 auto it = adapters_.find(name);
138 if (
it == adapters_.end()) {
142 auto& entry =
it->second;
145 active_name_.clear();
150 entry.handle =
nullptr;
154 logger->info(
"Unloaded adapter '{}'", name);
176 std::lock_guard<std::mutex> lock(adapter_mutex_);
178 auto it = adapters_.find(name);
185 logger->error(
"Cannot activate adapter '{}': {}",
186 name,
it == adapters_.end() ?
"not found" :
"state is COLD");
190 auto& entry =
it->second;
193 if (!active_name_.empty() && active_name_ != name) {
194 auto active_it = adapters_.find(active_name_);
204 logger->info(
"Activated adapter '{}' (scale={:.2f})", name, entry.scale);
220 std::lock_guard<std::mutex> lock(adapter_mutex_);
222 if (active_name_.empty()) {
226 auto it = adapters_.find(active_name_);
227 if (
it != adapters_.end()) {
234 logger->info(
"Deactivated adapter '{}'", active_name_);
235 active_name_.clear();
255 std::lock_guard<std::mutex> lock(adapter_mutex_);
257 auto it = adapters_.find(name);
263 if (
cannot_swap || !fire_swap_hook(active_name_, name,
it->second.path)) {
264 logger->error(
"Cannot swap to adapter '{}': {}",
265 name,
cannot_swap ?
"not found or COLD" :
"cancelled by hook");
272 if (!active_name_.empty()) {
273 auto active_it = adapters_.find(active_name_);
280 auto& target =
it->second;
284 std::string
previous = active_name_;
287 logger->info(
"Swapped adapter '{}' -> '{}' in {:.1f}ms",
308 std::lock_guard<std::mutex> lock(adapter_mutex_);
313 for (
auto& [name, entry] : adapters_) {
314 if (entry.model != model) {
327 entry.handle =
nullptr;
335 if (name == active_name_) {
336 active_name_.clear();
338 adapters_.erase(name);
341 logger->info(
"Unloaded {} adapter(s) for model",
to_remove.size());
359 std::lock_guard<std::mutex> lock(adapter_mutex_);
364 for (
auto& [name, entry] : adapters_) {
365 if (entry.model != model) {
continue; }
370 if (name == active_name_) { active_name_.clear(); }
373 entry.handle =
nullptr;
376 entry.model =
nullptr;
381 logger->info(
"Released {} adapter handle(s); registrations kept "
398 std::lock_guard<std::mutex> lock(adapter_mutex_);
400 for (
auto& [name, entry] : adapters_) {
403 entry.handle =
nullptr;
409 active_name_.clear();
411 logger->info(
"Unloaded all {} adapter(s) on shutdown",
freed);
425 std::lock_guard<std::mutex> lock(adapter_mutex_);
426 auto it = adapters_.find(name);
427 if (
it == adapters_.end()) {
430 return it->second.state;
441 std::lock_guard<std::mutex> lock(adapter_mutex_);
442 auto it = adapters_.find(name);
443 if (
it == adapters_.end()) {
446 return make_info(
it->second);
456 std::lock_guard<std::mutex> lock(adapter_mutex_);
457 std::vector<AdapterInfo> result;
458 result.reserve(adapters_.size());
459 for (
const auto& [name, entry] : adapters_) {
460 result.push_back(make_info(entry));
473 std::lock_guard<std::mutex> lock(adapter_mutex_);
496AdapterInfo AdapterManager::make_info(
const AdapterEntry& entry) {
522bool AdapterManager::fire_swap_hook(
524 const std::string& target,
527 if (!hooks_.fire_pre || !hooks_.registry) {
533 ctx[
"target_adapter"] = target;
538 int rc = hooks_.fire_pre(
AdapterManager — LoRA adapter lifecycle and hot-swap.
long long elapsed_ms
Wall time, spawn to reap.
bool swap(const std::string &name, llama_context *ctx)
Swap to a different adapter atomically.
std::vector< AdapterInfo > list_adapters() const
List all known adapters.
bool activate(const std::string &name, llama_context *ctx)
Activate adapter on context (WARM -> HOT).
std::string active_adapter() const
Get the currently HOT adapter name.
void unload_all_for_model(llama_model *model, llama_context *ctx)
Unload all adapters for a given base model.
void release_handles_for_model(llama_model *model, llama_context *ctx)
Free a base model's adapter handles, KEEPING the registrations (gh#164).
void deactivate(llama_context *ctx)
Deactivate current HOT adapter (HOT -> WARM).
bool load(const std::string &name, const std::filesystem::path &adapter_path, llama_model *model, float scale=1.0f)
Load a LoRA adapter into RAM (COLD -> WARM).
void unload(const std::string &name, llama_context *ctx)
Unload adapter (any state -> COLD).
AdapterInfo info(const std::string &name) const
Get metadata for an adapter.
void unload_all()
Free every loaded adapter handle (gh#58 close-out, v2.3.0).
AdapterState state(const std::string &name) const
Get adapter state.
void set_hook_interface(const HookInterface &hooks)
Set hook interface for ON_ADAPTER_SWAP dispatch.
@ ENTROPIC_HOOK_ON_ADAPTER_SWAP
16: Adapter/LoRA swap requested
spdlog initialization and logger access.
auto now()
Get current time for timing measurements.
ENTROPIC_EXPORT std::shared_ptr< spdlog::logger > get(const std::string &name)
Get or create a named logger.
double elapsed_ms(std::chrono::steady_clock::time_point start, std::chrono::steady_clock::time_point end)
Compute elapsed milliseconds between two time points.
Activate model on GPU (WARM → ACTIVE).
@ optional
optional: every escape asks the host's path approver
AdapterState
LoRA adapter lifecycle state.
@ WARM
Loaded in RAM via llama_adapter_lora_init(). Ready to activate.
@ COLD
Not loaded. No resources consumed.
@ HOT
Active on context via llama_set_adapter_lora(). Influencing generation.
Metadata for a loaded LoRA adapter.
std::string tier_name
Tier this adapter is assigned to (empty = unassigned)
size_t ram_bytes
RAM consumption when WARM/HOT (0 if COLD)
std::filesystem::path path
Resolved path to .gguf adapter file.
AdapterState state
Current lifecycle state.
std::string name
Unique adapter identifier.
std::unordered_map< std::string, std::string > metadata
Adapter-specific metadata for routing decisions.
float scale
LoRA scaling factor (alpha/rank)