From 2d6ec3d59d9bcc4e37fc94f049b2047e4a50704b Mon Sep 17 00:00:00 2001 From: Vukasin Date: Thu, 22 May 2025 17:31:49 +0200 Subject: [PATCH] fix: copy --- .../thread/chat-input/_use-model-selection.ts | 2 +- .../thread/chat-input/custom-model-dialog.tsx | 4 +- .../thread/chat-input/message-input.tsx | 5 ++- .../thread/chat-input/model-selector.tsx | 44 ++++++++++++++++--- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/thread/chat-input/_use-model-selection.ts b/frontend/src/components/thread/chat-input/_use-model-selection.ts index d13f3a25..860c7843 100644 --- a/frontend/src/components/thread/chat-input/_use-model-selection.ts +++ b/frontend/src/components/thread/chat-input/_use-model-selection.ts @@ -54,7 +54,7 @@ export const MODELS = { 'gpt-4.1': { tier: 'premium', priority: 95, - recommended: true, + recommended: false, lowQuality: false, description: 'GPT-4.1 - OpenAI\'s most advanced model with enhanced reasoning' }, diff --git a/frontend/src/components/thread/chat-input/custom-model-dialog.tsx b/frontend/src/components/thread/chat-input/custom-model-dialog.tsx index 9ce1409f..16bfc7e2 100644 --- a/frontend/src/components/thread/chat-input/custom-model-dialog.tsx +++ b/frontend/src/components/thread/chat-input/custom-model-dialog.tsx @@ -77,9 +77,11 @@ export const CustomModelDialog: React.FC = ({ {mode === 'add' ? 'Add Custom Model' : 'Edit Custom Model'} - Enter the model ID (use openrouter/ prefix for OpenRouter models). See LiteLLM docs; you may need to modify llm.py. + Kortix Suna uses LiteLLM under the hood, which makes it compatible with over 100 models. You can easily choose any OpenRouter model by prefixing it with openrouter/ and it should work out of the box. If you want to use other models besides OpenRouter, you might have to modify the llm.py, set the correct environment variables, and rebuild your self-hosted Docker container. + +
diff --git a/frontend/src/components/thread/chat-input/message-input.tsx b/frontend/src/components/thread/chat-input/message-input.tsx index f018593b..d33af54b 100644 --- a/frontend/src/components/thread/chat-input/message-input.tsx +++ b/frontend/src/components/thread/chat-input/message-input.tsx @@ -8,6 +8,9 @@ import { FileUploadHandler } from './file-upload-handler'; import { ModelSelector } from './model-selector'; import { SubscriptionStatus } from './_use-model-selection'; import { isLocalMode } from '@/lib/config'; +import { TooltipContent } from '@/components/ui/tooltip'; +import { Tooltip } from '@/components/ui/tooltip'; +import { TooltipProvider, TooltipTrigger } from '@radix-ui/react-tooltip'; interface MessageInputProps { value: string; @@ -137,7 +140,7 @@ export const MessageInput = forwardRef(
- {subscriptionStatus === 'no_subscription' && !isLocalMode() &&

Free plan. Upgrade.

} + {subscriptionStatus === 'no_subscription' && !isLocalMode() &&

Upgrade for full performance

The free tier is severely limited by inferior models; upgrade to experience the true full Suna experience.

}
= ({ )} {isRecommended && ( - + + Recommended + )} {isPremium && !accessible && ( @@ -531,7 +533,9 @@ export const ModelSelector: React.FC = ({ )} {(MODELS[model.id]?.recommended || false) && ( - + + Recommended + )} {selectedModel === model.id && ( @@ -580,7 +584,9 @@ export const ModelSelector: React.FC = ({
{/* Show capabilities */} {MODELS[model.id]?.recommended && ( - + + Recommended + )}
@@ -648,10 +654,34 @@ export const ModelSelector: React.FC = ({ )}
- {uniqueModels.filter(m => - m.label.toLowerCase().includes(searchQuery.toLowerCase()) || - m.id.toLowerCase().includes(searchQuery.toLowerCase()) - ).map((model, index) => renderModelOption(model, index))} + {uniqueModels + .filter(m => + m.label.toLowerCase().includes(searchQuery.toLowerCase()) || + m.id.toLowerCase().includes(searchQuery.toLowerCase()) + ) + // Sort to prioritize recommended paid models first + .sort((a, b) => { + const aRecommendedPaid = MODELS[a.id]?.recommended && a.requiresSubscription; + const bRecommendedPaid = MODELS[b.id]?.recommended && b.requiresSubscription; + + if (aRecommendedPaid && !bRecommendedPaid) return -1; + if (!aRecommendedPaid && bRecommendedPaid) return 1; + + // Secondary sorting: recommended free models next + const aRecommended = MODELS[a.id]?.recommended; + const bRecommended = MODELS[b.id]?.recommended; + + if (aRecommended && !bRecommended) return -1; + if (!aRecommended && bRecommended) return 1; + + // Paid models next + if (a.requiresSubscription && !b.requiresSubscription) return -1; + if (!a.requiresSubscription && b.requiresSubscription) return 1; + + // Default to alphabetical order + return a.label.localeCompare(b.label); + }) + .map((model, index) => renderModelOption(model, index))} {uniqueModels.length === 0 && (