from knaster.registry import AdapterSpec, Registry from knaster.skills import compact_body, parse_skill def test_slot_effective_context_prefers_calibration(registry): slot = registry.slot("tier1-general") assert slot.effective_context == 2000 registry.set_calibrated_context("tier1-general", 1500) assert registry.slot("tier1-general").effective_context == 1500 def test_effective_context_never_exceeds_max(registry): registry.set_calibrated_context("tier1-general", 999999) assert registry.slot("tier1-general").effective_context == 8192 def test_status_and_strong_slot(registry): registry.set_status("tier1-general", "degraded", reason="test", set_by="healer") slot = registry.slot("tier1-general") assert not slot.available and slot.set_by == "healer" assert registry.strong_slot().name == "tier0-strong" def test_unknown_fallback_rejected(store): import pytest with pytest.raises(ValueError): Registry.from_dict({"slots": {"a": {"tier": 1, "litellm_model": "a", "base_model": "b", "max_context": 10, "fallbacks": ["x"]}}}, store) def test_adapter_overlay_and_active(registry): assert registry.active_adapter("base-14b", "rechnungen").name == "rechnungen-v1" registry.set_adapter(AdapterSpec(name="rechnungen-v2", base_model="base-14b", cluster="rechnungen", version=2, status="active")) assert registry.active_adapter("base-14b", "rechnungen").name == "rechnungen-v2" registry.set_adapter(AdapterSpec(name="rechnungen-v2", base_model="base-14b", cluster="rechnungen", version=2, status="retired")) assert registry.active_adapter("base-14b", "rechnungen").name == "rechnungen-v1" assert registry.active_adapter("other-base", "rechnungen") is None def test_base_model_override_and_export(registry): registry.set_base_model("tier1-general", "new-base") assert registry.slot("tier1-general").base_model == "new-base" exported = registry.export() assert exported["slots"]["tier1-general"]["base_model"] == "new-base" def test_parse_skill_and_compact(library): skill = library.get("rechnung-extrahieren") assert skill.cluster == "rechnungen" assert skill.meta.output.format == "json" assert "Beispiele" in skill.prompt("full") assert "Beispiele" not in skill.prompt("compact") assert "Lies Nummer" in skill.prompt("compact") def test_compact_body_keeps_following_sections(): body = "# T\nA\n## Beispiele\nx\ny\n## Regeln\nR\n" assert compact_body(body) == "# T\nA\n## Regeln\nR" def test_parse_skill_requires_fields(): import pytest with pytest.raises(ValueError): parse_skill("---\nname: x\n---\nbody") with pytest.raises(ValueError): parse_skill("kein frontmatter") def test_routable_and_state_overlay(library): names = {s.name for s in library.routable()} assert "entwurf" not in names and "vertrag-pruefen" in names library.set_state("rechnung-extrahieren", status="demoted", reason="drift") assert library.get("rechnung-extrahieren").meta.status == "demoted" assert library.get("rechnung-extrahieren").meta.stage == 1