@base44-preview/sdk 0.7.0-dev.e78162e → 0.7.0-pr.26.ab75236
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 +549 -100
- package/dist/client.d.ts +63 -0
- package/dist/client.js +15 -7
- package/dist/index.d.ts +1 -0
- package/dist/modules/agents.d.ts +85 -0
- package/dist/modules/agents.js +251 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,15 +15,15 @@ yarn add @base44/sdk
|
|
|
15
15
|
### Basic Setup
|
|
16
16
|
|
|
17
17
|
```javascript
|
|
18
|
-
import { createClient } from
|
|
18
|
+
import { createClient } from "@base44/sdk";
|
|
19
19
|
|
|
20
20
|
// Create a client instance
|
|
21
21
|
const base44 = createClient({
|
|
22
|
-
serverUrl:
|
|
23
|
-
appId:
|
|
24
|
-
token:
|
|
25
|
-
serviceToken:
|
|
26
|
-
autoInitAuth: true,
|
|
22
|
+
serverUrl: "https://base44.app", // Optional, defaults to 'https://base44.app'
|
|
23
|
+
appId: "your-app-id", // Required
|
|
24
|
+
token: "your-user-token", // Optional, for user authentication
|
|
25
|
+
serviceToken: "your-service-token", // Optional, for service role authentication
|
|
26
|
+
autoInitAuth: true, // Optional, defaults to true - auto-detects tokens from URL or localStorage
|
|
27
27
|
});
|
|
28
28
|
```
|
|
29
29
|
|
|
@@ -35,31 +35,31 @@ const products = await base44.entities.Product.list();
|
|
|
35
35
|
|
|
36
36
|
// Filter products by category
|
|
37
37
|
const filteredProducts = await base44.entities.Product.filter({
|
|
38
|
-
category: [
|
|
38
|
+
category: ["electronics", "computers"],
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
// Get a specific product
|
|
42
|
-
const product = await base44.entities.Product.get(
|
|
42
|
+
const product = await base44.entities.Product.get("product-id");
|
|
43
43
|
|
|
44
44
|
// Create a new product
|
|
45
45
|
const newProduct = await base44.entities.Product.create({
|
|
46
|
-
name:
|
|
46
|
+
name: "New Product",
|
|
47
47
|
price: 99.99,
|
|
48
|
-
category:
|
|
48
|
+
category: "electronics",
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
// Update a product
|
|
52
|
-
const updatedProduct = await base44.entities.Product.update(
|
|
53
|
-
price: 89.99
|
|
52
|
+
const updatedProduct = await base44.entities.Product.update("product-id", {
|
|
53
|
+
price: 89.99,
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
// Delete a product
|
|
57
|
-
await base44.entities.Product.delete(
|
|
57
|
+
await base44.entities.Product.delete("product-id");
|
|
58
58
|
|
|
59
59
|
// Bulk create products
|
|
60
60
|
const newProducts = await base44.entities.Product.bulkCreate([
|
|
61
|
-
{ name:
|
|
62
|
-
{ name:
|
|
61
|
+
{ name: "Product 1", price: 19.99 },
|
|
62
|
+
{ name: "Product 2", price: 29.99 },
|
|
63
63
|
]);
|
|
64
64
|
```
|
|
65
65
|
|
|
@@ -68,13 +68,13 @@ const newProducts = await base44.entities.Product.bulkCreate([
|
|
|
68
68
|
Service role authentication allows server-side applications to perform operations with elevated privileges. This is useful for administrative tasks, background jobs, and server-to-server communication.
|
|
69
69
|
|
|
70
70
|
```javascript
|
|
71
|
-
import { createClient } from
|
|
71
|
+
import { createClient } from "@base44/sdk";
|
|
72
72
|
|
|
73
73
|
// Create a client with service role token
|
|
74
74
|
const base44 = createClient({
|
|
75
|
-
appId:
|
|
76
|
-
token:
|
|
77
|
-
serviceToken:
|
|
75
|
+
appId: "your-app-id",
|
|
76
|
+
token: "user-token", // For user operations
|
|
77
|
+
serviceToken: "service-token", // For service role operations
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
// User operations (uses user token)
|
|
@@ -90,7 +90,7 @@ const allEntities = await base44.asServiceRole.entities.User.list();
|
|
|
90
90
|
// Note: Service role does NOT have access to auth module for security
|
|
91
91
|
|
|
92
92
|
// If no service token is provided, accessing asServiceRole throws an error
|
|
93
|
-
const clientWithoutService = createClient({ appId:
|
|
93
|
+
const clientWithoutService = createClient({ appId: "your-app-id" });
|
|
94
94
|
try {
|
|
95
95
|
await clientWithoutService.asServiceRole.entities.User.list();
|
|
96
96
|
} catch (error) {
|
|
@@ -103,20 +103,20 @@ try {
|
|
|
103
103
|
For server-side applications, you can create a client from incoming HTTP requests:
|
|
104
104
|
|
|
105
105
|
```javascript
|
|
106
|
-
import { createClientFromRequest } from
|
|
106
|
+
import { createClientFromRequest } from "@base44/sdk";
|
|
107
107
|
|
|
108
108
|
// In your server handler (Express, Next.js, etc.)
|
|
109
|
-
app.get(
|
|
109
|
+
app.get("/api/data", async (req, res) => {
|
|
110
110
|
try {
|
|
111
111
|
// Extract client configuration from request headers
|
|
112
112
|
const base44 = createClientFromRequest(req);
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
// Headers used:
|
|
115
115
|
// - Authorization: Bearer <user-token>
|
|
116
116
|
// - Base44-Service-Authorization: Bearer <service-token>
|
|
117
117
|
// - Base44-App-Id: <app-id>
|
|
118
118
|
// - Base44-Api-Url: <custom-api-url> (optional)
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
// Use appropriate authentication based on available tokens
|
|
121
121
|
let data;
|
|
122
122
|
if (base44.asServiceRole) {
|
|
@@ -126,7 +126,7 @@ app.get('/api/data', async (req, res) => {
|
|
|
126
126
|
// Only user token available - use user permissions
|
|
127
127
|
data = await base44.entities.PublicData.list();
|
|
128
128
|
}
|
|
129
|
-
|
|
129
|
+
|
|
130
130
|
res.json(data);
|
|
131
131
|
} catch (error) {
|
|
132
132
|
res.status(500).json({ error: error.message });
|
|
@@ -139,15 +139,15 @@ app.get('/api/data', async (req, res) => {
|
|
|
139
139
|
```javascript
|
|
140
140
|
// Send an email using the Core integration
|
|
141
141
|
const emailResult = await base44.integrations.Core.SendEmail({
|
|
142
|
-
to:
|
|
143
|
-
subject:
|
|
144
|
-
body:
|
|
142
|
+
to: "user@example.com",
|
|
143
|
+
subject: "Hello from Base44",
|
|
144
|
+
body: "This is a test email sent via the Base44 SDK",
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
// Use a custom integration
|
|
148
148
|
const result = await base44.integrations.CustomPackage.CustomEndpoint({
|
|
149
|
-
param1:
|
|
150
|
-
param2:
|
|
149
|
+
param1: "value1",
|
|
150
|
+
param2: "value2",
|
|
151
151
|
});
|
|
152
152
|
|
|
153
153
|
// Upload a file
|
|
@@ -155,7 +155,7 @@ const fileInput = document.querySelector('input[type="file"]');
|
|
|
155
155
|
const file = fileInput.files[0];
|
|
156
156
|
const uploadResult = await base44.integrations.Core.UploadFile({
|
|
157
157
|
file,
|
|
158
|
-
metadata: { type:
|
|
158
|
+
metadata: { type: "profile-picture" },
|
|
159
159
|
});
|
|
160
160
|
```
|
|
161
161
|
|
|
@@ -168,45 +168,49 @@ The SDK provides comprehensive authentication capabilities to help you build sec
|
|
|
168
168
|
To create a client with authentication:
|
|
169
169
|
|
|
170
170
|
```javascript
|
|
171
|
-
import { createClient } from
|
|
172
|
-
import { getAccessToken } from
|
|
171
|
+
import { createClient } from "@base44/sdk";
|
|
172
|
+
import { getAccessToken } from "@base44/sdk/utils/auth-utils";
|
|
173
173
|
|
|
174
174
|
// Create a client with authentication
|
|
175
175
|
const base44 = createClient({
|
|
176
|
-
appId:
|
|
177
|
-
token: getAccessToken() // Automatically retrieves token from localStorage or URL
|
|
176
|
+
appId: "your-app-id",
|
|
177
|
+
token: getAccessToken(), // Automatically retrieves token from localStorage or URL
|
|
178
178
|
});
|
|
179
179
|
|
|
180
180
|
// Check authentication status
|
|
181
181
|
const isAuthenticated = await base44.auth.isAuthenticated();
|
|
182
|
-
console.log(
|
|
182
|
+
console.log("Authenticated:", isAuthenticated);
|
|
183
183
|
|
|
184
184
|
// Get current user information (requires authentication)
|
|
185
185
|
if (isAuthenticated) {
|
|
186
186
|
const user = await base44.auth.me();
|
|
187
|
-
console.log(
|
|
187
|
+
console.log("Current user:", user);
|
|
188
188
|
}
|
|
189
189
|
```
|
|
190
190
|
|
|
191
191
|
### Login and Logout
|
|
192
192
|
|
|
193
193
|
```javascript
|
|
194
|
-
import { createClient } from
|
|
195
|
-
import {
|
|
194
|
+
import { createClient } from "@base44/sdk";
|
|
195
|
+
import {
|
|
196
|
+
getAccessToken,
|
|
197
|
+
saveAccessToken,
|
|
198
|
+
removeAccessToken,
|
|
199
|
+
} from "@base44/sdk/utils/auth-utils";
|
|
196
200
|
|
|
197
|
-
const base44 = createClient({ appId:
|
|
201
|
+
const base44 = createClient({ appId: "your-app-id" });
|
|
198
202
|
|
|
199
203
|
// Redirect to the login page
|
|
200
204
|
// This will redirect to: base44.app/login?from_url=http://your-app.com/dashboard&app_id=your-app-id
|
|
201
205
|
function handleLogin() {
|
|
202
|
-
base44.auth.login(
|
|
206
|
+
base44.auth.login("/dashboard");
|
|
203
207
|
}
|
|
204
208
|
|
|
205
209
|
// Handle successful login (on return from Base44 login)
|
|
206
210
|
function handleLoginReturn() {
|
|
207
211
|
const token = getAccessToken();
|
|
208
212
|
if (token) {
|
|
209
|
-
console.log(
|
|
213
|
+
console.log("Successfully logged in with token:", token);
|
|
210
214
|
// The token is automatically saved to localStorage and removed from URL
|
|
211
215
|
}
|
|
212
216
|
}
|
|
@@ -214,7 +218,7 @@ function handleLoginReturn() {
|
|
|
214
218
|
// Logout
|
|
215
219
|
function handleLogout() {
|
|
216
220
|
removeAccessToken();
|
|
217
|
-
window.location.href =
|
|
221
|
+
window.location.href = "/login";
|
|
218
222
|
}
|
|
219
223
|
```
|
|
220
224
|
|
|
@@ -223,10 +227,13 @@ function handleLogout() {
|
|
|
223
227
|
Here's a complete example of implementing Base44 authentication in a React application:
|
|
224
228
|
|
|
225
229
|
```jsx
|
|
226
|
-
import React, { createContext, useContext, useEffect, useState } from
|
|
227
|
-
import { Navigate, Outlet, Route, Routes, useLocation } from
|
|
228
|
-
import { createClient } from
|
|
229
|
-
import {
|
|
230
|
+
import React, { createContext, useContext, useEffect, useState } from "react";
|
|
231
|
+
import { Navigate, Outlet, Route, Routes, useLocation } from "react-router-dom";
|
|
232
|
+
import { createClient } from "@base44/sdk";
|
|
233
|
+
import {
|
|
234
|
+
getAccessToken,
|
|
235
|
+
removeAccessToken,
|
|
236
|
+
} from "@base44/sdk/utils/auth-utils";
|
|
230
237
|
|
|
231
238
|
// Create AuthContext
|
|
232
239
|
const AuthContext = createContext(null);
|
|
@@ -235,10 +242,10 @@ const AuthContext = createContext(null);
|
|
|
235
242
|
function AuthProvider({ children }) {
|
|
236
243
|
const [user, setUser] = useState(null);
|
|
237
244
|
const [loading, setLoading] = useState(true);
|
|
238
|
-
const [client] = useState(() =>
|
|
239
|
-
createClient({
|
|
240
|
-
appId:
|
|
241
|
-
token: getAccessToken()
|
|
245
|
+
const [client] = useState(() =>
|
|
246
|
+
createClient({
|
|
247
|
+
appId: "your-app-id",
|
|
248
|
+
token: getAccessToken(),
|
|
242
249
|
})
|
|
243
250
|
);
|
|
244
251
|
|
|
@@ -251,12 +258,12 @@ function AuthProvider({ children }) {
|
|
|
251
258
|
setUser(userData);
|
|
252
259
|
}
|
|
253
260
|
} catch (error) {
|
|
254
|
-
console.error(
|
|
261
|
+
console.error("Authentication error:", error);
|
|
255
262
|
} finally {
|
|
256
263
|
setLoading(false);
|
|
257
264
|
}
|
|
258
265
|
}
|
|
259
|
-
|
|
266
|
+
|
|
260
267
|
loadUser();
|
|
261
268
|
}, [client]);
|
|
262
269
|
|
|
@@ -267,7 +274,7 @@ function AuthProvider({ children }) {
|
|
|
267
274
|
const logout = () => {
|
|
268
275
|
removeAccessToken();
|
|
269
276
|
setUser(null);
|
|
270
|
-
window.location.href =
|
|
277
|
+
window.location.href = "/login";
|
|
271
278
|
};
|
|
272
279
|
|
|
273
280
|
return (
|
|
@@ -281,7 +288,7 @@ function AuthProvider({ children }) {
|
|
|
281
288
|
function useAuth() {
|
|
282
289
|
const context = useContext(AuthContext);
|
|
283
290
|
if (!context) {
|
|
284
|
-
throw new Error(
|
|
291
|
+
throw new Error("useAuth must be used within an AuthProvider");
|
|
285
292
|
}
|
|
286
293
|
return context;
|
|
287
294
|
}
|
|
@@ -323,12 +330,12 @@ function Dashboard() {
|
|
|
323
330
|
async function loadTodos() {
|
|
324
331
|
try {
|
|
325
332
|
// Load user-specific data using the SDK
|
|
326
|
-
const items = await client.entities.Todo.filter({
|
|
327
|
-
assignee: user.id
|
|
333
|
+
const items = await client.entities.Todo.filter({
|
|
334
|
+
assignee: user.id,
|
|
328
335
|
});
|
|
329
336
|
setTodos(items);
|
|
330
337
|
} catch (error) {
|
|
331
|
-
console.error(
|
|
338
|
+
console.error("Failed to load todos:", error);
|
|
332
339
|
} finally {
|
|
333
340
|
setLoading(false);
|
|
334
341
|
}
|
|
@@ -341,13 +348,13 @@ function Dashboard() {
|
|
|
341
348
|
<div>
|
|
342
349
|
<h1>Welcome, {user.name}!</h1>
|
|
343
350
|
<button onClick={logout}>Logout</button>
|
|
344
|
-
|
|
351
|
+
|
|
345
352
|
<h2>Your Todos</h2>
|
|
346
353
|
{loading ? (
|
|
347
354
|
<div>Loading todos...</div>
|
|
348
355
|
) : (
|
|
349
356
|
<ul>
|
|
350
|
-
{todos.map(todo => (
|
|
357
|
+
{todos.map((todo) => (
|
|
351
358
|
<li key={todo.id}>{todo.title}</li>
|
|
352
359
|
))}
|
|
353
360
|
</ul>
|
|
@@ -359,11 +366,11 @@ function Dashboard() {
|
|
|
359
366
|
// Login Page
|
|
360
367
|
function LoginPage() {
|
|
361
368
|
const { login, user } = useAuth();
|
|
362
|
-
|
|
369
|
+
|
|
363
370
|
if (user) {
|
|
364
371
|
return <Navigate to="/dashboard" />;
|
|
365
372
|
}
|
|
366
|
-
|
|
373
|
+
|
|
367
374
|
return (
|
|
368
375
|
<div>
|
|
369
376
|
<h1>Login Required</h1>
|
|
@@ -395,21 +402,21 @@ function App() {
|
|
|
395
402
|
This SDK includes TypeScript definitions out of the box:
|
|
396
403
|
|
|
397
404
|
```typescript
|
|
398
|
-
import { createClient, Base44Error } from
|
|
399
|
-
import type { Entity, Base44Client, AuthModule } from
|
|
405
|
+
import { createClient, Base44Error } from "@base44/sdk";
|
|
406
|
+
import type { Entity, Base44Client, AuthModule } from "@base44/sdk";
|
|
400
407
|
|
|
401
408
|
// Create a typed client
|
|
402
409
|
const base44: Base44Client = createClient({
|
|
403
|
-
appId:
|
|
410
|
+
appId: "your-app-id",
|
|
404
411
|
});
|
|
405
412
|
|
|
406
413
|
// Using the entities module with type safety
|
|
407
414
|
async function fetchProducts() {
|
|
408
415
|
try {
|
|
409
416
|
const products: Entity[] = await base44.entities.Product.list();
|
|
410
|
-
console.log(products.map(p => p.name));
|
|
411
|
-
|
|
412
|
-
const product: Entity = await base44.entities.Product.get(
|
|
417
|
+
console.log(products.map((p) => p.name));
|
|
418
|
+
|
|
419
|
+
const product: Entity = await base44.entities.Product.get("product-id");
|
|
413
420
|
console.log(product.name);
|
|
414
421
|
} catch (error) {
|
|
415
422
|
if (error instanceof Base44Error) {
|
|
@@ -421,8 +428,8 @@ async function fetchProducts() {
|
|
|
421
428
|
// Service role operations with TypeScript
|
|
422
429
|
async function adminOperations() {
|
|
423
430
|
const base44 = createClient({
|
|
424
|
-
appId:
|
|
425
|
-
serviceToken:
|
|
431
|
+
appId: "your-app-id",
|
|
432
|
+
serviceToken: "service-token",
|
|
426
433
|
});
|
|
427
434
|
|
|
428
435
|
// TypeScript knows asServiceRole requires a service token
|
|
@@ -440,19 +447,19 @@ async function adminOperations() {
|
|
|
440
447
|
async function handleAuth(auth: AuthModule) {
|
|
441
448
|
// Check authentication
|
|
442
449
|
const isAuthenticated: boolean = await auth.isAuthenticated();
|
|
443
|
-
|
|
450
|
+
|
|
444
451
|
if (isAuthenticated) {
|
|
445
452
|
// Get user info
|
|
446
453
|
const user: Entity = await auth.me();
|
|
447
454
|
console.log(`Logged in as: ${user.name}, Role: ${user.role}`);
|
|
448
|
-
|
|
455
|
+
|
|
449
456
|
// Update user
|
|
450
457
|
const updatedUser: Entity = await auth.updateMe({
|
|
451
|
-
preferences: { theme:
|
|
458
|
+
preferences: { theme: "dark" },
|
|
452
459
|
});
|
|
453
460
|
} else {
|
|
454
461
|
// Redirect to login
|
|
455
|
-
auth.login(
|
|
462
|
+
auth.login("/dashboard");
|
|
456
463
|
}
|
|
457
464
|
}
|
|
458
465
|
|
|
@@ -469,9 +476,9 @@ You can define your own entity interfaces for better type safety:
|
|
|
469
476
|
interface User extends Entity {
|
|
470
477
|
name: string;
|
|
471
478
|
email: string;
|
|
472
|
-
role:
|
|
479
|
+
role: "admin" | "editor" | "viewer";
|
|
473
480
|
preferences?: {
|
|
474
|
-
theme:
|
|
481
|
+
theme: "light" | "dark";
|
|
475
482
|
notifications: boolean;
|
|
476
483
|
};
|
|
477
484
|
}
|
|
@@ -485,13 +492,13 @@ interface Product extends Entity {
|
|
|
485
492
|
|
|
486
493
|
// Use your custom interfaces with the SDK
|
|
487
494
|
async function getLoggedInUser(): Promise<User | null> {
|
|
488
|
-
const base44 = createClient({ appId:
|
|
489
|
-
|
|
495
|
+
const base44 = createClient({ appId: "your-app-id" });
|
|
496
|
+
|
|
490
497
|
try {
|
|
491
|
-
const user = await base44.auth.me() as User;
|
|
498
|
+
const user = (await base44.auth.me()) as User;
|
|
492
499
|
return user;
|
|
493
500
|
} catch (error) {
|
|
494
|
-
console.error(
|
|
501
|
+
console.error("Failed to get user:", error);
|
|
495
502
|
return null;
|
|
496
503
|
}
|
|
497
504
|
}
|
|
@@ -500,24 +507,24 @@ async function getLoggedInUser(): Promise<User | null> {
|
|
|
500
507
|
function useBase44User() {
|
|
501
508
|
const [user, setUser] = useState<User | null>(null);
|
|
502
509
|
const [loading, setLoading] = useState<boolean>(true);
|
|
503
|
-
|
|
510
|
+
|
|
504
511
|
useEffect(() => {
|
|
505
|
-
const base44 = createClient({ appId:
|
|
506
|
-
|
|
512
|
+
const base44 = createClient({ appId: "your-app-id" });
|
|
513
|
+
|
|
507
514
|
async function fetchUser() {
|
|
508
515
|
try {
|
|
509
|
-
const userData = await base44.auth.me() as User;
|
|
516
|
+
const userData = (await base44.auth.me()) as User;
|
|
510
517
|
setUser(userData);
|
|
511
518
|
} catch (error) {
|
|
512
|
-
console.error(
|
|
519
|
+
console.error("Auth error:", error);
|
|
513
520
|
} finally {
|
|
514
521
|
setLoading(false);
|
|
515
522
|
}
|
|
516
523
|
}
|
|
517
|
-
|
|
524
|
+
|
|
518
525
|
fetchUser();
|
|
519
526
|
}, []);
|
|
520
|
-
|
|
527
|
+
|
|
521
528
|
return { user, loading };
|
|
522
529
|
}
|
|
523
530
|
```
|
|
@@ -527,9 +534,9 @@ function useBase44User() {
|
|
|
527
534
|
The SDK provides a custom `Base44Error` class for error handling:
|
|
528
535
|
|
|
529
536
|
```javascript
|
|
530
|
-
import { createClient, Base44Error } from
|
|
537
|
+
import { createClient, Base44Error } from "@base44/sdk";
|
|
531
538
|
|
|
532
|
-
const base44 = createClient({ appId:
|
|
539
|
+
const base44 = createClient({ appId: "your-app-id" });
|
|
533
540
|
|
|
534
541
|
try {
|
|
535
542
|
const result = await base44.entities.NonExistentEntity.list();
|
|
@@ -540,7 +547,7 @@ try {
|
|
|
540
547
|
console.error(`Code: ${error.code}`);
|
|
541
548
|
console.error(`Data: ${JSON.stringify(error.data)}`);
|
|
542
549
|
} else {
|
|
543
|
-
console.error(
|
|
550
|
+
console.error("Unexpected error:", error);
|
|
544
551
|
}
|
|
545
552
|
}
|
|
546
553
|
```
|
|
@@ -555,8 +562,8 @@ const result = await base44.functions.myFunction();
|
|
|
555
562
|
|
|
556
563
|
// Invoke a function with parameters
|
|
557
564
|
const result = await base44.functions.calculateTotal({
|
|
558
|
-
items: [
|
|
559
|
-
discount: 0.1
|
|
565
|
+
items: ["item1", "item2"],
|
|
566
|
+
discount: 0.1,
|
|
560
567
|
});
|
|
561
568
|
|
|
562
569
|
// Functions are automatically authenticated with the user token
|
|
@@ -564,6 +571,447 @@ const result = await base44.functions.calculateTotal({
|
|
|
564
571
|
const serviceResult = await base44.asServiceRole.functions.adminFunction();
|
|
565
572
|
```
|
|
566
573
|
|
|
574
|
+
## AI Agents
|
|
575
|
+
|
|
576
|
+
The SDK provides comprehensive support for AI agent conversations with real-time messaging capabilities.
|
|
577
|
+
|
|
578
|
+
### Basic Agent Setup
|
|
579
|
+
|
|
580
|
+
```javascript
|
|
581
|
+
import { createClient } from "@base44/sdk";
|
|
582
|
+
|
|
583
|
+
// Create a client with agents support
|
|
584
|
+
const base44 = createClient({
|
|
585
|
+
appId: "your-app-id",
|
|
586
|
+
token: "your-auth-token",
|
|
587
|
+
agents: {
|
|
588
|
+
enableWebSocket: true, // Enable real-time updates
|
|
589
|
+
socketUrl: "wss://base44.app/ws", // Optional: custom WebSocket URL
|
|
590
|
+
},
|
|
591
|
+
});
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
### Working with Agent Conversations
|
|
595
|
+
|
|
596
|
+
```javascript
|
|
597
|
+
// Create a new conversation with an agent
|
|
598
|
+
const conversation = await base44.agents.createConversation({
|
|
599
|
+
agent_name: "customer-support-agent",
|
|
600
|
+
metadata: {
|
|
601
|
+
source: "web-app",
|
|
602
|
+
priority: "normal",
|
|
603
|
+
customer_id: "cust_12345",
|
|
604
|
+
},
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
// Send a message to the agent
|
|
608
|
+
const response = await base44.agents.sendMessage(conversation.id, {
|
|
609
|
+
role: "user",
|
|
610
|
+
content: "Hello! I need help with my account.",
|
|
611
|
+
metadata: {
|
|
612
|
+
timestamp: new Date().toISOString(),
|
|
613
|
+
},
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
// Get conversation history
|
|
617
|
+
const fullConversation = await base44.agents.getConversation(conversation.id);
|
|
618
|
+
console.log("Messages:", fullConversation.messages);
|
|
619
|
+
|
|
620
|
+
// List all conversations
|
|
621
|
+
const conversations = await base44.agents.listConversations({
|
|
622
|
+
limit: 10,
|
|
623
|
+
sort: { created_at: -1 },
|
|
624
|
+
});
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
### Real-Time Agent Conversations
|
|
628
|
+
|
|
629
|
+
```javascript
|
|
630
|
+
// Subscribe to real-time updates for a conversation
|
|
631
|
+
const unsubscribe = base44.agents.subscribeToConversation(
|
|
632
|
+
conversation.id,
|
|
633
|
+
(updatedConversation) => {
|
|
634
|
+
console.log("New messages:", updatedConversation.messages);
|
|
635
|
+
|
|
636
|
+
// Handle new agent responses
|
|
637
|
+
const lastMessage =
|
|
638
|
+
updatedConversation.messages[updatedConversation.messages.length - 1];
|
|
639
|
+
if (lastMessage?.role === "assistant") {
|
|
640
|
+
displayAgentMessage(lastMessage.content);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
);
|
|
644
|
+
|
|
645
|
+
// Send a message and receive real-time responses
|
|
646
|
+
await base44.agents.sendMessage(conversation.id, {
|
|
647
|
+
role: "user",
|
|
648
|
+
content: "Can you help me with billing questions?",
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
// Clean up subscription when done
|
|
652
|
+
unsubscribe();
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
### Advanced Agent Usage
|
|
656
|
+
|
|
657
|
+
```javascript
|
|
658
|
+
// Filter conversations by agent type
|
|
659
|
+
const supportConversations = await base44.agents.listConversations({
|
|
660
|
+
query: { agent_name: "support-agent" },
|
|
661
|
+
limit: 20,
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
// Update conversation metadata
|
|
665
|
+
await base44.agents.updateConversation(conversation.id, {
|
|
666
|
+
metadata: {
|
|
667
|
+
status: "resolved",
|
|
668
|
+
satisfaction_rating: 5,
|
|
669
|
+
resolution_time: "5 minutes",
|
|
670
|
+
},
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
// Delete a specific message from conversation
|
|
674
|
+
await base44.agents.deleteMessage(conversation.id, "message-id");
|
|
675
|
+
|
|
676
|
+
// Check WebSocket connection status
|
|
677
|
+
const status = base44.agents.getWebSocketStatus();
|
|
678
|
+
console.log("WebSocket enabled:", status.enabled);
|
|
679
|
+
console.log("WebSocket connected:", status.connected);
|
|
680
|
+
|
|
681
|
+
// Manually control WebSocket connection
|
|
682
|
+
if (status.enabled && !status.connected) {
|
|
683
|
+
await base44.agents.connectWebSocket();
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// Disconnect WebSocket when done
|
|
687
|
+
base44.agents.disconnectWebSocket();
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
### TypeScript Support for Agents
|
|
691
|
+
|
|
692
|
+
```typescript
|
|
693
|
+
import {
|
|
694
|
+
createClient,
|
|
695
|
+
AgentConversation,
|
|
696
|
+
Message,
|
|
697
|
+
CreateConversationPayload,
|
|
698
|
+
} from "@base44/sdk";
|
|
699
|
+
|
|
700
|
+
// Define custom conversation metadata interface
|
|
701
|
+
interface CustomerSupportMetadata {
|
|
702
|
+
customer_id: string;
|
|
703
|
+
priority: "low" | "normal" | "high" | "urgent";
|
|
704
|
+
department: "sales" | "support" | "technical";
|
|
705
|
+
source: "web" | "mobile" | "email";
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// Create typed conversation
|
|
709
|
+
const conversation: AgentConversation = await base44.agents.createConversation({
|
|
710
|
+
agent_name: "support-agent",
|
|
711
|
+
metadata: {
|
|
712
|
+
customer_id: "cust_123",
|
|
713
|
+
priority: "high",
|
|
714
|
+
department: "support",
|
|
715
|
+
source: "web",
|
|
716
|
+
} as CustomerSupportMetadata,
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
// Send typed message
|
|
720
|
+
const message: Omit<Message, "id"> = {
|
|
721
|
+
role: "user",
|
|
722
|
+
content: "I need help with my order",
|
|
723
|
+
timestamp: new Date().toISOString(),
|
|
724
|
+
metadata: {
|
|
725
|
+
intent: "order_inquiry",
|
|
726
|
+
order_id: "ord_456",
|
|
727
|
+
},
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
const response: Message = await base44.agents.sendMessage(
|
|
731
|
+
conversation.id,
|
|
732
|
+
message
|
|
733
|
+
);
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
### Customer Service Chatbot Example
|
|
737
|
+
|
|
738
|
+
```javascript
|
|
739
|
+
class CustomerServiceBot {
|
|
740
|
+
constructor(base44Client) {
|
|
741
|
+
this.client = base44Client;
|
|
742
|
+
this.activeConversations = new Map();
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
async startConversation(customerId, initialMessage) {
|
|
746
|
+
// Create conversation with customer context
|
|
747
|
+
const conversation = await this.client.agents.createConversation({
|
|
748
|
+
agent_name: "customer-service-bot",
|
|
749
|
+
metadata: {
|
|
750
|
+
customer_id: customerId,
|
|
751
|
+
session_start: new Date().toISOString(),
|
|
752
|
+
channel: "web-chat",
|
|
753
|
+
},
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
// Set up real-time message handling
|
|
757
|
+
const unsubscribe = this.client.agents.subscribeToConversation(
|
|
758
|
+
conversation.id,
|
|
759
|
+
(updatedConversation) => {
|
|
760
|
+
this.handleConversationUpdate(updatedConversation);
|
|
761
|
+
}
|
|
762
|
+
);
|
|
763
|
+
|
|
764
|
+
// Store conversation reference
|
|
765
|
+
this.activeConversations.set(conversation.id, {
|
|
766
|
+
conversation,
|
|
767
|
+
unsubscribe,
|
|
768
|
+
customerId,
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
// Send initial message
|
|
772
|
+
await this.client.agents.sendMessage(conversation.id, {
|
|
773
|
+
role: "user",
|
|
774
|
+
content: initialMessage,
|
|
775
|
+
metadata: { message_type: "initial_inquiry" },
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
return conversation.id;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
handleConversationUpdate(conversation) {
|
|
782
|
+
const lastMessage = conversation.messages[conversation.messages.length - 1];
|
|
783
|
+
|
|
784
|
+
if (lastMessage?.role === "assistant") {
|
|
785
|
+
// Display agent response to user
|
|
786
|
+
this.displayMessage(conversation.id, lastMessage);
|
|
787
|
+
|
|
788
|
+
// Check for escalation keywords
|
|
789
|
+
if (this.shouldEscalate(lastMessage.content)) {
|
|
790
|
+
this.escalateToHuman(conversation.id);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
shouldEscalate(messageContent) {
|
|
796
|
+
const escalationKeywords = [
|
|
797
|
+
"human agent",
|
|
798
|
+
"supervisor",
|
|
799
|
+
"manager",
|
|
800
|
+
"escalate",
|
|
801
|
+
];
|
|
802
|
+
return escalationKeywords.some((keyword) =>
|
|
803
|
+
messageContent.toLowerCase().includes(keyword)
|
|
804
|
+
);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
async escalateToHuman(conversationId) {
|
|
808
|
+
await this.client.agents.updateConversation(conversationId, {
|
|
809
|
+
metadata: {
|
|
810
|
+
escalated: true,
|
|
811
|
+
escalation_time: new Date().toISOString(),
|
|
812
|
+
status: "pending_human_agent",
|
|
813
|
+
},
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
console.log(`Conversation ${conversationId} escalated to human agent`);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
async endConversation(conversationId) {
|
|
820
|
+
const conversationData = this.activeConversations.get(conversationId);
|
|
821
|
+
if (conversationData) {
|
|
822
|
+
// Clean up subscription
|
|
823
|
+
conversationData.unsubscribe();
|
|
824
|
+
|
|
825
|
+
// Update conversation status
|
|
826
|
+
await this.client.agents.updateConversation(conversationId, {
|
|
827
|
+
metadata: {
|
|
828
|
+
status: "completed",
|
|
829
|
+
session_end: new Date().toISOString(),
|
|
830
|
+
},
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
this.activeConversations.delete(conversationId);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
displayMessage(conversationId, message) {
|
|
838
|
+
// Implement your UI message display logic here
|
|
839
|
+
console.log(`[${conversationId}] Agent: ${message.content}`);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// Usage
|
|
844
|
+
const customerBot = new CustomerServiceBot(base44);
|
|
845
|
+
const conversationId = await customerBot.startConversation(
|
|
846
|
+
"customer_123",
|
|
847
|
+
"Hi, I have a problem with my recent order"
|
|
848
|
+
);
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
### Multi-Agent System Example
|
|
852
|
+
|
|
853
|
+
```javascript
|
|
854
|
+
class MultiAgentRouter {
|
|
855
|
+
constructor(base44Client) {
|
|
856
|
+
this.client = base44Client;
|
|
857
|
+
this.agents = {
|
|
858
|
+
sales: "sales-agent",
|
|
859
|
+
support: "support-agent",
|
|
860
|
+
technical: "technical-agent",
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
async routeQuery(userQuery, customerContext) {
|
|
865
|
+
// Determine the best agent based on query content
|
|
866
|
+
const department = this.classifyQuery(userQuery);
|
|
867
|
+
const agentName = this.agents[department];
|
|
868
|
+
|
|
869
|
+
// Create conversation with appropriate agent
|
|
870
|
+
const conversation = await this.client.agents.createConversation({
|
|
871
|
+
agent_name: agentName,
|
|
872
|
+
metadata: {
|
|
873
|
+
...customerContext,
|
|
874
|
+
department,
|
|
875
|
+
routing_reason: `Auto-routed based on query classification`,
|
|
876
|
+
original_query: userQuery,
|
|
877
|
+
},
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
// Send initial message
|
|
881
|
+
await this.client.agents.sendMessage(conversation.id, {
|
|
882
|
+
role: "user",
|
|
883
|
+
content: userQuery,
|
|
884
|
+
metadata: {
|
|
885
|
+
routing_department: department,
|
|
886
|
+
confidence: this.getClassificationConfidence(userQuery, department),
|
|
887
|
+
},
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
return { conversationId: conversation.id, department, agent: agentName };
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
classifyQuery(query) {
|
|
894
|
+
const lowerQuery = query.toLowerCase();
|
|
895
|
+
|
|
896
|
+
if (
|
|
897
|
+
lowerQuery.includes("buy") ||
|
|
898
|
+
lowerQuery.includes("price") ||
|
|
899
|
+
lowerQuery.includes("plan")
|
|
900
|
+
) {
|
|
901
|
+
return "sales";
|
|
902
|
+
}
|
|
903
|
+
if (
|
|
904
|
+
lowerQuery.includes("api") ||
|
|
905
|
+
lowerQuery.includes("integration") ||
|
|
906
|
+
lowerQuery.includes("code")
|
|
907
|
+
) {
|
|
908
|
+
return "technical";
|
|
909
|
+
}
|
|
910
|
+
return "support"; // Default to support
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
getClassificationConfidence(query, department) {
|
|
914
|
+
// Simple confidence scoring (you could use ML models here)
|
|
915
|
+
const keywords = {
|
|
916
|
+
sales: ["buy", "purchase", "price", "plan", "upgrade", "billing"],
|
|
917
|
+
technical: ["api", "integration", "code", "sdk", "development", "bug"],
|
|
918
|
+
support: ["help", "problem", "issue", "account", "login", "password"],
|
|
919
|
+
};
|
|
920
|
+
|
|
921
|
+
const queryWords = query.toLowerCase().split(" ");
|
|
922
|
+
const matches = keywords[department].filter((keyword) =>
|
|
923
|
+
queryWords.some((word) => word.includes(keyword))
|
|
924
|
+
);
|
|
925
|
+
|
|
926
|
+
return Math.min(matches.length * 0.3, 1.0);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// Usage
|
|
931
|
+
const router = new MultiAgentRouter(base44);
|
|
932
|
+
const result = await router.routeQuery(
|
|
933
|
+
"I want to upgrade to your enterprise plan",
|
|
934
|
+
{ customer_id: "cust_789", tier: "premium" }
|
|
935
|
+
);
|
|
936
|
+
|
|
937
|
+
console.log(
|
|
938
|
+
`Routed to ${result.department} (${result.agent}): ${result.conversationId}`
|
|
939
|
+
);
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
### Error Handling with Agents
|
|
943
|
+
|
|
944
|
+
```javascript
|
|
945
|
+
import { Base44Error } from "@base44/sdk";
|
|
946
|
+
|
|
947
|
+
async function robustAgentInteraction() {
|
|
948
|
+
const maxRetries = 3;
|
|
949
|
+
let retryCount = 0;
|
|
950
|
+
|
|
951
|
+
while (retryCount < maxRetries) {
|
|
952
|
+
try {
|
|
953
|
+
// Attempt to create conversation
|
|
954
|
+
const conversation = await base44.agents.createConversation({
|
|
955
|
+
agent_name: "support-agent",
|
|
956
|
+
});
|
|
957
|
+
|
|
958
|
+
// Send message with retry logic
|
|
959
|
+
const response = await base44.agents.sendMessage(conversation.id, {
|
|
960
|
+
role: "user",
|
|
961
|
+
content: "Hello, I need assistance",
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
console.log("Successfully sent message:", response);
|
|
965
|
+
return conversation;
|
|
966
|
+
} catch (error) {
|
|
967
|
+
retryCount++;
|
|
968
|
+
|
|
969
|
+
if (error instanceof Base44Error) {
|
|
970
|
+
console.error(`Agent API Error (${error.status}): ${error.message}`);
|
|
971
|
+
|
|
972
|
+
// Don't retry on client errors (4xx)
|
|
973
|
+
if (error.status >= 400 && error.status < 500) {
|
|
974
|
+
throw error;
|
|
975
|
+
}
|
|
976
|
+
} else {
|
|
977
|
+
console.error("Network or other error:", error);
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
if (retryCount >= maxRetries) {
|
|
981
|
+
throw new Error(
|
|
982
|
+
`Failed to create agent conversation after ${maxRetries} attempts`
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
// Exponential backoff
|
|
987
|
+
const delay = Math.pow(2, retryCount) * 1000;
|
|
988
|
+
console.log(
|
|
989
|
+
`Retrying in ${delay}ms... (attempt ${retryCount + 1}/${maxRetries})`
|
|
990
|
+
);
|
|
991
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// WebSocket error handling
|
|
997
|
+
base44.agents.subscribeToConversation(
|
|
998
|
+
conversationId,
|
|
999
|
+
(conversation) => {
|
|
1000
|
+
// Handle successful updates
|
|
1001
|
+
console.log("Conversation updated:", conversation.id);
|
|
1002
|
+
},
|
|
1003
|
+
(error) => {
|
|
1004
|
+
// Handle WebSocket errors
|
|
1005
|
+
console.error("WebSocket error:", error);
|
|
1006
|
+
|
|
1007
|
+
// Attempt to reconnect
|
|
1008
|
+
setTimeout(() => {
|
|
1009
|
+
base44.agents.connectWebSocket().catch(console.error);
|
|
1010
|
+
}, 5000);
|
|
1011
|
+
}
|
|
1012
|
+
);
|
|
1013
|
+
```
|
|
1014
|
+
|
|
567
1015
|
## Testing
|
|
568
1016
|
|
|
569
1017
|
The SDK includes comprehensive tests to ensure reliability.
|
|
@@ -590,6 +1038,7 @@ E2E tests require access to a Base44 API. To run these tests:
|
|
|
590
1038
|
|
|
591
1039
|
1. Copy `tests/.env.example` to `tests/.env`
|
|
592
1040
|
2. Fill in your Base44 API credentials in the `.env` file:
|
|
1041
|
+
|
|
593
1042
|
```
|
|
594
1043
|
BASE44_SERVER_URL=https://base44.app
|
|
595
1044
|
BASE44_APP_ID=your_app_id_here
|
|
@@ -603,25 +1052,25 @@ E2E tests require access to a Base44 API. To run these tests:
|
|
|
603
1052
|
You can use the provided test utilities for writing your own tests:
|
|
604
1053
|
|
|
605
1054
|
```javascript
|
|
606
|
-
const { createClient } = require(
|
|
607
|
-
const { getTestConfig } = require(
|
|
1055
|
+
const { createClient } = require("@base44/sdk");
|
|
1056
|
+
const { getTestConfig } = require("@base44/sdk/tests/utils/test-config");
|
|
608
1057
|
|
|
609
|
-
describe(
|
|
1058
|
+
describe("My Tests", () => {
|
|
610
1059
|
let base44;
|
|
611
|
-
|
|
1060
|
+
|
|
612
1061
|
beforeAll(() => {
|
|
613
1062
|
const config = getTestConfig();
|
|
614
1063
|
base44 = createClient({
|
|
615
1064
|
serverUrl: config.serverUrl,
|
|
616
1065
|
appId: config.appId,
|
|
617
1066
|
});
|
|
618
|
-
|
|
1067
|
+
|
|
619
1068
|
if (config.token) {
|
|
620
1069
|
base44.setToken(config.token);
|
|
621
1070
|
}
|
|
622
1071
|
});
|
|
623
|
-
|
|
624
|
-
test(
|
|
1072
|
+
|
|
1073
|
+
test("My test", async () => {
|
|
625
1074
|
const todos = await base44.entities.Todo.filter({}, 10);
|
|
626
1075
|
expect(Array.isArray(todos)).toBe(true);
|
|
627
1076
|
expect(todos.length).toBeGreaterThan(0);
|
|
@@ -631,4 +1080,4 @@ describe('My Tests', () => {
|
|
|
631
1080
|
|
|
632
1081
|
## License
|
|
633
1082
|
|
|
634
|
-
MIT
|
|
1083
|
+
MIT
|