SilverElixir commited on
Commit
ed78515
·
1 Parent(s): 7dfd59d

Exclude dead nex-mini from free route, redact org IDs

Browse files
lumen_router_config.py CHANGED
@@ -219,6 +219,10 @@ _OR_MODEL_HEALTH: dict[str, _ModelHealthNote] = {
219
  "thinkingmachines/inkling-small:free": _ModelHealthNote(
220
  reason="Логи прода 17.09.2026: 'only available on agentic harnesses' — не обслуживает обычные chat-запросы; стояла второй в лёгкой цепочке."
221
  ),
 
 
 
 
222
  }
223
 
224
  # Вычисляется из _OR_MODEL_HEALTH — роутер не должен выбирать эти модели.
@@ -362,11 +366,10 @@ def _groq_route(models: list[str]) -> list[tuple[str, str]]:
362
 
363
 
364
  # ── "Лёгкие" запросы — самый частый маршрут, целиком OpenRouter.
365
- # Порядок по аудитам 22.08/17.09.2026; nex-mini повышен продом 17.09.2026.
366
- # НАБЛЮДЕНИЕ 17.09.2026: один ответ nex-mini с вкраплениями чужих языков — при повторе понижать.
367
  _OR_LIGHT_ORDER: list[str] = [
368
  "nvidia/nemotron-3.5-lightning:free",
369
- "nex-agi/nex-n2.5-mini:free",
370
  "inclusionai/ling-3.0-flash-sante:free",
371
  "inclusionai/ling-3.0-flash-fin:free",
372
  "liquid/lfm-2.5-2.6b:free",
 
219
  "thinkingmachines/inkling-small:free": _ModelHealthNote(
220
  reason="Логи прода 17.09.2026: 'only available on agentic harnesses' — не обслуживает обычные chat-запросы; стояла второй в лёгкой цепочке."
221
  ),
222
+ # ── Логи прода 05.10.2026 ──
223
+ "nex-agi/nex-n2.5-mini:free": _ModelHealthNote(
224
+ reason="Логи прода 05.10.2026: 'This model is unavailable for free. The paid version is available now' — стояла второй в лёгкой цепочке."
225
+ ),
226
  }
227
 
228
  # Вычисляется из _OR_MODEL_HEALTH — роутер не должен выбирать эти модели.
 
366
 
367
 
368
  # ── "Лёгкие" запросы — самый частый маршрут, целиком OpenRouter.
