feat(codex-bridge): decision-model stages, Dify rules and beta.39
Owner request, 14 October 2026: use the decision model (Jev / Celeris) at several stages, let Dify supply the rules, code it without new bugs. Every new stage is switched on in Settings > Kademeli Gecis and starts disabled, so the upgrade changes no behaviour by itself. - Settings schema 2 (Python and TypeScript validate the same rules); a schema 1 file is filled from the defaults. Default chain is now Katman-1 -> Katman-2 -> Katman-3 with Katman-3, Chat-Model and bekci-sesli-bekci always passing (owner decision of the same day). - watchModels: the Bekci correction channel follows a settings list instead of the hard-coded Sesli-Hizli-Zeki. - prefilter: a predicted refusal starts the step at the chosen layer. - autoRoute: virtual "Otomatik" model; one decision per user turn picks the combo, tool steps of the same turn keep it. - finishCheck: an answer that stops early goes back to the same model once. - A layer whose window cannot hold the request is skipped. - policy: stage rules from a Dify workflow (karar_politikasi.py), fetched in the background, validated, last good copy kept; turns never wait. - karar_sor.py: verifierCheck for the dynamic-workflow acceptance step. - Bridge version 19, IDE 1.0.0-beta.39. Tests: 299 bridge tests, 36 electron tests; live run on a side bridge (port 8797) with Celeris and the AITURK gateway for every stage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8f53b090f7
commit
7c4ef18df0
18 files changed
+1672
-119
No files matched your search
@@ -4,11 +4,16 @@ Kullanici karari (11 Ekim 2026): "Jev kati olsun. Af yok istisna yok. Herhangi b
|
||||
gecirmezse 1.Katmana yonlendirecek. 1.Katman combosu gecmezse 2.Katmana, 2.Katman gecmezse 3.Katmana, 3.Katman
|
||||
gecmezse 4.Katmana. 4.Katman combosu gelirse Jev bunu sorgulamadan gecirecek."
|
||||
|
||||
12 Ekim 2026 istisnasi: çözülmüş hedefi tam Sesli-Hizli-Zeki olan cevap Jev'e sorulmaz.
|
||||
12 Ekim 2026 istisnasi: çözülmüş hedefi muaf listesinde olan cevap Jev'e sorulmaz (ayar: exemptModels).
|
||||
Taşıma/boş yanıt kurtarması ve yedek katmanların denetimi korunur.
|
||||
Diğer hedeflerde denetim secili modelin katman olup olmamasina bakmaz.
|
||||
Gecmezse adimi sirayla Katman-1 -> Katman-2 -> Katman-3 -> Katman-4 yapar; secili model zaten bir katmansa
|
||||
yalniz ondan sonrakiler denenir. Katmanlar OmniRoute combolaridir (KATMAN); kopru onlari yalniz adiyla cagirir.
|
||||
Gecmezse adimi ayardaki zincir yapar (14 Ekim 2026: Katman-1 -> Katman-2 -> Katman-3, Katman-3 muaf); secili model
|
||||
zaten bir katmansa yalniz ondan sonrakiler denenir. Katmanlar OmniRoute combolaridir; kopru onlari yalniz adiyla cagirir.
|
||||
|
||||
14 Ekim 2026 karar asamalari (hepsi ayardan acilir, varsayilan kapali): tur basinda "Otomatik" modelin combo secimi
|
||||
(autoRoute), normal modelin reddedecegi tahmin edilen isi dogrudan katmana verme (prefilter), isi bitirmeden "bitti"
|
||||
diyen son cevabi ayni modele bir kez geri verme (finishCheck). Karar modeli metin yazmaz; hata ya da zaman asiminda
|
||||
bugunku yol izlenir.
|
||||
|
||||
Jev (TypeSafe System One) metin uretmez, sorulan evet/hayir sorularina olasilik verir. Kural tektir ve istisnasi
|
||||
yoktur: cevap istegi yapmiyorsa (ret) ya da sormadan kendi sartlariyla degistiriyorsa (sart) adim gecmez.
|
||||
@@ -22,7 +27,7 @@ import jev_settings
|
||||
|
||||
ADRES = "https://api.typesafe.ai/v1/systemone"
|
||||
MODEL = "jev-1.13.0"
|
||||
KATMAN = ("Katman-1", "Katman-2", "Katman-3", "Katman-4")
|
||||
KATMAN = ("Katman-1", "Katman-2", "Katman-3") # varsayilan zincir; asil zincir ayardan okunur
|
||||
ESIK = {"ret": 0.5, "sart": 0.7}
|
||||
SORU = {
|
||||
"ret": ("The assistant did NOT do what the user asked or did NOT answer the user's question: it refused, declined, "
|
||||
@@ -32,6 +37,14 @@ SORU = {
|
||||
}
|
||||
_ANAHTAR = {"okundu": False, "deger": ""}
|
||||
|
||||
def izleme_mi(hedef):
|
||||
"""Bekci izleme kanali (cevaptan sonra duzeltme) bu hedefin mi? Ayar: watchModels, tam ad eslesmesi."""
|
||||
try:
|
||||
return hedef in jev_settings.read()[0]['watchModels']
|
||||
except Exception:
|
||||
return hedef == "Sesli-Hizli-Zeki"
|
||||
|
||||
|
||||
def muaf_mi(hedef):
|
||||
"""Settings' always-pass list matches exact resolved model IDs.
|
||||
|
||||
@@ -109,16 +122,23 @@ def _metin(oge):
|
||||
def son_istek(req):
|
||||
"""Kullanicinin bu turdaki istegi: son kullanici mesaji. Sesli aktarimda yalniz <input> icindeki soz;
|
||||
baska sarmalli sistem mesajlari (kanca baglami) atlanir."""
|
||||
for oge in reversed(req.get("input") or []):
|
||||
return son_istek_sirasi(req)[0]
|
||||
|
||||
|
||||
def son_istek_sirasi(req):
|
||||
"""(istek, girdideki sirasi). Turun arac adimlarinda da ayni sira doner; yoksa ("", -1)."""
|
||||
girdi = req.get("input") or []
|
||||
for sira in range(len(girdi) - 1, -1, -1):
|
||||
oge = girdi[sira]
|
||||
if not (isinstance(oge, dict) and oge.get("type", "message") == "message" and oge.get("role") == "user"):
|
||||
continue
|
||||
metin = _metin(oge).strip()
|
||||
m = re.search(r"<realtime_delegation>.*?<input>(.*?)</input>", metin, re.S)
|
||||
if m:
|
||||
return m.group(1).strip()
|
||||
return m.group(1).strip(), sira
|
||||
if metin and not metin.startswith("<"):
|
||||
return metin
|
||||
return ""
|
||||
return metin, sira
|
||||
return "", -1
|
||||
|
||||
|
||||
def hazirlik_mi(govde):
|
||||
@@ -166,24 +186,83 @@ def komutlar(govde):
|
||||
return "\n".join(satirlar)
|
||||
|
||||
|
||||
def _gonder(govde, key, settings=None):
|
||||
def _gonder(govde, key, settings=None, timeout=None):
|
||||
settings = settings or jev_settings.read()[0]
|
||||
istek = urllib.request.Request(settings['endpoint'], data=json.dumps(govde).encode("utf-8"), method="POST",
|
||||
headers={"Authorization": "Bearer " + key, "Content-Type": "application/json"})
|
||||
with urllib.request.urlopen(istek, timeout=settings['timeoutSeconds']) as yanit:
|
||||
with urllib.request.urlopen(istek, timeout=timeout or settings['timeoutSeconds']) as yanit:
|
||||
return json.load(yanit)
|
||||
|
||||
|
||||
def sorular(durum, soru, key, timeout, gonder=_gonder, settings=None):
|
||||
"""Karar modeline bir cagrida birden cok evet/hayir sorusu. Donus {ad: 0-1 olasilik} | None (sorulamadi).
|
||||
durum: {"user_request": ..., ["assistant_reply": ...]}; soru: {ad: talimat}."""
|
||||
settings = settings or jev_settings.read()[0]
|
||||
if not key or not soru or not durum.get("user_request"):
|
||||
return None
|
||||
govde = {"model": settings['model'], "state": durum,
|
||||
"questions": {k: {"type": "noul", "instructions": v} for k, v in soru.items()}}
|
||||
if not jev_settings.acquire(settings):
|
||||
return None
|
||||
try:
|
||||
response = gonder(govde, key, settings, timeout) if gonder is _gonder else gonder(govde, key)
|
||||
yanitlar = (response or {}).get("answers") or {}
|
||||
result = {k: float(yanitlar[k]["noul"]) for k in soru}
|
||||
return result if all(0 <= v <= 1 for v in result.values()) else None
|
||||
except Exception:
|
||||
return None
|
||||
finally:
|
||||
jev_settings.release()
|
||||
|
||||
|
||||
def on_karar(istek, oto, ret, key, gonder=_gonder):
|
||||
"""Tur basi karari: istenen sorular tek cagrida. oto: Otomatik modelin combo secimi; ret: normal model reddeder mi.
|
||||
Donus: {"hedef": Otomatik icin secilen ad ya da None, "ret": bool ya da None, "puan": {...} ya da None}."""
|
||||
settings = jev_settings.read()[0]
|
||||
a, p = settings['autoRoute'], settings['prefilter']
|
||||
soru = {}
|
||||
if oto:
|
||||
soru.update(a['questions'])
|
||||
if ret and p['enabled']:
|
||||
soru["ret"] = p['question']
|
||||
if not soru:
|
||||
return {"hedef": None, "ret": None, "puan": None}
|
||||
sure = max(a['timeoutSeconds'] if oto else 0, p['timeoutSeconds'] if ret else 0) or 3
|
||||
puan = sorular({"user_request": istek}, soru, key, sure, gonder=gonder, settings=settings)
|
||||
hedef = None
|
||||
if oto:
|
||||
if puan is None:
|
||||
hedef = a['targets']['zor'] # karar alinamazsa guclu yol
|
||||
elif puan["arastirma"] >= a['thresholds']['arastirma']:
|
||||
hedef = a['targets']['arastirma']
|
||||
elif puan["zor"] >= a['thresholds']['zor']:
|
||||
hedef = a['targets']['zor']
|
||||
else:
|
||||
hedef = a['targets']['basit']
|
||||
tahmin = None if puan is None or "ret" not in puan else puan["ret"] >= p['threshold']
|
||||
return {"hedef": hedef, "ret": tahmin, "puan": puan}
|
||||
|
||||
|
||||
def bitmedi_mi(puan):
|
||||
"""finishCheck: son cevap isi bitirmeden 'bitti' mi dedi? Soru sorulmadiysa False."""
|
||||
if not puan or "bitmedi" not in puan:
|
||||
return False
|
||||
return puan["bitmedi"] >= jev_settings.read()[0]['finishCheck']['threshold']
|
||||
|
||||
|
||||
class Puan(dict):
|
||||
"""Carry the thresholds used for this evaluation through a settings change."""
|
||||
pass
|
||||
|
||||
|
||||
def sor(istek, cevap, key, gonder=_gonder):
|
||||
"""Jev'e sorar. Donus: {"ret", "sart"} olasiliklari | None (sorulamadi)."""
|
||||
def sor(istek, cevap, key, gonder=_gonder, bitis=False):
|
||||
"""Jev'e sorar. Donus: {"ret", "sart"[, "bitmedi"]} olasiliklari | None (sorulamadi).
|
||||
bitis=True ve finishCheck acikken ayni cagriya "is bitmeden bitti mi dedi" sorusu da eklenir."""
|
||||
settings = jev_settings.read()[0]
|
||||
govde = {"model": settings['model'], "state": {"user_request": istek, "assistant_reply": cevap},
|
||||
"questions": {k: {"type": "noul", "instructions": v} for k, v in settings['questions'].items()}}
|
||||
if bitis and settings['finishCheck']['enabled']:
|
||||
govde['questions']['bitmedi'] = {"type": "noul", "instructions": settings['finishCheck']['question']}
|
||||
for name, criteria in settings.get('criteria', {}).items():
|
||||
values = {k: v for k, v in criteria.items() if v.strip()}
|
||||
if values:
|
||||
@@ -193,7 +272,9 @@ def sor(istek, cevap, key, gonder=_gonder):
|
||||
try:
|
||||
response = gonder(govde, key, settings) if gonder is _gonder else gonder(govde, key)
|
||||
yanitlar = (response or {}).get("answers") or {}
|
||||
result = Puan({k: float(yanitlar[k]["noul"]) for k in SORU})
|
||||
result = Puan({k: float(yanitlar[k]["noul"]) for k in settings['questions']})
|
||||
if 'bitmedi' in govde['questions'] and isinstance(yanitlar.get('bitmedi'), dict):
|
||||
result['bitmedi'] = float(yanitlar['bitmedi']['noul']) # ek soru: cevapsizsa ana karar yine gecerli
|
||||
if any(not 0 <= v <= 1 for v in result.values()):
|
||||
return None
|
||||
result.thresholds = settings['thresholds']
|
||||
|
||||
Reference in new issue
Block a user