@meetsmore-oss/use-ai-client 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -5,6 +5,44 @@ export { AgentInfo, ToolAnnotations, ToolDefinition } from '@meetsmore-oss/use-a
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
  import React$1, { MutableRefObject, RefObject, ReactNode } from 'react';
7
7
 
8
+ /**
9
+ * Context provided to tool execution functions.
10
+ * Allows tools to dynamically request user approval at runtime.
11
+ */
12
+ interface ToolExecutionContext {
13
+ /**
14
+ * Request user approval during tool execution.
15
+ * Use this for conditional approval based on runtime values
16
+ * (e.g., API endpoint, input values, computed risk).
17
+ *
18
+ * @param input - Approval request details
19
+ * @returns Promise resolving with approval decision
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const callApi = defineTool(
24
+ * 'Call an external API',
25
+ * z.object({ url: z.string() }),
26
+ * async (input, ctx) => {
27
+ * if (input.url.includes('production')) {
28
+ * const { approved } = await ctx.requestApproval({
29
+ * message: `This will call production API: ${input.url}`,
30
+ * });
31
+ * if (!approved) return { error: 'User rejected the action' };
32
+ * }
33
+ * return fetch(input.url);
34
+ * }
35
+ * );
36
+ * ```
37
+ */
38
+ requestApproval(input: {
39
+ message: string;
40
+ metadata?: Record<string, unknown>;
41
+ }): Promise<{
42
+ approved: boolean;
43
+ reason?: string;
44
+ }>;
45
+ }
8
46
  /**
9
47
  * Options for configuring tool behavior.
10
48
  */
@@ -36,13 +74,13 @@ interface DefinedTool<T extends z.ZodType> {
36
74
  /** Zod schema for validating input */
37
75
  _zodSchema: T;
38
76
  /** The function to execute when the tool is called */
39
- fn: (input: z.infer<T>) => unknown | Promise<unknown>;
77
+ fn: (input: z.infer<T>, ctx: ToolExecutionContext) => unknown | Promise<unknown>;
40
78
  /** Configuration options for the tool */
41
79
  _options: ToolOptions;
42
80
  /** Converts this tool to a ToolDefinition for registration with the server */
43
81
  _toToolDefinition: (name: string) => ToolDefinition;
44
82
  /** Validates input and executes the tool function */
45
- _execute: (input: unknown) => Promise<unknown>;
83
+ _execute: (input: unknown, ctx: ToolExecutionContext) => Promise<unknown>;
46
84
  }
47
85
  /**
48
86
  * Defines a tool with no input parameters that can be called by the AI.
@@ -61,7 +99,7 @@ interface DefinedTool<T extends z.ZodType> {
61
99
  * );
62
100
  * ```
63
101
  */
64
- declare function defineTool<TReturn>(description: string, fn: () => TReturn | Promise<TReturn>, options?: ToolOptions): DefinedTool<z.ZodObject<{}>>;
102
+ declare function defineTool<TReturn>(description: string, fn: (ctx: ToolExecutionContext) => TReturn | Promise<TReturn>, options?: ToolOptions): DefinedTool<z.ZodObject<{}>>;
65
103
  /**
66
104
  * Defines a tool with typed input parameters that can be called by the AI.
67
105
  *
@@ -87,7 +125,7 @@ declare function defineTool<TReturn>(description: string, fn: () => TReturn | Pr
87
125
  * );
88
126
  * ```
89
127
  */
90
- declare function defineTool<TSchema extends z.ZodType>(description: string, schema: TSchema, fn: (input: z.infer<TSchema>) => unknown | Promise<unknown>, options?: ToolOptions): DefinedTool<TSchema>;
128
+ declare function defineTool<TSchema extends z.ZodType>(description: string, schema: TSchema, fn: (input: z.infer<TSchema>, ctx: ToolExecutionContext) => unknown | Promise<unknown>, options?: ToolOptions): DefinedTool<TSchema>;
91
129
  /**
92
130
  * A collection of named tools.
93
131
  * Used to register multiple tools with the useAI hook.
@@ -111,7 +149,7 @@ declare function convertToolsToDefinitions(tools: ToolsDefinition): ToolDefiniti
111
149
  * @throws Error if the tool is not found
112
150
  * @internal
113
151
  */
