Repository navigation
feat(settings): show and switch the provider in use on AI Providers - #104
Merged
Merged
Conversation
Release builds are stamped with the git tag (v3.6.0), so the template's hardcoded "v" produced "vv3.6.0". versionLabel() (core/version-label.ts) now adds the prefix only to a bare version number: tags and git-describe output keep their own "v", a dev build shows "dev" rather than "vdev", and a lone commit hash from `git describe --always` stays as it is. The About tab uses the same label, so both places read alike. Closes #21
Bedrock is a stub that only returns "not yet supported", yet it sat in the Active Provider dropdown with its own key field. It is gone from both, and README, CLAUDE.md and the website no longer list it. The Go stub and the settings value stay so #23 can bring it back. A settings file that already names bedrock is left as it is: switching it would send the user's text to a service they never chose. Settings and Pyramidize both show "Choose a provider" with a note that AWS Bedrock is not available yet. Pyramidize also stays disabled, skips the key banner and model probe for it, and so never reaches the raw "unsupported provider" error. Picking any provider clears the note. Closes #22
Only the dark theme is styled. Choosing Light dropped PrimeNG into its unstyled light mode, and System did nothing. The theme control is gone (a dropdown with one entry is not a choice), and applyTheme() keeps .app-dark whatever theme_preference says, so a value saved by an older version cannot unstyle the app either. The field stays in the settings model and is saved unchanged, for the light theme in #25. The dark-mode E2E spec gains a test that serves a stored "light" through the Wails runtime endpoint and asserts the page stays dark with no theme control. Closes #24
The Sensitive Logging row puts a long hint next to its switch, and the flex row squeezed the switch (30px at 1280px wide, 10px at 600px), so the knob slid past the track's edge. The switch no longer shrinks; a Playwright test at a 600px viewport asserts every toggle row's switch keeps its 40px width. Closes #26
PrimeNG declares component tokens on :root as aliases of the theme tokens (the select panel's background is var(overlay background)), and an alias resolves on the element that declares it. With .app-dark on <body>, <html> never saw the dark theme, so every aliased token came out light: the disabled Pyramidize global-instruction input (slate-200), every p-select dropdown panel (white), tab bars, and the dim slate key labels on the AI Providers tab. The class now sits on <html> (index.html, applyTheme). The existing overrides in styles.scss are kept so no colour that was right changes; the card background moves to :root.app-dark so PrimeNG's own :root card token cannot raise the settings card off the page. Disabled pInputText, pTextarea and p-select keep a dark zinc-900 surface with muted text, rather than Aura's zinc-700 block. Two dark-mode E2E tests pin the disabled-input and dropdown-panel colours. Closes #28
Apply wore the same accent as the Pyramidize button even while it was disabled, so a button that could do nothing competed with the page's main action. It is now secondary while the global instruction is empty or whitespace, and turns primary as soon as the user types one. Closes #29
With a saved AWS Bedrock provider, the Pyramidize button was already guarded, but the Editor canvas is editable before any Pyramidize: typing a global instruction enabled Apply, and Apply, Ctrl+Enter or the selection bubble ended in a raw "unsupported provider: bedrock" error. Apply now stays secondary and disabled, the bubble's Apply is disabled, and both methods return early. The note on the page now points to Settings, since a choice made on the page lasts for the session only. Also: the settings spec's no-AWS-key test asserts the provider keys that must be there, so an unrendered tab cannot pass it, and the lookup uses Object.hasOwn so an inherited property name cannot match. Refs #22
Every provider card on the AI Providers tab now says whether KeyLint uses it and offers a one-click switch. A provider that cannot work yet stays selectable and its card says why. The General tab's dropdown is replaced by a read-only pointer to the tab where the choice is made. An environment-supplied key now names its variable on the card.
Save swapped the live settings before writing the file, so a failed write still switched the provider for Fix and Pyramidize while the settings screen put its marker back. Also reword the missing Anthropic key error, which pointed at the removed Active Provider dropdown.
Keep presets added this visit, hold Save and Reset during a switch, drop a stale Ollama warning when the URL changes, move focus to the marked card or the AI Providers tab, and word the summary so it does not promise more than Pyramidize's own session choice delivers.
SetActiveProvider saves the provider alone under saveMu, validated against the providers the screen offers. Settings are written to a temp file and renamed over settings.json, so an interrupted write can no longer leave a truncated file that stops the app from starting.
Use this calls SetActiveProvider, so other pending edits stay pending. Switch, Save and Reset lock each other; Save shows its errors. The marker moves once saved, focus goes to the card heading and a live region announces it. Pyramidize re-adopts the Settings provider on every visit unless the user picked another there, which it now shows as a session override with a way back.
settings.Update holds saveMu from read to write; SetActiveProvider, CompleteSetup and the preset and threshold writers use it, so none can undo a switch landing meanwhile. On Windows the final rename retries for about 2 s while another process holds settings.json open.
Pyramidize drops an override once Settings agrees with it and treats a pick forced by an unusable Settings provider as no override. A failed switch is announced once and focuses the error when no card is in use. A switch refreshes the target's status and clears a stale Save error. Specs reset Pyramidize's module state, so test order no longer matters.
Owner
Author
|
Ready to merge after #94, which it stacks on. Three independent Opus review rounds, each with review-pr fork supplement; all findings addressed (a272639). I checked the last round's new Go code myself: |
0xMMA
added a commit
that referenced
this pull request
Oct 8, 2026
Brings in settings atomic writes and settings.Update, provider switching (#104), the dev channel (#107) incl. workflows, the shell footer (#106), Go 1.27 and the CI apt fixes. Conflicts: shell keeps the subscription list and silent-fix guard next to the dev-channel update title; wails service keeps setShortcutPaused next to the dev-channel calls; settings imports ToggleSwitch and SliderModule. Bindings regenerated. E2E settings stubs gain the shortcut fields the backend now returns.
2 of 11 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacks on #94 (
fix/ui-quick-bugs). Merge it after #94. Until #94 lands, the diff against main includes it; this PR's own change is the commits on top of it.What the user now sees
Settings › AI Providers shows which provider is used, and that's where you switch it. This is the owner's decision: one source, clearly visible, one click to switch, no automatic fallback.
SetActiveProvider.http://localhost:11434.General tab: a pointer instead of the dropdown
The Active Provider dropdown is gone. In its place is one read-only line: "Using: Anthropic API — change under AI Providers". "Change under AI Providers" is a button that opens that tab and moves focus to its summary line. If the provider in use can't work, the same warning shows on this line too. With a saved Bedrock it reads "No provider in use", followed by one warning that explains why.
Why a pointer rather than nothing: General is the tab Settings opens on. A pointer keeps "which one is used" on the first screen and shows where to change it, while the choice itself still lives in only one place.
Pyramidize follows Settings
Before this, Pyramidize took the provider from settings once per app session. A switch made later in Settings was silently ignored until restart.
Now it re-reads
active_provideron every visit, unless you picked a different provider in Pyramidize during this session. When your pick differs from Settings, a note under the select says so: "Session override — Settings uses X. Use X". The link drops the override.settings:changed, which is registered but never emitted. Pyramidize's labels now match Settings ("Anthropic API", "Ollama (local)"). The welcome wizard keeps its own labels.Backend
settings.Update(svc, mutate)holdssaveMufrom the read to the write. It is a package function, so Wails does not bind it.SetActiveProvider,welcome.CompleteSetup, and Pyramidize'sSetAppPreset,DeleteAppPresetandSetQualityThreshold.SetActiveProvider(id)accepts only the providers the screen offers: not Bedrock, unknown IDs or an empty string.os.WriteFiletruncates first, so a write that stopped partway (full disk, or a crash mid-write) left a cut-offsettings.jsonthatload()refuses to start on. Now the data goes to a temp file, which is synced and then renamed over the original; until that rename the old file is untouched.os.RenameusesMoveFileExwith replace). What holds there is that the old file stays whole until a complete new one replaces it.WriteFilefailed when opening the file.ERROR_ACCESS_DENIEDorERROR_SHARING_VIOLATION, the same approach as Go'scmd/internal/robustio(x/tools/go/packages: TestOverlay/Modules is flaky on windows-386-2008 builder golang/go#31247). The retry is build-tagged, so other platforms do a single rename. A virus scanner, the search indexer or a concurrentKeyLint -fixcan briefly hold the file open. Tests use a swappable rename to cover the retry, the time limit, and failed renames leaving no temp file.wire genproduces no change.wails3 generate bindingsaddsSetActiveProvider, plus doc-comment changes.Follow-ups (existing problems, not fixed here)
fix.component.spec.ts› "output textarea is empty before a fix is run" fails when the whole suite runs in shuffled order (vitestsequence.shuffle, seed 7). The cause is FixComponent's module-level state; this PR doesn't touch FixComponent. With seeds 1 and 42, and with every changed spec shuffled on its own, everything passed.Also in this PR: preset changes made earlier in the same visit are now copied into the page's settings, so the next Save no longer undoes them.
Screenshots (local, Playwright against a fake settings backend)
Before and after, both tabs, with one provider (CLI only) and with two (Anthropic key plus CLI). After shots also cover "not ready" and a Pyramidize session override.
Review
Three Opus reviews. Every finding was checked against the code and fixed, with two exceptions: there is no Ollama Re-check button, and there is no way to skip the backend's 30 s cache of a failed Ollama check. The specs that touch Pyramidize reset its module-level provider state before and after each test. Before that,
unavailable-provider.spec.tspassed only because of the order its tests ran in.Verification (local)
main's CI Linux jobs stay red until #103 (empty apt cache) merges, so these results are local.
npm test: 15 files, 271 tests, 0 failures.npm run build: OK. The only warning is the style budget on text-enhancement, which was already there.npx playwright test: 67 passed, 3 skipped (the existing skipped specs). New since the last round: a refused switch (the fake backend now validates the ID and can be made to fail).e2e/provider-switch.spec.tscovers switching, persistence across a reload, a provider that isn't ready, Pyramidize following a switch, and the General pointer.e2e/support/fake-backend.tsanswers the settings service's binding calls from in-memory state. It's documented in.claude/rules/testing.md.go test -race ./internal/...: pass.GOOS=windows go vetandgo build: OK.go build -o bin/KeyLint .: OK.git statusis clean after the runs.Conflicts with #31 (frozen,
feature/shortcut-double-press)git merge-tree --write-tree --name-only origin/feature/shortcut-double-press HEADreports no conflicts.