Repository navigation
Serves System One decision models at POST /v1/systemone, with the Kev and Clef families, LoRA variants and a prefix-state cache.
Added
-
loader::load_safetensors_with_report— the regular SafeTensors load, plus aTensorLoadReport: the tensors uploaded, the tensors left on disk, and the compute dtype.loader::model_torch_dtypegives the dtype a model'sconfig.jsonnames. -
tests/decision_loader_real_file.rs— a Qwen3.5 decision model (Jebadiah, the Mapika decider) through blazr's loader, thenLabelTokenHeadagainst reference fixtures, from SafeTensors or GGUF, on CPU or CUDA. It skips unlessBLAZR_DECISION_MODEL_DIRorBLAZR_DECISION_GGUF, andBLAZR_DECISION_FIXTURE_DIR, are set. -
POST /v1/systemone— typed decisions from a System One model (Jebadiah, the Mapika decider), each answer in the family's own wire shape. The family comes from--decision-family, a sidecar beside the weights, or the GGUF header. Each model gets one decision worker thread: requests with a short shared prefix merge into one run, longer ones run once over their prefix. Limits answer413and a full queue503. Keys:inference.decision.*and the--decision-*flags.GET /v1/modelsadds adecisionobject read without loading weights. -
blazr_decision_*metrics — requests, rows, prefill tokens, latency and queued rows, by model. -
blazr decision calibrate— fits one temperature per answer type (choice, noul, score) of a decision model on a JSON-lines label file, with boostr's fitters. A line is a labelled request (state,questions,labels), rendered by the model's renderer and run at temperature 1 on its decision worker, or a precomputeddecider/calibrate.pyrecord. A records-only file loads no weights. A type with fewer than--min-rowsanswers keeps the vendor temperature. The fit goes toblazr_calibration.jsonin the sidecar directory, or--out.--dry-runwrites nothing.blazr serveand/v1/modelstake each type that file sets over the vendor'stemperature_by_typeortemperatures.json.calibration.sourceis thenblazr_calibration.json, and/v1/modelsaddsfitted_atand per-typesources. An invalid file stops the model from loading. -
boostr::inference::decision::fit_temperature_mixed— one temperature over listed and isolated Score answers together, the Score fit ofblazr decision calibrate. -
LoRA variants — a PEFT adapter applies to a loaded
qwen35model as the variant<model>:<name>, built with boostr'sLoadedModel::derive_with_adapter: shared base weights, the adapter unmerged, its own executor and KV cache.serve --lora <dir>[=<name>](repeatable) andinference.loraregister variants of the start model;POST /v1/loraregisters one at run time. A request selects a variant bymodel: "<model>:<name>"orlora_adapter; an unknown adapter is a404.runandgeneratetake one--lora./v1/modelsandGET /v1/loralist each variant's base, path, rank and adapted module count. Eviction drops a variant before its base; a registered variant builds again on its next request./v1/systemoneserves variants. Data-parallel start models refuse adapters. -
tests/lora_variant_real_file.rs— a Qwen3.5 base and a PEFT adapter through the scheduler's variant path, checked againsttransformers+peftlogits. It skips unlessBLAZR_LORA_BASE_DIR,BLAZR_LORA_ADAPTER_DIR,BLAZR_LORA_REFandBLAZR_LORA_BASE_REFare set. -
Kev on
POST /v1/systemone— a Kev directory (a LoRA adapter and a pointer head inhead.pt, no base weights) in the model directory serves by its name. blazr finds the base with--decision-base(inference.decision.base), else by the adapter'sbase_model_name_or_pathin the model directory or a Hugging Face hub cache, and never downloads it. The base loads once under its own name. The Kev model is the LoRA variant of it, and boostr'sPointerHeadreads the answers at the fitted temperaturehead.ptholds. Prompts and answers follow Kev's own code: every question on its own row, at most 255 options, states over 65,536 tokens refused (--decision-truncate-statescuts them instead), 4-digit answers, and Kev'susage./v1/modelsreportsfamily: "kev",readout: "pointer", the base, the adapter rank and the temperature. -
tests/decision_kev_fixtures.rsandtests/decision_kev_route.rs— Kev's rows, positions and answers against fixtures from Kev's own code, without weights; then the route end to end on the CPU in F32. They skip unlessBLAZR_DECISION_MODEL_DIRandBLAZR_DECISION_FIXTURE_DIRare set, and the route test alsoBLAZR_DECISION_BASE. -
Clef on
POST /v1/systemone— a Clef or Clef-Flash directory serves by its name: a full fine-tuned Qwen3.5 checkpoint withjoint_head_config.jsonandjoint_head.safetensorsbeside it, or any checkpoint named Clef with--decision-family clef. The backbone loads through blazr's own loader; boostr'sJointSchemaHeadreads every hidden row of the record and scores all questions together, in F32, with no temperature. Prompts, option order, limits, error words and answers follow the release'sjoint_schema_model.py: one record of at most 16,384 tokens with the state cut to fit, choice probabilities in the order the request wrote the keys,confidencethe chosen option's probability, and a one-option field accepted. Control-token text in a request stays text, unlike the release. Requests with images or video are refused./v1/modelsreportsfamily: "clef",readout: "joint_schema"and the head's width and dtype.blazr decision calibraterefuses Clef. Clef-Flash's text backbone is 16.7 GiB in BF16: it serves on the CPU with that much free RAM, or on one GPU that holds it. -
tests/decision_clef_fixtures.rsandtests/decision_clef_route.rs— Clef's records and spans against the release's fixtures, and the head through blazr's readout over the fixtures' saved hidden rows, without the backbone; then the route end to end on the CPU. They skip unlessBLAZR_DECISION_MODEL_DIRandBLAZR_DECISION_FIXTURE_DIRare set, and the route test alsoBLAZR_CLEF_FULL=1. -
Decision prefix-state cache — each decision model's worker keeps the model's state after a request's state prefix on the device. A later
/v1/systemonerequest about the same state reads it back and runs only its questions. The key is the loaded weights (each LoRA or Kev variant has its own), the family and the prefix ids. With the cache on, a request's prefix ends at the family's state boundary, for one question too. Kept states count againstlane_budget_mb: before a run the worker drops the least recently used states so that they, the run's state and its largest pass fit. A model that unloads drops its states. Clef keeps none, since its head reads the whole record. Size:inference.decision.prefix_cache_mband--decision-prefix-cache-mb, default 2048 MiB,0off. Responses fillusage.cached_tokensand the newusage.cached_input_tokenswith the prefix tokens a hit saved. Kev'susageis unchanged./v1/modelsaddsdecision.prefix_cache. New metrics:blazr_decision_prefix_cache_{hits,misses,evictions}_totalandblazr_decision_prefix_cache_bytes. -
tests/decision_prefix_cache_real_file.rs— the route with the cache on: each fixture twice, then the same state with other questions twice. The first send matches the reference, and each hit matches the first send to one rounding unit. It skips unlessBLAZR_DECISION_MODEL_DIRandBLAZR_DECISION_FIXTURE_DIRare set. -
docs/decision-models.md— the System One guide: the families, how to run each, calibration, the prefix-state cache, limits and the tested matrix. The README, API reference and configuration reference link to it.
Changed
engine::decision::preparetakes aPrefixRule(min_tokens,at_state) in place of the shared-prefix minimum.Pending::wait_answeredreturns the answers with the prompt tokens the prefix-state cache saved.RenderedDecisiongainsstate_end, the row position where the state ends, andRenderedDecision::new.Executor::get_embeddingsis a plain function./v1/embeddingsand/rerankrun it on a blocking thread, never inside an async task.POST /v1/lorareads adapters through boostr'sPeftAdapter. A load now fails whenadapter_config.jsonis missing or lacksrorlora_alpha. It also fails on an unpairedlora_A/lora_B, a rank mismatch,.binweights, DoRA,fan_in_fan_out,lora_biasandmodules_to_save.use_rslora,rank_patternandalpha_patternnow set each module's scaling.- Model lookup errors — an unknown model or LoRA adapter returns
404model_not_found. A load that fails returns500model_load_failed. A load the device cannot hold returns503model_load_out_of_memory. Before, a failed load returned404. - Model loads — base-model and LoRA-variant loads run on a blocking thread. A load gate makes concurrent requests for one model wait for a single load.
- Load path — the server,
run,chatandbenchshare one set of load steps.run,chatandbenchreport a failed CUDA client asFailed to create CUDA client for preload: .... The text wasFailed to create CUDA client: .... - Chat template file — a model directory's
chat_template.jinjais read beforetokenizer_config.json.bos_tokenandeos_tokencome from the model's config.tojsonhonoursseparators, and floats render as Python'srepr. - Dependencies — boostr 0.9, voxr 0.7, and voxr-narrate 0.7.
- Tests —
.config/nextest.tomlrunsarch_referenceandbatch_decode_per_rowin aheavy-modelgroup of two threads.
Removed
engine::load_lora_adapter,engine::LoraAdapter,engine::LoraAdapterRegistry, andExecutor::{load_lora, unload_lora, list_loras, lora_registry}.Scheduler::{register_variant, remove_variant, variants, select_model}replace them.
Fixed
- Command stack on Windows — the binary runs its command on a thread with a 16 MiB stack. The command's frames overflowed the 1 MiB main-thread stack of a Windows process, and
sound-reviewandspeakcrashed at start. Linux and macOS have 8 MiB and did not crash. - Sharded SafeTensors directories — a directory with
model.safetensors.index.jsonloads only the shards the index names (boostr'sSafeTensorsLoader). Every.safetensorsfile of the directory loaded before, so a head or adapter file beside the shards was read as part of the model. lora_adapteron generation requests — it now runs the request on the adapter's variant. It was logged and ignored before: the request generated with the base weights, and an unknown name fell back to the base.- Qwen3.5 SafeTensors configs — a
qwen3_5(nestedtext_config) orqwen3_5_textconfig.jsongoes to boostr'sqwen35_config_from_hfbefore any other parse. It fell through to tensor-name detection or a partial parse before. - Config dtype — the compute dtype reads
torch_dtype, thendtype, then both undertext_config. Only the top-leveltorch_dtypewas read before, so transformers v5 andQwen3_5ForConditionalGenerationconfigs fell back to the backend default. - Qwen3.5 MTP and vision tensors — they stay on disk in every SafeTensors path. They were uploaded to the device and then dropped before.
- Qwen3.5 edit precision —
1 + wand-exp(A_log)round once, to the compute dtype. Each 1-D tensor waits in F32 when the compute dtype cannot hold its file value. A BF16 model rounded these edits twice before, and the F32A_logwas rounded to BF16 first. - Sharded checkpoints named by an index — a directory with
model.safetensors.index.jsonis SafeTensors whatever its shard names, such asmodel.safetensors-00001-of-00002.safetensors. It failed withNo supported model files foundbefore. - Offloading load —
load_safetensors_with_offloadingcallsrestructure_hf_checkpoint, as the other SafeTensors paths do. It takes the layer count from the config and the layer prefix from the tensor names. Non-Llama layouts failed to load through it before. - Qwen3.5 GGUF configs — the GGUF config builder passes the open GGUF file to boostr's
qwen35_config_from_gguf. It passed a bare metadata map before. Qwen3.5 GGUF models, decision models included, load through this path.
Archives
| Archive | Platform |
|---|---|
blazr-linux-x64.tar.gz |
Linux x86_64, CPU |
blazr-linux-x64-gpu.tar.gz |
Linux x86_64, CPU and Vulkan |
blazr-linux-arm64.tar.gz |
Linux aarch64, CPU |
blazr-macos-arm64.tar.gz |
macOS on Apple silicon, Metal |
blazr-windows-x64.zip |
Windows x86_64, CPU |
blazr-windows-x64-gpu.zip |
Windows x86_64, CPU and DX12 |
blazr-android-arm64.tar.gz |
Android arm64, static library |
blazr-ios-arm64.tar.gz |
iOS arm64, static library |
Full diff: v0.3.0...v0.4.0