Skip to content

fix(openrouter): live settings on status checks, API key in the secret store - #80

Merged
gfsaaser24 merged 2 commits into
turbofrom
fix/openrouter-live-settings
Aug 18, 2026
Merged

fix(openrouter): live settings on status checks, API key in the secret store#80
gfsaaser24 merged 2 commits into
turbofrom
fix/openrouter-live-settings

Conversation

@gfsaaser24

Copy link
Copy Markdown
Owner

OpenRouter went stale, did not hold the API key, and never refreshed its model list.

Cause

makeProviderSnapshotSettingsSource captures the driver config at create time — mapSettings closes 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: checkOpenRouterProviderStatus completing 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

  1. Live settings on every check. The status check now resolves the current config per 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 if settings are unreadable or fail to decode.

  2. 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.ts covers 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.ts shows 20 failures on Windows against a 21-failure baseline on the same machine — pre-existing environmental, none added.

🤖 Generated with Claude Code

t3-turbo-bot and others added 2 commits August 18, 2026 18:32
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>
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ad3d6079-338b-4138-873f-cd841f48e2f9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L labels Aug 18, 2026
@github-actions

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ No successful main baseline artifact is available yet. This run establishes the initial measurement.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 12.6 KiB 15.1 KiB
Codex Thread snapshot wire 6.3 KiB 7.3 KiB
Codex Live turn WebSocket wire 6.3 KiB 7.8 KiB
Codex Live turn WebSocket decoded 51.8 KiB 66.4 KiB
Codex Live turn messages 16 21
Claude Total thread wire 12.6 KiB 15.1 KiB
Claude Thread snapshot wire 6.3 KiB 7.3 KiB
Claude Live turn WebSocket wire 6.3 KiB 7.8 KiB
Claude Live turn WebSocket decoded 52.7 KiB 66.4 KiB
Claude Live turn messages 16 21

Baseline: unavailable · PR result: e939e29 · Source CI: success

Scenario and decoded snapshot size

10 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.

  • Codex decoded thread snapshot: 99.9 KiB
  • Claude decoded thread snapshot: 100.6 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@gfsaaser24
gfsaaser24 merged commit f3e8bfd into turbo Aug 18, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant