feat(codex-bridge): Jev routes a blocked step down the layer combos, no exceptions

Katman-1..3 answers are checked by Jev each step; a blocked step is redone by
the next layer combo. Katman-4 is delivered unasked. The technical-obstacle,
question and third-party exemptions and the settings overrides are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
yilsemandClaude Opus 5.5 committed 2026-10-11 09:06:21 +03:00
1 parent 1f4f2de428
commit be0b33e89b
3 files changed
+160 -182

No files matched your search

+57 -58
View File
@@ -871,51 +871,56 @@ class H(http.server.BaseHTTPRequestHandler):
self.send_header("Transfer-Encoding", "chunked")
self.end_headers()
def _denetimli_akis(self, resp, tag, rewriter, izle, istek, ayar, yedek):
"""Adim denetimi (jev_denetim.py): cevap istemciye verilmeden once tamami okunur ve Jev'e sorulur.
Gecerse oldugu gibi verilir; gecmezse atilir ve ayni adimi yedek model yapar (yedek(): (resp, rewriter, tag)).
Beklerken istemciye SSE yorum satiri gider ki Codex akisi kopmus saymasin."""
def _denetimli_akis(self, resp, tag, rewriter, izle, istek, sira, ac):
"""Katman denetimi (jev_denetim.py): cevap istemciye verilmeden once tamami okunur ve Jev'e sorulur.
Gecerse oldugu gibi verilir; gecmezse atilir ve ayni adimi siradaki katman yapar (ac(ad): (resp, rewriter,
tag)). Son katmanin cevabi sorulmadan akar. Beklerken SSE yorum satiri gider ki Codex akisi kopmus saymasin."""
self._akis_basligi(resp, resp.status)
parcalar, okuyan, son_yazi = [], yarim.Izleyici("", ""), time.time()
kalan, son_yazi = list(sira), time.time()
def w(b):
if b:
self.wfile.write(b"%x\r\n" % len(b) + b + b"\r\n"); self.wfile.flush()
try:
while True:
try:
chunk = resp.read1(4096)
except (OSError, http.client.HTTPException) as e:
log(f"{tag} ust kaynak koptu (denetim tamponu, {sum(map(len, parcalar))} bayt): {type(e).__name__}: {e}")
self.close_connection = True
return
if not chunk:
parcalar, okuyan = [], yarim.Izleyici("", "")
while True:
try:
chunk = resp.read1(4096)
except (OSError, http.client.HTTPException) as e:
log(f"{tag} ust kaynak koptu (denetim tamponu, {sum(map(len, parcalar))} bayt): {type(e).__name__}: {e}")
self.close_connection = True
return
if not chunk:
break
parcalar.append(chunk)
okuyan.feed(chunk)
if time.time() - son_yazi >= 10:
w(b": denetim\n\n"); son_yazi = time.time()
metin = okuyan.metin.strip()
gecmedi = False
if metin:
t0 = time.time()
puan = jev_denetim.sor(istek, metin, jev_denetim.anahtar())
if puan is None:
log(f"{tag} katman denetimi: Jev'e sorulamadi, cevap oldugu gibi geciyor")
else:
gecmedi = jev_denetim.karar(puan)
log(f"{tag} katman denetimi: ret={puan['ret']:.2f} sart={puan['sart']:.2f} -> "
f"{'GECMEDI' if gecmedi else 'gecti'} ({time.time() - t0:.1f} sn, {len(metin)} karakter)")
yeni = None
while gecmedi and kalan and yeni is None:
ad = kalan.pop(0)
try:
yeni = ac(ad)
except Exception as e:
log(f"{tag} katman denetimi: {ad} acilamadi ({type(e).__name__}: {str(e)[:120]})")
if yeni is None:
break
parcalar.append(chunk)
okuyan.feed(chunk)
if time.time() - son_yazi >= 10:
w(b": denetim\n\n"); son_yazi = time.time()
metin = okuyan.metin.strip()
gecmedi = False
if metin and istek:
t0 = time.time()
puan = jev_denetim.sor(istek, metin, jev_denetim.anahtar(), float(ayar.get("sure") or jev_denetim.SURE))
if puan is None:
log(f"{tag} adim denetimi: Jev'e sorulamadi, cevap oldugu gibi geciyor")
else:
gecmedi = jev_denetim.karar(puan, ayar)
log(f"{tag} adim denetimi: ret={puan['ret']:.2f} sart={puan['sart']:.2f} teknik={puan['teknik']:.2f} "
f"soru={puan['soru']:.2f} -> {'GECMEDI' if gecmedi else 'gecti'} ({time.time() - t0:.1f} sn, {len(metin)} karakter)")
if gecmedi:
try:
yeni = yedek()
except Exception as e:
yeni = None
log(f"{tag} adim denetimi: yedek model acilamadi ({type(e).__name__}: {str(e)[:120]}); ilk cevap veriliyor")
if yeni is not None:
resp2, rewriter2, tag2 = yeni
log(f"{tag} adim denetimi: adim yedek modele verildi -> {tag2}")
return self._stream(resp2, resp2.status, tag2, rewriter2, izle, basliksiz=True)
resp, rewriter, tag = yeni
log(f"{tag} katman denetimi: adim bu katmana verildi")
if not kalan:
return self._stream(resp, resp.status, tag, rewriter, izle, basliksiz=True)
for chunk in parcalar:
if izle is not None:
izle.feed(chunk)
@@ -1012,7 +1017,7 @@ class H(http.server.BaseHTTPRequestHandler):
"ide_model": int((sayi.split() or ["0"])[0]),
"ozet": bool((CFG.get("ozet_kopru") or {}).get("enabled", False)),
"is_hatti": bool(HAT_KOMUT[0]),
"adim_denetimi": bool(jev_denetim.ayar_oku(CFG.get("jev_denetim"))[0] and jev_denetim.anahtar())})
"adim_denetimi": bool(jev_denetim.anahtar())})
if self.command == "POST" and path.rstrip("/").endswith("/stop"):
self._send_json(200, {"ok": True})
log("AITURK IDE istegiyle kapatiliyor")
@@ -1563,25 +1568,19 @@ class H(http.server.BaseHTTPRequestHandler):
open(os.path.join(LOGDIR, f"{n:04d}_req.json"), "wb").write(data)
hdrs = {"Authorization": f"Bearer {route['key']}", "Content-Type": "application/json", "Accept": "text/event-stream", "User-Agent": UA}
last = None
# Adim denetimi (jev_denetim.py): Jev'in gecirmedigi adimi yedek model yapar. Yedek ayni gecitteyse ve
# secili model zaten yedek degilse acilir; ozet isteginde ve Jev anahtari yokken kapalidir.
jev_yedek = None
jev_acik, jev_hedef, jev_ayar = jev_denetim.ayar_oku(CFG.get("jev_denetim"))
jev_esleme = MODEL_MAP.get(jev_hedef)
if (jev_acik and not ozet_tetik and slug != jev_hedef and jev_esleme and jev_esleme[0] == route_name
and rewriter is not None and jev_denetim.anahtar()):
jev_istek = jev_denetim.son_istek(req)
# Katman denetimi (jev_denetim.py): Katman-1..3 cevabini Jev gecirmezse adimi siradaki katman yapar.
# Katman-4 ve katman olmayan modeller sorulmaz.
jev_sira = [] if ozet_tetik or rewriter is None or not jev_denetim.anahtar() else jev_denetim.sonrakiler(target)
jev_istek = jev_denetim.son_istek(req) if jev_sira else ""
def jev_yedek():
yedek_req = json.loads(data)
yedek_req["model"] = jev_esleme[1]
yanit = urllib.request.urlopen(urllib.request.Request(
route["url"], data=json.dumps(yedek_req, ensure_ascii=False).encode("utf-8"), headers=hdrs, method="POST"),
timeout=UPSTREAM_IDLE_TIMEOUT)
return (yanit, SseRewriter(custom, hedef=jev_esleme[1], tasma=self._tasma_ogren, aracsiz=self._aracsiz_ogren),
f"[{n} {route_name.upper()} {slug}=>{jev_esleme[1]}]")
if not jev_istek:
jev_yedek = None
def jev_ac(ad):
katman_req = json.loads(data)
katman_req["model"] = ad
yanit = urllib.request.urlopen(urllib.request.Request(
route["url"], data=json.dumps(katman_req, ensure_ascii=False).encode("utf-8"), headers=hdrs, method="POST"),
timeout=UPSTREAM_IDLE_TIMEOUT)
return (yanit, SseRewriter(custom, hedef=ad, tasma=self._tasma_ogren, aracsiz=self._aracsiz_ogren),
f"[{n} {route_name.upper()} {slug}=>{ad}]")
# A 9Router combo (Fusion-*, no provider prefix) runs a whole panel upstream. Once it may
# have started (timeout, 504, cut stream) resending it runs and bills it twice (28 Sep 2026);
# only failures before the work starts (no connection, 500/502/503/529) are retried.
@@ -1634,8 +1633,8 @@ class H(http.server.BaseHTTPRequestHandler):
sonuc = self._stream(resp, resp.status, tag, akis)
log(f"{tag} ozet kopru: {akis.sonuc_notu()}")
return sonuc
if jev_yedek is not None and resp.status == 200:
return self._denetimli_akis(resp, tag, rewriter, izle, jev_istek, jev_ayar, jev_yedek)
if jev_sira and jev_istek and resp.status == 200:
return self._denetimli_akis(resp, tag, rewriter, izle, jev_istek, jev_sira, jev_ac)
return self._stream(resp, resp.status, tag, rewriter, izle)
self._send_json(503, {"error": {"message": f"bridge: hedef ulasilamadi {last}"}})