Some checks failed
CI / lint (push) Successful in 39s
CI / notebooks-smoke (push) Successful in 1m42s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
CI / test (push) Failing after 2m30s
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / llm (push) Has been skipped
Deploy / mc (push) Has been skipped
Infra CI / zotero (push) Successful in 15s
Infra CI / notebooks (push) Successful in 52s
Deploy / report (push) Has been cancelled
Infra CI / api (push) Has been cancelled
Infra CI / llm (push) Has been cancelled
Infra CI / mc (push) Has been cancelled
Infra CI / docs (push) Has started running
A retrieved FR paragraph that cites a CMS manual ('Pub. 100-04,
Chapter 12, Section 30.6.4') now carries those citations on its source
(as_source iom_refs, parsed by pfs.guidance.iom_refs over the full
chunk text). llm.iomlink resolves each cited section to its indexed
manual chunk (exact section, else the first finer section under it,
else the chapter's first section) and the chat merges up to
iom_companion_max (4) of them in after the CPT manual block, labelled
'IOM 100-04 ch.12 §30.6.4', linked to the chapter PDF page, marked
'cited by [91 FR … ¶n]' in the prompt and the sources drawer; most-cited
sections first, nothing already among the sources repeated, no query
when no rule cites a manual. The search page shows 'cites IOM …' links
on rule hits that open the cited section under the manual filters, and
gains manual / chapter / section / theme fields. Rule paragraphs are
theme-stamped as well (stack llm stamp-themes --collection rules
--doctype rule: 67,340 chunks).
145 lines
5.2 KiB
Python
145 lines
5.2 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.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
|