Skip to content

Dynamic multi-provider AI engine & custom endpoints (BYOM) - #2

Merged
arvarik merged 2 commits into
mainfrom
feature/multi-provider-byom
Aug 17, 2026
Merged

Dynamic multi-provider AI engine & custom endpoints (BYOM)#2
arvarik merged 2 commits into
mainfrom
feature/multi-provider-byom

Conversation

@arvarik

@arvarik arvarik commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Summary

Upgrades the AI layer into an open, auto-updating, multi-provider platform:

  • OpenAI joins Gemini and Claude as a first-class key-based provider.
  • Live model discovery: on key verification (or a manual Refresh Models click) the app queries each provider's official model listing API. New model releases appear without an app update.
  • Catalog guardrails: models released/updated over 1 year ago are excluded (when the provider exposes timestamps); embeddings, audio/whisper, TTS, image/video generation, and moderation models are stripped; pinned snapshots (gpt-4o-2024-08-06) collapse into their floating alias.
  • Bring Your Own Model: register any OpenAI-compatible endpoint (Ollama, LM Studio, vLLM, OpenRouter, Groq presets included) with a name, base URL, and optional key. Endpoints are pinged and their models discovered before saving; their models join the global picker as custom:<endpointId>:<model>.
  • Adaptive structured output: json_schemajson_object → prompt-enforced JSON, with the working mode cached per endpoint+model, so flashcard generation and other structured features work on local models with basic JSON support. Tool calls degrade to plain chat on engines that reject tools.
  • Security: keys are stored server-side and always returned masked (••••1234); masked values sent back by forms are never re-saved; removing a key drops the provider's catalog and cached instances, and the client resets the active model pointer to the first available alternative.

UX

  • Settings: per-provider cards with Connected / Not configured / Connection error badges, portal links, masked key hints; a custom endpoint manager with quick-fill presets and add/edit/test/delete flows; a Refresh Models button; grouped model picker with brand accents and family chips (Flash/Pro, Sonnet/Haiku/Opus, Flagship/Mini/Reasoning).
  • Sidebar: grouped model dropdown including custom endpoint groups; an empty state linking to Settings when nothing is configured.

Testing

  • 59 new automated tests (all 155 pass, lint clean, production build OK):
    • recency window, modality stripping, alias dedupe, family inference
    • credential masking + masked-value round-trip protection
    • adaptive JSON fallback chain, mode caching, array-root schema wrapping
    • endpoint connectivity errors, SSE streaming, tool-call loop + degradation
    • namespaced custom model routing, settings/sidebar flows, safe model fallback
  • Manual end-to-end smoke test against a live server: registered a fake OpenAI-compatible endpoint (embedding + legacy models correctly filtered out), streamed chat and structured JSON through it via real routes, exercised live discovery against the real Gemini/Anthropic model APIs (27 and 10 models discovered), verified per-provider error reporting, masking, key removal, and endpoint deletion.

🤖 Generated with Claude Code

Add OpenAI as a first-class provider and support user-registered
OpenAI-compatible endpoints (Ollama, LM Studio, vLLM, OpenRouter, Groq).
Model catalogs are now discovered live from each provider's model
listing API instead of hardcoded lists.

Server:
- New OpenAICompatibleProvider core (fetch-based, no SDK) shared by the
  branded OpenAI provider and custom endpoints
- Adaptive structured output: json_schema → json_object → prompt-based
  JSON with per-endpoint/model mode caching; tool calls degrade to plain
  chat on engines that reject tools
- Live model discovery for Gemini/Claude/OpenAI/custom with guardrails:
  1-year recency window, non-chat modality stripping (embeddings, audio,
  TTS, image/video, moderation), and alias/snapshot dedupe
- SQLite-backed catalog cache (model_catalog) + custom_endpoints table
- /api/endpoints CRUD with pre-flight connectivity checks
- /api/config/refresh-models for 1-click catalog re-sync
- Keys masked as ••••1234 in all responses; masked values never re-saved;
  key removal drops the catalog and cached provider instances
- Key verification now lists models (no token spend) and triggers
  immediate discovery on save

Frontend:
- Settings: OpenAI key card, connection-error badges, masked key hints,
  custom endpoint manager with quick-fill presets, Refresh Models button,
  family labels in the grouped model picker
- Sidebar: grouped picker includes custom endpoints; empty state links
  to Settings when nothing is configured
- Store: active model safely falls back to the first available model
  when its provider/endpoint disappears

Tests: 59 new tests covering recency/modality filtering, alias dedupe,
key masking, adaptive JSON fallbacks, endpoint connectivity, namespaced
custom model routing, and the settings/sidebar UX flows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Model filtering (server):
- New "latest generation per family" heuristic on top of the existing
  guardrails: classify models into families (Gemini Pro/Flash/Flash-Lite/
  Gemma; Claude Fable/Opus/Sonnet/Haiku; OpenAI Flagship/Balanced/Fast/
  Mini/Nano/Reasoning incl. GPT-5.6 sol/terra/luna tier names), extract
  generation numbers, and keep only the newest generation of each family,
  preferring stable releases over previews and collapsing suffix variants
- Strip specialized non-chat systems: image generation (Nano Banana),
  music (Lyria), robotics, deep-research agents, computer-use models
- OpenAI static fallback updated to the GPT-5.6 family (Sol/Terra/Luna)
- Verified live: Gemini 27→4, Claude 10→4, OpenAI shows current lineup

Model selection UX (frontend, mobile-first):
- New ModelPicker component replaces the sidebar <select> and the long
  settings radio list: bottom sheet on mobile, command-palette dialog on
  desktop, with search, provider-grouped rows with brand accents, family
  chips, catalog refresh, provider-management shortcut, and an empty
  state that guides setup
- Mobile header gains a model chip — model switching now works on mobile
- Settings redesign: provider cards with status pills (Connected / Not
  configured / Error), active-model summary card with a Change-model
  action, and matching card styling for custom endpoints
- Design stays within the app's token system; light/dark themes and
  reduced-motion are respected; 44px touch targets on mobile

Tests: filter heuristics (generation extraction, preview detection,
latest-per-family, specialized-model exclusion) plus reworked UI tests
for the picker flows; verified visually via headless-browser screenshots
in both themes and both breakpoints.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@arvarik
arvarik merged commit 1c384b7 into main Aug 17, 2026
1 check passed
@arvarik
arvarik deleted the feature/multi-provider-byom branch August 17, 2026 02:44
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.

1 participant