'use client'; import { IconCpu } from '@tabler/icons-react'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@kandev/ui/select'; import { useAppStore } from '@/components/state-provider'; import { useAvailableAgents } from '@/hooks/use-available-agents'; import { useSettingsData } from '@/hooks/use-settings-data'; import { cn } from '@/lib/utils'; type ModelSelectorProps = { sessionId: string | null; }; export function ModelSelector({ sessionId }: ModelSelectorProps) { // Ensure settings data (agents with profiles) is loaded useSettingsData(true); const settingsAgents = useAppStore((state) => state.settingsAgents.items); const taskSessions = useAppStore((state) => state.taskSessions.items); const pendingModels = useAppStore((state) => state.pendingModel.bySessionId); const activeModels = useAppStore((state) => state.activeModel.bySessionId); const setPendingModel = useAppStore((state) => state.setPendingModel); // Ensure available agents are loaded (contains model_config) // Note: We don't block on this loading - it only affects the dropdown options const { items: availableAgents } = useAvailableAgents(); // Find the session from taskSessions const session = sessionId ? (taskSessions[sessionId] ?? null) : null; // Get model from agent_profile_snapshot (guaranteed to be non-empty since model is required) const snapshotModel = session?.agent_profile_snapshot && typeof session.agent_profile_snapshot === 'object' ? (session.agent_profile_snapshot as Record).model : null; const snapshotModelStr = typeof snapshotModel === 'string' && snapshotModel ? snapshotModel : null; // Resolve the agent profile from settings (for getting available models list) let sessionProfile: { profile: (typeof settingsAgents)[0]['profiles'][0]; agent: (typeof settingsAgents)[0] } | null = null; if (session?.agent_profile_id) { for (const agent of settingsAgents) { const profile = agent.profiles.find((p) => p.id === session.agent_profile_id); if (profile) { sessionProfile = { profile, agent }; break; } } } // Get available models from the agent discovery data let availableModels: { id: string; name: string; provider: string; context_window: number; is_default: boolean }[] = []; if (sessionProfile?.agent) { const agentName = sessionProfile.agent.name; const availableAgent = availableAgents.find((a) => a.name === agentName); if (availableAgent?.model_config?.available_models) { availableModels = availableAgent.model_config.available_models; } } // Priority: activeModel (after switch) > snapshot model // Profile model fallback removed - all profiles now have models const activeModel = sessionId ? (activeModels[sessionId] || null) : null; const currentModel = activeModel || snapshotModelStr; const pendingModel = sessionId ? (pendingModels[sessionId] || null) : null; const displayedModel = pendingModel || currentModel || ''; const hasPendingChange = pendingModel && pendingModel !== currentModel; // Ensure current model is included in the list (even if not in available models) const modelOptions = [...availableModels]; if (currentModel && !modelOptions.some((m) => m.id === currentModel)) { modelOptions.unshift({ id: currentModel, name: currentModel, provider: 'unknown', context_window: 0, is_default: false, }); } const handleModelChange = (modelId: string) => { if (!sessionId) return; setPendingModel(sessionId, modelId); }; // If no session or no model available, show disabled placeholder if (!sessionId || !currentModel) { return ( ); } return ( ); }