fix(openrouter): live settings on status checks, API key in the secret store - #80
Conversation
Provider snapshot settings sources capture the driver config at create time: `makeProviderSnapshotSettingsSource` closes over the config it was seeded with, so every later refresh re-probed with the config the instance was born with. That is harmless for drivers whose credentials live outside settings, but OpenRouter keeps its API key in that config, so a key saved after boot never reached the probe. The provider stayed on "add an API key", the model catalog never refreshed past the fallback list, and the snapshot looked permanently stale. The status check now resolves the current config on each run, preferring an explicit `providerInstances` entry over the legacy `providers.openrouter` block (matching ProviderInstanceRegistryHydration), and rebuilds the OpenRouter-owned process env from it. Falls back to the create-time config when settings are unreadable or fail to decode. Adds persistence tests covering the schema round trip, whole-map replacement, and the instance-over-legacy precedence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The key was only readable from `settings.json`, which is plain text, travels with settings exports, and is the same blob the UI rewrites wholesale. It now resolves from the server secret store (0600 files under the secrets dir), keyed per instance as `provider-<instanceId>-api-key`, so several OpenRouter instances can hold different accounts. Resolution order: a key typed into settings still wins, so an explicit edit applies immediately; otherwise the stored secret is used. When settings do carry a key it is copied into the secret store, so entering one in the UI gives the credential a home outside the settings blob. The secret store is taken as an optional service, so the driver still builds in contexts that do not wire one (tests, minimal embeddings) and simply falls back to the settings key. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
OpenRouter went stale, did not hold the API key, and never refreshed its model list.
Cause
makeProviderSnapshotSettingsSourcecaptures the driver config at create time —mapSettingscloses over the config it was seeded with, so every later status check re-probes with the config the instance was born with. That is harmless for drivers whose credentials live outside settings (Claude, Codex), but OpenRouter keeps its API key in that config, so a key saved after boot never reached the probe.Observed on a live install:
checkOpenRouterProviderStatuscompleting in 0.06 ms, i.e. the "no API key" short circuit, while the provider was configured.Result: permanent "add an API key", model catalog stuck on the built-in fallback list, snapshot looking stale.
Changes
Live settings on every check. The status check now resolves the current config per run, preferring an explicit
providerInstancesentry over the legacyproviders.openrouterblock (matchingProviderInstanceRegistryHydration), and rebuilds the OpenRouter-owned process env from it. Falls back to the create-time config if settings are unreadable or fail to decode.API key moves to the secret store. Keyed per instance as
provider-<instanceId>-api-key(0600 files under the secrets dir), so multiple instances can hold different accounts. A key typed into settings still wins so an explicit edit applies at once; when settings carry one it is copied into the secret store. The secret store is an optional service, so the driver still builds where none is wired and falls back to the settings key.Tests
OpenRouterSettingsPersistence.test.tscovers the schema round trip, whole-map replacement not dropping the key, instance-over-legacy precedence, key resolution order (including a trailing newline in the secret file), and per-instance secret naming.25 OpenRouter tests pass; typecheck clean.
ProviderRegistry.test.tsshows 20 failures on Windows against a 21-failure baseline on the same machine — pre-existing environmental, none added.🤖 Generated with Claude Code