@tambo-ai/react 0.29.0 → 0.29.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 +170 -46
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Tambo React SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Tambo allows AI models to dynamically render React components in response to user messages, enabling AI assistants to display interactive widgets, charts, forms, and other UI elements instead of just text. Tambo is a great way to add generative UI to your AI assistant, copilot, or agent.
|
|
4
|
+
|
|
5
|
+
This package provides react hooks to talk to the Tambo API and render custom components inline, but does not provide any UI components on its own. For pre-built UI components that use this package, see [tambo-ui](https://ui.tambo.co).
|
|
4
6
|
|
|
5
7
|
## Build with MCP and Generative UI
|
|
6
8
|
|
|
@@ -8,19 +10,54 @@ A React package for adding generative React UI components to your AI assistant,
|
|
|
8
10
|
|
|
9
11
|
[Source code](https://github.com/tambo-ai/mcp-template)
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
### Creating a new project
|
|
14
|
+
|
|
15
|
+
You can create a new project using our MCP template:
|
|
12
16
|
|
|
13
17
|
```bash
|
|
14
18
|
npx tambo create-app -t mcp tambo-mcp-app
|
|
15
19
|
```
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
This will create a new nextjs project with Tambo pre-configured, and then step you through the process of setting up a Tambo project, including signing up for an API key, and adding it to `.env.local`.
|
|
22
|
+
|
|
23
|
+
### Adding components to an existing project
|
|
24
|
+
|
|
25
|
+
If you have an existing project, you can add components to it. First, initialize your project:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx tambo init
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This will step you through the process of setting up a Tambo project, including signing up for an API key, and adding it to `.env.local`.
|
|
32
|
+
|
|
33
|
+
Then add components from our library to your project in the `components/ui` directory:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx tambo add message-thread-full
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
See the complete component library at [ui.tambo.co](https://ui.tambo.co).
|
|
40
|
+
|
|
41
|
+
### Manual installation
|
|
42
|
+
|
|
43
|
+
You can also install Tambo manually:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install @tambo-ai/react
|
|
47
|
+
# or
|
|
48
|
+
yarn add @tambo-ai/react
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## How does Tambo work?
|
|
18
52
|
|
|
19
|
-
|
|
53
|
+
Tambo uses a client-side registry of React components that can be used by an LLM.
|
|
20
54
|
|
|
21
55
|
### 1. Register your components
|
|
22
56
|
|
|
23
57
|
```tsx
|
|
58
|
+
import { type TamboComponent } from "@tambo-ai/react";
|
|
59
|
+
import { Graph, graphSchema } from "@/components/ui/graph";
|
|
60
|
+
|
|
24
61
|
const components: TamboComponent[] = [
|
|
25
62
|
{
|
|
26
63
|
name: "Graph",
|
|
@@ -35,50 +72,120 @@ const components: TamboComponent[] = [
|
|
|
35
72
|
|
|
36
73
|
### 2. Wrap your app in a TamboProvider
|
|
37
74
|
|
|
75
|
+
If you are using one of Tambo's pre-built components, you can wrap your app in a TamboProvider.
|
|
76
|
+
|
|
38
77
|
```tsx
|
|
78
|
+
import { TamboProvider } from "@tambo-ai/react";
|
|
79
|
+
import { MessageThreadFull } from "@/components/ui/message-thread-full";
|
|
80
|
+
|
|
39
81
|
// In your chat page
|
|
40
82
|
<TamboProvider
|
|
41
83
|
apiKey={process.env.NEXT_PUBLIC_TAMBO_API_KEY!}
|
|
42
84
|
components={components}
|
|
43
85
|
>
|
|
44
|
-
<MessageThreadFull
|
|
45
|
-
</TamboProvider
|
|
86
|
+
<MessageThreadFull />
|
|
87
|
+
</TamboProvider>;
|
|
46
88
|
```
|
|
47
89
|
|
|
48
|
-
|
|
90
|
+
You can also use your own components with the TamboProvider:
|
|
49
91
|
|
|
50
92
|
```tsx
|
|
51
|
-
|
|
93
|
+
import { TamboProvider } from "@tambo-ai/react";
|
|
52
94
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
95
|
+
<TamboProvider
|
|
96
|
+
apiKey={process.env.NEXT_PUBLIC_TAMBO_API_KEY!}
|
|
97
|
+
components={components}
|
|
98
|
+
>
|
|
99
|
+
<YourChatComponents />
|
|
100
|
+
</TamboProvider>;
|
|
57
101
|
```
|
|
58
102
|
|
|
59
|
-
###
|
|
103
|
+
### 3. Render AI-generated components
|
|
104
|
+
|
|
105
|
+
This is also handled automatically for you if you are using the `MessageThreadFull` component.
|
|
106
|
+
|
|
107
|
+
For custom components, you can use the `useMessageContext` hook to get the current message.
|
|
60
108
|
|
|
61
109
|
```tsx
|
|
62
|
-
|
|
110
|
+
import {
|
|
111
|
+
useTambo,
|
|
112
|
+
useMessageContext,
|
|
113
|
+
type TamboThreadMessage,
|
|
114
|
+
} from "@tambo-ai/react";
|
|
115
|
+
|
|
116
|
+
function ChatHistory() {
|
|
117
|
+
const { thread } = useTambo();
|
|
118
|
+
return (
|
|
119
|
+
<div>
|
|
120
|
+
{thread.messages.map((message) => (
|
|
121
|
+
<CustomMessage key={message.id} message={message} />
|
|
122
|
+
))}
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
63
126
|
|
|
64
|
-
|
|
65
|
-
|
|
127
|
+
function CustomMessage({ message }: { message: TamboThreadMessage }) {
|
|
128
|
+
// Render the component
|
|
129
|
+
return (
|
|
130
|
+
<div>
|
|
131
|
+
{/* Render the message content */}
|
|
132
|
+
<div>Role: {message.role}</div>
|
|
133
|
+
<div>
|
|
134
|
+
{message.content.map((part) =>
|
|
135
|
+
part.type === "text" ? (
|
|
136
|
+
<div key={part.id}>{part.text}</div>
|
|
137
|
+
) : (
|
|
138
|
+
<div key={part.id}>Non-text content: {part.type}</div>
|
|
139
|
+
),
|
|
140
|
+
)}
|
|
141
|
+
</div>
|
|
142
|
+
{/* Render the component, if any */}
|
|
143
|
+
<div>{message.renderedComponent}</div>
|
|
144
|
+
</div>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
66
147
|
```
|
|
67
148
|
|
|
68
|
-
|
|
149
|
+
### 4. Submit user messages
|
|
69
150
|
|
|
70
|
-
|
|
151
|
+
If you are using the `MessageThreadFull` component, you can skip this step, it is handled automatically.
|
|
71
152
|
|
|
72
|
-
|
|
153
|
+
If you are using a custom component, you can use the `useTamboThreadInput` hook to submit user messages.
|
|
73
154
|
|
|
74
|
-
|
|
155
|
+
```tsx
|
|
156
|
+
import { useTamboThreadInput } from "@tambo-ai/react";
|
|
75
157
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
158
|
+
function ChatInput() {
|
|
159
|
+
const { submit, value, setValue } = useTamboThreadInput();
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<div>
|
|
163
|
+
<input
|
|
164
|
+
type="text"
|
|
165
|
+
value={value}
|
|
166
|
+
onChange={(e) => setValue(e.target.value)}
|
|
167
|
+
/>
|
|
168
|
+
<button onClick={() => submit()}>Send</button>
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
80
172
|
```
|
|
81
173
|
|
|
174
|
+
### 5. Put it all together
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
function ChatInterface() {
|
|
178
|
+
return (
|
|
179
|
+
<div>
|
|
180
|
+
<ChatHistory />
|
|
181
|
+
<ChatInput />
|
|
182
|
+
</div>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Getting Started
|
|
188
|
+
|
|
82
189
|
### Templates
|
|
83
190
|
|
|
84
191
|
| App | Description |
|
|
@@ -89,11 +196,11 @@ npm run dev
|
|
|
89
196
|
|
|
90
197
|
Check out our UI library [tambo-ui](https://ui.tambo.co) for components that leverage tambo.
|
|
91
198
|
|
|
92
|
-
###
|
|
199
|
+
### In depth examples
|
|
93
200
|
|
|
94
201
|
#### 1. Displaying a message thread:
|
|
95
202
|
|
|
96
|
-
```
|
|
203
|
+
```tsx
|
|
97
204
|
import { useTambo, useTamboThreadInput } from "@tambo-ai/react";
|
|
98
205
|
|
|
99
206
|
function ChatInterface() {
|
|
@@ -107,7 +214,7 @@ function ChatInterface() {
|
|
|
107
214
|
{thread.messages.map((message, index) => (
|
|
108
215
|
<div key={index} className={`message ${message.role}`}>
|
|
109
216
|
<div>{message.content}</div>
|
|
110
|
-
{message.
|
|
217
|
+
{message.renderedComponent}
|
|
111
218
|
</div>
|
|
112
219
|
))}
|
|
113
220
|
</div>
|
|
@@ -137,29 +244,39 @@ function ChatInterface() {
|
|
|
137
244
|
|
|
138
245
|
Create components that can be dynamically generated by the AI:
|
|
139
246
|
|
|
140
|
-
```
|
|
247
|
+
```tsx
|
|
141
248
|
// components/WeatherCard.jsx
|
|
142
249
|
import { useTamboComponentState } from "@tambo-ai/react";
|
|
143
250
|
|
|
144
|
-
export function WeatherCard(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
251
|
+
export function WeatherCard({
|
|
252
|
+
location,
|
|
253
|
+
temperature,
|
|
254
|
+
condition,
|
|
255
|
+
}: {
|
|
256
|
+
location: string;
|
|
257
|
+
temperature: number;
|
|
258
|
+
condition: string;
|
|
259
|
+
}) {
|
|
260
|
+
// useTamboComponentState manages state that persists even if
|
|
261
|
+
// the component is unmounted
|
|
262
|
+
const [isMetric, setIsMetric] = useTamboComponentState(
|
|
263
|
+
"isMetric", // unique identifier for this component's state
|
|
264
|
+
false, // default value
|
|
152
265
|
);
|
|
153
266
|
|
|
154
|
-
if (isPending) {
|
|
155
|
-
return <div>Loading weather data...</div>;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
267
|
return (
|
|
159
268
|
<div>
|
|
160
|
-
<h3>{
|
|
161
|
-
<div>
|
|
162
|
-
|
|
269
|
+
<h3>{location}</h3>
|
|
270
|
+
<div>
|
|
271
|
+
{isMetric ? temperature : (temperature * 1.8 + 32).toFixed(1)}°
|
|
272
|
+
{isMetric ? "C" : "F"}
|
|
273
|
+
</div>
|
|
274
|
+
<div>{condition}</div>
|
|
275
|
+
<input
|
|
276
|
+
type="checkbox"
|
|
277
|
+
checked={isMetric}
|
|
278
|
+
onChange={(e) => setIsMetric(e.target.checked)}
|
|
279
|
+
/>
|
|
163
280
|
</div>
|
|
164
281
|
);
|
|
165
282
|
}
|
|
@@ -167,7 +284,7 @@ export function WeatherCard() {
|
|
|
167
284
|
|
|
168
285
|
#### 3. Register your components:
|
|
169
286
|
|
|
170
|
-
```
|
|
287
|
+
```tsx
|
|
171
288
|
// App.jsx
|
|
172
289
|
import { TamboProvider } from "@tambo-ai/react";
|
|
173
290
|
import { WeatherCard } from "./components/WeatherCard";
|
|
@@ -201,7 +318,11 @@ function App() {
|
|
|
201
318
|
|
|
202
319
|
Register tools to make them available to the AI:
|
|
203
320
|
|
|
204
|
-
```
|
|
321
|
+
```tsx
|
|
322
|
+
import { TamboTool } from "@tambo-ai/react";
|
|
323
|
+
import { z } from "zod";
|
|
324
|
+
|
|
325
|
+
// Define your tools
|
|
205
326
|
const tools: TamboTool[] = [
|
|
206
327
|
{
|
|
207
328
|
name: "getWeather",
|
|
@@ -243,6 +364,9 @@ const tools: TamboTool[] = [
|
|
|
243
364
|
### Using MCP Servers
|
|
244
365
|
|
|
245
366
|
```tsx
|
|
367
|
+
import { TamboProvider } from "@tambo-ai/react";
|
|
368
|
+
import { TamboMcpProvider } from "@tambo-ai/react/mcp";
|
|
369
|
+
|
|
246
370
|
const mcpServers = [
|
|
247
371
|
{
|
|
248
372
|
url: "https://mcp-server-1.com",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tambo-ai/react",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.1",
|
|
4
4
|
"description": "React client package for Tambo AI",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -67,41 +67,41 @@
|
|
|
67
67
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@modelcontextprotocol/sdk": "^1.12.
|
|
70
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
71
71
|
"@tambo-ai/typescript-sdk": "^0.52.0",
|
|
72
|
-
"@tanstack/react-query": "^5.
|
|
72
|
+
"@tanstack/react-query": "^5.80.6",
|
|
73
73
|
"partial-json": "^0.1.7",
|
|
74
74
|
"react-fast-compare": "^3.2.2",
|
|
75
|
-
"ts-essentials": "^10.0
|
|
76
|
-
"use-debounce": "^10.0.
|
|
77
|
-
"zod": "^3.25.
|
|
75
|
+
"ts-essentials": "^10.1.0",
|
|
76
|
+
"use-debounce": "^10.0.5",
|
|
77
|
+
"zod": "^3.25.56",
|
|
78
78
|
"zod-to-json-schema": "^3.24.5"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@eslint/js": "^9.
|
|
81
|
+
"@eslint/js": "^9.28.0",
|
|
82
82
|
"@tambo-ai/eslint-config": "*",
|
|
83
83
|
"@tambo-ai/typescript-config": "*",
|
|
84
84
|
"@testing-library/jest-dom": "^6.4.2",
|
|
85
85
|
"@testing-library/react": "^16.3.0",
|
|
86
86
|
"@types/jest": "^29.5.12",
|
|
87
87
|
"@types/json-schema": "^7.0.15",
|
|
88
|
-
"@types/node": "^20.
|
|
88
|
+
"@types/node": "^20.19.0",
|
|
89
89
|
"@types/react": "^18.3.12",
|
|
90
90
|
"@types/react-dom": "^18.3.5",
|
|
91
91
|
"concurrently": "^9.1.2",
|
|
92
|
-
"eslint": "^9.
|
|
93
|
-
"eslint-plugin-jsdoc": "^50.
|
|
92
|
+
"eslint": "^9.28.0",
|
|
93
|
+
"eslint-plugin-jsdoc": "^50.7.1",
|
|
94
94
|
"eslint-plugin-react": "^7.37.5",
|
|
95
95
|
"eslint-plugin-react-hooks": "^5.1.0",
|
|
96
96
|
"jest": "^29.7.0",
|
|
97
97
|
"jest-environment-jsdom": "^29.7.0",
|
|
98
|
-
"lint-staged": "^16.
|
|
98
|
+
"lint-staged": "^16.1.0",
|
|
99
99
|
"prettier": "^3.4.2",
|
|
100
100
|
"prettier-2": "npm:prettier@^2",
|
|
101
101
|
"react": "^18.3.1",
|
|
102
102
|
"react-dom": "^18.3.1",
|
|
103
103
|
"ts-jest": "^29.3.4",
|
|
104
104
|
"typescript": "^5.8.3",
|
|
105
|
-
"typescript-eslint": "^8.
|
|
105
|
+
"typescript-eslint": "^8.34.0"
|
|
106
106
|
}
|
|
107
107
|
}
|