"""Bridge 8: "modeli X yap" is handled by the bridge; a per-chat route survives until the user picks another model.""" import tempfile import unittest import model_gecis as g MODELS = [("gpt-6-sol", "GPT-6-Sol"), ("gpt-6-astra", "GPT-6-Astra"), ("gpt-6.1-sol", "GPT-6.1-Sol"), ("ide/9router-ag-gemini-3.8-flash-low", "agy/gemini-3.8-flash-low"), ("ide/9router-ag-gemini-3.8-flash-high", "agy/gemini-3.8-flash-high"), ("ide/9router-cc-claude-opus-5-5", "cc/opus-5-5"), ("ide/9router-cc-claude-opus-5-5-nt", "cc/opus-5-5 (no-think)"), ("ide/9router-nano-z-ai-glm-5.3-flash-uncensored", "nano/glm-5.3-flash-uncensored"), ("ide/agnes-agnes-2.0-flash", "agnes/agnes-2.0-flash"), ("ide/agnes-agnes-2.5-flash", "agnes/agnes-2.5-flash")] def user(text): return {"type": "message", "role": "user", "content": [{"type": "input_text", "text": text}]} def voice(text): return user(f"\n {text}\n user: x\n") def pick(text): command = g.komut_coz(text) return g.eslestir(command["ad"], MODELS) if command and command["tur"] == "gec" else command class Komut(unittest.TestCase): def test_spoken_names_resolve_to_one_model(self): for text, slug in [("modeli gemini flash low yap", "ide/9router-ag-gemini-3.8-flash-low"), ("Modeli Gemini 3.8 Flash High'a geçir", "ide/9router-ag-gemini-3.8-flash-high"), ("modeli klod opus 5 5 yap", "ide/9router-cc-claude-opus-5-5"), ("modeli opus 5 5'e geç", "ide/9router-cc-claude-opus-5-5"), ("modeli gpt 6 astra yap", "gpt-6-astra"), ("model geç gpt 6.1 sol", "gpt-6.1-sol"), ("modeli glm flaş sansürsüz yap", "ide/9router-nano-z-ai-glm-5.3-flash-uncensored")]: self.assertEqual((pick(text) or {}).get("slug"), slug, text) def test_ambiguous_name_lists_candidates_and_changes_nothing(self): self.assertEqual(pick("modeli agnes yap"), {"adaylar": ["agnes/agnes-2.0-flash", "agnes/agnes-2.5-flash"]}) self.assertIn("adaylar", pick("modeli klod opus yap")) # two Opus entries: ask self.assertIn("adaylar", pick("modeli sol yap")) # GPT-6-Sol or GPT-6.1-Sol: ask self.assertIn("adaylar", pick("modeli gpt 999 astra yap")) # words fit, version does not: ask def test_negations_and_general_questions_are_not_commands(self): for text in ("modeli gemini flash low yapma", "modeli değiştirme opus kalsın", "GPT 6 Astra modeli için test yap", "hangi model daha ucuz", "en iyi model hangisi", "modeli seçili dosyaya göre gemini flash low yap"): result = pick(text) self.assertFalse(result and ("slug" in result or result.get("tur") == "sor"), text) self.assertEqual(g.komut_coz("hangi modelsin"), {"tur": "sor"}) def test_ordinary_sentences_are_not_commands(self): for text in ("Masaüstünde kaç klasör var", "bu modeli kullanarak bir site yap", "yapay zeka modeli nedir", "hangi modeli önerirsin bu iş için bana söyle bakalım lütfen", "model " + "çok uzun bir cümle " * 5 + "yap"): self.assertFalse(pick(text) and "slug" in pick(text), text) self.assertEqual(g.komut_coz("seçili model hangisi"), {"tur": "sor"}) self.assertEqual(g.komut_coz("bu chatte ana model kim"), {"tur": "sor"}) def test_voice_delegation_yields_only_the_spoken_input(self): text, index, spoken = g.son_kullanici_metni({"input": [user("a"), voice("modeli opus yap")]}) self.assertEqual((text, index, spoken), ("modeli opus yap", 1, True)) self.assertEqual(g.son_kullanici_metni({"input": [user("x")]})[0], None) self.assertEqual(g.son_kullanici_metni({"input": [{"type": "function_call_output", "output": "x"}]})[0], None) class TurOrtasi(unittest.TestCase): def test_message_after_tool_items_is_mid_turn_and_after_final_answer_is_not(self): final = {"type": "message", "role": "assistant", "phase": "final_answer", "content": "ok"} call = {"type": "function_call", "call_id": "c", "name": "shell", "arguments": "{}"} out = {"type": "function_call_output", "call_id": "c", "output": "x"} self.assertFalse(g.tur_ortasi({"input": [user("a"), final, user(".")]}, 2)) self.assertTrue(g.tur_ortasi({"input": [user("a"), call, out, user(".")]}, 3)) self.assertTrue(g.tur_ortasi({"input": [user("a"), call, out, voice("bekliyorum"), user(".")]}, 4)) self.assertTrue(g.tur_ortasi({"input": [user("a"), {"type": "message", "role": "assistant", "phase": "commentary", "content": "bakıyorum"}, user(".")]}, 2)) self.assertFalse(g.tur_ortasi({"input": [user(".")]}, 0)) def test_handover_note_replaces_only_the_spoken_input(self): req = {"input": [voice("modeli opus yap")]} g.metni_degistir(req, 0, g.devir_notu("cc/opus-5-5", "GPT-6-Sol")) text = req["input"][0]["content"][0]["text"] self.assertIn("", text) self.assertIn("cc/opus-5-5 olarak devam ediyorum", text) self.assertNotIn("modeli opus yap", text) class Gecmis(unittest.TestCase): def test_handled_commands_in_history_become_notes_but_the_last_message_is_left_alone(self): req = {"input": [user("modeli gemini flash low yap"), user("Masaüstünde kaç dosya var"), voice("modeli opus 5 5 yap"), user("modeli gpt 6 astra yap")]} self.assertEqual(g.gecmisi_temizle(req, MODELS), 2) self.assertIn("agy/gemini-3.8-flash-low olarak değiştirdi", req["input"][0]["content"][0]["text"]) self.assertEqual(req["input"][1]["content"][0]["text"], "Masaüstünde kaç dosya var") self.assertIn("", req["input"][2]["content"][0]["text"]) self.assertEqual(req["input"][3]["content"][0]["text"], "modeli gpt 6 astra yap") self.assertEqual(g.gecmisi_temizle(req, MODELS), 0) class Bilgi(unittest.TestCase): def test_model_is_told_once_that_the_chat_model_changes_by_saying_so(self): req = {"input": [user("selam")]} self.assertTrue(g.bilgi_ekle(req)) self.assertEqual(req["input"][0]["role"], "developer") self.assertIn("modeli yap", req["input"][0]["content"][0]["text"]) self.assertFalse(g.bilgi_ekle(req)) self.assertEqual(len(req["input"]), 2) self.assertFalse(g.bilgi_ekle({"input": []})) def test_a_command_without_a_name_asks_which_model(self): for text in ("modeli değiştir", "başka modele geç", "modeli değiştirir misin"): self.assertEqual(g.komut_coz(text), {"tur": "nasil"}, text) self.assertIsNone(g.komut_coz("modeli değiştirme")) class Dogal(unittest.TestCase): GECIT = [("ide/9router/ModelARK/dola-seed-2-1-turbo-260628", "9router/ModelARK/dola-seed-2-1-turbo-260628"), ("ide/9router/ModelARK/seed-2-0-pro-260328", "9router/ModelARK/seed-2-0-pro-260328")] def test_command_without_the_word_model_and_a_spelled_out_name(self): for text in ("Seed iki nokta bir turbo yap", "Evet. Seed, S E E D iki nokta bir turbo yap"): command = g.komut_coz(text) self.assertEqual((command["ad"], command["kesin"]), (["seed", "2", "1", "turbo"], False), text) self.assertEqual(g.eslestir(command["ad"], self.GECIT)["slug"], "ide/9router/ModelARK/dola-seed-2-1-turbo-260628") self.assertTrue(g.komut_coz("Modeli Seed iki nokta bir turbo yap")["kesin"]) self.assertEqual(g.eslestir(g.komut_coz("gemini flash low'a geç")["ad"], MODELS)["slug"], "ide/9router-ag-gemini-3.8-flash-low") def test_ordinary_requests_ending_in_a_verb_are_not_commands(self): for text in ("test yap", "kahve yap", "yapma"): self.assertIsNone(g.komut_coz(text), text) for text in ("şu dosyayı düzelt ve commit yap", "rapor hazırla gemini flash low ile karşılaştırma yap"): command = g.komut_coz(text) self.assertFalse(command["kesin"]) self.assertFalse((g.eslestir(command["ad"], MODELS) or {}).get("slug"), text) class Yon(unittest.TestCase): def test_route_lasts_until_the_user_picks_another_model_in_the_list(self): with tempfile.TemporaryDirectory() as home: y = g.Yonlendirme(home) y.koy("chat", "gpt-6-sol", "ide/x", simdi=1000) self.assertEqual(g.Yonlendirme(home).al("chat", "gpt-6-sol", simdi=1001), "ide/x") # survives a restart self.assertIsNone(y.al("other", "gpt-6-sol", simdi=1001)) self.assertIsNone(y.al("chat", "gpt-6-astra", simdi=1002)) # user picked another self.assertIsNone(y.al("chat", "gpt-6-sol", simdi=1003)) # and it stays cleared y.koy("chat", "gpt-6-sol", "ide/x", simdi=1000) y.koy("chat", "gpt-6-sol", "gpt-6-sol", simdi=1001) # back to the picked one self.assertIsNone(y.al("chat", "gpt-6-sol", simdi=1002)) y.koy("old", "a", "b", simdi=1000) self.assertIsNone(y.al("old", "a", simdi=1000 + g.OMUR_SN + 1)) if __name__ == "__main__": unittest.main()