({ projectSlug, agents, inFlightCounts = {} }: Props)
| 42 | }; |
| 43 | |
| 44 | export function AgentNav({ projectSlug, agents, inFlightCounts = {} }: Props) { |
| 45 | const pathname = usePathname(); |
| 46 | const live = useLiveCounts(); |
| 47 | const counts: Record<string, number> = { ...inFlightCounts, ...live.agents }; |
| 48 | |
| 49 | return ( |
| 50 | <SidebarMenu> |
| 51 | {agents.map((a) => { |
| 52 | // Every agent lands on Chat by default — users start by talking to |
| 53 | // the agent. Tasks tab (the audit/history view of filed work) is one |
| 54 | // click away. |
| 55 | const href = projectHref(projectSlug, `/agents/${a.slug}/chat`); |
| 56 | const agentBase = `/${projectSlug}/agents/${a.slug}`; |
| 57 | const isActive = |
| 58 | pathname === agentBase || pathname?.startsWith(`${agentBase}/`); |
| 59 | const liveCount = counts[a.key] ?? 0; |
| 60 | const rolePalette = a.template_key ? colorForRole(a.template_key) : null; |
| 61 | return ( |
| 62 | <SidebarMenuItem key={a.key}> |
| 63 | <SidebarMenuButton asChild isActive={isActive}> |
| 64 | <Link href={href}> |
| 65 | {a.template_key ? ( |
| 66 | <AgentAvatar role={a.template_key} size={20} /> |
| 67 | ) : ( |
| 68 | <Bot /> |
| 69 | )} |
| 70 | <span className="truncate">{a.name}</span> |
| 71 | {a.role_label && rolePalette && ( |
| 72 | <span |
| 73 | className={cn( |
| 74 | "ml-1 rounded-[4px] border px-1.5 py-[1px] text-[9.5px] font-medium uppercase tracking-wide leading-none", |
| 75 | rolePalette.chip, |
| 76 | )} |
| 77 | > |
| 78 | {a.role_label} |
| 79 | </span> |
| 80 | )} |
| 81 | {liveCount > 0 && ( |
| 82 | <span |
| 83 | className="ml-auto inline-flex items-center gap-1.5" |
| 84 | role="status" |
| 85 | aria-label={`${liveCount} running`} |
| 86 | > |
| 87 | <span aria-hidden className="ns-dot ns-dot-live" /> |
| 88 | <span className="text-[10px] font-semibold tabular-nums text-[hsl(var(--notfair-accent))]"> |
| 89 | {liveCount} |
| 90 | </span> |
| 91 | </span> |
| 92 | )} |
| 93 | </Link> |
| 94 | </SidebarMenuButton> |
| 95 | </SidebarMenuItem> |
| 96 | ); |
| 97 | })} |
| 98 | </SidebarMenu> |
| 99 | ); |
| 100 | } |
nothing calls this directly
no test coverage detected