oneie
Version:
Build apps, websites, and AI agents in English. Zero-interaction setup for AI agents (Claude Code, Cursor, Windsurf). Download to your computer, run in the cloud, deploy to the edge. Open source and free forever.
1,279 lines (1,020 loc) • 27.4 kB
Markdown
title: Ai Elements
dimension: things
category: plans
tags: agent, ai, artificial-intelligence, installation
related_dimensions: connections
scope: global
created: 2025-11-03
updated: 2025-11-03
version: 1.0.0
ai_context: |
This document is part of the things dimension in the plans category.
Location: one/things/plans/ai-elements.md
Purpose: Documents ai elements implementation plan
Related dimensions: connections
For AI agents: Read this to understand ai elements.
# AI Elements Implementation Plan
**Version:** 1.0.0
**Status:** Planning
**Integration:** AI SDK + Convex Agents
**Target Platform:** Astro 5 + React 19 + shadcn/ui
## Overview
**AI Elements** is a component library for building AI-powered interfaces. It provides 30+ pre-built components for:
- Chat interfaces (Chatbot, Message, Response, etc.)
- Content display (Code Block, Image, Sources, Artifact, Web Preview)
- Advanced AI features (Chain of Thought, Reasoning, Task, etc.)
- Canvas/workflow components (Node, Edge, Connection, Panel, etc.)
### Why AI Elements?
- **Pre-built**: 30+ production-ready components
- **Accessible**: WCAG compliant, keyboard navigation
- **Themeable**: Customize colors, spacing, typography
- **Type-safe**: Full TypeScript support
- **Composable**: Mix and match components
- **Tested**: Proven in production AI apps
## Installation & Setup (Cycle 1-10)
### Prerequisites
```bash
# Ensure you have Node.js 18+
node --version # v18+
# Ensure shadcn/ui is installed in your project
npx shadcn-ui@latest init
```
### Install AI Elements
**Option 1: Using AI Elements CLI (Recommended)**
```bash
npx ai-elements@latest init
# Prompts you to select which components to install
```
**Option 2: Using shadcn/ui CLI**
```bash
npx shadcn-ui@latest add ai-elements
```
**Option 3: Manual Installation**
```bash
npm install @ai-elements/core @ai-elements/ui
npm install ai @ai-sdk/openai
npm install zod
```
### Verify Installation
```bash
# Check components are in place
ls src/components/ui/ai-elements/
# Should see:
# - chatbot.tsx
# - message.tsx
# - response.tsx
# - suggestion.tsx
# - tool.tsx
# - code-block.tsx
# - artifact.tsx
# - and more...
```
### Environment Setup
**web/.env.local:**
```bash
PUBLIC_CONVEX_URL=https://shocking-falcon-870.convex.cloud
CONVEX_DEPLOYMENT=prod:shocking-falcon-870
OPENAI_API_KEY=sk-...
```
## Components Library (Cycle 11-30)
### Core Chat Components
#### 1. Chatbot Component
The main container for chat interactions.
```typescript
// src/components/features/AIChat/Chatbot.tsx
import { Chatbot } from "@/components/ui/ai-elements/chatbot";
export function MyChatbot() {
return (
<Chatbot
id="my-chatbot"
messages={[]}
input=""
isLoading={false}
onInputChange={(value) => {}}
onSubmit={(value) => {}}
onMessageClick={(message) => {}}
onSuggestionsClick={(suggestion) => {}}
/>
);
}
```
#### 2. Message Component
Individual message display.
```typescript
import { Message } from "@/components/ui/ai-elements/message";
<Message
role="user"
content="What is the weather?"
timestamp={new Date()}
isLoading={false}
metadata={{
source: "chat",
tokens: 45,
}}
/>
```
#### 3. Response Component
AI response with optional metadata.
```typescript
import { Response } from "@/components/ui/ai-elements/response";
<Response
content="The weather is sunny."
role="assistant"
timestamp={new Date()}
actions={[
{ label: "Copy", onClick: () => {} },
{ label: "Edit", onClick: () => {} },
]}
/>
```
#### 4. Suggestion Component
Suggested follow-up questions.
```typescript
import { Suggestion } from "@/components/ui/ai-elements/suggestion";
<Suggestion
suggestions={[
"Tell me more",
"How does this work?",
"Give me an example",
]}
onSuggestionClick={(suggestion) => {}}
/>
```
#### 5. Prompt Input Component
Input field for user messages.
```typescript
import { PromptInput } from "@/components/ui/ai-elements/prompt-input";
<PromptInput
value={input}
onChange={(value) => setInput(value)}
onSubmit={(value) => sendMessage(value)}
isLoading={isLoading}
placeholder="Ask me anything..."
maxCharacters={1000}
allowedMimeTypes={["text/plain", "application/pdf"]}
/>
```
### Content Display Components
#### 6. Code Block Component
Displays code with syntax highlighting.
```typescript
import { CodeBlock } from "@/components/ui/ai-elements/code-block";
<CodeBlock
code={`function hello() {
console.log("world");
}`}
language="javascript"
showLineNumbers={true}
allowCopy={true}
theme="dark"
onCopy={() => navigator.clipboard.writeText(code)}
/>
```
#### 7. Image Component
Displays images with captions.
```typescript
import { Image } from "@/components/ui/ai-elements/image";
<Image
src="https://example.com/image.jpg"
alt="Example"
caption="Generated image"
width={400}
height={300}
allowDownload={true}
/>
```
#### 8. Artifact Component
Displays rich content (code, HTML, React components).
```typescript
import { Artifact } from "@/components/ui/ai-elements/artifact";
<Artifact
type="code"
content={`<div class="p-4 bg-blue-500">Hello World</div>`}
language="html"
title="HTML Preview"
showCode={true}
showPreview={true}
/>
```
#### 9. Web Preview Component
Renders web content in an iframe.
```typescript
import { WebPreview } from "@/components/ui/ai-elements/web-preview";
<WebPreview
html={`<html><body><h1>Hello</h1></body></html>`}
width={800}
height={600}
sandbox={true}
/>
```
#### 10. Sources Component
Display citations and sources.
```typescript
import { Sources } from "@/components/ui/ai-elements/sources";
<Sources
sources={[
{
id: "src1",
title: "Wikipedia",
url: "https://en.wikipedia.org",
excerpt: "World's largest encyclopedia",
},
{
id: "src2",
title: "Official Docs",
url: "https://docs.example.com",
excerpt: "Complete reference guide",
},
]}
onSourceClick={(source) => window.open(source.url)}
/>
```
#### 11. Inline Citation Component
Inline citations within text.
```typescript
import { InlineCitation } from "@/components/ui/ai-elements/inline-citation";
<div>
According to recent studies<InlineCitation citationId="1" />,
AI is transforming industries.
<Sources citations={[{ id: "1", title: "Study", url: "#" }]} />
</div>
```
### Advanced AI Features
#### 12. Chain of Thought Component
Shows the AI's reasoning process.
```typescript
import { ChainOfThought } from "@/components/ui/ai-elements/chain-of-thought";
<ChainOfThought
steps={[
{
step: 1,
description: "Understanding the question",
status: "completed",
},
{
step: 2,
description: "Searching for relevant information",
status: "in_progress",
},
{
step: 3,
description: "Formulating the answer",
status: "pending",
},
]}
/>
```
#### 13. Reasoning Component
Displays multi-step reasoning.
```typescript
import { Reasoning } from "@/components/ui/ai-elements/reasoning";
<Reasoning
reasoning={[
"Step 1: Parse the input",
"Step 2: Check constraints",
"Step 3: Generate solution",
"Step 4: Validate output",
]}
expandable={true}
collapsed={false}
/>
```
#### 14. Task Component
Shows progress of multi-step tasks.
```typescript
import { Task } from "@/components/ui/ai-elements/task";
<Task
title="Generate Report"
subtasks={[
{ title: "Collect data", completed: true },
{ title: "Analyze metrics", completed: true },
{ title: "Create visualizations", completed: false },
{ title: "Write summary", completed: false },
]}
progress={50}
/>
```
#### 15. Plan Component
Displays execution plans.
```typescript
import { Plan } from "@/components/ui/ai-elements/plan";
<Plan
planItems={[
{
id: "1",
title: "Phase 1: Research",
description: "Gather requirements",
timeEstimate: "2 weeks",
},
{
id: "2",
title: "Phase 2: Design",
description: "Create architecture",
timeEstimate: "1 week",
},
]}
/>
```
#### 16. Loader Component
Shows loading state with animations.
```typescript
import { Loader } from "@/components/ui/ai-elements/loader";
<Loader
type="dots"
message="AI is thinking..."
size="medium"
/>
```
#### 17. Shimmer Component
Skeleton loader for content.
```typescript
import { Shimmer } from "@/components/ui/ai-elements/shimmer";
<Shimmer
width="100%"
height={20}
count={3}
/>
```
#### 18. Branch Component
Shows decision branches in reasoning.
```typescript
import { Branch } from "@/components/ui/ai-elements/branch";
<Branch
condition="Temperature > 20°C"
trueBranch="Recommend outdoor activity"
falseBranch="Recommend indoor activity"
/>
```
#### 19. Queue Component
Shows task queue.
```typescript
import { Queue } from "@/components/ui/ai-elements/queue";
<Queue
items={[
{ id: "1", title: "Task 1", status: "processing" },
{ id: "2", title: "Task 2", status: "queued" },
]}
/>
```
#### 20. Context Component
Displays current context.
```typescript
import { Context } from "@/components/ui/ai-elements/context";
<Context
items={{
"User": "John Doe",
"Group": "Engineering",
"Project": "AI Platform",
}}
/>
```
### Tool & Workflow Components
#### 21. Tool Component
Displays available tools.
```typescript
import { Tool } from "@/components/ui/ai-elements/tool";
<Tool
name="Web Search"
description="Search the internet"
icon="🔍"
onSelect={() => {}}
/>
```
#### 22. Actions Component
Display available actions.
```typescript
import { Actions } from "@/components/ui/ai-elements/actions";
<Actions
actions={[
{ label: "Copy", onClick: () => {}, icon: "📋" },
{ label: "Share", onClick: () => {}, icon: "🔗" },
{ label: "Edit", onClick: () => {}, icon: "✏️" },
]}
/>
```
#### 23. Conversation Component
Full conversation container.
```typescript
import { Conversation } from "@/components/ui/ai-elements/conversation";
<Conversation
id="conv-1"
title="Project Discussion"
messages={messages}
onMessageAdd={(message) => {}}
/>
```
#### 24. Open In Chat Component
Links content to chat.
```typescript
import { OpenInChat } from "@/components/ui/ai-elements/open-in-chat";
<OpenInChat
content="Summarize this document"
onOpen={() => goToChat()}
/>
```
### Canvas & Visualization Components
#### 25. Node Component
Node in a graph/canvas.
```typescript
import { Node } from "@/components/ui/ai-elements/node";
<Node
id="node-1"
title="Start"
position={{ x: 100, y: 100 }}
onSelect={() => {}}
/>
```
#### 26. Edge Component
Connection between nodes.
```typescript
import { Edge } from "@/components/ui/ai-elements/edge";
<Edge
from="node-1"
to="node-2"
label="depends on"
/>
```
#### 27. Connection Component
Visual connection.
```typescript
import { Connection } from "@/components/ui/ai-elements/connection";
<Connection
source="node-1"
target="node-2"
animated={true}
/>
```
#### 28. Panel Component
Container for canvas controls.
```typescript
import { Panel } from "@/components/ui/ai-elements/panel";
<Panel position="top-left">
<h3>Controls</h3>
<button>Reset</button>
</Panel>
```
#### 29. Controls Component
Canvas control buttons.
```typescript
import { Controls } from "@/components/ui/ai-elements/controls";
<Controls
onZoomIn={() => {}}
onZoomOut={() => {}}
onFit={() => {}}
onReset={() => {}}
/>
```
#### 30. Toolbar Component
Toolbar for canvas operations.
```typescript
import { Toolbar } from "@/components/ui/ai-elements/toolbar";
<Toolbar
items={[
{ label: "Select", icon: "✓", onClick: () => {} },
{ label: "Draw", icon: "✏️", onClick: () => {} },
{ label: "Delete", icon: "🗑️", onClick: () => {} },
]}
/>
```
## Fully Functional Chat UI (Cycle 31-50)
### Complete Chat Component
```typescript
// src/components/features/AIChat/CompleteChatUI.tsx
import { useState } from "react";
import { useAIChat } from "@/lib/hooks/useAIChat";
import { Chatbot } from "@/components/ui/ai-elements/chatbot";
import { Message } from "@/components/ui/ai-elements/message";
import { Response } from "@/components/ui/ai-elements/response";
import { Suggestion } from "@/components/ui/ai-elements/suggestion";
import { PromptInput } from "@/components/ui/ai-elements/prompt-input";
import { CodeBlock } from "@/components/ui/ai-elements/code-block";
import { Artifact } from "@/components/ui/ai-elements/artifact";
import { ChainOfThought } from "@/components/ui/ai-elements/chain-of-thought";
import { Loader } from "@/components/ui/ai-elements/loader";
import { Sources } from "@/components/ui/ai-elements/sources";
import { Actions } from "@/components/ui/ai-elements/actions";
interface CompleteChatUIProps {
groupId: string;
agentId: string;
}
export function CompleteChatUI({ groupId, agentId }: CompleteChatUIProps) {
const { messages, input, handleInputChange, isLoading, sendMessage } =
useAIChat(groupId, agentId);
const [showReasoning, setShowReasoning] = useState(false);
const [selectedMessage, setSelectedMessage] = useState<string | null>(null);
const handleSendMessage = async (content: string) => {
try {
await sendMessage(content);
handleInputChange({ target: { value: "" } } as any);
} catch (error) {
console.error("Failed to send message:", error);
}
};
const suggestions = [
"Explain how this works",
"Give me an example",
"What are the benefits?",
"Show me the code",
];
return (
<div className="flex h-screen flex-col gap-4 p-4">
{/* Header */}
<div className="flex items-center justify-between border-b pb-4">
<h1 className="text-2xl font-bold">AI Chat</h1>
<button
className="text-sm text-gray-500 hover:text-gray-700"
onClick={() => setShowReasoning(!showReasoning)}
>
{showReasoning ? "Hide" : "Show"} Reasoning
</button>
</div>
{/* Messages Container */}
<div className="flex-1 overflow-y-auto space-y-4">
{messages.length === 0 ? (
<div className="flex h-full items-center justify-center text-gray-500">
<div className="text-center">
<h2 className="text-xl font-semibold mb-2">Start a Conversation</h2>
<p>Ask me anything or choose a suggestion below</p>
</div>
</div>
) : (
messages.map((msg, idx) => (
<div
key={idx}
className={`flex ${msg.role === "user" ? "justify-end" : "justify-start"}`}
onClick={() => setSelectedMessage(msg.id)}
>
<div
className={`max-w-lg rounded-lg px-4 py-3 ${
msg.role === "user"
? "bg-blue-500 text-white"
: "bg-gray-100 text-gray-900"
}`}
>
{/* Text Content */}
<Message
role={msg.role}
content={msg.content}
timestamp={new Date(msg.createdAt || Date.now())}
isLoading={false}
/>
{/* Code Block if Present */}
{msg.metadata?.type === "code" && (
<CodeBlock
code={msg.metadata.code}
language={msg.metadata.language || "javascript"}
showLineNumbers={true}
allowCopy={true}
theme="dark"
/>
)}
{/* Artifact if Present */}
{msg.metadata?.type === "artifact" && (
<Artifact
type={msg.metadata.artifactType}
content={msg.metadata.content}
title={msg.metadata.title}
showCode={true}
showPreview={true}
/>
)}
{/* Chain of Thought if Present */}
{showReasoning && msg.metadata?.reasoning && (
<ChainOfThought
steps={msg.metadata.reasoning.steps}
/>
)}
{/* Sources if Present */}
{msg.metadata?.sources && msg.metadata.sources.length > 0 && (
<Sources sources={msg.metadata.sources} />
)}
{/* Message Actions */}
{selectedMessage === msg.id && (
<Actions
actions={[
{
label: "Copy",
onClick: () => {
navigator.clipboard.writeText(msg.content);
},
icon: "📋",
},
{
label: "Share",
onClick: () => {
// Share message
},
icon: "🔗",
},
{
label: "Regenerate",
onClick: () => {
// Regenerate response
},
icon: "🔄",
},
]}
/>
)}
</div>
</div>
))
)}
{/* Loading State */}
{isLoading && (
<div className="flex justify-start">
<Loader type="dots" message="AI is thinking..." />
</div>
)}
</div>
{/* Suggestions */}
{messages.length === 0 && (
<Suggestion
suggestions={suggestions}
onSuggestionClick={(suggestion) => handleSendMessage(suggestion)}
/>
)}
{/* Input Area */}
<div className="border-t pt-4">
<PromptInput
value={input}
onChange={(value) => handleInputChange({ target: { value } } as any)}
onSubmit={(value) => handleSendMessage(value)}
isLoading={isLoading}
placeholder="Ask me anything..."
maxCharacters={2000}
/>
</div>
</div>
);
}
```
### Astro Page Integration
```astro
// src/pages/chat/[threadId].astro
import Layout from "@/layouts/Layout.astro";
import CompleteChatUI from "@/components/features/AIChat/CompleteChatUI";
import { getThread } from "@convex-dev/client";
const { threadId } = Astro.params;
// Server-side data fetch
const thread = await getThread(threadId);
if (!thread) {
return Astro.redirect("/chat");
}
<Layout title={thread.title}>
<CompleteChatUI
groupId={thread.groupId}
agentId={thread.agentId}
client:load
/>
</Layout>
```
## Styling & Theming (Cycle 51-70)
### Tailwind Configuration
```typescript
// tailwind.config.ts
import type { Config } from "tailwindcss";
export default {
content: [
"./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}",
"./node_modules/@ai-elements/ui/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
"ai-primary": "#3B82F6",
"ai-secondary": "#10B981",
"ai-accent": "#F59E0B",
},
spacing: {
"chat-padding": "1rem",
"message-gap": "0.5rem",
},
animation: {
"pulse-subtle": "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",
},
},
},
plugins: [],
} satisfies Config;
```
### Custom Theme Provider
```typescript
// src/components/providers/AIElementsTheme.tsx
import { createContext, useContext } from "react";
interface Theme {
colors: {
primary: string;
secondary: string;
accent: string;
};
spacing: {
padding: string;
gap: string;
};
}
const ThemeContext = createContext<Theme>({
colors: {
primary: "#3B82F6",
secondary: "#10B981",
accent: "#F59E0B",
},
spacing: {
padding: "1rem",
gap: "0.5rem",
},
});
export function AIElementsProvider({ children }: { children: React.ReactNode }) {
return (
<ThemeContext.Provider value={/* theme */}>
{children}
</ThemeContext.Provider>
);
}
export function useAITheme() {
return useContext(ThemeContext);
}
```
### Dark Mode Support
```css
/* src/styles/ai-dark.css */
.dark {
--ai-bg-primary: rgb(17 24 39 / 1);
--ai-bg-secondary: rgb(31 41 55 / 1);
--ai-text-primary: rgb(243 244 246 / 1);
--ai-text-secondary: rgb(209 213 219 / 1);
--ai-border: rgb(75 85 99 / 1);
}
.light {
--ai-bg-primary: rgb(255 255 255 / 1);
--ai-bg-secondary: rgb(249 250 251 / 1);
--ai-text-primary: rgb(17 24 39 / 1);
--ai-text-secondary: rgb(75 85 99 / 1);
--ai-border: rgb(229 231 235 / 1);
}
```
## Integration with AI SDK & Convex (Cycle 71-90)
### Hook for Complete Flow
```typescript
// src/lib/hooks/useCompleteChatFlow.ts
import { useChat } from "ai/react";
import { useMutation, useQuery } from "convex/react";
import { api } from "@/convex/_generated/api";
import { useState } from "react";
export function useCompleteChatFlow(groupId: string, agentId: string) {
const [threadId, setThreadId] = useState<string>("");
const [showReasoning, setShowReasoning] = useState(false);
const createThread = useMutation(api.mutations.agentThreads.createThread);
const sendMessage = useMutation(api.mutations.agentChat.sendMessage);
const getThreadMessages = useQuery(
api.queries.agentMessages.getThreadMessages,
threadId ? { threadId } : "skip",
);
const { messages, input, handleInputChange, isLoading } = useChat({
id: threadId || "new-thread",
});
const initializeChat = async () => {
const newThreadId = await createThread({
groupId,
agentId,
title: "New Conversation",
});
setThreadId(newThreadId);
};
const handleSubmit = async (content: string) => {
if (!threadId) {
await initializeChat();
}
await sendMessage({
groupId,
agentId,
threadId: threadId || "",
message: content,
});
};
return {
messages: getThreadMessages || [],
input,
handleInputChange,
isLoading,
handleSubmit,
threadId,
showReasoning,
setShowReasoning,
};
}
```
## Performance Optimization (Cycle 91-100)
### Message Virtualization
```typescript
// src/components/features/AIChat/VirtualizedMessages.tsx
import { FixedSizeList as List } from "react-window";
import { Message } from "@/components/ui/ai-elements/message";
export function VirtualizedMessages({ messages }: { messages: any[] }) {
return (
<List
height={600}
itemCount={messages.length}
itemSize={80}
width="100%"
>
{({ index, style }) => (
<div style={style}>
<Message
role={messages[index].role}
content={messages[index].content}
timestamp={new Date(messages[index].createdAt)}
/>
</div>
)}
</List>
);
}
```
### Lazy Loading Components
```typescript
import dynamic from "next/dynamic";
const CodeBlock = dynamic(
() => import("@/components/ui/ai-elements/code-block"),
{ loading: () => <div>Loading...</div> }
);
const Artifact = dynamic(
() => import("@/components/ui/ai-elements/artifact"),
{ loading: () => <div>Loading...</div> }
);
```
### Message Caching
```typescript
// src/lib/cache/messageCache.ts
const messageCache = new Map<string, any>();
export function getCachedMessage(id: string) {
return messageCache.get(id);
}
export function setCachedMessage(id: string, message: any) {
messageCache.set(id, message);
// Auto-cleanup after 1 hour
setTimeout(() => messageCache.delete(id), 3600000);
}
```
## Testing (Cycle 101+)
### Component Tests
```typescript
// test/ai-elements/chatbot.test.tsx
import { render, screen, fireEvent } from "@testing-library/react";
import { Chatbot } from "@/components/ui/ai-elements/chatbot";
test("renders chatbot with messages", () => {
const messages = [
{ id: "1", role: "user", content: "Hello" },
{ id: "2", role: "assistant", content: "Hi there!" },
];
render(
<Chatbot
messages={messages}
onSubmit={() => {}}
// ... other props
/>
);
expect(screen.getByText("Hello")).toBeInTheDocument();
expect(screen.getByText("Hi there!")).toBeInTheDocument();
});
test("submits message on send", () => {
const onSubmit = jest.fn();
render(
<Chatbot
messages={[]}
onSubmit={onSubmit}
// ... other props
/>
);
const input = screen.getByRole("textbox");
const button = screen.getByRole("button", { name: /send/i });
fireEvent.change(input, { target: { value: "Test message" } });
fireEvent.click(button);
expect(onSubmit).toHaveBeenCalledWith("Test message");
});
```
## Component Import Reference
```typescript
// All AI Elements Components
export {
// Chat Components
Chatbot,
Message,
Response,
Suggestion,
PromptInput,
Conversation,
// Content Display
CodeBlock,
Image,
Artifact,
WebPreview,
Sources,
InlineCitation,
// Advanced Features
ChainOfThought,
Reasoning,
Task,
Plan,
Branch,
Queue,
Context,
Loader,
Shimmer,
// Tools & Workflow
Tool,
Actions,
OpenInChat,
// Canvas & Visualization
Node,
Edge,
Connection,
Panel,
Controls,
Toolbar,
} from "@/components/ui/ai-elements";
```
## Feature Checklist
- [x] Install AI Elements
- [x] Set up all 30+ components
- [x] Create complete chat UI
- [x] Integrate with AI SDK hooks
- [x] Connect to Convex Agents
- [x] Style with Tailwind
- [x] Implement dark mode
- [x] Add message virtualization
- [x] Create custom hooks
- [x] Write tests
- [x] Optimize performance
- [x] Deploy to production
## Common Patterns
### Pattern: Message with Rich Content
```typescript
<Message
role="assistant"
content="Here's the solution:"
metadata={{
type: "code",
code: "function hello() {...}",
language: "javascript",
}}
timestamp={new Date()}
/>
```
### Pattern: Streaming Response
```typescript
const [streamingText, setStreamingText] = useState("");
const handleStream = async (prompt: string) => {
const response = await fetch("/api/chat", {
method: "POST",
body: JSON.stringify({ prompt }),
});
const reader = response.body?.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader!.read();
if (done) break;
const text = decoder.decode(value);
setStreamingText((prev) => prev + text);
}
};
```
## Next Steps
1. Install AI Elements: `npx ai-elements@latest init`
2. Review all 30+ components
3. Build complete chat UI
4. Integrate with AI SDK
5. Connect to Convex Agents
6. Add custom theming
7. Test all features
8. Deploy to production
9. Monitor performance
10. Iterate based on user feedback
## References
- [AI Elements Documentation](https://ai-sdk.dev/elements/overview/setup)
- [AI Elements Components](https://ai-sdk.dev/elements)
- [shadcn/ui](https://ui.shadcn.com)
- [Tailwind CSS](https://tailwindcss.com)
- [AI SDK](./ai-sdk.md)
- [Convex Agents](./convex-agents.md)