fix: route Codex "Approve for me" reviews in the shipped Switchyard configs - #872
elyasmnvidian merged 2 commits into
Conversation
d6ce102 to
c559654
Compare
|
ee44fbc to
3e9a724
Compare
c871c35 to
042211d
Compare
36124e8 to
c3da05d
Compare
|
@coderabbitai review |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: NVIDIA-NeMo/Switchyard/.coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (11)
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 7 remain after this review. WalkthroughThe change adds a ChangesCodex review routing
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Merge Risk: ⚪ Minimal · up to The Codex review route and approval option have no identified issue requiring a fix before merge. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 61.54% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 8 files. (3 skipped: 3 unsupported.)
A rabbit checks the review route at night, Comment |
c3da05d to
91092be
Compare
|
91092be to
79c3328
Compare
…onfigs Signed-off-by: Elyas Mehtabuddin <emehtabuddin@nvidia.com>
…wer model Signed-off-by: Elyas Mehtabuddin <emehtabuddin@nvidia.com>
a797312 to
97a3139
Compare
What
When Codex runs through Switchyard with "Approve for me" on, Codex declines every action that needs approval. With "Approve for me" on, Codex asks a reviewer model to approve each of these actions, and it sends that review request to the model ID
codex-auto-review. Neitherexamples/run_codex.shnorscripts/config/composite.toml(the server config thatscripts/linux/install.shcopies) had a route with that ID. So the server returned 404model_not_found, and Codex treated the failed review as a denial.This affects anyone who uses Codex through Switchyard with "Approve for me" on in the Default or Read Only mode, including Codex logged in with ChatGPT. It does not affect Full Access mode, which never asks for approval, or sessions with "Approve for me" off.
This PR adds a
codex-auto-reviewroute to both shipped configs. The route sends the review request unchanged tocodex-auto-reviewon the ChatGPT backend, using thechatgpt_backendclient the configs already have (forward_auth = true, so Switchyard forwards the caller's login):dev-server/config.tomlhas no ChatGPT backend client, so its newcodex-auto-reviewroute uses its existingefficienttarget (gpt-5.6-luna). Reviews still run at low effort, because Codex asks forlowand the target'sextra_bodyonly fills in a missing effort. The dev server needs the file copied over and a restart after merge (seedev-server/README).There are no code changes. A new server README section explains the route and recommends a small, fast reviewer at low reasoning effort for anyone who points it at another model. The installer never overwrites an existing
~/.switchyard/composite.toml, so existing installs must add the two blocks by hand.Why
Codex sends each review request to the session's own model provider, so when Codex points at Switchyard, the review goes to Switchyard. Codex picks the model ID from its login type, not from Switchyard: every login uses
codex-auto-review, except an OpenAI API-key login, which usesgpt-5.6-luna. The README covers the API-key case and its catch: agpt-5.6-lunaroute also gets Codex's other requests for that ID.Codex waits for each review before it runs the action, so a slow reviewer slows down every step that needs approval. Codex keeps its own reviews light: every review request asks for
lowreasoning effort, and OpenAI's Auto-review post says its reviewer runs GPT-5.4 Thinking at low reasoning. The same post says stronger models catch risky actions more reliably, so a small model trades some safety for speed and cost.Codex has no simple setting to pick the reviewer model. The only way is a full replacement model catalog (
model_catalog_json) whose session-model entry setsauto_review_model_override. That catalog must list every model Codex uses and changes with Codex releases, so a Switchyard route is simpler.An earlier version of this PR also added a route type that approved every action without a review. I removed it, because Codex's own settings already do that: Full Access (
--dangerously-bypass-approvals-and-sandbox) runs every action without a review, andapproval_policy = "never"keeps the sandbox but sends no reviews. The README points people to those settings.Notes for reviewers
Start with the new section in
crates/switchyard-server/README.md. The second commit adds the dev server route and the reviewer-model advice. The macOS menu bar price forcodex-auto-reviewis suggested on #902.The new route changes
GET /v1/models: the server sorts route IDs, andcodex-auto-reviewsorts beforeswitchyard, sodefault_modeland the startup banner's examplecurlnow usecodex-auto-review. I found no client in this repo or in Codex that readsdefault_model.No test below sent traffic to OpenAI or ChatGPT. Model IDs on the OpenAI-compatible LiteLLM gateway are shown as their public IDs.
Dry runs of the three configs
switchyard-server --dry-runbuilt from this branch:Replay: what the shipped route forwards to the ChatGPT backend
I copied
scripts/config/composite.tomland pointed itschatgpt_backendclient at a local stub. Then I sent a review request captured from Codex 0.152.0 toPOST /v1/responseswithmodel: codex-auto-review, fakeauthorizationandchatgpt-account-idvalues, and Codex'sx-openai-subagent: guardianheader. The server returned 200 and streamed the stub's{"outcome":"allow"}verdict. The stub recorded:Server log:
Dev server config: reviews run on gpt-5.6-luna at low effort
What reaches the gateway. I copied
dev-server/config.toml, pointed its gateway client at a local stub, and replayed the captured Codex review request. Then I sent one plain request with no reasoning effort toswitchyard/passthrough, which uses the same target. The stub recorded:reasoning.effortmodel: codex-auto-reviewgpt-5.6-lunalow, Codex's valueswitchyard/passthrough, no effort setgpt-5.6-lunamedium, from the target'sextra_bodyThe review also kept Codex's JSON output schema (
codex_output_schema).Real gateway. With the unmodified
dev-server/config.toml, the same replay returned HTTP 200 in 2.5 s and streamed{"outcome":"allow"}. The model used 130 output tokens, 112 of them for reasoning.Codex end to end. Codex 0.152.0,
codex exec --ephemeral --skip-git-repo-check --approve-for-me, a temporaryCODEX_HOMEwith no OpenAI login, andswitchyard/passthroughas the session model. Codex ran withapproval: on-requestandsandbox: workspace-write. Itscurl https://example.comcommand needed network access, so Codex sent it for review, then ran it and printed200. Server log, trimmed:Codex end to end, reviewer on the gateway
Codex 0.152.0,
codex exec --ignore-user-config --ephemeral --skip-git-repo-check --approve-for-me --json, a temporaryCODEX_HOMEwith no OpenAI login, and a custom model provider pointing at a local Switchyard server (env_key,wire_api = "responses"). The prompt asked Codex to runcurl https://example.comwith network access, which the sandbox blocks, so Codex asked for approval.Config:
Server log:
Codex events, trimmed:
{"type":"command_execution","command":"/bin/zsh -lc \"curl -sS -o /dev/null -w '%{http_code}' https://example.com\"","aggregated_output":"200","exit_code":0,"status":"completed"} {"type":"agent_message","text":"200"}In an earlier run of the same setup without the route, the server logged
status=404 requested_model="codex-auto-review"and Codex reported the command asdeclined.