fix(codex-link): summarize with a subscription model, reject tiny summaries, describe added models
Model switch lost the conversation: on 10 Oct a 1 MB thread was compacted by the newly selected small model into 2201 characters. The compaction summary for a bridge model is now written by a subscription model (ozet_kopru.ozet_modeli, default gpt-6.1-sol); if that request is refused before it starts, the target model is used as before. A summary far shorter than the conversation warrants is not accepted: Codex gets response.failed and keeps the history. The line under each added model no longer repeats its name. Teams show their members, fallback chains their order, single models their provider and the traits readable from the name; the text fits one phone row (30 characters). Also normalizes tool call ids in the streamed response so Codex persists ids the subscription backend accepts (fc_ -> ctc_), and bumps the bridge protocol to 6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ce49d6d1cc
commit
adf73eeedd
7 files changed
+248
-13
No files matched your search
@@ -26,7 +26,7 @@ from resim_context import resimleri_sadelestir
|
||||
import ide_catalog
|
||||
import ozet_kopru
|
||||
|
||||
SURUM = "5"
|
||||
SURUM = "6"
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# Codex sends request bodies zstd-compressed. Python gained zstd in 3.14; for older
|
||||
@@ -191,7 +191,8 @@ def load_ide_catalog():
|
||||
if slug in model_map:
|
||||
continue
|
||||
extra_models.append({"slug": slug, "display_name": adlar[g["id"]],
|
||||
"description": f"AITURK IDE: {g['ad']}", "route": IDE_ROUTE, "target": g["id"],
|
||||
"description": g.get("aciklama") or f"AITURK IDE: {g['ad']}",
|
||||
"route": IDE_ROUTE, "target": g["id"],
|
||||
"clone_from": clone, "priority": 300 + n, "reasoning_levels": levels,
|
||||
"kind": g["kind"]})
|
||||
model_map[slug] = (IDE_ROUTE, g["id"], None)
|
||||
@@ -426,6 +427,9 @@ class SseRewriter:
|
||||
inp = args
|
||||
d["item"] = {"type": "custom_tool_call", "id": item.get("id"), "call_id": item.get("call_id"),
|
||||
"name": item.get("name"), "input": inp, "status": item.get("status", "completed")}
|
||||
# Normalize before Codex persists the response. Request-only repair
|
||||
# cannot help when the user later disables the bridge.
|
||||
fix_tool_ids({"input": [d["item"]]})
|
||||
return d
|
||||
if t.startswith("response.function_call_arguments.") and d.get("item_id") in self.custom_ids:
|
||||
return None # JSON parcalari custom input'a cevrilemez; done olayinda tam metin gidiyor
|
||||
@@ -437,6 +441,7 @@ class SseRewriter:
|
||||
except Exception: inp = item.get("arguments", "")
|
||||
item = {"type": "custom_tool_call", "id": item.get("id"), "call_id": item.get("call_id"),
|
||||
"name": item.get("name"), "input": inp, "status": "completed"}
|
||||
fix_tool_ids({"input": [item]})
|
||||
out.append(item)
|
||||
d["response"]["output"] = out
|
||||
return d
|
||||
@@ -678,6 +683,40 @@ class H(http.server.BaseHTTPRequestHandler):
|
||||
log(f"[{n} ozet kopru] OpenAI ozeti duz metne cevrildi ({len(metin)} karakter, onbellege yazildi)")
|
||||
return metin or None
|
||||
|
||||
def _ozet_openai(self, n, path, req, slug, ozet_cfg, girdi_bayt):
|
||||
"""Kopru modeline (ide/, 9r/) gelen sikistirma isteginin ozetini abonelik modeline yazdirir.
|
||||
Donus: True = yanit istemciye gitti; False = abonelik istegi baslamadan basarisiz oldu
|
||||
(istemciye hicbir sey yazilmadi, cagiran hedef modelle devam eder). req cagiranin kopyasidir."""
|
||||
model = ozet_cfg.get("ozet_modeli", "gpt-6.1-sol")
|
||||
tag = f"[{n} CHATGPT {model} <- {slug}]"
|
||||
try:
|
||||
req["model"] = model
|
||||
fix_tool_ids(req)
|
||||
atilan = drop_foreign_items(req)
|
||||
ozet_kopru.ozetleri_ac(req, yabanci_hedef=False)
|
||||
ozet_kopru.ozet_istegi_hazirla(req, ozet_cfg.get("istem"))
|
||||
body = json.dumps(req, ensure_ascii=False).encode("utf-8")
|
||||
except Exception as e:
|
||||
log(f"{tag} ozet kopru: abonelik ozeti hazirlanamadi ({type(e).__name__}: {e}), hedef model deneniyor")
|
||||
return False
|
||||
hdrs = {k: v for k, v in self.headers.items() if k.lower() not in REQ_HOP and k.lower() != "content-encoding"}
|
||||
hdrs["Content-Type"] = "application/json"; hdrs["Accept"] = "text/event-stream"
|
||||
r = urllib.request.Request(CHATGPT + path, data=body, headers=hdrs, method="POST")
|
||||
try:
|
||||
resp = urllib.request.urlopen(r, timeout=UPSTREAM_IDLE_TIMEOUT)
|
||||
except urllib.error.HTTPError as e:
|
||||
log(f"{tag} ozet kopru: abonelik ozeti reddedildi (HTTP {e.code} {e.read()[:200]!r}), hedef model deneniyor")
|
||||
return False
|
||||
except Exception as e:
|
||||
log(f"{tag} ozet kopru: abonelik ozeti baslatilamadi ({type(e).__name__}), hedef model deneniyor")
|
||||
return False
|
||||
log(f"{tag} ozet kopru: sikistirma ozeti abonelik modeline yazdiriliyor (girdi={len(req.get('input', []))} oge, "
|
||||
f"{girdi_bayt} bayt, {atilan} yabanci oge atildi)")
|
||||
akis = ozet_kopru.OzetAkisi(None, tohum=str(n), en_az=ozet_kopru.en_az_karakter(girdi_bayt, ozet_cfg))
|
||||
self._stream(resp, resp.status, tag, akis)
|
||||
log(f"{tag} ozet kopru: {akis.sonuc_notu()}")
|
||||
return True
|
||||
|
||||
def _models(self, resp, tag):
|
||||
raw = resp.read()
|
||||
try:
|
||||
@@ -797,8 +836,9 @@ class H(http.server.BaseHTTPRequestHandler):
|
||||
log(f"[{n} CHATGPT {slug}] ozet kopru: DONGU FRENI, ozet istegi reddedildi")
|
||||
return self._send_json(400, {"error": {"message": ozet_kopru.DONGU_MESAJI % OZET_FRENI.sinir,
|
||||
"type": "invalid_request_error", "code": "astrabridge_ozet_dongusu"}})
|
||||
girdi_bayt = len(json.dumps(req.get("input") or [], ensure_ascii=False).encode("utf-8"))
|
||||
ozet_kopru.ozet_istegi_hazirla(req, ozet_cfg.get("istem"))
|
||||
ozet_akisi = ozet_kopru.OzetAkisi(None, tohum=str(n))
|
||||
ozet_akisi = ozet_kopru.OzetAkisi(None, tohum=str(n), en_az=ozet_kopru.en_az_karakter(girdi_bayt, ozet_cfg))
|
||||
ob["acilan"] += 1
|
||||
log(f"[{n} CHATGPT {slug}] ozet kopru: sikistirma istegi duz metin ozet istegine cevrildi (girdi={len(req.get('input', []))} oge)")
|
||||
except Exception as e:
|
||||
@@ -816,7 +856,7 @@ class H(http.server.BaseHTTPRequestHandler):
|
||||
if parcalar: log(f"[{n} CHATGPT {slug}] " + ", ".join(parcalar))
|
||||
if ozet_akisi is not None:
|
||||
sonuc = self._passthrough(n, path, body, tagname=f"CHATGPT {slug}", rewritten=True, rewriter=ozet_akisi)
|
||||
log(f"[{n} CHATGPT {slug}] ozet kopru: ozet {'uretildi, ' + str(len(ozet_akisi.metin)) + ' karakter' if ozet_akisi.metin else 'URETILEMEDI'}")
|
||||
log(f"[{n} CHATGPT {slug}] ozet kopru: {ozet_akisi.sonuc_notu()}")
|
||||
return sonuc
|
||||
return self._passthrough(n, path, body, tagname=f"CHATGPT {slug}",
|
||||
rewritten=bool(fixed or atilan or degisti))
|
||||
@@ -826,11 +866,25 @@ class H(http.server.BaseHTTPRequestHandler):
|
||||
except Exception as e:
|
||||
ozet_tetik = False; ozet_acik = False
|
||||
log(f"[{n} {slug}] ozet kopru atlandi: {type(e).__name__}: {e}")
|
||||
girdi_bayt = 0
|
||||
if ozet_tetik:
|
||||
OZET_FRENI.sinir = int(ozet_cfg.get("dongu_siniri", 3)); OZET_FRENI.pencere = int(ozet_cfg.get("dongu_pencere_sn", 600))
|
||||
if not OZET_FRENI.izin(str(req.get("prompt_cache_key") or slug), time.time()):
|
||||
log(f"[{n} {slug}] ozet kopru: DONGU FRENI, ozet istegi reddedildi (ayni sohbette {OZET_FRENI.sinir} ozetten sonra)")
|
||||
return self._send_json(400, {"error": {"message": ozet_kopru.DONGU_MESAJI % OZET_FRENI.sinir,
|
||||
"type": "invalid_request_error", "code": "astrabridge_ozet_dongusu"}})
|
||||
girdi_bayt = len(json.dumps(req.get("input") or [], ensure_ascii=False).encode("utf-8"))
|
||||
if ozet_tetik and ozet_cfg.get("model"):
|
||||
# Ozeti baglami alabilen baska bir modele yazdirmak icin (ornegin kucuk hedef kendi basina ozetleyemiyorsa).
|
||||
alt = MODEL_MAP.get(ozet_cfg["model"])
|
||||
if alt:
|
||||
route_name, target, flat = alt
|
||||
elif ozet_tetik and ozet_cfg.get("ozetleyen", "openai") == "openai":
|
||||
# Ozeti secili kopru modeli degil, abonelikteki guclu model yazar (10 Ekim 2026: 1 MB'lik
|
||||
# sohbeti kucuk bir model 2201 karaktere indirdi ve model degisince hafiza gitti).
|
||||
# Abonelik istegi baslamadan reddedilirse asagidaki eski yol (hedef model) calisir.
|
||||
if self._ozet_openai(n, path, copy.deepcopy(req), slug, ozet_cfg, girdi_bayt):
|
||||
return
|
||||
# 9Router cevirisinden gecen hedefler (9Router ve AITURK IDE gecidi): ayni istek duzeltmeleri uygulanir.
|
||||
via_router = route_name in (catalog.get("route", "9router"), ide_route)
|
||||
route = ROUTES[route_name]
|
||||
@@ -844,11 +898,6 @@ class H(http.server.BaseHTTPRequestHandler):
|
||||
if ob["acilan"] or ob["cozulen"] or ob["okunamayan"]:
|
||||
log(f"{tag} ozet kopru: kopru ozeti={ob['acilan']}, OpenAI ozeti duz metne cevrildi={ob['cozulen']}, okunamayan={ob['okunamayan']}")
|
||||
if ozet_tetik:
|
||||
OZET_FRENI.sinir = int(ozet_cfg.get("dongu_siniri", 3)); OZET_FRENI.pencere = int(ozet_cfg.get("dongu_pencere_sn", 600))
|
||||
if not OZET_FRENI.izin(str(req.get("prompt_cache_key") or slug), time.time()):
|
||||
log(f"{tag} ozet kopru: DONGU FRENI, ozet istegi reddedildi (ayni sohbette {OZET_FRENI.sinir} ozetten sonra)")
|
||||
return self._send_json(400, {"error": {"message": ozet_kopru.DONGU_MESAJI % OZET_FRENI.sinir,
|
||||
"type": "invalid_request_error", "code": "astrabridge_ozet_dongusu"}})
|
||||
ozet_kopru.ozet_istegi_hazirla(req, ozet_cfg.get("istem"))
|
||||
log(f"{tag} ozet kopru: sikistirma istegi duz metin ozet istegine cevrildi (girdi={len(req.get('input', []))} oge)")
|
||||
rewriter = None
|
||||
@@ -919,9 +968,9 @@ class H(http.server.BaseHTTPRequestHandler):
|
||||
time.sleep(min(2 * attempt, 8)); continue
|
||||
# Headers go to the client from here on: a cut stream is never resent.
|
||||
if ozet_tetik:
|
||||
akis = ozet_kopru.OzetAkisi(rewriter, tohum=str(n))
|
||||
akis = ozet_kopru.OzetAkisi(rewriter, tohum=str(n), en_az=ozet_kopru.en_az_karakter(girdi_bayt, ozet_cfg))
|
||||
sonuc = self._stream(resp, resp.status, tag, akis)
|
||||
log(f"{tag} ozet kopru: ozet {'uretildi, ' + str(len(akis.metin)) + ' karakter' if akis.metin else 'URETILEMEDI'}")
|
||||
log(f"{tag} ozet kopru: {akis.sonuc_notu()}")
|
||||
return sonuc
|
||||
return self._stream(resp, resp.status, tag, rewriter)
|
||||
self._send_json(503, {"error": {"message": f"bridge: hedef ulasilamadi {last}"}})
|
||||
|
||||
Reference in new issue
Block a user