Skip to content

Chained clients (provider hub) drop per-model context windows the hub already serves — every routed row materializes at the 128k fallback #4032

Description

@tizerluo

Client or integration

Other

Area

Catalog / models

Summary

A chained client (single provider hub pointing at a remote hub data plane, liveModels: true — the provider-based chained setup, not ocx connect) materializes every hub-routed row with context_window: 128000 — the parser's compatibility fallback — even though the hub already serves correct per-model windows on two surfaces. Effect: Codex compacts at ~121.6k effective tokens on 1M-class models (cursor GPT-5.6, zai GLM-5.3), silently discarding ~87% of usable context on chained machines.

Reproduction

  1. Hub 2.48.0, runtimeRole: hub, per-provider modelContextWindows configured. The hub's own surfaces carry the truth:
    • GET /v1/catalog (the shared serializer used by the dashboard and the data-plane route): all 436 entries have context_window > 0, e.g. "slug":"cursor/gpt-5.6-sol","context_window":1000000, "slug":"zai/glm-5.3-flash","context_window":1000000, "slug":"alibaba-token-plan-intl/qwen3.8-max","context_window":983616.
    • GET /v1/models: "id":"cursor/gpt-5.6-sol","capabilities":{"context_length":922000,"max_output_tokens":128000,...} — per-model metadata is present here too.
  2. Client 2.48.0: single provider hub (baseUrl → hub data plane /v1, liveModels: true, allowPrivateNetwork: true), ocx service install + ocx sync.
  3. Client catalog ~/.codex/opencodex-catalog.json: every hub/* row = "context_window": 128000, "max_context_window": 128000. hub/cursor-gpt-5.6-sol 128000 (real 1,000,000), hub/zai-glm-5.3-flash 128000 (real 1,000,000), hub/alibaba-token-plan-intl-qwen3.8-max 128000 (real 983,616). Only rows backed by the client's own local openai forward provider keep real roster values (272000) — the loss is specific to routed rows.
  4. Where it drops: routed-row assembly never maps the hub-served metadata into the discovered window (applyProviderConfigHints in src/codex/catalog/provider-fetch.ts sees no discovered value), so src/codex/catalog/parsing.ts applies its 128000 compatibility fallback at materialization.
  5. Workaround we run today (effective, but per-client and manual): set providers.hub.modelContextWindows on each client, keyed by the /v1/models id space, plus modelMaxInputTokens. configuredContextWindow() fills the value because discovery is absent, and the gather fingerprint (providerCatalogFingerprint includes ctxW) invalidates the cache so the next ocx sync picks it up. Result: 227/449 rows corrected on one client, 220/441 on another; a streamed call through hub/gpt-5.6-luna completes.

Papercut discovered while keying that map: the two hub surfaces disagree on id shape for nested vendors — catalog slugs are single-slash (zenmux/openai-gpt-5.6-sol) while /v1/models ids are multi-slash (zenmux/openai/gpt-5.6-sol), and the client flattens all slashes to -. Any cross-referencing code (or operator) has to collapse both sides to match.

Version

2.48.0 (hub and clients)

Operating system

Hub: Ubuntu 24.04 (Contabo VPS); clients: macOS 26 and Ubuntu VPS

Provider and model

Any hub-routed provider. Observed: cursor/gpt-5.6-sol (1,000,000 → 128,000), zai/glm-5.3-flash (1,000,000 → 128,000), alibaba-token-plan-intl/qwen3.8-max (983,616 → 128,000)

Logs or error output

No error — silent metadata loss. Verified comparison:

model                                        hub /v1/catalog   hub /v1/models capabilities   client catalog after sync
cursor/gpt-5.6-sol                           1,000,000         context_length 922,000          128,000
zai/glm-5.3-flash                            1,000,000         —                              128,000
alibaba-token-plan-intl/qwen3.8-max          983,616           —                              128,000
gpt-5.6-sol (hub's own openai roster row)    272,000           context_length 922,000          128,000 (routed) vs 272,000 (local native row — correct)

Screenshots and supporting files

No response

Redacted configuration

Client (chained setup):

{
  "providers": {
    "hub": {
      "adapter": "openai-responses",
      "baseUrl": "http://<hub-tailnet-ip>:10100/v1",
      "allowPrivateNetwork": true,
      "authMode": "key",
      "liveModels": true
    }
  },
  "defaultProvider": "hub"
}

Workaround added per client (keys in /v1/models id space):

{
  "providers": {
    "hub": {
      "modelContextWindows": {
        "cursor/gpt-5.6-sol": 1050000,
        "zenmux/openai/gpt-5.6-sol": 1050000,
        "zai/glm-5.3-flash": 1000000
      },
      "modelMaxInputTokens": { "cursor/gpt-5.6-sol": 922000 }
    }
  }
}

Suggested fix

  1. When assembling routed rows for a provider whose listing carries per-model metadata, map capabilities.context_length / max_output_tokens from GET /v1/models into the discovered window instead of dropping it — that alone fixes provider-based chained clients with zero operator config.
  2. Alternatively (or additionally), have the provider-based sync path consume the same GET /v1/catalog payload the connect flow already downloads — it carries the operator-curated modelContextWindows truth byte-for-byte.
  3. Worth preserving while fixing: bare native rows correctly keep the roster's plan-effective window today (e.g. 272000 for GPT-5.6 via a ChatGPT plan, where pricing.overrides.min_prompt_tokens: 272000 applies); routed API-billed rows should get the API truth instead of the 128k floor.
  4. Papercut: unify catalog-slug vs /v1/models-id shape for nested vendors (single- vs multi-slash) so the two surfaces can be cross-referenced without collapsing separators.

Activity

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

    bugSomething isn't workingcatalogModel catalog, slugs, visibility, routed entriesplatformOS/service/tray/ACL (Windows-heavy, not Windows-only)serviceService lifecycle (WinSW/launchd/scheduler)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions