@assemble-inc/chat-widget 0.1.1 → 0.1.2

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 (2) hide show
  1. package/README.md +274 -18
  2. package/package.json +6 -3
package/README.md CHANGED
@@ -1,34 +1,290 @@
1
- This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
1
+ # @assemble-inc/chat-widget
2
2
 
3
- ## Getting Started
3
+ An embeddable, general-purpose AI chat widget. Drop it into any React app — or any plain HTML page — to give users a floating chat interface backed by Anthropic Claude and MCP (Model Context Protocol). Fully configurable at embed time: system prompt, model, knowledge base, UI copy, and more.
4
4
 
5
- First, run the development server:
5
+ ---
6
+
7
+ ## Installation
6
8
 
7
9
  ```bash
8
- npm run dev
9
- # or
10
- yarn dev
10
+ npm install @assemble-inc/chat-widget
11
11
  # or
12
- pnpm dev
12
+ yarn add @assemble-inc/chat-widget
13
+ ```
14
+
15
+ **Peer dependencies** — make sure these are already in your project:
16
+
17
+ ```bash
18
+ npm install react react-dom
19
+ ```
20
+
21
+ ---
22
+
23
+ ## Quick Start
24
+
25
+ ### 1. Mount the widget
26
+
27
+ ```tsx
28
+ import { Widget } from "@assemble-inc/chat-widget";
29
+ import "@assemble-inc/chat-widget/style.css";
30
+
31
+ export default function App() {
32
+ return (
33
+ <>
34
+ {/* your app */}
35
+ <Widget
36
+ config={{
37
+ systemPrompt: "You are a helpful assistant for Acme Corp.",
38
+ title: "Ask Us Anything",
39
+ placeholder: "Type your question...",
40
+ }}
41
+ />
42
+ </>
43
+ );
44
+ }
45
+ ```
46
+
47
+ The widget renders as a fixed floating button in the bottom-right corner (configurable). Clicking it opens the chat panel.
48
+
49
+ ### 2. Add the server-side handler
50
+
51
+ ```ts
52
+ // server.ts
53
+ import express from "express";
54
+ import { createChatHandler } from "@assemble-inc/chat-widget/server";
55
+
56
+ const app = express();
57
+ app.use(express.json());
58
+
59
+ app.post(
60
+ "/api/chat",
61
+ createChatHandler({
62
+ apiKey: process.env.ANTHROPIC_API_KEY!,
63
+ mcpServerUrl: process.env.MCP_SERVER_URL!,
64
+ mcpBearerToken: process.env.MCP_BEARER_TOKEN,
65
+ }),
66
+ );
67
+
68
+ app.listen(3001);
69
+ ```
70
+
71
+ ### 3. Environment variables
72
+
73
+ ```bash
74
+ ANTHROPIC_API_KEY=sk-ant-...
75
+ MCP_SERVER_URL=https://your-mcp-server.example.com/mcp
76
+ MCP_BEARER_TOKEN=your-bearer-token # optional
77
+ SYSTEM_PROMPT="You are..." # optional server-side override
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Script-tag Embed (no React required)
83
+
84
+ For non-React apps, use the self-contained IIFE bundle:
85
+
86
+ ```html
87
+ <link rel="stylesheet" href="https://cdn.example.com/asm-widget/index.css" />
88
+ <script src="https://cdn.example.com/asm-widget/embed.js"></script>
89
+ <script>
90
+ AsmWidget.init({
91
+ endpoint: "https://my-server.com/api/chat",
92
+ systemPrompt: "You are a helpful assistant.",
93
+ title: "Help",
94
+ });
95
+ </script>
96
+ ```
97
+
98
+ Build the embed bundle:
99
+
100
+ ```bash
101
+ npm run build:embed # outputs dist/embed.js
102
+ ```
103
+
104
+ ---
105
+
106
+ ## Configuration Reference
107
+
108
+ ### `WidgetConfig`
109
+
110
+ All configuration is passed as a single `config` prop. Every field is optional.
111
+
112
+ #### Network
113
+
114
+ | Field | Type | Default | Description |
115
+ | ---------- | -------- | ------------- | -------------------------- |
116
+ | `endpoint` | `string` | `'/api/chat'` | Backend chat endpoint URL. |
117
+
118
+ #### AI Behavior
119
+
120
+ These fields are forwarded to the server on every request. **Server-side values always win** when both are set.
121
+
122
+ | Field | Type | Description |
123
+ | -------------- | -------- | ------------------------------------------------------------------------------------------------- |
124
+ | `systemPrompt` | `string` | Full system prompt for this embed. Used when the server has no `systemPrompt` configured. |
125
+ | `context` | `string` | Additional context appended after the system prompt (e.g. current page, user role). |
126
+ | `mcpServerUrl` | `string` | Which MCP server (knowledge base) to use. Must appear in the server's `mcpCredentials` allowlist. |
127
+ | `model` | `string` | Claude model ID (e.g. `'claude-opus-4-5'`). Defaults to `claude-sonnet-4-5`. |
128
+ | `temperature` | `number` | Response creativity, 0–1. |
129
+
130
+ #### Conversation
131
+
132
+ | Field | Type | Description |
133
+ | ----------------- | -------------------------- | ------------------------------------------------------------------ |
134
+ | `initialMessages` | `Array<{ role, content }>` | Seed messages shown when the widget first opens. |
135
+ | `persist` | `boolean` | Save the conversation to `sessionStorage` across page navigations. |
136
+
137
+ #### User Identity
138
+
139
+ | Field | Type | Description |
140
+ | ------ | ----------------------- | --------------------------------------------------------------------------- |
141
+ | `user` | `{ id?, name?, role? }` | Forwarded in every request body for server-side personalisation or logging. |
142
+
143
+ #### UI
144
+
145
+ | Field | Type | Default | Description |
146
+ | ---------------- | --------------------------------- | ---------------- | --------------------------------- |
147
+ | `title` | `string` | `'Ask ASMBL'` | Header title. |
148
+ | `logo` | `string` | Built-in logo | URL to a custom logo image. |
149
+ | `welcomeHeading` | `string` | — | Heading shown in the empty state. |
150
+ | `placeholder` | `string` | — | Textarea placeholder text. |
151
+ | `position` | `'bottom-right' \| 'bottom-left'` | `'bottom-right'` | Widget anchor corner. |
152
+
153
+ ### `WidgetProps`
154
+
155
+ | Prop | Type | Description |
156
+ | -------------- | ---------------------------------- | ------------------------------------------------------------------------------------ |
157
+ | `config` | `WidgetConfig` | All configuration (see above). |
158
+ | `children` | `ReactNode` | Custom content shown in the empty state. Replaces the built-in empty state entirely. |
159
+ | `open` | `boolean` | Control open/close state from outside (controlled mode). |
160
+ | `defaultOpen` | `boolean` | Initial open state when uncontrolled. Defaults to `false`. |
161
+ | `onOpenChange` | `(open: boolean) => void` | Called whenever the widget opens or closes. |
162
+ | `onMessage` | `(msg: { role, content }) => void` | Called after each new assistant message. |
163
+ | `onError` | `(error: Error) => void` | Called when a stream error occurs. |
164
+
165
+ ---
166
+
167
+ ## Server Reference
168
+
169
+ ### `createChatHandler(config)`
170
+
171
+ Returns an Express-compatible `(req, res) => Promise<void>` request handler that streams Claude responses via your MCP server.
172
+
173
+ | Option | Type | Required | Description |
174
+ | ---------------- | ------------------------ | -------- | -------------------------------------------------------------------------------- |
175
+ | `apiKey` | `string` | Yes | Anthropic API key. |
176
+ | `mcpServerUrl` | `string` | Yes | Default Streamable HTTP URL of your MCP server. |
177
+ | `mcpBearerToken` | `string` | No | Bearer token for the default MCP server. |
178
+ | `model` | `string` | No | Claude model ID. Overrides widget value. Defaults to `claude-sonnet-4-5`. |
179
+ | `systemPrompt` | `string` | No | Operator system prompt. Overrides widget value. |
180
+ | `temperature` | `number` | No | Model temperature. Overrides widget value. |
181
+ | `mcpCredentials` | `Record<string, string>` | No | Map of additional MCP server URLs → bearer tokens for multi-context deployments. |
182
+
183
+ #### Precedence rules
184
+
185
+ For `systemPrompt`, `model`, `temperature`, and `mcpServerUrl`, the server-side value **always takes precedence** over what the widget sends. The resolution order is:
186
+
187
+ ```
188
+ ChatHandlerConfig value → widget config value → built-in default
189
+ ```
190
+
191
+ #### Multi-context deployments
192
+
193
+ A single server can serve multiple embeds pointing at different MCP servers:
194
+
195
+ ```ts
196
+ createChatHandler({
197
+ apiKey: process.env.ANTHROPIC_API_KEY!,
198
+ mcpServerUrl: process.env.MCP_SERVER_URL!, // default fallback
199
+ mcpBearerToken: process.env.MCP_BEARER_TOKEN,
200
+ mcpCredentials: {
201
+ "https://mcp.acme.com/hr": process.env.MCP_HR_TOKEN,
202
+ "https://mcp.acme.com/it": process.env.MCP_IT_TOKEN,
203
+ },
204
+ });
13
205
  ```
14
206
 
15
- Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
207
+ Each embed specifies which server it wants via `config.mcpServerUrl`. Bearer tokens are looked up server-side — they are never exposed to the browser.
208
+
209
+ ---
210
+
211
+ ## Examples
16
212
 
17
- You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
213
+ ### Minimal embed
18
214
 
19
- This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
215
+ ```tsx
216
+ <Widget config={{ systemPrompt: "You are a helpful assistant." }} />
217
+ ```
20
218
 
21
- ## Learn More
219
+ ### Fully configured embed
22
220
 
23
- To learn more about Next.js, take a look at the following resources:
221
+ ```tsx
222
+ <Widget
223
+ config={{
224
+ endpoint: "https://api.acme.com/chat",
225
+ systemPrompt: "You are an HR assistant for Acme Corp.",
226
+ mcpServerUrl: "https://mcp.acme.com/hr",
227
+ model: "claude-opus-4-5",
228
+ temperature: 0.3,
229
+ title: "Ask HR",
230
+ welcomeHeading: "How can we help?",
231
+ placeholder: "Ask an HR question...",
232
+ position: "bottom-left",
233
+ persist: true,
234
+ user: { id: currentUser.id, name: currentUser.name },
235
+ }}
236
+ onMessage={({ content }) => analytics.track("chat_message", { content })}
237
+ onOpenChange={(open) => setHelpOpen(open)}
238
+ />
239
+ ```
24
240
 
25
- - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
26
- - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
241
+ ### Custom empty state (children)
27
242
 
28
- You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
243
+ ```tsx
244
+ <Widget config={{ title: "Support", placeholder: "Describe your issue..." }}>
245
+ <div>
246
+ <h3>How can we help?</h3>
247
+ <button onClick={() => sendMessage("Reset my password")}>
248
+ Reset my password
249
+ </button>
250
+ <button onClick={() => sendMessage("Billing question")}>
251
+ Billing question
252
+ </button>
253
+ </div>
254
+ </Widget>
255
+ ```
29
256
 
30
- ## Deploy on Vercel
257
+ ---
31
258
 
32
- The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
259
+ ## Local Development
33
260
 
34
- Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
261
+ ```bash
262
+ # Install dependencies
263
+ npm install
264
+
265
+ # Copy and fill in environment variables
266
+ cp .env.example .env
267
+
268
+ # Start the Vite dev server (port 3003) + Express API server (port 3001)
269
+ npm run dev
270
+ ```
271
+
272
+ The Vite dev server proxies `/api/*` to `http://localhost:3001`.
273
+
274
+ ```bash
275
+ npm run lint # type-check without emitting
276
+ npm run build # build the React library (dist/)
277
+ npm run build:embed # build the standalone IIFE script (dist/embed.js)
278
+ ```
279
+
280
+ ---
281
+
282
+ ## Publishing
283
+
284
+ ```bash
285
+ npm version patch # bug fixes (0.1.x)
286
+ npm version minor # new features (0.x.0)
287
+ npm version major # breaking changes (x.0.0)
288
+
289
+ npm publish
290
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assemble-inc/chat-widget",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Embeddable AI chat widget powered by Anthropic and MCP",
5
5
  "keywords": [
6
6
  "chat",
@@ -25,7 +25,8 @@
25
25
  "import": "./dist/server.js",
26
26
  "require": "./dist/server.cjs"
27
27
  },
28
- "./style.css": "./dist/index.css"
28
+ "./style.css": "./dist/index.css",
29
+ "./embed": "./dist/embed.js"
29
30
  },
30
31
  "files": [
31
32
  "dist"
@@ -36,6 +37,7 @@
36
37
  "scripts": {
37
38
  "dev": "concurrently \"vite\" \"tsx watch server.ts\"",
38
39
  "build": "vite build && tsup",
40
+ "build:embed": "vite build --config vite.embed.config.ts",
39
41
  "preview": "vite preview",
40
42
  "lint": "tsc --noEmit",
41
43
  "auth": "tsx scripts/auth.ts"
@@ -50,7 +52,8 @@
50
52
  "@modelcontextprotocol/sdk": "^1.12.0",
51
53
  "ai": "^6.0.176",
52
54
  "class-variance-authority": "^0.7.1",
53
- "express": "^4.21.2"
55
+ "express": "^4.21.2",
56
+ "react-markdown": "^9.0.1"
54
57
  },
55
58
  "devDependencies": {
56
59
  "@tailwindcss/postcss": "^4.2.4",