Files
aiturk-hermes-ide/apps/desktop/assets/codex-bridge/test_model_gecis.py
T
yilsemandClaude Opus 5.5 8a612beba7
ci / mobile-link-windows (push) Canceled after 0s
ci / approval-gate-windows (push) Canceled after 0s
feat(codex-bridge): tell the model the chat model can be changed by saying so; a nameless command asks which
Measured in a live voice chat: asked whether it could change the model, Opus answered "I cannot change this
chat's model here". Every request now carries one short developer note, and "modeli değiştir" without a
name is answered by the bridge with how to say it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 01:55:34 +03:00

133 lines
7.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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"<realtime_delegation>\n <input>{text}</input>\n <transcript_delta>user: x</transcript_delta>\n</realtime_delegation>")
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("<skill>x</skill>")]})[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("<transcript_delta>", text)
self.assertIn("cc/opus-5-5 olarak devam ediyorum", text)
self.assertNotIn("modeli opus yap</input>", 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("<transcript_delta>", 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 <ad> 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 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()