diff --git a/apps/desktop/assets/codex-bridge/ide_catalog.py b/apps/desktop/assets/codex-bridge/ide_catalog.py index ca85231..143088e 100644 --- a/apps/desktop/assets/codex-bridge/ide_catalog.py +++ b/apps/desktop/assets/codex-bridge/ide_catalog.py @@ -86,6 +86,7 @@ def ide_yapilandirma(agent=AGENT): return base.rstrip("/"), varsayilan, adlar +EN_COK_MODEL = 300 AITURK_EKI = " (AITURK)" # Gecidin kisa saglayici kodu -> kullanicinin gormek istedigi kod (10 Ekim 2026: "agy/gemini"). _SAGLAYICI_KISA = {"ag": "agy"} @@ -188,7 +189,7 @@ def sec(data, tanimli=(), kapsam="ide", turler=None): if taban != s["ad"] and taban.split(" · ")[-1].strip().lower() not in adlar: adlar.add(taban.split(" · ")[-1].strip().lower()) s["ad"] = taban - return [{"id": s["id"], "ad": s["ad"], "kind": s["kind"], "yol": s["yol"]} for s in secilen] + return [{"id": s["id"], "ad": s["ad"], "kind": s["kind"], "yol": s["yol"]} for s in secilen[:EN_COK_MODEL]] def sirala_codex(modeller, ekler, ozgun_kimlikler=()): diff --git a/apps/desktop/assets/codex-bridge/jev_denetim.py b/apps/desktop/assets/codex-bridge/jev_denetim.py index 1a71ea1..ce673c6 100644 --- a/apps/desktop/assets/codex-bridge/jev_denetim.py +++ b/apps/desktop/assets/codex-bridge/jev_denetim.py @@ -15,8 +15,6 @@ Metni olmayan (yalniz arac cagiran) adimda sorulacak cevap yoktur. Jev'e ulasila import json import os import re -import threading -import time import urllib.request ADRES = "https://api.typesafe.ai/v1/systemone" @@ -26,16 +24,12 @@ ESIK = {"ret": 0.5, "sart": 0.7} SURE = 6.0 EN_COK_ISTEK = 3000 EN_COK_CEVAP = 6000 -DEVRE_HATA = 3 # art arda bu kadar hatadan sonra -DEVRE_SN = 300 # bu kadar sure Jev'e sorulmaz SORU = { "ret": ("The assistant did NOT do what the user asked or did NOT answer the user's question: it refused, declined, " "said it cannot or will not, avoided giving the requested judgment, or redirected to a different topic."), "sart": ("The assistant changed the request on its own: it added its own conditions, softened or relabeled what was " "asked, or left part of it out, instead of doing exactly what the user asked."), } -_KILIT = threading.Lock() -_DEVRE = {"hata": 0, "kadar": 0.0} _ANAHTAR = {"okundu": False, "deger": ""} @@ -116,26 +110,15 @@ def _gonder(govde, key, sure): return json.load(yanit) -def sor(istek, cevap, key, sure=SURE, gonder=_gonder, simdi=None): +def sor(istek, cevap, key, sure=SURE, gonder=_gonder): """Jev'e sorar. Donus: {"ret", "sart"} olasiliklari | None (sorulamadi).""" - simdi = time.time() if simdi is None else simdi - with _KILIT: - if simdi < _DEVRE["kadar"]: - return None govde = {"model": MODEL, "state": {"user_request": istek, "assistant_reply": _kisalt(cevap, EN_COK_CEVAP)}, "questions": {k: {"type": "noul", "instructions": v} for k, v in SORU.items()}} try: yanitlar = (gonder(govde, key, sure) or {}).get("answers") or {} - sonuc = {k: float(yanitlar[k]["noul"]) for k in SORU} + return {k: float(yanitlar[k]["noul"]) for k in SORU} except Exception: - with _KILIT: - _DEVRE["hata"] += 1 - if _DEVRE["hata"] >= DEVRE_HATA: - _DEVRE.update(hata=0, kadar=simdi + DEVRE_SN) return None - with _KILIT: - _DEVRE["hata"] = 0 - return sonuc def karar(puan): diff --git a/apps/desktop/assets/codex-bridge/kopru.py b/apps/desktop/assets/codex-bridge/kopru.py index c8390e6..ffb8698 100644 --- a/apps/desktop/assets/codex-bridge/kopru.py +++ b/apps/desktop/assets/codex-bridge/kopru.py @@ -876,7 +876,7 @@ class H(http.server.BaseHTTPRequestHandler): 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) - kalan, son_yazi = list(sira), time.time() + kalan, son_yazi, katmanda = list(sira), time.time(), False def w(b): if b: @@ -908,6 +908,14 @@ class H(http.server.BaseHTTPRequestHandler): 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)") + elif katmanda: + # Katman cevap yerine hata dondurduyse (or. arac cagrisi desteklemeyen model "upstream 400") + # acilamamis sayilir; hata cevap diye verilirse Codex ayni adimi bastan dener ve tur cevapsiz kalir. + govde = b"".join(parcalar) + if (b"event: error" in govde or b'"type":"error"' in govde or b'"type": "error"' in govde + or b"response.failed" in govde): + gecmedi = True + log(f"{tag} katman denetimi: katman hata dondurdu, siradakine geciliyor: {govde[-200:]!r}") yeni = None while gecmedi and kalan and yeni is None: ad = kalan.pop(0) @@ -918,6 +926,7 @@ class H(http.server.BaseHTTPRequestHandler): if yeni is None: break resp, rewriter, tag = yeni + katmanda = True log(f"{tag} katman denetimi: adim bu katmana verildi") if not kalan: return self._stream(resp, resp.status, tag, rewriter, izle, basliksiz=True) diff --git a/apps/desktop/assets/codex-bridge/test_jev_denetim.py b/apps/desktop/assets/codex-bridge/test_jev_denetim.py index e9b0da7..6539225 100644 --- a/apps/desktop/assets/codex-bridge/test_jev_denetim.py +++ b/apps/desktop/assets/codex-bridge/test_jev_denetim.py @@ -86,9 +86,6 @@ class Istek(unittest.TestCase): class Sor(unittest.TestCase): - def setUp(self): - jev_denetim._DEVRE.update(hata=0, kadar=0.0) - def test_request_shape_and_scores(self): seen = {} @@ -100,16 +97,15 @@ class Sor(unittest.TestCase): self.assertEqual(seen["govde"]["state"]["user_request"], "istek") self.assertLess(len(seen["govde"]["state"]["assistant_reply"]), 6100) - def test_failures_return_none_and_open_the_breaker(self): + def test_failures_return_none_every_time(self): calls = [] def bozuk(govde, key, sure): calls.append(1) raise OSError("ulasilamadi") - for _ in range(jev_denetim.DEVRE_HATA): - self.assertIsNone(jev_denetim.sor("i", "c", "k", gonder=bozuk, simdi=1000.0)) - self.assertIsNone(jev_denetim.sor("i", "c", "k", gonder=bozuk, simdi=1001.0)) - self.assertEqual(len(calls), jev_denetim.DEVRE_HATA) + for _ in range(5): + self.assertIsNone(jev_denetim.sor("i", "c", "k", gonder=bozuk)) + self.assertEqual(len(calls), 5) def test_key_is_read_from_env_or_file(self): self.assertEqual(jev_denetim.anahtar({"TYPESAFE_API_KEY": " a "}), "a") @@ -208,6 +204,14 @@ class Akis(unittest.TestCase): self.assertEqual(self.opened, ["Katman-2", "Katman-3"]) self.assertEqual(self.sent(), self.cevap["Katman-3"]) + def test_a_layer_that_answers_with_an_error_is_skipped(self): + self.puanlar = [{"ret": 0.9, "sart": 0.0}] + self.cevap["Katman-2"] = b'event: error\ndata: {"type":"error","error":{"type":"upstream_error","message":"upstream 400"}}\n\n' + self.calistir(sse("hayir")) + self.assertEqual(self.opened, ["Katman-2", "Katman-3"]) + self.assertEqual(self.sent(), self.cevap["Katman-3"]) + self.assertNotIn(b"upstream 400", self.h.wfile.getvalue()) + def test_a_step_without_text_is_not_sent_to_jev(self): body = b'event: response.output_item.done\ndata: {"type": "response.output_item.done", "item": {"type": "function_call"}}\n\n' + sse() self.calistir(body)