Repository navigation
Chained clients (provider hub) drop per-model context windows the hub already serves — every routed row materializes at the 128k fallback #4032
Description
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
- Hub 2.48.0,
runtimeRole: hub, per-providermodelContextWindowsconfigured. 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 havecontext_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.
- Client 2.48.0: single provider
hub(baseUrl→ hub data plane/v1,liveModels: true,allowPrivateNetwork: true),ocx service install+ocx sync. - Client catalog
~/.codex/opencodex-catalog.json: everyhub/*row ="context_window": 128000, "max_context_window": 128000.hub/cursor-gpt-5.6-sol128000 (real 1,000,000),hub/zai-glm-5.3-flash128000 (real 1,000,000),hub/alibaba-token-plan-intl-qwen3.8-max128000 (real 983,616). Only rows backed by the client's own localopenaiforward provider keep real roster values (272000) — the loss is specific to routed rows. - Where it drops: routed-row assembly never maps the hub-served metadata into the discovered window (
applyProviderConfigHintsinsrc/codex/catalog/provider-fetch.tssees no discovered value), sosrc/codex/catalog/parsing.tsapplies its128000compatibility fallback at materialization. - Workaround we run today (effective, but per-client and manual): set
providers.hub.modelContextWindowson each client, keyed by the/v1/modelsid space, plusmodelMaxInputTokens.configuredContextWindow()fills the value because discovery is absent, and the gather fingerprint (providerCatalogFingerprintincludesctxW) invalidates the cache so the nextocx syncpicks it up. Result: 227/449 rows corrected on one client, 220/441 on another; a streamed call throughhub/gpt-5.6-lunacompletes.
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
- When assembling routed rows for a provider whose listing carries per-model metadata, map
capabilities.context_length/max_output_tokensfromGET /v1/modelsinto the discovered window instead of dropping it — that alone fixes provider-based chained clients with zero operator config. - Alternatively (or additionally), have the provider-based sync path consume the same
GET /v1/catalogpayload theconnectflow already downloads — it carries the operator-curatedmodelContextWindowstruth byte-for-byte. - 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: 272000applies); routed API-billed rows should get the API truth instead of the 128k floor. - 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
lidge-jun commentedon Sep 8, 2026
리뷰 · 우선순위 70 / 80
이 이슈는 tizerluo가 보고한 허브 체이닝 메타데이터 유실이다. 허브(
runtimeRole: hub)는GET /v1/catalog와GET /v1/models에 모델별 context window를 이미 실어 보낸다. 예:cursor/gpt-5.6-solcatalog 1,000,000, models APIcapabilities.context_length922,000. 그런데 클라이언트가 provider 하나(hub,liveModels: true, data-plane/v1)로만 붙으면,ocx sync뒤~/.codex/opencodex-catalog.json의 모든hub/*행이context_window: 128000으로 떨어진다. Codex는 대략 121.6k에서 컴팩트한다. 1M급 모델에서 쓸 수 있는 문맥의 대부분을 에러 없이 버린다. 로컬openaiforward 행만 정상(272000)이고, 유실은 routed 행에만 난다.지금
devHEAD29bb221c3의 코드를 보면 원인 후보가 바로 보인다.src/codex/catalog/provider-fetch.ts의catalogHintsFromModelsApiItem은 context window를limits.max_context_length,capabilities.limits.max_context_window_tokens,metadata.context_length, 최상위item.context_length등에서 읽는다. 그런데 허브/v1/models가 쓰는capabilities.context_length는 읽지 않는다. 같은 함수는capabilityRecord?.max_output_tokens는 이미 읽는다. 즉 capabilities 객체의 출력 한도는 먹고, context_length는 안 먹는 비대칭이다. discovered window가 비면applyProviderConfigHints가 채워 줄 값이 없고,src/codex/catalog/parsing.ts물질화 단계에서 호환 폴백128000이 들어간다. 작성자가 쓴 워크어라운드(providers.hub.modelContextWindows를/v1/modelsid 공간으로 수동 기입)는configuredContextWindow()경로라서 동작한다. 다만 클라이언트마다 손으로 맞춰야 한다.점수는 70이다. 재현이 구체적이고, HEAD에서 경로가 확인되며, hub 운영자에게 침묵 손실이 크다. tip(
#4002)과는 다른 축이지만 catalog/platform 버그 우선순위는 높다. 부가로 catalog slug(zenmux/openai-gpt-5.6-sol)와/v1/modelsid(zenmux/openai/gpt-5.6-sol)의 슬래시 모양이 달라 교차 참조가 깨지는 papercut도 같이 적혀 있다. 이건 본버그와 묶어도 되고, 따로 잘라도 된다.라인 / 경로로 보면 문제·확인할 지점은 이렇다.
src/codex/catalog/provider-fetch.tscatalogHintsFromModelsApiItem-capabilityRecord?.context_length를positiveSafeInteger후보에 넣지 않는다. 허브가 내려주는 바로 그 필드를 놓친다src/codex/catalog/provider-fetch.ts같은 함수의maxOutputTokens-capabilityRecord?.max_output_tokens는 이미 읽는다. context만 빠진 비대칭이 버그의 핵심 증거다src/codex/catalog/parsing.ts물질화 폴백128000- discovered/configured가 없을 때의 호환 기본값이다. 폴백 자체를 없애기보다, discovery가 hub capabilities를 먹게 고치는 쪽이 맞다허브
GET /v1/catalogvs 클라이언트 liveModels 경로 - connect 플로우는 catalog payload를 쓰지만, provider 기반 체이닝은 models API discovery에 기대는 것으로 보인다. catalog의 operator-curatedmodelContextWindows를 sync에 태울지도 설계 선택이다id 모양 papercut - nested vendor에서 catalog 단일 슬래시 vs models 다중 슬래시.
modelContextWindows키와 교차 참조를 어렵게 만든다. 본수정과 분리 가능메인테이너의 판단이 필요한 지점
/v1/catalog도 소비하게 할지너의 추천
도움 환영 / 작은 패치로 고치세요. 1순위는
catalogHintsFromModelsApiItem에capabilityRecord?.context_length를 넣고, hub/v1/modelsfixture로 회귀 테스트를 고정하는 것이다. 그보다 크면 liveModels sync가 hub catalog의 per-model window를 함께 먹게 하면 작성자 제안 2번과 맞는다. 워크어라운드는 임시로 두고, 랜딩 후 릴리즈 노트에 “체이닝 클라이언트 128k 폴백”을 명시하세요. types/config 대분할과 무관하다. 중복 이슈로 당장 닫을 근거는 없다.이 댓글은 grok-bot이 작성했습니다
wp4: fix four reported bugs with no owning pull request (#4058)
lidge-jun commentedon Sep 8, 2026
Fixed on
devin ff524ae (via #4058).catalogHintsFromModelsApiItemalready read the hub's capability record formax_output_tokensbut never for the window, so a hub servingcapabilities.context_length: 922000produced a window-less row and materialization applied the 128k floor. One argument is appended last to the existingpositiveSafeIntegerchain, so any provider that already resolves a window — Command Code and Featherless publish a top-levelcontext_length, which still wins — is unaffected. A hub row that previously materialized at 128000 now materializes at its real value.Regression test
tests/codex-integration/catalog-hub-context-window.test.tscovers both shapes the hub can send, pins the ordering contract, and rejects zero, negative, and string values. It fails ondevwithout the fix (4 pass / 2 fail).Closing manually because pull requests here target
dev, and GitHub only auto-closes on merge intomain.wp4: fix four reported bugs with no owning pull request (lidge-jun#4058)