oterm/tests/unit/test_providers_ollama.py
Yiorgis Gozadinos b0954e5bcb
Show context used against the model's context window
The usage footer now ends each turn with the tokens the conversation
occupies and, when known, the model's context window, as
"ctx 12.3k / 32.8k (38%)".

pydantic-ai only knows windows for cloud models. Local servers report
the context they actually run a model with, which can be far below
what the model supports (Ollama ran gpt-oss at 32768 of 131072, LM
Studio loaded Gemma 4 at 4096 of 262144), and only once it is loaded,
so oterm asks after each reply: Ollama's loaded models, max_model_len
from /v1/models (vLLM, oMLX), or LM Studio's loaded_context_length.
2026-09-27 13:04:06 +03:00

105 lines
3.6 KiB
Python

from oterm.providers import ollama as ollama_mod
from oterm.providers.ollama import (
ollama_client_host,
openai_compat_base_url,
parse_modelfile_parameters,
)
class _FakeClient:
last_kwargs: dict = {}
def __init__(self, host=None, verify=None, timeout=None):
type(self).last_kwargs = {"host": host, "verify": verify, "timeout": timeout}
def list(self):
return "list-response"
def show(self, model):
return f"show-{model}"
class TestClientWrappers:
def test_list_models_uses_env_config(self, monkeypatch):
import oterm.config
monkeypatch.setattr(ollama_mod, "Client", _FakeClient)
monkeypatch.setattr(oterm.config.envConfig, "OLLAMA_URL", "http://host:123")
monkeypatch.setattr(oterm.config.envConfig, "OTERM_VERIFY_SSL", False)
result = ollama_mod.list_models()
assert result == "list-response"
assert _FakeClient.last_kwargs == {
"host": "http://host:123",
"verify": False,
"timeout": None,
}
def test_list_models_strips_v1_suffix(self, monkeypatch):
"""OLLAMA_URL set to the OpenAI-compat base must still work for /api/list."""
import oterm.config
monkeypatch.setattr(ollama_mod, "Client", _FakeClient)
monkeypatch.setattr(oterm.config.envConfig, "OLLAMA_URL", "http://h:1/v1")
monkeypatch.setattr(oterm.config.envConfig, "OTERM_VERIFY_SSL", True)
ollama_mod.list_models()
assert _FakeClient.last_kwargs["host"] == "http://h:1"
def test_show_model_uses_env_config(self, monkeypatch):
monkeypatch.setattr(ollama_mod, "Client", _FakeClient)
assert ollama_mod.show_model("llama3") == "show-llama3"
class TestOllamaClientHost:
def test_passthrough_for_plain_host(self, monkeypatch):
import oterm.config
monkeypatch.setattr(oterm.config.envConfig, "OLLAMA_URL", "http://h:1")
assert ollama_client_host() == "http://h:1"
def test_strips_v1_suffix(self, monkeypatch):
import oterm.config
monkeypatch.setattr(oterm.config.envConfig, "OLLAMA_URL", "http://h:1/v1")
assert ollama_client_host() == "http://h:1"
def test_strips_trailing_slash(self, monkeypatch):
import oterm.config
monkeypatch.setattr(oterm.config.envConfig, "OLLAMA_URL", "http://h:1/v1/")
assert ollama_client_host() == "http://h:1"
class TestParseModelfileParameters:
def test_ignores_unknown_keys(self):
result = parse_modelfile_parameters("unknown_key 42\ntemperature 0.5")
assert result == {"temperature": 0.5}
def test_ignores_invalid_values(self):
result = parse_modelfile_parameters("temperature not_a_float\ntop_p 0.9")
assert result == {"top_p": 0.9}
def test_ignores_blank_and_valueless_lines(self):
result = parse_modelfile_parameters("\nseed\ntemperature 0.5")
assert result == {"temperature": 0.5}
class TestOpenAICompatBaseUrl:
def test_appends_v1(self, monkeypatch):
import oterm.config
monkeypatch.setattr(oterm.config.envConfig, "OLLAMA_URL", "http://h:1")
assert openai_compat_base_url() == "http://h:1/v1"
def test_idempotent_when_already_v1(self, monkeypatch):
import oterm.config
monkeypatch.setattr(oterm.config.envConfig, "OLLAMA_URL", "http://h:1/v1")
assert openai_compat_base_url() == "http://h:1/v1"
def test_strips_trailing_slash(self, monkeypatch):
import oterm.config
monkeypatch.setattr(oterm.config.envConfig, "OLLAMA_URL", "http://h:1/v1/")
assert openai_compat_base_url() == "http://h:1/v1"