fix(studio): inherit llama_extra_args and honor --no-mmproj (#5902)
* fix(studio): inherit llama_extra_args and honor --no-mmproj Reloading the same GGUF from the UI without gguf_variant no longer drops CLI pass-through args like --no-mmproj. Skip mmproj download and launch when --no-mmproj is present in llama_extra_args. Co-authored-by: Cursor <cursoragent@cursor.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix(studio): tighten GGUF llama_extra_args variant inheritance guard Reject inherited CLI args when the request changes gguf_variant or when omitted variant resolves differently from the stored extra_args source. Co-authored-by: Cursor <cursoragent@cursor.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Treat --no-mmproj-auto and --mmproj-auto with last-wins parsing for PR #5902 --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Daniel Han <danielhanchen@gmail.com>
This commit is contained in:
parent
3e6920627c
commit
f22e890ab8
4 changed files with 64 additions and 17 deletions
|
|
@ -28,6 +28,7 @@ from typing import Callable, Generator, Iterable, List, Optional
|
|||
import httpx
|
||||
|
||||
from core.inference.llama_server_args import (
|
||||
extra_args_disable_mmproj,
|
||||
parse_cache_override,
|
||||
parse_ctx_override,
|
||||
resolve_cache_type_kv,
|
||||
|
|
@ -2929,8 +2930,8 @@ class LlamaCppBackend:
|
|||
hf_variant = hf_variant,
|
||||
hf_token = hf_token,
|
||||
)
|
||||
# Auto-download mmproj for vision models
|
||||
if is_vision and not mmproj_path:
|
||||
# Auto-download mmproj for vision models unless opted out.
|
||||
if is_vision and not mmproj_path and not extra_args_disable_mmproj(extra_args):
|
||||
mmproj_path = self._download_mmproj(
|
||||
hf_repo = hf_repo,
|
||||
hf_token = hf_token,
|
||||
|
|
@ -3191,10 +3192,12 @@ class LlamaCppBackend:
|
|||
gpu_indices, use_fit = None, True
|
||||
effective_ctx = requested_ctx # fall back to original
|
||||
|
||||
launch_mmproj_path = self._resolve_launch_mmproj_path(
|
||||
model_path = model_path,
|
||||
mmproj_path = mmproj_path,
|
||||
)
|
||||
launch_mmproj_path = None
|
||||
if not extra_args_disable_mmproj(extra_args):
|
||||
launch_mmproj_path = self._resolve_launch_mmproj_path(
|
||||
model_path = model_path,
|
||||
mmproj_path = mmproj_path,
|
||||
)
|
||||
# Need both a resolved mmproj AND the config vision flag; a stray
|
||||
# mmproj passing the family-name heuristic must not flip a non-VLM
|
||||
# GGUF into vision mode.
|
||||
|
|
|
|||
|
|
@ -260,6 +260,28 @@ def resolve_cache_type_kv(
|
|||
return override if override is not None else fallback_cache_type_kv
|
||||
|
||||
|
||||
_MMPROJ_DISABLE_FLAGS: frozenset[str] = frozenset({"--no-mmproj", "--no-mmproj-auto"})
|
||||
_MMPROJ_ENABLE_FLAGS: frozenset[str] = frozenset({"--mmproj-auto"})
|
||||
|
||||
|
||||
def extra_args_disable_mmproj(args: Optional[Iterable[str]]) -> bool:
|
||||
"""True when pass-through args opt out of vision mmproj loading.
|
||||
|
||||
llama-server parses --mmproj-auto / --no-mmproj / --no-mmproj-auto as one
|
||||
boolean with last-wins semantics; mirror that here.
|
||||
"""
|
||||
if not args:
|
||||
return False
|
||||
disabled = False
|
||||
for raw in args:
|
||||
flag = _flag_name(str(raw))
|
||||
if flag in _MMPROJ_DISABLE_FLAGS:
|
||||
disabled = True
|
||||
elif flag in _MMPROJ_ENABLE_FLAGS:
|
||||
disabled = False
|
||||
return disabled
|
||||
|
||||
|
||||
def strip_shadowing_flags(
|
||||
args: Iterable[str],
|
||||
*,
|
||||
|
|
|
|||
|
|
@ -1449,18 +1449,23 @@ async def load_model(
|
|||
# parse against a freshly-supplied first-class field.
|
||||
if request.llama_extra_args is None and llama_backend.extra_args:
|
||||
source = llama_backend.extra_args_source
|
||||
# Compare against the resolved variant, not the request field:
|
||||
# callers commonly omit gguf_variant for local ``.gguf`` paths
|
||||
# and HF auto-pick flows. ``config.gguf_variant`` is the variant
|
||||
# load_model was actually invoked with (see HF / local branches
|
||||
# below), so both sides key off the same string.
|
||||
resolved_variant = config.gguf_variant
|
||||
same_source = bool(
|
||||
source
|
||||
and source[0]
|
||||
and source[0].lower() == model_identifier.lower()
|
||||
and (source[1] or "").lower() == (resolved_variant or "").lower()
|
||||
# Compare against the resolved variant, not the request
|
||||
# field: callers commonly omit gguf_variant for local
|
||||
# ``.gguf`` paths and HF auto-pick flows. ``config.gguf_
|
||||
# variant`` is the variant load_model was actually
|
||||
# invoked with (see the HF / local branches below), so
|
||||
# both sides of the comparison key off the same string.
|
||||
resolved_variant = (config.gguf_variant or "").lower()
|
||||
request_variant = (request.gguf_variant or "").lower()
|
||||
stored_variant = (source[1] or "").lower() if source else ""
|
||||
same_model = bool(
|
||||
source and source[0] and source[0].lower() == model_identifier.lower()
|
||||
)
|
||||
if request.gguf_variant:
|
||||
variant_mismatch = request_variant != stored_variant
|
||||
else:
|
||||
variant_mismatch = bool(stored_variant and resolved_variant != stored_variant)
|
||||
same_source = same_model and not variant_mismatch
|
||||
if not same_source:
|
||||
logger.info(
|
||||
"Not inheriting llama_extra_args: stored args came from %s, loading %s",
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ parse_cache_override = _lsa.parse_cache_override
|
|||
parse_ctx_override = _lsa.parse_ctx_override
|
||||
resolve_cache_type_kv = _lsa.resolve_cache_type_kv
|
||||
strip_shadowing_flags = _lsa.strip_shadowing_flags
|
||||
extra_args_disable_mmproj = _lsa.extra_args_disable_mmproj
|
||||
validate_extra_args = _lsa.validate_extra_args
|
||||
|
||||
|
||||
|
|
@ -509,6 +510,22 @@ def test_strip_shadowing_flags_defaults_strip_everything():
|
|||
assert out == []
|
||||
|
||||
|
||||
def test_extra_args_disable_mmproj_detects_flag():
|
||||
assert extra_args_disable_mmproj(["--no-mmproj"]) is True
|
||||
assert extra_args_disable_mmproj(["--threads", "12", "--no-mmproj"]) is True
|
||||
assert extra_args_disable_mmproj(["--no-mmproj-auto"]) is True
|
||||
|
||||
|
||||
def test_extra_args_disable_mmproj_false_when_absent():
|
||||
assert extra_args_disable_mmproj(None) is False
|
||||
assert extra_args_disable_mmproj(["--threads", "12"]) is False
|
||||
|
||||
|
||||
def test_extra_args_disable_mmproj_last_wins():
|
||||
assert extra_args_disable_mmproj(["--no-mmproj", "--mmproj-auto"]) is False
|
||||
assert extra_args_disable_mmproj(["--mmproj-auto", "--no-mmproj-auto"]) is True
|
||||
|
||||
|
||||
def test_strip_shadowing_flags_drops_model_draft_with_spec():
|
||||
# --model-draft (and aliases) are Studio-managed since the separate
|
||||
# MTP drafter support: an inherited copy must not last-wins-override
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue