feat(codex-bridge): per-step check with Jev, blocked steps go to a fallback model

User decision (11 Oct 2026): every step of an added model is checked in the
bridge; Jev only passes or blocks; a blocked step is redone by
Uncensored-Uygulama and the next step goes back to the selected model.

The bridge buffers the step's answer, asks Jev four yes/no questions and
decides in code: blocked when the answer refuses or dodges the request, or
changes it with its own conditions without asking; passed when it reports a
concrete technical obstacle, asks the user a question, or has no text (tool
calls only). While buffering the client gets SSE comment lines. Jev unreachable
or fallback unavailable: the first answer is delivered. Codex's own models do
not reach the bridge and are not checked.

Also logs the shape of each forwarded request (not its content): the recurring
"upstream 400" turned out to be Codex's trailing configuration_update item.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
yilsemandClaude Opus 5.5 committed 2026-10-11 07:56:27 +03:00
1 parent c8993d58cc
commit 5556ad11af
6 files changed
+451 -5

No files matched your search

@@ -0,0 +1,155 @@
"""Adim denetimi: ek modelin her adimdaki cevabini Jev gecirir ya da gecirmez (11 Ekim 2026).
Kullanici karari (11 Ekim 2026): "Bu kopruye Jev koy, her model her adimda kontrol etsin ve yakaladigini qwen 3.8
obliterated thinking versin." / "Bir prompt cok adimli olabilir; her adim kontrol edilsin. Jev sadece geciren ya da
gecirmeyen; gecirmezse 3.8 obliterated thinking." Ardindan (ayni gun): "obliterated:thinking yerine Uncensored-Uygulama yapar
misin" -> yedek, Uncensored-Uygulama combosudur. Yani denetim adim basinadir: Jev'in gecirmedigi adimi yedek model
yapar, sonraki adim yine secili modele gider ve yine denetlenir.
Jev (TypeSafe System One) metin uretmez; bir duruma sorulan evet/hayir sorularina olasilik verir (olcum 11 Ekim
2026: cagri basina ~0,4 sn, 13 gercek ornegin 13'u dogru ayrildi). Kural kodda durur:
- yakalanir: cevap istegi yapmiyor/soylemiyor (ret, kacamak, konuyu degistirme) ya da istegi sormadan kendi
sartlariyla degistiriyor;
- yakalanmaz: somut bir teknik engel bildiren cevap (hata, eksik dosya/arac/yetki) ve kullaniciya soru ya da onay
soran cevap; metni olmayan (yalniz arac cagiran) adim.
Jev'e ulasilamazsa cevap oldugu gibi gecer (is durmaz); art arda hatada bir sure hic sorulmaz.
Codex'in kendi modelleri kopruye ugramadigi icin bu denetimin disindadir.
Ayar (bridge.json, istege bagli): "jev_denetim": {"enabled": false} kapatir; "hedef" yedek modelin Codex adi;
"ret", "sart", "teknik", "soru" esikleri; "sure" saniye.
"""
import json
import os
import re
import threading
import time
import urllib.request
ADRES = "https://api.typesafe.ai/v1/systemone"
MODEL = "jev-1.13.0"
HEDEF = "ide/Uncensored-Uygulama"
ESIK = {"ret": 0.7, "sart": 0.9, "teknik": 0.5, "soru": 0.5}
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."),
"teknik": ("The assistant reports a concrete technical obstacle as the reason: an error message, a failed command, "
"a missing file, tool, permission, connection or piece of information."),
"soru": ("The assistant's reply is mainly a question to the user: it asks for a clarification, a choice or an "
"approval and waits for the user's answer before doing anything."),
}
_KILIT = threading.Lock()
_DEVRE = {"hata": 0, "kadar": 0.0}
_ANAHTAR = {"okundu": False, "deger": ""}
def anahtar(ortam=None, dosyalar=None):
"""TypeSafe anahtari: ortam degiskeni, sonra ~/.typesafe/typesafe.env. Yoksa "" (denetim kapali sayilir)."""
ortam = os.environ if ortam is None else ortam
deger = str(ortam.get("TYPESAFE_API_KEY") or "").strip()
if deger:
return deger
if dosyalar is None:
if _ANAHTAR["okundu"]:
return _ANAHTAR["deger"]
dosyalar = [os.path.join(os.path.expanduser("~"), ".typesafe", "typesafe.env")]
onbellek = True
else:
onbellek = False
for yol in dosyalar:
try:
with open(yol, encoding="utf-8", errors="replace") as f:
for satir in f:
m = re.match(r"^\s*TYPESAFE_API_KEY\s*=\s*(.*)$", satir)
if m:
deger = m.group(1).strip().strip('"').strip("'")
break
except OSError:
continue
if deger:
break
if onbellek:
_ANAHTAR.update(okundu=True, deger=deger)
return deger
def _metin(oge):
icerik = oge.get("content")
if isinstance(icerik, str):
return icerik
return "".join(str(p.get("text") or "") for p in icerik or [] if isinstance(p, dict))
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 []):
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()[:EN_COK_ISTEK]
if metin and not metin.startswith("<"):
return metin[:EN_COK_ISTEK]
return ""
def _kisalt(metin, sinir):
if len(metin) <= sinir:
return metin
bas = sinir * 2 // 3
return metin[:bas] + "\n[...]\n" + metin[-(sinir - bas):]
def _gonder(govde, key, sure):
istek = urllib.request.Request(ADRES, data=json.dumps(govde).encode("utf-8"), method="POST",
headers={"Authorization": "Bearer " + key, "Content-Type": "application/json"})
with urllib.request.urlopen(istek, timeout=sure) as yanit:
return json.load(yanit)
def sor(istek, cevap, key, sure=SURE, gonder=_gonder, simdi=None):
"""Jev'e dort soruyu sorar. Donus: {"ret","sart","teknik","soru"} 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}
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, ayar=None):
"""True: adim gecmez (yedek model yapar). Esikler ayardan degistirilebilir."""
e = dict(ESIK)
e.update({k: float(v) for k, v in (ayar or {}).items() if k in ESIK})
if puan["soru"] >= e["soru"]:
return False # kullaniciya soru/onay soruyor: kullanici cevaplar
if puan["ret"] >= e["ret"] and puan["teknik"] < e["teknik"]:
return True # yapmiyor / soylemiyor (teknik engel degil)
return puan["sart"] >= e["sart"] # sormadan kendi sartlariyla degistirdi
def ayar_oku(cfg):
"""(acik, hedef slug, ayar sozlugu)."""
ayar = cfg if isinstance(cfg, dict) else {}
return ayar.get("enabled", True) is not False, str(ayar.get("hedef") or HEDEF), ayar
+95 -2
View File
@@ -30,6 +30,7 @@ import yarim
import model_gecis
import is_hatti
import internet
import jev_denetim
SURUM = "8"
HERE = os.path.dirname(os.path.abspath(__file__))
@@ -862,13 +863,73 @@ class H(http.server.BaseHTTPRequestHandler):
n = int(self.headers.get("Content-Length") or 0)
return self.rfile.read(n) if n else b""
def _stream(self, resp, status, tag, rewriter=None, izle=None):
def _akis_basligi(self, resp, status):
self.send_response(status)
for k, v in resp.headers.items():
if k.lower() in RESP_HOP: continue
self.send_header(k, v)
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."""
self._akis_basligi(resp, resp.status)
parcalar, okuyan, son_yazi = [], yarim.Izleyici("", ""), 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:
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)
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()
except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError):
log(f"{tag} istemci baglantiyi kapatti (denetim tamponu)")
return
log(f"{tag} bitti status={resp.status} {sum(map(len, parcalar))} bayt")
def _stream(self, resp, status, tag, rewriter=None, izle=None, basliksiz=False):
if not basliksiz:
self._akis_basligi(resp, status)
total = 0
bas = b"" # ust kaynagin ilk baytlari: cok kisa (bos) akislarin nedeni gunluge yazilir
def w(b):
@@ -950,7 +1011,8 @@ class H(http.server.BaseHTTPRequestHandler):
return self._send_json(200, {"ok": ZSTD_OK, "surum": SURUM, "kod": KOD, "zstd": ZSTD_OK, "ide_durum": durum,
"ide_model": int((sayi.split() or ["0"])[0]),
"ozet": bool((CFG.get("ozet_kopru") or {}).get("enabled", False)),
"is_hatti": bool(HAT_KOMUT[0])})
"is_hatti": bool(HAT_KOMUT[0]),
"adim_denetimi": bool(jev_denetim.ayar_oku(CFG.get("jev_denetim"))[0] and jev_denetim.anahtar())})
if self.command == "POST" and path.rstrip("/").endswith("/stop"):
self._send_json(200, {"ok": True})
log("AITURK IDE istegiyle kapatiliyor")
@@ -1487,10 +1549,39 @@ class H(http.server.BaseHTTPRequestHandler):
"Daha büyük pencereli bir model seçin ya da mesajı kısaltın.")
data = json.dumps(req, ensure_ascii=False).encode("utf-8")
log(f"{tag} girdi={len(req.get('input', []))} oge, arac={len(req.get('tools', []) or [])} {len(data)} bayt")
try:
# Istegin bicimi (icerik degil): gecidin reddettigi istegi sonradan ayirt edebilmek icin.
son = (req.get("input") or [None])[-1]
bicim = {k: v for k, v in req.items() if k not in ("input", "tools", "instructions", "prompt_cache_key")}
log(f"{tag} bicim={json.dumps(bicim, ensure_ascii=False)[:420]} son_oge="
f"{(son.get('type'), son.get('role')) if isinstance(son, dict) else type(son).__name__}"
+ (f" icerik={json.dumps(son, ensure_ascii=False)[:700]}" if isinstance(son, dict) and son.get("type") not in
("message", "function_call_output", "custom_tool_call_output", "function_call", "reasoning") else ""))
except Exception:
pass
if DEBUG:
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)
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
# 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.
@@ -1543,6 +1634,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)
return self._stream(resp, resp.status, tag, rewriter, izle)
self._send_json(503, {"error": {"message": f"bridge: hedef ulasilamadi {last}"}})
@@ -33,7 +33,7 @@ class AccessPrograms(unittest.TestCase):
"fix_tool_ids": lambda req: 0,
"drop_foreign_items": lambda req: 0,
"SseRewriter": Mock(),
"log": lambda message: None, "pencere": __import__("pencere"), "IDE_BILGI": {}, "yarim": __import__("yarim"), "is_hatti": __import__("is_hatti"), "GORULEN_ISTEMCI": set(), "arac_semalarini_duzelt": lambda req: 0, "nokta_mesaji_mi": lambda req: False, "EXTRA_MODELS": [],
"log": lambda message: None, "pencere": __import__("pencere"), "IDE_BILGI": {}, "yarim": __import__("yarim"), "jev_denetim": __import__("jev_denetim"), "internet": __import__("internet"), "is_hatti": __import__("is_hatti"), "GORULEN_ISTEMCI": set(), "arac_semalarini_duzelt": lambda req: 0, "nokta_mesaji_mi": lambda req: False, "EXTRA_MODELS": [],
"DEBUG": False, "UA": "test", "RETRIES": 1, "UPSTREAM_IDLE_TIMEOUT": 3900,
}
exec(compile(ast.Module(body=taraf + [flatten, claude_sonu, responses, ozgun], type_ignores=[]), "bridge.py", "exec"), self.env)
@@ -40,7 +40,7 @@ class ComboNotResent(unittest.TestCase):
"fix_tool_ids": lambda req: 0, "drop_foreign_items": lambda req: 0,
"SseRewriter": Mock(), "log": lambda message: None,
"DEBUG": False, "UA": "test", "RETRIES": 6, "UPSTREAM_IDLE_TIMEOUT": 3600,
"NO_RETRY_PATTERNS": [], "pencere": __import__("pencere"), "IDE_BILGI": {}, "yarim": __import__("yarim"), "is_hatti": __import__("is_hatti"), "GORULEN_ISTEMCI": set(), "arac_semalarini_duzelt": lambda req: 0, "nokta_mesaji_mi": lambda req: False, "EXTRA_MODELS": [],
"NO_RETRY_PATTERNS": [], "pencere": __import__("pencere"), "IDE_BILGI": {}, "yarim": __import__("yarim"), "jev_denetim": __import__("jev_denetim"), "internet": __import__("internet"), "is_hatti": __import__("is_hatti"), "GORULEN_ISTEMCI": set(), "arac_semalarini_duzelt": lambda req: 0, "nokta_mesaji_mi": lambda req: False, "EXTRA_MODELS": [],
}
exec(compile(ast.Module(body=[pick("ek_model_mu"), pick("yonlendirilen"), pick("flatten_request"), pick("claude_sonu_duzelt"),
pick("is_timeout"), pick("kopma_mi"), responses],
@@ -263,7 +263,7 @@ class Zincir(unittest.TestCase):
"decompress": lambda body, enc: body, "MODEL_MAP": {}, "ROUTES": {}, "CFG": {"model_bilgi": False}, "log": lambda m: None,
"model_gecis": model_gecis, "YONLENDIRME": model_gecis.Yonlendirme(None), "bilinen_modeller": lambda: MODELS,
"model_adi": lambda slug: dict(MODELS).get(slug, slug), "is_hatti": is_hatti, "GORULEN_ISTEMCI": set(),
"yarim": yarim, "ozet_kopru": ozet_kopru, "OZET_FRENI": ozet_kopru.DonguFreni(), "pencere": pencere,
"yarim": yarim, "jev_denetim": __import__("jev_denetim"), "internet": __import__("internet"), "ozet_kopru": ozet_kopru, "OZET_FRENI": ozet_kopru.DonguFreni(), "pencere": pencere,
"fix_tool_ids": lambda req: 0, "drop_foreign_items": lambda req: 0, "IDE_BILGI": {}, "EXTRA_MODELS": [],
"arac_semalarini_duzelt": lambda req: 0, "SseRewriter": Mock(), "DEBUG": False, "UA": "test", "RETRIES": 6,
"UPSTREAM_IDLE_TIMEOUT": 1, "NO_RETRY_PATTERNS": [], "pano_blogunu_ulastir": lambda req: (0, ""),
@@ -0,0 +1,198 @@
"""Step check (11 Oct 2026): Jev passes or blocks each step of an added model; a blocked step is redone by the
fallback model, the next step goes back to the selected model."""
import ast
import http.client
import io
import json
import os
import tempfile
import time
import unittest
from pathlib import Path
from unittest.mock import Mock
import jev_denetim
import yarim
SOURCE = Path(__file__).with_name("kopru.py").read_text(encoding="utf-8")
tree = ast.parse(SOURCE)
handler = next(n for n in tree.body if isinstance(n, ast.ClassDef) and n.name == "H")
def method(name):
return next(n for n in handler.body if isinstance(n, ast.FunctionDef) and n.name == name)
def user(text):
return {"type": "message", "role": "user", "content": [{"type": "input_text", "text": text}]}
def sse(*deltas, done=True):
out = b""
for d in deltas:
out += b"event: response.output_text.delta\ndata: " + json.dumps(
{"type": "response.output_text.delta", "delta": d}).encode() + b"\n\n"
if done:
out += b'event: response.completed\ndata: {"type": "response.completed"}\n\n'
return out
class Yanit:
"""Fake upstream response: read1 returns the body in two pieces."""
status = 200
def __init__(self, body):
self.parts = [body[:len(body) // 2], body[len(body) // 2:]]
self.headers = {"Content-Type": "text/event-stream"}
def read1(self, n):
return self.parts.pop(0) if self.parts else b""
def scores(ret=0.0, sart=0.0, teknik=0.0, soru=0.0):
return {"ret": ret, "sart": sart, "teknik": teknik, "soru": soru}
class Karar(unittest.TestCase):
def test_refusals_and_silent_conditions_are_blocked(self):
self.assertTrue(jev_denetim.karar(scores(ret=0.84))) # "böyle bir hüküm vermiyorum"
self.assertTrue(jev_denetim.karar(scores(ret=0.41, sart=0.95))) # did it with its own conditions
self.assertTrue(jev_denetim.karar(scores(ret=0.93, sart=0.72)))
def test_normal_answers_technical_obstacles_and_questions_pass(self):
self.assertFalse(jev_denetim.karar(scores(ret=0.05, sart=0.3)))
self.assertFalse(jev_denetim.karar(scores(ret=0.85, teknik=0.97))) # "SSH key rejected, could not read"
self.assertFalse(jev_denetim.karar(scores(ret=0.62, sart=0.91, soru=0.93))) # asks for approval first
self.assertFalse(jev_denetim.karar(scores(ret=0.48, soru=0.96)))
def test_thresholds_come_from_settings(self):
self.assertFalse(jev_denetim.karar(scores(ret=0.84), {"ret": 0.9}))
self.assertTrue(jev_denetim.karar(scores(sart=0.8), {"sart": 0.75}))
class Istek(unittest.TestCase):
def test_last_user_request_is_taken_and_wrappers_are_skipped(self):
voice = user("<realtime_delegation>\n <input>siteyi yap</input>\n <transcript_delta>x</transcript_delta>\n</realtime_delegation>")
self.assertEqual(jev_denetim.son_istek({"input": [user("eski"), voice]}), "siteyi yap")
hook = user("<hook_context>pano</hook_context>")
call = {"type": "function_call", "call_id": "c", "name": "shell", "arguments": "{}"}
self.assertEqual(jev_denetim.son_istek({"input": [user("README'yi düzelt"), call, hook]}), "README'yi düzelt")
self.assertEqual(jev_denetim.son_istek({"input": [call]}), "")
class Sor(unittest.TestCase):
def setUp(self):
jev_denetim._DEVRE.update(hata=0, kadar=0.0)
def test_request_shape_and_scores(self):
seen = {}
def gonder(govde, key, sure):
seen.update(govde=govde, key=key)
return {"answers": {k: {"type": "noul", "noul": 0.25} for k in jev_denetim.SORU}}
puan = jev_denetim.sor("istek", "c" * 9000, "anahtar", gonder=gonder)
self.assertEqual(puan, scores(0.25, 0.25, 0.25, 0.25))
self.assertEqual(seen["key"], "anahtar")
self.assertEqual(seen["govde"]["state"]["user_request"], "istek")
self.assertLess(len(seen["govde"]["state"]["assistant_reply"]), 6100) # long answers are cut
self.assertEqual(set(seen["govde"]["questions"]), {"ret", "sart", "teknik", "soru"})
def test_failures_pass_the_answer_and_open_the_breaker(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)) # breaker open: not called
self.assertEqual(len(calls), jev_denetim.DEVRE_HATA)
self.assertIsNone(jev_denetim.sor("i", "c", "k", gonder=bozuk, simdi=1000.0 + jev_denetim.DEVRE_SN + 1))
self.assertEqual(len(calls), jev_denetim.DEVRE_HATA + 1)
def test_key_is_read_from_env_or_file(self):
self.assertEqual(jev_denetim.anahtar({"TYPESAFE_API_KEY": " a "}), "a")
with tempfile.TemporaryDirectory() as d:
yol = os.path.join(d, "typesafe.env")
Path(yol).write_text('TYPESAFE_API_KEY="b"\n', encoding="utf-8")
self.assertEqual(jev_denetim.anahtar({}, [yol]), "b")
self.assertEqual(jev_denetim.anahtar({}, [os.path.join(d, "yok.env")]), "")
def test_settings(self):
self.assertEqual(jev_denetim.ayar_oku(None)[:2], (True, "ide/Uncensored-Uygulama"))
self.assertEqual(jev_denetim.ayar_oku({"enabled": False, "hedef": "ide/x"})[:2], (False, "ide/x"))
class Akis(unittest.TestCase):
"""_denetimli_akis through a fake handler: what reaches the client."""
def setUp(self):
self.logs = []
self.asked = []
self.puan = scores()
sahte = Mock()
sahte.SURE = 6.0
sahte.anahtar = lambda: "k"
sahte.sor = lambda istek, metin, key, sure: (self.asked.append((istek, metin)), self.puan)[1]
sahte.karar = jev_denetim.karar
env = {"jev_denetim": sahte, "yarim": yarim, "time": time, "http": __import__("http"), "log": self.logs.append,
"RESP_HOP": set(), "json": json}
adlar = ("_akis_basligi", "_denetimli_akis", "_stream")
exec(compile(ast.Module(body=[method(a) for a in adlar], type_ignores=[]), "kopru.py", "exec"), env)
self.h = type("H", (), {a: env[a] for a in adlar})()
self.h.wfile = io.BytesIO()
self.h.send_response = Mock()
self.h.send_header = Mock()
self.h.end_headers = Mock()
def sent(self):
"""Chunked body the client received, decoded."""
raw, out = self.h.wfile.getvalue(), b""
while raw:
size, _, rest = raw.partition(b"\r\n")
n = int(size, 16)
if n == 0:
break
out += rest[:n]
raw = rest[n + 2:]
return out
def test_a_passed_step_is_delivered_unchanged(self):
body = sse("Fenerbahçe'nin ", "13 puanı var.")
self.h._denetimli_akis(Yanit(body), "[1]", None, None, "kaç puan", {}, lambda: self.fail("fallback opened"))
self.assertEqual(self.sent(), body)
self.assertEqual(self.asked, [("kaç puan", "Fenerbahçe'nin 13 puanı var.")])
self.assertIn("gecti", self.logs[0])
def test_a_blocked_step_is_dropped_and_redone_by_the_fallback(self):
self.puan = scores(ret=0.9)
yedek = sse("Tamam, yaptım.")
self.h._denetimli_akis(Yanit(sse("Bunu yapamam.")), "[1]", None, None, "yap", {},
lambda: (Yanit(yedek), None, "[1 yedek]"))
self.assertEqual(self.sent(), yedek) # the refused text never reaches the client
self.assertNotIn(b"yapamam", self.h.wfile.getvalue())
self.assertTrue(any("GECMEDI" in s for s in self.logs))
self.h.send_response.assert_called_once() # headers once, although two upstream answers
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.h._denetimli_akis(Yanit(body), "[1]", None, None, "yap", {}, lambda: self.fail("fallback opened"))
self.assertEqual(self.sent(), body)
self.assertEqual(self.asked, [])
def test_unreachable_jev_or_fallback_keeps_the_first_answer(self):
self.puan = None
body = sse("Bunu yapamam.")
self.h._denetimli_akis(Yanit(body), "[1]", None, None, "yap", {}, lambda: self.fail("fallback opened"))
self.assertEqual(self.sent(), body)
self.h.wfile = io.BytesIO()
self.puan = scores(ret=0.9)
def bozuk():
raise OSError("yedek acilamadi")
self.h._denetimli_akis(Yanit(body), "[1]", None, None, "yap", {}, bozuk)
self.assertEqual(self.sent(), body)
if __name__ == "__main__":
unittest.main()