feat(codex-link): AITURK work routing setting and beta.40
- Default routing rule (user decision, 15 Oct 2026): repeating/scheduled work goes to the AITURK IDE bot as a cron job; coding stays in Codex (itself or its subagents); 'Codex' or 'sen yap' keeps everything in Codex. - Settings > Codex Bağlama: choice (recommended / send large work / never / custom text) with a text box and restore-default; written to bridge.json aiturk_hat. - Bridge re-reads aiturk_hat when bridge.json changes: no restart. IDE apply keeps aiturk_hat instead of wiping it. - Bridge version 20, IDE 1.0.0-beta.40. Jev untouched.
This commit is contained in:
1 parent
a7ba300448
commit
557e619499
16 files changed
+388
-26
No files matched your search
@@ -35,7 +35,7 @@ import gecis_context
|
||||
import terminal_stream
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
SURUM = "19" # AITURK IDE'nin bekledigi kopru surumu (codex-link-config.ts CODEX_BRIDGE_VERSION)
|
||||
SURUM = "20" # AITURK IDE'nin bekledigi kopru surumu (codex-link-config.ts CODEX_BRIDGE_VERSION)
|
||||
try:
|
||||
with open(os.path.abspath(__file__), "rb") as _f:
|
||||
KOD = hashlib.sha256(_f.read()).hexdigest()[:8]
|
||||
|
||||
@@ -11,7 +11,9 @@ isteklere, istek gecerken ekler. Istemci `originator` basligindan ayirt edilir (
|
||||
Hat, Codex Baglama'nin parcasidir: ayri bir dugmesi yoktur, bu bilgisayarda isi gonderebilen bir AITURK komutu
|
||||
(`aiturk is`) bulundugu surece aciktir. Komut yoksa talimat eklenmez: gonderme yolu olmayan bir "AITURK'e gonder"
|
||||
talimati modeli yaniltir. Ayar (bridge.json, istege bagli): "aiturk_hat": {"enabled": false} kapatir;
|
||||
{"komut": "..."} komutu elle verir; {"talimat": "..."} metni degistirir.
|
||||
{"komut": "..."} komutu elle verir; {"talimat": "..."} metni degistirir ({komut}, {zamanla} yer tutuculari);
|
||||
{"secim": "onerilen"|"buyuk"|"kapali"|"ozel"} AITURK IDE ayarlar ekranindan yazilir. Kopru ayari her istekte
|
||||
dosyadan tazeler (kopru.py hat_ayari), yeniden baslatma gerekmez.
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
@@ -19,7 +21,7 @@ import subprocess
|
||||
|
||||
MASAUSTU = {"codex desktop"}
|
||||
ISARET = "[AITURK iş hattı]"
|
||||
VARSAYILAN = (
|
||||
ESKI = (
|
||||
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"
|
||||
@@ -28,6 +30,31 @@ VARSAYILAN = (
|
||||
"bitmesini bekle ve sonucu kullanıcıya kısaca aktar:\n{komut}\n"
|
||||
"Komut \"işi sen yap\" derse ya da hata verirse işi kendin yap. Emin değilsen işi küçük say ve kendin yap."
|
||||
)
|
||||
# Kullanici karari, 15 Ekim 2026: tekrarli/zamanli isler AITURK IDE botuna, kodlama Codex'te kalir.
|
||||
VARSAYILAN = (
|
||||
ISARET + " Bu Codex, AITURK'e bağlı. İş dağıtımı kuralı:\n"
|
||||
"1. Tekrarlı, zamanlanmış ya da sürekli açık kalacak işleri (her gün şu saatte, saat başı, haftada bir, "
|
||||
"'7 gün her gün baksın' gibi) AITURK IDE'deki bota zamanlanmış iş olarak ver. PowerShell'de tek satır:\n{zamanla}\n"
|
||||
"Belirli süreli işte (ör. 7 gün her gün) --repeat ile tekrar sayısını ver. HERMES_HOME kısmını atlama. "
|
||||
"Aynı satırla 'cron list' çalıştırıp işin kaydını doğrula; kullanıcıya işin adını, zamanlamasını ve ilk çalışma "
|
||||
"zamanını söyle. İşler AITURK IDE açıkken çalışır.\n"
|
||||
"2. Kodlama işlerini AITURK'e verme: kolaysa kendin ya da kendi alt ajanınla yap, zorsa kendi alt ajan ekibine dağıt.\n"
|
||||
"3. Basit soru, bilgi isteği ve küçük düzeltmeleri kendin yap.\n"
|
||||
"4. Kullanıcı 'Codex' ya da 'sen yap' derse hiçbir işi devretme. Komut hata verirse işi kendin yap."
|
||||
)
|
||||
# Ayarlar ekranindaki hazir secenekler (bridge.json "aiturk_hat": {"secim": ...}).
|
||||
SECIMLER = {"onerilen": VARSAYILAN, "buyuk": ESKI}
|
||||
|
||||
|
||||
def zamanla_satiri(ortam=None):
|
||||
"""AITURK IDE botuna zamanlanmis is veren hazir satir; IDE ajan klasoru yoksa ''."""
|
||||
ortam = os.environ if ortam is None else ortam
|
||||
ev = str(ortam.get("HERMES_HOME") or "").strip()
|
||||
if not ev:
|
||||
return ""
|
||||
exe = os.path.join(ev, "bin", "hermes.exe")
|
||||
return (f"$env:HERMES_HOME='{ev}'; & '{exe}' cron create --name '<kısa ad>' --workdir '<işin klasörü>' "
|
||||
"'<zamanlama: 30m, every 2h ya da 0 9 * * *>' '<işin tam ve kendi başına anlaşılır talimatı>'")
|
||||
|
||||
|
||||
def masaustu_mu(originator):
|
||||
@@ -76,16 +103,25 @@ def komut_satiri(yol, sohbet=""):
|
||||
return f'"{yol}" is' + (f" --sohbet {sohbet}" if sohbet else "") + ' --dosya "<iş metnini yazdığın dosya>"'
|
||||
|
||||
|
||||
def talimat(ayar, bulunan=None, sohbet=""):
|
||||
"""Eklenecek metin; hat kapaliysa ya da gonderme komutu yoksa None.
|
||||
bulunan: bu bilgisayarda bulunan AITURK komutunun yolu (komut_bul); ayardaki "komut" onun onune gecer."""
|
||||
def talimat(ayar, bulunan=None, sohbet="", zamanla=None):
|
||||
"""Eklenecek metin; hat kapaliysa ya da metnin istedigi gonderme yolu yoksa None.
|
||||
bulunan: bu bilgisayarda bulunan AITURK komutunun yolu (komut_bul); ayardaki "komut" onun onune gecer.
|
||||
zamanla: AITURK IDE botuna zamanlanmis is veren satir (zamanla_satiri); None ise ortamdan bulunur.
|
||||
Secim (ayarlar ekrani): "onerilen" (varsayilan), "buyuk" (eski davranis), "kapali", "ozel" ("talimat" metni).
|
||||
Secimsiz eski ayarda "talimat" doluysa ozel sayilir."""
|
||||
ayar = ayar if isinstance(ayar, dict) else {}
|
||||
if ayar.get("enabled") is False:
|
||||
secim = str(ayar.get("secim") or "").strip()
|
||||
if ayar.get("enabled") is False or secim == "kapali":
|
||||
return None
|
||||
if secim in SECIMLER:
|
||||
metin = SECIMLER[secim]
|
||||
else:
|
||||
metin = str(ayar.get("talimat") or "").strip() or VARSAYILAN
|
||||
komut = str(ayar.get("komut") or "").strip() or (komut_satiri(bulunan, sohbet) if bulunan else "")
|
||||
if not komut:
|
||||
zamanla = zamanla_satiri() if zamanla is None else zamanla
|
||||
if ("{komut}" in metin and not komut) or ("{zamanla}" in metin and not zamanla):
|
||||
return None
|
||||
return str(ayar.get("talimat") or VARSAYILAN).replace("{komut}", komut)
|
||||
return metin.replace("{komut}", komut).replace("{zamanla}", zamanla)
|
||||
|
||||
|
||||
def ekle(req, metin):
|
||||
|
||||
@@ -42,7 +42,7 @@ from bekci_watch import MetadataFilter
|
||||
# Installed only by owned native launcher, never an HTTP control endpoint.
|
||||
WATCH_OWNER = None
|
||||
|
||||
SURUM = "19"
|
||||
SURUM = "20"
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
try:
|
||||
with open(os.path.abspath(__file__), "rb") as _f:
|
||||
@@ -416,7 +416,7 @@ HAT_KOMUT = [None]
|
||||
def hat_komut_loop():
|
||||
while True:
|
||||
try:
|
||||
if (CFG.get("aiturk_hat") or {}).get("enabled") is not False:
|
||||
if True: # komut her zaman aranir; secim ayarlar ekranindan sonradan acilabilir
|
||||
bulunan = is_hatti.komut_bul()
|
||||
if bulunan != HAT_KOMUT[0]:
|
||||
HAT_KOMUT[0] = bulunan
|
||||
@@ -427,6 +427,21 @@ def hat_komut_loop():
|
||||
|
||||
threading.Thread(target=hat_komut_loop, daemon=True).start()
|
||||
|
||||
_HAT_AYAR = {"mtime": None, "deger": None}
|
||||
|
||||
def hat_ayari():
|
||||
"""bridge.json "aiturk_hat" alani; ayarlar ekranindan yapilan degisiklik yeniden baslatmadan uygulanir."""
|
||||
yol = os.path.join(HOME, "bridge.json")
|
||||
try:
|
||||
mt = os.path.getmtime(yol)
|
||||
if mt != _HAT_AYAR["mtime"]:
|
||||
with open(yol, encoding="utf-8") as f:
|
||||
_HAT_AYAR["deger"] = (json.load(f) or {}).get("aiturk_hat")
|
||||
_HAT_AYAR["mtime"] = mt
|
||||
return _HAT_AYAR["deger"]
|
||||
except Exception:
|
||||
return CFG.get("aiturk_hat")
|
||||
|
||||
LAST_MODELS = {} # hesap kimligi -> son basarili model listesi (chatgpt.com hata verirse bu verilir)
|
||||
CACHE_DIR = os.path.join(LOGDIR, "son-liste")
|
||||
|
||||
@@ -1755,7 +1770,7 @@ class H(http.server.BaseHTTPRequestHandler):
|
||||
if CFG.get("sesle_model", True) and CFG.get("model_bilgi", True) and sohbet and model_gecis.bilgi_ekle(req):
|
||||
govde_degisti = True
|
||||
if is_hatti.masaustu_mu(kaynak) and is_hatti.ekle(
|
||||
req, is_hatti.talimat(CFG.get("aiturk_hat"), HAT_KOMUT[0], sohbet)):
|
||||
req, is_hatti.talimat(hat_ayari(), HAT_KOMUT[0], sohbet)):
|
||||
govde_degisti = True
|
||||
# Ek modelde yerlesik web aramasi yok (flatten_request atar): aramayi kabukla yapan komut soylenir.
|
||||
if internet.ekle(req, internet.talimat(CFG.get("internet"), os.path.join(HERE, "ara.py"))):
|
||||
|
||||
@@ -11,24 +11,39 @@ class Hat(unittest.TestCase):
|
||||
self.assertFalse(h.masaustu_mu(other), other)
|
||||
|
||||
def test_no_instruction_when_switched_off_or_without_a_send_command(self):
|
||||
self.assertIsNone(h.talimat(None))
|
||||
self.assertIsNone(h.talimat({}))
|
||||
self.assertIsNone(h.talimat({"enabled": True, "komut": " "}))
|
||||
self.assertIsNone(h.talimat({"secim": "buyuk"}, zamanla=""))
|
||||
self.assertIsNone(h.talimat({"secim": "buyuk", "komut": " "}, zamanla="z"))
|
||||
self.assertIsNone(h.talimat({"secim": "kapali", "komut": "x"}, "C:/a.exe", zamanla="z"))
|
||||
self.assertIsNone(h.talimat({"enabled": False, "komut": "aiturk gonder"}))
|
||||
self.assertIsNone(h.talimat({"enabled": False}, "C:/a/aiturk.exe", "s1"))
|
||||
text = h.talimat({"enabled": True, "komut": "aiturk gonder --dosya is.md"})
|
||||
text = h.talimat({"secim": "buyuk", "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_on_by_default_once_a_send_command_exists_on_this_computer(self):
|
||||
text = h.talimat(None, "C:/Program/aiturk.exe", "019a-bc_d")
|
||||
text = h.talimat({"secim": "buyuk"}, "C:/Program/aiturk.exe", "019a-bc_d")
|
||||
self.assertIn('"C:/Program/aiturk.exe" is --sohbet 019a-bc_d --dosya', text)
|
||||
self.assertIn('"C:/Program/aiturk.exe" is --dosya', h.talimat({}, "C:/Program/aiturk.exe", ""))
|
||||
self.assertIn('"C:/Program/aiturk.exe" is --dosya', h.talimat({"talimat": h.ESKI}, "C:/Program/aiturk.exe", ""))
|
||||
# Sohbet kimligi komut satirina yazilir: kabuk karakteri tasiyamaz.
|
||||
self.assertIn("--sohbet abrm-rf ", h.komut_satiri("x", 'a"b; rm -rf /'))
|
||||
# Ayardaki komut bulunanin onune gecer.
|
||||
self.assertIn("elle", h.talimat({"komut": "elle"}, "C:/Program/aiturk.exe"))
|
||||
self.assertIn("elle", h.talimat({"secim": "buyuk", "komut": "elle"}, "C:/Program/aiturk.exe"))
|
||||
|
||||
def test_default_sends_scheduled_work_to_the_ide_bot_and_keeps_coding(self):
|
||||
z = h.zamanla_satiri({"HERMES_HOME": "C:/ide/agent"})
|
||||
self.assertIn("cron create", z)
|
||||
self.assertIn("$env:HERMES_HOME='C:/ide/agent'", z)
|
||||
self.assertEqual(h.zamanla_satiri({}), "")
|
||||
for ayar in (None, {}, {"secim": "onerilen"}, {"secim": "bilinmeyen"}):
|
||||
text = h.talimat(ayar, None, zamanla=z)
|
||||
self.assertIn("cron create", text)
|
||||
self.assertIn("Kodlama işlerini AITURK'e verme", text)
|
||||
self.assertIn("'Codex' ya da 'sen yap'", text)
|
||||
self.assertNotIn("{", text)
|
||||
self.assertIsNone(h.talimat(None, "C:/a.exe", zamanla=""))
|
||||
self.assertEqual(h.talimat({"secim": "ozel", "talimat": "kendi kuralim"}, zamanla=""), "kendi kuralim")
|
||||
self.assertIn("cron create", h.talimat({"secim": "ozel", "talimat": " "}, zamanla=z))
|
||||
|
||||
def test_the_first_candidate_that_knows_the_command_is_used(self):
|
||||
import os
|
||||
@@ -58,7 +73,7 @@ class Hat(unittest.TestCase):
|
||||
|
||||
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"})
|
||||
text = h.talimat({"secim": "buyuk", "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))
|
||||
|
||||
Reference in new issue
Block a user