import * as React from 'react';
import { useNavigate } from 'react-router-dom';
import { Check, ChevronDown, Plus, Search, SquareArrowOutUpRight } from 'lucide-react';
import { cn } from '@/lib/utils';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { searchAgents } from '@/lib/agents/registry';
import { agentIconFor } from '@/components/agents/icons';
import OwliverAvatar from '@/components/krow/OwliverAvatar';
import { useActiveAgent } from './AgentContext';
/**
* The agent switcher, inside Owliver's own header.
*
* Designed with high-density Krow Control Tower aesthetics: clean popover
* geometry, smooth row hover/active states, and legible status indicators.
*/
/** The avatar for the primary agent; a lucide glyph for the rest. */
function AgentGlyph({ agent, className = 'h-7 w-7' }) {
const Icon = agentIconFor(agent?.icon);
if (!Icon) return ;
return (
);
}
/** The label a constrained agent carries, in the switcher and in the header. */
function ConstrainedTag({ className = '' }) {
return (
Constrained
);
}
/** One row in the list. */
function AgentRow({ agent, active, covers, onSelect }) {
return (
);
}
export function AgentSwitcher({ page }) {
const navigate = useNavigate();
const { agents, agent, covers, select, coversPage } = useActiveAgent();
const [open, setOpen] = React.useState(false);
const [query, setQuery] = React.useState('');
const listRef = React.useRef(null);
React.useEffect(() => {
if (!open) setQuery('');
}, [open]);
const matches = React.useMemo(() => {
const found = searchAgents(agents, query);
return [...found].sort((a, b) => Number(coversPage(b)) - Number(coversPage(a)));
}, [agents, query, coversPage]);
const choose = (id) => {
select(id);
setOpen(false);
};
const onListKeyDown = (event) => {
const step = event.key === 'ArrowDown' ? 1 : event.key === 'ArrowUp' ? -1 : 0;
if (!step) return;
const rows = [...(listRef.current?.querySelectorAll('[role="option"]') ?? [])];
if (!rows.length) return;
event.preventDefault();
const at = rows.indexOf(document.activeElement);
rows[Math.max(0, Math.min(rows.length - 1, (at === -1 ? 0 : at + step)))]?.focus();
};
if (!agent) {
return (
<>
>
);
}
return (
Switch agent
Choose an agent to focus Owliver's scope on this page.
{matches.map((candidate) => (
))}
{!matches.length && (
No agents match that.
)}
);
}
export default AgentSwitcher;