import pytest from aiatlas.connectors.labs.mistral import DOCS, NEWS_RSS, MistralConnector from aiatlas.sdk.facts import Target from tests.conftest import claims_of, entity_names, extract_from_fixture, fixture_path @pytest.fixture def connector() -> MistralConnector: return MistralConnector() async def test_models_overview(connector): facts = await extract_from_fixture(connector, Target(url=f"{DOCS}/models", doc_type="model_docs", key="models"), fixture_path("mistral", "models.html")) models = entity_names(facts, "model") assert len(models) >= 55 medium = claims_of(facts, "Mistral Medium 3.5") assert medium["license"] == "MIT-Modified" and medium["license_raw"] == "Modified MIT" and medium["openness"] == "open-weights" and medium["version"] == "26.04" assert medium["weights_available"] is True and medium["official_url"] == f"{DOCS}/models/mistral-medium-3-5-26-04" small = claims_of(facts, "Mistral Small 4") assert small["license"] == "Apache-2.0" and small["license_raw"] == "Apache 2.0" and small["openness"] == "open-weights" # badge → ontology key mrl = next((claims_of(facts, e.name) for e in facts.entities if e.entity_type == "model" and claims_of(facts, e.name).get("license_raw") == "MRL"), None) if mrl is not None: assert mrl["license"] == "Mistral-Research" and mrl["openness"] == "restricted-weights" # research licence ≠ open weights medium_ref = next(e for e in facts.entities if e.name == "Mistral Medium 3.5") assert medium_ref.family is not None and medium_ref.family.name == "Mistral" and medium_ref.family.organization.name == "Mistral AI" # deprecation table: versioned API ids, dates (US format), status vs. today, alternative m31 = next(e for e in facts.entities if e.name == "Mistral Medium 3.1") assert m31.identifiers == {"mistral_docs_slug": "mistral-medium-3-1-25-08", "mistral_model_id": "mistral-medium-2508"} c31 = claims_of(facts, "Mistral Medium 3.1") assert c31["api_model_id"] == "mistral-medium-2508" and c31["deprecation_date"] == "2026-05-22" and c31["retirement_date"] == "2026-08-31" assert c31["status"] == "retired" assert ("Mistral Medium 3.1", "Mistral Medium 3.5") in {(r.subject.name, r.object.name) for r in facts.relations if r.predicate == "superseded_by"} # third-party model hosted on La Plateforme keeps its own developer glm = next(e for e in facts.entities if e.name == "Z.ai GLM 5.2") assert glm.organization is not None and glm.organization.slug_hint == "zhipu" assert any(r.predicate == "available_through" and r.subject is glm for r in facts.relations) pages = [t for t in facts.targets if t.doc_type == "model_page"] assert len(pages) == 20 and pages[0].url == f"{DOCS}/models/mistral-medium-3-5-26-04" # a reused display name never folds distinct versions together codestral = sorted(e.name for e in facts.entities if e.entity_type == "model" and e.name.startswith("Codestral") and "Embed" not in e.name and "Mamba" not in e.name) assert codestral == ["Codestral", "Codestral 24.05", "Codestral 25.01"] assert claims_of(facts, "Codestral 25.01")["api_model_id"] == "codestral-2501" assert len({(e.name.lower()) for e in facts.entities if e.entity_type == "model"}) == len([e for e in facts.entities if e.entity_type == "model"]) async def test_model_page(connector): target = Target(url=f"{DOCS}/models/mistral-medium-3-5-26-04", doc_type="model_page", key="model:mistral-medium-3-5-26-04", meta={"slug": "mistral-medium-3-5-26-04"}) facts = await extract_from_fixture(connector, target, fixture_path("mistral", "model-mistral-medium-3-5.html")) m = claims_of(facts, "Mistral Medium 3.5") assert m["context_length"] == 256_000 and m["license"] == "MIT-Modified" and m["license_raw"] == "Modified MIT" and m["openness"] == "open-weights" assert m["api_alias"] == "mistral-medium-latest" and m["api_aliases"] == ["mistral-medium-latest"] and m["tool_calling"] is True and m["structured_output"] is True assert {"function_calling", "structured_output"} <= set(m["capabilities"]) assert len(facts.prices) == 1 p = facts.prices[0] assert (p.input_per_mtok, p.output_per_mtok) == (1.5, 7.5) and p.features["eur_input_per_mtok"] == 1.25 and p.provider.identifiers["registry_provider"] == "mistral" ref = next(e for e in facts.entities if e.entity_type == "model") assert ref.identifiers == {"mistral_docs_slug": "mistral-medium-3-5-26-04"} async def test_news_feed(connector): facts = await extract_from_fixture(connector, Target(url=NEWS_RSS, doc_type="feed", key="news"), fixture_path("mistral", "news.rss.xml"), content_type="application/rss+xml") assert len(facts.events) == 86 assert facts.events[0].summary.startswith("Mistral AI: Cloudera and Mistral Partner") and facts.events[0].effective_at.date().isoformat() == "2026-09-10" assert any(e.category == "release" and "Mistral Small 4" in e.summary for e in facts.events)