v4.8.0: gallery: add Agents-A1 4B variants (#11365) #11371
mudler
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
🎉 LocalAI 4.8.0 Release! 🚀
LocalAI 4.8.0 is out!
Twenty-two days, 386 pull requests, and three new modalities. This release introduces vllm.cpp, a C++20 engine maintained by the LocalAI team, which began as a vLLM port and now carries its own featureset, shipping as the
vllm-cppbackend in alpha development builds. Around it: 3D generation as a new modality, a multi-family audio.cpp engine, gallery entries that install the build your hardware can actually run, and a deep reliability pass on distributed mode driven by production incidents.Highlights:
Generate3DRPC,FLAG_3Dcapability,POST /v1/3d/generations, thetrellis2cppimage-to-3D backend, and a UI page with a native GLB viewer and print remeshing.variants:, and LocalAI installs the largest build that your host can actually run. No more hunting through the gallery for the right quantization.80%) or an absolute amount (12GB).magpie-tts-cpp(NVIDIA Magpie Multilingual, 5 voices, 9+ languages) andmoss-tts-cpp(48 kHz stereo with reference-audio voice cloning).bonsaibackend serves the 1-bit and ternary Bonsai quantizations of Qwen3 and Qwen3.6-27B.in_flightcounters stop leaking.Plus a Valkey vector store, systemd socket activation, persistent trace history, two security fixes, a documentation overhaul aimed squarely at onboarding, and a new localai.io.
📊 This release in numbers
vllm-cpp,audio-cpp,trellis2cpp,valkey-store,bonsai,magpie-tts-cpp,moss-tts-cpp)Where the work landed:
core/gallery/backend/pkg/.github/docs/website/scripts/📌 TL;DR
vllm-cppbackend over its stable C ABI v5. It uses vLLM as its reference implementation and benchmark, and implements vLLM's V1 architecture (paged KV cache, continuous batching, prefix caching, scheduler, sampler) with no Python, PyTorch or ggml at inference. Safetensors + GGUF, in-engine structured output (JSON schema / regex / choice / GBNF). Chat and tool calling ride the llama.cpp autoparser path: full minja templates,tool_choice: autoas a lazy structural-tag constraint, 30 tool dialects and 7 reasoning parsers, streamedChatDelta/ToolCallDelta. CPU amd64/arm64, CUDA 12/13 (Blackwell), L4T, Vulkan and Darwin Metal, the last with the MLX GEMM provider vendored in (1.5x to 2.2x on an M4).Generate3DRPC,FLAG_3Dcapability,POST /v1/3d/generations, thetrellis2cppimage-to-3D backend over TRELLIS.2, and a UI page with a native GLB viewer, IndexedDB history and previewable print remeshing./v1/audio/speech(supertonic, chatterbox, irodori-voicedesign),/v1/audio/transcriptions(citrinet, nemotron, forced-aligner),/v1/audio/vad,/v1/audio/diarize(sortformer),/audio/transform(htdemucs 4-stem separation, voice conversion, speech-to-speech) and/v1/sound-generation. Family comes from the GGUF's ownaudiocpp.model_spec.familykey, so no per-model backend options. 13 gallery entries. CPU, CUDA 12/13, Vulkan, Metal.✕now hides rather than cancels), with a new admin/app/activitypage: in-progress detail with per-node breakdown, a "needs attention" lane with Cancel and Retry, and a bounded 50-entry record of what finished.valkey-storebackend adding Valkey Search as a vector store option./docs/, with 214 generated redirect stubs so every published URL keeps working. Adds an engines page driven by YAML, a blog, an ecosystem band andADOPTERS.md.variants:referencing other entries. Install-time selection drops builds the host cannot run (IsBackendCompatible) or cannot fit (VRAM, or cgroup-aware RAM on CPU hosts), then picks the largest that fits. Override withvariantonPOST /models/apply,local-ai models install --variant, theinstall_modelMCP tool, or the UI split-button.GET /api/models?has_variants=truenarrows the list. Older clients ignore the key and install the entry as before.--disable-http-compression,--http-compression-min-length), with streaming paths explicitly skipped./assets/*servedimmutable,index.htmlno-cache./api/tracesand/api/backend-tracesacceptlimit/offset/fulland summarize by default, withGET /api/traces/{id}for the full record. React bundle 2,815,513 B to 807,918 B; backend-trace poll 21,131,097 B to 7,201 B.LOCALAI_VRAM_BUDGET=80%or=12GB(also--vram-budget), onlocal-aiandlocal-ai worker. Standalone it is a hard per-process cap inherited by context-fit, GGUF warnings and the watchdog; distributed it is a placement ceiling the scheduler respects. Admin override viaPUT/DELETE /api/nodes/:id/vram-budgetand theset_node_vram_budgetMCP tool. Unset means all detected VRAM.models.runningsubject, and the port-probe fallback distinguishesDeadlineExceeded(busy) fromUnavailable(gone), requiring three consecutive misses. Frontend model stubs are dropped when no healthy replica remains,in_flightleaks are closed, and model-load deadlines scale with checkpoint size.POST /api/fine-tuning/jobsis refused unless the operator setsLOCALAI_TRL_ALLOW_INLINE_REWARD=true; the previous builtin allowlist was escapable to arbitrary code execution on an endpoint that is unauthenticated by default. Also picks up hono 4.12.25 for CVE-2026-54290.🚀 New Features & Major Enhancements
🚀 Introducing vllm.cpp (alpha)
vllm.cpp against vLLM on Qwen3.6-27B, identical output at every concurrency.
vllm.cpp is Apache-2.0, maintained by the LocalAI team, and began as a C++20 port of vLLM. We want it community-first rather than a LocalAI-only engine, so it lives in its own repository with its own docs, benchmark record and issue tracker, and it is usable without LocalAI anywhere in the picture. It implements vLLM's V1 serving architecture (paged KV cache, continuous batching, prefix caching, scheduler, sampler) on a portable tensor runtime with no Python, no PyTorch and no ggml at inference time, and uses vLLM itself as its reference implementation: correctness is checked by comparing output against it, and the benchmark scoreboard is kept against it.
It has since grown a featureset vLLM does not have, which is what the port was for. It loads GGUF as well as Hugging Face safetensors, runs on CPU, Apple Metal and Vulkan alongside NVIDIA CUDA, ships speculative decoding and KV offload, and enforces structured output in-engine (JSON schema, regex, choice, GBNF). Its benchmark page now measures against llama.cpp, MLX-LM and DwarfStar as well as vLLM, because those are the engines it actually competes with on that hardware.
The project is expected to be renamed, with the new name still to be decided. It is drifting far enough from vLLM that calling it a port undersells it and calling it vllm.cpp will eventually mislead.
Numbers, from the project's own scoreboard
These come from vllm.cpp's BENCHMARKS.md, which reports ties as ties and losses as losses. Throughput is vllm.cpp over the reference, so above 1.0 is ahead.
The upstream page is careful about its own noise band: on the 27B grid it calls c2 through c32 ties rather than wins, because the run-to-run spread is 0.5% and those margins land between 0.7% and 1.7%. The c1 result is the one it stands behind.
The DeepSeek-V4-Flash row is the one that shows how far the project has moved from being a vLLM port. It runs DeepSeek-V4-Flash at roughly 2-bit (IQ2_XXS mixed, about 80 GB) on a single DGX Spark, decoding at 18.69 tok/s against DwarfStar's 16.33. At 300B+ total parameters even a 4-bit checkpoint is 156 GB or more, so a 2-bit GGUF is what fits inside the Spark's 119 GiB unified pool, and reading GGUF is what makes that possible.
That figure moved twice in a week, and the second move came from one lever. The dense Q8_0 projection tower was being read from the GGUF mmap over unified memory, which the GB10 reads about 20% slower per-GEMV than device memory. Staging that ~6 GiB tower device-resident once at load, same bytes and same kernels, took decode from 16.23 to 18.69, generating the same tokens and using no more peak memory. The same change took Laguna-XS-2.1 from 87% of vLLM to 1.03x ahead of it.
Speculative decoding is in similar shape: MTP on Qwen3.6-27B NVFP4 generates the same tokens as vLLM's MTP and runs about 4% faster at concurrency 1.
It ships here as the
vllm-cppbackend, which dlopens the engine's stable C ABI (v5) through purego. Concurrent requests batch continuously inside the engine's shared scheduler rather than serializing, so the backend runs onbase.Baserather thanSingleThread.Tool calling is at llama.cpp parity, by construction, because chat reuses the same autoparser path. With
use_tokenizer_templatethe engine renders the model's own chat template (GGUFtokenizer.chat_templateortokenizer_config.json, full minja) and handles the rest itself:tool_choice: autolowers to a lazy structural-tag decode constraint;requiredand named choices force the family's native syntax where expressible.<think>reasoning split before tool parsing.ChatDelta,ToolCallDeltaand reasoning stream exactly as the llama-cpp backend does.tool_parser:andreasoning_parser:are model options, auto-detected when unset.Getting started is a normal backend install:
The build matrix covers CPU amd64/arm64, CUDA 12/13 (including Blackwell
120a;121a), L4T arm64 for GB10, Vulkan and Darwin Metal, with a gallery meta plus 12 image entries. The llama-cpp GGUF and vllm safetensors importers gained preference swaps, so the backend can be chosen at import time.Apple Silicon gets the MLX GEMM provider. The darwin build vendors vllm.cpp's optional MLX backend, which upstream keeps off by default on the position that it has to earn its ~124 MB. Measured on an M4 (Qwen3-1.7B-bf16, p=512 g=128, arms toggled on one binary so there is no build-difference confound):
Read those as indicative rather than binding: two reps with a spread reaching 9.4%, so the multipliers carry about +/-10%. The gap is far larger than the noise, and time-to-first-token roughly halves across the range.
These are alpha development builds, not a released backend. vllm.cpp is early. It ships in 4.8 so people who want to try it can, not because it is ready for anything you depend on, and
llama-cppstays the default for real use. Expect rough edges.The CPU path is end-to-end verified against
Qwen3.5-2B-UD-Q8_K_XL.ggufwith the full Ginkgo suite: blocking and streaming byte-parity, greedy determinism, stop words, GBNF-constrained generation, concurrent streams, real template rendering, reasoning split, arequiredtool call returning schema-valid arguments, and anautorun where the engine engages the tool itself and streams parsed deltas. The GPU images build and ship, but their runtime behavior has not been through that gate. No throughput comparison against upstream vLLM is claimed. Please report what breaks.🧊 3D generation, end to end
trellis2-4b, 2,502,928 vertices, turning in the browser.
LocalAI gains a new modality. Image-to-3D is wired through the whole stack rather than bolted onto an existing endpoint: a
Generate3DRPC inbackend.proto, aFLAG_3Dcapability so the loader knows which backends can serve it, andPOST /v1/3d/generations.The first engine behind it is
trellis2cpp, a native image-to-3D backend over TRELLIS.2. The React UI gets a 3D generation page with a native GLB viewer, IndexedDB-backed history so your generations survive a reload, and previewable print remeshing for output you intend to actually print.🔊 audio.cpp: one backend, six audio endpoints
audio-cppwraps audio.cpp, a multi-family ggml audio engine. Rather than one backend per model family, a single backend process serves several unrelated families through one runtime vocabulary, and picks the family from the GGUF's ownaudiocpp.model_spec.familymetadata key, so a model needs no backend-specific options to load./v1/audio/speech(batch + streaming)instructions)/v1/audio/transcriptions(batch, streaming, live)/v1/audio/vad/v1/audio/diarize/audio/transform/v1/sound-generationThirteen gallery entries ship with it, one representative model per task kind the engine can actually serve. Where it cannot honestly back an RPC it returns
UNIMPLEMENTEDwith a reason rather than an empty success, and a failed load is a gRPC error rather thansuccess: false, so the loader's greedy backend probe never silently selects it for a model it cannot serve.Two changes reach beyond the backend.
backend.protogainsAudioTransformStemandAudioTransformResult.stems, so source separation can return the whole stem set instead of a single mixdown. And/audio/transformno longer hardcodes a 16 kHz mono fold: that fold made 4-stem separation unreachable by construction, so it became a per-backend capability, with existing backends keeping it explicitly and the default for an unregistered backend being to leave the upload alone.Platforms: CPU (amd64 and arm64), CUDA 12, CUDA 13 and Vulkan on Linux, plus Metal on darwin-arm64. No ROCm, which upstream does not support.
📊 A one-line strip, and an Activity page
Four backend installs in flight, with the record of what already finished.
The operations bar rendered one row per in-flight operation above every page. Queue four model installs and a backend and it took most of the viewport, on every route, until the last one finished. Two things were conflated: a global "something is happening" signal, which needs one line, and the detail of what is happening, which needs a page.
The strip now collapses to a single line permanently, showing one operation (a failure first, otherwise the least-advanced running one) with a
+N morepill. Its✕hides the strip and never cancels, a deliberate change: the same glyph previously cancelled a 17 GB download in one row and dismissed a message in the next. Cancelling moved to the page, behind a labelled button.The new admin-only Activity page at
/app/activitycarries the detail the strip has to drop (phase, bytes, derived time remaining, and a per-node breakdown for cluster installs), a "needs attention" lane for unacknowledged failures with Cancel and Retry, and a record of what finished. That record is a bounded 50-entry ring, which closes a real gap:/api/operationsdropped an operation the moment it succeeded, so a user who stepped away had no way to learn whether an install finished, failed, or never started.Several latent UI bugs were fixed along the way: retrying a failed removal re-downloaded the model, queued operations rendered as "Installing" with a spinner, a long error message pushed every page ~270px past the viewport, and the ETA blanked for every operation whenever one was verifying.
🎛️ One gallery entry, several builds
One entry, four builds. LocalAI picks the largest that fits and marks it auto-selected.
A gallery entry can now declare
variants:, a list of references to other gallery entries that are alternative builds of the same weights:Selection at install time, in order:
The entry's own build competes in that ranking and is never filtered out, so selection always ends with something installable.
Sizes come from the existing
pkg/vramestimator (remote GGUF header, HTTPHEAD, the declaredsize:, then the HF repo listing). Nothing is downloaded to decide, and a probe failure never fails an install.Auto-selection is the default and every surface can override it:
variantonPOST /models/applyandPOST /api/models/install/:id,local-ai models install <name> --variant <variant>, thevariantparameter on theinstall_modelMCP tool, and a split-button menu in the models table. An explicit selection is honored even when it does not fit, with a warning, since that is a deliberate operator override.Existing installations are unaffected: every released LocalAI reads
gallery/index.yamllive and ignores keys it does not understand, so an older client dropsvariants:and installs the entry exactly as before. A spec re-parses the real index through a legacy-shaped struct to keep that true.Known gaps worth stating: in distributed mode
InstallModelresolves against the frontend rather than the worker that will serve the model, so a cluster with a small frontend and large workers selects conservatively. Probing within a single entry is still serial and uncapped.📦 Hugging Face model artifacts
Model artifacts from Hugging Face are now materialized as a managed snapshot flow: immutable snapshot resolution, authenticated downloads with progress reporting, materialization on gallery install and preload, runtime binding to the staged artifacts, and progress surfaced in the UI. Python backends reuse the Go download path rather than fetching on their own.
A substantial run of follow-ups landed alongside it: per-file resume of interrupted materialization rather than starting over, each writer staging into its own partial tree, companion artifacts persisted so remote workers receive the
base_modeloption, single-file HF snapshots loaded from the file rather than the directory, inferred materialization gated by backend, CIFSEACCEStreated as lock contention rather than failure, and multi-file install progress kept proportional during verification.⚡ A much lighter web UI and trace API
Three HTTP-layer problems, all measured on a live deployment, fixed together because they all shape what goes on the wire.
The server sent no
Content-Encodingat all, regardless ofAccept-Encoding. There is now gzip middleware, on by default and controllable with--disable-http-compression/LOCALAI_DISABLE_HTTP_COMPRESSIONand--http-compression-min-length/LOCALAI_HTTP_COMPRESSION_MIN_LENGTH(default 1024). Streaming responses are skipped explicitly, since buffering them behind a gzip writer defeats incremental flushing and reads as a hung stream: SSEAcceptheaders, WebSocket upgrades, and the completion, realtime, speech, transcription, agent-job and log-tail path prefixes. Already-compressed formats are skipped too, because gzip made those marginally larger.Vite content-hashes the bundle filenames, so an
/assets/URL can never change content, yet they shipped with noCache-Control,ETagorLast-Modified. They now carrypublic, max-age=31536000, immutable,index.htmlis explicitlyno-cacheso deploys are picked up, and unhashed locale JSONs get a 5 minute policy./api/traceswas returning a 21 MB unpaginated blob that the UI polled every 5 seconds. Both list endpoints now acceptlimit(default 50, max 1000,0for all),offsetandfull, and summarize by default: bodies and headers are dropped, the byte counters kept so the UI can still report what went missing. Every trace carries a process-lifetimeid, andGET /api/traces/{id}serves the full record on expand or export. Paging metadata rides inX-Total-Count,X-Trace-OffsetandX-Trace-Limit, so the list body stays a plain JSON array for existing consumers./api/backend-tracespoll payload🎚️ Per-node VRAM allocation budgets
Operators can now cap how much VRAM LocalAI uses for model allocation on a node, as a percentage (
80%) or an absolute amount (12GB). Everywhere LocalAI reads VRAM to make an allocation decision it now usesmin(detected, budget), a hard ceiling that never raises usable VRAM above physical. Percentages above 100% are rejected; absolute values above physical are clamped.It applies to both
local-aiandlocal-ai worker(also--vram-budget), and is editable live from the standalone Settings page and per node in the distributed node UI.The two paths are deliberately asymmetric:
xsysinfoholds it as a process-global default, so hardware defaults, context auto-fit, GGUF warnings and the watchdog all inherit it.available_vramon registration and heartbeat, so the SQL scheduler needs no query change. The worker still sees its full card for its own context-fit.Admin overrides via
PUT/DELETE /api/nodes/:id/vram-budgetsurvive worker restarts, and are exposed as theset_node_vram_budgetMCP tool.Default unset means all detected VRAM, so existing deployments are unchanged.
🗣️ Two new text-to-speech engines
magpie-tts-cpp wraps magpie-tts.cpp, a C++17/ggml port of NVIDIA's Magpie TTS Multilingual 357M with its NanoCodec vocoder embedded: 5 voices (Aria, Jason, John, Leo, Sofia), 9+ languages, 22.05 kHz mono, from one self-contained GGUF with no Python or PyTorch at inference. GGUFs are published at mudler/magpie-tts.cpp-gguf. A live gRPC check returns a valid non-silent WAV that round-trips exactly through ASR, and the upstream engine is parity-gated against NeMo per component (teacher-forced replay max abs diff 3.6e-5).
moss-tts-cpp wraps moss-tts.cpp, the ggml port of the OpenMOSS MOSS-TTS family, serving MOSS-TTS-Local v1.5 (a GPT-J local transformer decoded through MOSS-Audio-Tokenizer-v2). It produces 48 kHz stereo with optional reference-audio voice cloning. GGUFs are at mudler/MOSS-TTS-Local-Transformer-v1.5-GGUF. Images cover CPU, CUDA 12/13, Intel SYCL f16/f32, Vulkan, ROCm, NVIDIA L4T and Darwin Metal.
🌳 Sub-2-bit models with the bonsai backend
The Bonsai models are 1-bit (Q1_0) and ternary / 1.58-bit (Q2_0) quantizations of Qwen3 8B dense and Qwen3.6-27B hybrid attention. Their quant formats are only decodable by the PrismML fork of llama.cpp, since stock llama.cpp has no Q1_0/Q2_0 kernels, so they need a dedicated fork backend in the same shape as
ik-llama-cppandturboquant.The backend reuses
backend/cpp/llama-cpp/grpc-server.cppagainst the fork'slibllamathrough a thin wrapper Makefile that only swapsLLAMA_REPOandLLAMA_VERSION, so these models are served over the same OpenAI-compatible API as stockllama-cpp. The reused server compiles against the fork with zero skew patches.Eight gallery entries ship with it:
bonsai-8b-1bitternary-bonsai-8b-q2-g64,-pq2bonsai-27b-1bitternary-bonsai-27b-pq2,-q2-g64If Q1_0 and Q2_0 land in mainline llama.cpp, this backend can retire in favor of a routine
LLAMA_VERSIONbump on stockllama-cpp.🖧 Distributed mode reliability
Investigating a model that showed as loaded on the home page but appeared on no node in the cluster turned up four separate bugs, all fixed here.
The reaper was deleting rows for backends that were alive and working.
probeLoadedModelsreaped anode_modelsrow after one failed 1 second health check, and a busy backend cannot answer one: a single-threaded Python backend blocks for minutes inside a request.models.runningsubject asks the worker directly, since it holds the process handle and is not blocked by the backend. The reconciler diffs its process keys against the registry before any port probe.DeadlineExceeded(busy) fromUnavailable(gone), and only the latter counts, after three consecutive misses.Every routed model also left an in-process stub in the frontend's
ModelLoader, and removal paths deleted only the database row, so the stub outlived the replica and the model was reported as loaded forever. The replica-removed hook became a list, and a new local-stub invalidator drops the stub once no healthy replica remains cluster-wide.Alongside those:
in_flightcounters could leak high and pin a replica's VRAM against eviction; model-load deadlines now scale with checkpoint size and with progress rather than wall-clock; staging verification counts as progress rather than a stall; backend discovery no longer hides worker-installed or GPU-only backends behind the controller's filesystem and capability; the scheduler will not place a model on a node that cannot store it; and open responses are visible and cancellable across replicas.Worker-side, a backend process whose directory a reinstall replaced is never reused, the gRPC port allocator is bounded and stops leaking dead backends' ports, deleted backends are reaped, and the worker has a real health endpoint with a mode-aware
HEALTHCHECK.🧰 Smaller features worth knowing about
valkey-storebackend adds Valkey as a vector store option alongside the existing ones.local-aiconsumes a TCP listener inherited through the systemd socket-activation protocol on Linux, so it can start on demand. Ordinary--address/LOCALAI_ADDRESSbinding is unchanged when no activation listener is present, ambiguous multiple listeners are rejected, and the public-bind auth safety check runs against the actual inherited address. Documented alongside the Podman descriptor-passing requirement.traces/apiandtraces/backend. No database dependency, existingtracing_max_itemsbounds preserved, restored IDs advanced to avoid collisions, corrupt records skipped rather than blocking startup.stablediffusion-ggml, and voice control on low-power devices (feat(classifier/VAD): support voice control on low power devices #10804) via the classifier/VAD path./v1/detokenize(feat(api): add /v1/detokenize endpoint #9620), and deterministic, type-filtered backend auto-detection (fix(model): deterministic, type-filtered backend auto-detection (#9287) #10286) so backend selection stops depending on probe order.mlx-audiorather than a generic text backend.🛡️ Inline fine-tuning reward code is now opt-in
POST /api/fine-tuning/jobsacceptsreward_functions[].code, an inline Python body that was executed against a hand-rolled builtin allowlist. That allowlist was not a security boundary: standard CPython introspection reaches the realosmodule and yields arbitrary code execution on the host. Execution happened synchronously during a smoke test at job start, and the fine-tuning endpoint is unauthenticated by default.Rather than trying to harden the allowlist, inline reward code is now refused unless the operator explicitly opts in with
LOCALAI_TRL_ALLOW_INLINE_REWARD=trueon the backend. Builtin reward functions are unaffected and keep working with no configuration. The documentation no longer describes the allowlist as a sandbox and states plainly that inline code is arbitrary execution.Two further hardening fixes landed in the same cycle:
ExtractArchivepre-scanned members and rejected symlinks, but tar hardlink entries carry a regular file mode and passed that check, andHeader.Linknamewas never validated, so an archive could create a link to a path outside the destination directory. Linkname now gets the same path check as member names; hardlinks resolving inside the root still extract, so ordinary archives are unaffected.$refin a JSON-schema grammar is rejected (fix(grammars): reject cyclic $ref in JSON-schema grammar to prevent stack-overflow crash (#11020) #11041) rather than recursing into a stack-overflow crash.This release also picks up hono 4.12.25 for CVE-2026-54290.
🔍 Traces gain request identity
The API Traces panel recorded who issued each request but never showed it, and never captured the caller's network identity. The table now has a sortable User column, and the expanded row carries User, Client IP and User Agent, from echo's
RealIP()(honouringX-Forwarded-For/X-Real-IPbehind a trusted proxy). Fields render only when present, so older buffered traces and unauthenticated local requests degrade cleanly. The time column now shows the date too.🐛 Bug Fixes (recap)
fix(distributed): reaper reaps live backends, ghost model stubs,in_flightleak, sidecar staging runaway - fix(distributed): reaper reaps live backends, ghost model stubs, in_flight leak, sidecar staging runaway #11142fix(distributed): scale the remote model-load deadline with checkpoint size - fix(distributed): scale the remote model-load deadline with checkpoint size #11030fix(distributed): make the cold-load hold scale with progress, not wall-clock - fix(distributed): make the cold-load hold scale with progress, not wall-clock #11019fix(distributed): count staging verification as progress, not as a stall - fix(distributed): count staging verification as progress, not as a stall #11026fix(distributed): reject wrong-model requests at the backend and on the remaining modalities - fix(distributed): reject wrong-model requests at the backend #10970, fix(distributed): reject wrong-model requests on the remaining modalities #10990fix(distributed): backend discovery hid worker-installed and GPU-only backends - fix(distributed): backend discovery hid worker-installed backends behind the controller's filesystem #10967, fix(distributed): backend discovery hid GPU-only backends behind the controller's capability #10947fix(distributed): configurable remote model-load timeout, and reap the load when it times out - fix(distributed): configurable remote model-load timeout, and reap the load when it times out #10948fix(distributed): make per-node backend upgrade actually upgrade - fix(distributed): make per-node backend upgrade actually upgrade #10838fix(nodes): never schedule a model onto a node that cannot store it - fix(nodes): never schedule a model onto a node that cannot store it #11054fix(openresponses): make responses visible and cancellable across replicas - fix(openresponses): make responses visible and cancellable across replicas #11000fix(worker): never reuse a backend process whose directory a reinstall replaced - fix(worker): never reuse a backend process whose directory a reinstall replaced #11029fix(worker): bound the gRPC port allocator and stop leaking dead backends' ports - fix(worker): bound the gRPC port allocator and stop leaking dead backends' ports #10968fix(worker): reap deleted backends and stop models that live on a worker - fix(worker): reap deleted backends and stop models that live on a worker #10956fix(worker): give the worker a real health endpoint and a mode-aware HEALTHCHECK - fix(worker): give the worker a real health endpoint and a mode-aware HEALTHCHECK #10999fix(downloader): hash the partial file before issuing the resume request - fix(downloader): hash the partial file before issuing the resume request #11099fix(downloader): bound the wait for response headers so a wedged origin cannot hang an install - fix(downloader): bound the wait for response headers so a wedged origin cannot hang an install forever #11053fix(downloader): distinguish read from write failures and retry transient ones - fix(downloader): distinguish read from write failures and retry transient ones #10985fix(modelartifacts): resume interrupted materialization per-file, not from scratch - fix(modelartifacts): resume interrupted materialization per-file, not from scratch #11071fix(modelartifacts): stage each writer's artifact in its own partial tree - fix(modelartifacts): stage each writer's artifact in its own partial tree #10995fix(modelartifacts): treat CIFS EACCES as lock contention, not failure - fix(modelartifacts): treat CIFS EACCES as lock contention, not failure #10986fix(model-artifacts): persist companion artifacts so remote workers get thebase_modeloption - fix(model-artifacts): persist companion artifacts so remote workers get the base_model option #11075fix(model-artifacts): load single-file HF snapshots from the file, not the directory - fix(model-artifacts): load single-file HF snapshots from the file, not the directory #10909fix(model-artifacts): gate inferred artifact materialization by backend - fix(model-artifacts): gate inferred artifact materialization by backend #10910fix(model-artifacts): materialize longcat-video on the controller, and support companion repos - fix(model-artifacts): materialize longcat-video on the controller, and support companion repos #10949fix(gallery): coalesce Hugging Face artifact progress - fix(gallery): coalesce Hugging Face artifact progress #11117fix(gallery): keep multi-file HF install progress proportional during verify - fix(gallery): keep multi-file HF install progress proportional during verify #10908fix(galleryop): make admitted operations queryable and survive a failed op - fix(galleryop): make admitted operations queryable and survive a failed op #11044fix(gpu-libs): bundle cuDNN only where it is used, and complete it when it is - fix(gpu-libs): bundle cuDNN only where it is used, and complete it when it is #10946fix(gpu): detect GPUs via sysfs when no pci.ids database is present - fix(gpu): detect GPUs via sysfs when no pci.ids database is present #10966fix(watchdog): force-kill stuck-busy backends instead of deadlocking the loader - fix(watchdog): force-kill stuck-busy backends instead of deadlocking the loader #10578fix(watchdog): guardStopWatchdogwithwatchdogMutexto prevent double close - fix(watchdog): guard StopWatchdog with watchdogMutex to prevent double close (#10841) #10859fix(config): only inject llama.cpp serving options on the llama.cpp path - fix(config): only inject llama.cpp serving options on the llama.cpp path #10822fix(runtime-settings): apply persisted threads/context_size/f16 at startup - fix(runtime-settings): apply persisted threads/context_size/f16 at startup #10853fix(model): make backend shutdown model-scoped - fix(model): make backend shutdown model-scoped #10865fix(model): only announce a load at INFO when a load actually happens - fix(model): only announce a load at INFO when a load actually happens #11017fix(completions): reject emptyPromptStringsin streaming to avoid an index-out-of-range panic - fix(completions): reject empty PromptStrings in streaming to avoid index-out-of-range panic #11028fix(tts): forward the OpenAIspeedfield to the backend - fix(tts): forward the OpenAI speed field to the backend (#11097) #11120fix(realtime): accept the legacymodalitiesalias foroutput_modalities- fix(realtime): accept legacy 'modalities' alias for output_modalities (fixes #11103) #11104fix(vision): probe the media marker for pinned llama.cpp backend variants - fix(vision): probe the media marker for pinned llama.cpp backend variants #10955fix(audio-transform): serialize WebSocket writes to avoid a concurrent-write panic - fix(audio-transform): serialize WebSocket writes to avoid concurrent-write panic #10857fix(qwen-asr): map ISO language codes to the names Qwen3-ASR expects - fix(qwen-asr): map ISO language codes to the names Qwen3-ASR expects #10959fix(ollama): capnum_ctxso it cannot wrap negative when cast to int32 - fix(ollama): cap num_ctx so it cannot wrap negative when cast to int32 #11032fix(ollama): setContextSizevia the embeddedLLMConfigso the package builds - fix(ollama): set ContextSize via the embedded LLMConfig so the package builds #11049fix(webui): use relative asset base so fonts and lazy chunks honorX-Forwarded-Prefix- fix(webui): use relative asset base so fonts and lazy chunks honor X-Forwarded-Prefix (#10889) #10904fix(agent-ui): reset streamed text at generation boundaries in agent chat - fix(agent-ui): reset streamed text at generation boundaries in agent chat #10664fix(mcp): bound MCP session connect so an unreachable server cannot hang the widget - fix(mcp): bound MCP session connect so an unreachable server can't hang the widget (#10880) #10884fix(http): make/readyzreflect startup readiness - fix(http): make /readyz reflect startup readiness, plus gitignore and coverage-ratchet fixes #10989fix(upgrade-check): don't filter upgrade candidates by controller capability - fix(upgrade-check): don't filter upgrade candidates by controller capability #11024fix(cloud-proxy): publish backend gallery entries - fix(cloud-proxy): publish backend gallery entries #10858fix(backend): don't crash the whole process on an invalidcutstrings/extract_regex- fix(backend): don't crash the whole process on an invalid cutstrings/extract_regex #10855fix(backends): derive the protoc generator from the protobuf runtime - fix(backends): derive the protoc generator from the protobuf runtime, regenerate stubs after late installs #11057fix(backend/python): don't await sync servicer behaviors inAsyncModelIdentityInterceptor- fix(backend/python): don't await sync servicer behaviors in AsyncModelIdentityInterceptor #10980fix(sglang): implement the Status RPC to unblock backend-monitor polling - fix(sglang): implement Status RPC to unblock backend-monitor polling #10867fix(vllm): generate protobuf 6 compatible stubs - fix(vllm): generate protobuf 6 compatible stubs #10944fix(vibevoice): install diffusers from PyPI instead of git main - fix(vibevoice): install diffusers from PyPI instead of git main #10972fix(kokoro): pin a compatible Intel XPU runtime - fix(kokoro): pin compatible Intel XPU runtime #10823fix(ace-step): drop nonexistentGet*proto accessors inSoundGeneration- fix(ace-step): drop nonexistent Get* proto accessors in SoundGeneration (#11069) #11072fix(trl): disable inline GRPO reward code by default (RCE) - fix(trl): disable inline GRPO reward code by default (RCE, #11015) #11068fix(turboquant): supersede stale dependency bump - fix(turboquant): supersede stale dependency bump #11064fix(turboquant,bonsai): do not apply vendored llama.cpp patches to fork trees - fix(turboquant,bonsai): do not apply vendored llama.cpp patches to fork trees #10866fix(llama-cpp): retain CPU variants in GPU builds - fix(llama-cpp): retain CPU variants in GPU builds #11255, and the same for turboquant - fix(turboquant): retain CPU variants in GPU builds #11276fix(llama-cpp): preserve GPU layers during option passthrough - fix(llama-cpp): preserve GPU layers during option passthrough #11193fix(utils): reject tar hardlinks that escape the extraction root - fix(utils): reject tar hardlinks that escape the extraction root #11266fix(grammars): reject cyclic$refin JSON-schema grammar to prevent a stack-overflow crash - fix(grammars): reject cyclic $ref in JSON-schema grammar to prevent stack-overflow crash (#11020) #11041fix(grammars): restore backslash escaping in the llama31 grammar fixture - fix(grammars): restore backslash escaping in llama31 grammar fixture #11242fix(model): deterministic, type-filtered backend auto-detection - fix(model): deterministic, type-filtered backend auto-detection (#9287) #10286fix(oci): install backends on filesystems without symlinks - fix(oci): install backends on filesystems without symlinks #11166fix(oci): identify signature verification requests - fix(oci): identify signature verification requests #11244fix(realtime): echoresponse.metadataonresponse.createdandresponse.done- fix(realtime): echo response.metadata on response.created and response.done #11198fix(worker): report RAM alongside GPU memory - fix(worker): report RAM alongside GPU memory #11167fix(vllm): applyOptions[]engine flags before engine init - fix(vllm): apply Options[] engine flags before engine init #11147fix(mlx-vlm): install torch dependencies on Metal - fix(mlx-vlm): install torch dependencies on Metal #11164fix(kokoro): add a CPU backend fallback - fix(kokoro): add CPU backend fallback #11161fix(chatterbox): pin cublas12 torch/transformers and setuptools so the backend loads - fix(chatterbox): pin cublas12 torch/transformers and setuptools so the backend loads (fixes #11070) #11074fix(gallery): correct Nanbeige 4.2 artifacts - fix(gallery): correct Nanbeige 4.2 artifacts #11269known_usecases, so they resolved to image rather than video and/videorejected them - Fix use case for video model #11214🖧 P2P area
fix(p2p): serialize access top2pCtx/p2pCancel- fix(p2p): serialize access to p2pCtx/p2pCancel (#10839) #10861👒 Dependencies
121 dependency updates landed this cycle, mostly nightly engine bumps:
Plus 20 dependabot updates across Python, JavaScript and GitHub Actions, and a
go-processmanagerbump for the concurrent-Runfix.Note: one
ggml-org/llama.cppbump (d2a8182) was reverted within the cycle and is excluded from these notes.📖 Documentation
The documentation received an onboarding-focused overhaul (#10895), driven by a mapped per-page audit rather than page dates, with every factual claim verified against the code, backends, gallery and CLI:
localai/localai:latest(there is nolatest-cpu), the registry unified, the deadllama-stablebackend removed from examples, themitm-proxyflag documentation corrected, a non-existent/soundendpoint removed, the Voice Activity Detection example made runnable, and the CLI reference refreshed withagent,mcp-server,agent-workerandp2p-worker.qwen3-4b) now carries through install, Web UI chat and API curl, plus a new Build your first agent walkthrough that states plainly that LocalAGI is embedded.Also:
grpc.attemptstiming and tuning guidance (#10868), a fix to the Opus backend installation instructions for realtime (#11018), reverse-proxy and long-inference timeout guidance (#11195, #11065), persistent container storage clarified (#11190), and ROCm 7.x / RDNA 3.5 (Strix Halo, gfx1151) added to the GPU acceleration guide (#9229).🌐 A new localai.io
The site splits in two: the project site at the root, and the documentation moved under
/docs/. The Hugo docs site had always been localai.io, which left nowhere to explain what LocalAI is or to show what the team builds.Every previously published URL keeps working. GitHub Pages has no server-side rewrites, so a generator walks the built docs output and leaves a meta refresh, a canonical link and a
noindexat each old root path: 214 redirect stubs, covering bare.htmlfiles as well as directory indexes, and never overwriting a path the root site owns.The new site adds an
/engines/page driven entirely by a YAML data file (so adding an engine is one edit, not hand-written HTML in two places), a/blog/, a real POSIXinstall.shand a Kubernetes manifest wired to the actual/readyzand/healthzendpoints. An ecosystem band lists the companies whose engineers have contributed, the projects that integrate LocalAI, and where LocalAI has been written about, each backed by a different and stated standard of evidence, withADOPTERS.mdas the self-service mechanism for anyone who wants to be listed.🧹 CI cost and correctness
A sustained pass on the build pipeline, most of it invisible to users but responsible for how quickly changes land: the full backend matrix now only rebuilds on breaking
backend.protoedits (#11192), image and Go PR workflows skip content they cannot see (#11218, #11223, #11224), the native engine builds in a layer the registry cache can actually restore (#11221), and three workflows that stacked runs on every PR push were deduplicated (#11058). Go backends now rebuild on linkedpkg/changes and matrix-entry edits (#10988, #10975).🙌 New Contributors
Eleven people landed their first LocalAI contribution this cycle:
Thank you all, and thanks to everyone who filed issues, tested builds and reported regressions this cycle.
Full Changelog: v4.7.1...v4.8.0
This discussion was created from the release v4.8.0: gallery: add Agents-A1 4B variants (#11365).
All reactions