Skip to content

fix: persist Dictation Cleanup custom API key across restarts#893

Merged
gabrielste1n merged 1 commit into
mainfrom
fix/cleanup-custom-api-key-persistence
Jun 4, 2026
Merged

fix: persist Dictation Cleanup custom API key across restarts#893
gabrielste1n merged 1 commit into
mainfrom
fix/cleanup-custom-api-key-persistence

Conversation

@gabrielste1n
Copy link
Copy Markdown
Collaborator

Summary

Fixes #885 — the Dictation Cleanup custom-provider API key was silently wiped on every app restart, causing cleanup requests to fail with HTTP 401 and fall back to pasting the raw transcription.

Root cause

All four inference scopes (Dictation Cleanup, Voice Agent, Note Formatting, Chat) edit their custom API key in Settings through one generic writer, setResolvedLLMConfig, which only wrote to localStorage.

That works for the other three scopes because their custom keys live in localStorage permanently. But cleanupCustomApiKey is different — it is a secret backed by the OS secure store (CUSTOM_CLEANUP_API_KEY, encrypted via Electron safeStorage). On startup the app:

  1. reads cleanupCustomApiKey back from the secure store (where the UI never wrote it), and
  2. strips cleanupCustomApiKey from localStorage (it is in STALE_SECRET_LOCALSTORAGE_KEYS).

So the key entered via Settings → Language Models → Dictation Cleanup was saved only to localStorage, then read from an empty secure store and wiped from localStorage on the next launch. The dedicated setCleanupCustomApiKey setter (used by Notes onboarding and updateApiKeys) already persists to the secure store correctly — the Settings editor just wasn't using it.

Fix

Route the cleanup scope's customApiKey through the existing setCleanupCustomApiKey setter, which encrypts it to the secure store and invalidates the API-key cache — consistent with how the value is read back on startup. One guard, no new abstractions, other three scopes untouched.

End-to-end trace (verified)

  • Write: Settings editor → setResolvedLLMConfigsetCleanupCustomApiKeydebouncedSaveSecret("cleanupCustom") → IPC save-cleanup-custom-keyEnvironmentManager.saveCleanupCustomKey → encrypted .enc on disk.
  • Read (startup): initializeSettings → IPC get-cleanup-custom-keyEnvironmentManager.getCleanupCustomKey → store state → shown in UI.
  • Consume: ReasoningService.getApiKey("custom") reads the secure store first, falls back to store state. Both populated after the fix.
  • Clearing the field deletes the .enc file (empty value → _deleteSecretKey), as before.

Impact on current users

  • Users who set a Dictation Cleanup custom key via Settings need to re-enter it once after updating; it then persists permanently.
  • Users who configured it via Notes onboarding or the legacy reasoning key path are unaffected (those already wrote to the secure store).
  • No IPC/API/type/signature changes; the other three scopes are unchanged.

Verification

  • npm run typecheck — clean
  • eslint on the changed file — clean

The Settings UI writes every inference scope's custom API key through
setResolvedLLMConfig, which only persisted to localStorage. But
cleanupCustomApiKey is a secret backed by the OS secure store and is
stripped from localStorage on startup, so the key was silently lost on
every restart. Cleanup requests then failed with HTTP 401 and fell back
to pasting the raw, unprocessed transcription.

Route the dictation-cleanup scope's customApiKey through the dedicated
setCleanupCustomApiKey setter so it is encrypted to the secure store and
survives restarts, consistent with how it is read back on startup.

Fixes #885
@gabrielste1n gabrielste1n requested a review from xAlcahest June 4, 2026 00:12
@gabrielste1n gabrielste1n merged commit 18063b3 into main Jun 4, 2026
6 checks passed
@gabrielste1n gabrielste1n deleted the fix/cleanup-custom-api-key-persistence branch June 4, 2026 00:16
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.

Dictation Cleanup API key is not persisted — silently wiped on every app restart

1 participant