microsoft / microsoft/vscode

agentHost: adding a Claude credential while gated at "Sign in to use Agents" needs a restart

Open
#329,722 0 comments 0 reactions 1 assignee Claimed by @vritant24 View on GitHub
Dominant language
TypeScript
Stars
193k
Forks
42.4k
PR merge metrics
PR metrics pending

Description

### Symptom

A signed-out user with no Anthropic credential opens the Agents window and hits the **"Sign in to use Agents"** gate. They then set up a Claude credential (an `ANTHROPIC_API_KEY` / `CLAUDE_CODE_OAUTH_TOKEN` in `~/.claude/settings.json` or the environment) and return to the window.

Nothing happens. The gate stays up until the app is restarted — even though the user now has exactly the setup the signed-out feature exists to serve.

### Why

The gate is `resolveAgentAuthRequirement`, which needs **both** halves to flip, and neither is reactive at agent level while no session exists:

1. **`protectedResources[].required`** — `ClaudeAgent.getProtectedResources()` reads the credential on demand, but agent infos are only republished on the `agents` observable, `onDidCustomizationsChange`, or `RootConfigChanged`. A credential file appearing triggers none of them.
2. **`models.length`** — `_refreshModels()` gates the native catalog on `detectExistingClaudeSetup`, so it would pick the credential up, but nothing calls it. `AgentModelRefreshScheduler._refreshActive` only ticks providers in `_activeSinceLastRefresh`, which is populated exclusively by `onDidStartTurn`. A gated user has never started a turn, so Claude is never refreshed. Catch-22.

`ClaudeCustomizationWatcher` does watch `/.claude` recursively, but it's constructed per **session** (`claudeAgentSession.ts`) — and the gated scenario has zero sessions.

### Note on scope

Half of this is long-standing: before #329718 the same user was already stuck, via `models: 0` → `Unusable`. #329718 made `required` a second stale input but did not create the stuck state, and fixing only `required` would not unstick anyone, because the model count would still be `0`. **Both halves have to move together**, which is why it wasn't folded into that PR.

### Sketch

- Add an optional `onDidChangeProtectedResources?: Event` to `IAgent`, wired in `AgentSideEffects._registerAgentListeners` next to `onDidCustomizationsChange` so it calls `_publishAgentInfos`. (Reusing `onDidCustomizationsChange` for this would work mechanically but is the wrong signal, and the repo guidance discourages events driving cross-component control flow.)
- Give `ClaudeAgent` an agent-lifetime watcher on the credential sources, firing that event **and** kicking `_startModelRefresh()` when usability actually flips, so both gate inputs update together.
- Prefer a correlated watcher (`fileService.createWatcher`) per the repo guideline, debounced like `ClaudeCustomizationWatcher`.

Worth checking whether Codex has the same shape for its own native providers.

Found during review of #329718 (thanks @copilot-pull-request-reviewer for spotting the reactivity gap).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.