Skip to content

[Feature]: config-level retainModels allow-list so operators keep configured models in the authoritative live catalog #1690

Closed

Description

@rrmlima

Problem to solve

When a provider does live model discovery, the authoritative catalog drops configured models that the upstream does not (yet) return — even when the operator explicitly configured them and the wire mapping exists in code. Concretely:

  • google-antigravity (Cloud Code Assist) does not return gemini-3.7-flash from :fetchAvailableModels for accounts where the model is not yet provisioned, so the picker loses the model even though the operator configured it (see [Bug]: v2.15.1 drops gemini-3.7-flash from Antigravity live discovery on macOS #1683 for the user-facing symptom).
  • Today the only retention paths are: the hardcoded CALLABLE_CONFIGURED_COMPATIBILITY_MODELS allow-list (kimi, xai), combo targets, and the Vertex default seed. There is no operator-facing, config-level way to say "keep this configured model in the catalog even if discovery omits it."

Operators who run proxies for their own account know their provider's roadmap (e.g. "gemini-3.7-flash is coming to my region; keep the row so it appears the moment the upstream enables it") and should not need a code change per model.

Proposed solution

  1. Add a config-level retention list per provider: providers.<name>.retainModels: string[].

    {
      "providers": {
        "google-antigravity": {
          "retainModels": ["gemini-3.7-flash"],
          "modelCosts": {
            "gemini-3.7-flash": { "input": 0.75, "output": 3.75, "cacheRead": 0.15, "cacheWrite": 0 }
          }
        }
      }
    }
  2. In mergeConfiguredModelsIntoLiveCatalog (src/codex/catalog/provider-fetch.ts), extend the retention condition:

    if (
      seedVertexDefault === true
      || shouldRetainConfiguredProviderModel(name, candidate.id)
    + || (retainConfiguredModelIds?.has(candidate.id) === true)
    + || (providerRetainModels?.has(candidate.id) === true)
      || (retainComboTargets && retainConfiguredModelIds?.has(candidate.id) === true)
    ) {
      out.push(candidate);
      present.add(candidate.id);
      continue;
    }
  3. When a retained model is invoked but the upstream returns 404/not-found, surface a clear diagnostic (log + warnDroppedConfiguredIdsOnce-style one-shot warning) so a model that "exists in the picker but is not callable yet" is not silently hidden — the operator sees exactly why.

  4. Seed CALLABLE_CONFIGURED_COMPATIBILITY_MODELS with google-antigravity: ["gemini-3.7-flash"] as the first entry, so the picker row exists out-of-the-box for antigravity users while the upstream catches up (mirrors the existing kimi/xai pattern).

Alternatives considered

  • Keep the hardcoded allow-list only: works but requires a code change + release per model/per provider; does not scale to operator-specific account states.
  • Make discovery "never drop configured models": would resurrect stale/broken models for everyone (the reason the authoritative catalog exists); the retention must be explicit and opt-in.
  • Document "wait for upstream": not actionable for operators who know their model is coming; the row should exist with a clear "not callable yet" state.

Additional context

  • Related open issue: [Bug]: v2.15.1 drops gemini-3.7-flash from Antigravity live discovery on macOS #1683 (gemini-3.7-flash dropped from Antigravity live discovery).
  • Precedent for static + live coexistence: other gateways keep a static model list alongside live discovery (e.g. OmniRoute QODER_STATIC_MODELS + live --list-models fallback in open-sse/services/qoderCli.ts).
  • The existing warnDroppedConfiguredIdsOnce infrastructure already logs dropped configured ids once per signature — the retention path should reuse it for the inverse case (retained-but-404) so logs stay quiet in steady state.

Acceptance criteria:

  • retainModels entry absent from discovery → row present in catalog (visibility list).
  • Invoking a retained-but-unavailable model → 4xx from upstream is surfaced with a one-shot diagnostic log; the catalog row stays.
  • Without retainModels → current behavior unchanged (no behavior change for existing users).

Activity

  1. added
    enhancementNew feature or request
    catalogModel catalog, slugs, visibility, routed entries
    on Aug 14, 2026
  2. coderabbitai commented on Aug 14, 2026

    @coderabbitai
    Contributor
    ⚠️ Possible Duplicate Issue(s)
    🔗 Related PRs

    #354 - fix(models): surface discovery failure status when /v1/models returns 401 (#329) [open]
    #652 - feat(providers): add bounded model discovery contract [merged]
    #963 - fix(catalog): preserve provider capabilities on custom models [open]
    #1331 - fix(catalog): keep failover combos when live discovery omits members [merged]
    #1658 - fix(antigravity): discover live tiered models from CCA [merged]


    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  3. lidge-jun commented on Aug 19, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 42 / 80

    라이브 디스커버리가 아직 안 돌려주는 설정 모델을 운영자가 카탈로그에 남겨 두고 싶다는 요청입니다. google-antigravity의 gemini-3.7-flash처럼 계정에 아직 프로비저닝되지 않은 모델이 피커에서 사라지는 증상(#1683)이 배경입니다. 모든 설정 모델을 무조건 남기면 깨진 줄이 다시 살아나서, 명시적 허용 목록이 필요합니다.

    현재 dev의 src/codex/catalog/provider-fetch.ts를 보면 CALLABLE_CONFIGURED_COMPATIBILITY_MODELS는 kimi와 xai만 들고 있습니다. shouldRetainConfiguredProviderModel()도 그 하드코드와 opencode-free 규칙만 봅니다. mergeConfiguredModelsIntoLiveCatalog()는 Vertex 시드, 위 함수, 콤보 타깃만 남기고 나머지는 droppedConfiguredIds로 보냅니다. providers.*.retainModels 필드는 이 조건에 없습니다.

    이슈가 제안한 설정 형태는 운영자 허용 목록을 코드 변경 없이 넣는 것입니다. 유지된 모델을 호출했는데 업스트림이 404면, 피커에서 지우지 말고 warnDroppedConfiguredIdsOnce 같은 한 번만 찍는 진단이 필요합니다. 설정이 없으면 지금 동작을 바꾸면 안 됩니다.

    해결방안: mergeConfiguredModelsIntoLiveCatalog 유지 조건에 설정 retainModels를 더하고, 404는 한 줄 진단으로 남기면 됩니다. antigravity 시드를 하드코드에 넣는 일은 제품 판단이지만, 설정 경로가 있으면 모델마다 릴리스할 필요는 없습니다. 디스커버리에서 무조건 설정 모델을 남기는 패치는 이 이슈와 맞지 않습니다.

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

  4. lidge-jun commented on Aug 19, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 42 / 80 · 유지

    라이브 디스커버리가 모델을 안 주면 피커에서 빠짐. 지금 남는 길은 하드코딩 CALLABLE_CONFIGURED_COMPATIBILITY_MODELS(kimi/xai), 콤보 타겟, Vertex 시드뿐임. 설정으로 retainModels 주고 남겨 달라는 요청. 증상은 #1683.

    유지함. 전부 남기면 죽은 모델이 다시 살아나서, opt-in만. 호출 404는 한 번만 경고하고 행은 유지.

    해결방안: providers.<name>.retainModels + mergeConfiguredModelsIntoLiveCatalog 조건 추가. 기본 동작은 그대로.

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

  5. 68 remaining items

  6. lidge-jun commented on Sep 1, 2026

    @lidge-jun
    Owner

    Landed on dev via #3206 (squash 6a6efa928), carrying #2860's retention predicate and #2122's config/migration design.

    What shipped:

    • providers.<name>.retainModels: string[] keeps listed ids in the routed catalog when live discovery omits them. Ids do not need to be repeated in models; they get the same context/effort hints and survive liveModels: false.
    • Validated at config load and through the management PATCH (null/empty clears); echoed in the provider DTO.
    • CLI: ocx provider edit <name> --retain-models <id,id|->.
    • Rename migration covers the new list.
    • Default behavior is unchanged when the key is absent.

    Not included (deliberately): seeding gemini-3.7-flash as an antigravity product default (with the config key available this no longer needs a release), a dashboard field (the PATCH contract is ready for one), and a 404-time warning. selectedModels still narrows what is visible, so an id must be in both lists when an allowlist is active.

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

    catalogModel catalog, slugs, visibility, routed entriesenhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions