feat(codex-bridge): handoff instruction for Codex Desktop only (off by default)

User decision: the "larger work goes to AITURK" instruction lives only in what Codex IDE sees; the CLI must
not know it exists. The bridge adds it in flight by the originator header (measured: Codex Desktop, codex-tui,
codex_exec) and only when a send command is configured.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
yilsemandClaude Opus 5.5 committed 2026-10-11 01:05:00 +03:00
1 parent d9a7661281
commit 1445e204da
6 files changed
+108 -2

No files matched your search

@@ -45,6 +45,13 @@ for the chat, i.e. until the user picks another one in the list.
Setting: `sesle_model` (default on).
### Work handoff instruction (prepared, off by default)
`is_hatti.py`: when `aiturk_hat` is enabled and has a `komut`, the bridge prepends a developer message ("small work
yourself; larger work goes to AITURK via this command") to requests whose `originator` header is `Codex Desktop`.
The Codex CLI (`codex-tui`, `codex_exec`) never receives it and nothing is written to any file it reads. Each new
`originator` value is logged once (`istemci goruldu`).
## Version 7 (IDE beta.26): external models behave like subscription models
Measured on 10 Oct 2026 with the unmodified Codex binary (`codex exec`, same conversation, model switched per turn).
@@ -28,6 +28,7 @@ import ozet_kopru
import pencere
import yarim
import model_gecis
import is_hatti
SURUM = "8"
HERE = os.path.dirname(os.path.abspath(__file__))
@@ -666,6 +667,7 @@ def decompress(body, enc):
OZET_FRENI = ozet_kopru.DonguFreni()
YONLENDIRME = model_gecis.Yonlendirme(HOME)
GORULEN_ISTEMCI = set() # originator degerleri; her biri gunluge bir kez yazilir
_BILINEN = {"kaynak": None, "liste": []}
def bilinen_modeller():
@@ -1108,6 +1110,16 @@ class H(http.server.BaseHTTPRequestHandler):
# istek sanip is yapmaz, yavas modelde asil soru beklemez. Secilen modelin adiyla aninda donulur.
log(f"[{n} {slug}] nokta mesaji kopruden karsilandi (modele gonderilmedi)")
return self._yerel_yanit(gelen, f"{model_adi(slug)} hazır. Sohbetin modeli artık {model_adi(slug)}.")
# Is hatti talimati yalniz masaustu uygulamasindan gelen istege eklenir; CLI hic gormez (is_hatti.py).
kaynak = self.headers.get("originator") or ""
if kaynak and kaynak not in GORULEN_ISTEMCI:
GORULEN_ISTEMCI.add(kaynak)
log(f"istemci goruldu: {kaynak}")
try:
if is_hatti.masaustu_mu(kaynak) and is_hatti.ekle(req, is_hatti.talimat(CFG.get("aiturk_hat"))):
govde_degisti = True
except Exception as e:
log(f"[{n} {slug}] is hatti talimati atlandi: {type(e).__name__}: {e}")
# Ayni sohbetin onceki cevabi yarida kesildiyse (yarim.py) metni bu istege not olarak eklenir.
yarim_eklenen = 0
if CFG.get("yarim_cevap", True):
@@ -0,0 +1,52 @@
"""Codex IDE'ye "is kucuk degilse AITURK yapacak" talimati (11 Ekim 2026).
Kullanici karari: talimat yalniz Codex IDE'nin (masaustu uygulamasi) gordugu sistem talimatinda durur; Codex CLI
talimati hic gormez, varligindan haberi olmaz. Karari secili model verir; kucuk modellerin yanilmasi kabul edilir,
ayri bir yazilimla onune gecilmez.
Bu yuzden talimat hicbir dosyaya yazilmaz (AGENTS.md'yi CLI da okur): kopru, yalniz masaustu uygulamasindan gelen
isteklere, istek gecerken ekler. Istemci `originator` basligindan ayirt edilir (olcum 11 Ekim 2026: masaustu
"Codex Desktop", etkilesimli CLI "codex-tui", `codex exec` "codex_exec").
Ayar (bridge.json): "aiturk_hat": {"enabled": true, "komut": "<isi AITURK'e gonderen komut>", "talimat": "<istege bagli>"}.
Komut tanimli degilse talimat eklenmez: gonderme yolu olmayan bir "AITURK'e gonder" talimati modeli yaniltir.
"""
MASAUSTU = {"codex desktop"}
ISARET = "[AITURK iş hattı]"
VARSAYILAN = (
ISARET + " Bu Codex, AITURK'e bağlı. Şu kurala göre çalış:\n"
"1. Basit soruyu, bilgi isteğini ya da tek küçük düzeltmeyi kendin yap.\n"
"2. Kullanıcı \"sen yap\" derse işi kendin yap.\n"
"3. İş küçük değilse (birden çok dosya, birkaç adım, yeni özellik, araştırma gerektiren iş) kendin yapma; "
"işi şu komutla AITURK'e gönder, bitmesini bekle ve sonucu kullanıcıya kısaca aktar:\n{komut}\n"
"Emin değilsen işi küçük say ve kendin yap."
)
def masaustu_mu(originator):
return str(originator or "").strip().lower() in MASAUSTU
def talimat(ayar):
"""Eklenecek metin; hat kapaliysa ya da komut yoksa None."""
if not isinstance(ayar, dict) or not ayar.get("enabled"):
return None
komut = str(ayar.get("komut") or "").strip()
if not komut:
return None
return str(ayar.get("talimat") or VARSAYILAN).replace("{komut}", komut)
def ekle(req, metin):
"""Talimati istegin basina developer mesaji olarak koyar. True: eklendi (zaten varsa eklenmez)."""
girdi = req.get("input")
if not metin or not isinstance(girdi, list):
return False
for oge in girdi[:3]:
icerik = oge.get("content") if isinstance(oge, dict) else None
yazi = icerik if isinstance(icerik, str) else " ".join(str(p.get("text") or "") for p in icerik or [] if isinstance(p, dict))
if ISARET in yazi:
return False
girdi.insert(0, {"type": "message", "role": "developer", "content": [{"type": "input_text", "text": metin}]})
return True
@@ -31,7 +31,7 @@ class AccessPrograms(unittest.TestCase):
"fix_tool_ids": lambda req: 0,
"drop_foreign_items": lambda req: 0,
"SseRewriter": Mock(),
"log": lambda message: None, "pencere": __import__("pencere"), "IDE_BILGI": {}, "yarim": __import__("yarim"), "nokta_mesaji_mi": lambda req: False, "EXTRA_MODELS": [],
"log": lambda message: None, "pencere": __import__("pencere"), "IDE_BILGI": {}, "yarim": __import__("yarim"), "is_hatti": __import__("is_hatti"), "GORULEN_ISTEMCI": set(), "nokta_mesaji_mi": lambda req: False, "EXTRA_MODELS": [],
"DEBUG": False, "UA": "test", "RETRIES": 1, "UPSTREAM_IDLE_TIMEOUT": 3900,
}
exec(compile(ast.Module(body=[flatten, claude_sonu, responses], type_ignores=[]), "bridge.py", "exec"), self.env)
@@ -40,7 +40,7 @@ class ComboNotResent(unittest.TestCase):
"fix_tool_ids": lambda req: 0, "drop_foreign_items": lambda req: 0,
"SseRewriter": Mock(), "log": lambda message: None,
"DEBUG": False, "UA": "test", "RETRIES": 6, "UPSTREAM_IDLE_TIMEOUT": 3600,
"NO_RETRY_PATTERNS": [], "pencere": __import__("pencere"), "IDE_BILGI": {}, "yarim": __import__("yarim"), "nokta_mesaji_mi": lambda req: False, "EXTRA_MODELS": [],
"NO_RETRY_PATTERNS": [], "pencere": __import__("pencere"), "IDE_BILGI": {}, "yarim": __import__("yarim"), "is_hatti": __import__("is_hatti"), "GORULEN_ISTEMCI": set(), "nokta_mesaji_mi": lambda req: False, "EXTRA_MODELS": [],
}
exec(compile(ast.Module(body=[pick("flatten_request"), pick("claude_sonu_duzelt"), pick("is_timeout"), responses],
type_ignores=[]), "bridge.py", "exec"), self.env)
@@ -0,0 +1,35 @@
"""The "send larger work to AITURK" instruction reaches only Codex Desktop, and only when a send command exists."""
import unittest
import is_hatti as h
class Hat(unittest.TestCase):
def test_only_the_desktop_app_is_recognised(self):
self.assertTrue(h.masaustu_mu("Codex Desktop"))
for other in ("codex-tui", "codex_exec", "codex_cli_rs", "", None, "Codex Desktop Helper"):
self.assertFalse(h.masaustu_mu(other), other)
def test_no_instruction_without_the_switch_or_without_a_send_command(self):
self.assertIsNone(h.talimat(None))
self.assertIsNone(h.talimat({"enabled": False, "komut": "aiturk gonder"}))
self.assertIsNone(h.talimat({"enabled": True}))
self.assertIsNone(h.talimat({"enabled": True, "komut": " "}))
text = h.talimat({"enabled": True, "komut": "aiturk gonder --dosya is.md"})
self.assertIn("aiturk gonder --dosya is.md", text)
self.assertIn("sen yap", text)
self.assertEqual(h.talimat({"enabled": True, "komut": "x", "talimat": "ozel {komut}"}), "ozel x")
def test_instruction_is_put_first_once_and_never_repeated(self):
req = {"input": [{"type": "message", "role": "user", "content": "selam"}]}
text = h.talimat({"enabled": True, "komut": "aiturk gonder"})
self.assertTrue(h.ekle(req, text))
self.assertEqual((req["input"][0]["role"], len(req["input"])), ("developer", 2))
self.assertFalse(h.ekle(req, text))
self.assertEqual(len(req["input"]), 2)
self.assertFalse(h.ekle({"input": "duz metin"}, text))
self.assertFalse(h.ekle(req, None))
if __name__ == "__main__":
unittest.main()