@timbal-ai/timbal-react 0.1.1 → 0.2.1
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 +361 -36
- package/dist/index.cjs +83 -39
- package/dist/index.d.cts +49 -3
- package/dist/index.d.ts +49 -3
- package/dist/index.esm.js +84 -40
- package/package.json +7 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @timbal-ai/timbal-react
|
|
2
2
|
|
|
3
|
-
React components and runtime for building Timbal chat UIs.
|
|
3
|
+
React components and runtime for building Timbal chat UIs. Drop in a single component to get a fully-featured streaming chat interface connected to a Timbal workforce agent.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -10,15 +10,15 @@ npm install @timbal-ai/timbal-react
|
|
|
10
10
|
bun add @timbal-ai/timbal-react
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
**Peer dependencies:**
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
npm install react react-dom @assistant-ui/react @timbal-ai/timbal-sdk
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
###
|
|
19
|
+
### Tailwind setup
|
|
20
20
|
|
|
21
|
-
The package ships pre-built class names
|
|
21
|
+
The package ships pre-built Tailwind class names. Add this `@source` line to your CSS entry file — **without it the components will be unstyled**:
|
|
22
22
|
|
|
23
23
|
```css
|
|
24
24
|
/* src/index.css */
|
|
@@ -29,7 +29,7 @@ The package ships pre-built class names that Tailwind must scan. Add this `@sour
|
|
|
29
29
|
|
|
30
30
|
> Adjust the path if your CSS file lives at a different depth relative to `node_modules`.
|
|
31
31
|
|
|
32
|
-
###
|
|
32
|
+
### CSS imports
|
|
33
33
|
|
|
34
34
|
Import these stylesheets once in your app entry:
|
|
35
35
|
|
|
@@ -41,11 +41,74 @@ import "katex/dist/katex.min.css";
|
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Quick start
|
|
45
45
|
|
|
46
|
-
###
|
|
46
|
+
### Basic usage
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
`TimbalChat` is a single component that handles everything — runtime, streaming, messages, and the composer:
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { TimbalChat } from "@timbal-ai/timbal-react";
|
|
52
|
+
|
|
53
|
+
export default function App() {
|
|
54
|
+
return (
|
|
55
|
+
<div style={{ height: "100vh" }}>
|
|
56
|
+
<TimbalChat workforceId="your-workforce-id" />
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
> `TimbalChat` requires a fixed height parent. Use `height: "100vh"` or `flex-1 min-h-0` depending on your layout.
|
|
63
|
+
|
|
64
|
+
### Welcome screen and suggestions
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
<TimbalChat
|
|
68
|
+
workforceId="your-workforce-id"
|
|
69
|
+
welcome={{
|
|
70
|
+
heading: "Hi, I'm your assistant",
|
|
71
|
+
subheading: "Ask me anything about your data.",
|
|
72
|
+
}}
|
|
73
|
+
suggestions={[
|
|
74
|
+
{ title: "Summarize this week", description: "Get a quick overview of recent activity" },
|
|
75
|
+
{ title: "What can you help with?" },
|
|
76
|
+
{ title: "Show me the latest report" },
|
|
77
|
+
]}
|
|
78
|
+
/>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Placeholder and width
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
<TimbalChat
|
|
85
|
+
workforceId="your-workforce-id"
|
|
86
|
+
composerPlaceholder="Type a question..."
|
|
87
|
+
maxWidth="60rem"
|
|
88
|
+
className="my-custom-class"
|
|
89
|
+
/>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Switching agents dynamically
|
|
93
|
+
|
|
94
|
+
Pass `key` to fully reset the chat when the workforce changes:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
const [workforceId, setWorkforceId] = useState("agent-a");
|
|
98
|
+
|
|
99
|
+
<select onChange={(e) => setWorkforceId(e.target.value)}>
|
|
100
|
+
<option value="agent-a">Agent A</option>
|
|
101
|
+
<option value="agent-b">Agent B</option>
|
|
102
|
+
</select>
|
|
103
|
+
|
|
104
|
+
<TimbalChat workforceId={workforceId} key={workforceId} />
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Splitting the runtime and UI
|
|
110
|
+
|
|
111
|
+
`TimbalChat` is a convenience wrapper around `TimbalRuntimeProvider` + `Thread`. Use them separately when you need to place the runtime above the chat — for example, to build a custom header that reads or controls chat state:
|
|
49
112
|
|
|
50
113
|
```tsx
|
|
51
114
|
import { TimbalRuntimeProvider, Thread } from "@timbal-ai/timbal-react";
|
|
@@ -53,89 +116,292 @@ import { TimbalRuntimeProvider, Thread } from "@timbal-ai/timbal-react";
|
|
|
53
116
|
export default function App() {
|
|
54
117
|
return (
|
|
55
118
|
<TimbalRuntimeProvider workforceId="your-workforce-id">
|
|
56
|
-
<div style={{ height: "100vh" }}>
|
|
57
|
-
<
|
|
119
|
+
<div style={{ height: "100vh", display: "flex", flexDirection: "column" }}>
|
|
120
|
+
<header>My App</header>
|
|
121
|
+
<Thread
|
|
122
|
+
composerPlaceholder="Ask anything..."
|
|
123
|
+
className="flex-1 min-h-0"
|
|
124
|
+
/>
|
|
58
125
|
</div>
|
|
59
126
|
</TimbalRuntimeProvider>
|
|
60
127
|
);
|
|
61
128
|
}
|
|
62
129
|
```
|
|
63
130
|
|
|
64
|
-
###
|
|
131
|
+
### Custom API base URL
|
|
132
|
+
|
|
133
|
+
Useful when your API is mounted at a subpath (e.g. behind a reverse proxy):
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
<TimbalRuntimeProvider workforceId="your-workforce-id" baseUrl="/api">
|
|
137
|
+
<Thread />
|
|
138
|
+
</TimbalRuntimeProvider>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Custom fetch function
|
|
142
|
+
|
|
143
|
+
Pass your own `fetch` to add headers, inject tokens, or proxy requests:
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
const myFetch: typeof fetch = (url, options) => {
|
|
147
|
+
return fetch(url, {
|
|
148
|
+
...options,
|
|
149
|
+
headers: { ...options?.headers, "X-My-Header": "value" },
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
<TimbalRuntimeProvider workforceId="your-workforce-id" fetch={myFetch}>
|
|
154
|
+
<Thread />
|
|
155
|
+
</TimbalRuntimeProvider>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Customizing the UI
|
|
161
|
+
|
|
162
|
+
Use the `components` prop on `TimbalChat` or `Thread` to replace any part of the interface while keeping everything else as the default.
|
|
163
|
+
|
|
164
|
+
### Available slots
|
|
165
|
+
|
|
166
|
+
| Slot | Props forwarded | Default |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| `UserMessage` | none | built-in user bubble |
|
|
169
|
+
| `AssistantMessage` | none | built-in assistant bubble |
|
|
170
|
+
| `EditComposer` | none | built-in inline edit composer |
|
|
171
|
+
| `Composer` | `placeholder` | built-in composer bar |
|
|
172
|
+
| `Welcome` | `config`, `suggestions` | built-in welcome screen |
|
|
173
|
+
| `ScrollToBottom` | none | built-in scroll button |
|
|
174
|
+
|
|
175
|
+
Custom slot components read their data via hooks — no props are passed automatically except where noted above.
|
|
176
|
+
|
|
177
|
+
### Custom user message
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
import { TimbalChat, MessagePrimitive } from "@timbal-ai/timbal-react";
|
|
181
|
+
|
|
182
|
+
const CompactUserMessage = () => (
|
|
183
|
+
<MessagePrimitive.Root className="flex justify-end px-4 py-2">
|
|
184
|
+
<div className="bg-primary text-primary-foreground rounded-2xl px-4 py-2 text-sm max-w-[75%]">
|
|
185
|
+
<MessagePrimitive.Parts />
|
|
186
|
+
</div>
|
|
187
|
+
</MessagePrimitive.Root>
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
<TimbalChat workforceId="..." components={{ UserMessage: CompactUserMessage }} />
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Custom composer
|
|
194
|
+
|
|
195
|
+
The `Composer` slot receives `placeholder` from the `composerPlaceholder` prop:
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
import { TimbalChat, ComposerPrimitive } from "@timbal-ai/timbal-react";
|
|
199
|
+
|
|
200
|
+
const MinimalComposer = ({ placeholder }: { placeholder?: string }) => (
|
|
201
|
+
<ComposerPrimitive.Root className="flex items-center gap-2 border rounded-full px-4 py-2">
|
|
202
|
+
<ComposerPrimitive.Input
|
|
203
|
+
placeholder={placeholder ?? "Type here..."}
|
|
204
|
+
className="flex-1 bg-transparent text-sm outline-none"
|
|
205
|
+
rows={1}
|
|
206
|
+
/>
|
|
207
|
+
<ComposerPrimitive.Send className="text-primary font-medium text-sm">
|
|
208
|
+
Send
|
|
209
|
+
</ComposerPrimitive.Send>
|
|
210
|
+
</ComposerPrimitive.Root>
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
<TimbalChat workforceId="..." components={{ Composer: MinimalComposer }} />
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Custom welcome screen
|
|
217
|
+
|
|
218
|
+
The `Welcome` slot is always mounted and controls its own visibility. Use `useThread` to replicate the default "show only when the thread is empty" behaviour:
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
import { TimbalChat, useThread, useThreadRuntime, type ThreadWelcomeProps } from "@timbal-ai/timbal-react";
|
|
222
|
+
|
|
223
|
+
const BrandedWelcome = ({ suggestions }: ThreadWelcomeProps) => {
|
|
224
|
+
const isEmpty = useThread((s) => s.isEmpty);
|
|
225
|
+
const runtime = useThreadRuntime();
|
|
226
|
+
if (!isEmpty) return null;
|
|
227
|
+
return (
|
|
228
|
+
<div className="flex flex-col items-center justify-center h-full gap-4">
|
|
229
|
+
<img src="/logo.svg" className="h-12" />
|
|
230
|
+
<h2 className="text-xl font-semibold">Welcome to Acme AI</h2>
|
|
231
|
+
<div className="flex gap-2 flex-wrap justify-center">
|
|
232
|
+
{suggestions?.map((s) => (
|
|
233
|
+
<button
|
|
234
|
+
key={s.title}
|
|
235
|
+
onClick={() => runtime.append({ role: "user", content: [{ type: "text", text: s.title }] })}
|
|
236
|
+
className="border rounded-full px-4 py-1.5 text-sm hover:bg-muted"
|
|
237
|
+
>
|
|
238
|
+
{s.title}
|
|
239
|
+
</button>
|
|
240
|
+
))}
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
<TimbalChat
|
|
247
|
+
workforceId="..."
|
|
248
|
+
suggestions={[{ title: "Get started" }, { title: "Show me an example" }]}
|
|
249
|
+
components={{ Welcome: BrandedWelcome }}
|
|
250
|
+
/>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Mixing slots
|
|
254
|
+
|
|
255
|
+
Override any combination — slots are independent of each other:
|
|
256
|
+
|
|
257
|
+
```tsx
|
|
258
|
+
<TimbalChat
|
|
259
|
+
workforceId="..."
|
|
260
|
+
components={{
|
|
261
|
+
UserMessage: CompactUserMessage,
|
|
262
|
+
Composer: MinimalComposer,
|
|
263
|
+
}}
|
|
264
|
+
/>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Hooks and primitives
|
|
268
|
+
|
|
269
|
+
These are re-exported from `@assistant-ui/react` for use inside custom slot components:
|
|
270
|
+
|
|
271
|
+
| Export | Use inside |
|
|
272
|
+
|---|---|
|
|
273
|
+
| `ThreadPrimitive` | Any slot |
|
|
274
|
+
| `MessagePrimitive` | `UserMessage`, `AssistantMessage`, `EditComposer` |
|
|
275
|
+
| `ComposerPrimitive` | `Composer`, `EditComposer` |
|
|
276
|
+
| `ActionBarPrimitive` | `UserMessage`, `AssistantMessage` |
|
|
277
|
+
| `useThread` | Any slot — subscribe to thread state (e.g. `isRunning`, `isEmpty`) |
|
|
278
|
+
| `useThreadRuntime` | Any slot — call actions (e.g. `runtime.append(...)`) |
|
|
279
|
+
| `useMessageRuntime` | `UserMessage`, `AssistantMessage` — edit, reload, branch |
|
|
280
|
+
| `useComposerRuntime` | `Composer`, `EditComposer` — access composer state |
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## API reference
|
|
285
|
+
|
|
286
|
+
### `TimbalChat` props
|
|
287
|
+
|
|
288
|
+
`TimbalChat` accepts all `TimbalRuntimeProvider` props plus all `Thread` props.
|
|
65
289
|
|
|
66
290
|
| Prop | Type | Default | Description |
|
|
67
291
|
|---|---|---|---|
|
|
68
|
-
| `workforceId` | `string` |
|
|
292
|
+
| `workforceId` | `string` | **required** | ID of the workforce to stream from |
|
|
69
293
|
| `baseUrl` | `string` | `"/api"` | Base URL for API calls. Posts to `{baseUrl}/workforce/{workforceId}/stream` |
|
|
70
|
-
| `fetch` | `(url, options?) => Promise<Response>` | `authFetch` | Custom fetch
|
|
294
|
+
| `fetch` | `(url, options?) => Promise<Response>` | `authFetch` | Custom fetch. Defaults to the built-in auth-aware fetch (Bearer token + auto-refresh) |
|
|
295
|
+
| `welcome.heading` | `string` | `"How can I help you today?"` | Welcome screen heading |
|
|
296
|
+
| `welcome.subheading` | `string` | `"Send a message to start a conversation."` | Welcome screen subheading |
|
|
297
|
+
| `suggestions` | `{ title: string; description?: string }[]` | — | Suggestion chips on the welcome screen |
|
|
298
|
+
| `composerPlaceholder` | `string` | `"Send a message..."` | Composer input placeholder |
|
|
299
|
+
| `components` | `ThreadComponents` | — | Override individual UI slots |
|
|
300
|
+
| `maxWidth` | `string` | `"44rem"` | Max width of the message column |
|
|
301
|
+
| `className` | `string` | — | Extra classes on the root element |
|
|
302
|
+
|
|
303
|
+
### `Thread` props
|
|
304
|
+
|
|
305
|
+
Same as `TimbalChat` minus `workforceId`, `baseUrl`, and `fetch` (those live on `TimbalRuntimeProvider`).
|
|
306
|
+
|
|
307
|
+
### `TimbalRuntimeProvider` props
|
|
308
|
+
|
|
309
|
+
| Prop | Type | Default | Description |
|
|
310
|
+
|---|---|---|---|
|
|
311
|
+
| `workforceId` | `string` | **required** | ID of the workforce to stream from |
|
|
312
|
+
| `baseUrl` | `string` | `"/api"` | Base URL for API calls |
|
|
313
|
+
| `fetch` | `(url, options?) => Promise<Response>` | `authFetch` | Custom fetch function |
|
|
71
314
|
|
|
72
315
|
---
|
|
73
316
|
|
|
74
317
|
## Auth
|
|
75
318
|
|
|
76
|
-
The package includes
|
|
319
|
+
The package includes an optional session/auth system backed by localStorage tokens. The API is expected to expose `/api/auth/login`, `/api/auth/logout`, and `/api/auth/refresh`.
|
|
320
|
+
|
|
321
|
+
Auth is **opt-in** — it only activates when `VITE_TIMBAL_PROJECT_ID` is set in your environment.
|
|
77
322
|
|
|
78
323
|
### Setup
|
|
79
324
|
|
|
80
325
|
Wrap your app with `SessionProvider` and protect routes with `AuthGuard`:
|
|
81
326
|
|
|
82
327
|
```tsx
|
|
328
|
+
// src/App.tsx
|
|
83
329
|
import { SessionProvider, AuthGuard, TooltipProvider } from "@timbal-ai/timbal-react";
|
|
330
|
+
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
|
331
|
+
import Home from "./pages/Home";
|
|
84
332
|
|
|
85
333
|
const isAuthEnabled = !!import.meta.env.VITE_TIMBAL_PROJECT_ID;
|
|
86
334
|
|
|
87
|
-
function App() {
|
|
335
|
+
export default function App() {
|
|
88
336
|
return (
|
|
89
337
|
<SessionProvider enabled={isAuthEnabled}>
|
|
90
338
|
<TooltipProvider>
|
|
91
|
-
<
|
|
92
|
-
<
|
|
93
|
-
|
|
339
|
+
<BrowserRouter>
|
|
340
|
+
<AuthGuard requireAuth enabled={isAuthEnabled}>
|
|
341
|
+
<Routes>
|
|
342
|
+
<Route path="/" element={<Home />} />
|
|
343
|
+
</Routes>
|
|
344
|
+
</AuthGuard>
|
|
345
|
+
</BrowserRouter>
|
|
94
346
|
</TooltipProvider>
|
|
95
347
|
</SessionProvider>
|
|
96
348
|
);
|
|
97
349
|
}
|
|
98
350
|
```
|
|
99
351
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
| Prop | Type | Default | Description |
|
|
103
|
-
|---|---|---|---|
|
|
104
|
-
| `enabled` | `boolean` | `true` | When `false`, session is always `null` and no API calls are made |
|
|
105
|
-
|
|
106
|
-
### `AuthGuard` props
|
|
107
|
-
|
|
108
|
-
| Prop | Type | Default | Description |
|
|
109
|
-
|---|---|---|---|
|
|
110
|
-
| `requireAuth` | `boolean` | `false` | Redirect to login if not authenticated |
|
|
111
|
-
| `enabled` | `boolean` | `true` | When `false`, renders children unconditionally |
|
|
352
|
+
When `enabled` is `false`, both `SessionProvider` and `AuthGuard` are transparent — no redirects, no API calls.
|
|
112
353
|
|
|
113
354
|
### `useSession` hook
|
|
114
355
|
|
|
356
|
+
Access the current session anywhere inside `SessionProvider`:
|
|
357
|
+
|
|
115
358
|
```tsx
|
|
116
359
|
import { useSession } from "@timbal-ai/timbal-react";
|
|
117
360
|
|
|
118
361
|
function Header() {
|
|
119
362
|
const { user, isAuthenticated, loading, logout } = useSession();
|
|
120
|
-
|
|
363
|
+
if (loading) return null;
|
|
364
|
+
return (
|
|
365
|
+
<header>
|
|
366
|
+
{isAuthenticated ? (
|
|
367
|
+
<>
|
|
368
|
+
<span>{user?.email}</span>
|
|
369
|
+
<button onClick={logout}>Log out</button>
|
|
370
|
+
</>
|
|
371
|
+
) : (
|
|
372
|
+
<a href="/login">Log in</a>
|
|
373
|
+
)}
|
|
374
|
+
</header>
|
|
375
|
+
);
|
|
121
376
|
}
|
|
122
377
|
```
|
|
123
378
|
|
|
124
379
|
### `authFetch`
|
|
125
380
|
|
|
126
|
-
A drop-in replacement for `fetch` that attaches the Bearer token and auto-refreshes on 401:
|
|
381
|
+
A drop-in replacement for `fetch` that attaches the Bearer token from localStorage and auto-refreshes on 401. It's also the default `fetch` used by `TimbalRuntimeProvider`, so you only need to import it directly for your own API calls (e.g. loading workforce lists):
|
|
127
382
|
|
|
128
383
|
```tsx
|
|
129
384
|
import { authFetch } from "@timbal-ai/timbal-react";
|
|
130
385
|
|
|
131
386
|
const res = await authFetch("/api/workforce");
|
|
387
|
+
if (res.ok) {
|
|
388
|
+
const agents = await res.json();
|
|
389
|
+
}
|
|
132
390
|
```
|
|
133
391
|
|
|
392
|
+
### Auth prop reference
|
|
393
|
+
|
|
394
|
+
| Component | Prop | Type | Default | Description |
|
|
395
|
+
|---|---|---|---|---|
|
|
396
|
+
| `SessionProvider` | `enabled` | `boolean` | `true` | When `false`, session is always `null` and no API calls are made |
|
|
397
|
+
| `AuthGuard` | `requireAuth` | `boolean` | `false` | Redirect to login if not authenticated |
|
|
398
|
+
| `AuthGuard` | `enabled` | `boolean` | `true` | When `false`, renders children unconditionally |
|
|
399
|
+
|
|
134
400
|
---
|
|
135
401
|
|
|
136
|
-
##
|
|
402
|
+
## Other exports
|
|
137
403
|
|
|
138
|
-
|
|
404
|
+
### Components
|
|
139
405
|
|
|
140
406
|
| Export | Description |
|
|
141
407
|
|---|---|
|
|
@@ -156,12 +422,71 @@ Re-exported Radix UI wrappers pre-styled to match the Timbal design system:
|
|
|
156
422
|
|
|
157
423
|
---
|
|
158
424
|
|
|
425
|
+
## Full example
|
|
426
|
+
|
|
427
|
+
A complete page with agent switching, auth, and a custom header:
|
|
428
|
+
|
|
429
|
+
```tsx
|
|
430
|
+
// src/pages/Home.tsx
|
|
431
|
+
import { useEffect, useState } from "react";
|
|
432
|
+
import type { WorkforceItem } from "@timbal-ai/timbal-sdk";
|
|
433
|
+
import { TimbalChat, Button, authFetch, useSession } from "@timbal-ai/timbal-react";
|
|
434
|
+
import { LogOut } from "lucide-react";
|
|
435
|
+
|
|
436
|
+
const isAuthEnabled = !!import.meta.env.VITE_TIMBAL_PROJECT_ID;
|
|
437
|
+
|
|
438
|
+
export default function Home() {
|
|
439
|
+
const { logout } = useSession();
|
|
440
|
+
const [workforces, setWorkforces] = useState<WorkforceItem[]>([]);
|
|
441
|
+
const [selectedId, setSelectedId] = useState("");
|
|
442
|
+
|
|
443
|
+
useEffect(() => {
|
|
444
|
+
authFetch("/api/workforce")
|
|
445
|
+
.then((r) => r.json())
|
|
446
|
+
.then((data: WorkforceItem[]) => {
|
|
447
|
+
setWorkforces(data);
|
|
448
|
+
const agent = data.find((w) => w.type === "agent") ?? data[0];
|
|
449
|
+
if (agent) setSelectedId(agent.id ?? agent.name ?? "");
|
|
450
|
+
})
|
|
451
|
+
.catch(() => {});
|
|
452
|
+
}, []);
|
|
453
|
+
|
|
454
|
+
return (
|
|
455
|
+
<div style={{ display: "flex", flexDirection: "column", height: "100vh" }}>
|
|
456
|
+
<header style={{ display: "flex", justifyContent: "space-between", padding: "0.5rem 1.25rem" }}>
|
|
457
|
+
<select value={selectedId} onChange={(e) => setSelectedId(e.target.value)}>
|
|
458
|
+
{workforces.map((w) => (
|
|
459
|
+
<option key={w.id ?? w.name} value={w.id ?? w.name ?? ""}>
|
|
460
|
+
{w.name}
|
|
461
|
+
</option>
|
|
462
|
+
))}
|
|
463
|
+
</select>
|
|
464
|
+
|
|
465
|
+
{isAuthEnabled && (
|
|
466
|
+
<Button variant="ghost" size="icon" onClick={logout}>
|
|
467
|
+
<LogOut />
|
|
468
|
+
</Button>
|
|
469
|
+
)}
|
|
470
|
+
</header>
|
|
471
|
+
|
|
472
|
+
<TimbalChat
|
|
473
|
+
workforceId={selectedId}
|
|
474
|
+
key={selectedId}
|
|
475
|
+
className="flex-1 min-h-0"
|
|
476
|
+
welcome={{ heading: "How can I help you today?" }}
|
|
477
|
+
/>
|
|
478
|
+
</div>
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
159
485
|
## Local development
|
|
160
486
|
|
|
161
487
|
Install via a local path reference:
|
|
162
488
|
|
|
163
489
|
```json
|
|
164
|
-
// package.json
|
|
165
490
|
{
|
|
166
491
|
"dependencies": {
|
|
167
492
|
"@timbal-ai/timbal-react": "file:../../timbal-react"
|
|
@@ -171,7 +496,7 @@ Install via a local path reference:
|
|
|
171
496
|
|
|
172
497
|
Adjust the relative path to where `timbal-react` lives on your machine.
|
|
173
498
|
|
|
174
|
-
After editing source files, rebuild
|
|
499
|
+
After editing source files, rebuild:
|
|
175
500
|
|
|
176
501
|
```bash
|
|
177
502
|
cd timbal-react
|
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
ActionBarPrimitive: () => import_react13.ActionBarPrimitive,
|
|
33
34
|
AuthGuard: () => AuthGuard,
|
|
34
35
|
Avatar: () => Avatar,
|
|
35
36
|
AvatarFallback: () => AvatarFallback,
|
|
@@ -37,6 +38,7 @@ __export(index_exports, {
|
|
|
37
38
|
Button: () => Button,
|
|
38
39
|
ComposerAddAttachment: () => ComposerAddAttachment,
|
|
39
40
|
ComposerAttachments: () => ComposerAttachments,
|
|
41
|
+
ComposerPrimitive: () => import_react13.ComposerPrimitive,
|
|
40
42
|
Dialog: () => Dialog,
|
|
41
43
|
DialogClose: () => DialogClose,
|
|
42
44
|
DialogContent: () => DialogContent,
|
|
@@ -45,10 +47,13 @@ __export(index_exports, {
|
|
|
45
47
|
DialogTitle: () => DialogTitle,
|
|
46
48
|
DialogTrigger: () => DialogTrigger,
|
|
47
49
|
MarkdownText: () => MarkdownText,
|
|
50
|
+
MessagePrimitive: () => import_react13.MessagePrimitive,
|
|
48
51
|
SessionProvider: () => SessionProvider,
|
|
49
52
|
Shimmer: () => Shimmer,
|
|
50
53
|
SyntaxHighlighter: () => syntax_highlighter_default,
|
|
51
54
|
Thread: () => Thread,
|
|
55
|
+
ThreadPrimitive: () => import_react13.ThreadPrimitive,
|
|
56
|
+
TimbalChat: () => TimbalChat,
|
|
52
57
|
TimbalRuntimeProvider: () => TimbalRuntimeProvider,
|
|
53
58
|
ToolFallback: () => ToolFallback,
|
|
54
59
|
Tooltip: () => Tooltip,
|
|
@@ -65,7 +70,11 @@ __export(index_exports, {
|
|
|
65
70
|
getAccessToken: () => getAccessToken,
|
|
66
71
|
getRefreshToken: () => getRefreshToken,
|
|
67
72
|
refreshAccessToken: () => refreshAccessToken,
|
|
68
|
-
|
|
73
|
+
useComposerRuntime: () => import_react13.useComposerRuntime,
|
|
74
|
+
useMessageRuntime: () => import_react13.useMessageRuntime,
|
|
75
|
+
useSession: () => useSession,
|
|
76
|
+
useThread: () => import_react13.useThread,
|
|
77
|
+
useThreadRuntime: () => import_react13.useThreadRuntime
|
|
69
78
|
});
|
|
70
79
|
module.exports = __toCommonJS(index_exports);
|
|
71
80
|
|
|
@@ -1267,34 +1276,48 @@ ToolFallback.displayName = "ToolFallback";
|
|
|
1267
1276
|
var import_react11 = require("@assistant-ui/react");
|
|
1268
1277
|
var import_lucide_react5 = require("lucide-react");
|
|
1269
1278
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1270
|
-
var Thread = (
|
|
1279
|
+
var Thread = ({
|
|
1280
|
+
className,
|
|
1281
|
+
maxWidth = "44rem",
|
|
1282
|
+
welcome,
|
|
1283
|
+
suggestions,
|
|
1284
|
+
composerPlaceholder = "Send a message...",
|
|
1285
|
+
components
|
|
1286
|
+
}) => {
|
|
1287
|
+
const WelcomeSlot = components?.Welcome ?? ThreadWelcome;
|
|
1288
|
+
const ComposerSlot = components?.Composer ?? Composer;
|
|
1289
|
+
const UserMessageSlot = components?.UserMessage ?? UserMessage;
|
|
1290
|
+
const AssistantMessageSlot = components?.AssistantMessage ?? AssistantMessage;
|
|
1291
|
+
const EditComposerSlot = components?.EditComposer ?? EditComposer;
|
|
1292
|
+
const ScrollToBottomSlot = components?.ScrollToBottom ?? ThreadScrollToBottom;
|
|
1271
1293
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1272
1294
|
import_react11.ThreadPrimitive.Root,
|
|
1273
1295
|
{
|
|
1274
|
-
className:
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1296
|
+
className: cn(
|
|
1297
|
+
"aui-root aui-thread-root @container flex h-full flex-col bg-background",
|
|
1298
|
+
className
|
|
1299
|
+
),
|
|
1300
|
+
style: { ["--thread-max-width"]: maxWidth },
|
|
1278
1301
|
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1279
1302
|
import_react11.ThreadPrimitive.Viewport,
|
|
1280
1303
|
{
|
|
1281
1304
|
turnAnchor: "bottom",
|
|
1282
1305
|
className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll px-4 pt-4",
|
|
1283
1306
|
children: [
|
|
1284
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1307
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(WelcomeSlot, { config: welcome, suggestions }),
|
|
1285
1308
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1286
1309
|
import_react11.ThreadPrimitive.Messages,
|
|
1287
1310
|
{
|
|
1288
1311
|
components: {
|
|
1289
|
-
UserMessage,
|
|
1290
|
-
EditComposer,
|
|
1291
|
-
AssistantMessage
|
|
1312
|
+
UserMessage: UserMessageSlot,
|
|
1313
|
+
EditComposer: EditComposerSlot,
|
|
1314
|
+
AssistantMessage: AssistantMessageSlot
|
|
1292
1315
|
}
|
|
1293
1316
|
}
|
|
1294
1317
|
),
|
|
1295
1318
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react11.ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-3xl bg-background pb-4 md:pb-6", children: [
|
|
1296
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1297
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1319
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ScrollToBottomSlot, {}),
|
|
1320
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ComposerSlot, { placeholder: composerPlaceholder })
|
|
1298
1321
|
] })
|
|
1299
1322
|
]
|
|
1300
1323
|
}
|
|
@@ -1313,8 +1336,8 @@ var ThreadScrollToBottom = () => {
|
|
|
1313
1336
|
}
|
|
1314
1337
|
) });
|
|
1315
1338
|
};
|
|
1316
|
-
var ThreadWelcome = () => {
|
|
1317
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: [
|
|
1339
|
+
var ThreadWelcome = ({ config, suggestions }) => {
|
|
1340
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.AuiIf, { condition: (s) => s.thread.isEmpty, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: [
|
|
1318
1341
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "aui-thread-welcome-message flex size-full flex-col items-center justify-center px-4 text-center", children: [
|
|
1319
1342
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "fade-in animate-in fill-mode-both relative mb-6 flex size-14 items-center justify-center duration-300", children: [
|
|
1320
1343
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "animate-ai-ring-glow absolute inset-0 rounded-2xl bg-gradient-to-br from-primary/15 to-primary/5 ring-1 ring-primary/15" }),
|
|
@@ -1334,42 +1357,40 @@ var ThreadWelcome = () => {
|
|
|
1334
1357
|
}
|
|
1335
1358
|
)
|
|
1336
1359
|
] }),
|
|
1337
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h1", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both font-semibold text-2xl duration-200", children: "How can I help you today?" }),
|
|
1338
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-muted-foreground mt-2 delay-75 duration-200", children: "Send a message to start a conversation." })
|
|
1360
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h1", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both font-semibold text-2xl duration-200", children: config?.heading ?? "How can I help you today?" }),
|
|
1361
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-muted-foreground mt-2 delay-75 duration-200", children: config?.subheading ?? "Send a message to start a conversation." })
|
|
1339
1362
|
] }) }),
|
|
1340
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ThreadSuggestions, {})
|
|
1341
|
-
] });
|
|
1363
|
+
suggestions && suggestions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ThreadSuggestions, { suggestions })
|
|
1364
|
+
] }) });
|
|
1342
1365
|
};
|
|
1343
|
-
var ThreadSuggestions = () => {
|
|
1344
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "aui-thread-welcome-suggestions grid w-full @md:grid-cols-2 gap-2 pb-4", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1345
|
-
import_react11.ThreadPrimitive.Suggestions,
|
|
1346
|
-
{
|
|
1347
|
-
components: {
|
|
1348
|
-
Suggestion: ThreadSuggestionItem
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
) });
|
|
1366
|
+
var ThreadSuggestions = ({ suggestions }) => {
|
|
1367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "aui-thread-welcome-suggestions grid w-full @md:grid-cols-2 gap-2 pb-4", children: suggestions.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ThreadSuggestionItem, { title: s.title, description: s.description }, i)) });
|
|
1352
1368
|
};
|
|
1353
|
-
var ThreadSuggestionItem = () => {
|
|
1354
|
-
|
|
1369
|
+
var ThreadSuggestionItem = ({ title, description }) => {
|
|
1370
|
+
const runtime = (0, import_react11.useThreadRuntime)();
|
|
1371
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "aui-thread-welcome-suggestion-display fade-in slide-in-from-bottom-2 animate-in fill-mode-both duration-200", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1355
1372
|
Button,
|
|
1356
1373
|
{
|
|
1357
1374
|
variant: "ghost",
|
|
1358
1375
|
className: "aui-thread-welcome-suggestion h-auto w-full @md:flex-col flex-wrap items-start justify-start gap-1 rounded-2xl border px-4 py-3 text-left text-sm transition-colors hover:bg-muted",
|
|
1376
|
+
onClick: () => runtime.append({
|
|
1377
|
+
role: "user",
|
|
1378
|
+
content: [{ type: "text", text: title }]
|
|
1379
|
+
}),
|
|
1359
1380
|
children: [
|
|
1360
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "aui-thread-welcome-suggestion-text-1 font-medium", children:
|
|
1361
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "aui-thread-welcome-suggestion-text-2 text-muted-foreground", children:
|
|
1381
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "aui-thread-welcome-suggestion-text-1 font-medium", children: title }),
|
|
1382
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "aui-thread-welcome-suggestion-text-2 text-muted-foreground", children: description })
|
|
1362
1383
|
]
|
|
1363
1384
|
}
|
|
1364
|
-
) })
|
|
1385
|
+
) });
|
|
1365
1386
|
};
|
|
1366
|
-
var Composer = () => {
|
|
1387
|
+
var Composer = ({ placeholder }) => {
|
|
1367
1388
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ComposerPrimitive.Root, { className: "aui-composer-root relative mt-3 flex w-full flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react11.ComposerPrimitive.AttachmentDropzone, { className: "aui-composer-attachment-dropzone flex w-full flex-col rounded-2xl border border-input bg-background px-1 pt-2 outline-none transition-shadow has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-2 has-[textarea:focus-visible]:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50", children: [
|
|
1368
1389
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ComposerAttachments, {}),
|
|
1369
1390
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1370
1391
|
import_react11.ComposerPrimitive.Input,
|
|
1371
1392
|
{
|
|
1372
|
-
placeholder: "Send a message...",
|
|
1393
|
+
placeholder: placeholder ?? "Send a message...",
|
|
1373
1394
|
className: "aui-composer-input mb-1 max-h-32 min-h-14 w-full resize-none bg-transparent px-4 pt-2 pb-3 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-0",
|
|
1374
1395
|
rows: 1,
|
|
1375
1396
|
autoFocus: true,
|
|
@@ -1517,9 +1538,23 @@ var EditComposer = () => {
|
|
|
1517
1538
|
] }) });
|
|
1518
1539
|
};
|
|
1519
1540
|
|
|
1541
|
+
// src/components/chat.tsx
|
|
1542
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1543
|
+
function TimbalChat({
|
|
1544
|
+
workforceId,
|
|
1545
|
+
baseUrl,
|
|
1546
|
+
fetch: fetch2,
|
|
1547
|
+
...threadProps
|
|
1548
|
+
}) {
|
|
1549
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TimbalRuntimeProvider, { workforceId, baseUrl, fetch: fetch2, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Thread, { ...threadProps }) });
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
// src/index.ts
|
|
1553
|
+
var import_react13 = require("@assistant-ui/react");
|
|
1554
|
+
|
|
1520
1555
|
// src/auth/provider.tsx
|
|
1521
1556
|
var import_react12 = require("react");
|
|
1522
|
-
var
|
|
1557
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1523
1558
|
var SessionContext = (0, import_react12.createContext)(void 0);
|
|
1524
1559
|
var useSession = () => {
|
|
1525
1560
|
const context = (0, import_react12.useContext)(SessionContext);
|
|
@@ -1583,7 +1618,7 @@ var SessionProvider = ({
|
|
|
1583
1618
|
() => window.location.href = `/api/auth/login?return_to=${returnTo}`
|
|
1584
1619
|
);
|
|
1585
1620
|
}, []);
|
|
1586
|
-
return /* @__PURE__ */ (0,
|
|
1621
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1587
1622
|
SessionContext.Provider,
|
|
1588
1623
|
{
|
|
1589
1624
|
value: {
|
|
@@ -1599,7 +1634,7 @@ var SessionProvider = ({
|
|
|
1599
1634
|
|
|
1600
1635
|
// src/auth/guard.tsx
|
|
1601
1636
|
var import_lucide_react6 = require("lucide-react");
|
|
1602
|
-
var
|
|
1637
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1603
1638
|
var AuthGuard = ({
|
|
1604
1639
|
children,
|
|
1605
1640
|
requireAuth = false,
|
|
@@ -1610,7 +1645,7 @@ var AuthGuard = ({
|
|
|
1610
1645
|
return children;
|
|
1611
1646
|
}
|
|
1612
1647
|
if (loading) {
|
|
1613
|
-
return /* @__PURE__ */ (0,
|
|
1648
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.Loader2, { className: "w-8 h-8 animate-spin" }) });
|
|
1614
1649
|
}
|
|
1615
1650
|
if (requireAuth && !isAuthenticated) {
|
|
1616
1651
|
const returnTo = encodeURIComponent(
|
|
@@ -1623,6 +1658,7 @@ var AuthGuard = ({
|
|
|
1623
1658
|
};
|
|
1624
1659
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1625
1660
|
0 && (module.exports = {
|
|
1661
|
+
ActionBarPrimitive,
|
|
1626
1662
|
AuthGuard,
|
|
1627
1663
|
Avatar,
|
|
1628
1664
|
AvatarFallback,
|
|
@@ -1630,6 +1666,7 @@ var AuthGuard = ({
|
|
|
1630
1666
|
Button,
|
|
1631
1667
|
ComposerAddAttachment,
|
|
1632
1668
|
ComposerAttachments,
|
|
1669
|
+
ComposerPrimitive,
|
|
1633
1670
|
Dialog,
|
|
1634
1671
|
DialogClose,
|
|
1635
1672
|
DialogContent,
|
|
@@ -1638,10 +1675,13 @@ var AuthGuard = ({
|
|
|
1638
1675
|
DialogTitle,
|
|
1639
1676
|
DialogTrigger,
|
|
1640
1677
|
MarkdownText,
|
|
1678
|
+
MessagePrimitive,
|
|
1641
1679
|
SessionProvider,
|
|
1642
1680
|
Shimmer,
|
|
1643
1681
|
SyntaxHighlighter,
|
|
1644
1682
|
Thread,
|
|
1683
|
+
ThreadPrimitive,
|
|
1684
|
+
TimbalChat,
|
|
1645
1685
|
TimbalRuntimeProvider,
|
|
1646
1686
|
ToolFallback,
|
|
1647
1687
|
Tooltip,
|
|
@@ -1658,5 +1698,9 @@ var AuthGuard = ({
|
|
|
1658
1698
|
getAccessToken,
|
|
1659
1699
|
getRefreshToken,
|
|
1660
1700
|
refreshAccessToken,
|
|
1661
|
-
|
|
1701
|
+
useComposerRuntime,
|
|
1702
|
+
useMessageRuntime,
|
|
1703
|
+
useSession,
|
|
1704
|
+
useThread,
|
|
1705
|
+
useThreadRuntime
|
|
1662
1706
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import React__default, { ReactNode, FC, ComponentPropsWithRef, ElementType } from 'react';
|
|
3
|
+
import React__default, { ReactNode, FC, ComponentType, ComponentPropsWithRef, ElementType } from 'react';
|
|
4
4
|
import { ToolCallMessagePartComponent } from '@assistant-ui/react';
|
|
5
|
+
export { ActionBarPrimitive, ComposerPrimitive, MessagePrimitive, ThreadPrimitive, useComposerRuntime, useMessageRuntime, useThread, useThreadRuntime } from '@assistant-ui/react';
|
|
5
6
|
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
6
7
|
import { VariantProps } from 'class-variance-authority';
|
|
7
8
|
import { SyntaxHighlighterProps } from '@assistant-ui/react-markdown';
|
|
@@ -26,7 +27,52 @@ interface TimbalRuntimeProviderProps {
|
|
|
26
27
|
}
|
|
27
28
|
declare function TimbalRuntimeProvider({ workforceId, children, baseUrl, fetch: fetchFn, }: TimbalRuntimeProviderProps): react_jsx_runtime.JSX.Element;
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
interface ThreadSuggestion {
|
|
31
|
+
title: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
}
|
|
34
|
+
interface ThreadWelcomeConfig {
|
|
35
|
+
heading?: string;
|
|
36
|
+
subheading?: string;
|
|
37
|
+
}
|
|
38
|
+
interface ThreadWelcomeProps {
|
|
39
|
+
config?: ThreadWelcomeConfig;
|
|
40
|
+
suggestions?: ThreadSuggestion[];
|
|
41
|
+
}
|
|
42
|
+
interface ThreadComponents {
|
|
43
|
+
/** Replace the user message bubble. Access message content via `MessagePrimitive.Parts`. */
|
|
44
|
+
UserMessage?: ComponentType;
|
|
45
|
+
/** Replace the assistant message bubble. Access message content via `MessagePrimitive.Parts`. */
|
|
46
|
+
AssistantMessage?: ComponentType;
|
|
47
|
+
/** Replace the inline edit composer. */
|
|
48
|
+
EditComposer?: ComponentType;
|
|
49
|
+
/** Replace the composer (input bar). Receives `placeholder` from `composerPlaceholder`. */
|
|
50
|
+
Composer?: ComponentType<{
|
|
51
|
+
placeholder?: string;
|
|
52
|
+
}>;
|
|
53
|
+
/** Replace the welcome / empty state. Receives `config` and `suggestions` props. Controls its own visibility — use `useThread(s => s.isEmpty)` to replicate the default behaviour. */
|
|
54
|
+
Welcome?: ComponentType<ThreadWelcomeProps>;
|
|
55
|
+
/** Replace the scroll-to-bottom button. */
|
|
56
|
+
ScrollToBottom?: ComponentType;
|
|
57
|
+
}
|
|
58
|
+
interface ThreadProps {
|
|
59
|
+
className?: string;
|
|
60
|
+
/** Max width of the message column. Default: "44rem" */
|
|
61
|
+
maxWidth?: string;
|
|
62
|
+
/** Welcome screen text */
|
|
63
|
+
welcome?: ThreadWelcomeConfig;
|
|
64
|
+
/** Suggestion chips shown on the welcome screen */
|
|
65
|
+
suggestions?: ThreadSuggestion[];
|
|
66
|
+
/** Composer input placeholder. Default: "Send a message..." */
|
|
67
|
+
composerPlaceholder?: string;
|
|
68
|
+
/** Override individual UI slots while keeping the rest as defaults. */
|
|
69
|
+
components?: ThreadComponents;
|
|
70
|
+
}
|
|
71
|
+
declare const Thread: FC<ThreadProps>;
|
|
72
|
+
|
|
73
|
+
interface TimbalChatProps extends Omit<TimbalRuntimeProviderProps, "children">, ThreadProps {
|
|
74
|
+
}
|
|
75
|
+
declare function TimbalChat({ workforceId, baseUrl, fetch, ...threadProps }: TimbalChatProps): react_jsx_runtime.JSX.Element;
|
|
30
76
|
|
|
31
77
|
declare const MarkdownText: React.MemoExoticComponent<() => react_jsx_runtime.JSX.Element>;
|
|
32
78
|
|
|
@@ -113,4 +159,4 @@ declare const Shimmer: React.MemoExoticComponent<({ children, as: Component, cla
|
|
|
113
159
|
|
|
114
160
|
declare function cn(...inputs: ClassValue[]): string;
|
|
115
161
|
|
|
116
|
-
export { AuthGuard, Avatar, AvatarFallback, AvatarImage, Button, ComposerAddAttachment, ComposerAttachments, Dialog, DialogClose, DialogContent, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, MarkdownText, SessionProvider, Shimmer, ShikiSyntaxHighlighter as SyntaxHighlighter, type TextShimmerProps, Thread, TimbalRuntimeProvider, type TimbalRuntimeProviderProps, ToolFallback, Tooltip, TooltipContent, TooltipIconButton, type TooltipIconButtonProps, TooltipProvider, TooltipTrigger, UserMessageAttachments, authFetch, buttonVariants, clearTokens, cn, fetchCurrentUser, getAccessToken, getRefreshToken, refreshAccessToken, useSession };
|
|
162
|
+
export { AuthGuard, Avatar, AvatarFallback, AvatarImage, Button, ComposerAddAttachment, ComposerAttachments, Dialog, DialogClose, DialogContent, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, MarkdownText, SessionProvider, Shimmer, ShikiSyntaxHighlighter as SyntaxHighlighter, type TextShimmerProps, Thread, type ThreadComponents, type ThreadProps, type ThreadSuggestion, type ThreadWelcomeConfig, type ThreadWelcomeProps, TimbalChat, type TimbalChatProps, TimbalRuntimeProvider, type TimbalRuntimeProviderProps, ToolFallback, Tooltip, TooltipContent, TooltipIconButton, type TooltipIconButtonProps, TooltipProvider, TooltipTrigger, UserMessageAttachments, authFetch, buttonVariants, clearTokens, cn, fetchCurrentUser, getAccessToken, getRefreshToken, refreshAccessToken, useSession };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import React__default, { ReactNode, FC, ComponentPropsWithRef, ElementType } from 'react';
|
|
3
|
+
import React__default, { ReactNode, FC, ComponentType, ComponentPropsWithRef, ElementType } from 'react';
|
|
4
4
|
import { ToolCallMessagePartComponent } from '@assistant-ui/react';
|
|
5
|
+
export { ActionBarPrimitive, ComposerPrimitive, MessagePrimitive, ThreadPrimitive, useComposerRuntime, useMessageRuntime, useThread, useThreadRuntime } from '@assistant-ui/react';
|
|
5
6
|
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
6
7
|
import { VariantProps } from 'class-variance-authority';
|
|
7
8
|
import { SyntaxHighlighterProps } from '@assistant-ui/react-markdown';
|
|
@@ -26,7 +27,52 @@ interface TimbalRuntimeProviderProps {
|
|
|
26
27
|
}
|
|
27
28
|
declare function TimbalRuntimeProvider({ workforceId, children, baseUrl, fetch: fetchFn, }: TimbalRuntimeProviderProps): react_jsx_runtime.JSX.Element;
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
interface ThreadSuggestion {
|
|
31
|
+
title: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
}
|
|
34
|
+
interface ThreadWelcomeConfig {
|
|
35
|
+
heading?: string;
|
|
36
|
+
subheading?: string;
|
|
37
|
+
}
|
|
38
|
+
interface ThreadWelcomeProps {
|
|
39
|
+
config?: ThreadWelcomeConfig;
|
|
40
|
+
suggestions?: ThreadSuggestion[];
|
|
41
|
+
}
|
|
42
|
+
interface ThreadComponents {
|
|
43
|
+
/** Replace the user message bubble. Access message content via `MessagePrimitive.Parts`. */
|
|
44
|
+
UserMessage?: ComponentType;
|
|
45
|
+
/** Replace the assistant message bubble. Access message content via `MessagePrimitive.Parts`. */
|
|
46
|
+
AssistantMessage?: ComponentType;
|
|
47
|
+
/** Replace the inline edit composer. */
|
|
48
|
+
EditComposer?: ComponentType;
|
|
49
|
+
/** Replace the composer (input bar). Receives `placeholder` from `composerPlaceholder`. */
|
|
50
|
+
Composer?: ComponentType<{
|
|
51
|
+
placeholder?: string;
|
|
52
|
+
}>;
|
|
53
|
+
/** Replace the welcome / empty state. Receives `config` and `suggestions` props. Controls its own visibility — use `useThread(s => s.isEmpty)` to replicate the default behaviour. */
|
|
54
|
+
Welcome?: ComponentType<ThreadWelcomeProps>;
|
|
55
|
+
/** Replace the scroll-to-bottom button. */
|
|
56
|
+
ScrollToBottom?: ComponentType;
|
|
57
|
+
}
|
|
58
|
+
interface ThreadProps {
|
|
59
|
+
className?: string;
|
|
60
|
+
/** Max width of the message column. Default: "44rem" */
|
|
61
|
+
maxWidth?: string;
|
|
62
|
+
/** Welcome screen text */
|
|
63
|
+
welcome?: ThreadWelcomeConfig;
|
|
64
|
+
/** Suggestion chips shown on the welcome screen */
|
|
65
|
+
suggestions?: ThreadSuggestion[];
|
|
66
|
+
/** Composer input placeholder. Default: "Send a message..." */
|
|
67
|
+
composerPlaceholder?: string;
|
|
68
|
+
/** Override individual UI slots while keeping the rest as defaults. */
|
|
69
|
+
components?: ThreadComponents;
|
|
70
|
+
}
|
|
71
|
+
declare const Thread: FC<ThreadProps>;
|
|
72
|
+
|
|
73
|
+
interface TimbalChatProps extends Omit<TimbalRuntimeProviderProps, "children">, ThreadProps {
|
|
74
|
+
}
|
|
75
|
+
declare function TimbalChat({ workforceId, baseUrl, fetch, ...threadProps }: TimbalChatProps): react_jsx_runtime.JSX.Element;
|
|
30
76
|
|
|
31
77
|
declare const MarkdownText: React.MemoExoticComponent<() => react_jsx_runtime.JSX.Element>;
|
|
32
78
|
|
|
@@ -113,4 +159,4 @@ declare const Shimmer: React.MemoExoticComponent<({ children, as: Component, cla
|
|
|
113
159
|
|
|
114
160
|
declare function cn(...inputs: ClassValue[]): string;
|
|
115
161
|
|
|
116
|
-
export { AuthGuard, Avatar, AvatarFallback, AvatarImage, Button, ComposerAddAttachment, ComposerAttachments, Dialog, DialogClose, DialogContent, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, MarkdownText, SessionProvider, Shimmer, ShikiSyntaxHighlighter as SyntaxHighlighter, type TextShimmerProps, Thread, TimbalRuntimeProvider, type TimbalRuntimeProviderProps, ToolFallback, Tooltip, TooltipContent, TooltipIconButton, type TooltipIconButtonProps, TooltipProvider, TooltipTrigger, UserMessageAttachments, authFetch, buttonVariants, clearTokens, cn, fetchCurrentUser, getAccessToken, getRefreshToken, refreshAccessToken, useSession };
|
|
162
|
+
export { AuthGuard, Avatar, AvatarFallback, AvatarImage, Button, ComposerAddAttachment, ComposerAttachments, Dialog, DialogClose, DialogContent, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, MarkdownText, SessionProvider, Shimmer, ShikiSyntaxHighlighter as SyntaxHighlighter, type TextShimmerProps, Thread, type ThreadComponents, type ThreadProps, type ThreadSuggestion, type ThreadWelcomeConfig, type ThreadWelcomeProps, TimbalChat, type TimbalChatProps, TimbalRuntimeProvider, type TimbalRuntimeProviderProps, ToolFallback, Tooltip, TooltipContent, TooltipIconButton, type TooltipIconButtonProps, TooltipProvider, TooltipTrigger, UserMessageAttachments, authFetch, buttonVariants, clearTokens, cn, fetchCurrentUser, getAccessToken, getRefreshToken, refreshAccessToken, useSession };
|
package/dist/index.esm.js
CHANGED
|
@@ -1216,8 +1216,8 @@ import {
|
|
|
1216
1216
|
ComposerPrimitive as ComposerPrimitive2,
|
|
1217
1217
|
ErrorPrimitive,
|
|
1218
1218
|
MessagePrimitive as MessagePrimitive2,
|
|
1219
|
-
|
|
1220
|
-
|
|
1219
|
+
ThreadPrimitive,
|
|
1220
|
+
useThreadRuntime
|
|
1221
1221
|
} from "@assistant-ui/react";
|
|
1222
1222
|
import {
|
|
1223
1223
|
ArrowDownIcon,
|
|
@@ -1231,34 +1231,48 @@ import {
|
|
|
1231
1231
|
SquareIcon
|
|
1232
1232
|
} from "lucide-react";
|
|
1233
1233
|
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1234
|
-
var Thread = (
|
|
1234
|
+
var Thread = ({
|
|
1235
|
+
className,
|
|
1236
|
+
maxWidth = "44rem",
|
|
1237
|
+
welcome,
|
|
1238
|
+
suggestions,
|
|
1239
|
+
composerPlaceholder = "Send a message...",
|
|
1240
|
+
components
|
|
1241
|
+
}) => {
|
|
1242
|
+
const WelcomeSlot = components?.Welcome ?? ThreadWelcome;
|
|
1243
|
+
const ComposerSlot = components?.Composer ?? Composer;
|
|
1244
|
+
const UserMessageSlot = components?.UserMessage ?? UserMessage;
|
|
1245
|
+
const AssistantMessageSlot = components?.AssistantMessage ?? AssistantMessage;
|
|
1246
|
+
const EditComposerSlot = components?.EditComposer ?? EditComposer;
|
|
1247
|
+
const ScrollToBottomSlot = components?.ScrollToBottom ?? ThreadScrollToBottom;
|
|
1235
1248
|
return /* @__PURE__ */ jsx12(
|
|
1236
1249
|
ThreadPrimitive.Root,
|
|
1237
1250
|
{
|
|
1238
|
-
className:
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1251
|
+
className: cn(
|
|
1252
|
+
"aui-root aui-thread-root @container flex h-full flex-col bg-background",
|
|
1253
|
+
className
|
|
1254
|
+
),
|
|
1255
|
+
style: { ["--thread-max-width"]: maxWidth },
|
|
1242
1256
|
children: /* @__PURE__ */ jsxs7(
|
|
1243
1257
|
ThreadPrimitive.Viewport,
|
|
1244
1258
|
{
|
|
1245
1259
|
turnAnchor: "bottom",
|
|
1246
1260
|
className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll px-4 pt-4",
|
|
1247
1261
|
children: [
|
|
1248
|
-
/* @__PURE__ */ jsx12(
|
|
1262
|
+
/* @__PURE__ */ jsx12(WelcomeSlot, { config: welcome, suggestions }),
|
|
1249
1263
|
/* @__PURE__ */ jsx12(
|
|
1250
1264
|
ThreadPrimitive.Messages,
|
|
1251
1265
|
{
|
|
1252
1266
|
components: {
|
|
1253
|
-
UserMessage,
|
|
1254
|
-
EditComposer,
|
|
1255
|
-
AssistantMessage
|
|
1267
|
+
UserMessage: UserMessageSlot,
|
|
1268
|
+
EditComposer: EditComposerSlot,
|
|
1269
|
+
AssistantMessage: AssistantMessageSlot
|
|
1256
1270
|
}
|
|
1257
1271
|
}
|
|
1258
1272
|
),
|
|
1259
1273
|
/* @__PURE__ */ jsxs7(ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-3xl bg-background pb-4 md:pb-6", children: [
|
|
1260
|
-
/* @__PURE__ */ jsx12(
|
|
1261
|
-
/* @__PURE__ */ jsx12(
|
|
1274
|
+
/* @__PURE__ */ jsx12(ScrollToBottomSlot, {}),
|
|
1275
|
+
/* @__PURE__ */ jsx12(ComposerSlot, { placeholder: composerPlaceholder })
|
|
1262
1276
|
] })
|
|
1263
1277
|
]
|
|
1264
1278
|
}
|
|
@@ -1277,8 +1291,8 @@ var ThreadScrollToBottom = () => {
|
|
|
1277
1291
|
}
|
|
1278
1292
|
) });
|
|
1279
1293
|
};
|
|
1280
|
-
var ThreadWelcome = () => {
|
|
1281
|
-
return /* @__PURE__ */ jsxs7("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: [
|
|
1294
|
+
var ThreadWelcome = ({ config, suggestions }) => {
|
|
1295
|
+
return /* @__PURE__ */ jsx12(AuiIf, { condition: (s) => s.thread.isEmpty, children: /* @__PURE__ */ jsxs7("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: [
|
|
1282
1296
|
/* @__PURE__ */ jsx12("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ jsxs7("div", { className: "aui-thread-welcome-message flex size-full flex-col items-center justify-center px-4 text-center", children: [
|
|
1283
1297
|
/* @__PURE__ */ jsxs7("div", { className: "fade-in animate-in fill-mode-both relative mb-6 flex size-14 items-center justify-center duration-300", children: [
|
|
1284
1298
|
/* @__PURE__ */ jsx12("div", { className: "animate-ai-ring-glow absolute inset-0 rounded-2xl bg-gradient-to-br from-primary/15 to-primary/5 ring-1 ring-primary/15" }),
|
|
@@ -1298,42 +1312,40 @@ var ThreadWelcome = () => {
|
|
|
1298
1312
|
}
|
|
1299
1313
|
)
|
|
1300
1314
|
] }),
|
|
1301
|
-
/* @__PURE__ */ jsx12("h1", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both font-semibold text-2xl duration-200", children: "How can I help you today?" }),
|
|
1302
|
-
/* @__PURE__ */ jsx12("p", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-muted-foreground mt-2 delay-75 duration-200", children: "Send a message to start a conversation." })
|
|
1315
|
+
/* @__PURE__ */ jsx12("h1", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both font-semibold text-2xl duration-200", children: config?.heading ?? "How can I help you today?" }),
|
|
1316
|
+
/* @__PURE__ */ jsx12("p", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-muted-foreground mt-2 delay-75 duration-200", children: config?.subheading ?? "Send a message to start a conversation." })
|
|
1303
1317
|
] }) }),
|
|
1304
|
-
/* @__PURE__ */ jsx12(ThreadSuggestions, {})
|
|
1305
|
-
] });
|
|
1318
|
+
suggestions && suggestions.length > 0 && /* @__PURE__ */ jsx12(ThreadSuggestions, { suggestions })
|
|
1319
|
+
] }) });
|
|
1306
1320
|
};
|
|
1307
|
-
var ThreadSuggestions = () => {
|
|
1308
|
-
return /* @__PURE__ */ jsx12("div", { className: "aui-thread-welcome-suggestions grid w-full @md:grid-cols-2 gap-2 pb-4", children: /* @__PURE__ */ jsx12(
|
|
1309
|
-
ThreadPrimitive.Suggestions,
|
|
1310
|
-
{
|
|
1311
|
-
components: {
|
|
1312
|
-
Suggestion: ThreadSuggestionItem
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
) });
|
|
1321
|
+
var ThreadSuggestions = ({ suggestions }) => {
|
|
1322
|
+
return /* @__PURE__ */ jsx12("div", { className: "aui-thread-welcome-suggestions grid w-full @md:grid-cols-2 gap-2 pb-4", children: suggestions.map((s, i) => /* @__PURE__ */ jsx12(ThreadSuggestionItem, { title: s.title, description: s.description }, i)) });
|
|
1316
1323
|
};
|
|
1317
|
-
var ThreadSuggestionItem = () => {
|
|
1318
|
-
|
|
1324
|
+
var ThreadSuggestionItem = ({ title, description }) => {
|
|
1325
|
+
const runtime = useThreadRuntime();
|
|
1326
|
+
return /* @__PURE__ */ jsx12("div", { className: "aui-thread-welcome-suggestion-display fade-in slide-in-from-bottom-2 animate-in fill-mode-both duration-200", children: /* @__PURE__ */ jsxs7(
|
|
1319
1327
|
Button,
|
|
1320
1328
|
{
|
|
1321
1329
|
variant: "ghost",
|
|
1322
1330
|
className: "aui-thread-welcome-suggestion h-auto w-full @md:flex-col flex-wrap items-start justify-start gap-1 rounded-2xl border px-4 py-3 text-left text-sm transition-colors hover:bg-muted",
|
|
1331
|
+
onClick: () => runtime.append({
|
|
1332
|
+
role: "user",
|
|
1333
|
+
content: [{ type: "text", text: title }]
|
|
1334
|
+
}),
|
|
1323
1335
|
children: [
|
|
1324
|
-
/* @__PURE__ */ jsx12("span", { className: "aui-thread-welcome-suggestion-text-1 font-medium", children:
|
|
1325
|
-
/* @__PURE__ */ jsx12("span", { className: "aui-thread-welcome-suggestion-text-2 text-muted-foreground", children:
|
|
1336
|
+
/* @__PURE__ */ jsx12("span", { className: "aui-thread-welcome-suggestion-text-1 font-medium", children: title }),
|
|
1337
|
+
description && /* @__PURE__ */ jsx12("span", { className: "aui-thread-welcome-suggestion-text-2 text-muted-foreground", children: description })
|
|
1326
1338
|
]
|
|
1327
1339
|
}
|
|
1328
|
-
) })
|
|
1340
|
+
) });
|
|
1329
1341
|
};
|
|
1330
|
-
var Composer = () => {
|
|
1342
|
+
var Composer = ({ placeholder }) => {
|
|
1331
1343
|
return /* @__PURE__ */ jsx12(ComposerPrimitive2.Root, { className: "aui-composer-root relative mt-3 flex w-full flex-col", children: /* @__PURE__ */ jsxs7(ComposerPrimitive2.AttachmentDropzone, { className: "aui-composer-attachment-dropzone flex w-full flex-col rounded-2xl border border-input bg-background px-1 pt-2 outline-none transition-shadow has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-2 has-[textarea:focus-visible]:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50", children: [
|
|
1332
1344
|
/* @__PURE__ */ jsx12(ComposerAttachments, {}),
|
|
1333
1345
|
/* @__PURE__ */ jsx12(
|
|
1334
1346
|
ComposerPrimitive2.Input,
|
|
1335
1347
|
{
|
|
1336
|
-
placeholder: "Send a message...",
|
|
1348
|
+
placeholder: placeholder ?? "Send a message...",
|
|
1337
1349
|
className: "aui-composer-input mb-1 max-h-32 min-h-14 w-full resize-none bg-transparent px-4 pt-2 pb-3 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-0",
|
|
1338
1350
|
rows: 1,
|
|
1339
1351
|
autoFocus: true,
|
|
@@ -1481,6 +1493,29 @@ var EditComposer = () => {
|
|
|
1481
1493
|
] }) });
|
|
1482
1494
|
};
|
|
1483
1495
|
|
|
1496
|
+
// src/components/chat.tsx
|
|
1497
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
1498
|
+
function TimbalChat({
|
|
1499
|
+
workforceId,
|
|
1500
|
+
baseUrl,
|
|
1501
|
+
fetch: fetch2,
|
|
1502
|
+
...threadProps
|
|
1503
|
+
}) {
|
|
1504
|
+
return /* @__PURE__ */ jsx13(TimbalRuntimeProvider, { workforceId, baseUrl, fetch: fetch2, children: /* @__PURE__ */ jsx13(Thread, { ...threadProps }) });
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// src/index.ts
|
|
1508
|
+
import {
|
|
1509
|
+
ThreadPrimitive as ThreadPrimitive2,
|
|
1510
|
+
MessagePrimitive as MessagePrimitive3,
|
|
1511
|
+
ComposerPrimitive as ComposerPrimitive3,
|
|
1512
|
+
ActionBarPrimitive as ActionBarPrimitive2,
|
|
1513
|
+
useThread,
|
|
1514
|
+
useThreadRuntime as useThreadRuntime2,
|
|
1515
|
+
useMessageRuntime,
|
|
1516
|
+
useComposerRuntime
|
|
1517
|
+
} from "@assistant-ui/react";
|
|
1518
|
+
|
|
1484
1519
|
// src/auth/provider.tsx
|
|
1485
1520
|
import {
|
|
1486
1521
|
createContext,
|
|
@@ -1489,7 +1524,7 @@ import {
|
|
|
1489
1524
|
useEffect as useEffect4,
|
|
1490
1525
|
useState as useState5
|
|
1491
1526
|
} from "react";
|
|
1492
|
-
import { jsx as
|
|
1527
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1493
1528
|
var SessionContext = createContext(void 0);
|
|
1494
1529
|
var useSession = () => {
|
|
1495
1530
|
const context = useContext(SessionContext);
|
|
@@ -1553,7 +1588,7 @@ var SessionProvider = ({
|
|
|
1553
1588
|
() => window.location.href = `/api/auth/login?return_to=${returnTo}`
|
|
1554
1589
|
);
|
|
1555
1590
|
}, []);
|
|
1556
|
-
return /* @__PURE__ */
|
|
1591
|
+
return /* @__PURE__ */ jsx14(
|
|
1557
1592
|
SessionContext.Provider,
|
|
1558
1593
|
{
|
|
1559
1594
|
value: {
|
|
@@ -1569,7 +1604,7 @@ var SessionProvider = ({
|
|
|
1569
1604
|
|
|
1570
1605
|
// src/auth/guard.tsx
|
|
1571
1606
|
import { Loader2 } from "lucide-react";
|
|
1572
|
-
import { jsx as
|
|
1607
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1573
1608
|
var AuthGuard = ({
|
|
1574
1609
|
children,
|
|
1575
1610
|
requireAuth = false,
|
|
@@ -1580,7 +1615,7 @@ var AuthGuard = ({
|
|
|
1580
1615
|
return children;
|
|
1581
1616
|
}
|
|
1582
1617
|
if (loading) {
|
|
1583
|
-
return /* @__PURE__ */
|
|
1618
|
+
return /* @__PURE__ */ jsx15("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ jsx15(Loader2, { className: "w-8 h-8 animate-spin" }) });
|
|
1584
1619
|
}
|
|
1585
1620
|
if (requireAuth && !isAuthenticated) {
|
|
1586
1621
|
const returnTo = encodeURIComponent(
|
|
@@ -1592,6 +1627,7 @@ var AuthGuard = ({
|
|
|
1592
1627
|
return children;
|
|
1593
1628
|
};
|
|
1594
1629
|
export {
|
|
1630
|
+
ActionBarPrimitive2 as ActionBarPrimitive,
|
|
1595
1631
|
AuthGuard,
|
|
1596
1632
|
Avatar,
|
|
1597
1633
|
AvatarFallback,
|
|
@@ -1599,6 +1635,7 @@ export {
|
|
|
1599
1635
|
Button,
|
|
1600
1636
|
ComposerAddAttachment,
|
|
1601
1637
|
ComposerAttachments,
|
|
1638
|
+
ComposerPrimitive3 as ComposerPrimitive,
|
|
1602
1639
|
Dialog,
|
|
1603
1640
|
DialogClose,
|
|
1604
1641
|
DialogContent,
|
|
@@ -1607,10 +1644,13 @@ export {
|
|
|
1607
1644
|
DialogTitle,
|
|
1608
1645
|
DialogTrigger,
|
|
1609
1646
|
MarkdownText,
|
|
1647
|
+
MessagePrimitive3 as MessagePrimitive,
|
|
1610
1648
|
SessionProvider,
|
|
1611
1649
|
Shimmer,
|
|
1612
1650
|
syntax_highlighter_default as SyntaxHighlighter,
|
|
1613
1651
|
Thread,
|
|
1652
|
+
ThreadPrimitive2 as ThreadPrimitive,
|
|
1653
|
+
TimbalChat,
|
|
1614
1654
|
TimbalRuntimeProvider,
|
|
1615
1655
|
ToolFallback,
|
|
1616
1656
|
Tooltip,
|
|
@@ -1627,5 +1667,9 @@ export {
|
|
|
1627
1667
|
getAccessToken,
|
|
1628
1668
|
getRefreshToken,
|
|
1629
1669
|
refreshAccessToken,
|
|
1630
|
-
|
|
1670
|
+
useComposerRuntime,
|
|
1671
|
+
useMessageRuntime,
|
|
1672
|
+
useSession,
|
|
1673
|
+
useThread,
|
|
1674
|
+
useThreadRuntime2 as useThreadRuntime
|
|
1631
1675
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timbal-ai/timbal-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "React components and runtime for building Timbal chat UIs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"build": "tsup",
|
|
23
23
|
"build:watch": "tsup --watch",
|
|
24
24
|
"clean": "rm -rf dist",
|
|
25
|
+
"test": "bun test",
|
|
26
|
+
"test:watch": "bun test --watch",
|
|
25
27
|
"typecheck": "tsc --noEmit",
|
|
26
28
|
"prepublishOnly": "bun run build && bun run typecheck"
|
|
27
29
|
},
|
|
@@ -52,9 +54,13 @@
|
|
|
52
54
|
},
|
|
53
55
|
"devDependencies": {
|
|
54
56
|
"@assistant-ui/react": "^0.12.10",
|
|
57
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
58
|
+
"@testing-library/react": "^16.3.2",
|
|
59
|
+
"@testing-library/user-event": "^14.6.1",
|
|
55
60
|
"@timbal-ai/timbal-sdk": "0.4.9",
|
|
56
61
|
"@types/react": "^19.2.4",
|
|
57
62
|
"@types/react-dom": "^19.2.3",
|
|
63
|
+
"happy-dom": "^20.8.9",
|
|
58
64
|
"react": "^19.2.0",
|
|
59
65
|
"react-dom": "^19.2.0",
|
|
60
66
|
"tsup": "^8.5.0",
|