114
- declare function executeDefinedTool(tools: ToolsDefinition, toolName: string, input: unknown): Promise<unknown>;
152
+ declare function executeDefinedTool(tools: ToolsDefinition, toolName: string, input: unknown, ctx: ToolExecutionContext): Promise<unknown>;
115
153
 
116
154
  /**
117
155
  * Options for configuring the useAI hook.
@@ -1155,6 +1193,10 @@ interface PendingToolApproval {
1155
1193
  toolCallName: string;
1156
1194
  toolCallArgs: Record<string, unknown>;
1157
1195
  annotations?: ToolAnnotations;
1196
+ /** Optional message explaining why approval is needed (runtime approval) */
1197
+ message?: string;
1198
+ /** Optional metadata for the approval request (runtime approval) */
1199
+ metadata?: Record<string, unknown>;
1158
1200
  }
1159
1201
  interface UseToolSystemOptions {
1160
1202
  /** Reference to the UseAI client for sending responses */
@@ -2376,4 +2418,4 @@ interface UseDropdownStateOptions {
2376
2418
  */
2377
2419
  declare function useDropdownState(options?: UseDropdownStateOptions): UseDropdownStateReturn;
2378
2420
 
2379
- export { type AgentContextValue, type Chat, type ChatContextValue, type ChatMetadata, type ChatPanelProps, type ChatRepository, CloseButton, type CommandContextValue, type CommandRepository, type CreateChatOptions, type CreateCommandOptions, DEFAULT_MAX_FILE_SIZE, type DefinedTool, type DropZoneProps, EmbedFileUploadBackend, type ExecutingToolDisplay, type FileAttachment, type FileProcessingState, type FileProcessingStatus, type FileTransformer, type FileTransformerContext, type FileTransformerMap, type FileUploadBackend, type FileUploadConfig, type FloatingButtonProps, type InlineSaveProps, type ListChatsOptions, type ListCommandsOptions, LocalStorageChatRepository, LocalStorageCommandRepository, type Message, type PendingToolApproval, type PersistedContentPart, type PersistedFileContent, type PersistedFileMetadata, type PersistedMessage, type PersistedMessageContent, type PersistedTextContent, type ProcessAttachmentsConfig, type PromptsContextValue, type RegisterToolsOptions, type SavedCommand, type SendMessageOptions, type ToolOptions, type ToolRegistryContextValue, type ToolsDefinition, type TriggerWorkflowOptions, UseAIChat, UseAIChatPanel, type UseAIChatPanelProps, type UseAIChatPanelStrings, type UseAIChatPanelTheme, type UseAIChatProps, UseAIClient, type UseAIConfig, type UseAIContextValue, UseAIFloatingButton, UseAIFloatingChatWrapper, type UseAIOptions, UseAIProvider, type UseAIProviderProps, type UseAIResult, type UseAIStrings, type UseAITheme, type UseAIWorkflowResult, type UseAgentSelectionOptions, type UseAgentSelectionReturn, type UseChatManagementOptions, type UseChatManagementReturn, type UseCommandManagementOptions, type UseCommandManagementReturn, type UseDropdownStateOptions, type UseDropdownStateReturn, type UseFeedbackOptions, type UseFeedbackReturn, type UseFileUploadOptions, type UseFileUploadReturn, type UseMessageQueueOptions, type UseMessageQueueReturn, type UsePromptStateOptions, type UsePromptStateReturn, type UseServerEventsOptions, type UseServerEventsReturn, type UseSlashCommandsOptions, type UseSlashCommandsReturn, type UseToolSystemOptions, type UseToolSystemReturn, type WorkflowProgress, clearTransformationCache, convertToolsToDefinitions, defaultStrings, defaultTheme, defineTool, executeDefinedTool, findTransformerPattern, generateChatId, generateCommandId, generateMessageId, matchesMimeType, processAttachments, useAI, useAIContext, useAIWorkflow, useAgentSelection, useChatManagement, useCommandManagement, useDropdownState, useFeedback, useFileUpload, useMessageQueue, usePromptState, useServerEvents, useSlashCommands, useStableTools, useStrings, useTheme, useToolSystem, validateCommandName };
2421
+ export { type AgentContextValue, type Chat, type ChatContextValue, type ChatMetadata, type ChatPanelProps, type ChatRepository, CloseButton, type CommandContextValue, type CommandRepository, type CreateChatOptions, type CreateCommandOptions, DEFAULT_MAX_FILE_SIZE, type DefinedTool, type DropZoneProps, EmbedFileUploadBackend, type ExecutingToolDisplay, type FileAttachment, type FileProcessingState, type FileProcessingStatus, type FileTransformer, type FileTransformerContext, type FileTransformerMap, type FileUploadBackend, type FileUploadConfig, type FloatingButtonProps, type InlineSaveProps, type ListChatsOptions, type ListCommandsOptions, LocalStorageChatRepository, LocalStorageCommandRepository, type Message, type PendingToolApproval, type PersistedContentPart, type PersistedFileContent, type PersistedFileMetadata, type PersistedMessage, type PersistedMessageContent, type PersistedTextContent, type ProcessAttachmentsConfig, type PromptsContextValue, type RegisterToolsOptions, type SavedCommand, type SendMessageOptions, type ToolExecutionContext, type ToolOptions, type ToolRegistryContextValue, type ToolsDefinition, type TriggerWorkflowOptions, UseAIChat, UseAIChatPanel, type UseAIChatPanelProps, type UseAIChatPanelStrings, type UseAIChatPanelTheme, type UseAIChatProps, UseAIClient, type UseAIConfig, type UseAIContextValue, UseAIFloatingButton, UseAIFloatingChatWrapper, type UseAIOptions, UseAIProvider, type UseAIProviderProps, type UseAIResult, type UseAIStrings, type UseAITheme, type UseAIWorkflowResult, type UseAgentSelectionOptions, type UseAgentSelectionReturn, type UseChatManagementOptions, type UseChatManagementReturn, type UseCommandManagementOptions, type UseCommandManagementReturn, type UseDropdownStateOptions, type UseDropdownStateReturn, type UseFeedbackOptions, type UseFeedbackReturn, type UseFileUploadOptions, type UseFileUploadReturn, type UseMessageQueueOptions, type UseMessageQueueReturn, type UsePromptStateOptions, type UsePromptStateReturn, type UseServerEventsOptions, type UseServerEventsReturn, type UseSlashCommandsOptions, type UseSlashCommandsReturn, type UseToolSystemOptions, type UseToolSystemReturn, type WorkflowProgress, clearTransformationCache, convertToolsToDefinitions, defaultStrings, defaultTheme, defineTool, executeDefinedTool, findTransformerPattern, generateChatId, generateCommandId, generateMessageId, matchesMimeType, processAttachments, useAI, useAIContext, useAIWorkflow, useAgentSelection, useChatManagement, useCommandManagement, useDropdownState, useFeedback, useFileUpload, useMessageQueue, usePromptState, useServerEvents, useSlashCommands, useStableTools, useStrings, useTheme, useToolSystem, validateCommandName };
package/dist/index.js CHANGED
@@ -1638,7 +1638,8 @@ function ToolApprovalDialog({
1638
1638
  const [showDetails, setShowDetails] = useState4(false);
1639
1639
  const displayName = annotations?.title || toolCallName;
1640
1640
  const isBatch = toolCount > 1;
1641
- const message = isBatch ? strings.toolApproval.batchMessage?.replace("{count}", String(toolCount)) ?? `${toolCount} actions are waiting for your approval` : strings.toolApproval.message.replace("{toolName}", displayName);
1641
+ const runtimeMessage = pendingTools.find((t) => t.message)?.message;
1642
+ const message = runtimeMessage ? runtimeMessage : isBatch ? strings.toolApproval.batchMessage?.replace("{count}", String(toolCount)) ?? `${toolCount} actions are waiting for your approval` : strings.toolApproval.message.replace("{toolName}", displayName);
1642
1643
  const getToolDisplayName = (tool) => tool.annotations?.title || tool.toolCallName;
1643
1644
  return /* @__PURE__ */ jsxs7(
1644
1645
  "div",
@@ -3605,7 +3606,8 @@ function defineTool(description, schemaOrFn, fnOrOptions, options) {
3605
3606
  let actualFn;
3606
3607
  let actualOptions;
3607
3608
  if (isNoParamFunction) {
3608
- actualFn = schemaOrFn;
3609
+ const noParamFn = schemaOrFn;
3610
+ actualFn = (_input, ctx) => noParamFn(ctx);
3609
3611
  actualOptions = fnOrOptions || {};
3610
3612
  } else {
3611
3613
  actualFn = fnOrOptions;
@@ -3639,21 +3641,21 @@ function defineTool(description, schemaOrFn, fnOrOptions, options) {
3639
3641
  }
3640
3642
  return toolDef;
3641
3643
  },
3642
- async _execute(input) {
3644
+ async _execute(input, ctx) {
3643
3645
  const validated = this._zodSchema.parse(input);
3644
- return await actualFn(validated);
3646
+ return await actualFn(validated, ctx);
3645
3647
  }
3646
3648
  };
3647
3649
  }
3648
3650
  function convertToolsToDefinitions(tools) {
3649
3651
  return Object.entries(tools).map(([name, tool]) => tool._toToolDefinition(name));
3650
3652
  }
3651
- async function executeDefinedTool(tools, toolName, input) {
3653
+ async function executeDefinedTool(tools, toolName, input, ctx) {
3652
3654
  const tool = tools[toolName];
3653
3655
  if (!tool) {
3654
3656
  throw new Error(`Tool "${toolName}" not found`);
3655
3657
  }
3656
- return await tool._execute(input);
3658
+ return await tool._execute(input, ctx);
3657
3659
  }
3658
3660
 
3659
3661
  // src/providers/chatRepository/LocalStorageChatRepository.ts
@@ -4344,6 +4346,7 @@ function useToolSystem({
4344
4346
  const waitersRef = useRef7(/* @__PURE__ */ new Map());
4345
4347
  const [pendingApprovals, setPendingApprovals] = useState9([]);
4346
4348
  const pendingApprovalToolCallsRef = useRef7(/* @__PURE__ */ new Map());
4349
+ const runtimeApprovalResolversRef = useRef7(/* @__PURE__ */ new Map());
4347
4350
  const registerTools = useCallback7((id, tools, options) => {
4348
4351
  const existingTools = toolRegistryRef.current.get(id);
4349
4352
  toolRegistryRef.current.set(id, tools);
@@ -4453,7 +4456,9 @@ function useToolSystem({
4453
4456
  toolCallId: event.toolCallId,
4454
4457
  toolCallName: event.toolCallName,
4455
4458
  toolCallArgs: event.toolCallArgs,
4456
- annotations: event.annotations
4459
+ annotations: event.annotations,
4460
+ message: event.message,
4461
+ metadata: event.metadata
4457
4462
  }
4458
4463
  ]);
4459
4464
  }, []);
@@ -4466,8 +4471,26 @@ function useToolSystem({
4466
4471
  try {
4467
4472
  const ownerId = toolOwnershipRef.current.get(name);
4468
4473
  console.log(`[useToolSystem] Tool "${name}" owned by component:`, ownerId);
4474
+ const ctx = {
4475
+ requestApproval: ({ message, metadata }) => {
4476
+ return new Promise((resolve) => {
4477
+ const approvalId = `${toolCallId}-runtime-${Date.now()}`;
4478
+ runtimeApprovalResolversRef.current.set(approvalId, resolve);
4479
+ setPendingApprovals((prev) => [
4480
+ ...prev,
4481
+ {
4482
+ toolCallId: approvalId,
4483
+ toolCallName: name,
4484
+ toolCallArgs: input || {},
4485
+ message,
4486
+ metadata
4487
+ }
4488
+ ]);
4489
+ });
4490
+ }
4491
+ };
4469
4492
  console.log("[useToolSystem] Executing tool...");
4470
- const result = await executeDefinedTool(aggregatedToolsRef.current, name, input);
4493
+ const result = await executeDefinedTool(aggregatedToolsRef.current, name, input, ctx);
4471
4494
  const isErrorResult = result && typeof result === "object" && ("error" in result || result.success === false);
4472
4495
  const ownerIsInvisible = ownerId ? isInvisible(ownerId) : false;
4473
4496
  if (ownerId && !isErrorResult && !ownerIsInvisible) {
@@ -4512,24 +4535,32 @@ function useToolSystem({
4512
4535
  if (!clientRef.current) return;
4513
4536
  console.log("[useToolSystem] Approving all tool calls:", pendingApprovals.length);
4514
4537
  const pendingTools = [...pendingApprovals];
4515
- for (const pending of pendingTools) {
4516
- clientRef.current.sendToolApprovalResponse(pending.toolCallId, true);
4517
- }
4518
4538
  setPendingApprovals([]);
4519
- for (const tool of pendingTools) {
4520
- await executePendingToolAfterApproval(tool.toolCallId);
4539
+ for (const pending of pendingTools) {
4540
+ const runtimeResolver = runtimeApprovalResolversRef.current.get(pending.toolCallId);
4541
+ if (runtimeResolver) {
4542
+ runtimeApprovalResolversRef.current.delete(pending.toolCallId);
4543
+ runtimeResolver({ approved: true });
4544
+ } else {
4545
+ clientRef.current.sendToolApprovalResponse(pending.toolCallId, true);
4546
+ await executePendingToolAfterApproval(pending.toolCallId);
4547
+ }
4521
4548
  }
4522
4549
  }, [clientRef, pendingApprovals, executePendingToolAfterApproval]);
4523
4550
  const rejectAll = useCallback7((reason) => {
4524
4551
  if (!clientRef.current) return;
4525
4552
  console.log("[useToolSystem] Rejecting all tool calls:", pendingApprovals.length, reason);
4526
4553
  const pendingTools = [...pendingApprovals];
4527
- for (const pending of pendingTools) {
4528
- clientRef.current.sendToolApprovalResponse(pending.toolCallId, false, reason);
4529
- }
4530
4554
  setPendingApprovals([]);
4531
- for (const tool of pendingTools) {
4532
- pendingApprovalToolCallsRef.current.delete(tool.toolCallId);
4555
+ for (const pending of pendingTools) {
4556
+ const runtimeResolver = runtimeApprovalResolversRef.current.get(pending.toolCallId);
4557
+ if (runtimeResolver) {
4558
+ runtimeApprovalResolversRef.current.delete(pending.toolCallId);
4559
+ runtimeResolver({ approved: false, reason });
4560
+ } else {
4561
+ clientRef.current.sendToolApprovalResponse(pending.toolCallId, false, reason);
4562
+ pendingApprovalToolCallsRef.current.delete(pending.toolCallId);
4563
+ }
4533
4564
  }
4534
4565
  }, [clientRef, pendingApprovals]);
4535
4566
  return {
@@ -5326,19 +5357,19 @@ function useStableTools(tools) {
5326
5357
  return stableToolsRef.current;
5327
5358
  }
5328
5359
  function createStableToolWrapper(name, tool, latestToolsRef) {
5329
- const stableHandler = (input) => {
5360
+ const stableHandler = (input, ctx) => {
5330
5361
  const currentTool = latestToolsRef.current[name];
5331
5362
  if (!currentTool) {
5332
5363
  throw new Error(`Tool "${name}" no longer exists`);
5333
5364
  }
5334
- return currentTool.fn(input);
5365
+ return currentTool.fn(input, ctx);
5335
5366
  };
5336
- const stableExecute = async (input) => {
5367
+ const stableExecute = async (input, ctx) => {
5337
5368
  const currentTool = latestToolsRef.current[name];
5338
5369
  if (!currentTool) {
5339
5370
  throw new Error(`Tool "${name}" no longer exists`);
5340
5371
  }
5341
- return await currentTool._execute(input);
5372
+ return await currentTool._execute(input, ctx);
5342
5373
  };
5343
5374
  return {
5344
5375
  description: tool.description,
@@ -5546,7 +5577,10 @@ function useAIWorkflow(runner, workflowId) {
5546
5577
  console.log(`[useAIWorkflow] Executing tool: ${toolName}`, toolArgs);
5547
5578
  console.log(`[useAIWorkflow] Available tools:`, Object.keys(currentWorkflow.tools));
5548
5579
  try {
5549
- const result = await executeDefinedTool(currentWorkflow.tools, toolName, toolArgs);
5580
+ const noopCtx = {
5581
+ requestApproval: async () => ({ approved: true })
5582
+ };
5583
+ const result = await executeDefinedTool(currentWorkflow.tools, toolName, toolArgs, noopCtx);
5550
5584
  currentWorkflow.toolCalls.push({
5551
5585
  toolName,
5552
5586
  args: toolArgs,