@base44-preview/sdk 0.8.19-pr.124.bb33a2f → 0.8.19-pr.126.c537ed8

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.
@@ -3,6 +3,8 @@ export function createAgentsModule({ axios, getSocket, appId, serverUrl, token,
3
3
  const baseURL = `/apps/${appId}/agents`;
4
4
  // Track active conversations
5
5
  const currentConversations = {};
6
+ // Stores client tool handlers keyed by conversation ID
7
+ const clientToolHandlers = {};
6
8
  const getConversations = () => {
7
9
  return axios.get(`${baseURL}/conversations`);
8
10
  };
@@ -20,6 +22,60 @@ export function createAgentsModule({ axios, getSocket, appId, serverUrl, token,
20
22
  const addMessage = async (conversation, message) => {
21
23
  return axios.post(`${baseURL}/conversations/v2/${conversation.id}/messages`, message);
22
24
  };
25
+ const registerClientToolHandlers = (conversationId, handlers) => {
26
+ clientToolHandlers[conversationId] = {
27
+ ...(clientToolHandlers[conversationId] || {}),
28
+ ...handlers,
29
+ };
30
+ };
31
+ const submitToolResults = (conversationId, results) => {
32
+ return axios.post(`${baseURL}/conversations/${conversationId}/client-tool-results`, { results });
33
+ };
34
+ const handlePendingClientTools = async (conversationId, message) => {
35
+ var _a;
36
+ if (!(message === null || message === void 0 ? void 0 : message.tool_calls))
37
+ return false;
38
+ const pendingCalls = message.tool_calls.filter((tc) => tc.status === "pending_client_execution");
39
+ if (pendingCalls.length === 0)
40
+ return false;
41
+ const handlers = clientToolHandlers[conversationId];
42
+ if (!handlers)
43
+ return false;
44
+ const results = [];
45
+ for (const tc of pendingCalls) {
46
+ const handler = handlers[tc.name];
47
+ if (!handler) {
48
+ results.push({
49
+ tool_call_id: tc.id,
50
+ result: `Error: No handler registered for client tool '${tc.name}'`,
51
+ });
52
+ continue;
53
+ }
54
+ try {
55
+ const args = JSON.parse(tc.arguments_string);
56
+ const context = {
57
+ appId,
58
+ conversationId,
59
+ toolCallId: tc.id,
60
+ toolName: tc.name,
61
+ messages: ((_a = currentConversations[conversationId]) === null || _a === void 0 ? void 0 : _a.messages) || [],
62
+ };
63
+ const result = await handler(args, context);
64
+ results.push({
65
+ tool_call_id: tc.id,
66
+ result: typeof result === "string" ? result : JSON.stringify(result),
67
+ });
68
+ }
69
+ catch (error) {
70
+ results.push({
71
+ tool_call_id: tc.id,
72
+ result: `Error executing client tool '${tc.name}': ${error.message}`,
73
+ });
74
+ }
75
+ }
76
+ await submitToolResults(conversationId, results);
77
+ return true;
78
+ };
23
79
  const subscribeToConversation = (conversationId, onUpdate) => {
24
80
  const room = `/agent-conversations/${conversationId}`;
25
81
  const socket = getSocket();
@@ -49,6 +105,8 @@ export function createAgentsModule({ axios, getSocket, appId, serverUrl, token,
49
105
  messages: updatedMessages,
50
106
  };
51
107
  onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(currentConversations[conversationId]);
108
+ // Automatically handle pending client tool calls
109
+ await handlePendingClientTools(conversationId, message);
52
110
  }
53
111
  }
54
112
  },
@@ -71,6 +129,9 @@ export function createAgentsModule({ axios, getSocket, appId, serverUrl, token,
71
129
  listConversations,
72
130
  createConversation,
73
131
  addMessage,
132
+ registerClientToolHandlers,
133
+ submitToolResults,
134
+ handlePendingClientTools,
74
135
  subscribeToConversation,
75
136
  getWhatsAppConnectURL,
76
137
  };
@@ -37,7 +37,7 @@ export interface AgentMessageToolCall {
37
37
  /** Arguments passed to the tool as JSON string. */
38
38
  arguments_string: string;
39
39
  /** Status of the tool call. */
40
- status: "running" | "success" | "error" | "stopped";
40
+ status: "running" | "success" | "error" | "stopped" | "pending_client_execution";
41
41
  /** Results from the tool call. */
42
42
  results?: string;
43
43
  }
@@ -141,6 +141,37 @@ export interface CreateConversationParams {
141
141
  /** Optional metadata to attach to the conversation. */
142
142
  metadata?: Record<string, any>;
143
143
  }
144
+ /**
145
+ * Context passed to client tool handlers during execution.
146
+ */
147
+ export interface ClientToolContext {
148
+ /** The app ID. */
149
+ appId: string;
150
+ /** The conversation ID. */
151
+ conversationId: string;
152
+ /** The unique tool call ID. */
153
+ toolCallId: string;
154
+ /** The tool name. */
155
+ toolName: string;
156
+ /** The conversation messages so far. */
157
+ messages: AgentMessage[];
158
+ }
159
+ /**
160
+ * A client tool handler function.
161
+ *
162
+ * Receives parsed arguments and execution context, returns a string result
163
+ * (or an object that will be JSON.stringified).
164
+ */
165
+ export type ClientToolHandler = (args: Record<string, any>, context: ClientToolContext) => Promise<string | Record<string, any>> | string | Record<string, any>;
166
+ /**
167
+ * Result of a client tool execution, to be submitted back to the server.
168
+ */
169
+ export interface ClientToolResult {
170
+ /** The tool call ID this result corresponds to. */
171
+ tool_call_id: string;
172
+ /** The result string. */
173
+ result: string;
174
+ }
144
175
  /**
145
176
  * Configuration for creating the agents module.
146
177
  * @internal
@@ -304,6 +335,71 @@ export interface AgentsModule {
304
335
  * ```
305
336
  */
306
337
  addMessage(conversation: AgentConversation, message: Partial<AgentMessage>): Promise<AgentMessage>;
338
+ /**
339
+ * Registers handler functions for client-side tools defined in the agent configuration.
340
+ *
341
+ * Client tools are tools that execute in the browser rather than on the server.
342
+ * They are defined by the app builder in the agent configuration (name, description,
343
+ * parameters). The SDK caller provides the handler functions that run locally when
344
+ * the agent invokes these tools.
345
+ *
346
+ * When subscribed to the conversation via {@linkcode subscribeToConversation | subscribeToConversation()},
347
+ * client tool calls are handled automatically — the SDK detects pending client tool calls,
348
+ * executes the registered handlers, and submits results back to the server.
349
+ *
350
+ * For user info inside a handler, call `base44.auth.me()` from the handler body.
351
+ *
352
+ * @param conversationId - The conversation ID to register handlers for.
353
+ * @param handlers - Map of tool name to handler function. Each handler receives
354
+ * `(args, context)` where `args` are the parsed tool arguments and `context`
355
+ * includes `appId`, `conversationId`, `toolCallId`, `toolName`, and `messages`.
356
+ *
357
+ * @example
358
+ * ```typescript
359
+ * base44.agents.registerClientToolHandlers(conversation.id, {
360
+ * get_current_location: async ({ accuracy }, { conversationId, messages }) => {
361
+ * const pos = await new Promise((resolve, reject) =>
362
+ * navigator.geolocation.getCurrentPosition(resolve, reject, {
363
+ * enableHighAccuracy: accuracy === 'high'
364
+ * })
365
+ * );
366
+ * return JSON.stringify({
367
+ * lat: pos.coords.latitude,
368
+ * lng: pos.coords.longitude
369
+ * });
370
+ * },
371
+ * get_clipboard_text: async () => {
372
+ * return await navigator.clipboard.readText();
373
+ * }
374
+ * });
375
+ * ```
376
+ */
377
+ registerClientToolHandlers(conversationId: string, handlers: Record<string, ClientToolHandler>): void;
378
+ /**
379
+ * Submits results for client-side tool calls.
380
+ *
381
+ * This is called automatically when using {@linkcode subscribeToConversation | subscribeToConversation()}
382
+ * with registered handlers. You only need to call this directly if you are
383
+ * implementing custom tool call handling logic outside of the subscription flow.
384
+ *
385
+ * @param conversationId - The conversation ID.
386
+ * @param results - Array of tool call results.
387
+ */
388
+ submitToolResults(conversationId: string, results: ClientToolResult[]): Promise<any>;
389
+ /**
390
+ * Processes pending client-side tool calls from a message.
391
+ *
392
+ * Finds tool calls with `pending_client_execution` status, executes their
393
+ * registered handlers, and submits the results back to the server.
394
+ *
395
+ * This is called automatically by {@linkcode subscribeToConversation | subscribeToConversation()}.
396
+ * You only need to call this directly for custom handling flows.
397
+ *
398
+ * @param conversationId - The conversation ID.
399
+ * @param message - The message containing tool calls.
400
+ * @returns `true` if client tool calls were processed, `false` otherwise.
401
+ */
402
+ handlePendingClientTools(conversationId: string, message: AgentMessage): Promise<boolean>;
307
403
  /**
308
404
  * Subscribes to realtime updates for a conversation.
309
405
  *
@@ -311,6 +407,9 @@ export interface AgentsModule {
311
407
  * messages are added to the conversation. Returns an unsubscribe function
312
408
  * to clean up the connection.
313
409
  *
410
+ * Client tool handlers registered via {@linkcode registerClientToolHandlers | registerClientToolHandlers()}
411
+ * are automatically executed when tool calls with `pending_client_execution` status arrive.
412
+ *
314
413
  * <Note>
315
414
  When receiving messages through this function, tool call data is truncated for efficiency. The `arguments_string` is limited to 500 characters and `results` to 50 characters. The complete tool call data is always saved in storage and can be retrieved by calling {@linkcode getConversation | getConversation()} after the message completes.
316
415
  </Note>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/sdk",
3
- "version": "0.8.19-pr.124.bb33a2f",
3
+ "version": "0.8.19-pr.126.c537ed8",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",