import { View, Text, Platform, Pressable } from "react-native"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { Brain, ChevronDown, SlidersHorizontal } from "lucide-react-native"; import { useSessionStore } from "@/stores/session-store"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { AdaptiveModalSheet } from "@/components/adaptive-modal-sheet"; import { useMemo, useState } from "react"; import { useQuery } from "@tanstack/react-query"; interface AgentStatusBarProps { agentId: string; serverId: string; } function normalizeModelId(modelId: string | null | undefined): string | null { const normalized = typeof modelId === "string" ? modelId.trim() : ""; if (!normalized || normalized.toLowerCase() === "default") { return null; } return normalized; } export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) { const { theme } = useUnistyles(); const IS_WEB = Platform.OS === "web"; const [prefsOpen, setPrefsOpen] = useState(false); const dropdownMaxWidth = IS_WEB ? 360 : undefined; // Select only the specific agent (not all agents) const agent = useSessionStore((state) => state.sessions[serverId]?.agents?.get(agentId) ); const client = useSessionStore((state) => state.sessions[serverId]?.client ?? null); if (!agent) { return null; } const canFetchModels = Boolean(client) && Boolean(agent.provider) && (IS_WEB || prefsOpen); const modelsQuery = useQuery({ queryKey: ["providerModels", serverId, agent.provider, agent.cwd], enabled: canFetchModels, staleTime: 5 * 60 * 1000, queryFn: async () => { if (!client) { throw new Error("Daemon client unavailable"); } const payload = await client.listProviderModels(agent.provider, { cwd: agent.cwd }); if (payload.error) { throw new Error(payload.error); } return payload.models ?? []; }, }); const models = modelsQuery.data ?? null; function handleModeChange(modeId: string) { if (!client) { return; } void client.setAgentMode(agentId, modeId).catch((error) => { console.warn("[AgentStatusBar] setAgentMode failed", error); }); } const normalizedRuntimeModelId = normalizeModelId(agent.runtimeInfo?.model); const normalizedConfiguredModelId = normalizeModelId(agent.model); const preferredModelId = normalizedRuntimeModelId ?? normalizedConfiguredModelId; const selectedModel = useMemo(() => { if (!models || !preferredModelId) return null; return models.find((m) => m.id === preferredModelId) ?? null; }, [models, preferredModelId]); const activeModelId = selectedModel?.id ?? preferredModelId ?? null; const displayModel = selectedModel ? selectedModel.label : preferredModelId ?? "Auto"; const thinkingOptions = selectedModel?.thinkingOptions ?? null; const explicitThinkingId = agent.thinkingOptionId && agent.thinkingOptionId !== "default" ? agent.thinkingOptionId : null; const selectedThinkingId = explicitThinkingId ?? selectedModel?.defaultThinkingOptionId ?? null; const selectedThinking = thinkingOptions?.find((o) => o.id === selectedThinkingId) ?? null; const displayThinking = selectedThinking?.label ?? (selectedThinkingId === "default" ? "Model default" : selectedThinkingId ?? "auto"); const displayMode = agent.availableModes?.find((m) => m.id === agent.currentModeId)?.label || agent.currentModeId || "default"; return ( {/* Agent Mode Badge (desktop only — on mobile, mode is in the preferences sheet) */} {IS_WEB && agent.availableModes && agent.availableModes.length > 0 && ( [ styles.modeBadge, hovered && styles.modeBadgeHovered, (pressed || open) && styles.modeBadgePressed, ]} accessibilityRole="button" accessibilityLabel="Select agent mode" testID="agent-mode-selector" > {agent.availableModes?.find((m) => m.id === agent.currentModeId) ?.label || agent.currentModeId || "default"} {agent.availableModes.map((mode) => { const isActive = mode.id === agent.currentModeId; return ( handleModeChange(mode.id)} > {mode.label} ); })} )} {/* Desktop: inline dropdowns for model/thinking */} {IS_WEB && ( <> [ styles.modeBadge, hovered && styles.modeBadgeHovered, (pressed || open) && styles.modeBadgePressed, ]} accessibilityRole="button" accessibilityLabel="Select agent model" testID="agent-model-selector" > {displayModel} {models?.map((model) => { const isActive = model.id === activeModelId; return ( { if (!client) { return; } void client.setAgentModel(agentId, model.id).catch((error) => { console.warn("[AgentStatusBar] setAgentModel failed", error); }); }} > {model.label} ); })} {thinkingOptions && thinkingOptions.length > 1 && ( [ styles.modeBadge, hovered && styles.modeBadgeHovered, (pressed || open) && styles.modeBadgePressed, ]} accessibilityRole="button" accessibilityLabel="Select thinking option" testID="agent-thinking-selector" > {displayThinking} {thinkingOptions.map((opt) => { const isActive = opt.id === selectedThinkingId; return ( { if (!client) { return; } void client .setAgentThinkingOption(agentId, opt.id) .catch((error) => { console.warn("[AgentStatusBar] setAgentThinkingOption failed", error); }); }} > {opt.label} ); })} )} )} {/* Mobile: preferences button opens a bottom sheet */} {!IS_WEB && ( <> setPrefsOpen(true)} style={({ pressed }) => [ styles.prefsButton, pressed && styles.prefsButtonPressed, ]} accessibilityRole="button" accessibilityLabel="Agent preferences" testID="agent-preferences-button" > setPrefsOpen(false)} testID="agent-preferences-sheet" > {agent.availableModes && agent.availableModes.length > 0 && ( [ styles.sheetSelect, pressed && styles.sheetSelectPressed, ]} accessibilityRole="button" accessibilityLabel="Select agent mode" testID="agent-preferences-mode" > {displayMode} {agent.availableModes.map((mode) => { const isActive = mode.id === agent.currentModeId; return ( handleModeChange(mode.id)} > {mode.label} ); })} )} [ styles.sheetSelect, pressed && styles.sheetSelectPressed, ]} accessibilityRole="button" accessibilityLabel="Select agent model" testID="agent-preferences-model" > {displayModel} {models?.map((model) => { const isActive = model.id === activeModelId; return ( { if (!client) { return; } void client.setAgentModel(agentId, model.id).catch((error) => { console.warn("[AgentStatusBar] setAgentModel failed", error); }); }} > {model.label} ); })} {thinkingOptions && thinkingOptions.length > 1 && ( [ styles.sheetSelect, pressed && styles.sheetSelectPressed, ]} accessibilityRole="button" accessibilityLabel="Select thinking option" testID="agent-preferences-thinking" > {displayThinking} {thinkingOptions.map((opt) => { const isActive = opt.id === selectedThinkingId; return ( { if (!client) { return; } void client .setAgentThinkingOption(agentId, opt.id) .catch((error) => { console.warn("[AgentStatusBar] setAgentThinkingOption failed", error); }); }} > {opt.label} ); })} )} )} ); } const styles = StyleSheet.create((theme) => ({ container: { flexDirection: "row", alignItems: "center", gap: theme.spacing[1], }, modeBadge: { flexDirection: "row", alignItems: "center", backgroundColor: "transparent", gap: theme.spacing[1], paddingHorizontal: theme.spacing[2], paddingVertical: theme.spacing[1], borderRadius: theme.borderRadius["2xl"], }, modeBadgeHovered: { backgroundColor: theme.colors.surface2, }, modeBadgePressed: { backgroundColor: theme.colors.surface0, }, modeBadgeText: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.sm, fontWeight: theme.fontWeight.normal, }, prefsButton: { width: 34, height: 34, borderRadius: theme.borderRadius.full, alignItems: "center", justifyContent: "center", }, prefsButtonPressed: { backgroundColor: theme.colors.surface0, }, sheetSection: { gap: theme.spacing[2], }, sheetSelect: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", gap: theme.spacing[3], paddingHorizontal: theme.spacing[4], paddingVertical: theme.spacing[3], borderRadius: theme.borderRadius.lg, borderWidth: 1, borderColor: theme.colors.surface2, backgroundColor: theme.colors.surface0, }, sheetSelectPressed: { backgroundColor: theme.colors.surface2, }, sheetSelectText: { flex: 1, color: theme.colors.foreground, fontSize: theme.fontSize.base, fontWeight: theme.fontWeight.semibold, }, }));