feat(web): add streaming AI chat UI to the AI Insights page - #135
feat(web): add streaming AI chat UI to the AI Insights page#135YorgoTabet wants to merge 2 commits into
Conversation
Replaces the batch insight-generation page with a conversational, action-chip chat wired to the existing POST /chat endpoint, so owners can ask about their own sales, expenses, products and goals. - useChat (@ai-sdk/react) over DefaultChatTransport pointed at the Nest endpoint with credentials: 'include', so the session cookie rides along and the backend AuthGuard scopes every answer to the caller's org. - Renders UIMessage parts: text as markdown, tool calls as "Checked your <label>" activity chips driven by part.state, plus typing dots and a stop control while streaming. - Four preset action chips map to the read-only data tools (businessSummary, topNExpenses, listSales/listProducts, listGoals). - @ai-sdk/react pinned to the 3.x line, which is the one that pairs with ai@6 (the 4.x line targets ai@7). Metrics stay computed in code; the model only interprets tool results.
|
Warning Review limit reached
Next review available in: 44 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe AI Insights page now provides an authenticated streaming chat UI using ChangesAI Insights chat
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant User
participant AiInsightsPage
participant ChatAPI
User->>AiInsightsPage: Submit chat message
AiInsightsPage->>ChatAPI: POST /chat with credentials
ChatAPI-->>AiInsightsPage: Stream text and tool parts
AiInsightsPage-->>User: Render markdown and tool status
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/web/app/(authenticated)/ai-insights/page.tsx (1)
105-114: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse semantic heading tags for accessibility.
Rendering
h1,h2, andh3as<p>tags breaks the document outline for screen readers. You can maintain the exact same visual styling while using the correct semantic HTML elements.♻️ Proposed fix
- h1: ({ children }: { children?: React.ReactNode }) => ( - <p className="text-sm font-semibold text-foreground">{children}</p> - ), - h2: ({ children }: { children?: React.ReactNode }) => ( - <p className="text-sm font-semibold text-foreground">{children}</p> - ), - h3: ({ children }: { children?: React.ReactNode }) => ( - <p className="text-sm font-semibold text-foreground">{children}</p> - ), + h1: ({ children }: { children?: React.ReactNode }) => ( + <h1 className="text-sm font-semibold text-foreground">{children}</h1> + ), + h2: ({ children }: { children?: React.ReactNode }) => ( + <h2 className="text-sm font-semibold text-foreground">{children}</h2> + ), + h3: ({ children }: { children?: React.ReactNode }) => ( + <h3 className="text-sm font-semibold text-foreground">{children}</h3> + ),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/app/`(authenticated)/ai-insights/page.tsx around lines 105 - 114, Update the Markdown heading renderers h1, h2, and h3 to emit their corresponding semantic heading elements instead of p tags, while preserving the existing text-sm font-semibold text-foreground styling and children handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/app/`(authenticated)/ai-insights/page.tsx:
- Around line 235-237: Update the scroll behavior in the useEffect that tracks
messages and waitingForReply to use immediate scrolling instead of smooth
scrolling. Keep the existing endRef.current?.scrollIntoView call and
dependencies unchanged so streaming updates remain anchored without repeatedly
restarting an animation.
---
Nitpick comments:
In `@apps/web/app/`(authenticated)/ai-insights/page.tsx:
- Around line 105-114: Update the Markdown heading renderers h1, h2, and h3 to
emit their corresponding semantic heading elements instead of p tags, while
preserving the existing text-sm font-semibold text-foreground styling and
children handling.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 05278c38-bba9-48d4-94d4-0de815515f49
⛔ Files ignored due to path filters (3)
docs/screenshots/ai-chat-conversation.pngis excluded by!**/*.pngdocs/screenshots/ai-chat-empty-state.pngis excluded by!**/*.pngpackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (2)
apps/web/app/(authenticated)/ai-insights/page.tsxapps/web/package.json
The scroll effect depends on `messages`, which changes on every streamed chunk, so a smooth scroll restarted its animation many times a second and visibly stuttered. Uses 'instant' rather than 'auto': 'auto' defers to the CSS scroll-behavior property, so it would silently regress if a global `scroll-behavior: smooth` were ever added. Verified in-browser: with the list overflowing (827px into a 331px viewport) the view stays pinned to the bottom.
|
@AliMahmoudDev Thanks for looking — replying to both points. Cancel button — already in there 👍It's in the composer at Easy to miss from the PR — both screenshots are of the idle state, so they show the send button. I tried to grab a mid-stream shot to make it visible and hit the Gemini free-tier cap ( Reconnection mid-stream — real gap, needs backend workAgreed, and it's genuinely missing. Right now a dropped connection surfaces the error state rather than resuming, so you lose the partial answer. Doing it properly isn't frontend-only: the AI SDK's resume support ( Logical properties / RTL — agree in principle, but not in this file aloneTwo things worth flagging before we do this:
So converting just this one file would make it the only file in the codebase using a different idiom, while delivering no actual RTL benefit — the sidebar, top nav, tables and every other page would still be LTR-physical, so the layout breaks under If RTL is on the roadmap I'm all for it, but as a deliberate app-wide pass (flip the shared components + add |
What & why
Final piece of the AI chat feature: the frontend. The streaming
POST /chatendpoint and its read-only data tools already landed (#22/#55, #78) — but nothing in the UI talked to them. This wires the/ai-insightspage up to that endpoint so owners can actually ask about their own records.Per the product decision, the AI surface is the action-chip chat, so this replaces the old batch insight-generation UI on that page rather than adding a second AI screen.
Screenshots
Live conversation — grounded in real records
Both answers come from tool calls against the caller's own org: the summary reads
businessSummary(revenue $15,520, gross margin 41.21%, net −$2,104 — a real loss despite healthy gross margin), and the expense list readstopNExpenses.Empty state — action chips
How it works
useChat(@ai-sdk/react) overDefaultChatTransportpointed at the Nest endpoint withcredentials: 'include'— the session cookie rides along so the backendAuthGuardscopes every answer to the caller's organization.UIMessage.partsin order: text as markdown, tool calls as "Checked your <label>" activity chips driven bypart.state, plus typing dots and a stop control while streaming.businessSummary,topNExpenses,listSales/listProducts,listGoals.Notes for reviewers
@ai-sdk/reactis pinned to the 3.x line, which is the one that pairs withai@6(matchingapps/api). The4.xline depends onai@7— don't@latestit.react-markdown: the model replies in markdown; without a renderer the UI printed literal**asterisks**. Styled via explicit component overrides since this app doesn't use the Tailwind typography plugin.ai-insightsbackend module andhooks/use-ai-insights.tsare no longer surfaced but left in place — nothing deleted, easy to revert.Verification
tsc --noEmitandeslint --max-warnings 0clean onapps/web.Known limitation (not introduced here)
For questions that need ranking/arithmetic the model can occasionally reason over raw tool output and slip — e.g. asked "most profit per unit" it once picked a $65/unit item over a $420/unit one. The system prompt already says to read figures from tool results; tightening that (or adding a dedicated per-unit-margin tool) is backend work worth a follow-up.
Summary by CodeRabbit