- Create ChatAgentSelector with Popover+Command dropdown
- Show active agent icon, name, and ChevronDown indicator
- 'Select agent' placeholder when no agent selected
- 'No agents configured' empty state via CommandEmpty
- Agent list shows icon, name, and role label per item
- Selection calls onAgentChange and PATCHes conversation via chatApi
- Role-specific colors from agentRoleColors applied to agent icons
- Loading state shows Skeleton placeholder
- Create chat.ts API client with updateConversation supporting agentId
- Create shared types/chat.ts with ChatMessage, ChatConversation types
- Create ChatCodeBlock prerequisite from phase-21 base
- TypeScript compiles clean
- Add postMessageAndStream and savePartialMessage to chatApi (fetch ReadableStream for POST SSE)
- Create useStreamingChat hook with startStream, stop, streamingContent, isStreaming
- startTransition wraps token updates to avoid blocking user input (PERF-02)
- AbortController used for stop functionality (CHAT-12)
- stop() saves partial content with [stopped] suffix to DB
- Add @testing-library/react devDependency to enable renderHook testing
- 5 passing unit tests: token accumulation, lifecycle, stop/abort, error, null guard
- Add ilike import and search/agentId conditions in chatService.listConversations
- Extract search and agentId from req.query in GET /conversations route
- Extend chatApi.listConversations opts with search and agentId params
- Update useChatConversations to accept opts.search and include in queryKey