fix(config): only inject llama.cpp serving options on the llama.cpp path (#10822)

SetDefaults injected the llama.cpp server options cache_reuse
(ApplyServingDefaults) and parallel (ApplyHardwareDefaults, re-applied
per selected node by the distributed router) onto every model config
regardless of backend. Every other backend ignores options it does not
understand, so this was harmless until longcat-video, which strictly
validates its options and fails LoadModel with
"unknown model option(s): cache_reuse, parallel".

Gate both injections behind a new UsesLlamaCppServingOptions allow-list
(llama-cpp plus the empty/auto-detect case that resolves to llama.cpp
from a GGUF file, mirroring how llamaCppDefaults is registered). This
follows the existing UsesLlamaSamplerDefaults precedent for llama-only
defaults. The typed NBatch field is deliberately left alone: it is a
proto field every backend simply ignores, which is why batch never
triggered the error.

Also harden the longcat-video backend to warn-and-ignore unknown model
options and request params through a testable select_known_options
helper, matching the other LocalAI Python backends, so a future
server-injected option cannot break loading again.


Assisted-by: Claude:claude-opus-4-8 [Claude Code]

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
LocalAI [bot]
2026-07-14 17:46:15 +02:00
committed by GitHub
parent 9f14571397
commit b224c96db6
10 changed files with 139 additions and 21 deletions

View File

@@ -32,6 +32,7 @@ from longcat_utils import (
require_bool,
require_float,
require_int,
select_known_options,
validate_dimensions,
)
@@ -126,10 +127,17 @@ class BackendServicer(backend_pb2_grpc.BackendServicer):
)
try:
options = parse_options(request.Options)
unknown = sorted(set(options) - LOAD_OPTIONS)
if unknown:
raise ValueError(f"unknown model option(s): {', '.join(unknown)}")
options, ignored = select_known_options(
parse_options(request.Options), LOAD_OPTIONS
)
if ignored:
# The server injects llama.cpp serving defaults (cache_reuse,
# parallel) onto every config; ignore what we don't understand
# rather than fail to load.
print(
f"longcat-video ignoring unknown model option(s): {', '.join(ignored)}",
file=sys.stderr,
)
self._import_torch()
if not self.torch.cuda.is_available():
@@ -240,10 +248,14 @@ class BackendServicer(backend_pb2_grpc.BackendServicer):
self.pipeline._interrupt = True
try:
params = dict(request.params)
unknown = sorted(set(params) - REQUEST_PARAMS)
if unknown:
raise ValueError(f"unknown request param(s): {', '.join(unknown)}")
params, ignored_params = select_known_options(
dict(request.params), REQUEST_PARAMS
)
if ignored_params:
print(
f"longcat-video ignoring unknown request param(s): {', '.join(ignored_params)}",
file=sys.stderr,
)
os.makedirs(os.path.dirname(request.dst) or ".", mode=0o750, exist_ok=True)
if hasattr(context, "add_callback"):

View File

@@ -65,6 +65,23 @@ def parse_options(values):
return options
def select_known_options(options, known):
"""Split parsed options into the subset this backend understands and the
unknown keys to ignore.
LocalAI injects serving defaults (e.g. the llama.cpp cache_reuse / parallel
options) onto every model config regardless of backend. A backend should
tolerate options it does not understand rather than refuse to load, matching
the other LocalAI Python backends; the caller logs the ignored keys.
Returns (kept, ignored) where kept preserves the known entries and ignored is
the sorted list of dropped keys.
"""
ignored = sorted(key for key in options if key not in known)
kept = {key: value for key, value in options.items() if key in known}
return kept, ignored
def require_bool(value, name):
if isinstance(value, bool):
return value

View File

@@ -21,6 +21,7 @@ from longcat_utils import ( # noqa: E402
normalize_model_source,
normalize_num_frames,
parse_options,
select_known_options,
validate_dimensions,
)
@@ -61,6 +62,26 @@ class LongCatUtilsTest(unittest.TestCase):
self.assertEqual(options["source"], "https://example.com/model")
self.assertEqual(options["flag"], True)
def test_select_known_options_keeps_known_and_reports_unknown(self):
# The server injects llama.cpp serving defaults (cache_reuse, parallel)
# onto every model config. longcat-video must ignore what it does not
# understand rather than refuse to load - matching every other backend.
options = {
"use_distill": True,
"max_segments": 4,
"cache_reuse": 256,
"parallel": 1,
}
kept, ignored = select_known_options(options, {"use_distill", "max_segments"})
self.assertEqual(kept, {"use_distill": True, "max_segments": 4})
self.assertEqual(ignored, ["cache_reuse", "parallel"])
def test_select_known_options_reports_nothing_when_all_known(self):
kept, ignored = select_known_options({"use_distill": True}, {"use_distill"})
self.assertEqual(kept, {"use_distill": True})
self.assertEqual(ignored, [])
def test_classify_model_accepts_only_supported_longcat_models(self):
cases = {
"meituan-longcat/LongCat-Video": MODEL_KIND_BASE,