@base44-preview/sdk 0.6.1-dev.d43b559 → 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 CHANGED
@@ -15,15 +15,15 @@ yarn add @base44/sdk
15
15
  ### Basic Setup
16
16
 
17
17
  ```javascript
18
- import { createClient } from '@base44/sdk';
18
+ import { createClient } from "@base44/sdk";
19
19
 
20
20
  // Create a client instance
21
21
  const base44 = createClient({
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
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: ['electronics', 'computers']
38
+ category: ["electronics", "computers"],
39
39
  });
40
40
 
41
41
  // Get a specific product
42
- const product = await base44.entities.Product.get('product-id');
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: 'New Product',
46
+ name: "New Product",
47
47
  price: 99.99,
48
- category: 'electronics'
48
+ category: "electronics",
49
49
  });
50
50
 
51
51
  // Update a product
52
- const updatedProduct = await base44.entities.Product.update('product-id', {
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('product-id');
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: 'Product 1', price: 19.99 },
62
- { name: 'Product 2', price: 29.99 }
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 '@base44/sdk';
71
+ import { createClient } from "@base44/sdk";
72
72
 
73
73
  // Create a client with service role token
74
74
  const base44 = createClient({
75
- appId: 'your-app-id',
76
- token: 'user-token', // For user operations
77
- serviceToken: 'service-token' // For service role operations
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: 'your-app-id' });
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 '@base44/sdk';
106
+ import { createClientFromRequest } from "@base44/sdk";
107
107
 
108
108
  // In your server handler (Express, Next.js, etc.)
109
- app.get('/api/data', async (req, res) => {
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: 'user@example.com',
143
- subject: 'Hello from Base44',
144
- body: 'This is a test email sent via the Base44 SDK'
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: 'value1',
150
- param2: 'value2'
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: 'profile-picture' }
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 '@base44/sdk';
172
- import { getAccessToken } from '@base44/sdk/utils/auth-utils';
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: 'your-app-id',
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('Authenticated:', isAuthenticated);
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('Current user:', user);
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 '@base44/sdk';
195
- import { getAccessToken, saveAccessToken, removeAccessToken } from '@base44/sdk/utils/auth-utils';
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: 'your-app-id' });
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('/dashboard');
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('Successfully logged in with token:', token);
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 = '/login';
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 'react';
227
- import { Navigate, Outlet, Route, Routes, useLocation } from 'react-router-dom';
228
- import { createClient } from '@base44/sdk';
229
- import { getAccessToken, removeAccessToken } from '@base44/sdk/utils/auth-utils';
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: 'your-app-id',
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('Authentication error:', 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 = '/login';
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('useAuth must be used within an AuthProvider');
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('Failed to load todos:', 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 '@base44/sdk';
399
- import type { Entity, Base44Client, AuthModule } from '@base44/sdk';
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: 'your-app-id'
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('product-id');
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: 'your-app-id',
425
- serviceToken: 'service-token'
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: 'dark' }
458
+ preferences: { theme: "dark" },
452
459
  });
453
460
  } else {
454
461
  // Redirect to login
455
- auth.login('/dashboard');
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: 'admin' | 'editor' | 'viewer';
479
+ role: "admin" | "editor" | "viewer";
473
480
  preferences?: {
474
- theme: 'light' | 'dark';
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: 'your-app-id' });
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('Failed to get user:', 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: 'your-app-id' });
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('Auth error:', 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 '@base44/sdk';
537
+ import { createClient, Base44Error } from "@base44/sdk";
531
538
 
532
- const base44 = createClient({ appId: 'your-app-id' });
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('Unexpected error:', 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: ['item1', 'item2'],
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('@base44/sdk');
607
- const { getTestConfig } = require('@base44/sdk/tests/utils/test-config');
1055
+ const { createClient } = require("@base44/sdk");
1056
+ const { getTestConfig } = require("@base44/sdk/tests/utils/test-config");
608
1057
 
609
- describe('My Tests', () => {
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('My test', async () => {
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