User decision: the "larger work goes to AITURK" instruction lives only in what Codex IDE sees; the CLI must not know it exists. The bridge adds it in flight by the originator header (measured: Codex Desktop, codex-tui, codex_exec) and only when a send command is configured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
76 lines
6.4 KiB
Markdown
76 lines
6.4 KiB
Markdown
# 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).
|
||
|
||
### Work handoff instruction (prepared, off by default)
|
||
|
||
`is_hatti.py`: when `aiturk_hat` is enabled and has a `komut`, the bridge prepends a developer message ("small work
|
||
yourself; larger work goes to AITURK via this command") to requests whose `originator` header is `Codex Desktop`.
|
||
The Codex CLI (`codex-tui`, `codex_exec`) never receives it and nothing is written to any file it reads. Each new
|
||
`originator` value is logged once (`istemci goruldu`).
|
||
|
||
## 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 "<model> 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.
|