Fix custom provider icons in the model picker and Model Pad - #102
Conversation
Encode saved provider artwork at 1x so the display validator keeps it, recover oversize PNGs on save, theme custom marks like bundled logos, and put the icon on the Model Pad puck. Co-authored-by: Sambit Biswas <sambitcreate@users.noreply.github.com>
Lock the save path to persistable artwork recovery, recover a real 65px PNG, and tighten picker/pad source scans so they cannot match the wrong branch. Co-authored-by: Sambit Biswas <sambitcreate@users.noreply.github.com>
Narrow slug before passing it to ThemedProviderMark so type-check accepts mark as a string. Co-authored-by: Sambit Biswas <sambitcreate@users.noreply.github.com>
|
Readiness hardening pushed at
Local verification:
Keeping the PR in draft until hosted exact-head CI is green. |
|
Hosted follow-up at Local verification after the change: E2E type-check and lint passed; the complete responsive Model Pad case passed 3/3 ( |
There was a problem hiding this comment.
ℹ️ No critical issues — one informational note inline, plus a description nitpick.
Reviewed changes
- Artwork persistence —
parseProvidernow persists through the newpersistableProviderArtwork, which keeps contract-valid PNG artwork and re-encodes oversize payloads; the encoder re-validates its own output and fails closed. - Picker / Model Pad rendering —
ProviderIconis refactored onto a sharedThemedProviderMarkfor bundled marks (custom artwork still renders as an original-color<img>), and the Model Pad puck now renders the active model's provider icon. - Knob theming — new
--model-pad-knob-foregroundtoken resolved fromforegroundForFill("#FFFFFF", scheme)with static fallbacks, applied to.model-pad-knoband its confirmed state. - Coverage — new source-reading provider-artwork suite registered in
test,test:coverage, andtest:slash-commands, expanded composer/picker/display tests, a new Electron E2E that saves a 128px PNG, relaunches, and asserts a bounded 64px persisted result, and a bounded Model Pad responsive case.
ℹ️ Nitpicks
- The PR description still says custom marks render "with the same
currentColormask as bundled logos," but the final code renders them as an original-color<img>and.papercuts/troubleshooting.mddocuments that reversal. Worth updating so the merge record matches the implementation.
DeepSeek Flash | 𝕏
|
Addressed the late review at |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Reverted the no-op 1x encode path — removed
PIXEL_SCALEand the explicitgetSize(PIXEL_SCALE)/toPNG({ scaleFactor: PIXEL_SCALE })arguments, restoring the basegetSize()/toPNG()calls;createFromBuffer(source.bytes, { scaleFactor: 1 })is unchanged from base. - Retargeted
provider-artwork.test.ts— dropped the assertions on the removed encode arguments and now pins the post-encodenormalizeProviderArtworkcheck plus thepersistStoredProviderArtworkrecovery wiring. - Corrected the narrative —
.papercuts/troubleshooting.mdnow credits save-time recovery instead of the Electron-default 1x arguments, and the artwork E2E is renamed from Retina to Oversized.
Verification at this head: focused provider-artwork suites 7/7 pass, tsc --noEmit and type-check:e2e clean. The prior review's inline thread on the no-op encode is resolved, and the PR description now matches the implementation.
DeepSeek Flash | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Reviewed the single commit added since the prior Pullfrog review (391923f6), a test-only stabilization of the Assistant/Scheduled E2E.
- Stabilized scheduled-search cleanup — the E2E now clears the controlled scheduled-task search through the native
HTMLInputElement.valuesetter plus a bubblinginputevent instead of an empty Playwrightfill(""). - Documented the quirk — a papercut records that empty
fill("")can leave a controlled search unchanged on hosted Electron and points at the native-setter workaround.
The replacement is the canonical React controlled-input workaround: Playwright's fill for input[type=search] selects the value and calls document.execCommand("insertText", false, value), where an empty string can be a no-op; calling the prototype setter bypasses React's per-node value tracker so the dispatched input event registers as a real change. The follow-up toHaveValue("") and No matching tasks assertions still prove React state cleared, so the workaround cannot mask a product regression. npm run type-check:e2e is clean at this head; the deterministic Electron E2E was still running when this review was written.
DeepSeek Flash | 𝕏

Summary
Fix custom provider artwork disappearing from the model picker and Model Pad.
Electron's
getSize()andtoPNG()already default to a 1.0 scale factor; explicit 1x arguments were removed because they were not the effective fix. The save-time recovery path is the behavior that restores previously oversized artwork.Validation
391923f6, including the full verification and deterministic Electron E2E gates; the release-consumer contract is green.providers:save, verifies a decodable bounded persisted PNG, relaunches, and confirms the artwork survives.Review status
main, no merge commits, GitHub mergeable.391923f6after it exposed the only failed rerun.