feat(webui): Wave 4B — vision, compare, and omnifail provider tiers - #16
Merged
Conversation
added 8 commits
July 25, 2026 04:20
…g (U1) Establish the provider-tier orchestrator foundation for Wave 4B: - Split quality_api (direct/BYOK routes only) from proxy_failover (cloud proxy chain) so a single request is never attempted twice against the same endpoint. quality_api skips without a usable key, letting the orchestrator advance to the proxy tier — keyless zero-config visitors are still served by the proxy, matching pre-4B behavior. - Enable quality_api + proxy_failover by default for zero-config routing. - Preserve the user's saved tier order in normalizeTierSettings (R36), deduping and dropping unknown ids, appending omitted tiers at their default-enabled state instead of rebuilding from a fixed order. - Surface which tiers were tried and their last error on failure while preserving the ChatRouteError taxonomy (R40). - Add an in-memory localStorage/window test seam (vitest.setup.ts) so tier tests run under the node environment without full jsdom. - Add orchestrator ordering tests, normalize/default unit tests, and a FailoverProvider integration test for zero-config proxy routing and failure diagnostics. npm test: 41 passing (7 new).
- Register murm-ui AttachmentPlugin (image/* only, 4MB client cap) with clear oversize/unsupported errors that leave the session intact (R28, R31). - Add message-openai mapper: text-only turns stay strings; image file blocks become OpenAI image_url content parts so attachments are never dropped. - Vision guard (R29): block send with a clear, explorer-pointing message when an image is attached but the selected model is not vision-capable. - quality_api (direct/BYOK) skips image turns so multimodal requests route to the proxy tier instead of silently dropping the image; proxy body carries the multimodal content parts. - Expose modelSupportsVision / getVisionCatalogModels helpers (R30) and tighten the attachment tray thumbnails for the dark shell. npm test: 50 passing (9 new).
Ship the Tiers shell panel so users can reorder and enable omnifail routes (R36), with opt-in web-runner and SearXNG URL fields (R41) and clear ToS / best-effort copy (R42). Persist order through normalizeTierSettings so the orchestrator attempt sequence matches what the panel saved. Document the distinction between the omnifail route stack and cloud free-tier limits, bootstrap merge stale-localStorage behavior, and text-only vision export in CAVEATS; register the plugin in chat-ui-plugins.md. npm test: 54 passing (4 new).
Ship compare mode as a murm-ui plugin with dual FailoverProvider delegates (KTD4): same prompt streams to two independently chosen models in a split-pane grid. Sequential onEvent delivery creates two labeled assistant messages in one generation; exit keeps session history (R32–R35). Show a pre-send banner when both columns hit the metered public proxy (R34). Cover metered helpers in vitest and add a Playwright happy-path spec. npm test: 59 passing. Playwright compare-mode.spec.ts green.
Query a user-configured SearXNG instance for candidate free web chat URLs when the tier is enabled (R39). Heuristic filter keeps https chat-looking results, one per host; matches render as a dismissible pick list of manual links between history and composer — nothing is automated on the user's behalf. Discovery records a descriptive attempt and the chain continues to the next tier, so zero-config proxy chat is unchanged (R43). Empty results, HTTP errors, and CORS/network failures surface as typed diagnostics (R40). npm test: 65 passing. npm run build green.
Ship the web_ui tier (R38) as a user-run companion in runner/: a zero-dependency Node service exposing OpenAI-shaped SSE at /v1/chat/completions with a stub adapter for smoke testing and a generic selector-driven Playwright adapter (BYO selectors — no site automation is shipped). Chat returns 501 with setup guidance until an adapter is configured; CORS allows localhost and *.github.io. Browser side, streamFromWebRunner bridges the runner into FailoverProvider with typed not-configured/unreachable diagnostics (R40) and an image skip so attachments stay on the proxy tier. Routing metadata records web_ui only once the runner actually streams. Runner runs TypeScript natively (Node >= 23.6 type stripping) — no build step, no tsx/esbuild postinstall. webui npm test: 68 passing; runner npm test: 4 passing; build green.
Add vision-attach.spec.ts (PNG + vision model streams via proxy with an image_url part; non-vision model blocks clearly, AE1/R29) and tier-settings.spec.ts (reorder persists through localStorage and reload, R36; zero-config chat unchanged, AE3). Register the three Wave 4B specs — including compare-mode from U3 — in the Pages workflow. installLocalIndexHtml serves the locally built docs/index.html when a spec needs static markup (Tiers button) that has not deployed yet. Trim CONCEPTS to Wave 4B glossary terms only — Wave 5/6 rows land with their waves.
…tatus Mark the Wave 4B differentiation plan completed with landed-unit delta and commit trail; queue Wave 5 behind it and close out Wave 3. Refresh STRATEGY tracks (demo stays display/routing-first; user-run companions are opt-in extensions), record the murm-ui streaming plaintext-tail patch as a tooling-decision learning, and add the matching AGENTS pitfall.
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.
Summary
quality_api→ optional web runner → SearXNG discovery →proxy_failover) with disjoint route ownership so zero-config proxy chat stays unchanged.runner/(OpenAI-shaped SSE; stub + BYO-selector adapters) and a dismissible SearXNG pick list that never automates third-party chats.Test plan
cd webui && npm test && npm run build(68+ vitest green)cd runner && npm test(health + SSE + 501 + CORS)npx playwright test tests/e2e/vision-attach.spec.ts tests/e2e/compare-mode.spec.ts tests/e2e/tier-settings.spec.ts