Repository navigation
[Feature] Explicit per-thread external-provider routing during Codex Desktop Luna Reserve #4869
Description
Area
Proxy and routing / Codex Desktop compatibility
What are you trying to accomplish?
Continue working in Codex Desktop with an independently configured provider when the native ChatGPT/Codex quota is exhausted and Luna Reserve locks the model picker.
I am encountering the picker lockout described in #2813 and #4076. The desired outcome is to retain the Desktop workflow and, where technically compatible, the current conversation, while selecting the actual execution provider through OpenCodex.
This is not a request to reset, falsify, or bypass OpenAI usage limits. The alternative provider must use its own authorized credentials, billing, and quota.
What prevents this today?
The investigation recorded in #2813 identifies a Desktop-side restriction: Reserve can force the outgoing model to gpt-reserve before the request reaches OpenCodex. Changing catalog visibility or only setting model in config.toml therefore does not address that native-auth Desktop state.
There is already a promising configuration-level alternative: an effective codexDesktopAuthless setup uses a dedicated provider with requires_openai_auth = false. However, changing the global provider/auth presentation is a different workflow from keeping the existing Desktop setup. Related reports cover settings that are not yet applied or ineffective (#4809), Reserve catalog projection (#4811), and provider/history restoration (#4812).
This proposal is specifically about an explicit, per-thread execution-provider override, not another request to fix the native picker or re-report those existing bugs.
What should OpenCodex do?
Please evaluate an opt-in routing mode with the following behavior:
- The user explicitly selects an independently credentialed provider/model for one conversation in OpenCodex. Nothing changes globally or automatically when native quota is exhausted.
- If that conversation sends an inference request with the exact model
gpt-reserve, OpenCodex dispatches it through the selected provider's normal adapter and authorization path. - Other conversations, genuine Reserve requests without an override, and account-qualified Reserve routes remain unchanged.
- The dashboard clearly displays both the Desktop-requested model and the actual execution provider/model. It must warn that the Desktop may still display “Luna Reserve”; this proposal does not restore its native picker.
- Disabling the override restores ordinary routing for subsequent requests without modifying account credentials or rewriting conversation history merely to toggle the option.
Feasibility gate: first verify that an affected Desktop build actually sends a request to OpenCodex and supplies a stable, correctly scoped conversation identity. If Desktop blocks submission entirely, or the identity is missing/ambiguous, this mode cannot solve that case and must report it rather than apply a global substitute.
Example usage or interface
Proposed UI workflow, not an existing feature or command:
OpenCodex dashboard
-> Select a conversation
-> External execution override
-> Select an already configured independent provider/model
-> Review the data-sharing, billing, and Desktop-label warning
-> Enable for this conversation
Desktop request: model = gpt-reserve
OpenCodex route: the explicitly selected provider/model
Other threads: unchanged
Disable override -> ordinary routing resumes on subsequent requests
The warning should explicitly state that conversation content will be sent to the chosen provider and charged under that provider's terms. An active override must remain visible until disabled; quota recovery should not silently switch providers mid-conversation.
Additional context
Source-level basis, not an implementation claim
The following pinned sources informed this proposal:
- OpenCodex
src/router.tsat44de45d:routeModelInternalalready resolves policy/combo choices into concrete provider/model destinations. This is a possible integration point, not evidence that Reserve overrides currently work. - OpenCodex combo validation and native model definitions:
nativeAliasis restricted to supported native slugs, whilegpt-reserveis separately defined and absent from that supported set. Simply configuring a native alias is therefore not the proposed solution. Please keep those general validation boundaries intact. - OpenCodex auth-context handling: conversation identity and request/account ownership already have dedicated handling. Any override should reuse the appropriate identity boundaries rather than keying a global rule by a raw model name or assuming parent and child threads are interchangeable.
- OpenCodex provider injection and Codex
ConfiguredModelProvider::account_state: the existing authless alternative changes the native account presentation. This is preferable if it already satisfies the workflow. - Recorded Desktop investigation: the repository records source-level evidence for authless avoiding a particular Desktop Reserve gate, while explicitly distinguishing that from a live Reserve-session test. That distinction should be preserved.
Required safeguards and validation
- Keep normal proxy admission checks. Use only the selected provider's credentials; never forward native ChatGPT bearer tokens or account-identifying headers to an unrelated provider.
- Preserve all upstream authorization/quota checks. Do not modify WHAM responses, recovery flags, or Reserve eligibility. Do not fall back to the exhausted native account if the chosen provider fails.
- Validate target capability compatibility, tool calls/results, images, reasoning settings, streaming/cancellation, context limits, and compaction. Rewriting the model string alone is not a complete implementation. Reject unsupported continuation explicitly instead of silently dropping context.
- Keep response IDs, cached/reasoning state, and provider-specific continuation artifacts isolated across providers. A route change must not reuse an upstream response ID that belongs to another provider.
- Ensure per-thread isolation, including concurrent threads, forks, and subagents; do not inherit overrides into child conversations implicitly.
- Record requested versus resolved provider/model and the override reason without logging secrets or conversation content merely for diagnostics.
- Test the no-override path, exact-match behavior, missing identity, disabled/unauthorized targets, disable/reenable behavior, and an actual affected Desktop version before describing this as a working workaround.
Alternatives or workarounds
- Effective authless provider configuration: the first alternative to validate. The existing sequence is
ocx system settings --desktop-authless on,ocx sync, then a complete Desktop/app-server restart and a fresh-thread test with a routed model. The effective provider/auth state matters, not only the saved flag. Please treat the application/diagnostic defects in Toggling --desktop-authless / --client-compaction does not rewrite ~/.codex/config.toml until a separate sync, and gives no warning about the auth-source switch #4809 and history concerns in ocx restore / stop / uninstall refuse to restore config.toml on paginated Codex history, leaving the CLI pointed at a dead proxy port #4812 as their own work items rather than duplicating them here. - Another client or direct
/v1access: useful existing alternatives, but they do not preserve the requested Desktop workflow. - Catalog-only changes: do not address a model that the Desktop overwrites before dispatch.
- A global
gpt-reservealias or quota-response manipulation: not requested. Those would obscure model identity or affect unrelated requests.
If maintainers consider the authless workflow sufficient and intentionally do not support this kind of override, a clear statement of that supported boundary would also help. Otherwise, the first deliverable should be a small feasibility test and design review before a production PR.
Verification status
This is an AI-assisted, source-informed feature proposal, not a tested patch. No live successful Reserve-to-external-provider session, complete end-to-end authentication trace, or compatibility test is claimed. The cited commits identify the analysis baseline; they do not imply that my installed binaries exactly match those revisions. No Desktop bundle has been patched.
Checks
- I searched existing issues and documentation.
- This request describes a concrete OpenCodex workflow rather than merely naming a desired technology.
- I removed secrets and personal data.
Activity
lidge-jun commentedon Sep 17, 2026
리뷰 · 우선순위 64 / 80
설명
이 이슈는 oocheol이 올린 enhancement 이고, Codex Desktop이 Luna Reserve로 피커를 잠근 뒤에도 OpenCodex 대시보드에서 대화(스레드) 단위로 이미 설정된 독립 제공자/모델로 실행을 넘기고 싶다는 설계 제안이다. 지금 리뷰 기준인
devtip은#4862머지 커밋e18ca246305bd8fc2b266bdb0ff287c6b25f6bd4(package 2.58.0) 이다. 본문은#2813/#4076의 “피커가 Reserve로 접힌다”는 조사 결과를 인정하면서도, 피커를 푸는 요청이 아니라 Desktop이model=gpt-reserve로 프록시에 요청을 계속 보내는 경우에만 명시 오버라이드로 바꿔 치는 축을 제안한다. OpenAI 할당량 위조·우회가 아니라고 여러 번 못 박았고, 전역 authless 전환(codexDesktopAuthless)이나#4809/#4811/#4812버그 수정 재보고와도 선을 그었다.현재 HEAD에서 관련 코드는 이렇게 나뉜다.
NATIVE_RESERVE_MODEL = "gpt-reserve"(src/codex/catalog/native-models.ts) 와src/codex/catalog/reserve.ts/src/codex/reserve-availability.ts는 Reserve 요청이 들어왔을 때 카탈로그 줄·자격·헬퍼를 다루는 쪽이다.#2813/#4076리뷰가 이미 적은 대로, Desktop이 Reserve 활성 시 피커를gpt-reserve한 칸으로 접는 동작은 OpenCodex 카탈로그 visibility가 아니라 클라이언트 게이트다.codexDesktopAuthless(src/types/config.ts, inject의requires_openai_auth = false) 는 전역으로 Desktop 로그인 게이트를 우회하는 다른 워크플로다. 대화 ID는src/server/request-log-conversation.ts등에 로그/필터용으로 있지만, 스레드별 실행 제공자 오버라이드 저장소는 없다. 그래서 이 제안은 기존 버그 수정이 아니라 새 제품 표면이다.제안의 좋은 점: (1) opt-in·대화 단위·끄면 원래 라우팅 복귀, (2) 대시보드에 Desktop 요청 모델과 실제 실행 제공자를 둘 다 보여 주고 Luna 라벨 경고, (3) 할당량 회복 시 조용한 제공자 전환 금지, (4) feasibility gate — Desktop이 실제로 OpenCodex까지 요청을 보내고, 안정적인 conversation identity를 주는지 먼저 검증하고, 막히거나 identity가 애매하면 전역 대체로 숨기지 말라고 했다. 이건
#2813/#4076을 duplicate로 닫을 때와 다른 질문이다. 그쪽은 “피커를 프록시로 풀 수 있냐”(대체로 아니오)였고, 이쪽은 “gpt-reserve요청이 프록시에 오면 스레드 오버라이드로 다시 칠 수 있냐”다.우선순위를 64로 둔 이유: 문장·경계·비목표가 매우 맑아서 메인테이너가 바로 제품 결정을 내릴 수 있다. 다만 구현 PR을 지금 받으면 안 된다. feasibility가 실패하면(요청이 Desktop에서 막히거나 identity가 없으면) 기능이 성립하지 않고, 성공해도 계정 자격·데이터 공유·Reserve 전용 경로(
src/server/search.ts등의 Reserve eligibility)와 충돌하지 않게 설계해야 한다. types.ts/config.ts split 캠페인에 새 설정/대시보드 상태를 넣으면 쓸려 갈 수 있으니, 확인 전에는 키를 추가하는 PR을 받지 마라. preview 배포와도 무관하다.#4809/#4811/#4812는 관련 맥락이지 이 이슈의 중복이 아니다.라인 단위 / 경로 단위 문제
경로 이슈 본문 - “피커 잠금 해제”가 아니라 “
gpt-reserve도착 시 스레드 오버라이드”로 축을 바꾼 점은#2813/#4076과 구분된다. duplicate close만으로 처리하면 제품 질문을 잃어버린다경로
#2813(CLOSED) /#4076(CLOSED) - 원인(클라이언트 Reserve 게이트)은 공유하지만, 요청된 해결책은 다르다. 문서 우회(ocx claude, 로컬/v1)만 가리키고 닫기 전에 feasibility를 한 줄로 남길지 결정이 필요하다경로
NATIVE_RESERVE_MODEL/src/codex/catalog/reserve.ts- Reserve 줄·메타데이터는 있다. 스레드별 외부 제공자 remap 훅은 없다경로
codexDesktopAuthless(src/types/config.ts, inject) - 전역 auth 표현 전환이다. 본문이 원하는 per-thread override와 워크플로가 다르다경로
src/server/request-log-conversation.ts- conversation id는 로그/필터용이다. Desktop이 보내는 identity가 여기와 같은 키인지는 미검증이다(본문 feasibility gate와 동일)경로
#4809/#4811/#4812- authless sync·Reserve 카탈로그·restore 이슈다. 이 제안의 선행 버그가 될 수는 있어도, 이 번호로 흡수하면 안 된다경로 types/config split - 새 대시보드/설정 키 PR은 스플릿 캠페인에 쓸릴 수 있다. feasibility·설계 합의 전에는 받지 마라
메인테이너의 판단이 필요한 지점
model=gpt-reserve요청을 보내는지(feasibility)를 메인테이너가 재현할지, 작성자 로그를 받을지#2813/#4076문서(“Routed models during Codex reserve mode”)에 이 제안을 “미지원 / 검토 중”으로 한 줄 추가할지너의 추천
이슈는 열어 두되, 구현 PR은 지금 받지 마세요. 먼저 feasibility gate만 하세요: Reserve 활성 Desktop에서 프록시 로그에
gpt-reserve요청과 안정적인 conversation identity가 오는지. 요청이 막히거나 identity가 없으면 이 모드는 성립하지 않으니 문서에 한계로 적고 닫거나 upstream-tracking으로 두세요. 요청이 오면 그때 설계 리뷰(표시·경고·끄기·계정 격리) 후 작은 실험 PR만 받으세요.#2813/#4076duplicate로 즉시 close하지 마세요(축이 다름). types/config 키는 합의 전 금지. 점수 64/80 — 제안 품질은 높고, 제품·feasibility 미결이라 구현 착수 직전은 아님.이 댓글은 grok-bot이 작성했습니다
oocheol commentedon Sep 17, 2026
Follow-up: feasibility first, implementation only after design agreement
Following the automated review above, I agree that the next deliverable should be live feasibility evidence, not a production implementation PR. This is a proposed sequence for maintainer consideration, not a claim that the feature has been approved or reproduced successfully.
The review used
e18ca246305bd8fc2b266bdb0ff287c6b25f6bd4(#4862) as its baseline. A reproduction should record the actual OpenCodex revision/version and Codex Desktop build rather than assume they match that baseline.1. Keep the scope distinct
The question here is not whether OpenCodex can unlock Desktop's native model picker. It is:
#2813 / #4076 address the picker restriction. Global
codexDesktopAuthlesschanges, settings synchronization (#4809), Reserve catalog projection (#4811), and restoration (#4812) remain separate work items. In particular, an authless/settings-sync patch must not be presented as implementing or closing #4869.2. Phase 0: observation only
Use an actual Reserve-active Desktop session and existing diagnostic surfaces where sufficient. Do not add production configuration keys, an override store, dashboard controls, model remapping, or changes to quota/authentication behavior at this stage.
The evidence should establish:
Record the effective provider/auth mode and local versus remote proxy topology. Test the affected native-auth workflow first; an authless result is a separate control, not proof of this proposal.
Publish only a minimal, redacted evidence summary: build/version, request arrival, model, identity-field presence, and correlations such as “thread A” / “thread B.” Do not upload raw request bodies, prompts, tokens, authorization headers, or raw account/session/thread identifiers. Temporary local pseudonyms can preserve correlation without publishing those values. Absence from a particular log is inconclusive unless that log is known to cover the actual ingress path.
3. Decision after the evidence
gpt-reservesubstitution. Record the identity blocker separately.Until then, I suggest keeping this as a distinct enhancement rather than closing it solely as a duplicate of the picker issues.
4. Design decisions required before an experimental PR
Maintainers should agree on the identity/lifecycle contract and storage owner first, including behavior across proxy restarts and credential changes. No conversation-history rewrite should be required merely to toggle the override.
The design also needs explicit consent for data sharing/billing, requested-versus-executed model visibility, enable/disable semantics, and fail-closed behavior. Normal admission and the destination provider's credentials/authorization remain mandatory; native credentials must never leak to an unrelated provider. Genuine Reserve requests and Reserve-specific search/helper paths must retain their existing authorization boundaries. Interactions with account hard-locks and quota policies need an explicit decision, not an accidental bypass.
One transition deserves particular attention: if quota recovers and Desktop starts sending a non-Reserve model, an exact-match override would stop matching. The design must specify a visible transition/confirmation policy rather than silently returning to native execution or silently expanding the override to other models.
Only after those decisions should a small experimental PR validate streaming, tools, context/compaction, provider-specific continuation state, concurrent-thread isolation, and disable behavior. New configuration/dashboard state should wait for that agreement and coordination with the types/config split.
Verification status: no live feasibility result or successful end-to-end Reserve-to-external-provider session is being claimed in this follow-up.
Could a maintainer confirm who should own the live reproduction—maintainer testing or a redacted reporter capture—and whether this observation-only report is the preferred first deliverable?
lidge-jun commentedon Sep 17, 2026
Holding this pending one piece of evidence that only your side can produce.
The question ahead of any proxy-side change is whether the request reaches the proxy at all. If the client never sends it, no routing change here will make it work, and a fix built on that assumption would be wrong in a way that is hard to detect afterwards.
Could you capture whether the request arrives — the proxy's request log for the attempt, or
ocx logsaround that moment? If it does arrive, this becomes actionable immediately and we will pick it up. If it does not, the investigation belongs on the client side.lidge-jun commentedon Sep 27, 2026
Release train 4 (account-pool lane) reviewed this. Per-thread external-provider routing is a client-integration question, separate from account-pool failover, so this lane makes no change. It still waits on the evidence requested above: whether the affected Desktop turn reaches OpenCodex at all (
ocx logsaround the attempt), plus the effective provider and auth mode. Keeping it open.chrissotraidis commentedon Sep 28, 2026
I hit this on macOS with OpenCodex 2.63.0 and Codex Desktop using the normal loopback injection (
openai_base_url = "http://127.0.0.1:10100/v1"). The effective OCX settings reportcodexDesktopAuthless: false,routingKind: opencodex-local,routingInjected: true, and a Desktop auth source that presents the Codex account.Practical impact: I could not get
anthropic/claude-opus-5-5working in Desktop after my primary Codex allowance was exhausted. I consumed a banked reset on the primary Codex account, after which Claude worked. That is a costly recovery for a model using separate Anthropic credentials and quota.Evidence from the retained
ocx logs --jsonrequest history (times JST, 2026-09-29):primary/gpt-6-astra->openai-primary, HTTP 429,rate_limit_exceeded, upstream errorThe usage limit has been reached.gpt-6-lunarequests. It contains noanthropic/claude-opus-5-5orgpt-reserverequest in that interval.anthropic/claude-opus-5-5->anthropic, HTTP 200, completed. The Anthropic quota report subsequently showed 32% weekly usage.This is retrospective log evidence, not a synchronized capture of a specific Send click. I cannot claim from it alone that Desktop suppressed a particular attempted turn. It does answer part of the requested routing question: no Claude or Reserve request appears at OCX in the retained interval between the primary 429 and Claude's first successful turn. If a live reproduction with an exact click timestamp is required for the proposed per-thread override, please keep that gate explicit.
Given the user impact, could the OCX team prioritize a tested recovery path that does not require spending a Codex reset? If the request does not reach OCX, I understand a per-thread proxy override cannot help; in that case, a verified
codexDesktopAuthlessworkflow and clear diagnostics/warning before users spend a reset would still materially help.