Measured with the unmodified Codex binary on 10 Oct 2026: - real context windows per model (NanoGPT list, local table, combo = its smallest member, capped at the summarizer's window) so Codex compacts by itself when switching to a smaller model; an overflow guard trims oversized old parts and reports what still does not fit - classic tools instead of code mode for external models: GLM 0/3 -> 3/3, Qwen 0/3 -> 2/3 on simple tool tasks, Claude/cx/Gemini unchanged - phase (commentary / final_answer) on external assistant messages - an answer cut by the client is carried to the next turn once - images stay for vision-capable targets - summary brake stops tight loops, not frequent compaction - permanent gateway errors and tool-less targets fail at once with a readable message instead of five reconnects - a lone "." (used to apply a model change in voice) is answered locally - the bridge listens within seconds; the IDE waits 45 s for it Release: AITURK IDE 1.0.0-beta.26. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
112 lines
5.1 KiB
Python
112 lines
5.1 KiB
Python
"""9Router'a giden isteklerde resim, video, ses, PDF ve dev içerikleri sadeleştirir (24 Eylül 2026, kullanıcı onayı).
|
||
|
||
Sorun: Codex, image_gen aracının ürettiği resmi (≈3 MB base64 PNG) araç çıktısı olarak sohbete geri koyuyor.
|
||
9Router'ın Claude çevirisi bunu düz yazı sayıyor: istek 3 milyon token'a çıktı ("prompt is too long:
|
||
3040251 tokens > 1000000 maximum") ve sohbetteki sonraki HER tur 400 ile düştü; sohbet kurtarılamadı.
|
||
Aynısı video, ses, PDF/dosya ve çok büyük araç çıktılarıyla da olabilir (kullanıcı isteği: "tekrar böyle sorun olmasın").
|
||
|
||
Kural:
|
||
- Medya parçaları (resim, dosya/PDF, ses, video): araç çıktılarında ve eski mesajlarda kısa notla değiştirilir.
|
||
Kullanıcının SON mesajındaki medya toplamı TUT_BAYT'ı aşmıyorsa korunur (yeni eklenen dosyayı model görebilsin).
|
||
- Tür ne olursa olsun tek başına DEV_BAYT'tan büyük her parça (son mesajdaki korunanlar hariç) notla değiştirilir.
|
||
- Düz yazı araç çıktısı DEV_BAYT'tan büyükse başı ve sonu kalır, ortası notla kısaltılır.
|
||
Codex'in kendi kaydına dokunulmaz; yalnız 9Router'a giden kopya değişir.
|
||
"""
|
||
import json
|
||
|
||
TUT_BAYT = 1_000_000
|
||
DEV_BAYT = 1_000_000
|
||
RESIM_TUT_BAYT = TUT_BAYT # eski ad
|
||
MEDYA_TURLERI = {'input_image': 'resim', 'image': 'resim', 'image_url': 'resim',
|
||
'input_file': 'dosya/PDF', 'file': 'dosya/PDF',
|
||
'input_audio': 'ses', 'audio': 'ses',
|
||
'input_video': 'video', 'video': 'video'}
|
||
|
||
|
||
def _boyut(p):
|
||
try:
|
||
return len(json.dumps(p, ensure_ascii=False))
|
||
except (TypeError, ValueError):
|
||
return len(str(p))
|
||
|
||
|
||
def _medya_mi(p):
|
||
return isinstance(p, dict) and p.get('type') in MEDYA_TURLERI
|
||
|
||
|
||
def _not(p):
|
||
tur = MEDYA_TURLERI.get(p.get('type'), p.get('type') or 'içerik') if isinstance(p, dict) else 'içerik'
|
||
ad = p.get('filename') or p.get('file_path') or p.get('path') or '' if isinstance(p, dict) else ''
|
||
ek = f' ({ad})' if ad else ''
|
||
return {'type': 'input_text',
|
||
'text': f'[{tur}{ek} çıkarıldı (AstraBridge): bu yoldan gönderilemiyor, ~{_boyut(p) // 1024} KB; '
|
||
'gerekirse dosyayı yolundan aç]'}
|
||
|
||
|
||
def _kisalt(metin):
|
||
yarim = DEV_BAYT // 4
|
||
return (metin[:yarim] + f'\n[... {len(metin) - 2 * yarim} karakter çıkarıldı (AstraBridge): çıktı çok büyüktü ...]\n'
|
||
+ metin[-yarim:])
|
||
|
||
|
||
def resimleri_sadelestir(req, tut_bayt=TUT_BAYT, gorsel=False):
|
||
"""(değiştirilen parça sayısı, kazanılan bayt). req['input'] yerinde değişir.
|
||
gorsel=True (hedef model resim görebiliyor): eski KULLANICI mesajlarındaki resimler de, en yeniden eskiye
|
||
toplam tut_bayt'ı aşmadıkça korunur (10 Ekim 2026: resim görebilen modele geçince "göremiyorum" diyordu).
|
||
Araç çıktılarındaki medya her durumda notla değiştirilir."""
|
||
inp = req.get('input')
|
||
if not isinstance(inp, list):
|
||
return 0, 0
|
||
son_kullanici = None
|
||
for i, it in enumerate(inp):
|
||
if isinstance(it, dict) and it.get('type') == 'message' and it.get('role') == 'user':
|
||
son_kullanici = i
|
||
koru = set()
|
||
if son_kullanici is not None:
|
||
icerik = inp[son_kullanici].get('content')
|
||
if isinstance(icerik, list):
|
||
medya = [p for p in icerik if _medya_mi(p)]
|
||
if medya and sum(_boyut(p) for p in medya) <= tut_bayt:
|
||
koru.add(son_kullanici)
|
||
if gorsel:
|
||
kalan = tut_bayt - sum(_boyut(p) for i in koru for p in inp[i].get('content') or [] if _medya_mi(p))
|
||
for i in range(len(inp) - 1, -1, -1):
|
||
it = inp[i]
|
||
if i in koru or not (isinstance(it, dict) and it.get('type') == 'message' and it.get('role') == 'user'):
|
||
continue
|
||
icerik = it.get('content')
|
||
resimler = [p for p in icerik if _medya_mi(p) and MEDYA_TURLERI.get(p.get('type')) == 'resim'] \
|
||
if isinstance(icerik, list) else []
|
||
diger = [p for p in icerik if _medya_mi(p) and p not in resimler] if isinstance(icerik, list) else []
|
||
boyut = sum(_boyut(p) for p in resimler)
|
||
if resimler and not diger and boyut <= kalan:
|
||
koru.add(i)
|
||
kalan -= boyut
|
||
sayi = kazanc = 0
|
||
for i, it in enumerate(inp):
|
||
if not isinstance(it, dict) or i in koru:
|
||
continue
|
||
for alan in ('content', 'output'):
|
||
deger = it.get(alan)
|
||
if isinstance(deger, str) and len(deger) > DEV_BAYT:
|
||
yeni = _kisalt(deger)
|
||
kazanc += len(deger) - len(yeni)
|
||
sayi += 1
|
||
it[alan] = yeni
|
||
continue
|
||
if not isinstance(deger, list):
|
||
continue
|
||
degisti = False
|
||
yeni_liste = []
|
||
for p in deger:
|
||
if _medya_mi(p) or _boyut(p) > DEV_BAYT:
|
||
kazanc += _boyut(p)
|
||
sayi += 1
|
||
degisti = True
|
||
yeni_liste.append(_not(p))
|
||
else:
|
||
yeni_liste.append(p)
|
||
if degisti:
|
||
it[alan] = yeni_liste
|
||
return sayi, kazanc
|