Skip to content

[Feature] Explicit per-thread external-provider routing during Codex Desktop Luna Reserve #4869

Open

Description

@oocheol

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:

  1. The user explicitly selects an independently credentialed provider/model for one conversation in OpenCodex. Nothing changes globally or automatically when native quota is exhausted.
  2. 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.
  3. Other conversations, genuine Reserve requests without an override, and account-qualified Reserve routes remain unchanged.
  4. 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.
  5. 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.ts at 44de45d: routeModelInternal already 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: nativeAlias is restricted to supported native slugs, while gpt-reserve is 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

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

  1. lidge-jun commented on Sep 17, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 64 / 80

    설명

    이 이슈는 oocheol이 올린 enhancement 이고, Codex Desktop이 Luna Reserve로 피커를 잠근 뒤에도 OpenCodex 대시보드에서 대화(스레드) 단위로 이미 설정된 독립 제공자/모델로 실행을 넘기고 싶다는 설계 제안이다. 지금 리뷰 기준인 dev tip은 #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·설계 합의 전에는 받지 마라

    메인테이너의 판단이 필요한 지점

    • Reserve 활성 Desktop이 실제로 OpenCodex에 model=gpt-reserve 요청을 보내는지(feasibility)를 메인테이너가 재현할지, 작성자 로그를 받을지
    • 지원 경계를 “authless 전역만 / 외부 클라이언트만”으로 공식화할지, per-thread override를 실험 기능으로 받을지
    • 오버라이드 저장 위치를 대시보드 상태·config·대화 메타 중 어디에 둘지(히스토리 rewrite 금지 조건과 맞춤)
    • Reserve eligibility·계정 hard-lock·quota 경로와 충돌 시 fail-closed 규칙을 어떻게 할지
    • #2813/#4076 문서(“Routed models during Codex reserve mode”)에 이 제안을 “미지원 / 검토 중”으로 한 줄 추가할지

    너의 추천

    이슈는 열어 두되, 구현 PR은 지금 받지 마세요. 먼저 feasibility gate만 하세요: Reserve 활성 Desktop에서 프록시 로그에 gpt-reserve 요청과 안정적인 conversation identity가 오는지. 요청이 막히거나 identity가 없으면 이 모드는 성립하지 않으니 문서에 한계로 적고 닫거나 upstream-tracking으로 두세요. 요청이 오면 그때 설계 리뷰(표시·경고·끄기·계정 격리) 후 작은 실험 PR만 받으세요. #2813/#4076 duplicate로 즉시 close하지 마세요(축이 다름). types/config 키는 합의 전 금지. 점수 64/80 — 제안 품질은 높고, 제품·feasibility 미결이라 구현 착수 직전은 아님.

    이 댓글은 grok-bot이 작성했습니다

  2. oocheol commented on Sep 17, 2026

    @oocheol
    ContributorAuthor

    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:

    When an affected Desktop continues sending inference requests with the exact incoming model gpt-reserve, can OpenCodex identify the requesting conversation reliably enough to support an explicit, isolated external-provider override?

    #2813 / #4076 address the picker restriction. Global codexDesktopAuthless changes, 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:

    Question Required observation
    Does inference reach OpenCodex? Observe the incoming request at the proxy ingress, before model normalization/routing. Record the transport/path and exact incoming model. A native Reserve banner alone is not evidence of request arrival.
    Can the same conversation be recognized? Compare multiple turns in one conversation, then a second concurrent conversation. The first must correlate consistently and the second must remain distinguishable.
    Is the identity suitable for routing? Establish which request fields define the conversation and how they are scoped to the admitted caller. A log/filter conversation ID is not automatically an authoritative routing key.
    Where does identity stop being valid? Check resume/restart and, where available, forks/subagents. Missing identity, parent-only identity, or ambiguous correlation must not become a global or implicitly inherited override. Record credential-refresh behavior if observable.

    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

    • No request reaches the proxy: this mode cannot help that tested Desktop/build/state. Record the limitation and decide whether to close as unsupported or retain upstream tracking.
    • Requests arrive but safe conversation scoping cannot be established: do not implement a global gpt-reserve substitution. Record the identity blocker separately.
    • Requests and adequate identity are confirmed: proceed to design review. This establishes feasibility of interception/scoping only, not end-to-end external-provider compatibility.

    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?

  3. lidge-jun commented on Sep 17, 2026

    @lidge-jun
    Owner

    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 logs around 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.

  4. added
    priority: P3Low: new provider/client integration, large or experimental feature (>2000 LOC or >50 files), RFC/ro
    on Sep 24, 2026
  5. lidge-jun commented on Sep 27, 2026

    @lidge-jun
    Owner

    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 logs around the attempt), plus the effective provider and auth mode. Keeping it open.

  6. chrissotraidis commented on Sep 28, 2026

    @chrissotraidis

    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 report codexDesktopAuthless: 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-5 working 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 --json request history (times JST, 2026-09-29):

    • 07:12:40: primary/gpt-6-astra -> openai-primary, HTTP 429, rate_limit_exceeded, upstream error The usage limit has been reached.
    • The retained log covers 06:53:09–08:40:01. From 07:12:40 up to 08:10:30 it contains seven requests: that primary-account 429 and six gpt-6-luna requests. It contains no anthropic/claude-opus-5-5 or gpt-reserve request in that interval.
    • 08:10:36, 08:11:16, and 08:11:20: 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 codexDesktopAuthless workflow and clear diagnostics/warning before users spend a reset would still materially help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpriority: P3Low: new provider/client integration, large or experimental feature (>2000 LOC or >50 files), RFC/ro

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions