SPB Git forge

spb/ai-atlas

Public
41commits 1branches 0releases
4.6 MBsize
maindefault branch
12 days agolast push
HTML 77.2% TypeScript 10.5% Python 9.6% JavaScript 2.5%

SDK: never lose a failed target silently, order-insensitive list comparison, unique result dedupe suffix; scheduler runs connectors sequentially; ecosystem connector fixes and registry fragments

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed 13 days ago (Sep 11, 2026) parent 0fce6ab

7 changed files +40 −17

modified src/aiatlas/connectors/benchmarks/leaderboards.py +8 −4
@@ -175,6 +175,8 @@ class SweBenchLeaderboardConnector(_Leaderboard):
175 175 resolved = r.get("resolved")
176 176 if not model_name or not isinstance(resolved, (int, float)):
177 177 return
178 + if re.search(r"\s(&|\+|and)\s", model_name): # "GPT-4o & Claude 3 Opus": a multi-model system, not one model
179 + return
178 180 tags = [t for t in r.get("tags") or [] if isinstance(t, str)]
179 181 model_tags = [t.split(":", 1)[1].strip() for t in tags if t.lower().startswith("model:")]
180 182 org = org_from_name(facts, r.get("model_org"))
@@ -332,16 +334,18 @@ class ArtificialAnalysisConnector(_Leaderboard):
332 334 org = facts.entity("company", creator_name, identifiers={"artificial_analysis_creator": creator.get("slug") or _slug(creator_name)})
333 335 ref = facts.entity("model", name[:200], identifiers={"artificial_analysis": slug}, organization=org,
334 336 aliases=[a for a in {slug, m.get("shortName")} if a and a != name])
337 + # AA copies release date / openness / context / deprecation from the labs: recorded under `aa_*` so that a second-hand
338 + # tier-2 source never supersedes another tier-2 source (hub/OpenRouter) every run; the results are AA's own data.
335 339 if m.get("releaseDate"):
336 − facts.claim(ref, "release_date", str(m["releaseDate"])[:10])
340 + facts.claim(ref, "aa_release_date", str(m["releaseDate"])[:10])
337 341 if isinstance(m.get("isOpenWeights"), bool):
338 − facts.claim(ref, "openness", "open-weights" if m["isOpenWeights"] else "proprietary")
342 + facts.claim(ref, "aa_openness", "open-weights" if m["isOpenWeights"] else "proprietary")
339 343 if isinstance(m.get("isReasoning"), bool):
340 344 facts.claim(ref, "reasoning", m["isReasoning"])
341 345 if m.get("deprecated") is True:
342 − facts.claim(ref, "status", "deprecated")
346 + facts.claim(ref, "aa_deprecated", True)
343 347 if isinstance(m.get("contextWindowTokens"), int) and m["contextWindowTokens"] > 0:
344 − facts.claim(ref, "context_length", m["contextWindowTokens"], unit="tokens")
348 + facts.claim(ref, "aa_context_window", m["contextWindowTokens"], unit="tokens")
345 349 if isinstance(m.get("medianOutputTokensPerSecond"), (int, float)):
346 350 facts.claim(ref, "metric.aa_median_output_tokens_per_second", round(float(m["medianOutputTokensPerSecond"]), 1))
347 351 ii = m.get("intelligenceIndex")
modified src/aiatlas/connectors/hub/huggingface.py +3 −2
@@ -133,7 +133,7 @@ class HuggingFaceConnector(BaseConnector):
133 133 if isinstance(m.get("numParameters"), int) and m["numParameters"] > 0:
134 134 facts.claim(ref, "parameter_count", m["numParameters"])
135 135 facts.follow(f"{HF}/{repo_id}", doc_type="model_page", entity=ref, key=f"model:{repo_id}", min_bytes=5000,
136 − meta={"hf_repo": repo_id, "hf_org": hf_org, "gated": bool(gated)})
136 + meta={"hf_repo": repo_id, "hf_org": hf_org, "gated": bool(gated), "num_parameters": m.get("numParameters")})
137 137 facts.document_entity = org
138 138 facts.document_title = f"Hugging Face models — {hf_org}"
139 139
@@ -172,7 +172,8 @@ class HuggingFaceConnector(BaseConnector):
172 172 # parameters
173 173 st = model.get("safetensors") or {}
174 174 total = st.get("total") if isinstance(st, dict) else None
175 − params = total if isinstance(total, int) and total > 0 else parse_param_count(repo_id.split("/")[-1])
175 + listed = target.meta.get("num_parameters") # the hub's own count from the listing (GGUF repos have no safetensors)
176 + params = total if isinstance(total, int) and total > 0 else listed if isinstance(listed, int) and listed > 0 else parse_param_count(repo_id.split("/")[-1])
176 177 facts.claim(ref, "parameter_count", params)
177 178 facts.claim(ref, "active_parameter_count", parse_active_params(repo_id.split("/")[-1]))
178 179 if isinstance(st, dict) and st.get("parameters"):
modified src/aiatlas/connectors/providers/openrouter.py +4 −1
@@ -130,7 +130,10 @@ class OpenRouterConnector(BaseConnector):
130 130 facts.claim(ref, "vision", True)
131 131 created = item.get("created")
132 132 if isinstance(created, (int, float)) and created > 1_000_000_000:
133 − facts.claim(ref, "release_date", datetime.fromtimestamp(created, tz=UTC).date().isoformat())
133 + listed = datetime.fromtimestamp(created, tz=UTC).date().isoformat()
134 + facts.claim(ref, "openrouter_listed_at", listed)
135 + if "hf_repo" not in ref.identifiers: # hub-hosted weights carry their own creation date (same tier) — API-only models don't
136 + facts.claim(ref, "release_date", listed)
134 137 facts.claim(ref, "knowledge_cutoff", _month(item.get("knowledge_cutoff")))
135 138 facts.claim(ref, "openrouter_expiration_date", item.get("expiration_date") if isinstance(item.get("expiration_date"), str) else None)
136 139
modified src/aiatlas/sdk/connector.py +13 −2
@@ -256,8 +256,19 @@ class BaseConnector:
256 256
257 257 async def worker(target: Target) -> None:
258 258 nonlocal processed
259 − async with sem:
260 − followups = await self._process_target(ctx, target)
259 + try:
260 + async with sem:
261 + followups = await self._process_target(ctx, target)
262 + except Exception as exc: # noqa: BLE001 — never lose a document silently
263 + ctx.stats.docs_failed += 1
264 + ctx.log.exception("target failed", extra={"url": target.url})
265 + try:
266 + async with transaction() as conn:
267 + await execute(conn, "insert into connector_errors (connector_name, run_id, url, error_type, message) values (:n, :r, :u, :t, :m)",
268 + n=self.name, r=ctx.run_id, u=target.url, t=exc.__class__.__name__, m=str(exc)[:2000])
269 + except Exception: # noqa: BLE001
270 + pass
271 + return
261 272 for f in followups:
262 273 cu = canonicalize_url(f.url)
263 274 if cu not in ctx.seen_urls and processed + queue.qsize() < ctx.max_targets:
modified src/aiatlas/sdk/writer.py +4 −3
@@ -41,8 +41,9 @@ NEW_IMPORTANCE = {"model": 3, "company": 2, "provider": 2, "paper": 1, "dataset"
41 41 def _norm_value(v: Any) -> Any:
42 42 if isinstance(v, datetime):
43 43 return v.astimezone(UTC).isoformat(timespec="seconds")
44 − if isinstance(v, (set, tuple)):
45 − return sorted(v) if all(isinstance(x, str) for x in v) else list(v)
44 + if isinstance(v, (set, tuple, list)):
45 + items = [_norm_value(x) for x in v]
46 + return sorted(items) if all(isinstance(x, (str, int, float)) and not isinstance(x, bool) for x in items) else items
46 47 if isinstance(v, float) and v.is_integer() and abs(v) < 1e15:
47 48 return int(v)
48 49 return v
@@ -281,7 +282,7 @@ class FactWriter:
281 282 if existing:
282 283 if abs((existing["score"] or 0) - r.score) > 1e-9:
283 284 await execute(self.conn, "update benchmark_results set valid_to = :o, dedupe_key = dedupe_key || ':' || :suffix where id = :id",
284 − o=self.observed_at, suffix=self.observed_at.strftime("%Y%m%d%H%M%S"), id=existing["id"])
285 + o=self.observed_at, suffix=new_id("result")[-10:], id=existing["id"])
285 286 model = await fetch_one(self.conn, "select canonical_name from entities where id = :id", id=mid)
286 287 bench = await fetch_one(self.conn, "select canonical_name from entities where id = :id", id=bid)
287 288 await self.emit_event("BENCHMARK_UPDATED", "benchmark",
modified src/aiatlas/services/scheduler.py +4 −2
@@ -57,14 +57,16 @@ async def tick() -> None:
57 57 forced = [n for n in await _pop_run_now() if n in known and n not in _running]
58 58 if forced:
59 59 log.info("run-now connectors", extra={"connectors": forced})
60 − await asyncio.gather(*(run_connector(n, force=True) for n in forced[:3]))
60 + for n in forced[:3]: # one at a time: concurrent runs touch the same organisation rows and can deadlock Postgres
61 + await run_connector(n, force=True)
61 62 async with transaction() as conn:
62 63 due = await fetch_all(conn, """select name from connectors where enabled and (next_run_at is null or next_run_at <= now())
63 64 and (circuit_open_until is null or circuit_open_until <= now()) order by priority, coalesce(next_run_at, 'epoch') limit 6""")
64 65 names = [r["name"] for r in due if r["name"] in known and r["name"] not in _running and r["name"] not in forced]
65 66 if names:
66 67 log.info("due connectors", extra={"connectors": names})
67 − await asyncio.gather(*(run_connector(n) for n in names[:3]))
68 + for n in names[:2]:
69 + await run_connector(n)
68 70 await cache.heartbeat("scheduler", {"at": datetime.now(UTC).isoformat(), "running": sorted(_running), "due": names, "forced": forced})
69 71
70 72
modified tests/test_leaderboards.py +4 −3
@@ -30,7 +30,7 @@ async def test_swebench():
30 30 benches = {e.identifiers["registry_benchmark"] for e in facts.entities if e.entity_type == "benchmark"}
31 31 assert benches == {"swe-bench-verified", "swe-bench-lite", "swe-bench-full", "swe-bench-multimodal", "swe-bench-multilingual"}
32 32 verified = [r for r in facts.results if r.benchmark.identifiers["registry_benchmark"] == "swe-bench-verified"]
33 − assert len(verified) == 40
33 + assert 35 <= len(verified) <= 40 and not any("&" in r.model.name for r in facts.results) # multi-model systems skipped
34 34 top = next(r for r in verified if r.config["system"] == "Sonar Foundation Agent")
35 35 assert top.model.name == "Claude 4.5 Opus" and top.config["model_tag"] == "claude-opus-4-5" and top.model.organization.name == "Anthropic"
36 36 assert top.score == 79.2 and top.metric == "resolved" and top.config["date"] == "2025-12-05" and top.config["open_source_system"] is False
@@ -70,5 +70,6 @@ async def test_artificial_analysis():
70 70 assert benches["gpqa"] >= 50 and benches["humanitys-last-exam"] >= 50 and benches["terminal-bench"] >= 50
71 71 gpqa = next(r for r in facts.results if r.benchmark.identifiers["registry_benchmark"] == "gpqa")
72 72 assert 0 < gpqa.score <= 100 and gpqa.unit == "%" and gpqa.config["evaluator"] == "Artificial Analysis"
73 − some = next(e for e in facts.entities if e.entity_type == "model" and claims_of(facts, e.name).get("openness"))
74 − assert claims_of(facts, some.name)["openness"] in ("open-weights", "proprietary")
73 + some = next(e for e in facts.entities if e.entity_type == "model" and claims_of(facts, e.name).get("aa_openness"))
74 + assert claims_of(facts, some.name)["aa_openness"] in ("open-weights", "proprietary")
75 + assert not any(c.property in ("openness", "context_length", "status", "release_date") for c in facts.claims) # second-hand facts stay aa_*
75 76