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.
Files changed (221) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +307 -0
  3. package/dist/ChatPanel-Cyq7boWQ.js +3468 -0
  4. package/dist/ChatPanel-Cyq7boWQ.js.map +1 -0
  5. package/dist/ChatPanel-D3VL5Vdq.cjs +10 -0
  6. package/dist/ChatPanel-D3VL5Vdq.cjs.map +1 -0
  7. package/dist/ChatProvider-DcrNbVMh.cjs +2 -0
  8. package/dist/ChatProvider-DcrNbVMh.cjs.map +1 -0
  9. package/dist/ChatProvider-DoD4jj4M.js +128 -0
  10. package/dist/ChatProvider-DoD4jj4M.js.map +1 -0
  11. package/dist/chat-engine-BaFdimfx.cjs +8 -0
  12. package/dist/chat-engine-BaFdimfx.cjs.map +1 -0
  13. package/dist/chat-engine-Cja0KtWE.js +520 -0
  14. package/dist/chat-engine-Cja0KtWE.js.map +1 -0
  15. package/dist/components/chat/AgentManager.d.ts +11 -0
  16. package/dist/components/chat/AgentManager.d.ts.map +1 -0
  17. package/dist/components/chat/AgentManager.js +110 -0
  18. package/dist/components/chat/Attachment.d.ts +34 -0
  19. package/dist/components/chat/Attachment.d.ts.map +1 -0
  20. package/dist/components/chat/Attachment.js +59 -0
  21. package/dist/components/chat/AttachmentPreview.d.ts +8 -0
  22. package/dist/components/chat/AttachmentPreview.d.ts.map +1 -0
  23. package/dist/components/chat/AttachmentPreview.js +43 -0
  24. package/dist/components/chat/ChatComposer.d.ts +11 -0
  25. package/dist/components/chat/ChatComposer.d.ts.map +1 -0
  26. package/dist/components/chat/ChatComposer.js +10 -0
  27. package/dist/components/chat/ChatHeader.d.ts +5 -0
  28. package/dist/components/chat/ChatHeader.d.ts.map +1 -0
  29. package/dist/components/chat/ChatHeader.js +132 -0
  30. package/dist/components/chat/ChatPanel.d.ts +36 -0
  31. package/dist/components/chat/ChatPanel.d.ts.map +1 -0
  32. package/dist/components/chat/ChatPanel.js +55 -0
  33. package/dist/components/chat/ChatProvider.d.ts +58 -0
  34. package/dist/components/chat/ChatProvider.d.ts.map +1 -0
  35. package/dist/components/chat/ChatProvider.js +145 -0
  36. package/dist/components/chat/Chatbubble.d.ts +30 -0
  37. package/dist/components/chat/Chatbubble.d.ts.map +1 -0
  38. package/dist/components/chat/Chatbubble.js +50 -0
  39. package/dist/components/chat/Markdown.d.ts +35 -0
  40. package/dist/components/chat/Markdown.d.ts.map +1 -0
  41. package/dist/components/chat/Markdown.js +130 -0
  42. package/dist/components/chat/Message.d.ts +22 -0
  43. package/dist/components/chat/Message.d.ts.map +1 -0
  44. package/dist/components/chat/Message.js +21 -0
  45. package/dist/components/chat/MessageInput.d.ts +24 -0
  46. package/dist/components/chat/MessageInput.d.ts.map +1 -0
  47. package/dist/components/chat/MessageInput.js +255 -0
  48. package/dist/components/chat/MessageList.d.ts +9 -0
  49. package/dist/components/chat/MessageList.d.ts.map +1 -0
  50. package/dist/components/chat/MessageList.js +249 -0
  51. package/dist/components/chat/MessageMarker.d.ts +25 -0
  52. package/dist/components/chat/MessageMarker.d.ts.map +1 -0
  53. package/dist/components/chat/MessageMarker.js +31 -0
  54. package/dist/components/chat/MessageScroller.d.ts +12 -0
  55. package/dist/components/chat/MessageScroller.d.ts.map +1 -0
  56. package/dist/components/chat/MessageScroller.js +48 -0
  57. package/dist/components/chat/MessageScrollerPrimitives.d.ts +76 -0
  58. package/dist/components/chat/MessageScrollerPrimitives.d.ts.map +1 -0
  59. package/dist/components/chat/MessageScrollerPrimitives.js +438 -0
  60. package/dist/components/chat/ProviderManager.d.ts +10 -0
  61. package/dist/components/chat/ProviderManager.d.ts.map +1 -0
  62. package/dist/components/chat/ProviderManager.js +110 -0
  63. package/dist/components/chat/ReasoningPanel.d.ts +15 -0
  64. package/dist/components/chat/ReasoningPanel.d.ts.map +1 -0
  65. package/dist/components/chat/ReasoningPanel.js +40 -0
  66. package/dist/components/chat/ThemeToggle.d.ts +4 -0
  67. package/dist/components/chat/ThemeToggle.d.ts.map +1 -0
  68. package/dist/components/chat/ThemeToggle.js +59 -0
  69. package/dist/components/index.d.ts +44 -0
  70. package/dist/components/index.d.ts.map +1 -0
  71. package/dist/components/index.js +49 -0
  72. package/dist/components/ui/avatar.d.ts +11 -0
  73. package/dist/components/ui/avatar.d.ts.map +1 -0
  74. package/dist/components/ui/avatar.js +33 -0
  75. package/dist/components/ui/badge.d.ts +10 -0
  76. package/dist/components/ui/badge.d.ts.map +1 -0
  77. package/dist/components/ui/badge.js +19 -0
  78. package/dist/components/ui/button.d.ts +12 -0
  79. package/dist/components/ui/button.d.ts.map +1 -0
  80. package/dist/components/ui/button.js +34 -0
  81. package/dist/components/ui/card.d.ts +8 -0
  82. package/dist/components/ui/card.d.ts.map +1 -0
  83. package/dist/components/ui/card.js +15 -0
  84. package/dist/components/ui/checkbox.d.ts +5 -0
  85. package/dist/components/ui/checkbox.d.ts.map +1 -0
  86. package/dist/components/ui/checkbox.js +8 -0
  87. package/dist/components/ui/collapsible.d.ts +6 -0
  88. package/dist/components/ui/collapsible.d.ts.map +1 -0
  89. package/dist/components/ui/collapsible.js +5 -0
  90. package/dist/components/ui/dialog.d.ts +24 -0
  91. package/dist/components/ui/dialog.d.ts.map +1 -0
  92. package/dist/components/ui/dialog.js +30 -0
  93. package/dist/components/ui/dropdown-menu.d.ts +17 -0
  94. package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
  95. package/dist/components/ui/dropdown-menu.js +20 -0
  96. package/dist/components/ui/input.d.ts +4 -0
  97. package/dist/components/ui/input.d.ts.map +1 -0
  98. package/dist/components/ui/input.js +7 -0
  99. package/dist/components/ui/label.d.ts +6 -0
  100. package/dist/components/ui/label.d.ts.map +1 -0
  101. package/dist/components/ui/label.js +10 -0
  102. package/dist/components/ui/popover.d.ts +6 -0
  103. package/dist/components/ui/popover.d.ts.map +1 -0
  104. package/dist/components/ui/popover.js +9 -0
  105. package/dist/components/ui/scroll-area.d.ts +3 -0
  106. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  107. package/dist/components/ui/scroll-area.js +8 -0
  108. package/dist/components/ui/select.d.ts +14 -0
  109. package/dist/components/ui/select.d.ts.map +1 -0
  110. package/dist/components/ui/select.js +26 -0
  111. package/dist/components/ui/separator.d.ts +3 -0
  112. package/dist/components/ui/separator.d.ts.map +1 -0
  113. package/dist/components/ui/separator.js +6 -0
  114. package/dist/components/ui/switch.d.ts +3 -0
  115. package/dist/components/ui/switch.d.ts.map +1 -0
  116. package/dist/components/ui/switch.js +6 -0
  117. package/dist/components/ui/tabs.d.ts +6 -0
  118. package/dist/components/ui/tabs.d.ts.map +1 -0
  119. package/dist/components/ui/tabs.js +11 -0
  120. package/dist/components/ui/tooltip.d.ts +6 -0
  121. package/dist/components/ui/tooltip.d.ts.map +1 -0
  122. package/dist/components/ui/tooltip.js +9 -0
  123. package/dist/components.cjs +2 -0
  124. package/dist/components.cjs.map +1 -0
  125. package/dist/components.js +129 -0
  126. package/dist/components.js.map +1 -0
  127. package/dist/hooks/index.d.ts +2 -0
  128. package/dist/hooks/index.d.ts.map +1 -0
  129. package/dist/hooks/index.js +3 -0
  130. package/dist/hooks/useChat.d.ts +6 -0
  131. package/dist/hooks/useChat.d.ts.map +1 -0
  132. package/dist/hooks/useChat.js +5 -0
  133. package/dist/hooks.cjs +2 -0
  134. package/dist/hooks.cjs.map +1 -0
  135. package/dist/hooks.js +8 -0
  136. package/dist/hooks.js.map +1 -0
  137. package/dist/index-Ci4qkGOp.cjs +20 -0
  138. package/dist/index-Ci4qkGOp.cjs.map +1 -0
  139. package/dist/index-NhYr-cEJ.js +567 -0
  140. package/dist/index-NhYr-cEJ.js.map +1 -0
  141. package/dist/index.cjs +2 -0
  142. package/dist/index.cjs.map +1 -0
  143. package/dist/index.d.ts +33 -0
  144. package/dist/index.d.ts.map +1 -0
  145. package/dist/index.js +32 -0
  146. package/dist/index.js.map +1 -0
  147. package/dist/lib/agents.d.ts +29 -0
  148. package/dist/lib/agents.d.ts.map +1 -0
  149. package/dist/lib/agents.js +145 -0
  150. package/dist/lib/attachments.d.ts +40 -0
  151. package/dist/lib/attachments.d.ts.map +1 -0
  152. package/dist/lib/attachments.js +152 -0
  153. package/dist/lib/chat-engine.d.ts +109 -0
  154. package/dist/lib/chat-engine.d.ts.map +1 -0
  155. package/dist/lib/chat-engine.js +505 -0
  156. package/dist/lib/index.d.ts +8 -0
  157. package/dist/lib/index.d.ts.map +1 -0
  158. package/dist/lib/index.js +7 -0
  159. package/dist/lib/persistence.d.ts +30 -0
  160. package/dist/lib/persistence.d.ts.map +1 -0
  161. package/dist/lib/persistence.js +104 -0
  162. package/dist/lib/providers.d.ts +40 -0
  163. package/dist/lib/providers.d.ts.map +1 -0
  164. package/dist/lib/providers.js +0 -0
  165. package/dist/lib/tw-merge.d.ts +9 -0
  166. package/dist/lib/tw-merge.d.ts.map +1 -0
  167. package/dist/lib/tw-merge.js +8 -0
  168. package/dist/lib/utils.d.ts +69 -0
  169. package/dist/lib/utils.d.ts.map +1 -0
  170. package/dist/lib/utils.js +166 -0
  171. package/dist/lib/voice.d.ts +57 -0
  172. package/dist/lib/voice.d.ts.map +1 -0
  173. package/dist/lib/voice.js +103 -0
  174. package/dist/lib.cjs +2 -0
  175. package/dist/lib.cjs.map +1 -0
  176. package/dist/lib.js +59 -0
  177. package/dist/lib.js.map +1 -0
  178. package/dist/marker.css +68 -0
  179. package/dist/package.json +6 -0
  180. package/dist/presets-BxnbImSM.cjs +2 -0
  181. package/dist/presets-BxnbImSM.cjs.map +1 -0
  182. package/dist/presets-D8VQTD8n.js +193 -0
  183. package/dist/presets-D8VQTD8n.js.map +1 -0
  184. package/dist/providers/anthropic.d.ts +30 -0
  185. package/dist/providers/anthropic.d.ts.map +1 -0
  186. package/dist/providers/anthropic.js +251 -0
  187. package/dist/providers/base.d.ts +55 -0
  188. package/dist/providers/base.d.ts.map +1 -0
  189. package/dist/providers/base.js +272 -0
  190. package/dist/providers/index.d.ts +15 -0
  191. package/dist/providers/index.d.ts.map +1 -0
  192. package/dist/providers/index.js +24 -0
  193. package/dist/providers/openai.d.ts +31 -0
  194. package/dist/providers/openai.d.ts.map +1 -0
  195. package/dist/providers/openai.js +192 -0
  196. package/dist/providers-BuaGy2tX.cjs +4 -0
  197. package/dist/providers-BuaGy2tX.cjs.map +1 -0
  198. package/dist/providers-kp-avTNl.js +324 -0
  199. package/dist/providers-kp-avTNl.js.map +1 -0
  200. package/dist/providers.cjs +2 -0
  201. package/dist/providers.cjs.map +1 -0
  202. package/dist/providers.js +14 -0
  203. package/dist/providers.js.map +1 -0
  204. package/dist/scroller.css +278 -0
  205. package/dist/style.css +1 -0
  206. package/dist/types/chat.d.ts +342 -0
  207. package/dist/types/chat.d.ts.map +1 -0
  208. package/dist/types/chat.js +4 -0
  209. package/dist/types/index.d.ts +9 -0
  210. package/dist/types/index.d.ts.map +1 -0
  211. package/dist/types/index.js +14 -0
  212. package/dist/types/presets.d.ts +25 -0
  213. package/dist/types/presets.d.ts.map +1 -0
  214. package/dist/types/presets.js +207 -0
  215. package/dist/types.cjs +2 -0
  216. package/dist/types.cjs.map +1 -0
  217. package/dist/types.js +16 -0
  218. package/dist/types.js.map +1 -0
  219. package/dist/typeset-presets.css +56 -0
  220. package/dist/typeset.css +505 -0
  221. 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
+ [![npm version](https://img.shields.io/npm/v/ai-schadcn-chat.svg)](https://www.npmjs.com/package/ai-schadcn-chat)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.6-blue.svg)](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)