Skip to content

fix: switch active provider on /login and /logout#59

Merged
assapir merged 4 commits into
mainfrom
fix/provider-switch-on-login
Mar 5, 2026
Merged

fix: switch active provider on /login and /logout#59
assapir merged 4 commits into
mainfrom
fix/provider-switch-on-login

Conversation

@assapir

@assapir assapir commented Mar 4, 2026

Copy link
Copy Markdown
Owner

Problem

When logged into both Anthropic and Google, /model always queries the Anthropic provider regardless of which provider was last authenticated via /login. After /logout from the current provider, /model still tries the old provider even when another is authenticated. The startup banner only showed the active provider's auth status, with no visibility into other authenticated providers.

Fixes #58

Root Cause

/login to a different provider returned CommandResult::Handled (no-op) instead of switching the active provider. The REPL's thinker was never swapped. /model only queried the single active provider.

Changes

1. Provider switching on /login and /logout

StateChange::Provider(String, Option<String>) — new variant that tells the REPL to switch provider, with an optional model override.

build_provider_by_id(id, db_path, model, debug) — builds a ProviderSetup from a string id. Used for runtime provider switches.

/login — when login succeeds for a different provider, returns StateChange::Provider to switch to it. Auth status is derived from storage (not hard-coded).

/logout — after logging out from the current provider, falls back to another authenticated provider if one exists (checks both stored credentials and env vars).

REPL handler — handles StateChange::Provider by calling build_provider_by_id(), swapping the engine's thinker, updating all display state, and persisting the new model preference to the config DB.

2. Banner shows all providers

all_provider_statuses(db_path) — returns auth status for every configurable provider.

The startup banner now lists every provider with its auth status, marking the active one:

   auth      Anthropic (Claude Pro/Max) (OAuth ✓) ← active
             Google (Gemini) (not authenticated)

3. /model shows models from all authenticated providers

/model now fetches models from all authenticated providers (not just the active one), displays them grouped by provider, and allows switching provider + model in one step:

  Anthropic (Claude) ← active:
    1. Claude Sonnet 4 ← current
    2. Claude Haiku 3.5

  Google (Gemini):
    3. Gemini 2.0 Flash
    4. Gemini 2.5 Pro

  Select model [1]:

Selecting a model from a different provider automatically switches the active provider via StateChange::Provider(id, Some(model)).

4. Review feedback addressed

  • Removed unnecessary env var save/restore from build_provider_by_id tests (avoids parallel test races)
  • Logout fallback checks env vars too, not just stored credentials (consistent with rest of app)
  • Login derives auth status from storage via provider_auth_status() instead of hard-coding "OAuth ✓"
  • Provider switch persists model preference to config DB

New public API

Function Purpose
build_provider_by_id() Build a provider by string id with optional model override
all_provider_statuses() Auth status for all providers (for banner)
provider_auth_status() Auth status for a single provider
is_authenticated() Bool check for provider authentication

Testing

23 new tests covering:

  • build_provider_by_id — known/unknown providers, auth detection, default model, model override
  • find_authenticated_provider — fallback logic (empty, excluded, found)
  • StateChange::Provider — variant dispatch
  • all_provider_statuses / is_authenticated / provider_auth_status — status helpers
  • find_other_authenticated_providers — empty db
  • Banner — multiple providers, no providers
  • provider_display_name — known and unknown ids

When /login succeeds for a different provider than the current one,
the REPL now switches to that provider (swaps the thinker, updates
the displayed provider name, model, and auth status).

When /logout removes credentials for the current provider, the REPL
falls back to another authenticated provider if one exists.

Adds StateChange::Provider variant and build_provider_by_id() for
runtime provider switching.

Closes #58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes REPL provider state not updating when authenticating/logging out across multiple providers, ensuring commands like /model operate against the currently active authenticated provider.

Changes:

  • Added StateChange::Provider(String) to allow commands to request a provider switch.
  • Introduced build_provider_by_id() for rebuilding the active provider/thinker using provider defaults when switching at runtime.
  • Updated /login and /logout flows plus the REPL handler to switch providers appropriately; added tests for the new behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/login_test.rs Adds tests for build_provider_by_id behavior and auth/model resolution expectations.
src/provider.rs Adds build_provider_by_id() helper for runtime provider switching using default model.
src/main.rs Handles StateChange::Provider by rebuilding provider setup and swapping the engine thinker + display state.
src/commands/mod.rs Adds StateChange::Provider and a registry dispatch test to ensure the payload is carried through.
src/commands/logout.rs Adds fallback logic to switch to another provider after logout if credentials exist.
src/commands/login.rs Updates /login to switch active provider when logging into a different provider.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/login_test.rs Outdated
Comment thread src/commands/logout.rs Outdated
Comment thread src/commands/login.rs Outdated
assapir added 3 commits March 4, 2026 14:29
…oviders

Banner now lists auth status for every provider (marking the active one).
/model fetches and displays models from all authenticated providers,
grouped by provider. Selecting a model from a different provider
automatically switches the active provider.

StateChange::Provider now carries an optional model override.
build_provider_by_id accepts an optional model parameter.
New helpers: all_provider_statuses(), is_authenticated().
- Remove unnecessary env var save/restore from build_provider_by_id
  tests (no auth_status assertions, avoids parallel test races)
- Logout fallback now checks env vars too, not just stored credentials
- Login derives auth status from storage instead of hard-coding 'OAuth ✓'
- Add provider_auth_status() public helper with tests
- Persist model preference to config DB on provider switch
The auth label and continuation lines now use the same 10-char label
column as the rest of the banner (provider, shell, workdir, etc.).
@assapir assapir merged commit dd916de into main Mar 5, 2026
4 checks passed
@assapir assapir deleted the fix/provider-switch-on-login branch March 5, 2026 06:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

when both anthropic and google logged in, only anthropic models are visible

2 participants