@usecrow/ui 0.1.25 → 0.1.27

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.cts CHANGED
@@ -230,8 +230,10 @@ interface CrowWidgetProps {
230
230
  onIdentify?: (identify: IdentifyFunction) => void;
231
231
  /** Client-side tools the agent can call */
232
232
  tools?: ToolsMap;
233
+ /** Callback fired when a server-side tool completes, with the tool name and full result data */
234
+ onToolResult?: (toolName: string, result: Record<string, unknown>) => void;
233
235
  }
234
- declare function CrowWidget({ productId, apiUrl, variant, styles: propStyles, previewMode, showThinking: showThinkingProp, agentName: agentNameProp, welcomeMessage: welcomeMessageProp, onReady, onIdentify, tools, }: CrowWidgetProps): react_jsx_runtime.JSX.Element;
236
+ declare function CrowWidget({ productId, apiUrl, variant, styles: propStyles, previewMode, showThinking: showThinkingProp, agentName: agentNameProp, welcomeMessage: welcomeMessageProp, onReady, onIdentify, tools, onToolResult, }: CrowWidgetProps): react_jsx_runtime.JSX.Element;
235
237
 
236
238
  interface CrowCopilotProps {
237
239
  /** Product ID for this copilot */
@@ -264,8 +266,10 @@ interface CrowCopilotProps {
264
266
  className?: string;
265
267
  /** Callback when copilot is ready */
266
268
  onReady?: () => void;
269
+ /** Callback fired when a server-side tool completes, with the tool name and full result data */
270
+ onToolResult?: (toolName: string, result: Record<string, unknown>) => void;
267
271
  }
268
- declare function CrowCopilot({ productId, apiUrl, variant, title, agentName: agentNameProp, welcomeMessage: welcomeMessageProp, position, width, defaultOpen, showClose, onClose, styles: propStyles, previewMode, className, onReady, }: CrowCopilotProps): react_jsx_runtime.JSX.Element;
272
+ declare function CrowCopilot({ productId, apiUrl, variant, title, agentName: agentNameProp, welcomeMessage: welcomeMessageProp, position, width, defaultOpen, showClose, onClose, styles: propStyles, previewMode, className, onReady, onToolResult, }: CrowCopilotProps): react_jsx_runtime.JSX.Element;
269
273
 
270
274
  interface CrowProviderProps extends CrowClientConfig {
271
275
  children: React.ReactNode;
@@ -448,6 +452,7 @@ interface Message {
448
452
  citations?: Citation[];
449
453
  thinking?: string;
450
454
  thinkingComplete?: boolean;
455
+ toolCalls?: ToolCall[];
451
456
  links?: ToolResultLink[];
452
457
  }
453
458
  interface Citation {
@@ -555,9 +560,10 @@ interface UseChatOptions {
555
560
  onConversationId?: (id: string) => void;
556
561
  onWorkflowEvent?: (event: WorkflowEvent) => void;
557
562
  onToolCall?: (toolCall: ToolCallEvent) => void;
563
+ onToolResult?: (toolName: string, result: Record<string, unknown>) => void;
558
564
  onRestoredConversation?: (conversationId: string) => void;
559
565
  }
560
- declare function useChat({ productId, apiUrl, persistAnonymousConversations, welcomeMessage, selectedModel: initialSelectedModel, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall, onRestoredConversation, }: UseChatOptions): {
566
+ declare function useChat({ productId, apiUrl, persistAnonymousConversations, welcomeMessage, selectedModel: initialSelectedModel, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall, onToolResult, onRestoredConversation, }: UseChatOptions): {
561
567
  messages: Message[];
562
568
  isLoading: boolean;
563
569
  activeToolCalls: ToolCall[];
package/dist/index.d.ts CHANGED
@@ -230,8 +230,10 @@ interface CrowWidgetProps {
230
230
  onIdentify?: (identify: IdentifyFunction) => void;
231
231
  /** Client-side tools the agent can call */
232
232
  tools?: ToolsMap;
233
+ /** Callback fired when a server-side tool completes, with the tool name and full result data */
234
+ onToolResult?: (toolName: string, result: Record<string, unknown>) => void;
233
235
  }
234
- declare function CrowWidget({ productId, apiUrl, variant, styles: propStyles, previewMode, showThinking: showThinkingProp, agentName: agentNameProp, welcomeMessage: welcomeMessageProp, onReady, onIdentify, tools, }: CrowWidgetProps): react_jsx_runtime.JSX.Element;
236
+ declare function CrowWidget({ productId, apiUrl, variant, styles: propStyles, previewMode, showThinking: showThinkingProp, agentName: agentNameProp, welcomeMessage: welcomeMessageProp, onReady, onIdentify, tools, onToolResult, }: CrowWidgetProps): react_jsx_runtime.JSX.Element;
235
237
 
236
238
  interface CrowCopilotProps {
237
239
  /** Product ID for this copilot */
@@ -264,8 +266,10 @@ interface CrowCopilotProps {
264
266
  className?: string;
265
267
  /** Callback when copilot is ready */
266
268
  onReady?: () => void;
269
+ /** Callback fired when a server-side tool completes, with the tool name and full result data */
270
+ onToolResult?: (toolName: string, result: Record<string, unknown>) => void;
267
271
  }
268
- declare function CrowCopilot({ productId, apiUrl, variant, title, agentName: agentNameProp, welcomeMessage: welcomeMessageProp, position, width, defaultOpen, showClose, onClose, styles: propStyles, previewMode, className, onReady, }: CrowCopilotProps): react_jsx_runtime.JSX.Element;
272
+ declare function CrowCopilot({ productId, apiUrl, variant, title, agentName: agentNameProp, welcomeMessage: welcomeMessageProp, position, width, defaultOpen, showClose, onClose, styles: propStyles, previewMode, className, onReady, onToolResult, }: CrowCopilotProps): react_jsx_runtime.JSX.Element;
269
273
 
270
274
  interface CrowProviderProps extends CrowClientConfig {
271
275
  children: React.ReactNode;
@@ -448,6 +452,7 @@ interface Message {
448
452
  citations?: Citation[];
449
453
  thinking?: string;
450
454
  thinkingComplete?: boolean;
455
+ toolCalls?: ToolCall[];
451
456
  links?: ToolResultLink[];
452
457
  }
453
458
  interface Citation {
@@ -555,9 +560,10 @@ interface UseChatOptions {
555
560
  onConversationId?: (id: string) => void;
556
561
  onWorkflowEvent?: (event: WorkflowEvent) => void;
557
562
  onToolCall?: (toolCall: ToolCallEvent) => void;
563
+ onToolResult?: (toolName: string, result: Record<string, unknown>) => void;
558
564
  onRestoredConversation?: (conversationId: string) => void;
559
565
  }
560
- declare function useChat({ productId, apiUrl, persistAnonymousConversations, welcomeMessage, selectedModel: initialSelectedModel, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall, onRestoredConversation, }: UseChatOptions): {
566
+ declare function useChat({ productId, apiUrl, persistAnonymousConversations, welcomeMessage, selectedModel: initialSelectedModel, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall, onToolResult, onRestoredConversation, }: UseChatOptions): {
561
567
  messages: Message[];
562
568
  isLoading: boolean;
563
569
  activeToolCalls: ToolCall[];
package/dist/index.js CHANGED
@@ -52,6 +52,7 @@ function useChat({
52
52
  onConversationId,
53
53
  onWorkflowEvent,
54
54
  onToolCall,
55
+ onToolResult,
55
56
  onRestoredConversation
56
57
  }) {
57
58
  const effectiveWelcomeMessage = welcomeMessage || DEFAULT_WELCOME_MESSAGE;
@@ -69,6 +70,7 @@ function useChat({
69
70
  const [selectedModel, setSelectedModel] = useState(initialSelectedModel || DEFAULT_MODEL);
70
71
  const abortControllerRef = useRef(null);
71
72
  const hasCheckedPersistRef = useRef(false);
73
+ const streamingToolCallsRef = useRef([]);
72
74
  useEffect(() => {
73
75
  if (initialSelectedModel) {
74
76
  setSelectedModel((prev) => prev !== initialSelectedModel ? initialSelectedModel : prev);
@@ -150,6 +152,22 @@ function useChat({
150
152
  const data = line.slice(6).trim();
151
153
  if (data === "[DONE]") {
152
154
  setIsLoading(false);
155
+ const finalToolCalls = [...streamingToolCallsRef.current];
156
+ if (finalToolCalls.length > 0) {
157
+ setMessages(
158
+ (prev) => prev.map(
159
+ (msg) => msg.id === botMsgId ? { ...msg, toolCalls: finalToolCalls, thinkingComplete: true } : msg
160
+ )
161
+ );
162
+ } else {
163
+ setMessages(
164
+ (prev) => prev.map(
165
+ (msg) => msg.id === botMsgId ? { ...msg, thinkingComplete: true } : msg
166
+ )
167
+ );
168
+ }
169
+ setActiveToolCalls([]);
170
+ streamingToolCallsRef.current = [];
153
171
  for (const tool of pendingClientTools) {
154
172
  onToolCall?.({
155
173
  type: "client_call",
@@ -232,16 +250,15 @@ function useChat({
232
250
  toolName: parsed.tool_name,
233
251
  arguments: parsed.arguments
234
252
  });
235
- setActiveToolCalls((prev) => [
236
- ...prev,
237
- {
238
- id: `tool-${Date.now()}`,
239
- name: parsed.tool_name,
240
- arguments: parsed.arguments || {},
241
- status: "executing",
242
- timestamp: /* @__PURE__ */ new Date()
243
- }
244
- ]);
253
+ const newToolCall = {
254
+ id: `tool-${Date.now()}`,
255
+ name: parsed.tool_name,
256
+ arguments: parsed.arguments || {},
257
+ status: "executing",
258
+ timestamp: /* @__PURE__ */ new Date()
259
+ };
260
+ streamingToolCallsRef.current = [...streamingToolCallsRef.current, newToolCall];
261
+ setActiveToolCalls((prev) => [...prev, newToolCall]);
245
262
  break;
246
263
  case "tool_call_complete":
247
264
  onToolCall?.({
@@ -249,11 +266,25 @@ function useChat({
249
266
  toolName: parsed.tool_name,
250
267
  success: parsed.success
251
268
  });
252
- setActiveToolCalls(
253
- (prev) => prev.map(
254
- (tool) => tool.name === parsed.tool_name ? { ...tool, status: parsed.success ? "complete" : "error" } : tool
255
- )
256
- );
269
+ const newStatus = parsed.success ? "complete" : "error";
270
+ let updated = false;
271
+ streamingToolCallsRef.current = streamingToolCallsRef.current.map((tool) => {
272
+ if (!updated && tool.name === parsed.tool_name && tool.status === "executing") {
273
+ updated = true;
274
+ return { ...tool, status: newStatus };
275
+ }
276
+ return tool;
277
+ });
278
+ setActiveToolCalls((prev) => {
279
+ let updated2 = false;
280
+ return prev.map((tool) => {
281
+ if (!updated2 && tool.name === parsed.tool_name && tool.status === "executing") {
282
+ updated2 = true;
283
+ return { ...tool, status: newStatus };
284
+ }
285
+ return tool;
286
+ });
287
+ });
257
288
  break;
258
289
  case "tool_result_links":
259
290
  if (parsed.links && Array.isArray(parsed.links)) {
@@ -264,7 +295,26 @@ function useChat({
264
295
  );
265
296
  }
266
297
  break;
298
+ case "tool_result":
299
+ if (parsed.tool_name && parsed.result) {
300
+ onToolResult?.(parsed.tool_name, parsed.result);
301
+ }
302
+ break;
267
303
  case "client_tool_call":
304
+ onToolCall?.({
305
+ type: "start",
306
+ toolName: parsed.tool_name,
307
+ arguments: parsed.arguments
308
+ });
309
+ const clientToolCall = {
310
+ id: `tool-${Date.now()}`,
311
+ name: parsed.tool_name,
312
+ arguments: parsed.arguments || {},
313
+ status: "executing",
314
+ timestamp: /* @__PURE__ */ new Date()
315
+ };
316
+ streamingToolCallsRef.current = [...streamingToolCallsRef.current, clientToolCall];
317
+ setActiveToolCalls((prev) => [...prev, clientToolCall]);
268
318
  pendingClientTools.push({
269
319
  toolName: parsed.tool_name,
270
320
  toolCallId: parsed.tool_call_id,
@@ -323,7 +373,7 @@ function useChat({
323
373
  abortControllerRef.current = null;
324
374
  }
325
375
  },
326
- [apiUrl, productId, conversationId, selectedModel, persistAnonymousConversations, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall]
376
+ [apiUrl, productId, conversationId, selectedModel, persistAnonymousConversations, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall, onToolResult]
327
377
  );
328
378
  const sendMessage = useCallback(
329
379
  (content) => {
@@ -331,6 +381,7 @@ function useChat({
331
381
  return { userMsgId: "", botMsgId: "" };
332
382
  }
333
383
  setActiveToolCalls([]);
384
+ streamingToolCallsRef.current = [];
334
385
  const userMsgId = generateMessageId("user");
335
386
  const botMsgId = generateMessageId("bot");
336
387
  setMessages((prev) => [
@@ -565,7 +616,16 @@ function useConversations({ productId, apiUrl = "" }) {
565
616
  id: `history-${idx}`,
566
617
  content: msg.content,
567
618
  isBot: msg.role === "assistant",
568
- timestamp: /* @__PURE__ */ new Date()
619
+ timestamp: /* @__PURE__ */ new Date(),
620
+ thinking: msg.thinking,
621
+ thinkingComplete: true,
622
+ toolCalls: msg.tool_calls?.map((tc, i) => ({
623
+ id: `history-tool-${idx}-${i}`,
624
+ name: tc.name,
625
+ arguments: tc.arguments || {},
626
+ status: tc.status,
627
+ timestamp: /* @__PURE__ */ new Date()
628
+ }))
569
629
  }));
570
630
  }
571
631
  } catch (error) {
@@ -593,7 +653,16 @@ function useConversations({ productId, apiUrl = "" }) {
593
653
  id: `history-${idx}`,
594
654
  content: msg.content,
595
655
  isBot: msg.role === "assistant",
596
- timestamp: /* @__PURE__ */ new Date()
656
+ timestamp: /* @__PURE__ */ new Date(),
657
+ thinking: msg.thinking,
658
+ thinkingComplete: true,
659
+ toolCalls: msg.tool_calls?.map((tc, i) => ({
660
+ id: `history-tool-${idx}-${i}`,
661
+ name: tc.name,
662
+ arguments: tc.arguments || {},
663
+ status: tc.status,
664
+ timestamp: /* @__PURE__ */ new Date()
665
+ }))
597
666
  }));
598
667
  }
599
668
  } catch (error) {
@@ -1914,15 +1983,19 @@ function MessageList({
1914
1983
  (lastIdx, m, i) => m.isBot ? i : lastIdx,
1915
1984
  -1
1916
1985
  );
1917
- return /* @__PURE__ */ jsx(Fragment, { children: messages.map((msg, index) => /* @__PURE__ */ jsx(
1918
- MessageBubble,
1919
- {
1920
- message: msg,
1921
- toolCalls: index === lastBotIndex ? activeToolCalls : void 0,
1922
- isLoading: index === lastBotIndex && isGenerating
1923
- },
1924
- msg.id
1925
- )) });
1986
+ return /* @__PURE__ */ jsx(Fragment, { children: messages.map((msg, index) => {
1987
+ const isLastBot = index === lastBotIndex;
1988
+ const toolCallsToShow = isLastBot && isGenerating ? activeToolCalls : msg.toolCalls || [];
1989
+ return /* @__PURE__ */ jsx(
1990
+ MessageBubble,
1991
+ {
1992
+ message: msg,
1993
+ toolCalls: toolCallsToShow,
1994
+ isLoading: isLastBot && isGenerating
1995
+ },
1996
+ msg.id
1997
+ );
1998
+ }) });
1926
1999
  }
1927
2000
  var MessagesContainer = forwardRef(({ children }, ref) => {
1928
2001
  const styles = useWidgetStyles2();
@@ -2747,7 +2820,8 @@ function CrowWidget({
2747
2820
  welcomeMessage: welcomeMessageProp,
2748
2821
  onReady,
2749
2822
  onIdentify,
2750
- tools
2823
+ tools,
2824
+ onToolResult
2751
2825
  }) {
2752
2826
  const {
2753
2827
  styles,
@@ -2825,6 +2899,7 @@ function CrowWidget({
2825
2899
  break;
2826
2900
  }
2827
2901
  },
2902
+ onToolResult,
2828
2903
  onToolCall: async (event) => {
2829
2904
  if (event.type === "client_call" && event.toolName && event.toolCallId) {
2830
2905
  try {
@@ -3264,7 +3339,8 @@ function CrowCopilot({
3264
3339
  styles: propStyles,
3265
3340
  previewMode = false,
3266
3341
  className,
3267
- onReady
3342
+ onReady,
3343
+ onToolResult
3268
3344
  }) {
3269
3345
  const {
3270
3346
  styles,
@@ -3305,6 +3381,7 @@ function CrowCopilot({
3305
3381
  },
3306
3382
  onConversationId: () => {
3307
3383
  },
3384
+ onToolResult,
3308
3385
  onToolCall: (event) => {
3309
3386
  if (event.type === "client_call" && event.toolName) {
3310
3387
  console.log(