369
+ # Порядок по аудитам 22.08/17.09.2026; nex-mini повышен продом 17.09.2026, снят
370
+ # 05.10.2026 (платная отсечка — см. _OR_MODEL_HEALTH): второй стала sante.
371
  _OR_LIGHT_ORDER: list[str] = [
372
  "nvidia/nemotron-3.5-lightning:free",
 
373
  "inclusionai/ling-3.0-flash-sante:free",
374
  "inclusionai/ling-3.0-flash-fin:free",
375
  "liquid/lfm-2.5-2.6b:free",
lumen_routes.py CHANGED
@@ -9,6 +9,7 @@ import asyncio
9
  import base64
10
  import json
11
  import logging
 
12
  import time
13
  from collections import deque
14
  from datetime import date, datetime
@@ -368,6 +369,8 @@ _SELFTEST_PING_TEXT = "Reply with exactly: ok"
368
  def _selftest_short_error(exc: BaseException) -> str:
369
  """Короткий однострочник для строки /selftest (только личка — ID моделей тут допустимы)."""
370
  text = f"{exc.__class__.__name__}: {exc}".strip()
 
 
371
  return " ".join(text.split())[:120] or exc.__class__.__name__
372
 
373
  async def selftest_llm_head(provider: str, *, chat_id: Any = None) -> tuple[bool, str, float]:
 
9
  import base64
10
  import json
11
  import logging
12
+ import re
13
  import time
14
  from collections import deque
15
  from datetime import date, datetime
 
369
  def _selftest_short_error(exc: BaseException) -> str:
370
  """Короткий однострочник для строки /selftest (только личка — ID моделей тут допустимы)."""
371
  text = f"{exc.__class__.__name__}: {exc}".strip()
372
+ # ID организации провайдера — внутрянка даже для владельца: затираем, как токены.
373
+ text = re.sub(r"org_[A-Za-z0-9]+", "<ORG>", text)
374
  return " ".join(text.split())[:120] or exc.__class__.__name__
375
 
376
  async def selftest_llm_head(provider: str, *, chat_id: Any = None) -> tuple[bool, str, float]:
tests/test_bot_commands.py CHANGED
@@ -1352,6 +1352,15 @@ def test_cmd_selftest_cooldown_blocks_second_run(monkeypatch):
1352
  assert fake_tg_call.text == bot._t(999703, "selftest_cooldown", sec=60)
1353
 
1354
 
 
 
 
 
 
 
 
 
 
1355
  def test_cmd_selftest_default_skips_gemini_and_hides_model_ids(monkeypatch):
1356
  # Дефолт без gemini бережёт самую дефицитную квоту; ID моделей в ответе нет.
1357
  from lumen_router_config import _GROQ_LIGHT_ORDER, _OR_LIGHT_ORDER, GEMINI_DEFAULT_CHAIN
 
1352
  assert fake_tg_call.text == bot._t(999703, "selftest_cooldown", sec=60)
1353
 
1354
 
1355
+ def test_selftest_short_error_redacts_org_id():
1356
+ # Прод 05.10.2026: текст Groq-ошибки тащил ID организации — внутрянка даже в личке.
1357
+ import lumen_routes
1358
+ err = lumen_routes._selftest_short_error(RuntimeError(
1359
+ "Request too large for model `qwen/qwen3.8-27b` in organization `org_01m321tq18eqksff96hz17m7es` service tier"))
1360
+ assert "org_01m321tq18eqksff96hz17m7es" not in err
1361
+ assert "<ORG>" in err
1362
+
1363
+
1364
  def test_cmd_selftest_default_skips_gemini_and_hides_model_ids(monkeypatch):
1365
  # Дефолт без gemini бережёт самую дефицитную квоту; ID моделей в ответе нет.
1366
  from lumen_router_config import _GROQ_LIGHT_ORDER, _OR_LIGHT_ORDER, GEMINI_DEFAULT_CHAIN
tests/test_lumen_router_config.py CHANGED
@@ -591,7 +591,6 @@ def test_sept_2026_new_light_models_after_proven_head_before_reserve():
591
  assert order[0] == "nvidia/nemotron-3.5-lightning:free"
592
  assert order[-1] == "openrouter/free"
593
  for model_id in (
594
- "nex-agi/nex-n2.5-mini:free",
595
  "inclusionai/ling-3.0-flash-sante:free", "inclusionai/ling-3.0-flash-fin:free",
596
  "liquid/lfm-2.5-2.6b:free",
597
  ):
@@ -606,8 +605,18 @@ def test_inkling_small_excluded_after_agentic_harness_refusal():
606
  assert "thinkingmachines/inkling-small:free" in lumen_router_config._OR_MODEL_HEALTH
607
  assert "thinkingmachines/inkling-small:free" in lumen_router_config._ROUTER_EXCLUDED_OR_MODELS
608
  assert "thinkingmachines/inkling-small:free" not in lumen_router_config._OR_LIGHT_ORDER
609
- # nex-mini тем же вечером подтверждён живьём — занял его место вторым.
610
- assert lumen_router_config._OR_LIGHT_ORDER[1] == "nex-agi/nex-n2.5-mini:free"
 
 
 
 
 
 
 
 
 
 
611
 
612
 
613
  def test_nemotron_super_demoted_below_ultra_after_second_mush_incident():
 
591
  assert order[0] == "nvidia/nemotron-3.5-lightning:free"
592
  assert order[-1] == "openrouter/free"
593
  for model_id in (
 
594
  "inclusionai/ling-3.0-flash-sante:free", "inclusionai/ling-3.0-flash-fin:free",
595
  "liquid/lfm-2.5-2.6b:free",
596
  ):
 
605
  assert "thinkingmachines/inkling-small:free" in lumen_router_config._OR_MODEL_HEALTH
606
  assert "thinkingmachines/inkling-small:free" in lumen_router_config._ROUTER_EXCLUDED_OR_MODELS
607
  assert "thinkingmachines/inkling-small:free" not in lumen_router_config._OR_LIGHT_ORDER
608
+ # nex-mini снят 05.10.2026 (платная отсечка) — второй стала sante.
609
+ assert lumen_router_config._OR_LIGHT_ORDER[1] == "inclusionai/ling-3.0-flash-sante:free"
610
+
611
+
612
+ def test_nex_mini_excluded_after_paid_tier_cutover():
613
+ # Прод 05.10.2026: та же платная отсечка, что у ling-3.0-flash (тест выше).
614
+ assert "nex-agi/nex-n2.5-mini:free" in lumen_router_config._OR_MODEL_HEALTH
615
+ assert "nex-agi/nex-n2.5-mini:free" in lumen_router_config._ROUTER_EXCLUDED_OR_MODELS
616
+ assert "nex-agi/nex-n2.5-mini:free" not in lumen_router_config._OR_LIGHT_ORDER
617
+ assert "nex-agi/nex-n2.5-mini:free" in lumen_router_config._KNOWN_MODEL_IDS_FOR_LEAK_DETECTION
618
+ route = lumen_router_config._or_route(["nex-agi/nex-n2.5-mini:free", "nvidia/nemotron-3.5-lightning:free"])
619
+ assert [m for _, m in route] == ["nvidia/nemotron-3.5-lightning:free"]
620
 
621
 
622
  def test_nemotron_super_demoted_below_ultra_after_second_mush_incident():