"""The docker deployment must run auxiliary calls on a small model. Latency win: intent judging, tool routing and arg extraction are classification/JSON calls, not the spoken answer. Running them on a small fast model means the big chat model only runs once per command (for the answer), instead of 2-3 times per command for routing/extraction too. The wiring is: docker/jarvis-config.template.json renders `intent_judge_model` from `${OLLAMA_INTENT_MODEL}`, and the reply engine's resolver falls through `tool_router_model -> intent_judge_model -> ollama_chat_model`. The template sets no `tool_router_model`, so the auxiliary model is whatever `OLLAMA_INTENT_MODEL` renders to. These tests pin that behaviour end to end. """ import json import string from pathlib import Path import pytest from jarvis.reply.engine import resolve_tool_router_model TEMPLATE = Path(__file__).resolve().parent.parent / "docker" / "jarvis-config.template.json" def _render(**env) -> dict: raw = TEMPLATE.read_text(encoding="utf-8") return json.loads(string.Template(raw).safe_substitute(**env)) class _Cfg: """cfg stand-in carrying only the fields the resolver reads. The template does not render `tool_router_model`, so it stays empty here too.""" def __init__(self, rendered: dict): self.tool_router_model = rendered.get("tool_router_model", "") or "" self.intent_judge_model = rendered.get("intent_judge_model", "") or "" self.ollama_chat_model = rendered.get("ollama_chat_model", "") or "" def test_template_renders_separate_intent_model(): cfg = _render(OLLAMA_CHAT_MODEL="qwen3:8b", OLLAMA_INTENT_MODEL="qwen2.5:3b") assert cfg["ollama_chat_model"] == "qwen3:8b" assert cfg["intent_judge_model"] == "qwen2.5:3b" assert cfg["intent_judge_model"] != cfg["ollama_chat_model"] @pytest.mark.unit def test_aux_calls_route_to_small_model_not_chat_model(): """The whole point: with a big chat model and a small intent model, tool routing must resolve to the small model, leaving the big model for answers.""" cfg = _Cfg(_render(OLLAMA_CHAT_MODEL="qwen3:8b", OLLAMA_INTENT_MODEL="qwen2.5:3b")) assert resolve_tool_router_model(cfg) == "qwen2.5:3b" @pytest.mark.unit def test_folding_intent_onto_chat_model_keeps_one_model(): """Setting OLLAMA_INTENT_MODEL == OLLAMA_CHAT_MODEL folds everything back onto a single resident model (the documented VRAM-saving opt-out).""" cfg = _Cfg(_render(OLLAMA_CHAT_MODEL="qwen2.5:3b", OLLAMA_INTENT_MODEL="qwen2.5:3b")) assert resolve_tool_router_model(cfg) == "qwen2.5:3b" assert cfg.intent_judge_model == cfg.ollama_chat_model