fix(codex-bridge): close the gaps an independent review found
- One decision per real turn: a turn starts with a user message after the previous final answer; tool steps, messages typed mid-turn, a lone "." and compaction keep the combo. Works without prompt_cache_key too. - The virtual Otomatik name never reaches the gateway (stage off or error -> last choice or targets.zor); prefilter.target may not be it. - finishCheck: at most once per turn; a broken, empty or refused retry delivers the already approved first answer. - Layer window filter: only trusted windows, never the last layer. - Correction channel only on always-pass targets while checks are on; Sesli-Hizli-Zeki stays always-pass by default; a >256 KB SSE frame passes unfiltered instead of breaking the stream. - Turn-start questions wait in the local queue no longer than their timeout; decision-turn memory under a lock with refreshed order. - Dify fetch refuses redirects (the app key never moves host); the rules file write retries a Windows sharing violation. - An unreadable settings file no longer breaks every request. - TypeScript accepts only https:// URLs the bridge accepts; finishCheck.timeoutSeconds (unused) removed. Tests: 310 bridge tests, 36 electron tests; side-bridge live run for the turn, prefilter (incl. decision timeout) and finish-check paths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7c4ef18df0
commit
a7ba300448
10 files changed
+353
-91
No files matched your search
@@ -36,25 +36,33 @@ decision always keeps the current path.
|
||||
|
||||
- `jev-settings.json` schema 2 adds `watchModels`, `prefilter`, `autoRoute`, `finishCheck`,
|
||||
`verifierCheck` and `policy`. A schema 1 file is filled from `jev-settings-defaults.json`.
|
||||
The default chain is `Katman-1 → Katman-2 → Katman-3`; `Katman-3`, `Chat-Model` and
|
||||
`bekci-sesli-bekci` always pass.
|
||||
The default chain is `Katman-1 → Katman-2 → Katman-3`; `Katman-3`, `Chat-Model`,
|
||||
`bekci-sesli-bekci` and `Sesli-Hizli-Zeki` always pass.
|
||||
- **Correction channel** (`watchModels`): the Bekçi watch sideband is no longer bound to the hard-coded
|
||||
name `Sesli-Hizli-Zeki`; any exact target in the list owns it.
|
||||
name `Sesli-Hizli-Zeki`; any exact target in the list owns it, but only while it always passes the check
|
||||
(a checked answer may be replaced by a layer, and a receipt must not belong to an answer the user never saw).
|
||||
A single SSE frame above 256 KB no longer breaks the stream; the rest of the stream passes unfiltered.
|
||||
- **Refusal pre-check** (`prefilter`): at the start of a turn, "would a mainstream model refuse or water
|
||||
this down?". If yes, the step starts at `prefilter.target` instead of collecting a refusal first.
|
||||
- **Automatic model** (`autoRoute`): a virtual `ide/<model>` entry ("Otomatik") in the Codex list. Each new
|
||||
user message gets one decision call (hard? research?) and goes to the configured combo. Tool steps of
|
||||
the same turn keep that combo, because switching providers mid-turn breaks encrypted history. The
|
||||
user's explicit model choice is never changed by this stage.
|
||||
- Both turn-start questions go in one call, bounded by `timeoutSeconds` (default 3 s).
|
||||
- **Layer window filter**: a layer whose context window cannot hold the request is skipped.
|
||||
- **Automatic model** (`autoRoute`): a virtual `ide/<model>` entry ("Otomatik") in the Codex list. A new turn
|
||||
(a user message after the previous final answer) gets one decision call (hard? research?) and goes to
|
||||
the configured combo. Tool steps, messages typed while the turn runs, a lone "." and compaction stay on
|
||||
the same combo, because switching providers mid-turn breaks encrypted history. When the stage is off or
|
||||
fails, the virtual name never reaches the gateway: the last choice or `targets.zor` is used. The user's
|
||||
explicit model choice is never changed by this stage.
|
||||
- Both turn-start questions go in one call; the wait, including the local queue, is bounded by
|
||||
`timeoutSeconds` (default 3 s).
|
||||
- **Layer window filter**: a layer whose trusted context window (pencere.bekci_calisir) cannot hold the
|
||||
request is skipped. The last link of the chain is never skipped.
|
||||
- **Early finish check** (`finishCheck`): asked in the same call as the refusal check on a final answer.
|
||||
If the answer stopped early or claimed success without evidence, it goes back to the same model once
|
||||
with `finishCheck.note`; the retry is delivered without another finish question.
|
||||
If the answer stopped early or claimed success without evidence, it goes back to the same model with
|
||||
`finishCheck.note`, at most once per turn. If the retry breaks, comes back empty or fails the check, the
|
||||
first (already approved) answer is delivered.
|
||||
- **Rules from Dify** (`policy.source = dify`, `karar_politikasi.py`): the stage questions, thresholds and
|
||||
combo choices may come from a Dify workflow's `kurallar` output. Fetched in the background every
|
||||
`refreshMinutes`, validated against the local settings, last good copy kept in `jev-policy.json`.
|
||||
The transition chain and the always-pass list stay local. A turn never waits for Dify.
|
||||
The transition chain and the always-pass list stay local. A turn never waits for Dify, and a redirect
|
||||
from the Dify endpoint is refused so the app key never travels to another host.
|
||||
- **Workflow reviewer check** (`verifierCheck`, `karar_sor.py`): the Codex dynamic-workflow acceptance
|
||||
step asks whether a reviewer approved without concrete evidence; if so acceptance is blocked.
|
||||
|
||||
|
||||
Reference in new issue
Block a user