Allow user to select provider#138
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe PR adds provider-agnostic LLM configuration across local setup, credential persistence, model discovery, model selection, schema inference, and Mastra workflows. Provider-specific clients, validation, verification, defaults, and model endpoints are introduced. Convex stores provider-scoped credentials and model preferences. Frontend setup and settings support provider selection, OAuth gating, model loading, and custom model IDs. Primary-key and row-data contracts now use arrays. Documentation and local development configuration are updated. Sequence Diagram(s)sequenceDiagram
participant Setup
participant Backend
participant Provider
participant Workflow
Setup->>Backend: save provider configuration
Backend->>Provider: verify credentials
Provider-->>Backend: verification result
Backend-->>Setup: setup status and models
Setup->>Backend: save selected model
Workflow->>Backend: resolve active provider configuration
Backend->>Provider: create configured model request
Provider-->>Workflow: model response
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
MMeteorL
left a comment
There was a problem hiding this comment.
Great job! The main layering is appropriate: credentials, provider verification, model creation, and Mastra wiring stay in the backend. Frontend remains UI/config. The provider abstraction is large but coherent. Timeouts are handled for verification/model-list fetches. Malformed schema output still has a retry path. Tool failures are mostly captured and logged. The weak point is saving models that may not support the required tool/schema behavior.
However, there are several blockers that we may need to address here:
1: Model selection can save incompatible model IDs and fail later at runtime.
frontend/components/settings/ModelSideSheet.tsx (line 170) always exposes a free-form “Custom model slug”, and backend/src/index.ts (line 884) only warns when the slug is not returned by the current provider, then saves it anyway. The later compatibility check in backend/src/config/models.ts (line 192) is mostly prefix/shape based, so values like unknown OpenRouter slugs or nonexistent gpt-* names can pass and only fail during schema inference/populate/update. This affects correctness, reliability, and product trust. I’d make unsupported selections a hard validation error except for explicitly custom/local endpoints.
2: /llm-provider/models is public and can trigger provider API calls using configured credentials.
backend/src/index.ts (line 841) is not behind requireAuth and has no local-mode guard. It can call fetchModelsForCurrentLlmProvider(), which may use stored/env provider credentials. Even if it does not expose secrets directly, it lets unauthenticated callers consume provider/model-list rate limits and exercise configured external endpoints. I’d either require auth, restrict it to local mode where setup needs it, or serve only cached public-safe model data from this route.
3: The provider/model surface is much broader than the current agent/tool reliability envelope.
The implementation puts many direct providers and local/custom endpoints behind an “Experimental Providers” opt-in, which is a good start, but the backend still treats broad text-model lists as selectable for Mastra agents. BigSet’s Mastra tool workflow depends on reliable tool-calling/schema behavior, and many older or non-tool-optimized models will not handle the tool protocol consistently. I recommend curating a small allowlist of known-compatible models per provider, with provider-specific defaults for each role, rather than exposing most returned text models plus arbitrary slugs. From what we tested, deepseek-v4-pro, Qwen3.7 are reliable models, as well as the more expensive latest Claude or OpenAI models.
| /> | ||
| </div> | ||
| )} | ||
| <form onSubmit={handleCustomSlugSubmit} className="flex items-center gap-2"> |
There was a problem hiding this comment.
This always exposes a free-form “Custom model slug.” Values like unknown OpenRouter slugs or nonexistent gpt-* names can pass and only fail during schema inference/populate/update. This affects correctness, reliability, and product trust. I’d make unsupported selections a hard validation error except for explicitly custom/local endpoints.
| return reply.code(400).send({ | ||
| error: `Invalid model slug "${slug}" for ${role}. Refresh the model list first or choose a different model.`, | ||
| }); | ||
| req.log.warn({ role, slug }, "Saving model slug that was not returned by the current LLM provider"); |
There was a problem hiding this comment.
This warns when the slug is not returned by the current provider, then saves it anyway. Values like unknown OpenRouter slugs or nonexistent gpt-* names can pass and only fail during schema inference/populate/update. This affects correctness, reliability, and product trust. I’d make unsupported selections a hard validation error except for explicitly custom/local endpoints.
| ); | ||
| } | ||
|
|
||
| function isProviderTextModelId( |
There was a problem hiding this comment.
The compatibility check is mostly prefix/shape based. Values like unknown OpenRouter slugs or nonexistent gpt-* names can pass and only fail during schema inference/populate/update. This affects correctness, reliability, and product trust. I’d make unsupported selections a hard validation error except for explicitly custom/local endpoints.
| if (toValidate.length > 0) { | ||
| try { | ||
| const models = await getCachedModels(); | ||
| const models = await fetchModelsForCurrentLlmProvider(); |
There was a problem hiding this comment.
This call is not behind requireAuth and has no local-mode guard. It can call fetchModelsForCurrentLlmProvider(), which may use stored/env provider credentials. Even if it does not expose secrets directly, it lets unauthenticated callers consume provider/model-list rate limits and exercise configured external endpoints. I’d either require auth, restrict it to local mode where setup needs it, or serve only cached public-safe model data from this route.
…dels Resolves the two review blockers on selecting a provider/model: 1. Hard validation on save. POST /settings/models now rejects a model slug the current provider doesn't offer (400) instead of warning and saving it, so incompatible selections fail at save time rather than during schema-inference/populate/update. Local/custom OpenAI-compatible providers (custom, ollama, lmstudio) whose catalogs can't be enumerated stay exempt. Validation fails closed (502 "try again") if the provider list can't be fetched. Logic centralized in findUnsupportedModelSlugs(). The frontend now surfaces the rejection inline in the model side sheet. 2. Auth guard on GET /llm-provider/models. The route exercised configured provider credentials and rate limits while being public; it now runs requireAuth first (passes through in local mode for setup, enforces a Clerk token in prod). getLlmProviderModels() threads the token from authenticated callers; the local-mode setup flow calls it without one. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
Thanks for the thorough review! Addressed the two blockers in 56f68ab: 1. Model selection could save incompatible slugs → now a hard validation error. 2. 3. Curated per-provider allowlist — deliberately not doing this here. Verified with |
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (4)
backend/src/config/llm.ts (1)
207-259: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winPrefer the validated
envmodule over rawprocess.envfor provider base URLs.
env(from../env.js) is already imported and used forSCHEMA_INFERENCE_MODEL/IS_LOCAL_MODEin this file, but every base-URL lookup here (process.env.OPENROUTER_BASE_URL,process.env.XAI_BASE_URL, etc.) bypasses it. As per path instructions, backend config should be read consistently through validated environment access; routing these throughenvwould keep validation/typing consistent across the file. As per path instructions, "Read required service configuration from environment variables, including Convex, Clerk, LLM, and TinyFish credentials; do not hardcode secrets."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/src/config/llm.ts` around lines 207 - 259, Update defaultBaseUrlForLlmProvider to read every provider base URL from the already imported validated env module instead of process.env, including OPENROUTER_BASE_URL, GOOGLE_GENERATIVE_AI_BASE_URL, XAI_BASE_URL, and the remaining provider-specific settings. Preserve each existing fallback URL and the undefined result for unsupported providers.Source: Path instructions
backend/src/local-credentials.ts (1)
365-391: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winLoad provider statuses concurrently.
This loop serializes a Convex query and potential keychain request for every provider, adding avoidable setup-page latency. Resolve the provider entries with
Promise.allbefore constructingproviderStatuses.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/src/local-credentials.ts` around lines 365 - 391, Update the provider-status construction around LLM_PROVIDER_TYPES to resolve each localCredentialForLlmProvider call concurrently with Promise.all, including the existing credential-to-status mapping for each provider. After all entries resolve, construct providerStatuses from the resulting provider/status pairs while preserving the current status fields and ordering.frontend/lib/backend.ts (1)
162-170: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winHardcoded default OpenRouter model may drift from the setup wizard's provider-defaults source.
saveOpenRouterApiKeyhardcodesdefaultModel: "anthropic/claude-sonnet-4.6", whilefrontend/app/setup/page.tsx's equivalent save path derivesdefaultModelfrom a sharedproviderCopy.defaultModelobject. If the canonical OpenRouter default model changes, only one of these two call sites would need to be updated — the other would silently keep saving the stale value for users going through the settings-page credential flow instead of setup.♻️ Suggested fix: source the default from one place
-export async function saveOpenRouterApiKey( - apiKey: string, -): Promise<LocalSetupStatus> { - return saveLlmProviderConfig({ - provider: "openrouter", - apiKey, - defaultModel: "anthropic/claude-sonnet-4.6", - }); -} +export async function saveOpenRouterApiKey( + apiKey: string, +): Promise<LocalSetupStatus> { + return saveLlmProviderConfig({ + provider: "openrouter", + apiKey, + defaultModel: OPENROUTER_DEFAULT_MODEL, // shared constant, single source of truth + }); +}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/lib/backend.ts` around lines 162 - 170, Update saveOpenRouterApiKey to obtain the OpenRouter default model from the shared providerCopy.defaultModel source used by the setup page, instead of hardcoding "anthropic/claude-sonnet-4.6". Ensure both credential-save flows use the same canonical default value.frontend/convex/localCredentials.ts (1)
83-98: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low valueClearing
llmBaseUrl/llmDefaultModelis coupled tollmProviderbeing present, not to the provider actually changing.Any caller that passes
llmProvider(even unchanged) without resendingllmBaseUrl/llmDefaultModelwill wipe those fields. Today's only visible caller (saveLlmProviderConfiginfrontend/lib/backend.ts) always sendsdefaultModelalongsideprovider, so this isn't currently exploitable from the code shown, but the mutation itself has no guard against a future caller (e.g. a re-verification path) passingllmProvideralone.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/convex/localCredentials.ts` around lines 83 - 98, The llmPatch construction in the local credentials mutation incorrectly clears llmBaseUrl and llmDefaultModel whenever llmProvider is supplied, even if unchanged. Compare the incoming provider with the stored provider and only clear or update those fields when the provider actually changes; preserve existing values when the provider is unchanged and omitted auxiliary fields should remain untouched. Apply the corresponding guard to llmInsert as needed for new records.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/src/index.ts`:
- Around line 722-767: Protect the `/local-setup/llm-provider` route before any
provider verification, persistence, or activation by moving it into the scoped
Fastify plugin whose `preHandler` is `requireAuth` (or otherwise applying that
existing setup capability). Do not rely on `env.IS_LOCAL_MODE` as authorization;
preserve the route’s validation and setup behavior after authentication.
In `@backend/src/local-credentials.ts`:
- Around line 102-125: Update the local credential lookup around the keyless
provider branch to call getKeychainCredential(service) before returning an empty
apiKey for custom, Ollama, or LM Studio endpoints. Reuse any stored keychain
credential when present, and only return the apiKey: "" fallback when no
keychain credential exists; preserve the existing endpoint metadata.
In `@backend/src/mastra/tools/dataset-tools.ts`:
- Around line 61-72: Update rowDataCellsToRecord and its callers to normalize
column names before building the record, detect duplicate normalized keys, and
return a structured tool failure before any data mutation occurs. Preserve
successful conversion for unique columns and apply the same validation to the
related flows around the referenced ranges, including cleanDataKeys handling.
In `@backend/src/pipeline/schema-inference.ts`:
- Line 13: Correct the spelling errors in the schema-inference prompt within the
primary-key guidance: replace “unqiue” with “unique,” “guarenteed” with
“guaranteed,” “thigns” with “things,” and “guarentee” with “guarantee.”
In `@frontend/app/setup/page.tsx`:
- Around line 368-371: Update the onSaved handler in the setup page to clear the
provider-scoped modelConfig whenever credentials change, before updating status
and closing the modal. Ensure stale model slugs cannot keep modelsConfigured
true while the new provider configuration loads.
In `@frontend/components/settings/llm-providers.tsx`:
- Around line 459-480: Update the showExperimentalProviders state initialization
and related effect in the provider selector to derive the initial opt-in from
whether value is experimental, preserving saved experimental providers on mount.
Ensure the OpenRouter fallback runs only from handleExperimentalChange when the
user explicitly unchecks the option, not during initial rendering or value
synchronization.
In `@frontend/components/settings/LocalCredentialsPanel.tsx`:
- Around line 596-608: The initialBaseUrl helpers in
frontend/components/settings/LocalCredentialsPanel.tsx lines 596-608 and
frontend/app/setup/page.tsx lines 779-791 must preserve the active base URL when
services.llmProviders is unavailable. Before using the provider-map value, fall
back to the matching active provider from aggregate services.llm or the inferred
local preset, then retain the existing default/custom-provider behavior in both
helpers.
In `@frontend/convex/localCredentials.ts`:
- Around line 4-47: Replace the duplicated provider literals with one shared
provider source of truth and derive all validators and TypeScript unions from
it. Update frontend/convex/localCredentials.ts (lines 4-47),
frontend/convex/schema.ts (lines 138-164 and 165-219),
frontend/convex/modelConfig.ts (lines 6-41), and frontend/lib/backend.ts (lines
66-82) so serviceValidator, llmProviderValidator, schema provider fields,
LlmProvider, providerValidator, and LlmProviderType all reuse the shared
definition without independent provider lists.
In `@frontend/lib/openrouter-oauth.ts`:
- Around line 55-85: Update isLocalIpv4Hostname to classify only 192.168.0.0/16
as local instead of all addresses beginning with 192. Extend isLocalIpv6Hostname
to recognize the unspecified address :: and IPv4-mapped loopback addresses such
as ::ffff:127.0.0.1, while preserving existing private and loopback
classifications.
In `@README.md`:
- Line 167: Remove the blank line within the blockquote in README.md, keeping
all blockquote lines contiguous to satisfy markdownlint MD028.
- Around line 153-164: Update provider documentation to match the implemented
selector: in README.md lines 153-164 explain that local runtimes require no API
key and models are chosen through the model picker; revise README.md line 96 and
line 249 to list the full supported providers or explicitly mark the examples as
non-exhaustive; update backend/CLAUDE.md line 51 likewise to include the full
local provider set or use “including”.
---
Nitpick comments:
In `@backend/src/config/llm.ts`:
- Around line 207-259: Update defaultBaseUrlForLlmProvider to read every
provider base URL from the already imported validated env module instead of
process.env, including OPENROUTER_BASE_URL, GOOGLE_GENERATIVE_AI_BASE_URL,
XAI_BASE_URL, and the remaining provider-specific settings. Preserve each
existing fallback URL and the undefined result for unsupported providers.
In `@backend/src/local-credentials.ts`:
- Around line 365-391: Update the provider-status construction around
LLM_PROVIDER_TYPES to resolve each localCredentialForLlmProvider call
concurrently with Promise.all, including the existing credential-to-status
mapping for each provider. After all entries resolve, construct providerStatuses
from the resulting provider/status pairs while preserving the current status
fields and ordering.
In `@frontend/convex/localCredentials.ts`:
- Around line 83-98: The llmPatch construction in the local credentials mutation
incorrectly clears llmBaseUrl and llmDefaultModel whenever llmProvider is
supplied, even if unchanged. Compare the incoming provider with the stored
provider and only clear or update those fields when the provider actually
changes; preserve existing values when the provider is unchanged and omitted
auxiliary fields should remain untouched. Apply the corresponding guard to
llmInsert as needed for new records.
In `@frontend/lib/backend.ts`:
- Around line 162-170: Update saveOpenRouterApiKey to obtain the OpenRouter
default model from the shared providerCopy.defaultModel source used by the setup
page, instead of hardcoding "anthropic/claude-sonnet-4.6". Ensure both
credential-save flows use the same canonical default value.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0460788e-90dd-44d2-bc63-10cc2d10418d
⛔ Files ignored due to path filters (19)
backend/package-lock.jsonis excluded by!**/package-lock.jsonfrontend/public/logos/providers/anthropic-icon.svgis excluded by!**/*.svgfrontend/public/logos/providers/anthropic.svgis excluded by!**/*.svgfrontend/public/logos/providers/deepinfra.svgis excluded by!**/*.svgfrontend/public/logos/providers/deepseek.svgis excluded by!**/*.svgfrontend/public/logos/providers/fireworks-ai.svgis excluded by!**/*.svgfrontend/public/logos/providers/google-g.svgis excluded by!**/*.svgfrontend/public/logos/providers/groq.svgis excluded by!**/*.svgfrontend/public/logos/providers/huggingface.svgis excluded by!**/*.svgfrontend/public/logos/providers/lmstudio.svgis excluded by!**/*.svgfrontend/public/logos/providers/mistral-ai.svgis excluded by!**/*.svgfrontend/public/logos/providers/ollama.svgis excluded by!**/*.svgfrontend/public/logos/providers/openai-icon.svgis excluded by!**/*.svgfrontend/public/logos/providers/openai.svgis excluded by!**/*.svgfrontend/public/logos/providers/openrouter-wordmark.svgis excluded by!**/*.svgfrontend/public/logos/providers/openrouter.svgis excluded by!**/*.svgfrontend/public/logos/providers/qwen.svgis excluded by!**/*.svgfrontend/public/logos/providers/together-ai.svgis excluded by!**/*.svgfrontend/public/logos/providers/xai.svgis excluded by!**/*.svg
📒 Files selected for processing (32)
CLAUDE.mdREADME.mdbackend/CLAUDE.mdbackend/package.jsonbackend/prompts/schema-inference.txtbackend/src/config/llm.tsbackend/src/config/models.tsbackend/src/env.tsbackend/src/index.tsbackend/src/local-credential-types.tsbackend/src/local-credentials.tsbackend/src/mastra/agents/investigate.tsbackend/src/mastra/agents/populate.tsbackend/src/mastra/agents/refresh.tsbackend/src/mastra/tools/dataset-tools.tsbackend/src/mastra/tools/investigate-tool.tsbackend/src/mastra/workflows/populate.tsbackend/src/mastra/workflows/update.tsbackend/src/pipeline/schema-inference.tsbackend/src/pipeline/types.tsfrontend/Dockerfile.devfrontend/app/dashboard/settings/models/page.tsxfrontend/app/setup/page.tsxfrontend/components/settings/LocalCredentialsPanel.tsxfrontend/components/settings/ModelSideSheet.tsxfrontend/components/settings/llm-providers.tsxfrontend/convex/localCredentials.tsfrontend/convex/modelConfig.tsfrontend/convex/schema.tsfrontend/lib/backend.tsfrontend/lib/openrouter-oauth.tsmakefiles/Makefile
| 3. Paste the provider key and model name into BigSet's setup screen | ||
|
|
||
| > **Note:** root `.env` is the only local env file. If you edit Convex functions in `frontend/convex/`, run `make convex-push` to deploy the changes. | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove the blank line inside the blockquote.
This triggers markdownlint MD028.
🧰 Tools
🪛 markdownlint-cli2 (0.23.0)
[warning] 167-167: Blank line inside blockquote
(MD028, no-blanks-blockquote)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@README.md` at line 167, Remove the blank line within the blockquote in
README.md, keeping all blockquote lines contiguous to satisfy markdownlint
MD028.
Source: Linters/SAST tools
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/src/index.ts`:
- Around line 842-847: Move the route containing the inline requireAuth(req,
reply) call into the scoped protected Fastify plugin, or configure requireAuth
as the route’s preHandler. Remove the direct authentication invocation and
preserve the existing handler behavior while ensuring every request is
authenticated before execution.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9edffa17-4199-4aed-aa7b-1620251c601b
📒 Files selected for processing (5)
backend/src/config/models.tsbackend/src/index.tsfrontend/app/dashboard/settings/models/page.tsxfrontend/components/settings/ModelSideSheet.tsxfrontend/lib/backend.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- frontend/lib/backend.ts
- backend/src/config/models.ts
- frontend/components/settings/ModelSideSheet.tsx
- frontend/app/dashboard/settings/models/page.tsx
Two confirmed false-rejection regressions in the new hard-validation path: - qwen: fetchModelsForCurrentLlmProvider returns a static 8-entry stub, not a live catalog, so valid DashScope slugs (qwen-turbo, qwen-vl-max, future releases) were hard-rejected at save time despite working at runtime. qwen's catalog isn't enumerable, so it now joins custom/ollama/lmstudio in providerAllowsAnyModelSlug (validation skipped; slug accepted as-is). - openrouter: models are served from a persistent Convex cache with no TTL, so a cache predating a model's release would falsely reject a currently-offered slug. findUnsupportedModelSlugs now refreshes the cache once on a miss and re-checks before rejecting. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Refresh every hardcoded default model to a current, verified provider API slug (researched against official docs, 2026-07-21): - OpenRouter env defaults: claude-sonnet-5 (schema/orchestrator), claude-haiku-4.5 (subagent) - OpenAI: gpt-5.6-terra / gpt-5.6-luna (Sol/Terra/Luna tiers; the old gpt-5.4-mini naming was wrong) - Anthropic: claude-sonnet-5 / claude-haiku-4-5 - xAI: grok-4.5 - DeepSeek: deepseek-v4-pro / deepseek-v4-flash (deepseek-chat is being deprecated 2026-07-24) - Qwen: qwen3-max / qwen3.5-flash; refreshed static picker list - Mistral: mistral-medium-latest / mistral-small-latest - Groq: gpt-oss-120b / gpt-oss-20b - Together / DeepInfra / Fireworks / HF: GLM 5.2 and DeepSeek V4 slugs - Gemini kept at gemini-3.5-flash (3.6 Flash unverified on official docs) Also fixes the provider modal snapping back to OpenRouter on open: the Experimental Providers toggle now initializes from the current selection, and removes a stray double blank line in the model settings page. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Send HTTP-Referer + X-Title + X-OpenRouter-Categories on OpenRouter model calls so BigSet's usage (including local-mode users on their own keys) rolls up under one app on OpenRouter's public rankings, marketplace, and per-app analytics. Applied in the single createLanguageModel OpenRouter path, so it covers every generation call. Defaults to https://bigset.tinyfish.ai / "TinyFish BigSet" / "personal-agent", overridable via OPENROUTER_APP_URL / OPENROUTER_APP_TITLE / OPENROUTER_APP_CATEGORIES. https://openrouter.ai/docs/app-attribution Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Summary
This PR rebuilds local setup for a multi-provider model world instead of assuming OpenRouter is the only path.
What changed
When a provider exposes a compatible model-list endpoint, BigSet fetches available models so users can choose from a list instead of manually entering exact model slugs. Local and custom providers do not assume default models, so setup now asks users to choose the models BigSet should use for each role.
Modernized default model slugs
Every hardcoded default model slug was refreshed to a current, provider-verified API string (each provider group researched against official docs):
anthropic/claude-sonnet-5anthropic/claude-haiku-4.5gpt-5.6-terragpt-5.6-lunaclaude-sonnet-5claude-haiku-4-5grok-4.5grok-4.5deepseek-v4-prodeepseek-v4-flashqwen3-maxqwen3.5-flashmistral-medium-latestmistral-small-latestopenai/gpt-oss-120bopenai/gpt-oss-20bzai-org/GLM-5.2openai/gpt-oss-120bdeepseek-ai/DeepSeek-V4-Prodeepseek-ai/DeepSeek-V4-Flashaccounts/fireworks/models/glm-5p2zai-org/GLM-5.2Qwen/Qwen3.5-9Bgemini-3.5-flashNotes:
deepseek-chat(being deprecated) onto thedeepseek-v4-*slugs.gemini-3.5-flash— a "3.6 Flash" slug could not be confirmed on Google's official docs.OpenRouter app attribution
OpenRouter model calls now send
HTTP-Referer,X-Title, andX-OpenRouter-Categories(app attribution) so BigSet's usage — including local-mode users on their own keys — rolls up under one app on OpenRouter's public rankings, marketplace, and per-app analytics. Applied in the singlecreateLanguageModelOpenRouter path, so it covers every generation call. Defaults tohttps://bigset.tinyfish.ai/TinyFish BigSet/personal-agent, overridable viaOPENROUTER_APP_URL/OPENROUTER_APP_TITLE/OPENROUTER_APP_CATEGORIES.Misc fixes