Files
aiturk-hermes-ide/apps/desktop/assets/codex-bridge
yilsemandClaude Opus 5.5 959f5f1459 feat(codex-bridge): change the chat model by saying so; bridge 8, IDE 1.0.0-beta.27
A model picked on the phone only arrives with a typed message that starts a turn. The bridge now
handles "modeli X yap" itself: per-chat routing, same-turn handover when a model is working,
truthful answer to "which model", and a lone "." joining a running turn no longer cuts the work.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:05:18 +03:00
..

AITURK IDE Codex bridge

Local HTTP proxy that AITURK IDE's Settings → Codex Bağlama runs for OpenAI Codex (desktop or CLI) on the same computer. Standard-library Python only; it runs on the agent venv's interpreter and keeps running after the IDE window closes, because Codex depends on it while openai_base_url points here.

  • bridge.py: the proxy. Subscription models go to chatgpt.com unchanged; ide/<id> models go to the AITURK gateway configured in the agent's config.yaml, with the key read from the agent's .env on every catalog refresh (never written elsewhere).
  • ide_catalog.py: which IDE models and combos are added to Codex's model list and how they are named (provider/model, combos by bare name). The public /models catalog supplies every OmniRoute chat model; a member does not need a private local model allowlist. /router/catalog supplies only the kind metadata used for sorting, never additional model IDs. Direct 9Router entries and internal 9Router combos are excluded. Combos sort A–Z first, then individual models by provider and name, including OpenAI subscription models. Codex labels the first visible row isDefault; a saved model selection remains unchanged. A failed or empty refresh keeps the last successful catalog.
  • ozet_kopru.py: conversation summaries are produced as plain text, so a summary made by one provider stays readable after the user switches to another.
  • gemini_context.py, resim_context.py: request fixes for routed models.

Run: python bridge.py --home <data dir> --hermes-home <agent home>. The IDE writes <data dir>/bridge.json and reads GET /aiturk/codex-baglama/status; POST /aiturk/codex-baglama/stop ends the process.

Tests: python -m unittest discover in this directory.

Version 8 (IDE beta.27): changing the model by saying so

Measured on a live voice chat (11 Oct 2026): a model picked on the phone reaches this machine only with a typed message that STARTS a turn; a message that joins a running turn (including the lone .) does not carry it. model_gecis.py therefore handles the change in the bridge. A short user message such as "modeli gemini flash low yap" (spoken through the voice assistant or typed) is matched against the model list; the chat's requests are then routed to that model (model-yonlendirme.json, keyed by prompt_cache_key) until Codex sends a different model for the chat, i.e. until the user picks another one in the list.

  • Idle chat: the bridge answers itself ("Sohbetin modeli artık X ..."), which also tells the voice assistant.
  • Running turn: the command is replaced by a handover note and the SAME turn continues on the new model.
  • "seçili model hangisi" / "ana model kim" is answered by the bridge with the model actually in use.
  • An ambiguous name changes nothing and lists the closest names; a name matching no model is not a command.
  • A lone . that joins a running turn is dropped instead of answered (answering it cut the work short).
  • Handled commands left in the history are turned into notes so a later model does not answer them again.

Setting: sesle_model (default on).

Version 7 (IDE beta.26): external models behave like subscription models

Measured on 10 Oct 2026 with the unmodified Codex binary (codex exec, same conversation, model switched per turn).

Area Before Now
Context window every added model declared 272 000 pencere.py: NanoGPT's own list for nano/*, a local table for cc/cx/ag, a combo declares its smallest member, unknown = 128 000, nothing above 272 000 (the summarizer's window). Codex then compacts by itself when switching to a smaller model.
Overflow the target answered with an empty stream; Codex retried five times pencere.sigdir trims the middle of oversized old parts in the outgoing copy; if it still does not fit Codex gets context_length_exceeded. A limit reported by the target is learned (pencere-ogrenilen.json).
Tools clones inherited code_mode_only + Responses Lite; GLM and Qwen failed 0/3 on simple tasks (empty answers, reasoning leaked into the answer) dis_arac_modu: "direct" (default): classic tools. GLM 3/3, Qwen 2/3; Claude, cx and Gemini unchanged (6/6). "kalip" restores the old behaviour.
Intermediate messages external assistant messages had no phase; Codex treats those as final answers SseRewriter stamps commentary / final_answer. Deltas are never delayed; only the item's done event waits for what follows.
Interrupted answer text written before a stop or an app exit was lost yarim.py keeps it (memory only) when the client closes the stream and adds it as a note to the next user message of the same conversation, once.
Images removed from every old message for all external models kept for vision-capable targets (user messages, newest first, 1 MB total).
Summary brake the 4th summary in 10 minutes failed the turn three summaries in a row with no normal request in between, or eight in 10 minutes.
Gateway errors event: error (e.g. upstream 402) looked like a cut stream permanent ones become response.failed with a readable message; short upstream bodies are logged.
Start-up the model list was fetched before listening; a slow gateway made the IDE give up after 10 s window data comes from the cache at start and is refreshed in the background; the IDE waits 45 s.

Not changed: subscription models, their order and names, and everything on the voice path (/realtime/* passes through untouched).

Settings in bridge.json (all optional): dis_arac_modu, tasma_bekcisi, yarim_cevap, ozet_kopru.dongu_siniri, ozet_kopru.dongu_art_arda.

A lone . sent as the user's message (used to apply a model change during a voice session) is answered by the bridge itself with " hazır." and never reaches a model (nokta_karsila, default on). Targets that reject tool calls are remembered (aracsiz-modeller.json) and marked "araçsız" in the picker.