HTML 77.2%
TypeScript 10.5%
Python 9.6%
JavaScript 2.5%
1import pytest23from aiatlas.connectors.labs.openai import DOCS, OpenAIConnector, _ids_in_cell, _shutdown_date, _split_model_cell4from aiatlas.sdk.facts import Target5from tests.conftest import claims_of, entity_names, extract_from_fixture, fixture_path67MD = "text/markdown"8910@pytest.fixture11def connector() -> OpenAIConnector:12 return OpenAIConnector()131415async def test_catalog(connector):16 target = Target(url=f"{DOCS}/models.md", doc_type="model_docs", key="models")17 facts = await extract_from_fixture(connector, target, fixture_path("openai", "models.md"), content_type=MD)18 models = entity_names(facts, "model")19 assert len(models) >= 9020 assert {"GPT-6 Astra", "GPT-4.1", "gpt-oss-120b", "o3", "Sora 2"} <= models21 gpt41 = claims_of(facts, "GPT-4.1")22 assert gpt41["api_model_id"] == "gpt-4.1" and gpt41["openness"] == "proprietary"23 assert gpt41["official_url"] == f"{DOCS}/models/gpt-4.1"24 assert claims_of(facts, "gpt-oss-120b")["openness"] == "open-weights"25 assert "status" not in claims_of(facts, "GPT-4.5 Preview") # lifecycle comes from the deprecations page26 pages = [t for t in facts.targets if t.doc_type == "model_page"]27 assert len(pages) == 40 and pages[0].url == f"{DOCS}/models/gpt-6-astra.md" # featured models first28 assert all(t.url.endswith(".md") for t in pages)29 assert sum(r.predicate == "develops" for r in facts.relations) >= 90303132async def test_model_page(connector):33 target = Target(url=f"{DOCS}/models/gpt-4.1.md", doc_type="model_page", key="model:gpt-4.1", meta={"model": "GPT-4.1", "api_id": "gpt-4.1"})34 facts = await extract_from_fixture(connector, target, fixture_path("openai", "model-gpt-4.1.md"), content_type=MD)35 m = claims_of(facts, "GPT-4.1")36 assert m["context_length"] == 1_047_576 and m["max_output_tokens"] == 32_768 and m["knowledge_cutoff"] == "2024-06"37 assert m["modalities_input"] == ["image", "text"] and m["modalities_output"] == ["text"] and m["vision"] is True # canonical, sorted38 assert m["tool_calling"] is True and m["structured_output"] is True and m["fine_tuning_available"] is True39 assert {"function_calling", "structured_output", "fine_tuning"} <= set(m["capabilities"]) and "structured_outputs" not in m["capabilities"]40 assert "structured_outputs" in m["capabilities_raw"] # OpenAI's own slugs kept as raw41 assert m["default_snapshot"] == "gpt-4.1-2025-04-14"42 ref = next(e for e in facts.entities if e.entity_type == "model")43 assert ref.identifiers == {"openai_model_id": "gpt-4.1"} and "gpt-4.1-2025-04-14" in ref.aliases44 assert ref.family is not None and ref.family.name == "GPT 4.1" and ref.family.organization.name == "OpenAI" and ref.identity_confidence == "high"45 assert facts.prices == [] # provider prices come from the pricing page only464748async def test_pricing(connector):49 target = Target(url=f"{DOCS}/pricing.md", doc_type="pricing", key="pricing")50 facts = await extract_from_fixture(connector, target, fixture_path("openai", "pricing.md"), content_type=MD)51 by_id = {p.provider_model_id: p for p in facts.prices}52 assert len(by_id) >= 6053 astra = by_id["gpt-6-astra"]54 assert (astra.input_per_mtok, astra.cached_input_per_mtok, astra.cache_write_per_mtok, astra.output_per_mtok) == (10.0, 1.0, 12.5, 50.0)55 assert (astra.batch_input_per_mtok, astra.batch_output_per_mtok) == (5.0, 25.0)56 assert astra.features["long_context_input_per_mtok"] == 20.0 and astra.features["fast_mode_input_per_mtok"] == 20.057 # snapshot rows price the base model under their own provider id58 snap = by_id["gpt-4o-2024-05-13"]59 assert snap.model.name == "gpt-4o" and snap.input_per_mtok == 5.0 and "gpt-4o-2024-05-13" in snap.model.aliases60 assert by_id["gpt-5.5"].features["context_note"] == "<272K context length"61 realtime = by_id["gpt-realtime-2.1"]62 assert (realtime.input_per_mtok, realtime.output_per_mtok) == (4.0, 24.0) and realtime.features["audio_input_per_mtok"] == 32.063 assert by_id["text-embedding-3-small"].input_per_mtok == 0.02 and by_id["omni-moderation-latest"].features.get("free") is True64 assert by_id["sora-2"].features["standard_per_second_by_size"]["720p"] == 0.1065 assert "gpt-5.4-cyber" not in by_id # a row made only of dashes carries no price66 assert all(p.model.identifiers.get("openai_model_id") for p in facts.prices)676869async def test_deprecations(connector):70 target = Target(url=f"{DOCS}/deprecations.md", doc_type="model_docs", key="deprecations")71 facts = await extract_from_fixture(connector, target, fixture_path("openai", "deprecations.md"), content_type=MD)72 whisper = claims_of(facts, "whisper-1")73 assert whisper["deprecation_date"] == "2026-08-26" and whisper["retirement_date"] == "2027-02-26" and whisper["status"] == "deprecated"74 gpt45 = claims_of(facts, "gpt-4.5-preview")75 assert gpt45["retirement_date"] == "2025-07-14" and gpt45["status"] == "retired"76 gpt5 = claims_of(facts, "gpt-5")77 assert gpt5["retirement_date"] == "2026-12-11" and gpt5["retired_snapshots"] == ["gpt-5-2025-08-07"]78 # one claim set per model = its latest deprecation round; every retired snapshot listed once79 turbo = claims_of(facts, "gpt-3.5-turbo")80 assert turbo["retirement_date"] == "2026-10-23" and turbo["deprecation_date"] == "2026-04-22" and turbo["status"] == "deprecated"81 assert {"gpt-3.5-turbo-0125", "gpt-3.5-turbo-0613", "gpt-3.5-turbo-0301"} <= set(turbo["retired_snapshots"])82 assert "api_model_id" not in turbo # ids come from the catalog83 props = [(c.entity.name, c.property) for c in facts.claims]84 assert len(props) == len(set(props)) # no flip-flopping claims inside the document85 # family + preview snapshots are one lineage: a single claim set for gpt-4o-audio (the preview id becomes an alias)86 audio = claims_of(facts, "gpt-4o-audio-preview") # catalog id of "GPT-4o Audio"87 assert audio["retirement_date"] == "2027-01-20" and "gpt-4o-audio" not in entity_names(facts, "model")88 assert "gpt-4o-audio" in next(e for e in facts.entities if e.name == "gpt-4o-audio-preview").aliases89 assert {"gpt-4.5-preview", "o1-preview", "o1", "gpt-4-1106-preview"} <= entity_names(facts, "model")90 o1p = claims_of(facts, "o1-preview") # a model of its own, not a variant of o191 assert o1p["retirement_date"] == "2025-07-28" and o1p["status"] == "retired" and o1p["deprecation_date"] == "2025-04-28"92 sup = {(r.subject.name, r.object.name) for r in facts.relations if r.predicate == "superseded_by"}93 assert ("whisper-1", "gpt-live-transcribe") in sup and ("gpt-4.5-preview", "gpt-4.1") in sup94 assert "gpt-4o-mini-transcribe-2025-12-15" not in entity_names(facts, "model") # replacement snapshots fold into their base model959697async def test_news(connector):98 target = Target(url="https://openai.com/news/rss.xml", doc_type="feed", key="news")99 facts = await extract_from_fixture(connector, target, fixture_path("openai", "news.rss.xml"), content_type="application/rss+xml")100 events = [e for e in facts.events if e.event_type == "ANNOUNCEMENT"]101 assert len(events) == 40 and all(e.effective_at is not None for e in events)102 assert any(e.category == "release" for e in events)103 assert events[0].dedupe_key == "ANNOUNCEMENT:https://openai.com/index/scaling-storage-one-billion-users-part-one"104 assert facts.targets == [] # article pages are blocked (403) for crawlers: no follow-ups105106107def test_helpers():108 assert _split_model_cell("gpt-5.5 (<272K context length)") == ("gpt-5.5", "<272K context length")109 assert _split_model_cell("Whisper") == (None, None)110 assert _ids_in_cell("`gpt-3.5-turbo-0125` | `gpt-3.5-turbo` , `gpt-3.5-turbo-completions`") == ["gpt-3.5-turbo-0125", "gpt-3.5-turbo", "gpt-3.5-turbo-completions"]111 assert _ids_in_cell("`gpt-5.6-sol` (`reasoning.mode: pro`)") == ["gpt-5.6-sol"]112 assert _shutdown_date("2026‑03‑26") == ("2026-03-26", False)113 assert _shutdown_date("at earliest 2024-06-13") == ("2024-06-13", True)114 assert _shutdown_date("Feb 26, 2027") == ("2027-02-26", False)115