ai-schadcn-chat 0.1.0
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/LICENSE +21 -0
- package/README.md +307 -0
- package/dist/ChatPanel-Cyq7boWQ.js +3468 -0
- package/dist/ChatPanel-Cyq7boWQ.js.map +1 -0
- package/dist/ChatPanel-D3VL5Vdq.cjs +10 -0
- package/dist/ChatPanel-D3VL5Vdq.cjs.map +1 -0
- package/dist/ChatProvider-DcrNbVMh.cjs +2 -0
- package/dist/ChatProvider-DcrNbVMh.cjs.map +1 -0
- package/dist/ChatProvider-DoD4jj4M.js +128 -0
- package/dist/ChatProvider-DoD4jj4M.js.map +1 -0
- package/dist/chat-engine-BaFdimfx.cjs +8 -0
- package/dist/chat-engine-BaFdimfx.cjs.map +1 -0
- package/dist/chat-engine-Cja0KtWE.js +520 -0
- package/dist/chat-engine-Cja0KtWE.js.map +1 -0
- package/dist/components/chat/AgentManager.d.ts +11 -0
- package/dist/components/chat/AgentManager.d.ts.map +1 -0
- package/dist/components/chat/AgentManager.js +110 -0
- package/dist/components/chat/Attachment.d.ts +34 -0
- package/dist/components/chat/Attachment.d.ts.map +1 -0
- package/dist/components/chat/Attachment.js +59 -0
- package/dist/components/chat/AttachmentPreview.d.ts +8 -0
- package/dist/components/chat/AttachmentPreview.d.ts.map +1 -0
- package/dist/components/chat/AttachmentPreview.js +43 -0
- package/dist/components/chat/ChatComposer.d.ts +11 -0
- package/dist/components/chat/ChatComposer.d.ts.map +1 -0
- package/dist/components/chat/ChatComposer.js +10 -0
- package/dist/components/chat/ChatHeader.d.ts +5 -0
- package/dist/components/chat/ChatHeader.d.ts.map +1 -0
- package/dist/components/chat/ChatHeader.js +132 -0
- package/dist/components/chat/ChatPanel.d.ts +36 -0
- package/dist/components/chat/ChatPanel.d.ts.map +1 -0
- package/dist/components/chat/ChatPanel.js +55 -0
- package/dist/components/chat/ChatProvider.d.ts +58 -0
- package/dist/components/chat/ChatProvider.d.ts.map +1 -0
- package/dist/components/chat/ChatProvider.js +145 -0
- package/dist/components/chat/Chatbubble.d.ts +30 -0
- package/dist/components/chat/Chatbubble.d.ts.map +1 -0
- package/dist/components/chat/Chatbubble.js +50 -0
- package/dist/components/chat/Markdown.d.ts +35 -0
- package/dist/components/chat/Markdown.d.ts.map +1 -0
- package/dist/components/chat/Markdown.js +130 -0
- package/dist/components/chat/Message.d.ts +22 -0
- package/dist/components/chat/Message.d.ts.map +1 -0
- package/dist/components/chat/Message.js +21 -0
- package/dist/components/chat/MessageInput.d.ts +24 -0
- package/dist/components/chat/MessageInput.d.ts.map +1 -0
- package/dist/components/chat/MessageInput.js +255 -0
- package/dist/components/chat/MessageList.d.ts +9 -0
- package/dist/components/chat/MessageList.d.ts.map +1 -0
- package/dist/components/chat/MessageList.js +249 -0
- package/dist/components/chat/MessageMarker.d.ts +25 -0
- package/dist/components/chat/MessageMarker.d.ts.map +1 -0
- package/dist/components/chat/MessageMarker.js +31 -0
- package/dist/components/chat/MessageScroller.d.ts +12 -0
- package/dist/components/chat/MessageScroller.d.ts.map +1 -0
- package/dist/components/chat/MessageScroller.js +48 -0
- package/dist/components/chat/MessageScrollerPrimitives.d.ts +76 -0
- package/dist/components/chat/MessageScrollerPrimitives.d.ts.map +1 -0
- package/dist/components/chat/MessageScrollerPrimitives.js +438 -0
- package/dist/components/chat/ProviderManager.d.ts +10 -0
- package/dist/components/chat/ProviderManager.d.ts.map +1 -0
- package/dist/components/chat/ProviderManager.js +110 -0
- package/dist/components/chat/ReasoningPanel.d.ts +15 -0
- package/dist/components/chat/ReasoningPanel.d.ts.map +1 -0
- package/dist/components/chat/ReasoningPanel.js +40 -0
- package/dist/components/chat/ThemeToggle.d.ts +4 -0
- package/dist/components/chat/ThemeToggle.d.ts.map +1 -0
- package/dist/components/chat/ThemeToggle.js +59 -0
- package/dist/components/index.d.ts +44 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +49 -0
- package/dist/components/ui/avatar.d.ts +11 -0
- package/dist/components/ui/avatar.d.ts.map +1 -0
- package/dist/components/ui/avatar.js +33 -0
- package/dist/components/ui/badge.d.ts +10 -0
- package/dist/components/ui/badge.d.ts.map +1 -0
- package/dist/components/ui/badge.js +19 -0
- package/dist/components/ui/button.d.ts +12 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +34 -0
- package/dist/components/ui/card.d.ts +8 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/card.js +15 -0
- package/dist/components/ui/checkbox.d.ts +5 -0
- package/dist/components/ui/checkbox.d.ts.map +1 -0
- package/dist/components/ui/checkbox.js +8 -0
- package/dist/components/ui/collapsible.d.ts +6 -0
- package/dist/components/ui/collapsible.d.ts.map +1 -0
- package/dist/components/ui/collapsible.js +5 -0
- package/dist/components/ui/dialog.d.ts +24 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/dialog.js +30 -0
- package/dist/components/ui/dropdown-menu.d.ts +17 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/components/ui/dropdown-menu.js +20 -0
- package/dist/components/ui/input.d.ts +4 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/input.js +7 -0
- package/dist/components/ui/label.d.ts +6 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/label.js +10 -0
- package/dist/components/ui/popover.d.ts +6 -0
- package/dist/components/ui/popover.d.ts.map +1 -0
- package/dist/components/ui/popover.js +9 -0
- package/dist/components/ui/scroll-area.d.ts +3 -0
- package/dist/components/ui/scroll-area.d.ts.map +1 -0
- package/dist/components/ui/scroll-area.js +8 -0
- package/dist/components/ui/select.d.ts +14 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/select.js +26 -0
- package/dist/components/ui/separator.d.ts +3 -0
- package/dist/components/ui/separator.d.ts.map +1 -0
- package/dist/components/ui/separator.js +6 -0
- package/dist/components/ui/switch.d.ts +3 -0
- package/dist/components/ui/switch.d.ts.map +1 -0
- package/dist/components/ui/switch.js +6 -0
- package/dist/components/ui/tabs.d.ts +6 -0
- package/dist/components/ui/tabs.d.ts.map +1 -0
- package/dist/components/ui/tabs.js +11 -0
- package/dist/components/ui/tooltip.d.ts +6 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/components/ui/tooltip.js +9 -0
- package/dist/components.cjs +2 -0
- package/dist/components.cjs.map +1 -0
- package/dist/components.js +129 -0
- package/dist/components.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/useChat.d.ts +6 -0
- package/dist/hooks/useChat.d.ts.map +1 -0
- package/dist/hooks/useChat.js +5 -0
- package/dist/hooks.cjs +2 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.js +8 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index-Ci4qkGOp.cjs +20 -0
- package/dist/index-Ci4qkGOp.cjs.map +1 -0
- package/dist/index-NhYr-cEJ.js +567 -0
- package/dist/index-NhYr-cEJ.js.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/agents.d.ts +29 -0
- package/dist/lib/agents.d.ts.map +1 -0
- package/dist/lib/agents.js +145 -0
- package/dist/lib/attachments.d.ts +40 -0
- package/dist/lib/attachments.d.ts.map +1 -0
- package/dist/lib/attachments.js +152 -0
- package/dist/lib/chat-engine.d.ts +109 -0
- package/dist/lib/chat-engine.d.ts.map +1 -0
- package/dist/lib/chat-engine.js +505 -0
- package/dist/lib/index.d.ts +8 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +7 -0
- package/dist/lib/persistence.d.ts +30 -0
- package/dist/lib/persistence.d.ts.map +1 -0
- package/dist/lib/persistence.js +104 -0
- package/dist/lib/providers.d.ts +40 -0
- package/dist/lib/providers.d.ts.map +1 -0
- package/dist/lib/providers.js +0 -0
- package/dist/lib/tw-merge.d.ts +9 -0
- package/dist/lib/tw-merge.d.ts.map +1 -0
- package/dist/lib/tw-merge.js +8 -0
- package/dist/lib/utils.d.ts +69 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +166 -0
- package/dist/lib/voice.d.ts +57 -0
- package/dist/lib/voice.d.ts.map +1 -0
- package/dist/lib/voice.js +103 -0
- package/dist/lib.cjs +2 -0
- package/dist/lib.cjs.map +1 -0
- package/dist/lib.js +59 -0
- package/dist/lib.js.map +1 -0
- package/dist/marker.css +68 -0
- package/dist/package.json +6 -0
- package/dist/presets-BxnbImSM.cjs +2 -0
- package/dist/presets-BxnbImSM.cjs.map +1 -0
- package/dist/presets-D8VQTD8n.js +193 -0
- package/dist/presets-D8VQTD8n.js.map +1 -0
- package/dist/providers/anthropic.d.ts +30 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +251 -0
- package/dist/providers/base.d.ts +55 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +272 -0
- package/dist/providers/index.d.ts +15 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +24 -0
- package/dist/providers/openai.d.ts +31 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +192 -0
- package/dist/providers-BuaGy2tX.cjs +4 -0
- package/dist/providers-BuaGy2tX.cjs.map +1 -0
- package/dist/providers-kp-avTNl.js +324 -0
- package/dist/providers-kp-avTNl.js.map +1 -0
- package/dist/providers.cjs +2 -0
- package/dist/providers.cjs.map +1 -0
- package/dist/providers.js +14 -0
- package/dist/providers.js.map +1 -0
- package/dist/scroller.css +278 -0
- package/dist/style.css +1 -0
- package/dist/types/chat.d.ts +342 -0
- package/dist/types/chat.d.ts.map +1 -0
- package/dist/types/chat.js +4 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +14 -0
- package/dist/types/presets.d.ts +25 -0
- package/dist/types/presets.d.ts.map +1 -0
- package/dist/types/presets.js +207 -0
- package/dist/types.cjs +2 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/typeset-presets.css +56 -0
- package/dist/typeset.css +505 -0
- package/package.json +158 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eduardo Inerarte (eddremonts86)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# ai-schadcn-chat
|
|
2
|
+
|
|
3
|
+
> A fully-featured, deeply configurable AI chat panel for React 18/19 — works with any Anthropic / OpenAI / OpenAI-compatible API (OpenRouter, MiniMax, Together, Groq, vLLM, Ollama, …).
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/ai-schadcn-chat)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
|
|
9
|
+
## Why ai-schadcn-chat
|
|
10
|
+
|
|
11
|
+
- **Three surfaces, one package** — drop in `<ChatPanel />` for an instant chat UI, compose `<ChatProvider />` + `<MessageList />` + `<ChatComposer />` for a custom layout, or use the framework-agnostic `ChatEngine` class without React at all.
|
|
12
|
+
- **Any provider** — native adapters for Anthropic and OpenAI, plus a generic OpenAI-compatible mode that works with OpenRouter, MiniMax, Together, Groq, vLLM, Ollama `/openai` endpoint, etc.
|
|
13
|
+
- **Built on shadcn/ui + Radix** — looks and feels like the rest of the shadcn ecosystem. Tailwind theming carries over.
|
|
14
|
+
- **Tools / function calling** — register named tools with JSON-Schema parameters and async handlers; the engine dispatches calls and feeds results back to the model.
|
|
15
|
+
- **Streaming, persistence, retries** — incremental SSE streaming, automatic retry with exponential back-off for 429/5xx, opt-in `localStorage` persistence keyed by `persistKey`.
|
|
16
|
+
- **Markdown / MDX / code highlighting** — GFM tables, raw HTML, syntax-highlighted code with one-click copy and collapse, all rendered through `react-markdown` + `remark-gfm` + `rehype-highlight` + `rehype-raw`.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add ai-schadcn-chat
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Peer deps: `react` ^18.3.0 || ^19.0.0, `react-dom` ^18.3.0 || ^19.0.0.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# if your bundler doesn't auto-install peers
|
|
28
|
+
pnpm add react react-dom
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quick start
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
import { ChatPanel, defaultConfig } from "ai-schadcn-chat";
|
|
35
|
+
// Import the bundled stylesheet once in your app root.
|
|
36
|
+
import "ai-schadcn-chat/styles.css";
|
|
37
|
+
|
|
38
|
+
export function App() {
|
|
39
|
+
// defaultConfig() reads VITE_MINIMAX_API_KEY (or MINIMAX_API_KEY) from
|
|
40
|
+
// both process.env and import.meta.env automatically.
|
|
41
|
+
const config = defaultConfig({
|
|
42
|
+
systemPrompt: "You are a concise coding assistant.",
|
|
43
|
+
ui: { title: "Edd's coding buddy", placeholder: "Ask me anything…" },
|
|
44
|
+
});
|
|
45
|
+
return <ChatPanel config={config} />;
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Connect to MiniMax
|
|
50
|
+
|
|
51
|
+
`defaultConfig()` is pre-wired for [MiniMax](https://MiniMax.ai) via the OpenAI-compatible protocol. It reads these env vars at runtime from both `process.env` and `import.meta.env`:
|
|
52
|
+
|
|
53
|
+
| Variable | Default | Purpose |
|
|
54
|
+
| ------------------- | ----------------------------- | -------------------------------------- |
|
|
55
|
+
| `MINIMAX_API_KEY` | _(required)_ | Bearer token sent on every request. |
|
|
56
|
+
| `MINIMAX_BASE_URL` | `https://api.MiniMax.chat/v1` | Override to use a proxy or gateway. |
|
|
57
|
+
| `MINIMAX_MODEL` | `MiniMax-M2` | Default model id surfaced in the UI. |
|
|
58
|
+
|
|
59
|
+
Set them in a `.env` / `.env.local` file:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# .env.local
|
|
63
|
+
VITE_MINIMAX_API_KEY=sk-…
|
|
64
|
+
VITE_MINIMAX_BASE_URL=https://api.MiniMax.chat/v1
|
|
65
|
+
VITE_MINIMAX_MODEL=MiniMax-M2
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
In Next.js / non-Vite environments, drop the `VITE_` prefix (or expose them through your bundler of choice). The engine checks `process.env` first, then `import.meta.env`, so both runtimes work.
|
|
69
|
+
|
|
70
|
+
## Connect to OpenAI / Anthropic
|
|
71
|
+
|
|
72
|
+
Swap the `provider.kind` and supply your own API key:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { ChatPanel, defaultConfig } from "ai-schadcn-chat";
|
|
76
|
+
|
|
77
|
+
// OpenAI
|
|
78
|
+
const openai = defaultConfig({
|
|
79
|
+
provider: {
|
|
80
|
+
kind: "openai",
|
|
81
|
+
baseUrl: "https://api.openai.com/v1",
|
|
82
|
+
authHeader: "bearer",
|
|
83
|
+
credentials: { apiKey: import.meta.env.VITE_OPENAI_API_KEY },
|
|
84
|
+
chatPath: "/chat/completions",
|
|
85
|
+
},
|
|
86
|
+
model: { id: "gpt-4o", label: "GPT-4o", tools: true, vision: true, contextWindow: 128_000 },
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Anthropic (Claude)
|
|
90
|
+
const claude = defaultConfig({
|
|
91
|
+
provider: {
|
|
92
|
+
kind: "anthropic",
|
|
93
|
+
baseUrl: "https://api.anthropic.com",
|
|
94
|
+
authHeader: "x-api-key",
|
|
95
|
+
credentials: {
|
|
96
|
+
apiKey: import.meta.env.VITE_ANTHROPIC_API_KEY,
|
|
97
|
+
secondaryKey: "2023-06-15", // sent as anthropic-version
|
|
98
|
+
secondaryKeyHeader: "anthropic-version",
|
|
99
|
+
},
|
|
100
|
+
chatPath: "/v1/messages",
|
|
101
|
+
},
|
|
102
|
+
model: { id: "claude-sonnet-4-5", label: "Claude Sonnet 4.5", tools: true, vision: true, contextWindow: 200_000 },
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Any OpenAI-compatible gateway (OpenRouter, Together, Groq, vLLM, Ollama `/openai`, …) just needs `kind: "openai-compatible"` plus the right `baseUrl`.
|
|
107
|
+
|
|
108
|
+
## Configuration
|
|
109
|
+
|
|
110
|
+
The full `ChatConfig` shape:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import type { ChatConfig } from "ai-schadcn-chat";
|
|
114
|
+
|
|
115
|
+
const config: ChatConfig = {
|
|
116
|
+
provider: { /* see "Connect to …" above */ },
|
|
117
|
+
model: { id: "MiniMax-M2", tools: true, vision: false, contextWindow: 128_000, maxOutput: 8_192 },
|
|
118
|
+
|
|
119
|
+
systemPrompt: "You are a helpful assistant.", // master system prompt
|
|
120
|
+
documents: [/* optional PromptDocument[] — extra context */],
|
|
121
|
+
|
|
122
|
+
personality: { name: "Edd's coding buddy", tone: "concise", locale: "en" },
|
|
123
|
+
|
|
124
|
+
maxContextTokens: 120_000, // sliding window over older messages
|
|
125
|
+
temperature: 0.7,
|
|
126
|
+
topP: 1,
|
|
127
|
+
thinking: { enabled: true, budgetTokens: 4_000 }, // anthropic extended thinking
|
|
128
|
+
stopSequences: ["\n\nUSER:"],
|
|
129
|
+
|
|
130
|
+
retry: { attempts: 3, initialDelayMs: 800, maxDelayMs: 8_000 },
|
|
131
|
+
persistKey: "ai-schadcn-chat:default", // or `false` to disable persistence
|
|
132
|
+
|
|
133
|
+
ui: { /* see below */ },
|
|
134
|
+
tools: [/* see "Tools / function calling" below */],
|
|
135
|
+
|
|
136
|
+
onResponse: (msg, ctx) => console.log("got", msg, ctx.conversationId),
|
|
137
|
+
onError: (err, ctx) => console.error(err, ctx.conversationId),
|
|
138
|
+
};
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## UI overrides
|
|
142
|
+
|
|
143
|
+
Every key is optional; sensible defaults ship.
|
|
144
|
+
|
|
145
|
+
| Key | Type | Default |
|
|
146
|
+
| ---------------------------- | ------------------------------------- | -------------------- |
|
|
147
|
+
| `title` | `string` | `"Chat"` |
|
|
148
|
+
| `subtitle` | `string` | — |
|
|
149
|
+
| `placeholder` | `string` | `"Ask anything…"` |
|
|
150
|
+
| `emptyState` | `ReactNode` | — |
|
|
151
|
+
| `showModelSelector` | `boolean` | `true` |
|
|
152
|
+
| `showDocumentPicker` | `boolean` | `true` |
|
|
153
|
+
| `showToolCalls` | `boolean` | `true` |
|
|
154
|
+
| `showTokenCount` | `boolean` | `true` |
|
|
155
|
+
| `showTimestamps` | `boolean` | `true` |
|
|
156
|
+
| `enableFileUpload` | `boolean` | `true` |
|
|
157
|
+
| `enableVoiceInput` | `boolean` | `false` |
|
|
158
|
+
| `enableMarkdown` | `boolean` | `true` |
|
|
159
|
+
| `enableMdx` | `boolean` | `true` |
|
|
160
|
+
| `enableCodeHighlight` | `boolean` | `true` |
|
|
161
|
+
| `enableCopyButtons` | `boolean` | `true` |
|
|
162
|
+
| `enableMessageActions` | `boolean` | `true` |
|
|
163
|
+
| `enableConversationHistory` | `boolean` | `true` |
|
|
164
|
+
| `enableRegenerate` | `boolean` | `true` |
|
|
165
|
+
| `enableEdit` | `boolean` | `true` |
|
|
166
|
+
| `maxFileSizeMb` | `number` | `10` |
|
|
167
|
+
| `acceptedFileTypes` | `string[]` | images + pdf + text |
|
|
168
|
+
| `theme` | `"light" \| "dark" \| "system"` | `"system"` |
|
|
169
|
+
| `accentColor` | `string` (CSS color) | — |
|
|
170
|
+
| `fontFamily` | `string` (CSS font-family) | — |
|
|
171
|
+
| `density` | `"compact" \| "comfortable" \| "spacious"` | `"comfortable"` |
|
|
172
|
+
| `layout` | `"panel" \| "floating" \| "fullpage"` | `"panel"` |
|
|
173
|
+
| `height` / `width` | `number \| string` | — |
|
|
174
|
+
| `position` | `"bottom-right"` \| `"bottom-left"` \| `"top-right"` \| `"top-left"` | `"bottom-right"` |
|
|
175
|
+
| `className` | `string` | — |
|
|
176
|
+
| `renderMessage` | `(msg: ChatMessage) => ReactNode` | — |
|
|
177
|
+
| `renderHeader` | `() => ReactNode` | — |
|
|
178
|
+
| `renderFooter` | `() => ReactNode` | — |
|
|
179
|
+
|
|
180
|
+
## Tools / function calling
|
|
181
|
+
|
|
182
|
+
Register named tools with a JSON-Schema for `parameters` and an async `handler`. The engine dispatches tool calls made by the model and feeds the result back as a `tool` message.
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
import { defaultConfig } from "ai-schadcn-chat";
|
|
186
|
+
|
|
187
|
+
const config = defaultConfig({
|
|
188
|
+
tools: [
|
|
189
|
+
{
|
|
190
|
+
name: "get_weather",
|
|
191
|
+
description: "Return the current weather for a city.",
|
|
192
|
+
parameters: {
|
|
193
|
+
type: "object",
|
|
194
|
+
properties: {
|
|
195
|
+
city: { type: "string", description: "City name, e.g. 'Berlin'." },
|
|
196
|
+
unit: { type: "string", enum: ["celsius", "fahrenheit"], default: "celsius" },
|
|
197
|
+
},
|
|
198
|
+
required: ["city"],
|
|
199
|
+
},
|
|
200
|
+
handler: async ({ city, unit }) => {
|
|
201
|
+
const res = await fetch(`https://wttr.in/${city}?format=j1`);
|
|
202
|
+
const data = await res.json();
|
|
203
|
+
return { city, unit, temp: data.current_condition?.[0]?.temp_C };
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Customization
|
|
211
|
+
|
|
212
|
+
`ChatPanel` and the underlying `ChatComposer` accept render overrides:
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
<ChatPanel
|
|
216
|
+
config={config}
|
|
217
|
+
renderHeader={() => <MyBranding />}
|
|
218
|
+
renderFooter={() => <SafetyNotice />}
|
|
219
|
+
renderSendButton={({ disabled, onClick }) => (
|
|
220
|
+
<button onClick={onClick} disabled={disabled}>Send ➤</button>
|
|
221
|
+
)}
|
|
222
|
+
/>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
For a fully bespoke message renderer, use `renderMessage` (per `UiConfig`):
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
<ChatPanel
|
|
229
|
+
config={{
|
|
230
|
+
...config,
|
|
231
|
+
ui: {
|
|
232
|
+
renderMessage: (msg) => (
|
|
233
|
+
msg.role === "assistant"
|
|
234
|
+
? <MyCustomBubble content={msg.content} />
|
|
235
|
+
: <UserBubble content={msg.content} />
|
|
236
|
+
),
|
|
237
|
+
},
|
|
238
|
+
}}
|
|
239
|
+
/>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
To compose your own layout without `ChatPanel`:
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
import { ChatProvider, ChatHeader, MessageList, ChatComposer, useChat } from "ai-schadcn-chat";
|
|
246
|
+
|
|
247
|
+
<ChatProvider config={config}>
|
|
248
|
+
<MyCustomHeader />
|
|
249
|
+
<MessageList />
|
|
250
|
+
<ChatComposer renderSendButton={MySendButton} />
|
|
251
|
+
</ChatProvider>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Custom markdown / MDX components
|
|
255
|
+
|
|
256
|
+
The underlying `<Markdown />` component accepts a `components` prop that maps to `react-markdown`'s `Components` type (so you can override `a`, `pre`, `code`, `h1`, …). It is **not yet exposed through `ChatPanel`'s public surface** — today you can either:
|
|
257
|
+
|
|
258
|
+
1. Subclass `<ChatPanel />` by composing your own `<MessageList />` and rendering `<Markdown components={…} />` manually.
|
|
259
|
+
2. Open an issue / PR and we'll lift it into `UiConfig.renderMessage`'s signature as a first-class prop.
|
|
260
|
+
|
|
261
|
+
This is on the roadmap for the next minor release.
|
|
262
|
+
|
|
263
|
+
## Persistence
|
|
264
|
+
|
|
265
|
+
Conversations are persisted to `localStorage` automatically when `persistKey` is set (default: `"ai-schadcn-chat:default"`). Pass `persistKey: false` to disable. Switching `persistKey` at runtime switches the storage namespace — handy for multi-user or multi-tenant apps.
|
|
266
|
+
|
|
267
|
+
## Demo
|
|
268
|
+
|
|
269
|
+
The repo ships with a Vite-powered demo under `demo/`:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
pnpm install
|
|
273
|
+
pnpm demo # starts the demo on http://localhost:5173
|
|
274
|
+
# or
|
|
275
|
+
pnpm install && pnpm dev
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Create `demo/.env` with your real key before launching:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# demo/.env
|
|
282
|
+
VITE_MINIMAX_API_KEY=sk-…
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
`demo/.env` is git-ignored.
|
|
286
|
+
|
|
287
|
+
## Build
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
pnpm build # tsc → vite build → scripts/postbuild.mjs
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Output goes to `dist/`:
|
|
294
|
+
|
|
295
|
+
- `dist/index.js` / `dist/index.cjs` — main entry
|
|
296
|
+
- `dist/components/` — `ChatPanel`, `MessageList`, `ChatComposer`, UI primitives
|
|
297
|
+
- `dist/hooks/` — `ChatProvider`, `useChat`, `useOptionalChat`, `defaultConfig`
|
|
298
|
+
- `dist/providers/` — Anthropic, OpenAI, OpenAI-compatible adapters
|
|
299
|
+
- `dist/lib/` — `ChatEngine` + helpers
|
|
300
|
+
- `dist/types/` — pure types (framework-agnostic)
|
|
301
|
+
- `dist/styles.css` — bundled Tailwind output
|
|
302
|
+
|
|
303
|
+
`scripts/postbuild.mjs` rewrites `dist/package.json` to set `"type": "module"` and `"sideEffects": ["**/*.css"]` so consumer bundlers treat the CSS side-effect correctly under both ESM and CJS resolution.
|
|
304
|
+
|
|
305
|
+
## License
|
|
306
|
+
|
|
307
|
+
[MIT](./LICENSE) © 2026 Eduardo Inerarte (eddremonts86)
|