mirror of
https://github.com/ggozad/oterm.git
synced 2026-11-04 12:21:24 +01:00
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.
105 lines
3.6 KiB
Python
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"
|