| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
On a fresh open of LevelCode, a paid plan's model picker showed only TWO models (the free engine + the flagship) instead of the full roster — no Opus 4.8, no Kimi K3, and none of the "×credits · ctx · turns left" detail or "coming soon" rows. That is the OFFLINE fallback branch of pickCloudModel, reached whenever fetchCloudRoster returns no models. Cause: fetchCloudRoster returned null on ANY non-OK response and, unlike the profile fetch (webHandoffUrl) and the agent loop, did NOT refresh the token on a 401. Access tokens are short-lived, so the FIRST roster request after a fresh open is made with last session's expired token → 401 → null → 2-model fallback. The account WEB page looked correct because it authenticates differently and refreshes. Fix, mirroring the proven webHandoffUrl retry: - On 401, refreshCloudToken() once and retry with the fresh token. - Gate on the stored TOKEN, not the cloudSignedIn flag — the flag can still be false mid-activation while a valid token exists, which was a second path to the same degraded menu. - On a genuinely transient failure, return the last-known-good roster (cloudRoster) instead of collapsing to the 2-model fallback; the menu just omits the credits/turns detail it can't recompute offline. Not unit-tested — this is vscode-requiring host glue with no pure seam to extract; it is verified by reading and by matching webHandoffUrl's battle-tested pattern (now the second of two 401-refresh call sites). I could not reproduce the live 401 without a running, signed-in editor, so this fixes the identified code path rather than an observed repro. Full gate: 24 suites, 0 failures. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Fixes a LevelCode Cloud gateway UX regression where the model picker could incorrectly fall back to the 2-model “offline” list on fresh launch due to an expired access token causing the first roster fetch to 401.
Changes:
extensions/levelcode-ai/extension.js:251
if (!res.ok) { dbg('cloud.roster', { ok: false, status: res.status }); return cached(); }
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Sorry, something went wrong.
…review) 1. The comment claimed "credits/turns aren't cached", but cloudRoster = data.models caches the per-model fields including turns_left, so the cached-roster fallback CAN show a slightly stale "≈ turns left". Only the account-level credit BALANCE is genuinely not carried (the "$X credits left" header is omitted until the next good fetch). Comment now says exactly that. 2. After refreshCloudToken() succeeds, the refreshed secret was used unchecked — if it came back falsy the retry would send `Authorization: Bearer null`, noise that masks the real 401. Now the retry only fires when the refreshed token is truthy; otherwise it falls through to the cached-roster path. Comment-and-guard only, no behaviour change on the happy path. Full gate: 24 suites, 0 failures. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…array (PR #43 review) The retry returned `data || cached()`, so any truthy JSON that lacked a valid `models` array — a 200 with an error object, a partial response, a schema drift — was returned as-is. pickCloudModel then sees "no models" and collapses to the 2-model fallback even though cloudRoster still holds a good list, defeating the whole point of the cache. Now a payload only counts as a roster when data.models is an array; otherwise it returns cached(). Also fixes the mirror case where a 200 arrives but json() failed (data null) — same fall-through to the cache. Full gate: 24 suites, 0 failures. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| /** Fetch the plan's model roster (entitled models + credits + ≈ turns-left). Caches it for the | ||
| * footer/picker. Best-effort; returns null when signed out / offline / not gateway. */ | ||
| async function fetchCloudRoster() { |
| Back | FazBrowse Home | New Git URL |
Reported: on a fresh open, the Pro+ model picker shows only two models (gpt-oss-120b + Kimi K2.7 Code) instead of the full roster.
It's the offline fallback, not an entitlement bug
The screenshot is unmistakably pickCloudModel's offline fallback branch:
So the roster came back empty and it degraded. The account web page shows Opus 4.8 + Kimi K3 as live because it authenticates differently and refreshes on 401.
Root cause
fetchCloudRoster returned null on any non-OK response and — unlike the profile fetch (webHandoffUrl) and the agent loop — did not refresh the token on a 401. Access tokens are short-lived, so the first roster request after a fresh open uses last session's expired token → 401 → null → 2-model fallback.
Fix (mirrors the proven webHandoffUrl retry)
Honest verification note
This is vscode-requiring host glue with no pure seam to unit-test. It's verified by reading and by matching webHandoffUrl's battle-tested pattern (now the second of two 401-refresh call sites). I could not reproduce the live 401 without a running, signed-in editor — so this fixes the identified code path, not an observed repro. Full gate: 24 suites, 0 failures.
To confirm on your side: open the picker on a fresh launch with levelcode.ai.debug on — a cloud.roster {ok:false, status:401} in the log before this fix is the fingerprint.
🤖 Generated with Claude Code