You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Drops the AI backend entirely and rebuilds the chat screen as a UI-only demo on shadcn/ui + Tailwind.
Integration removed
app/api/chat/route.ts deleted. It was the only backend, calling gemini-2.0-flash through streamText.
GOOGLE_GENERATIVE_AI_API_KEY removed from .env.example (and from the local .env, which is gitignored, so the key was never pushed).
Nine packages removed:
runtime AI: ai, @ai-sdk/google, @ai-sdk/react
pulled in only by the deleted elements/: @xyflow/react, shiki, streamdown, tokenlens, use-stick-to-bottom, @radix-ui/react-use-controllable-state
@xyflow/react is a full flow-diagram library and shiki a syntax highlighter shipping every language grammar; neither had any use once the chat was simplified. nanoid and motion were checked and kept, since other features still import them.
elements/ folder removed
All 30 files. It arrived as an ai-elements install and carried far more than a chat needs - canvas.tsx, node.tsx, edge.tsx, connection.tsx and controls.tsx were a node-graph editor, alongside artifacts, checkpoints, plans, queues, web previews and inline citations.
New chat UI
Four files, roughly 400 lines, using only shadcn primitives (Button, Select, Tooltip, Spinner):
ai-chat.tsx - container, state, auto-scroll, centred empty state with clickable suggestions
chat-message.tsx - user text in a right-aligned bubble, assistant replies full-width with no bubble, copy and regenerate on hover
chat-composer.tsx - textarea that grows to 200px, Enter sends and Shift+Enter newlines, model select and send button inline
data.ts / types.ts - suggestions, models, and a 5-line message type replacing the SDK's generics
Submitting appends the message, shows a thinking state, then returns a canned reply explaining that no model is connected and pointing at app/api/chat/route.ts for wiring one up. This keeps every UI state reachable rather than leaving a form that does nothing.
thinking-orbs
Added thinking-orbs (MIT, zero runtime dependencies, sideEffects: false, canvas-based) for the assistant mark, replacing a lucide Sparkles icon. It auto-detects the Tailwind dark class, so it follows the theme with no configuration.
It is used in two places only: a 64px breathing orb as the empty-state hero, and a 20px working orb in the "Thinking..." indicator - which is what the library is for. Delivered assistant messages have no avatar; a paused orb read as arbitrary noise at 20px and would have created one canvas element per message in a long conversation.
Notes
The model list is now vendor-neutral (Fast / Balanced / Advanced). It previously named three Gemini models, which would imply an integration that no longer exists.
The web-search toggle was dropped; it set state that went nowhere once the backend was removed.
Verification
tsc --noEmit clean
eslint clean
next build compiles
Signed in with the seed account and clicked through the real page: empty state, suggestion click, user message, thinking indicator, assistant reply, copy and regenerate all work
Code Review: refactor: remove ai chat integration and rebuild the chat ui on shadcn/ui
Summary
Clean, well-scoped removal of the AI backend and the oversized elements/ vendor folder, with a small (~370 line) UI-only replacement. No leftover references to the deleted packages, env var, or route were found anywhere in the codebase. A couple of medium-severity robustness gaps in the new chat UI and one minor consistency nit are worth addressing, but nothing blocks merge.
Medium Issues
1. Pending timeout not cleared on unmount (features/ai-chat/components/ai-chat.tsx:58-71)
If the user navigates away from the page while the "thinking" timeout is pending, setMessages/setStatus still fire after unmount, producing a React warning (Can't perform a state update on an unmounted component) and briefly holding a stale closure alive. It's low-impact for a demo, but easy to fix:
For users composing text with an IME (Japanese, Chinese, Korean input), pressing Enter to confirm a candidate also fires a keydown with key === "Enter", which will submit the message prematurely instead of just confirming the composition. Guard with the composition flag:
MAX_HEIGHT = 200 (JS) and the Tailwind class max-h-50 (which evaluates to 200px under Tailwind v4's calc(var(--spacing) * 50)) encode the same value in two different unit systems. They happen to agree today, but nothing enforces that — a future edit to one is likely to silently desync from the other. Consider deriving one from the other (e.g. an inline style={{ maxHeight: MAX_HEIGHT }} instead of the Tailwind class) or a comment noting the coupling.
4. Silent clipboard failure has no user-facing feedback (features/ai-chat/components/chat-message.tsx:54-62)
constcopy=async()=>{try{awaitnavigator.clipboard.writeText(message.content);setCopied(true);window.setTimeout(()=>setCopied(false),2000);}catch{// Clipboard unavailable; the text stays selectable by hand.}};
If navigator.clipboard.writeText rejects (e.g. non-secure context, permission denied), the button gives no indication that copying failed — the user just sees nothing happen. Not critical, but a toast (the project already uses sonner) would be more consistent with how other failures are surfaced elsewhere in the app.
Strengths
The elements/ removal is thorough and verified — no dangling imports of ai, @ai-sdk/*, @xyflow/react, shiki, streamdown, tokenlens, use-stick-to-bottom, GOOGLE_GENERATIVE_AI_API_KEY, or the deleted route remain anywhere in the tree (checked via grep across .ts/.tsx/README.md).
New files follow the project's feature-folder convention (features/ai-chat/{components,data.ts,types.ts}) and use only components/ui/* primitives and lucide-react icons, per repo conventions.
DEMO_REPLY in features/ai-chat/data.ts:14-15 clearly communicates the disconnected-backend state and points at the right file for wiring up a real integration, rather than leaving a dead-end form.
package.json dependency trimming is precise — nine packages removed, nanoid/motion correctly kept since other features still depend on them.
Verdict: No critical issues. Remaining items (timeout cleanup, IME composition guard) can be iterated on later, but are worth a follow-up before this pattern is copied elsewhere.
Note: tsc/eslint/next build could not be run in this sandbox (command execution required approval that wasn't available), so the PR author's own verification notes (clean tsc, eslint, and next build) were not independently re-verified — everything above is from manual reading of the diff and full file contents.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Drops the AI backend entirely and rebuilds the chat screen as a UI-only demo on shadcn/ui + Tailwind.
Integration removed
app/api/chat/route.tsdeleted. It was the only backend, callinggemini-2.0-flashthroughstreamText.GOOGLE_GENERATIVE_AI_API_KEYremoved from.env.example(and from the local.env, which is gitignored, so the key was never pushed).ai,@ai-sdk/google,@ai-sdk/reactelements/:@xyflow/react,shiki,streamdown,tokenlens,use-stick-to-bottom,@radix-ui/react-use-controllable-state@xyflow/reactis a full flow-diagram library andshikia syntax highlighter shipping every language grammar; neither had any use once the chat was simplified.nanoidandmotionwere checked and kept, since other features still import them.elements/ folder removed
All 30 files. It arrived as an
ai-elementsinstall and carried far more than a chat needs -canvas.tsx,node.tsx,edge.tsx,connection.tsxandcontrols.tsxwere a node-graph editor, alongside artifacts, checkpoints, plans, queues, web previews and inline citations.New chat UI
Four files, roughly 400 lines, using only shadcn primitives (
Button,Select,Tooltip,Spinner):ai-chat.tsx- container, state, auto-scroll, centred empty state with clickable suggestionschat-message.tsx- user text in a right-aligned bubble, assistant replies full-width with no bubble, copy and regenerate on hoverchat-composer.tsx- textarea that grows to 200px, Enter sends and Shift+Enter newlines, model select and send button inlinedata.ts/types.ts- suggestions, models, and a 5-line message type replacing the SDK's genericsSubmitting appends the message, shows a thinking state, then returns a canned reply explaining that no model is connected and pointing at
app/api/chat/route.tsfor wiring one up. This keeps every UI state reachable rather than leaving a form that does nothing.thinking-orbs
Added
thinking-orbs(MIT, zero runtime dependencies,sideEffects: false, canvas-based) for the assistant mark, replacing a lucideSparklesicon. It auto-detects the Tailwinddarkclass, so it follows the theme with no configuration.It is used in two places only: a 64px
breathingorb as the empty-state hero, and a 20pxworkingorb in the "Thinking..." indicator - which is what the library is for. Delivered assistant messages have no avatar; a paused orb read as arbitrary noise at 20px and would have created one canvas element per message in a long conversation.Notes
Verification
tsc --noEmitcleaneslintcleannext buildcompiles