Kopru: secili model hata verirse siradaki katman yapar

Hata kodu, baglanamama ve yarida kopma da siradaki katmana gider.
Siradakine gecilen adimda onceki cevap verilmez; son katman da
acilamazsa onun kendi hatasi gider.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
yilsemandClaude Opus 5.5 committed 2026-10-11 10:40:13 +03:00
1 parent 7547de1852
commit 06039b904d
2 files changed
+61 -15

No files matched your search

+36 -15
View File
@@ -875,22 +875,28 @@ class H(http.server.BaseHTTPRequestHandler):
"""Katman denetimi (jev_denetim.py): cevap istemciye verilmeden once tamami okunur ve Jev'e sorulur. """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, 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.""" tag)). Son katmanin cevabi sorulmadan akar. Beklerken SSE yorum satiri gider ki Codex akisi kopmus saymasin."""
self._akis_basligi(resp, resp.status) if resp is None: # secili model hata verdi: cevabi yok, adimi siradaki katman yapar
kalan, son_yazi = list(sira), time.time() self.send_response(200)
self.send_header("Content-Type", "text/event-stream")
self.send_header("Transfer-Encoding", "chunked")
self.end_headers()
else:
self._akis_basligi(resp, resp.status)
kalan, son_yazi, son_hata = list(sira), time.time(), ""
def w(b): def w(b):
if b: if b:
self.wfile.write(b"%x\r\n" % len(b) + b + b"\r\n"); self.wfile.flush() self.wfile.write(b"%x\r\n" % len(b) + b + b"\r\n"); self.wfile.flush()
try: try:
while True: while True:
parcalar, okuyan = [], yarim.Izleyici("", "") parcalar, okuyan, hata = [], yarim.Izleyici("", ""), resp is None
while True: while not hata:
try: try:
chunk = resp.read1(4096) chunk = resp.read1(4096)
except (OSError, http.client.HTTPException) as e: except (OSError, http.client.HTTPException) as e:
log(f"{tag} ust kaynak koptu (denetim tamponu, {sum(map(len, parcalar))} bayt): {type(e).__name__}: {e}") log(f"{tag} katman denetimi: cevap yarida koptu, siradakine geciliyor ({type(e).__name__}: {e})")
self.close_connection = True hata = True
return break
if not chunk: if not chunk:
break break
parcalar.append(chunk) parcalar.append(chunk)
@@ -901,7 +907,9 @@ class H(http.server.BaseHTTPRequestHandler):
# Her adim Jev'e gider: yazi yoksa modelin bu adimda cagirdigi araclar sorulur. # Her adim Jev'e gider: yazi yoksa modelin bu adimda cagirdigi araclar sorulur.
metin = yazi or jev_denetim.komutlar(b"".join(parcalar)) metin = yazi or jev_denetim.komutlar(b"".join(parcalar))
gecmedi = False gecmedi = False
if metin: if hata:
gecmedi = True
elif metin:
t0 = time.time() t0 = time.time()
puan = jev_denetim.sor(istek, metin, jev_denetim.anahtar()) puan = jev_denetim.sor(istek, metin, jev_denetim.anahtar())
if puan is None: if puan is None:
@@ -922,23 +930,32 @@ class H(http.server.BaseHTTPRequestHandler):
try: try:
yeni = ac(ad) yeni = ac(ad)
except Exception as e: except Exception as e:
log(f"{tag} katman denetimi: {ad} acilamadi ({type(e).__name__}: {str(e)[:120]})") govde = e.read().decode("utf-8", "replace") if hasattr(e, "read") else ""
son_hata = f"{ad}: {e} {govde}".strip()
log(f"{tag} katman denetimi: {ad} acilamadi ({son_hata[:300]})")
if yeni is None: if yeni is None:
break break
resp, rewriter, tag = yeni resp, rewriter, tag = yeni
log(f"{tag} katman denetimi: adim bu katmana verildi") log(f"{tag} katman denetimi: adim bu katmana verildi")
if not kalan: if not kalan:
return self._stream(resp, resp.status, tag, rewriter, izle, basliksiz=True) return self._stream(resp, resp.status, tag, rewriter, izle, basliksiz=True)
for chunk in parcalar: if gecmedi:
if izle is not None: # Siradakine gecilen adimda onceki model bir sey soyleyemez: son katmanin kendi hatasi gider.
izle.feed(chunk) log(f"{tag} katman denetimi: son katman da acilamadi, onun hatasi veriliyor")
w(rewriter.feed(chunk) if rewriter else chunk) olay = {"type": "response.failed", "response": {"id": "resp_astrabridge_katman", "object": "response",
if rewriter: w(rewriter.flush()) "status": "failed", "output": [], "error": {"code": "katman_hatasi", "message": son_hata}}}
w(b"event: response.failed\ndata: " + json.dumps(olay, ensure_ascii=False).encode("utf-8") + b"\n\n")
else:
for chunk in parcalar:
if izle is not None:
izle.feed(chunk)
w(rewriter.feed(chunk) if rewriter else chunk)
if rewriter: w(rewriter.flush())
self.wfile.write(b"0\r\n\r\n"); self.wfile.flush() self.wfile.write(b"0\r\n\r\n"); self.wfile.flush()
except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError): except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError):
log(f"{tag} istemci baglantiyi kapatti (denetim tamponu)") log(f"{tag} istemci baglantiyi kapatti (denetim tamponu)")
return return
log(f"{tag} bitti status={resp.status} {sum(map(len, parcalar))} bayt") log(f"{tag} bitti {'hata' if gecmedi else 'status=200'} {sum(map(len, parcalar))} bayt")
def _stream(self, resp, status, tag, rewriter=None, izle=None, basliksiz=False): def _stream(self, resp, status, tag, rewriter=None, izle=None, basliksiz=False):
if not basliksiz: if not basliksiz:
@@ -1620,6 +1637,8 @@ class H(http.server.BaseHTTPRequestHandler):
log(f"{tag} deneme {attempt}: HTTP {e.code} {errbody[:100]!r} -> tekrar") log(f"{tag} deneme {attempt}: HTTP {e.code} {errbody[:100]!r} -> tekrar")
time.sleep(min(2 * attempt, 8)); continue time.sleep(min(2 * attempt, 8)); continue
log(f"{tag} HTTP {e.code} {errbody[:200]!r}") log(f"{tag} HTTP {e.code} {errbody[:200]!r}")
if jev_sira: # secili model hata verdi: adimi siradaki katman yapar
return self._denetimli_akis(None, tag, rewriter, izle, jev_istek, jev_sira, jev_ac)
if pencere.tasma_mi(etxt): if pencere.tasma_mi(etxt):
# Hedef "baglam sigmiyor" dedi: Codex'in tanidigi tasma hatasi olarak iletilir ve hedefin # Hedef "baglam sigmiyor" dedi: Codex'in tanidigi tasma hatasi olarak iletilir ve hedefin
# bildirdigi gercek sinir ogrenilir (sonraki model listesinde pencere kuculur). # bildirdigi gercek sinir ogrenilir (sonraki model listesinde pencere kuculur).
@@ -1651,6 +1670,8 @@ class H(http.server.BaseHTTPRequestHandler):
if jev_sira and resp.status == 200: if jev_sira and resp.status == 200:
return self._denetimli_akis(resp, tag, rewriter, izle, jev_istek, jev_sira, jev_ac) return self._denetimli_akis(resp, tag, rewriter, izle, jev_istek, jev_sira, jev_ac)
return self._stream(resp, resp.status, tag, rewriter, izle) return self._stream(resp, resp.status, tag, rewriter, izle)
if jev_sira: # secili modele ulasilamadi: adimi siradaki katman yapar
return self._denetimli_akis(None, tag, rewriter, izle, jev_istek, jev_sira, jev_ac)
self._send_json(503, {"error": {"message": f"bridge: hedef ulasilamadi {last}"}}) self._send_json(503, {"error": {"message": f"bridge: hedef ulasilamadi {last}"}})
do_POST = _handle do_POST = _handle
@@ -241,6 +241,31 @@ class Akis(unittest.TestCase):
self.assertEqual(self.opened, ["Katman-2", "Katman-3"]) self.assertEqual(self.opened, ["Katman-2", "Katman-3"])
self.assertEqual(self.sent(), self.cevap["Katman-3"]) self.assertEqual(self.sent(), self.cevap["Katman-3"])
def test_an_error_of_the_selected_model_goes_to_the_next_layer(self):
self.h._denetimli_akis(None, "[1]", None, None, "yap", ["Katman-1", "Katman-2", "Katman-3", "Katman-4"], self.ac)
self.assertEqual(self.opened, ["Katman-1"])
self.assertEqual(self.sent(), self.cevap["Katman-1"])
def test_an_answer_cut_midway_goes_to_the_next_layer(self):
class Kopan(Yanit):
def read1(self, n):
if not self.parts:
raise OSError("koptu")
return self.parts.pop(0)
self.h._denetimli_akis(Kopan(sse("yarim")), "[1]", None, None, "yap", ["Katman-2", "Katman-3", "Katman-4"], self.ac)
self.assertEqual(self.opened, ["Katman-2"])
self.assertEqual(self.sent(), self.cevap["Katman-2"])
self.assertNotIn(b"yarim", self.h.wfile.getvalue())
def test_when_no_layer_opens_the_blocked_answer_is_not_delivered(self):
self.puanlar = [{"ret": 0.9, "sart": 0.0}]
self.cevap.update({"Katman-2": None, "Katman-3": None, "Katman-4": None})
self.calistir(sse("Bunu yapamam."))
self.assertEqual(self.opened, ["Katman-2", "Katman-3", "Katman-4"])
self.assertNotIn(b"yapamam", self.h.wfile.getvalue())
self.assertIn(b"response.failed", self.sent())
self.assertIn(b"Katman-4: acilamadi", self.sent()) # the last layer's own error reaches the user
def test_unreachable_jev_keeps_the_answer(self): def test_unreachable_jev_keeps_the_answer(self):
self.puanlar = [None] self.puanlar = [None]
body = sse("Bunu yapamam.") body = sse("Bunu yapamam.")