diff --git a/apps/desktop/assets/codex-bridge/bridge.py b/apps/desktop/assets/codex-bridge/bridge.py index 81e4ab9..49e2efb 100644 --- a/apps/desktop/assets/codex-bridge/bridge.py +++ b/apps/desktop/assets/codex-bridge/bridge.py @@ -185,7 +185,8 @@ def load_ide_catalog(): levels = (CFG.get("nine_router_catalog") or {}).get("reasoning_levels") # Gorunen adlari ayirt et; farkli kimlikteki modeller adlari benziyor diye silinmez. var_olan = {m.get("display_name", "").lower() for m in extra_models} - adlar = ide_catalog.adlandir([(g["id"], g["ad"]) for g in girdiler], dolu=var_olan) + adlar = ide_catalog.adlandir([(g["id"], g["ad"]) for g in girdiler], dolu=var_olan, + turler={g["id"]: g["kind"] for g in girdiler}) for g in girdiler: slug = IDE_PREFIX + g["id"] if slug in model_map: diff --git a/apps/desktop/assets/codex-bridge/ide_catalog.py b/apps/desktop/assets/codex-bridge/ide_catalog.py index 614f26e..81d7162 100644 --- a/apps/desktop/assets/codex-bridge/ide_catalog.py +++ b/apps/desktop/assets/codex-bridge/ide_catalog.py @@ -84,34 +84,61 @@ def ide_yapilandirma(agent=AGENT): return base.rstrip("/"), varsayilan, adlar -DOKUZ_ISARET = "9R · " AITURK_EKI = " (AITURK)" - - -def _isaret(ad): - """Gecidin dogrudan 9Router'dan gelen tekil modele koydugu kisa isaret korunur (kullanici karari, - 9 Ekim 2026: "9Router" yazisi uzun, hic yazmamak da sorun; "9R" olarak kisa gorunsun).""" - return DOKUZ_ISARET if (ad or "").startswith(DOKUZ_ISARET) else "" +# Gecidin kisa saglayici kodu -> kullanicinin gormek istedigi kod (10 Ekim 2026: "agy/gemini"). +_SAGLAYICI_KISA = {"ag": "agy"} +# Saglayici kodu zaten soyledigi icin model adinin basinda tekrar edilmeyen uretici adi ("cc/opus-5-5"). +_TEKRAR = ("claude-",) +DUSUNMESIZ = "no-think-" def kisa_ad(ad): - """Codex secicisinde gorunecek ad: yalniz kullanicinin ekledigi saglayici + model adi - (kullanici istegi, 9 Ekim 2026). "OmniRoute · " / "9Router · " gibi gecit onekleri ve aradaki - saglayici halkalari gosterilmez: "nano/qwen/qwen3.8-27b" -> "nano/qwen3.8-27b", - "OmniRoute · ag/gemini-3.8-flash" -> "ag/gemini-3.8-flash", combo adi oldugu gibi kalir.""" - on = _isaret(ad) + """Gecit onekleri ("OmniRoute · ", "9Router · ", "9R · ") ve aradaki saglayici halkalari atilir: + "nano/qwen/qwen3.8-27b" -> "nano/qwen3.8-27b", "9R · ag/gemini-3.8-flash" -> "ag/gemini-3.8-flash", + combo adi oldugu gibi kalir. Kullanici karari (10 Ekim 2026): "9R" yazilmaz.""" ad = (ad or "").split(" · ")[-1].strip() parcalar = [p for p in ad.split("/") if p] if len(parcalar) <= 2: - return on + ("/".join(parcalar) or ad) - return on + parcalar[0] + "/" + parcalar[-1] + return "/".join(parcalar) or ad + return parcalar[0] + "/" + parcalar[-1] -def adlandir(girdiler, dolu=()): +def gorunen_ad(kimlik, ad, tur="model"): + """Secicide gorunen ad (kullanici karari, 10 Ekim 2026): combo yalniz kendi adiyla; tek model + "saglayici/model" kalibinda, kisa ve surumlu: "9R · cc/claude-opus-5-5" -> "cc/opus-5-5", + "9R · ag/gemini-3.8-flash-high" -> "agy/gemini-3.8-flash-high", "Agnes 2.0 Flash" (agnes-agnes-2.0-flash) + -> "agnes/agnes-2.0-flash", "kurnaz" (bekci-kurnaz) -> "bekci/kurnaz". Dusunmesiz kopya asil + saglayicisiyla gorunur: "no-think/claude-opus-5-5" -> "cc/opus-5-5 (no-think)".""" + yalin = kisa_ad(ad) + if tur == "combo": + return yalin + kim, ek = kimlik or "", "" + if kim.startswith(DUSUNMESIZ): + kim, ek = kim[len(DUSUNMESIZ):], " (no-think)" + if kim.startswith("9router-"): + kim = kim[len("9router-"):] + saglayici, _, model = yalin.partition("/") + if not model or ek: + kod, _, kalan = kim.partition("-") + if not kod or not kalan: + return yalin + saglayici, model = kod, model or kalan + model = model.replace(" ", "-") + for tekrar in _TEKRAR: + if model.lower().startswith(tekrar) and len(model) > len(tekrar): + model = model[len(tekrar):] + return f"{_SAGLAYICI_KISA.get(saglayici.lower(), saglayici)}/{model}{ek}" + + +def adlandir(girdiler, dolu=(), turler=None): """[(kimlik, tam_ad)] -> {kimlik: gorunen_ad}. Kisa adlar cakisirsa aradaki halkalar geri konur; - yine cakisirsa kimligin sonu eklenir. `dolu`: baska kaynaktan gelen, zaten kullanilan adlar.""" - kisa = {k: kisa_ad(a) for k, a in girdiler} - tam = {k: _isaret(a) + (a or "").split(" · ")[-1].strip() for k, a in girdiler} + yine cakisirsa kimligin sonu eklenir. `dolu`: baska kaynaktan gelen, zaten kullanilan adlar. + `turler` ({kimlik: "combo"|"model"}) verilirse adlar gorunen_ad kuraliyla yazilir.""" + if turler is None: + kisa = {k: kisa_ad(a) for k, a in girdiler} + else: + kisa = {k: gorunen_ad(k, a, turler.get(k, "model")) for k, a in girdiler} + tam = {k: (a or "").split(" · ")[-1].strip() for k, a in girdiler} sayac = {} for v in list(kisa.values()) + list(dolu): sayac[v.lower()] = sayac.get(v.lower(), 0) + 1 @@ -175,8 +202,6 @@ def sirala_codex(modeller, ekler): slug = m.get("slug", "") bilgi = bilgiler.get(slug, {}) ad = kisa_ad(m.get("display_name") or slug) - if ad.startswith(DOKUZ_ISARET): - ad = ad[len(DOKUZ_ISARET):] if bilgi.get("kind") == "combo": return (0, ad.casefold(), "", slug) if slug.startswith("ide/"): @@ -208,7 +233,7 @@ ACIKLAMA_SINIRI = 30 _AILE = (("opus", "opus"), ("sonnet", "sonnet"), ("haiku", "haiku"), ("astra", "astra"), ("terra", "terra"), ("luna", "luna"), ("sol", "sol"), ("gemini", "gemini"), ("qwen", "qwen"), ("glm", "glm"), ("abliterated", "abliterated"), ("deepseek", "deepseek"), ("llama", "llama"), ("gemma", "gemma")) -_SAGLAYICI = {"cc": "Claude", "cx": "Codex", "ag": "Antigravity", "nano": "NanoGPT", "hf": "HuggingFace", +_SAGLAYICI = {"cc": "Claude", "cx": "Codex", "ag": "Antigravity", "agy": "Antigravity", "nano": "NanoGPT", "hf": "HuggingFace", "huggingface": "HuggingFace", "agnes": "Agnes", "bekci": "Bekçi"} _SANSURSUZ = re.compile(r"uncensored|abliterat|obliterat|derestrict|heretic|unshackled", re.I) @@ -264,9 +289,7 @@ def aciklama(kimlik, ad, tur, kayit=None): if uyeler: return _sigdir("Sıralı: ", _yapraklar(topoloji), ">") return "Takım" - kisa = kisa_ad(ad) - if kisa.startswith(DOKUZ_ISARET): - kisa = kisa[len(DOKUZ_ISARET):] + kisa = gorunen_ad(kimlik, ad, "model") kod = kisa.split("/")[0].lower() if "/" in kisa else (kimlik or "").split("-")[0].lower() parcalar = [_SAGLAYICI.get(kod, kod) or "Tek model"] if _SANSURSUZ.search(kisa) or _SANSURSUZ.search(kimlik or ""): diff --git a/apps/desktop/assets/codex-bridge/test_ide_catalog.py b/apps/desktop/assets/codex-bridge/test_ide_catalog.py index 0470fa7..2c16bab 100644 --- a/apps/desktop/assets/codex-bridge/test_ide_catalog.py +++ b/apps/desktop/assets/codex-bridge/test_ide_catalog.py @@ -84,7 +84,7 @@ class Secim(unittest.TestCase): ("nano/qwen/qwen3.8-27b-obliterated:thinking", "nano/qwen3.8-27b-obliterated:thinking"), ("9Router · Nous-Research/inclusionai/ling-3.1-flash", "Nous-Research/ling-3.1-flash"), ("cf/@cf/qwen/qwq-32b", "cf/qwq-32b"), - ("9R · nano/qwen/qwen3.8-27b", "9R · nano/qwen3.8-27b"), ("9R · ag/gemini", "9R · ag/gemini"), + ("9R · nano/qwen/qwen3.8-27b", "nano/qwen3.8-27b"), ("9R · ag/gemini", "ag/gemini"), ("OmniRoute · Ajan-Arac", "Ajan-Arac"), ("cc/claude-opus-5-5", "cc/claude-opus-5-5")]: self.assertEqual(c.kisa_ad(tam), beklenen, tam) diff --git a/apps/desktop/assets/codex-bridge/test_member_catalog.py b/apps/desktop/assets/codex-bridge/test_member_catalog.py index b53b397..9c5d649 100644 --- a/apps/desktop/assets/codex-bridge/test_member_catalog.py +++ b/apps/desktop/assets/codex-bridge/test_member_catalog.py @@ -109,5 +109,33 @@ class MemberCatalog(unittest.TestCase): for ad in ("Takim-Hizli", "9R · cc/claude-opus-5-5"): self.assertNotIn(ad, c.aciklama(ad, ad, "combo" if "Takim" in ad else "model", takim)) + def test_picker_names_are_combo_name_or_short_provider_slash_model(self): + # User decision, 10 Oct 2026: no "9R" mark; combos by name; single models as provider/model. + rows = [("Takim-Hizli", "Takim-Hizli", "combo"), + ("9router-cc-claude-opus-5-5", "9R · cc/claude-opus-5-5", "model"), + ("9router-cc-claude-opus-4-8", "9R · cc/claude-opus-4-8", "model"), + ("9router-cx-gpt-6-astra", "9R · cx/gpt-6-astra", "model"), + ("9router-ag-gemini-3.8-flash-high", "9R · ag/gemini-3.8-flash-high", "model"), + ("9router-nano-z-ai-glm-5.3-flash-uncensored", "9R · nano/glm-5.3-flash-uncensored", "model"), + ("agnes-agnes-2.0-flash", "Agnes 2.0 Flash", "model"), + ("agnes-agnes-2.0-flash-high", "agnes-2.0-flash-high", "model"), + ("bekci-bekci", "bekci", "model"), ("bekci-kurnaz", "kurnaz", "model"), + ("hf-deepseek-ai-DeepSeek-V3", "hf/DeepSeek V3", "model"), + ("no-think-9router-cc-claude-opus-5-5", "no-think/claude-opus-5-5", "model"), + ("no-think-9router-ag-claude-opus-4-6-thinking", "no-think/claude-opus-4-6-thinking", "model")] + adlar = c.adlandir([(k, a) for k, a, _ in rows], turler={k: t for k, _, t in rows}) + self.assertEqual([adlar[k] for k, _, _ in rows], + ["Takim-Hizli", "cc/opus-5-5", "cc/opus-4-8", "cx/gpt-6-astra", "agy/gemini-3.8-flash-high", + "nano/glm-5.3-flash-uncensored", "agnes/agnes-2.0-flash", "agnes/agnes-2.0-flash-high", + "bekci/bekci", "bekci/kurnaz", "hf/DeepSeek-V3", "cc/opus-5-5 (no-think)", + "agy/opus-4-6-thinking (no-think)"]) + self.assertFalse([a for a in adlar.values() if "9R" in a]) + # Added models sort after the combos by provider then model. + models = [{"slug": "ide/" + k, "display_name": adlar[k], "priority": 0} for k, _, _ in rows] + c.sirala_codex(models, [{"slug": "ide/" + k, "kind": t} for k, _, t in rows]) + gorunen = [m["display_name"] for m in models] + self.assertEqual(gorunen[0], "Takim-Hizli") + self.assertEqual(gorunen[1:], sorted(gorunen[1:], key=lambda a: tuple(p.casefold() for p in a.partition("/")[::2]))) + if __name__ == "__main__": unittest.main()