import React, { useEffect, useRef, useState } from 'react'; import { Label } from '@renderer/components/ui/label'; import { cn } from '@renderer/lib/utils'; import { Check, ChevronDown } from 'lucide-react'; // --- Provider SVG Icons (real brand logos from Simple Icons, monochrome currentColor) --- /** Anthropic — official "A" lettermark (Simple Icons) */ const AnthropicIcon: React.FC<{ className?: string }> = ({ className }) => ( ); /** OpenAI — official hexagonal knot logo (Simple Icons) */ const OpenAIIcon: React.FC<{ className?: string }> = ({ className }) => ( ); /** Google Gemini — official sparkle/star mark (Simple Icons) */ const GoogleIcon: React.FC<{ className?: string }> = ({ className }) => ( ); /** Local — server rack icon */ const LocalIcon: React.FC<{ className?: string }> = ({ className }) => ( ); // --- Provider definitions --- interface ProviderDef { id: string; label: string; icon: React.FC<{ className?: string }>; comingSoon: boolean; } const PROVIDERS: ProviderDef[] = [ { id: 'anthropic', label: 'Anthropic', icon: AnthropicIcon, comingSoon: false }, { id: 'openai', label: 'OpenAI', icon: OpenAIIcon, comingSoon: true }, { id: 'google', label: 'Google', icon: GoogleIcon, comingSoon: true }, { id: 'local', label: 'Local', icon: LocalIcon, comingSoon: true }, ]; const ACTIVE_PROVIDER = PROVIDERS[0]; // --- Model options (Anthropic only for now) --- const MODEL_OPTIONS = [ { value: '', label: 'Default' }, { value: 'opus', label: 'Opus 4.6' }, { value: 'sonnet', label: 'Sonnet 4.6' }, { value: 'haiku', label: 'Haiku 4.5' }, ] as const; /** * Computes the effective model string for team provisioning. * By default adds [1m] suffix for 1M context (Opus/Sonnet). * When limitContext=true, returns base model without [1m] (200K context). * Haiku does not support 1M — always returned as-is. */ export function computeEffectiveTeamModel( selectedModel: string, limitContext: boolean ): string | undefined { const base = selectedModel || undefined; if (limitContext) return base; if (base === 'haiku') return base; return base ? `${base}[1m]` : 'sonnet[1m]'; } export interface TeamModelSelectorProps { value: string; onValueChange: (value: string) => void; id?: string; } export const TeamModelSelector: React.FC = ({ value, onValueChange, id, }) => { const [dropdownOpen, setDropdownOpen] = useState(false); const containerRef = useRef(null); // Close dropdown on click outside useEffect(() => { if (!dropdownOpen) return; const handleClickOutside = (event: MouseEvent): void => { if (containerRef.current && !containerRef.current.contains(event.target as Node)) { setDropdownOpen(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, [dropdownOpen]); const ProviderIcon = ACTIVE_PROVIDER.icon; return (
{/* Provider button */} {/* Model pills */} {MODEL_OPTIONS.map((opt) => ( ))}
{/* Provider dropdown */} {dropdownOpen && (
{PROVIDERS.map((provider, index) => { const Icon = provider.icon; const isActive = provider.id === ACTIVE_PROVIDER.id; const isFirst = index === 0; const prevWasActive = index > 0 && !PROVIDERS[index - 1].comingSoon; return ( {prevWasActive && !isFirst && (
)} ); })}
)}
); };