feat: Add multi-profile support per provider#21353
feat: Add multi-profile support per provider#21353Pablo-GNU wants to merge 29 commits intoanomalyco:devfrom
Conversation
- Add composite key storage (providerID:profileName) - Implement profile resolution: config authProfile > env var > default - CLI login: prompt profile name before auth method - CLI logout: show profile list after provider selection - Add profile validation (max 20 chars, alphanum + hyphen + underscore) - Add --profile flag to login/logout commands - Maintain backward compat via virtual alias for bare keys - Add authProfile field to Provider.options schema
- parseModel extracts authProfile from providerID if contains ':' - Profile embedded in model string has highest priority - Precedence: embedded > config authProfile > env var > default - Auth.get supports direct lookup of provider:profile keys - Agent.Info model supports optional authProfile field
- currentProviderLabel now shows profile suffix when active - parsed() now returns profile from model state - isModelValid accepts authProfile optional field - model.set includes authProfile when updating - agent model change effect includes authProfile
- message-v2.ts: add authProfile to User.model schema - prompt.ts: copy authProfile from model to userMsg.model - lllm.ts: build auth key with profile when calling Auth.get() - acp/types.ts: add authProfile to ACPSessionState.model - acp/agent.ts: propagate authProfile in setModel call This fixes the bug where embedded profiles (e.g., 'minimax-coding-plan:personal') were lost when creating user messages and never reached Auth.get().
…ikeys
providers.ts:
- Use lastIndexOf + slice instead of split(':') for profile parsing
provider.ts:
- Extract base provider ID from composite auth keys (e.g., 'minimax-coding-plan:personal' → 'minimax-coding-plan')
- This fixes the issue where providers weren't recognized when using profile-based auth keys
When looking up auth credentials: - If profile key exists (e.g., 'minimax-coding-plan:personal'), use it - If profile key doesn't exist but base provider does (e.g., 'minimax-coding-plan'), use that as fallback This fixes the issue where build mode (no profile) wouldn't work when only 'minimax-coding-plan:personal' existed in auth.json. Also removes normalizeKey usage from Auth.get - the fallback logic is now inline and clearer.
When no profile is provided, normalizeKey now returns the base providerID without appending ':default'. This ensures backward compatibility - existing auth.json entries with bare provider keys work correctly.
Propagate authProfile from user messages into resolved models, inject profile-specific api keys into runtime model options in LLM streaming, and include authProfile in Provider.getLanguage cache keys to prevent cross-agent credential leakage.
SessionPrompt.PromptInput now accepts model.authProfile so TUI/API payloads keep profile selection instead of dropping it during validation. This allows profile-specific auth keys to be used end-to-end. debug(auth): increase key preview length in auth log
Prevents stale language model reuse when credentials change at runtime and avoids accidental key leakage across profile switches in the same process.
Use mergeDeep(provider.options, model.options) in resolveSDK so per-request model options (including profile-specific apiKey injected at runtime) override provider-level defaults. This prevents provider.key from overriding the auth key selected for the active profile.
Expand Switch Model entries by configured auth profiles per provider and preserve authProfile in recent/favorites selection keys so profile-specific model picks remain distinct.
…tate Ensure profile variants appear even when direct auth profile discovery is unavailable by combining profile sources from auth keys, configured agents, current model, recents, and favorites.
- Parse auth keys by last colon to avoid malformed profile extraction - Treat bare provider keys as default profile in logout flow - Remove both bare and :default keys when logging out default profile - Validate --profile against discovered profiles fix(tui): only list switch-model profiles present in auth state
In Ctrl+P -> Switch Model -> Connect a provider, prompt for profile name before auth method handling and store API credentials under provider:profile (default maps to bare provider key).
…missing For models without explicit authProfile: - use bare provider key when present - use :default when present - otherwise choose first available provider profile (sorted) Also reflect inferred profile in TUI status when model has no explicit profile.
Treat bare provider keys as default during logout, remove both bare and legacy :default keys, and validate profile selection against discovered profiles. Update auth tests to match bare-key storage semantics and relax memory leak test runtime to avoid CI/local timeout flakes.
|
Hey! Your PR title Please update it to start with one of:
Where See CONTRIBUTING.md for details. |
|
The following comment was made by an LLM, it may be inaccurate: Based on my search, I found two potentially related PRs that may overlap with the current PR #21353:
These PRs likely address similar or overlapping functionality around supporting multiple authentication profiles per provider. You may want to check their current state (open/closed/merged) and review whether PR #21353 incorporates changes from these earlier attempts or if there's duplication of effort. |
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
Both authProfile and variant now exist in the User model, fixing type errors after merging with anomalyco/dev
…eature/auth-multi-profile
Issue for this PR
Closes #13038
Type of change
What does this PR do?
Adds multi-profile auth support per provider and fixes several related auth/TUI issues.
Main changes:
provider:profile) while keeping backward compatibility for legacy bare keys (provider).Ctrl+P -> Switch Model -> Connect provider) before entering API key.:defaultkeys.:defaultif presentWhy this works:
model -> prompt/session -> llm runtime -> provider sdk).How did you verify your code works?
HOME=~/DEV/PERSONAL/.home bun typecheck(inpackages/opencode) ✅HOME=~/DEV/PERSONAL/.home bun test(inpackages/opencode) ✅HOME=~/DEV/PERSONAL/.home bun dev) and CLI (HOME=~/DEV/PERSONAL/.home bun dev -- `):provider:personal/...).build/plan) follow deterministic fallback.auth logoutremoves correct profile/default credentials.Screenshots / recordings
Checklist