@lantos1618/better-ui 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +217 -116
- package/dist/ThemeProvider-BYeqWMsn.d.mts +187 -0
- package/dist/ThemeProvider-BaVZaDBO.d.ts +187 -0
- package/dist/auth/index.d.mts +56 -0
- package/dist/auth/index.d.ts +56 -0
- package/dist/auth/index.js +104 -0
- package/dist/auth/index.mjs +67 -0
- package/dist/chunk-Y6FXYEAI.mjs +10 -0
- package/dist/components/index.d.mts +258 -0
- package/dist/components/index.d.ts +258 -0
- package/dist/components/index.js +1977 -0
- package/dist/components/index.mjs +1922 -0
- package/dist/index.d.mts +57 -296
- package/dist/index.d.ts +57 -296
- package/dist/index.js +243 -178
- package/dist/index.mjs +241 -175
- package/dist/persistence/index.d.mts +11 -0
- package/dist/persistence/index.d.ts +11 -0
- package/dist/persistence/index.js +66 -0
- package/dist/persistence/index.mjs +41 -0
- package/dist/react/index.d.mts +91 -0
- package/dist/react/index.d.ts +91 -0
- package/dist/react/index.js +284 -0
- package/dist/react/index.mjs +257 -0
- package/dist/tool-Ca2x-VNK.d.mts +361 -0
- package/dist/tool-Ca2x-VNK.d.ts +361 -0
- package/dist/types-CAOfGUPH.d.mts +31 -0
- package/dist/types-CAOfGUPH.d.ts +31 -0
- package/package.json +42 -20
- package/src/theme.css +101 -0
package/README.md
CHANGED
|
@@ -10,7 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
Better UI provides a clean, fluent API for creating tools that AI assistants can execute. Define input/output schemas with Zod, implement server and client logic separately, and render results with React components.
|
|
12
12
|
|
|
13
|
-
**Key
|
|
13
|
+
**Key differentiators**:
|
|
14
|
+
- **View integration** - tools render their own results in UI (no other framework does this)
|
|
15
|
+
- **Multi-provider support** - OpenAI, Anthropic, Google Gemini, OpenRouter
|
|
16
|
+
- **Streaming tool views** - progressive partial data rendering
|
|
17
|
+
- **Pre-made chat components** - drop-in `<Chat />` with automatic tool view rendering
|
|
18
|
+
- **Server infrastructure** - rate limiting, caching, Next.js/Express adapters
|
|
14
19
|
|
|
15
20
|
## Installation
|
|
16
21
|
|
|
@@ -40,12 +45,127 @@ weather.server(async ({ city }) => {
|
|
|
40
45
|
// View for rendering results (our differentiator!)
|
|
41
46
|
weather.view((data) => (
|
|
42
47
|
<div className="weather-card">
|
|
43
|
-
<span>{data.temp}
|
|
48
|
+
<span>{data.temp}</span>
|
|
44
49
|
<span>{data.condition}</span>
|
|
45
50
|
</div>
|
|
46
51
|
));
|
|
47
52
|
```
|
|
48
53
|
|
|
54
|
+
## Drop-in Chat UI
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { Chat } from '@lantos1618/better-ui/components';
|
|
58
|
+
|
|
59
|
+
function App() {
|
|
60
|
+
return (
|
|
61
|
+
<Chat
|
|
62
|
+
endpoint="/api/chat"
|
|
63
|
+
tools={{ weather, search, counter }}
|
|
64
|
+
className="h-[600px]"
|
|
65
|
+
placeholder="Ask something..."
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Or compose your own layout:
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { ChatProvider, Thread, Composer } from '@lantos1618/better-ui/components';
|
|
75
|
+
|
|
76
|
+
function App() {
|
|
77
|
+
return (
|
|
78
|
+
<ChatProvider endpoint="/api/chat" tools={tools}>
|
|
79
|
+
<div className="flex flex-col h-screen">
|
|
80
|
+
<Thread className="flex-1 overflow-y-auto" />
|
|
81
|
+
<Composer placeholder="Type a message..." />
|
|
82
|
+
</div>
|
|
83
|
+
</ChatProvider>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Tool results in chat automatically render using the tool's `.view()` component.
|
|
89
|
+
|
|
90
|
+
## Multi-Provider Support
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { createProvider } from '@lantos1618/better-ui';
|
|
94
|
+
|
|
95
|
+
// OpenAI
|
|
96
|
+
const provider = createProvider({ provider: 'openai', model: 'gpt-4o' });
|
|
97
|
+
|
|
98
|
+
// Anthropic
|
|
99
|
+
const provider = createProvider({ provider: 'anthropic', model: 'claude-4-sonnet' });
|
|
100
|
+
|
|
101
|
+
// Google Gemini
|
|
102
|
+
const provider = createProvider({ provider: 'google', model: 'gemini-2.5-pro' });
|
|
103
|
+
|
|
104
|
+
// OpenRouter (access any model)
|
|
105
|
+
const provider = createProvider({
|
|
106
|
+
provider: 'openrouter',
|
|
107
|
+
model: 'anthropic/claude-4-sonnet',
|
|
108
|
+
apiKey: process.env.OPENROUTER_API_KEY,
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Use with the chat handler:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { streamText, convertToModelMessages } from 'ai';
|
|
116
|
+
import { createProvider } from '@lantos1618/better-ui';
|
|
117
|
+
|
|
118
|
+
const provider = createProvider({ provider: 'openai', model: 'gpt-4o' });
|
|
119
|
+
|
|
120
|
+
export async function POST(req: Request) {
|
|
121
|
+
const { messages } = await req.json();
|
|
122
|
+
const result = streamText({
|
|
123
|
+
model: provider.model(),
|
|
124
|
+
messages: convertToModelMessages(messages),
|
|
125
|
+
tools: {
|
|
126
|
+
weather: weatherTool.toAITool(),
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
return result.toUIMessageStreamResponse();
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Streaming Tool Views
|
|
134
|
+
|
|
135
|
+
Tools can stream partial results progressively:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { useToolStream } from '@lantos1618/better-ui';
|
|
139
|
+
|
|
140
|
+
// Define a streaming tool
|
|
141
|
+
const analysis = tool({
|
|
142
|
+
name: 'analysis',
|
|
143
|
+
input: z.object({ query: z.string() }),
|
|
144
|
+
output: z.object({ summary: z.string(), score: z.number() }),
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
analysis.stream(async ({ query }, { stream }) => {
|
|
148
|
+
stream({ summary: 'Analyzing...' }); // Partial update
|
|
149
|
+
const result = await analyzeData(query);
|
|
150
|
+
stream({ summary: result.summary }); // More data
|
|
151
|
+
return { summary: result.summary, score: result.score }; // Final
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// In a component:
|
|
155
|
+
function AnalysisWidget({ query }) {
|
|
156
|
+
const { data, streaming, loading, execute } = useToolStream(analysis);
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<div>
|
|
160
|
+
<button onClick={() => execute({ query })}>Analyze</button>
|
|
161
|
+
{loading && <p>Starting...</p>}
|
|
162
|
+
{streaming && <p>Streaming: {data?.summary}</p>}
|
|
163
|
+
{data?.score && <p>Score: {data.score}</p>}
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
49
169
|
## Core Concepts
|
|
50
170
|
|
|
51
171
|
### 1. Tool Definition
|
|
@@ -79,7 +199,6 @@ The `.client()` method defines what happens when called from the browser. If not
|
|
|
79
199
|
|
|
80
200
|
```typescript
|
|
81
201
|
myTool.client(async ({ query }, ctx) => {
|
|
82
|
-
// Custom client logic: caching, optimistic updates, etc.
|
|
83
202
|
const cached = ctx.cache.get(query);
|
|
84
203
|
if (cached) return cached;
|
|
85
204
|
|
|
@@ -95,13 +214,27 @@ myTool.client(async ({ query }, ctx) => {
|
|
|
95
214
|
The `.view()` method defines how to render the tool's results:
|
|
96
215
|
|
|
97
216
|
```typescript
|
|
98
|
-
myTool.view((data, { loading, error }) => {
|
|
217
|
+
myTool.view((data, { loading, error, streaming }) => {
|
|
99
218
|
if (loading) return <Spinner />;
|
|
100
219
|
if (error) return <Error message={error.message} />;
|
|
220
|
+
if (streaming) return <PartialResults data={data} />;
|
|
101
221
|
return <Results items={data.results} />;
|
|
102
222
|
});
|
|
103
223
|
```
|
|
104
224
|
|
|
225
|
+
### 5. Streaming
|
|
226
|
+
|
|
227
|
+
The `.stream()` method enables progressive partial updates:
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
myTool.stream(async ({ query }, { stream }) => {
|
|
231
|
+
stream({ status: 'searching...' });
|
|
232
|
+
const results = await search(query);
|
|
233
|
+
stream({ results, status: 'done' });
|
|
234
|
+
return { results, status: 'done', count: results.length };
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
105
238
|
## Fluent Builder Alternative
|
|
106
239
|
|
|
107
240
|
```typescript
|
|
@@ -110,152 +243,119 @@ const search = tool('search')
|
|
|
110
243
|
.input(z.object({ query: z.string() }))
|
|
111
244
|
.output(z.object({ results: z.array(z.string()) }))
|
|
112
245
|
.server(async ({ query }) => ({ results: await db.search(query) }))
|
|
246
|
+
.stream(async ({ query }, { stream }) => {
|
|
247
|
+
stream({ results: [] });
|
|
248
|
+
const results = await db.search(query);
|
|
249
|
+
return { results };
|
|
250
|
+
})
|
|
113
251
|
.view((data) => <ResultsList items={data.results} />);
|
|
114
252
|
```
|
|
115
253
|
|
|
116
|
-
## React
|
|
254
|
+
## React Hooks
|
|
255
|
+
|
|
256
|
+
### `useTool(tool, input?, options?)`
|
|
117
257
|
|
|
118
258
|
```typescript
|
|
119
259
|
import { useTool } from '@lantos1618/better-ui';
|
|
120
260
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Or with auto-execution
|
|
135
|
-
function WeatherWidget({ city }) {
|
|
136
|
-
const { data, loading } = useTool(weather, { city }, { auto: true });
|
|
137
|
-
return <weather.View data={data} loading={loading} />;
|
|
138
|
-
}
|
|
261
|
+
const {
|
|
262
|
+
data, // Result data
|
|
263
|
+
loading, // Loading state
|
|
264
|
+
error, // Error if any
|
|
265
|
+
execute, // Execute function
|
|
266
|
+
reset, // Reset state
|
|
267
|
+
executed, // Has been executed
|
|
268
|
+
} = useTool(myTool, initialInput, {
|
|
269
|
+
auto: false,
|
|
270
|
+
onSuccess: (data) => {},
|
|
271
|
+
onError: (error) => {},
|
|
272
|
+
});
|
|
139
273
|
```
|
|
140
274
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
### With Vercel AI SDK
|
|
275
|
+
### `useToolStream(tool, options?)`
|
|
144
276
|
|
|
145
277
|
```typescript
|
|
146
|
-
import {
|
|
147
|
-
import { openai } from '@ai-sdk/openai';
|
|
148
|
-
|
|
149
|
-
export async function POST(req: Request) {
|
|
150
|
-
const { messages } = await req.json();
|
|
278
|
+
import { useToolStream } from '@lantos1618/better-ui';
|
|
151
279
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return result.toDataStreamResponse();
|
|
162
|
-
}
|
|
280
|
+
const {
|
|
281
|
+
data, // Progressive partial data
|
|
282
|
+
finalData, // Complete validated data (when done)
|
|
283
|
+
streaming, // True while receiving partial updates
|
|
284
|
+
loading, // True before first chunk
|
|
285
|
+
error,
|
|
286
|
+
execute,
|
|
287
|
+
reset,
|
|
288
|
+
} = useToolStream(myTool);
|
|
163
289
|
```
|
|
164
290
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
### `tool(config)` or `tool(name)`
|
|
168
|
-
|
|
169
|
-
Create a new tool with object config or fluent builder.
|
|
291
|
+
### `useTools(tools, options?)`
|
|
170
292
|
|
|
171
293
|
```typescript
|
|
172
|
-
|
|
173
|
-
const t = tool({
|
|
174
|
-
name: string,
|
|
175
|
-
description?: string,
|
|
176
|
-
input: ZodSchema,
|
|
177
|
-
output?: ZodSchema,
|
|
178
|
-
tags?: string[],
|
|
179
|
-
cache?: { ttl: number, key?: (input) => string },
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
// Fluent builder
|
|
183
|
-
const t = tool('name')
|
|
184
|
-
.description(string)
|
|
185
|
-
.input(ZodSchema)
|
|
186
|
-
.output(ZodSchema)
|
|
187
|
-
.tags(...string[])
|
|
188
|
-
.cache({ ttl, key? });
|
|
189
|
-
```
|
|
294
|
+
import { useTools } from '@lantos1618/better-ui';
|
|
190
295
|
|
|
191
|
-
|
|
296
|
+
const tools = useTools({ weather, search });
|
|
192
297
|
|
|
193
|
-
|
|
298
|
+
await tools.weather.execute({ city: 'London' });
|
|
299
|
+
await tools.search.execute({ query: 'restaurants' });
|
|
194
300
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
// ctx.env, ctx.headers, ctx.user, ctx.session available
|
|
198
|
-
return result;
|
|
199
|
-
});
|
|
301
|
+
tools.weather.data; // Weather result
|
|
302
|
+
tools.search.loading; // Search loading state
|
|
200
303
|
```
|
|
201
304
|
|
|
202
|
-
|
|
305
|
+
## Chat Components
|
|
203
306
|
|
|
204
|
-
|
|
307
|
+
Import from `@lantos1618/better-ui/components`:
|
|
205
308
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
309
|
+
| Component | Description |
|
|
310
|
+
|-----------|-------------|
|
|
311
|
+
| `Chat` | All-in-one chat component (ChatProvider + Thread + Composer) |
|
|
312
|
+
| `ChatProvider` | Context provider wrapping AI SDK's `useChat` |
|
|
313
|
+
| `Thread` | Message list with auto-scroll |
|
|
314
|
+
| `Message` | Single message with automatic tool view rendering |
|
|
315
|
+
| `Composer` | Input form with send button |
|
|
316
|
+
| `ToolResult` | Renders a tool's `.View` in chat context |
|
|
212
317
|
|
|
213
|
-
|
|
318
|
+
All components accept `className` for styling customization.
|
|
214
319
|
|
|
215
|
-
|
|
320
|
+
## Providers
|
|
216
321
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
322
|
+
| Provider | Package Required | Example Model |
|
|
323
|
+
|----------|-----------------|---------------|
|
|
324
|
+
| OpenAI | `@ai-sdk/openai` (included) | `gpt-4o`, `gpt-5.2` |
|
|
325
|
+
| Anthropic | `@ai-sdk/anthropic` (optional) | `claude-4-sonnet` |
|
|
326
|
+
| Google | `@ai-sdk/google` (optional) | `gemini-2.5-pro` |
|
|
327
|
+
| OpenRouter | `@ai-sdk/openai` (included) | `anthropic/claude-4-sonnet` |
|
|
220
328
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
```typescript
|
|
226
|
-
const {
|
|
227
|
-
data, // Result data
|
|
228
|
-
loading, // Loading state
|
|
229
|
-
error, // Error if any
|
|
230
|
-
execute, // Execute function
|
|
231
|
-
reset, // Reset state
|
|
232
|
-
executed, // Has been executed
|
|
233
|
-
} = useTool(myTool, initialInput, {
|
|
234
|
-
auto: false, // Auto-execute on mount
|
|
235
|
-
onSuccess: (data) => {},
|
|
236
|
-
onError: (error) => {},
|
|
237
|
-
});
|
|
329
|
+
```bash
|
|
330
|
+
# Optional providers
|
|
331
|
+
npm install @ai-sdk/anthropic # For Anthropic
|
|
332
|
+
npm install @ai-sdk/google # For Google Gemini
|
|
238
333
|
```
|
|
239
334
|
|
|
240
335
|
## Project Structure
|
|
241
336
|
|
|
242
337
|
```
|
|
243
338
|
src/
|
|
244
|
-
tool.tsx
|
|
339
|
+
tool.tsx # Core tool() API with streaming
|
|
245
340
|
react/
|
|
246
|
-
useTool.ts
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
341
|
+
useTool.ts # React hooks (useTool, useTools)
|
|
342
|
+
useToolStream.ts # Streaming hook
|
|
343
|
+
components/
|
|
344
|
+
Chat.tsx # All-in-one chat component
|
|
345
|
+
ChatProvider.tsx # Chat context provider
|
|
346
|
+
Thread.tsx # Message list
|
|
347
|
+
Message.tsx # Single message
|
|
348
|
+
Composer.tsx # Input form
|
|
349
|
+
ToolResult.tsx # Tool view renderer
|
|
350
|
+
providers/
|
|
351
|
+
openai.ts # OpenAI adapter
|
|
352
|
+
anthropic.ts # Anthropic adapter
|
|
353
|
+
google.ts # Google Gemini adapter
|
|
354
|
+
openrouter.ts # OpenRouter adapter
|
|
355
|
+
adapters/
|
|
356
|
+
nextjs.ts # Next.js route handlers
|
|
357
|
+
express.ts # Express middleware
|
|
358
|
+
index.ts # Main exports
|
|
259
359
|
```
|
|
260
360
|
|
|
261
361
|
## Development
|
|
@@ -266,6 +366,7 @@ npm run dev # Run dev server
|
|
|
266
366
|
npm run build:lib # Build library
|
|
267
367
|
npm run build # Build everything
|
|
268
368
|
npm run type-check # TypeScript check
|
|
369
|
+
npm test # Run tests
|
|
269
370
|
```
|
|
270
371
|
|
|
271
372
|
## License
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { UIMessage, ChatStatus } from 'ai';
|
|
4
|
+
import { T as Tool } from './tool-Ca2x-VNK.mjs';
|
|
5
|
+
import { P as PersistenceAdapter, T as Thread$1 } from './types-CAOfGUPH.mjs';
|
|
6
|
+
|
|
7
|
+
interface ToolStateEntry {
|
|
8
|
+
output: unknown;
|
|
9
|
+
loading: boolean;
|
|
10
|
+
error: string | null;
|
|
11
|
+
version: number;
|
|
12
|
+
toolName?: string;
|
|
13
|
+
/** HITL confirmation status */
|
|
14
|
+
status?: 'pending' | 'confirmed' | 'rejected';
|
|
15
|
+
/** Entity group key — "toolName:groupKey(input)" — groups related calls */
|
|
16
|
+
entityId?: string;
|
|
17
|
+
/** Raw tool input, stored for conditional confirm checks */
|
|
18
|
+
toolInput?: unknown;
|
|
19
|
+
/** Auto-incrementing insertion order (store-assigned) */
|
|
20
|
+
seqNo?: number;
|
|
21
|
+
}
|
|
22
|
+
interface ToolStateStore {
|
|
23
|
+
get: (toolCallId: string) => ToolStateEntry | undefined;
|
|
24
|
+
set: (toolCallId: string, entry: ToolStateEntry) => void;
|
|
25
|
+
/** Remove all entries (e.g. when switching threads) */
|
|
26
|
+
clear: () => void;
|
|
27
|
+
subscribe: (toolCallId: string, listener: () => void) => () => void;
|
|
28
|
+
subscribeAll: (listener: () => void) => () => void;
|
|
29
|
+
getSnapshot: () => Map<string, ToolStateEntry>;
|
|
30
|
+
/** Returns Map with highest-seqNo entry per entityId + all ungrouped entries */
|
|
31
|
+
getLatestPerEntity: () => Map<string, ToolStateEntry>;
|
|
32
|
+
/** Returns the oldest (lowest seqNo) entry with the given entityId — the "anchor" */
|
|
33
|
+
findAnchor: (entityId: string) => {
|
|
34
|
+
toolCallId: string;
|
|
35
|
+
entry: ToolStateEntry;
|
|
36
|
+
} | undefined;
|
|
37
|
+
}
|
|
38
|
+
declare function createToolStateStore(): ToolStateStore;
|
|
39
|
+
declare function useToolState(store: ToolStateStore, toolCallId: string): ToolStateEntry | undefined;
|
|
40
|
+
|
|
41
|
+
/** Parsed tool part from a UIMessage */
|
|
42
|
+
interface ToolPartInfo {
|
|
43
|
+
toolName: string;
|
|
44
|
+
toolCallId: string;
|
|
45
|
+
state: string;
|
|
46
|
+
output: unknown;
|
|
47
|
+
}
|
|
48
|
+
interface ChatContextValue {
|
|
49
|
+
messages: UIMessage[];
|
|
50
|
+
sendMessage: (text: string) => void;
|
|
51
|
+
isLoading: boolean;
|
|
52
|
+
status: ChatStatus;
|
|
53
|
+
tools: Record<string, Tool>;
|
|
54
|
+
executeToolDirect: (toolName: string, toolInput: Record<string, unknown>, toolCallId: string) => Promise<void>;
|
|
55
|
+
getOnAction: (toolCallId: string, toolName: string) => (input: Record<string, unknown>) => void;
|
|
56
|
+
toolStateStore: ToolStateStore;
|
|
57
|
+
/** Approve and execute a HITL tool, then feed result back to AI */
|
|
58
|
+
confirmTool: (toolCallId: string, toolName: string, toolInput: Record<string, unknown>) => Promise<void>;
|
|
59
|
+
/** Reject a HITL tool and notify AI */
|
|
60
|
+
rejectTool: (toolCallId: string, toolName: string) => Promise<void>;
|
|
61
|
+
/** Retry a failed tool execution */
|
|
62
|
+
retryTool: (toolCallId: string, toolName: string, toolInput: unknown) => void;
|
|
63
|
+
/** Available threads (only when persistence is configured) */
|
|
64
|
+
threads?: Thread$1[];
|
|
65
|
+
/** Current thread ID */
|
|
66
|
+
threadId?: string;
|
|
67
|
+
/** Create a new thread (only when persistence is configured) */
|
|
68
|
+
createThread?: (title?: string) => Promise<Thread$1>;
|
|
69
|
+
/** Switch to a different thread (only when persistence is configured) */
|
|
70
|
+
switchThread?: (threadId: string) => Promise<void>;
|
|
71
|
+
/** Delete a thread (only when persistence is configured) */
|
|
72
|
+
deleteThread?: (threadId: string) => Promise<void>;
|
|
73
|
+
}
|
|
74
|
+
interface ChatProviderProps {
|
|
75
|
+
endpoint?: string;
|
|
76
|
+
tools: Record<string, Tool>;
|
|
77
|
+
toolStateStore?: ToolStateStore;
|
|
78
|
+
/** Persistence adapter for thread/message storage */
|
|
79
|
+
persistence?: PersistenceAdapter;
|
|
80
|
+
/** Active thread ID (used with persistence) */
|
|
81
|
+
threadId?: string;
|
|
82
|
+
children: React.ReactNode;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Hook to access chat context. Must be used within a ChatProvider.
|
|
86
|
+
*/
|
|
87
|
+
declare function useChatContext(): ChatContextValue;
|
|
88
|
+
declare function ChatProvider({ endpoint, tools, toolStateStore: externalStore, persistence, threadId, children }: ChatProviderProps): react_jsx_runtime.JSX.Element;
|
|
89
|
+
|
|
90
|
+
interface ThreadProps {
|
|
91
|
+
className?: string;
|
|
92
|
+
emptyMessage?: string;
|
|
93
|
+
suggestions?: string[];
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Message list with auto-scroll.
|
|
97
|
+
* Renders messages from ChatContext, maps over messages, renders text parts and tool parts.
|
|
98
|
+
*/
|
|
99
|
+
declare function Thread({ className, emptyMessage, suggestions }: ThreadProps): react_jsx_runtime.JSX.Element;
|
|
100
|
+
|
|
101
|
+
interface MessageProps {
|
|
102
|
+
message: UIMessage;
|
|
103
|
+
tools: Record<string, Tool>;
|
|
104
|
+
toolStateStore: ToolStateStore;
|
|
105
|
+
getOnAction: (toolCallId: string, toolName: string) => (input: Record<string, unknown>) => void;
|
|
106
|
+
onConfirm?: (toolCallId: string, toolName: string, toolInput: Record<string, unknown>) => void;
|
|
107
|
+
onReject?: (toolCallId: string, toolName: string) => void;
|
|
108
|
+
onRetry?: (toolCallId: string, toolName: string, toolInput: unknown) => void;
|
|
109
|
+
className?: string;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Renders a single UIMessage.
|
|
113
|
+
* - User messages: right-aligned bubble (plain text)
|
|
114
|
+
* - Assistant messages: left-aligned bubble (rendered markdown)
|
|
115
|
+
* - Tool parts: renders tool.View automatically
|
|
116
|
+
*/
|
|
117
|
+
declare function Message({ message, tools, toolStateStore, getOnAction, onConfirm, onReject, onRetry, className }: MessageProps): react_jsx_runtime.JSX.Element | null;
|
|
118
|
+
|
|
119
|
+
interface ComposerProps {
|
|
120
|
+
className?: string;
|
|
121
|
+
placeholder?: string;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Input form with text input and send button.
|
|
125
|
+
* Uses ChatContext to send messages. Disabled during loading.
|
|
126
|
+
*/
|
|
127
|
+
declare function Composer({ className, placeholder }: ComposerProps): react_jsx_runtime.JSX.Element;
|
|
128
|
+
|
|
129
|
+
interface ToolResultProps {
|
|
130
|
+
toolName: string;
|
|
131
|
+
toolCallId: string;
|
|
132
|
+
output: unknown;
|
|
133
|
+
toolInput?: unknown;
|
|
134
|
+
hasResult: boolean;
|
|
135
|
+
/** Tool part state from the AI SDK (e.g. 'partial-call', 'call', 'output-available') */
|
|
136
|
+
toolPartState?: string;
|
|
137
|
+
toolStateStore: ToolStateStore;
|
|
138
|
+
tools: Record<string, Tool>;
|
|
139
|
+
getOnAction: (toolCallId: string, toolName: string) => (input: Record<string, unknown>) => void;
|
|
140
|
+
onConfirm?: (toolCallId: string, toolName: string, toolInput: Record<string, unknown>) => void;
|
|
141
|
+
onReject?: (toolCallId: string, toolName: string) => void;
|
|
142
|
+
onRetry?: (toolCallId: string, toolName: string, toolInput: unknown) => void;
|
|
143
|
+
className?: string;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Renders a tool's View component given tool name and output.
|
|
147
|
+
* Uses the tool state store for in-place updates (e.g. counter clicks),
|
|
148
|
+
* falling back to message part state.
|
|
149
|
+
*
|
|
150
|
+
* For HITL tools (confirm: true), renders a confirmation card when
|
|
151
|
+
* the tool is awaiting user approval.
|
|
152
|
+
*
|
|
153
|
+
* Supports groupKey-based in-place updates: when an older call (anchor) with
|
|
154
|
+
* the same entityId exists, followup calls update the anchor's data and render nothing.
|
|
155
|
+
*/
|
|
156
|
+
declare function ToolResult({ toolName, toolCallId, output, toolInput, hasResult, toolPartState, toolStateStore, tools, getOnAction, onConfirm, onReject, onRetry, className, }: ToolResultProps): react_jsx_runtime.JSX.Element | null;
|
|
157
|
+
|
|
158
|
+
interface ChatProps {
|
|
159
|
+
endpoint?: string;
|
|
160
|
+
tools: Record<string, Tool>;
|
|
161
|
+
className?: string;
|
|
162
|
+
placeholder?: string;
|
|
163
|
+
emptyMessage?: string;
|
|
164
|
+
suggestions?: string[];
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Convenience all-in-one chat component.
|
|
168
|
+
* Combines ChatProvider + Thread + Composer into a single drop-in component.
|
|
169
|
+
*/
|
|
170
|
+
declare function Chat({ endpoint, tools, className, placeholder, emptyMessage, suggestions, }: ChatProps): react_jsx_runtime.JSX.Element;
|
|
171
|
+
|
|
172
|
+
interface ThemeProviderProps {
|
|
173
|
+
/** Theme name — sets data-theme attribute. Default: 'dark' */
|
|
174
|
+
theme?: string;
|
|
175
|
+
/** Override individual CSS variables */
|
|
176
|
+
variables?: Record<string, string>;
|
|
177
|
+
/** Additional CSS class */
|
|
178
|
+
className?: string;
|
|
179
|
+
children: React.ReactNode;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Wraps children with a themed container.
|
|
183
|
+
* Sets `data-theme` for CSS variable scoping and applies inline variable overrides.
|
|
184
|
+
*/
|
|
185
|
+
declare function ThemeProvider({ theme, variables, className, children, }: ThemeProviderProps): react_jsx_runtime.JSX.Element;
|
|
186
|
+
|
|
187
|
+
export { type ChatProviderProps as C, type MessageProps as M, type ToolPartInfo as T, type ThreadProps as a, type ComposerProps as b, type ToolResultProps as c, type ChatProps as d, type ThemeProviderProps as e, type ToolStateStore as f, type ToolStateEntry as g, ChatProvider as h, Thread as i, Message as j, Composer as k, ToolResult as l, Chat as m, createToolStateStore as n, useToolState as o, ThemeProvider as p, useChatContext as u };
|