feat(codex-bridge): web search for added models, forgiving spoken model names

Added models had no web search: Codex's built-in one runs on OpenAI's side and
the bridge drops it from their tool list. Measured in a voice session on
11 Oct 2026: a model looked for a search tool ten times and ended the turn
with no answer. The bridge now tells added models two ready commands (ara.py:
search and read a page, standard library only, no key). Codex's own models
never see the note: their requests do not reach the bridge.

Spoken model names: a half-spoken word matches the start of a name part
("think" -> thinking, "obli" -> obliterated), and when one candidate is the
others minus extra words, the one without the unsaid suffix is picked
("Qwen 3.8 Obliterated" -> not the ":thinking" one).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
yilsemandClaude Opus 5.5 committed 2026-10-11 07:25:30 +03:00
1 parent 23e8aa8191
commit c8993d58cc
6 files changed
+265 -2

No files matched your search

+106
View File
@@ -0,0 +1,106 @@
"""Internet aramasi ve sayfa okuma: Codex'e sonradan eklenen modeller icin (11 Ekim 2026).
Codex'in yerlesik web aramasi OpenAI sunucusunda calisir ve yalniz Codex'in kendi modellerine verilir; kopru onu
ek modele giden arac listesinden atar. Ek model aramayi bu betigi kabuk araciyla calistirarak yapar (internet.py
modele komutu soyler). Anahtar gerekmez; yalniz standart kitaplik.
python ara.py ara "sorgu" [--adet 8]
python ara.py oku <adres> [--en-cok 8000]
"""
import argparse
import html
import re
import sys
import urllib.parse
import urllib.request
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36"
ARAMA = "https://html.duckduckgo.com/html/?"
SURE = 25
EN_COK_BAYT = 3_000_000
def indir(adres, sure=SURE):
adres = urllib.parse.quote(adres, safe=":/?#[]@!$&'()*+,;=%~") # Turkce harfli adres ("/wiki/Türkiye")
istek = urllib.request.Request(adres, headers={"User-Agent": UA, "Accept-Language": "tr,en;q=0.8"})
with urllib.request.urlopen(istek, timeout=sure) as yanit:
ham = yanit.read(EN_COK_BAYT)
kodlama = yanit.headers.get_content_charset() or "utf-8"
tur = yanit.headers.get_content_type()
try:
return ham.decode(kodlama, "replace"), tur
except LookupError:
return ham.decode("utf-8", "replace"), tur
def _duz(parca):
return re.sub(r"\s+", " ", html.unescape(re.sub(r"<[^>]+>", "", parca))).strip()
def sonuclari_coz(sayfa, adet=8):
"""Arama sayfasindan [(baslik, adres, ozet)]."""
cikti = []
for blok in re.split(r'<div[^>]+class="[^"]*\bresult\b[^"]*"', sayfa)[1:]:
bag = re.search(r'<a[^>]+class="result__a"[^>]+href="([^"]+)"[^>]*>(.*?)</a>', blok, re.S)
if not bag:
continue
adres = html.unescape(bag.group(1))
ic = re.search(r"[?&]uddg=([^&]+)", adres)
if ic:
adres = urllib.parse.unquote(ic.group(1))
if adres.startswith("//"):
adres = "https:" + adres
if "duckduckgo.com/y.js" in adres: # reklam
continue
ozet = re.search(r'class="result__snippet"[^>]*>(.*?)</a>', blok, re.S)
cikti.append((_duz(bag.group(2)), adres, _duz(ozet.group(1)) if ozet else ""))
if len(cikti) >= adet:
break
return cikti
def metne_cevir(sayfa):
"""HTML -> okunur duz metin (betik, bicim ve gezinme kisimlari atilir)."""
sayfa = re.sub(r"(?is)<(script|style|noscript|svg|nav|footer|header|form|iframe)\b.*?</\1>", " ", sayfa)
sayfa = re.sub(r"(?is)<!--.*?-->", " ", sayfa)
sayfa = re.sub(r"(?i)<(br|/p|/div|/li|/h[1-6]|/tr)\b[^>]*>", "\n", sayfa)
metin = html.unescape(re.sub(r"<[^>]+>", " ", sayfa))
satirlar = [re.sub(r"[ \t\r\f\v]+", " ", s).strip() for s in metin.split("\n")]
return "\n".join(s for s in satirlar if s)
def ara(sorgu, adet=8, indirici=indir):
sayfa, _ = indirici(ARAMA + urllib.parse.urlencode({"q": sorgu}))
sonuc = sonuclari_coz(sayfa, adet)
if not sonuc:
return "Sonuç bulunamadı. Sorguyu daha kısa ya da farklı sözcüklerle yeniden dene."
return "\n\n".join(f"{i}. {b}\n {a}\n {o}" for i, (b, a, o) in enumerate(sonuc, 1))
def oku(adres, en_cok=8000, indirici=indir):
if not re.match(r"https?://", adres):
adres = "https://" + adres
sayfa, tur = indirici(adres)
metin = metne_cevir(sayfa) if "html" in tur or "<html" in sayfa[:2000].lower() else sayfa
if len(metin) > en_cok:
metin = metin[:en_cok] + f"\n[... kesildi: {len(metin)} karakterin ilk {en_cok} karakteri]"
return metin or "Sayfada okunur metin bulunamadı."
def main(argv=None):
p = argparse.ArgumentParser(description="Internet aramasi ve sayfa okuma")
alt = p.add_subparsers(dest="is_", required=True)
a = alt.add_parser("ara"); a.add_argument("sorgu", nargs="+"); a.add_argument("--adet", type=int, default=8)
o = alt.add_parser("oku"); o.add_argument("adres"); o.add_argument("--en-cok", type=int, default=8000)
s = p.parse_args(argv)
try:
metin = ara(" ".join(s.sorgu), max(1, min(s.adet, 20))) if s.is_ == "ara" else oku(s.adres, max(500, s.en_cok))
kod = 0
except Exception as e:
metin, kod = f"Hata: {type(e).__name__}: {e}", 1
sys.stdout.buffer.write((metin + "\n").encode("utf-8", "replace"))
return kod
if __name__ == "__main__":
sys.exit(main())