From e9c600935704a0463fa2c3acf5f61e4fc1e8148e Mon Sep 17 00:00:00 2001 From: Tony Giorgio Date: Thu, 9 Apr 2026 12:28:34 -0500 Subject: [PATCH] Use the canonical Llama model ID Keep model selection, fetched models, and proxy examples aligned on the supported ID while dropping stale legacy aliases. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> Correct the canonical Llama model ID Use llama3-3-70b as the supported identifier and keep dotted legacy values migrating to it. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- docs/conversations-api-implementation.md | 2 +- frontend/public/llms-full.txt | 2 +- frontend/src/components/ModelSelector.tsx | 23 ++++------- .../components/apikeys/ProxyConfigSection.tsx | 5 ++- frontend/src/state/LocalStateContext.tsx | 24 +++++++++-- frontend/src/utils/utils.ts | 41 +++++-------------- 6 files changed, 44 insertions(+), 53 deletions(-) diff --git a/docs/conversations-api-implementation.md b/docs/conversations-api-implementation.md index 248389400..20857f321 100644 --- a/docs/conversations-api-implementation.md +++ b/docs/conversations-api-implementation.md @@ -519,7 +519,7 @@ const sendMessage = async (userInput: string, conversationId: string) => { try { // Create streaming response const stream = await openai.responses.create({ - model: "ibnzterrell/Meta-Llama-3.3-70B-Instruct-AWQ-INT4", // Or user's selected model + model: "llama3-3-70b", // Or user's selected model conversation: conversationId, input: [{ role: "user", content: userInput }], stream: true, // Enable streaming diff --git a/frontend/public/llms-full.txt b/frontend/public/llms-full.txt index cbe44041f..b3200bd36 100644 --- a/frontend/public/llms-full.txt +++ b/frontend/public/llms-full.txt @@ -161,7 +161,7 @@ All pricing is pay-as-you-go. Purchase credits in $10 increments. | Model | Price per million tokens | |---|---| -| llama-3.3-70b | $4 input / $4 output | +| llama3-3-70b | $4 input / $4 output | | gpt-oss-120b | $4 input / $4 output | | kimi-k2-5 | $4 input / $4 output | | qwen3-vl-30b | $4 input / $4 output | diff --git a/frontend/src/components/ModelSelector.tsx b/frontend/src/components/ModelSelector.tsx index 657a142de..02a0d2b71 100644 --- a/frontend/src/components/ModelSelector.tsx +++ b/frontend/src/components/ModelSelector.tsx @@ -12,6 +12,7 @@ import { useOpenSecret } from "@opensecret/react"; import { useEffect, useRef, useState } from "react"; import type { Model } from "openai/resources/models.js"; import { UpgradePromptDialog } from "@/components/UpgradePromptDialog"; +import { aliasModelName, LLAMA_MODEL_ID } from "@/utils/utils"; // Model configuration for display names, badges, and token limits type ModelCfg = { @@ -26,12 +27,7 @@ type ModelCfg = { }; export const MODEL_CONFIG: Record = { - "ibnzterrell/Meta-Llama-3.3-70B-Instruct-AWQ-INT4": { - displayName: "Llama 3.3 70B", - shortName: "Llama 3.3", - tokenLimit: 70000 - }, - "llama-3.3-70b": { + [LLAMA_MODEL_ID]: { displayName: "Llama 3.3 70B", shortName: "Llama 3.3", tokenLimit: 70000 @@ -79,7 +75,7 @@ export const DEFAULT_TOKEN_LIMIT = 64000; // Get token limit for a specific model export function getModelTokenLimit(modelId: string): number { - return MODEL_CONFIG[modelId]?.tokenLimit || DEFAULT_TOKEN_LIMIT; + return MODEL_CONFIG[aliasModelName(modelId)]?.tokenLimit || DEFAULT_TOKEN_LIMIT; } // Primary model options @@ -176,8 +172,10 @@ export function ModelSelector({ hasImages = false }: { hasImages?: boolean }) { // Get current models for merging from ref const currentModels = availableModelsRef.current || []; - const existingModelIds = new Set(currentModels.map((m) => m.id)); - const newModels = filteredModels.filter((m) => !existingModelIds.has(m.id)); + const existingModelIds = new Set(currentModels.map((m) => aliasModelName(m.id))); + const newModels = filteredModels.filter( + (m) => !existingModelIds.has(aliasModelName(m.id)) + ); // Merge with existing models (keeping the hardcoded one) setAvailableModels([...currentModels, ...newModels]); @@ -448,13 +446,6 @@ export function ModelSelector({ hasImages = false }: { hasImages?: boolean }) { Array.isArray(availableModels) && [...availableModels] .filter((m) => MODEL_CONFIG[m.id] !== undefined) - // Deduplicate: prefer short names over long names - .filter((m) => { - if (m.id === "ibnzterrell/Meta-Llama-3.3-70B-Instruct-AWQ-INT4") { - return !availableModels.some((model) => model.id === "llama-3.3-70b"); - } - return true; - }) // Remove duplicates by id .filter( (m, index, self) => diff --git a/frontend/src/components/apikeys/ProxyConfigSection.tsx b/frontend/src/components/apikeys/ProxyConfigSection.tsx index 90358b039..64c168bac 100644 --- a/frontend/src/components/apikeys/ProxyConfigSection.tsx +++ b/frontend/src/components/apikeys/ProxyConfigSection.tsx @@ -7,6 +7,7 @@ import { Alert, AlertDescription } from "@/components/ui/alert"; import { Play, Square, Loader2, AlertCircle, CheckCircle, Server, Copy, Check } from "lucide-react"; import { proxyService, ProxyConfig, ProxyStatus } from "@/services/proxyService"; import { isTauriDesktop } from "@/utils/platform"; +import { LLAMA_MODEL_ID } from "@/utils/utils"; interface ProxyConfigSectionProps { apiKeys: Array<{ name: string; created_at: string }>; @@ -339,7 +340,7 @@ client = OpenAI( ) response = client.chat.completions.create( - model="llama-3.3-70b", + model="${LLAMA_MODEL_ID}", messages=[{"role": "user", "content": "Hello!"}], stream=True ) @@ -357,7 +358,7 @@ for chunk in response: {`curl -N http://${config.host}:${config.port}/v1/chat/completions \\ -H "Content-Type: application/json" \\ -d '{ - "model": "llama-3.3-70b", + "model": "${LLAMA_MODEL_ID}", "messages": [{"role": "user", "content": "Hello!"}], "stream": true }'`} diff --git a/frontend/src/state/LocalStateContext.tsx b/frontend/src/state/LocalStateContext.tsx index 1eea1c8d6..49a4d20fc 100644 --- a/frontend/src/state/LocalStateContext.tsx +++ b/frontend/src/state/LocalStateContext.tsx @@ -46,6 +46,21 @@ function getInitialModel(): string { return DEFAULT_MODEL_ID; } +function normalizeAvailableModels(models: OpenSecretModel[]): OpenSecretModel[] { + const normalizedModels = new Map(); + + for (const model of models) { + const normalizedId = aliasModelName(model.id); + const normalizedModel = normalizedId === model.id ? model : { ...model, id: normalizedId }; + + if (!normalizedModels.has(normalizedId) || model.id === normalizedId) { + normalizedModels.set(normalizedId, normalizedModel); + } + } + + return Array.from(normalizedModels.values()); +} + export const LocalStateProvider = ({ children }: { children: React.ReactNode }) => { /** The model that should be assumed when a chat doesn't yet have one */ const defaultModel: OpenSecretModel = { @@ -62,7 +77,7 @@ export const LocalStateProvider = ({ children }: { children: React.ReactNode }) userImages: [] as File[], sentViaVoice: false, model: getInitialModel(), - availableModels: [defaultModel] as OpenSecretModel[], + availableModels: normalizeAvailableModels([defaultModel]), hasWhisperModel: true, // Default to true to avoid hiding button during loading billingStatus: null as BillingStatus | null, searchQuery: "", @@ -77,7 +92,7 @@ export const LocalStateProvider = ({ children }: { children: React.ReactNode }) const chatToSave = { ...chat, - /** If a model is missing, assume the default Llama and write it now */ + /** If a model is missing, assume the default model and write it now */ model: aliasModelName(chat.model) || DEFAULT_MODEL_ID }; @@ -377,7 +392,10 @@ export const LocalStateProvider = ({ children }: { children: React.ReactNode }) } function setAvailableModels(models: OpenSecretModel[]) { - setLocalState((prev) => ({ ...prev, availableModels: models })); + setLocalState((prev) => ({ + ...prev, + availableModels: normalizeAvailableModels(models) + })); } function setHasWhisperModel(hasWhisper: boolean) { diff --git a/frontend/src/utils/utils.ts b/frontend/src/utils/utils.ts index 49dc41e39..0cdbf5c65 100644 --- a/frontend/src/utils/utils.ts +++ b/frontend/src/utils/utils.ts @@ -74,37 +74,18 @@ export function useClickOutside( }, [ref, callback]); } -/** - * Alias old model names to new simplified names - * This ensures backward compatibility when the backend changes model names - */ -export function aliasModelName(modelName: string | undefined): string { - if (!modelName) return ""; - - // Map old model names to new simplified name - if ( - modelName === "ibnzterrell/Meta-Llama-3.3-70B-Instruct-AWQ-INT4" || - modelName === "llama3-3-70b" - ) { - return "llama-3.3-70b"; - } +export const LLAMA_MODEL_ID = "llama3-3-70b"; - if (modelName === "qwen3-coder-480b") { - return "kimi-k2-5"; - } +const MODEL_NAME_ALIASES: Record = { + "llama-3.3-70b": LLAMA_MODEL_ID, + "gemma-3-27b": "gemma4-31b", + "deepseek-r1-0528": "kimi-k2-5", + "kimi-k2": "kimi-k2-5", + "kimi-k2-thinking": "kimi-k2-5" +}; - if (modelName === "gemma-3-27b" || modelName === "leon-se/gemma-3-27b-it-fp8-dynamic") { - return "gemma4-31b"; - } - - if (modelName === "deepseek-r1-0528") { - return "kimi-k2-5"; - } - - // Alias kimi-k2 (old thinking model) to kimi-k2-5 - if (modelName === "kimi-k2" || modelName === "kimi-k2-thinking") { - return "kimi-k2-5"; - } +export function aliasModelName(modelName: string | undefined): string { + if (!modelName) return ""; - return modelName; + return MODEL_NAME_ALIASES[modelName] ?? modelName; }