"""Katman denetimi: Jev, katman combosunun her adimdaki cevabini gecirir ya da gecirmez (11 Ekim 2026). Kullanici karari (11 Ekim 2026): "Jev kati olsun. Af yok istisna yok. Herhangi bir model Jev'e gelirse Jev bunu 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 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 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. Metni olmayan (yalniz arac cagiran) adimda sorulacak cevap yoktur. Jev'e ulasilamazsa cevap oldugu gibi verilir. """ import json import os import re import urllib.request import jev_settings ADRES = "https://api.typesafe.ai/v1/systemone" MODEL = "jev-1.13.0" 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, " "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."), } _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. Taşıma hatalarının katman sırasını değiştirmez; yedek model kendi adına denetlenir. """ return hedef in jev_settings.read()[0]['exemptModels'] def sonrakiler(hedef): """Model-specific rejection edges take precedence over the general fallback. Stop at an always-pass model or before revisiting any target. """ settings = jev_settings.read()[0] ad = str(hedef or "") if not settings['enabled'] or not ad: return [] routes = {r['from']: r['to'] for r in settings['rejectionRules']} result, seen = [], {ad} # An exempt model can still use the general fallback on transport failure. # Repeated targets stop the walk even if a file was edited outside Settings. while len(result) < 65: target = routes.get(ad, settings['fallbackModel']) if target in seen: break seen.add(target) result.append(target) if target in settings['exemptModels']: break ad = target return result def anahtar(ortam=None, dosyalar=None): """TypeSafe anahtari: ortam degiskeni, sonra ~/.typesafe/typesafe.env. Yoksa "".""" if ortam is None and dosyalar is None: saved = jev_settings.key() if saved: return saved 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 icindeki soz; baska sarmalli sistem mesajlari (kanca baglami) atlanir.""" 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".*?(.*?)", metin, re.S) if m: return m.group(1).strip(), sira if metin and not metin.startswith("<"): return metin, sira return "", -1 def hazirlik_mi(govde): """Araç çağrısı veya commentary görüldüyse adım nihai cevap değildir. Tam SSE satırları üzerinden bakılır; parçalı olay bir sonraki parçada tamamlanır. Araç argümanında geçen olay adı hazırlık sayılmaz. """ for satir in govde.splitlines(): if not satir.startswith(b'data:'): continue try: olay = json.loads(satir[5:]) except (ValueError, UnicodeDecodeError): continue if not isinstance(olay, dict): continue tip = str(olay.get('type') or '') oge = olay.get('item') or {} if tip in ('response.output_item.added', 'response.output_item.done') and isinstance(oge, dict): if str(oge.get('type') or '').endswith('_call') or oge.get('phase') == 'commentary': return True if tip in ('response.function_call_arguments.delta', 'response.function_call_arguments.done', 'response.custom_tool_call_input.delta', 'response.custom_tool_call_input.done'): return True return False def komutlar(govde): """Yazisi olmayan adimda Jev'e giden metin: modelin bu adimda cagirdigi araclar (ad ve arguman). govde: ust kaynagin SSE yaniti (bayt). Arac cagrisi yoksa "".""" satirlar = [] for satir in govde.splitlines(): if not satir.startswith(b"data:") or b"response.output_item.done" not in satir: continue try: oge = json.loads(satir[5:]).get("item") or {} except (ValueError, AttributeError): continue if isinstance(oge, dict) and str(oge.get("type") or "").endswith("_call"): arguman = oge.get("arguments") or oge.get("input") or oge.get("action") or "" if not isinstance(arguman, str): arguman = json.dumps(arguman, ensure_ascii=False) satirlar.append(f"[komut] {oge.get('name') or oge.get('type')}: {arguman}") return "\n".join(satirlar) 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=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, 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: govde['questions'][name]['criteria'] = values if not jev_settings.acquire(settings): return None 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 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'] return result except Exception: return None finally: jev_settings.release() def karar(puan): """True: adim gecmez, sonraki katman yapar. Istisna yok.""" thresholds = getattr(puan, 'thresholds', None) or jev_settings.read()[0]['thresholds'] return puan["ret"] >= thresholds["ret"] or puan["sart"] >= thresholds["sart"] def hata_gecis(): return jev_settings.read()[0]['failureAction'] == 'next' def etkin_mi(): return bool(jev_settings.read()[0]['enabled'])