Ship beta34 with external agent tasks, terminal SSE and live token limits
Server CI and Windows package / verify (push) Successful in 3m13s
Server CI and Windows package / windows-package (push) Successful in 7m56s

This commit is contained in:
yilsem committed 2026-10-13 07:32:57 +03:00
1 parent 2cca6a66a6
commit ab7a721fbc
13 files changed
+93 -20

No files matched your search

+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
- name: Codex bridge regression tests
run: '"$RUNNER_TEMP/ci-venv/bin/python" -m unittest discover -s apps/desktop/assets/codex-bridge'
- name: Native watch and speech mux pytest regressions
run: '"$RUNNER_TEMP/ci-venv/bin/python" -m pytest apps/desktop/assets/codex-bridge/test_bekci_watch.py apps/desktop/assets/codex-bridge/test_native_speech_mux.py -q -p no:cacheprovider -rf'
run: '"$RUNNER_TEMP/ci-venv/bin/python" -m pytest apps/desktop/assets/codex-bridge/test_bekci_watch.py apps/desktop/assets/codex-bridge/test_native_speech_mux.py apps/desktop/assets/codex-bridge/test_live_limits.py -q -p no:cacheprovider -rf'
- name: Mobile and desktop startup regression tests
run: |
npm install --prefix "$RUNNER_TEMP/mobile-tests" --no-save --ignore-scripts --no-audit --no-fund --legacy-peer-deps vitest@4.1.10 ws@8.21.1
+5 -2
View File
@@ -25,6 +25,8 @@ ayrıntı seviyesi, korunacak mesajlaşmalar, yüzde/token bütçesi ve otomatik
seçimini sunar. Varsayılanlar: Gemini 3.8 Flash High, yedek Gemini 3 Flash,
10 mesajlaşma, geçişte %70, otomatik tetiklemede %70 ve sonrasında %50.
Kapasite bağlantıdan gelen model bilgisiyle hesaplanır; 272K genel tavan yoktur.
`/models` içindeki doğrulanmış sayısal bağlam bilgisi, model adından çıkarılan
yerel varsayılandan önce gelir; gözlenmiş daha düşük bir gerçek sınır korunur.
Girdi hesabı talimatlar ve araçları da içeren temkinli bir token tahminidir.
Abonelik modellerinin kendi aralarındaki istekler ve GPT-Live ses yolu özgün
@@ -58,8 +60,9 @@ npm run builder --workspace=apps/desktop -- --win nsis --x64 --publish never
Dağıtılacak derleme temiz, yayımlanmış Git commit'inden üretilmelidir. İlk açılış
ajan kurulumunu paketteki `install-stamp.json` commit'ine sabitler. Windows
imzası ve temiz kurulum doğrulanmadan bir paket doğrulanmış üretim sürümü diye
sunulmamalıdır. macOS ve Linux paketleri bu beta kapsamında doğrulanmamıştır.
paketleri imzasız EXE/ZIP olarak yayımlanır; SHA-256 ve gerçek Windows çalıştırma
kontrolü gereklidir. Kullanıcı açıkça istemeden imzalama yapılmaz. macOS ve Linux
paketleri bu beta kapsamında doğrulanmamıştır.
## Lisans ve kaynak
+1 -1
View File
@@ -34,7 +34,7 @@ import urllib.request
import gecis_context
HERE = os.path.dirname(os.path.abspath(__file__))
SURUM = "14" # AITURK IDE'nin bekledigi kopru surumu (codex-link-config.ts CODEX_BRIDGE_VERSION)
SURUM = "15" # AITURK IDE'nin bekledigi kopru surumu (codex-link-config.ts CODEX_BRIDGE_VERSION)
try:
with open(os.path.abspath(__file__), "rb") as _f:
KOD = hashlib.sha256(_f.read()).hexdigest()[:8]
@@ -104,6 +104,18 @@ def portable_reasoning(req):
return out
result = []
for item in items:
if isinstance(item, dict) and item.get("type") == "agent_message":
# Peer messages carry delegated tasks/results. External Responses
# translators do not understand this Codex-specific item type.
# Keep provenance as data, never as system/developer authority.
content = item.get("content") or []
if isinstance(content, str):
content = [{"type": "input_text", "text": content}]
result.append({"type": "message", "role": "user", "content": [
{"type": "input_text", "text": "Agent message: " + encoded({
"author": item.get("author"), "recipient": item.get("recipient")})}
] + content})
continue
if not isinstance(item, dict) or item.get("type") != "reasoning":
result.append(item)
continue
@@ -348,11 +348,13 @@ def yukle(ua="AstraBridge/1.0 (codex)", timeout=30, home=None, ag=True):
if not girdiler:
raise ValueError("Gecitte kullanilabilir OmniRoute sohbet modeli yok")
kayitlar = {m["id"]: m for m in metadata if m.get("id")}
ilanlar = {m["id"]: m for m in data if m.get("id")}
nano = pencere.nano_yukle(home, ua, ag=ag) # ag=False: acilista yalniz onbellek
ogr = pencere.ogrenilen(home)
aracsiz = pencere.aracsizlar(home)
for g in girdiler:
bilgi = pencere.coz(g["id"], g["kind"], g.get("yol"), kayitlar.get(g["id"]), nano, ogr, aracsiz)
bilgi = pencere.coz(g["id"], g["kind"], g.get("yol"), kayitlar.get(g["id"]), nano, ogr, aracsiz,
ilan=ilanlar.get(g["id"]))
g["pencere"], g["gorsel"], g["arac"], g["pencere_kaynak"] = (bilgi["pencere"], bilgi["gorsel"],
bilgi["arac"], bilgi["kaynak"])
g["claude"] = pencere.claude_var(g["kind"], g.get("yol"), kayitlar.get(g["id"]))
+13 -9
View File
@@ -40,7 +40,7 @@ from bekci_watch import MetadataFilter
# Installed only by owned native launcher, never an HTTP control endpoint.
WATCH_OWNER = None
SURUM = "14"
SURUM = "15"
HERE = os.path.dirname(os.path.abspath(__file__))
try:
with open(os.path.abspath(__file__), "rb") as _f:
@@ -365,6 +365,10 @@ def arac_semalarini_duzelt(req):
def flatten_request(req, tool_names=None):
"""additional_tools/namespace/custom -> duz function tools. Donus: custom arac adlari kumesi."""
if isinstance(req.get("input"), list) and any(
isinstance(item, dict) and item.get("type") == "agent_message" for item in req["input"]):
import gecis_context
req["input"] = gecis_context.portable_reasoning(req)["input"]
custom = set()
tools = []
tool_names = tool_names if tool_names is not None else {}
@@ -1031,13 +1035,13 @@ class H(http.server.BaseHTTPRequestHandler):
if jev_denetim.muaf_mi(hedef):
return self._stream(resp, resp.status, tag, rewriter, izle, basliksiz=True)
if gecmedi:
# Son katman ne dondurduyse o gider, hicbir sey eklenmez; dondurmediyse hicbir sey gitmez.
if son_govde:
w(son_govde)
else:
event = {"type": "response.failed", "response": {"status": "failed", "error": {
"code": "jev_no_fallback", "message": "Jev denetiminden gecen cevap alinamadi; gecis kurallarini kontrol edin."}}}
w(b"event: response.failed\ndata: " + json.dumps(event).encode() + b"\n\n")
# Headers already declare SSE. A raw upstream JSON/HTML body
# here leaves Codex waiting for a terminal event and retrying.
event = {"type": "response.failed", "response": {
"id": "resp_astrabridge_%d" % time.time_ns(),
"object": "response", "status": "failed", "output": [], "error": {
"code": "jev_no_fallback", "message": "Jev denetiminden gecen cevap alinamadi; gecis kurallarini kontrol edin."}}}
w(b"event: response.failed\ndata: " + json.dumps(event).encode() + b"\n\n")
else:
for chunk in parcalar:
if izle is not None:
@@ -1747,7 +1751,7 @@ class H(http.server.BaseHTTPRequestHandler):
yanit = urllib.request.urlopen(urllib.request.Request(
jev_rota["url"], data=json.dumps(katman_req, ensure_ascii=False).encode("utf-8"), headers=jev_hdrs, method="POST"),
timeout=UPSTREAM_IDLE_TIMEOUT)
return (yanit, SseRewriter(custom, hedef=ad, tasma=self._tasma_ogren, aracsiz=self._aracsiz_ogren),
return (yanit, SseRewriter(custom, hedef=ad, tasma=self._tasma_ogren, aracsiz=self._aracsiz_ogren, tool_names=tool_names),
f"[{n} {slug}=>{ad}]")
# 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);
+8 -1
View File
@@ -221,7 +221,7 @@ def _yapraklar(dugum, derinlik=0):
return cikti
def coz(kimlik, tur, yol, kayit=None, nano=None, ogr=None, aracsiz=()):
def coz(kimlik, tur, yol, kayit=None, nano=None, ogr=None, aracsiz=(), ilan=None):
"""Bir katalog girdisinin ilan edilecek penceresi ve yetenekleri.
kimlik: gecit kimligi; tur: "combo" | "model"; yol: gecidin aciklamasindaki "saglayici/model" yolu;
kayit: /router/catalog girdisi (combo topolojisi icin). Donus: {"pencere","gorsel","arac","kaynak"}."""
@@ -246,6 +246,13 @@ def coz(kimlik, tur, yol, kayit=None, nano=None, ogr=None, aracsiz=()):
m = re.match(r"no-think-(?:9router-)?([a-z0-9]+)-", kimlik or "")
yol = (m.group(1) + "/" + yol[len("no-think/"):]) if m else yol
sonuc = yol_bilgisi(yol, nano) or dict(bilinmeyen)
# Exact /models metadata is stronger evidence than name-based local
# fallbacks. Do not infer a combo's capacity from its display name.
ilan = ilan if isinstance(ilan, dict) else {}
canli_sinirlar = [ilan[k] for k in ("context_length", "max_input_tokens")
if type(ilan.get(k)) is int and TABAN <= ilan[k] <= 10_000_000]
if canli_sinirlar:
sonuc = {**sonuc, "pencere": min(canli_sinirlar), "kaynak": "saglayici-katalogu"}
if kimlik in aracsiz:
sonuc = {**sonuc, "arac": False}
sinir = (ogr or {}).get(kimlik)
@@ -22,6 +22,26 @@ from test_model_switch import env
class History(unittest.TestCase):
def test_agent_task_survives_external_projection_and_recent_history(self):
task = {"type": "agent_message", "id": "amsg_task", "author": "/root",
"recipient": "/root/child", "content": [
{"type": "input_text", "text": "Message Type: NEW_TASK\nRun CHILD_TOOL_410962"}]}
req = {"input": [{"role": "user", "content": "Old setup"}, task]}
before = copy.deepcopy(req)
self.assertEqual(gc.normalize(req), before)
projected = gc.portable_reasoning(req)
message = projected["input"][-1]
self.assertEqual(message["role"], "user")
self.assertEqual(message["content"][1:], task["content"])
self.assertIn('/root/child', message["content"][0]["text"])
self.assertNotIn("id", message)
self.assertEqual(gc.split_history(projected["input"], keep_users=1)[2], [message])
self.assertEqual(req, before)
self.assertEqual(gc.portable_reasoning(projected), projected)
direct = copy.deepcopy(req)
env["flatten_request"](direct)
self.assertEqual(direct["input"][-1], message)
def test_native_function_results_are_not_foreign_or_renamed(self):
req = {"input": [{"type": "function_call_output", "id": "fco_native",
"call_id": "call_native", "output": "kept"}]}
@@ -335,7 +335,7 @@ class Akis(unittest.TestCase):
self.assertNotIn(b"yapamam", self.h.wfile.getvalue())
self.assertIn(b'response.failed', self.sent())
def test_the_last_layers_own_error_body_is_delivered_untouched(self):
def test_last_layer_http_error_terminates_sse_without_leaking_raw_body(self):
class Hata(Exception):
def read(self):
return b'{"error": {"message": "katman 4 hatasi"}}'
@@ -344,7 +344,14 @@ class Akis(unittest.TestCase):
def ac(ad):
raise Hata("HTTP 400")
self.h._denetimli_akis(Yanit(sse("Bunu yapamam.")), "[1]", None, None, "yap", ["Katman-4"], ac)
self.assertEqual(self.sent(), b'{"error": {"message": "katman 4 hatasi"}}')
raw = self.sent()
self.assertTrue(raw.startswith(b"event: response.failed\ndata: "))
event = json.loads(raw.split(b"data: ", 1)[1])
self.assertEqual(event["response"]["status"], "failed")
self.assertEqual(event["response"]["error"]["code"], "jev_no_fallback")
self.assertEqual(event["response"]["output"], [])
self.assertNotIn(b"katman 4 hatasi", raw)
self.assertNotIn(b"Bunu yapamam", raw)
def test_unreachable_jev_keeps_the_answer(self):
self.puanlar = [None]
@@ -0,0 +1,18 @@
import pencere
def test_exact_combo_limits_override_unknown_and_local_defaults():
row = {"context_length": 872000, "max_input_tokens": 872000, "max_output_tokens": 128000}
result = pencere.coz("GPT-6-Astra", "combo", None, ilan=row)
assert result["pencere"] == 872000
assert result["kaynak"] == "saglayici-katalogu"
result = pencere.coz("codex-gpt-6-astra", "model", "codex/gpt-6-astra", ilan=row)
assert result["pencere"] == 872000
def test_learned_actual_limit_still_wins_and_invalid_metadata_is_ignored():
result = pencere.coz("combo", "combo", None, ilan={"context_length": 872000}, ogr={"combo": 500000})
assert result["pencere"] == 500000 and result["kaynak"] == "ogrenilen"
for value in (True, -1, "872000", 999999999):
result = pencere.coz("combo", "combo", None, ilan={"context_length": value})
assert result["pencere"] == pencere.VARSAYILAN
+1 -1
View File
@@ -27,7 +27,7 @@ export const CODEX_LINK_REFRESH_URL = `${CODEX_LINK_ORIGIN}/aiturk/codex-baglama
export const CODEX_LINK_MARKER = '# AITURK IDE Codex Baglama'
// Must equal SURUM in assets/codex-bridge/bridge.py; a running bridge that reports
// another version is restarted so an updated IDE never keeps an old bridge alive.
export const CODEX_BRIDGE_VERSION = '14'
export const CODEX_BRIDGE_VERSION = '15'
export const CODEX_LINK_LINE = `openai_base_url = "${CODEX_LINK_ORIGIN}/backend-api/codex" ${CODEX_LINK_MARKER}`
export const CODEX_LINK_RUN_KEY = 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run'
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "aiturk-ide",
"productName": "AITURK IDE",
"private": true,
"version": "1.0.0-beta.33",
"version": "1.0.0-beta.34",
"description": "TurkServis resmi yapay zekâ geliştirme ortamı. Hermes Agent tabanlıdır.",
"author": "AITURK / TurkServis",
"repository": {
+1 -1
View File
@@ -65,7 +65,7 @@
},
"apps/desktop": {
"name": "aiturk-ide",
"version": "1.0.0-beta.33",
"version": "1.0.0-beta.34",
"license": "MIT",
"dependencies": {
"@assistant-ui/core": "0.2.23",