From 17b3a14bfa17e606ccb714089a28aa3c664cd69f Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Sat, 3 Jan 2026 01:20:11 +0100 Subject: [PATCH] Fix slow /model selector by deferring OAuth token refresh getAvailable() now uses hasAuth() which checks if auth is configured without triggering OAuth token refresh. Refresh happens later when the model is actually used. --- packages/coding-agent/CHANGELOG.md | 1 + packages/coding-agent/src/core/auth-storage.ts | 14 +++++++++++++- packages/coding-agent/src/core/model-registry.ts | 14 ++++---------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 8bec2142..333fd861 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -38,6 +38,7 @@ ### Fixed +- `/model` selector now opens instantly instead of waiting for OAuth token refresh. Token refresh is deferred until a model is actually used. - Shift+Space, Shift+Backspace, and Shift+Delete now work correctly in Kitty-protocol terminals (Kitty, WezTerm, etc.) instead of being silently ignored ([#411](https://github.com/badlogic/pi-mono/pull/411) by [@nathyong](https://github.com/nathyong)) - `AgentSession.prompt()` now throws if called while the agent is already streaming, preventing race conditions. Use `steer()` or `followUp()` to queue messages during streaming. - Ctrl+C now works like Escape in selector components, so mashing Ctrl+C will eventually close the program ([#400](https://github.com/badlogic/pi-mono/pull/400) by [@mitsuhiko](https://github.com/mitsuhiko)) diff --git a/packages/coding-agent/src/core/auth-storage.ts b/packages/coding-agent/src/core/auth-storage.ts index 0b0c23a5..43ef3c58 100644 --- a/packages/coding-agent/src/core/auth-storage.ts +++ b/packages/coding-agent/src/core/auth-storage.ts @@ -122,12 +122,24 @@ export class AuthStorage { } /** - * Check if credentials exist for a provider. + * Check if credentials exist for a provider in auth.json. */ has(provider: string): boolean { return provider in this.data; } + /** + * Check if any form of auth is configured for a provider. + * Unlike getApiKey(), this doesn't refresh OAuth tokens. + */ + hasAuth(provider: string): boolean { + if (this.runtimeOverrides.has(provider)) return true; + if (this.data[provider]) return true; + if (getEnvApiKey(provider)) return true; + if (this.fallbackResolver?.(provider)) return true; + return false; + } + /** * Get all credentials (for passing to getOAuthApiKey). */ diff --git a/packages/coding-agent/src/core/model-registry.ts b/packages/coding-agent/src/core/model-registry.ts index 16cd6d02..a68866b8 100644 --- a/packages/coding-agent/src/core/model-registry.ts +++ b/packages/coding-agent/src/core/model-registry.ts @@ -350,17 +350,11 @@ export class ModelRegistry { } /** - * Get only models that have valid API keys available. + * Get only models that have auth configured. + * This is a fast check that doesn't refresh OAuth tokens. */ - async getAvailable(): Promise[]> { - const available: Model[] = []; - for (const model of this.models) { - const apiKey = await this.authStorage.getApiKey(model.provider); - if (apiKey) { - available.push(model); - } - } - return available; + getAvailable(): Model[] { + return this.models.filter((m) => this.authStorage.hasAuth(m.provider)); } /**