fix: copy

This commit is contained in:
Vukasin 2025-05-22 17:31:49 +02:00
parent b16a452920
commit 2d6ec3d59d
4 changed files with 45 additions and 10 deletions

View File

@ -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'
},

View File

@ -77,9 +77,11 @@ export const CustomModelDialog: React.FC<CustomModelDialogProps> = ({
<DialogHeader>
<DialogTitle>{mode === 'add' ? 'Add Custom Model' : 'Edit Custom Model'}</DialogTitle>
<DialogDescription>
Enter the model ID (use <code className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">openrouter/</code> prefix for OpenRouter models). See <a href="https://docs.litellm.ai/docs/" target="_blank" rel="noopener noreferrer" className="text-blue-500 hover:text-blue-600 underline">LiteLLM docs</a>; you may need to modify <code className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">llm.py</code>.
Kortix Suna uses <b>LiteLLM</b> under the hood, which makes it compatible with over 100 models. You can easily choose any <a href="https://openrouter.ai/models" target="_blank" rel="noopener noreferrer" className="text-blue-500 hover:text-blue-600 underline">OpenRouter model</a> by prefixing it with <code className="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">openrouter/</code> and it should work out of the box. If you want to use other models besides OpenRouter, you might have to modify the <a href="https://github.com/kortix-ai/suna/blob/main/backend/services/llm.py" target="_blank" rel="noopener noreferrer" className="text-blue-500 hover:text-blue-600 underline">llm.py</a>, set the correct environment variables, and rebuild your self-hosted Docker container.
</DialogDescription>
</DialogHeader>
<div className="flex flex-col gap-4 py-4">
<div className="flex flex-col items-start gap-4">

View File

@ -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<HTMLTextAreaElement, MessageInputProps>(
</div>
{subscriptionStatus === 'no_subscription' && !isLocalMode() && <p className='text-sm text-amber-500'>Free plan. Upgrade.</p>}
{subscriptionStatus === 'no_subscription' && !isLocalMode() && <TooltipProvider><Tooltip><TooltipTrigger><p className='text-sm text-amber-500'>Upgrade for full performance</p></TooltipTrigger><TooltipContent><p>The free tier is severely limited by inferior models; upgrade to experience the true full Suna experience.</p></TooltipContent></Tooltip></TooltipProvider>}
<div className='flex items-center gap-2'>
<ModelSelector
selectedModel={selectedModel}

View File

@ -388,7 +388,9 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
<AlertTriangle className="h-3.5 w-3.5 text-amber-500" />
)}
{isRecommended && (
<Brain className="h-3.5 w-3.5 text-blue-500" />
<span className="text-xs px-1.5 py-0.5 rounded-sm bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 font-medium">
Recommended
</span>
)}
{isPremium && !accessible && (
<Crown className="h-3.5 w-3.5 text-blue-500" />
@ -531,7 +533,9 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
<AlertTriangle className="h-3.5 w-3.5 text-amber-500" />
)}
{(MODELS[model.id]?.recommended || false) && (
<Brain className="h-3.5 w-3.5 text-blue-500" />
<span className="text-xs px-1.5 py-0.5 rounded-sm bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 font-medium">
Recommended
</span>
)}
{selectedModel === model.id && (
<Check className="h-4 w-4 text-blue-500" />
@ -580,7 +584,9 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
<div className="flex items-center gap-2">
{/* Show capabilities */}
{MODELS[model.id]?.recommended && (
<Brain className="h-3.5 w-3.5 text-blue-500" />
<span className="text-xs px-1.5 py-0.5 rounded-sm bg-blue-100 dark:bg-blue-900 text-blue-600 dark:text-blue-300 font-medium whitespace-nowrap">
Recommended
</span>
)}
<Crown className="h-3.5 w-3.5 text-blue-500" />
</div>
@ -648,10 +654,34 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
</TooltipProvider>
)}
</div>
{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 && (
<div className="text-sm text-center py-4 text-muted-foreground">