@copilotz/chat-ui 0.1.0 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +405 -13
- package/dist/index.cjs +467 -133
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -1
- package/dist/index.d.ts +38 -1
- package/dist/index.js +511 -174
- package/dist/index.js.map +1 -1
- package/dist/styles.css +260 -72
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,38 +1,430 @@
|
|
|
1
1
|
# @copilotz/chat-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**The chat interface your AI agent deserves.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Chat UI libraries give you message bubbles. Your AI agent has tool calls, streaming responses, file uploads, audio recording, persistent threads, and user memories. This gives you everything else.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@copilotz/chat-ui)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
[](https://react.dev/)
|
|
10
|
+
[](./LICENSE)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## The Problem
|
|
15
|
+
|
|
16
|
+
You're building a frontend for your AI agent. You grab a chat UI library. It renders messages. Great.
|
|
17
|
+
|
|
18
|
+
Then you need to show tool calls — the library doesn't support that. Streaming with a thinking indicator — you'll build it yourself. File uploads with previews — more custom code. Audio recording — even more. Thread management with search and archive — at this point you're maintaining your own chat UI.
|
|
19
|
+
|
|
20
|
+
**There's no shadcn for agentic chat. Just parts.**
|
|
21
|
+
|
|
22
|
+
## The Solution
|
|
23
|
+
|
|
24
|
+
`@copilotz/chat-ui` is the complete chat interface for AI agents. Everything you need to ship a production chat experience, in one package:
|
|
25
|
+
|
|
26
|
+
| What You Need | What This Gives You |
|
|
27
|
+
|---------------|---------------------|
|
|
28
|
+
| Messages | Markdown with syntax highlighting, streaming with thinking indicator |
|
|
29
|
+
| Tool Calls | Expandable cards with args, results, status, and execution time |
|
|
30
|
+
| Media | Image/audio/video attachments with native playback controls |
|
|
31
|
+
| Input | File upload (drag & drop), audio recording, attachment previews |
|
|
32
|
+
| Threads | Sidebar with search, archive, date grouping, rename, delete |
|
|
33
|
+
| User Profile | Dynamic fields, memories (CRUD), agent vs user distinction |
|
|
34
|
+
| Customization | 50+ labels (i18n-ready), feature toggles, 4 presets, theming |
|
|
35
|
+
|
|
36
|
+
**One package. Backend-agnostic. Production-ready.**
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
6
41
|
|
|
7
42
|
```bash
|
|
8
43
|
npm install @copilotz/chat-ui
|
|
9
44
|
```
|
|
10
45
|
|
|
11
|
-
|
|
46
|
+
Import the styles once in your app:
|
|
12
47
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
```ts
|
|
48
|
+
```tsx
|
|
16
49
|
import '@copilotz/chat-ui/styles.css';
|
|
17
50
|
```
|
|
18
51
|
|
|
19
|
-
|
|
52
|
+
Drop in the component:
|
|
20
53
|
|
|
21
54
|
```tsx
|
|
22
|
-
import { ChatUI
|
|
55
|
+
import { ChatUI } from '@copilotz/chat-ui';
|
|
56
|
+
|
|
57
|
+
function App() {
|
|
58
|
+
const [messages, setMessages] = useState([]);
|
|
23
59
|
|
|
24
|
-
export function Example() {
|
|
25
60
|
return (
|
|
26
61
|
<ChatUI
|
|
27
|
-
|
|
28
|
-
user={{ id: 'user-1', name: '
|
|
62
|
+
messages={messages}
|
|
63
|
+
user={{ id: 'user-1', name: 'Alex' }}
|
|
29
64
|
assistant={{ name: 'Assistant' }}
|
|
30
65
|
callbacks={{
|
|
31
66
|
onSendMessage: (content, attachments) => {
|
|
32
|
-
|
|
33
|
-
}
|
|
67
|
+
// Handle message — connect to your backend
|
|
68
|
+
},
|
|
34
69
|
}}
|
|
35
70
|
/>
|
|
36
71
|
);
|
|
37
72
|
}
|
|
38
73
|
```
|
|
74
|
+
|
|
75
|
+
That's it. You have a full-featured chat interface.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Features
|
|
80
|
+
|
|
81
|
+
### Messages That Do More
|
|
82
|
+
|
|
83
|
+
Real-time streaming with a thinking indicator while waiting for the first token. Markdown rendering with syntax highlighting. Tool calls displayed as expandable cards showing name, arguments, result, and execution time.
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
const message = {
|
|
87
|
+
id: '1',
|
|
88
|
+
role: 'assistant',
|
|
89
|
+
content: 'Here is the chart you requested.',
|
|
90
|
+
timestamp: Date.now(),
|
|
91
|
+
isStreaming: false,
|
|
92
|
+
toolCalls: [{
|
|
93
|
+
id: 'tc-1',
|
|
94
|
+
name: 'generate_chart',
|
|
95
|
+
arguments: { type: 'bar', data: [1, 2, 3] },
|
|
96
|
+
result: { url: 'https://...' },
|
|
97
|
+
status: 'completed',
|
|
98
|
+
startTime: 1234567890,
|
|
99
|
+
endTime: 1234567891,
|
|
100
|
+
}],
|
|
101
|
+
attachments: [{
|
|
102
|
+
kind: 'image',
|
|
103
|
+
dataUrl: 'data:image/png;base64,...',
|
|
104
|
+
mimeType: 'image/png',
|
|
105
|
+
}],
|
|
106
|
+
};
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Input That Works
|
|
110
|
+
|
|
111
|
+
File uploads with drag & drop. Audio recording with built-in MediaRecorder. Attachment previews with playback controls. Upload progress indicators. Stop generation button during streaming.
|
|
112
|
+
|
|
113
|
+
### Thread Management
|
|
114
|
+
|
|
115
|
+
Sidebar with threads grouped by date (Today, Yesterday, etc.). Search and filter. Archive toggle. Create, rename, and delete with confirmation dialogs. Collapsible icon mode for more screen space.
|
|
116
|
+
|
|
117
|
+
### User Profile
|
|
118
|
+
|
|
119
|
+
Built-in sheet panel with user info, dynamic custom fields (auto-detects icons based on field names), and a memories section. Memories support CRUD operations and distinguish between agent-created and user-created entries.
|
|
120
|
+
|
|
121
|
+
### Agent Selector
|
|
122
|
+
|
|
123
|
+
ChatGPT-style dropdown for switching between multiple agents. Displays agent avatars, names, and descriptions (truncated for long text). Consecutive messages from the same sender are automatically grouped to save screen space.
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
const agents = [
|
|
127
|
+
{ id: 'assistant', name: 'Assistant', description: 'General purpose helper' },
|
|
128
|
+
{ id: 'coder', name: 'Code Expert', description: 'Specialized in programming', avatarUrl: '/coder.png' },
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
<ChatUI
|
|
132
|
+
agentOptions={agents}
|
|
133
|
+
selectedAgentId="assistant"
|
|
134
|
+
onSelectAgent={(agentId) => setSelectedAgent(agentId)}
|
|
135
|
+
// ... other props
|
|
136
|
+
/>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Configuration
|
|
142
|
+
|
|
143
|
+
The configuration system lets you customize everything without touching the component internals.
|
|
144
|
+
|
|
145
|
+
### Presets
|
|
146
|
+
|
|
147
|
+
Start with a preset and override what you need:
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
import { ChatUI, chatConfigPresets } from '@copilotz/chat-ui';
|
|
151
|
+
|
|
152
|
+
// Minimal: no threads, no file upload, compact mode
|
|
153
|
+
<ChatUI config={chatConfigPresets.minimal} />
|
|
154
|
+
|
|
155
|
+
// Full: all features enabled, timestamps, word count
|
|
156
|
+
<ChatUI config={chatConfigPresets.full} />
|
|
157
|
+
|
|
158
|
+
// Developer: tool calls visible, timestamps, file upload
|
|
159
|
+
<ChatUI config={chatConfigPresets.developer} />
|
|
160
|
+
|
|
161
|
+
// Customer Support: threads, file upload, no message editing
|
|
162
|
+
<ChatUI config={chatConfigPresets.customer_support} />
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Custom Configuration
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
<ChatUI
|
|
169
|
+
config={{
|
|
170
|
+
branding: {
|
|
171
|
+
title: 'Acme Assistant',
|
|
172
|
+
subtitle: 'How can I help you today?',
|
|
173
|
+
logo: <AcmeLogo />,
|
|
174
|
+
avatar: <BotIcon />,
|
|
175
|
+
},
|
|
176
|
+
labels: {
|
|
177
|
+
inputPlaceholder: 'Ask me anything...',
|
|
178
|
+
sendButton: 'Send',
|
|
179
|
+
newChat: 'New Conversation',
|
|
180
|
+
thinking: 'Thinking...',
|
|
181
|
+
toolUsed: 'Tool Used',
|
|
182
|
+
// ... 50+ customizable labels for full i18n
|
|
183
|
+
},
|
|
184
|
+
features: {
|
|
185
|
+
enableThreads: true,
|
|
186
|
+
enableFileUpload: true,
|
|
187
|
+
enableAudioRecording: true,
|
|
188
|
+
enableMessageEditing: true,
|
|
189
|
+
enableMessageCopy: true,
|
|
190
|
+
enableRegeneration: true,
|
|
191
|
+
enableToolCallsDisplay: true,
|
|
192
|
+
maxAttachments: 4,
|
|
193
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
194
|
+
},
|
|
195
|
+
ui: {
|
|
196
|
+
theme: 'auto', // 'light' | 'dark' | 'auto'
|
|
197
|
+
showTimestamps: true,
|
|
198
|
+
showAvatars: true,
|
|
199
|
+
compactMode: false,
|
|
200
|
+
},
|
|
201
|
+
}}
|
|
202
|
+
/>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Custom Right Sidebar
|
|
206
|
+
|
|
207
|
+
Add a custom component to the right sidebar (e.g., profile info, settings, context):
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
<ChatUI
|
|
211
|
+
config={{
|
|
212
|
+
customComponent: {
|
|
213
|
+
label: 'Profile',
|
|
214
|
+
icon: <User />,
|
|
215
|
+
component: ({ onClose, isMobile }) => (
|
|
216
|
+
<div className="p-4">
|
|
217
|
+
<h2>User Profile</h2>
|
|
218
|
+
<button onClick={onClose}>Close</button>
|
|
219
|
+
</div>
|
|
220
|
+
),
|
|
221
|
+
},
|
|
222
|
+
}}
|
|
223
|
+
/>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Callbacks
|
|
229
|
+
|
|
230
|
+
All user interactions are handled through callbacks. This keeps the component purely presentational — you control the data.
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
<ChatUI
|
|
234
|
+
callbacks={{
|
|
235
|
+
// Messages
|
|
236
|
+
onSendMessage: (content, attachments, stateCallback) => {},
|
|
237
|
+
onEditMessage: (messageId, newContent, stateCallback) => {},
|
|
238
|
+
onDeleteMessage: (messageId, stateCallback) => {},
|
|
239
|
+
onRegenerateMessage: (messageId, stateCallback) => {},
|
|
240
|
+
onCopyMessage: (messageId, content, stateCallback) => {},
|
|
241
|
+
onStopGeneration: (stateCallback) => {},
|
|
242
|
+
|
|
243
|
+
// Threads
|
|
244
|
+
onCreateThread: (title, stateCallback) => {},
|
|
245
|
+
onSelectThread: (threadId, stateCallback) => {},
|
|
246
|
+
onRenameThread: (threadId, newTitle, stateCallback) => {},
|
|
247
|
+
onDeleteThread: (threadId, stateCallback) => {},
|
|
248
|
+
onArchiveThread: (threadId, stateCallback) => {},
|
|
249
|
+
|
|
250
|
+
// User Menu
|
|
251
|
+
onViewProfile: () => {},
|
|
252
|
+
onOpenSettings: () => {},
|
|
253
|
+
onThemeChange: (theme) => {}, // 'light' | 'dark' | 'system'
|
|
254
|
+
onLogout: () => {},
|
|
255
|
+
}}
|
|
256
|
+
/>
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Props Reference
|
|
262
|
+
|
|
263
|
+
### ChatUI
|
|
264
|
+
|
|
265
|
+
| Prop | Type | Description |
|
|
266
|
+
|------|------|-------------|
|
|
267
|
+
| `messages` | `ChatMessage[]` | Array of messages to display |
|
|
268
|
+
| `threads` | `ChatThread[]` | Array of conversation threads |
|
|
269
|
+
| `currentThreadId` | `string \| null` | Currently selected thread ID |
|
|
270
|
+
| `config` | `ChatConfig` | Configuration object |
|
|
271
|
+
| `callbacks` | `ChatCallbacks` | Event handlers |
|
|
272
|
+
| `isGenerating` | `boolean` | Whether the assistant is generating a response |
|
|
273
|
+
| `user` | `{ id, name?, avatar?, email? }` | Current user info |
|
|
274
|
+
| `assistant` | `{ name?, avatar?, description? }` | Assistant info |
|
|
275
|
+
| `suggestions` | `string[]` | Suggested prompts shown when no messages |
|
|
276
|
+
| `agentOptions` | `AgentOption[]` | Available agents for the selector dropdown |
|
|
277
|
+
| `selectedAgentId` | `string \| null` | Currently selected agent ID |
|
|
278
|
+
| `onSelectAgent` | `(agentId: string) => void` | Called when user selects an agent |
|
|
279
|
+
| `initialInput` | `string` | Pre-fill the input field (e.g., from URL params) |
|
|
280
|
+
| `onInitialInputConsumed` | `() => void` | Called when initial input is modified/sent |
|
|
281
|
+
| `className` | `string` | Additional CSS classes |
|
|
282
|
+
|
|
283
|
+
### ChatMessage
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
interface ChatMessage {
|
|
287
|
+
id: string;
|
|
288
|
+
role: 'user' | 'assistant' | 'system';
|
|
289
|
+
content: string;
|
|
290
|
+
timestamp: number;
|
|
291
|
+
attachments?: MediaAttachment[];
|
|
292
|
+
isStreaming?: boolean;
|
|
293
|
+
isComplete?: boolean;
|
|
294
|
+
isEdited?: boolean;
|
|
295
|
+
toolCalls?: ToolCall[];
|
|
296
|
+
metadata?: Record<string, any>;
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### MediaAttachment
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
type MediaAttachment =
|
|
304
|
+
| { kind: 'image'; dataUrl: string; mimeType: string; fileName?: string }
|
|
305
|
+
| { kind: 'audio'; dataUrl: string; mimeType: string; durationMs?: number }
|
|
306
|
+
| { kind: 'video'; dataUrl: string; mimeType: string; poster?: string };
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### ToolCall
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
interface ToolCall {
|
|
313
|
+
id: string;
|
|
314
|
+
name: string;
|
|
315
|
+
arguments: Record<string, any>;
|
|
316
|
+
result?: any;
|
|
317
|
+
status: 'pending' | 'running' | 'completed' | 'failed';
|
|
318
|
+
startTime?: number;
|
|
319
|
+
endTime?: number;
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### AgentOption
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
interface AgentOption {
|
|
327
|
+
id: string;
|
|
328
|
+
name: string;
|
|
329
|
+
description?: string; // Shown in dropdown (truncated to 2 lines)
|
|
330
|
+
avatarUrl?: string; // Agent avatar image
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## Exports
|
|
337
|
+
|
|
338
|
+
```tsx
|
|
339
|
+
// Components
|
|
340
|
+
export { ChatUI } from './components/chat/ChatUI';
|
|
341
|
+
export { ChatHeader } from './components/chat/ChatHeader';
|
|
342
|
+
export { ChatInput } from './components/chat/ChatInput';
|
|
343
|
+
export { Message } from './components/chat/Message';
|
|
344
|
+
export { Sidebar } from './components/chat/Sidebar';
|
|
345
|
+
export { ThreadManager } from './components/chat/ThreadManager';
|
|
346
|
+
export { UserProfile } from './components/chat/UserProfile';
|
|
347
|
+
export { UserMenu } from './components/chat/UserMenu';
|
|
348
|
+
export { ChatUserContextProvider, useChatUserContext } from './components/chat/UserContext';
|
|
349
|
+
|
|
350
|
+
// Configuration
|
|
351
|
+
export { defaultChatConfig, mergeConfig, chatConfigPresets, validateConfig } from './config/chatConfig';
|
|
352
|
+
export { themeUtils, featureFlags, configUtils } from './config/chatConfig';
|
|
353
|
+
|
|
354
|
+
// Types
|
|
355
|
+
export type { ChatMessage, ChatThread, ChatConfig, ChatCallbacks } from './types/chatTypes';
|
|
356
|
+
export type { MediaAttachment, ToolCall, ChatState, ChatUserContext, MemoryItem } from './types/chatTypes';
|
|
357
|
+
|
|
358
|
+
// Utilities
|
|
359
|
+
export { cn } from './lib/utils';
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## Styling
|
|
365
|
+
|
|
366
|
+
The package ships with compiled CSS that includes all necessary styles. Import it once:
|
|
367
|
+
|
|
368
|
+
```tsx
|
|
369
|
+
import '@copilotz/chat-ui/styles.css';
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Theming
|
|
373
|
+
|
|
374
|
+
The component respects the `dark` class on your document root. Set theme programmatically:
|
|
375
|
+
|
|
376
|
+
```tsx
|
|
377
|
+
import { themeUtils } from '@copilotz/chat-ui';
|
|
378
|
+
|
|
379
|
+
// Apply theme
|
|
380
|
+
themeUtils.applyTheme('dark'); // or 'light' or 'auto'
|
|
381
|
+
|
|
382
|
+
// Get system preference
|
|
383
|
+
const systemTheme = themeUtils.getSystemTheme(); // 'light' | 'dark'
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### CSS Variables
|
|
387
|
+
|
|
388
|
+
Override CSS variables to customize colors (uses Tailwind/shadcn conventions):
|
|
389
|
+
|
|
390
|
+
```css
|
|
391
|
+
:root {
|
|
392
|
+
--background: 0 0% 100%;
|
|
393
|
+
--foreground: 222.2 84% 4.9%;
|
|
394
|
+
--primary: 222.2 47.4% 11.2%;
|
|
395
|
+
--primary-foreground: 210 40% 98%;
|
|
396
|
+
/* ... */
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## Requirements
|
|
403
|
+
|
|
404
|
+
- React 18+
|
|
405
|
+
- Tailwind CSS 4+ (for custom styling, optional)
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## Works With Any Backend
|
|
410
|
+
|
|
411
|
+
This package is purely presentational. It doesn't make API calls or manage state. You provide the data, it renders the UI.
|
|
412
|
+
|
|
413
|
+
Works with:
|
|
414
|
+
- **Copilotz** — use `@copilotz/chat-adapter` for seamless integration
|
|
415
|
+
- **OpenAI** — connect to the Chat Completions API
|
|
416
|
+
- **Anthropic** — connect to Claude
|
|
417
|
+
- **LangChain** — use with any LangChain backend
|
|
418
|
+
- **Custom backends** — any API that returns messages
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## License
|
|
423
|
+
|
|
424
|
+
MIT — see [LICENSE](./LICENSE)
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
<p align="center">
|
|
429
|
+
<strong>Ship your agent's interface, not your UI backlog.</strong>
|
|
430
|
+
</p>
|