Skip to content

Commit bd5b012

Browse files
committed
feat: add advanced auxiliary model options
1 parent 5ec136a commit bd5b012

5 files changed

Lines changed: 951 additions & 18 deletions

File tree

api/config.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2392,6 +2392,9 @@ def set_hermes_default_model(model_id: str) -> dict:
23922392
"mcp",
23932393
"title_generation",
23942394
"curator",
2395+
"kanban_decomposer",
2396+
"profile_describer",
2397+
"triage_specifier",
23952398
)
23962399

23972400

@@ -2428,6 +2431,11 @@ def get_auxiliary_models() -> dict:
24282431
"provider": str(entry.get("provider") or "auto").strip(),
24292432
"model": str(entry.get("model") or "").strip(),
24302433
"base_url": str(entry.get("base_url") or "").strip(),
2434+
"timeout": entry.get("timeout", ""),
2435+
"download_timeout": entry.get("download_timeout", ""),
2436+
"max_concurrency": entry.get("max_concurrency", ""),
2437+
"extra_body": entry.get("extra_body") if isinstance(entry.get("extra_body"), dict) else {},
2438+
"api_key_set": bool(str(entry.get("api_key") or "").strip()),
24312439
})
24322440

24332441
return {
@@ -2436,10 +2444,29 @@ def get_auxiliary_models() -> dict:
24362444
}
24372445

24382446

2439-
def set_auxiliary_model(task: str, provider: str, model: str) -> dict:
2447+
def _coerce_optional_positive_int(value, field: str):
2448+
if value is None:
2449+
return None
2450+
if isinstance(value, str):
2451+
value = value.strip()
2452+
if value == "":
2453+
return ""
2454+
try:
2455+
number = int(value)
2456+
except (TypeError, ValueError) as exc:
2457+
raise ValueError(f"{field} must be a positive integer") from exc
2458+
if number < 1:
2459+
raise ValueError(f"{field} must be a positive integer")
2460+
return number
2461+
2462+
2463+
def set_auxiliary_model(task: str, provider: str, model: str, advanced: dict | None = None) -> dict:
24402464
"""Persist an auxiliary model assignment in config.yaml.
24412465
24422466
Special case: task='__reset__' clears all auxiliary slots.
2467+
``advanced`` may update per-slot fields surfaced behind the WebUI gear menu.
2468+
Sensitive api_key values are write-only: get_auxiliary_models() only reports
2469+
whether one is set.
24432470
"""
24442471
if task != "__reset__" and task not in AUX_TASK_SLOTS:
24452472
raise ValueError(
@@ -2472,6 +2499,41 @@ def set_auxiliary_model(task: str, provider: str, model: str) -> dict:
24722499
slot_cfg = {}
24732500
slot_cfg["provider"] = provider or "auto"
24742501
slot_cfg["model"] = model or ""
2502+
if advanced is not None:
2503+
if not isinstance(advanced, dict):
2504+
raise ValueError("advanced auxiliary options must be an object")
2505+
if "base_url" in advanced:
2506+
base_url = str(advanced.get("base_url") or "").strip().rstrip("/")
2507+
if base_url:
2508+
slot_cfg["base_url"] = base_url
2509+
else:
2510+
slot_cfg.pop("base_url", None)
2511+
for field in ("timeout", "download_timeout", "max_concurrency"):
2512+
if field in advanced:
2513+
coerced = _coerce_optional_positive_int(advanced.get(field), field)
2514+
if coerced == "":
2515+
slot_cfg.pop(field, None)
2516+
elif coerced is not None:
2517+
slot_cfg[field] = coerced
2518+
if "extra_body" in advanced:
2519+
extra_body = advanced.get("extra_body")
2520+
if isinstance(extra_body, str):
2521+
text = extra_body.strip()
2522+
extra_body = json.loads(text) if text else {}
2523+
if extra_body in (None, ""):
2524+
slot_cfg.pop("extra_body", None)
2525+
elif isinstance(extra_body, dict):
2526+
if extra_body:
2527+
slot_cfg["extra_body"] = extra_body
2528+
else:
2529+
slot_cfg.pop("extra_body", None)
2530+
else:
2531+
raise ValueError("extra_body must be a JSON object")
2532+
if advanced.get("api_key_clear"):
2533+
slot_cfg["api_key"] = ""
2534+
api_key = str(advanced.get("api_key") or "").strip()
2535+
if api_key:
2536+
slot_cfg["api_key"] = api_key
24752537
if provider and (provider.startswith("custom:") or provider == "custom"):
24762538
try:
24772539
_, _, resolved_base_url = resolve_model_provider(model)

api/routes.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5296,10 +5296,11 @@ def handle_post(handler, parsed) -> bool:
52965296
task = str(body.get("task") or "").strip()
52975297
provider = str(body.get("provider") or "auto").strip()
52985298
model = str(body.get("model") or "").strip()
5299+
advanced = body.get("advanced") if isinstance(body, dict) else None
52995300
if scope == "auxiliary":
53005301
from api.config import set_auxiliary_model
53015302
try:
5302-
return j(handler, set_auxiliary_model(task, provider, model))
5303+
return j(handler, set_auxiliary_model(task, provider, model, advanced=advanced))
53035304
except Exception as exc:
53045305
return bad(handler, str(exc), status=400)
53055306
if scope == "main":

0 commit comments

Comments
 (0)