Some checks failed
CI / lint (push) Successful in 1m36s
CI / notebooks-smoke (push) Successful in 2m6s
Deploy / changes (push) Successful in 18s
CI / test (push) Failing after 5m36s
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Successful in 2m24s
Deploy / notebooks (push) Successful in 6m4s
Deploy / api (push) Successful in 2m13s
Deploy / llm (push) Successful in 1m38s
Deploy / mc (push) Has been skipped
Deploy / bcda (push) Successful in 2m20s
Deploy / report (push) Successful in 15s
Golden v2 (200 comments, 8 dockets) showed recall, not precision, was the problem: stored tags scored P 0.96 R 0.55 on the held-out half. Live tune-split sweep on the rig: 14b/top 8/0.60 F1 0.72; /0.50 0.76; top 12/0.45 0.78; qwen2.5:32b was more conservative (top 8/0.50: P 0.97 R 0.59 F1 0.73). Held-out with top 12/0.45: P 0.95 R 0.61 F1 0.74 — PFS dockets 0.67-0.91, IPPS/OPPS ~0.28 (topics outside vocab v2).
167 lines
5.9 KiB
Python
167 lines
5.9 KiB
Python
"""llm.config — [llm] section parsing + env overrides."""
|
|
|
|
import pytest
|
|
|
|
from llm import config as llm_config
|
|
|
|
|
|
class TestLoad:
|
|
def test_defaults_from_stack_toml(self, monkeypatch):
|
|
monkeypatch.delenv("LLM_OLLAMA_HOSTS", raising=False)
|
|
monkeypatch.delenv("LLM_PG_HOST", raising=False)
|
|
monkeypatch.delenv("LLM_BUILD_ANN_INDEX", raising=False)
|
|
cfg = llm_config.load()
|
|
assert cfg.ollama_hosts == ("http://127.0.0.1:11434",)
|
|
assert cfg.embed_model == "nomic-embed-text"
|
|
assert cfg.embed_dim == 768
|
|
assert cfg.pg_host == "127.0.0.1"
|
|
assert cfg.pg_db == "llm"
|
|
assert cfg.build_ann_index is True
|
|
|
|
def test_env_overrides(self, monkeypatch):
|
|
monkeypatch.setenv(
|
|
"LLM_OLLAMA_HOSTS",
|
|
"http://rig:11434, http://laptop:11434",
|
|
)
|
|
monkeypatch.setenv("LLM_PG_HOST", "postgres")
|
|
cfg = llm_config.load()
|
|
assert cfg.ollama_hosts == ("http://rig:11434", "http://laptop:11434")
|
|
assert cfg.pg_host == "postgres"
|
|
|
|
def test_build_ann_index_env_override_true(self, monkeypatch):
|
|
monkeypatch.setenv("LLM_BUILD_ANN_INDEX", "1")
|
|
cfg = llm_config.load()
|
|
assert cfg.build_ann_index is True
|
|
|
|
def test_build_ann_index_env_override_false(self, monkeypatch):
|
|
monkeypatch.setenv("LLM_BUILD_ANN_INDEX", "no")
|
|
cfg = llm_config.load()
|
|
assert cfg.build_ann_index is False
|
|
|
|
|
|
class TestPgUrl:
|
|
def test_url_includes_password_from_env(self, monkeypatch):
|
|
monkeypatch.setenv("LLM_DB_PASSWORD", "s3cret")
|
|
cfg = llm_config.load()
|
|
url = llm_config.pg_url(cfg)
|
|
assert url == f"postgresql+psycopg://llm:s3cret@{cfg.pg_host}:5432/llm"
|
|
|
|
def test_missing_password_raises(self, monkeypatch):
|
|
monkeypatch.delenv("LLM_DB_PASSWORD", raising=False)
|
|
cfg = llm_config.load()
|
|
with pytest.raises(RuntimeError, match="LLM_DB_PASSWORD"):
|
|
llm_config.pg_url(cfg)
|
|
|
|
|
|
class TestParseHosts:
|
|
def test_bare_and_annotated(self):
|
|
out = llm_config.parse_hosts(
|
|
"http://ollama:11434, http://rig.local:11434@24 ,http://nb:11434@12"
|
|
)
|
|
assert out == (
|
|
("http://ollama:11434", 0.0),
|
|
("http://rig.local:11434", 24.0),
|
|
("http://nb:11434", 12.0),
|
|
)
|
|
|
|
def test_trailing_slash_stripped_and_empty_parts_dropped(self):
|
|
assert llm_config.parse_hosts("http://a:1/@8,,") == (("http://a:1", 8.0),)
|
|
|
|
|
|
class TestNewKnobs:
|
|
def test_defaults_when_section_lacks_keys(self, monkeypatch):
|
|
monkeypatch.delenv("LLM_OLLAMA_HOSTS", raising=False)
|
|
cfg = llm_config.load()
|
|
assert cfg.large_min_vram_gb == 20.0
|
|
assert cfg.chat_num_ctx == 8192
|
|
assert cfg.chat_chars_per_token == 2.4
|
|
assert cfg.recency_half_life_days == 365.0
|
|
assert cfg.recency_weight == 0.3
|
|
assert cfg.k_per_kind == {"comment": 8, "rule": 4, "corpus": 4}
|
|
assert cfg.top_n == 8
|
|
assert isinstance(cfg.instruct_model_large, str)
|
|
|
|
def test_env_hosts_populate_vram_map(self, monkeypatch):
|
|
monkeypatch.setenv(
|
|
"LLM_OLLAMA_HOSTS", "http://rig:11434@24,http://laptop:11434@12"
|
|
)
|
|
cfg = llm_config.load()
|
|
assert cfg.ollama_hosts == ("http://rig:11434", "http://laptop:11434")
|
|
assert cfg.host_vram == {"http://rig:11434": 24.0, "http://laptop:11434": 12.0}
|
|
|
|
def test_valuation_knobs_defaults(self, monkeypatch):
|
|
monkeypatch.delenv("LLM_DUCKDB_REPLICA", raising=False)
|
|
cfg = llm_config.load()
|
|
assert cfg.duckdb_replica == "data/replica/aco.ro.duckdb"
|
|
assert cfg.valuation_years == 4
|
|
assert cfg.code_cited_per_code == 3
|
|
assert cfg.code_cited_collections == ("rules", "comments", "corpus")
|
|
assert cfg.code_cited_max == 12
|
|
assert cfg.lineage_max_rows == 25
|
|
assert cfg.lineage_on_demand_max == 3
|
|
|
|
def test_duckdb_replica_env_override(self, monkeypatch):
|
|
monkeypatch.setenv("LLM_DUCKDB_REPLICA", "/app/data/replica/aco.ro.duckdb")
|
|
assert llm_config.load().duckdb_replica == "/app/data/replica/aco.ro.duckdb"
|
|
|
|
|
|
class TestStrTuple:
|
|
"""``code_cited_collections`` must never explode a bare scalar string
|
|
into a tuple of its characters (``tuple("rules")``)."""
|
|
|
|
def test_scalar_string_becomes_one_tuple(self):
|
|
assert llm_config._str_tuple("rules") == ("rules",)
|
|
|
|
def test_list_passes_through_as_tuple(self):
|
|
assert llm_config._str_tuple(["rules", "comments"]) == ("rules", "comments")
|
|
|
|
def test_code_cited_collections_scalar_string_in_toml_is_one_tuple(
|
|
self, monkeypatch
|
|
):
|
|
import conf
|
|
from conf import _Cfg
|
|
|
|
raw = dict(conf.cfg.to_dict())
|
|
raw["llm"] = dict(raw["llm"])
|
|
raw["llm"]["code_cited_collections"] = "rules"
|
|
monkeypatch.setattr(conf, "cfg", _Cfg(raw))
|
|
assert llm_config.load().code_cited_collections == ("rules",)
|
|
|
|
|
|
def test_iom_companion_max_defaults_to_four():
|
|
from llm.config import LlmConfig
|
|
|
|
cfg = LlmConfig(
|
|
ollama_hosts=("http://h",),
|
|
embed_model="e",
|
|
instruct_model="i",
|
|
embed_dim=1,
|
|
build_ann_index=False,
|
|
pg_host="h",
|
|
pg_port=1,
|
|
pg_db="d",
|
|
pg_user="u",
|
|
)
|
|
assert cfg.iom_companion_max == 4
|
|
|
|
|
|
def test_instruct_model_env_override(monkeypatch):
|
|
# Judge-model comparisons (14b vs 32b) without editing stack.toml.
|
|
from llm.config import load
|
|
|
|
monkeypatch.setenv("LLM_INSTRUCT_MODEL", "qwen2.5:32b")
|
|
assert load().instruct_model == "qwen2.5:32b"
|
|
monkeypatch.delenv("LLM_INSTRUCT_MODEL")
|
|
assert load().instruct_model == "qwen2.5:14b"
|
|
|
|
|
|
def test_tagging_parameters_load_from_config():
|
|
# `stack llm tag` defaulted to min_confidence 0.0 while eval-tags used
|
|
# 0.60: the run and its gate disagreed. Both now read these.
|
|
from llm.config import load
|
|
|
|
cfg = load()
|
|
assert cfg.tag_top == 12
|
|
assert cfg.tag_max_tags == 3
|
|
assert cfg.tag_min_confidence == 0.45
|