@usecrow/ui 0.1.50 → 0.1.52
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.cjs +188 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -3
- package/dist/index.d.ts +18 -3
- package/dist/index.js +189 -56
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -201,6 +201,10 @@ interface WidgetConfigResponse {
|
|
|
201
201
|
label: string;
|
|
202
202
|
message: string;
|
|
203
203
|
}>;
|
|
204
|
+
/** Per-tool consent settings from dashboard (shield icon) */
|
|
205
|
+
toolConsentSettings?: Record<string, {
|
|
206
|
+
requires_consent: boolean;
|
|
207
|
+
}>;
|
|
204
208
|
}
|
|
205
209
|
|
|
206
210
|
/**
|
|
@@ -649,6 +653,10 @@ interface UseChatOptions {
|
|
|
649
653
|
welcomeMessage?: string;
|
|
650
654
|
/** AI model to use for this chat (defaults to DEFAULT_MODEL) */
|
|
651
655
|
selectedModel?: string;
|
|
656
|
+
/** Per-tool consent settings — when a tool has requires_consent, show Allow/Deny before executing */
|
|
657
|
+
toolConsentSettings?: Record<string, {
|
|
658
|
+
requires_consent: boolean;
|
|
659
|
+
}>;
|
|
652
660
|
onVerificationStatus?: (isVerified: boolean) => void;
|
|
653
661
|
onConversationId?: (id: string) => void;
|
|
654
662
|
onWorkflowEvent?: (event: WorkflowEvent) => void;
|
|
@@ -656,7 +664,7 @@ interface UseChatOptions {
|
|
|
656
664
|
onToolResult?: (toolName: string, result: Record<string, unknown>) => void;
|
|
657
665
|
onRestoredConversation?: (conversationId: string) => void;
|
|
658
666
|
}
|
|
659
|
-
declare function useChat({ productId, apiUrl, persistAnonymousConversations, welcomeMessage, selectedModel: initialSelectedModel, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall, onToolResult, onRestoredConversation, }: UseChatOptions): {
|
|
667
|
+
declare function useChat({ productId, apiUrl, persistAnonymousConversations, welcomeMessage, selectedModel: initialSelectedModel, toolConsentSettings, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall, onToolResult, onRestoredConversation, }: UseChatOptions): {
|
|
660
668
|
messages: Message[];
|
|
661
669
|
isLoading: boolean;
|
|
662
670
|
activeToolCalls: ToolCall[];
|
|
@@ -781,6 +789,10 @@ interface UseWidgetStylesResult {
|
|
|
781
789
|
label: string;
|
|
782
790
|
message: string;
|
|
783
791
|
}>;
|
|
792
|
+
/** Per-tool consent settings from dashboard */
|
|
793
|
+
toolConsentSettings: Record<string, {
|
|
794
|
+
requires_consent: boolean;
|
|
795
|
+
}>;
|
|
784
796
|
/** Refetch styles from API */
|
|
785
797
|
refetch: () => Promise<void>;
|
|
786
798
|
}
|
|
@@ -822,6 +834,10 @@ interface UseCopilotStylesResult {
|
|
|
822
834
|
welcomeMessage: string | undefined;
|
|
823
835
|
/** AI model configured for this product */
|
|
824
836
|
selectedModel: string | undefined;
|
|
837
|
+
/** Per-tool consent settings from dashboard */
|
|
838
|
+
toolConsentSettings: Record<string, {
|
|
839
|
+
requires_consent: boolean;
|
|
840
|
+
}>;
|
|
825
841
|
/** Refetch styles from API */
|
|
826
842
|
refetch: () => Promise<void>;
|
|
827
843
|
}
|
|
@@ -1087,10 +1103,9 @@ interface WidgetHeaderProps {
|
|
|
1087
1103
|
onNewChat: () => void;
|
|
1088
1104
|
onToggleHistory: () => void;
|
|
1089
1105
|
showMinimize?: boolean;
|
|
1090
|
-
isMinimized?: boolean;
|
|
1091
1106
|
onToggleMinimize?: () => void;
|
|
1092
1107
|
}
|
|
1093
|
-
declare function WidgetHeader({ isVerifiedUser, showConversationList, onNewChat, onToggleHistory, showMinimize,
|
|
1108
|
+
declare function WidgetHeader({ isVerifiedUser, showConversationList, onNewChat, onToggleHistory, showMinimize, onToggleMinimize, }: WidgetHeaderProps): react_jsx_runtime.JSX.Element;
|
|
1094
1109
|
|
|
1095
1110
|
/**
|
|
1096
1111
|
* CopilotToggleButton - Edge toggle button for floating copilot
|
package/dist/index.d.ts
CHANGED
|
@@ -201,6 +201,10 @@ interface WidgetConfigResponse {
|
|
|
201
201
|
label: string;
|
|
202
202
|
message: string;
|
|
203
203
|
}>;
|
|
204
|
+
/** Per-tool consent settings from dashboard (shield icon) */
|
|
205
|
+
toolConsentSettings?: Record<string, {
|
|
206
|
+
requires_consent: boolean;
|
|
207
|
+
}>;
|
|
204
208
|
}
|
|
205
209
|
|
|
206
210
|
/**
|
|
@@ -649,6 +653,10 @@ interface UseChatOptions {
|
|
|
649
653
|
welcomeMessage?: string;
|
|
650
654
|
/** AI model to use for this chat (defaults to DEFAULT_MODEL) */
|
|
651
655
|
selectedModel?: string;
|
|
656
|
+
/** Per-tool consent settings — when a tool has requires_consent, show Allow/Deny before executing */
|
|
657
|
+
toolConsentSettings?: Record<string, {
|
|
658
|
+
requires_consent: boolean;
|
|
659
|
+
}>;
|
|
652
660
|
onVerificationStatus?: (isVerified: boolean) => void;
|
|
653
661
|
onConversationId?: (id: string) => void;
|
|
654
662
|
onWorkflowEvent?: (event: WorkflowEvent) => void;
|
|
@@ -656,7 +664,7 @@ interface UseChatOptions {
|
|
|
656
664
|
onToolResult?: (toolName: string, result: Record<string, unknown>) => void;
|
|
657
665
|
onRestoredConversation?: (conversationId: string) => void;
|
|
658
666
|
}
|
|
659
|
-
declare function useChat({ productId, apiUrl, persistAnonymousConversations, welcomeMessage, selectedModel: initialSelectedModel, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall, onToolResult, onRestoredConversation, }: UseChatOptions): {
|
|
667
|
+
declare function useChat({ productId, apiUrl, persistAnonymousConversations, welcomeMessage, selectedModel: initialSelectedModel, toolConsentSettings, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall, onToolResult, onRestoredConversation, }: UseChatOptions): {
|
|
660
668
|
messages: Message[];
|
|
661
669
|
isLoading: boolean;
|
|
662
670
|
activeToolCalls: ToolCall[];
|
|
@@ -781,6 +789,10 @@ interface UseWidgetStylesResult {
|
|
|
781
789
|
label: string;
|
|
782
790
|
message: string;
|
|
783
791
|
}>;
|
|
792
|
+
/** Per-tool consent settings from dashboard */
|
|
793
|
+
toolConsentSettings: Record<string, {
|
|
794
|
+
requires_consent: boolean;
|
|
795
|
+
}>;
|
|
784
796
|
/** Refetch styles from API */
|
|
785
797
|
refetch: () => Promise<void>;
|
|
786
798
|
}
|
|
@@ -822,6 +834,10 @@ interface UseCopilotStylesResult {
|
|
|
822
834
|
welcomeMessage: string | undefined;
|
|
823
835
|
/** AI model configured for this product */
|
|
824
836
|
selectedModel: string | undefined;
|
|
837
|
+
/** Per-tool consent settings from dashboard */
|
|
838
|
+
toolConsentSettings: Record<string, {
|
|
839
|
+
requires_consent: boolean;
|
|
840
|
+
}>;
|
|
825
841
|
/** Refetch styles from API */
|
|
826
842
|
refetch: () => Promise<void>;
|
|
827
843
|
}
|
|
@@ -1087,10 +1103,9 @@ interface WidgetHeaderProps {
|
|
|
1087
1103
|
onNewChat: () => void;
|
|
1088
1104
|
onToggleHistory: () => void;
|
|
1089
1105
|
showMinimize?: boolean;
|
|
1090
|
-
isMinimized?: boolean;
|
|
1091
1106
|
onToggleMinimize?: () => void;
|
|
1092
1107
|
}
|
|
1093
|
-
declare function WidgetHeader({ isVerifiedUser, showConversationList, onNewChat, onToggleHistory, showMinimize,
|
|
1108
|
+
declare function WidgetHeader({ isVerifiedUser, showConversationList, onNewChat, onToggleHistory, showMinimize, onToggleMinimize, }: WidgetHeaderProps): react_jsx_runtime.JSX.Element;
|
|
1094
1109
|
|
|
1095
1110
|
/**
|
|
1096
1111
|
* CopilotToggleButton - Edge toggle button for floating copilot
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { motion, AnimatePresence } from 'framer-motion';
|
|
|
3
3
|
import { DEFAULT_TOOLS, CrowClient } from '@usecrow/client';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
6
|
-
import { Square, ArrowUp, ChevronDown, Check, MessageCircle, Plus, History,
|
|
6
|
+
import { Square, ArrowUp, ChevronDown, Check, MessageCircle, Plus, RotateCcw, History, X, Brain, ChevronRight, Loader2 } from 'lucide-react';
|
|
7
7
|
import ReactMarkdown from 'react-markdown';
|
|
8
8
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
9
9
|
|
|
@@ -44,6 +44,7 @@ function useChat({
|
|
|
44
44
|
persistAnonymousConversations,
|
|
45
45
|
welcomeMessage,
|
|
46
46
|
selectedModel: initialSelectedModel,
|
|
47
|
+
toolConsentSettings,
|
|
47
48
|
onVerificationStatus,
|
|
48
49
|
onConversationId,
|
|
49
50
|
onWorkflowEvent,
|
|
@@ -68,6 +69,8 @@ function useChat({
|
|
|
68
69
|
const abortControllerRef = useRef(null);
|
|
69
70
|
const hasCheckedPersistRef = useRef(false);
|
|
70
71
|
const streamingToolCallsRef = useRef([]);
|
|
72
|
+
const toolConsentSettingsRef = useRef(toolConsentSettings);
|
|
73
|
+
toolConsentSettingsRef.current = toolConsentSettings;
|
|
71
74
|
useEffect(() => {
|
|
72
75
|
if (initialSelectedModel) {
|
|
73
76
|
setSelectedModel((prev) => prev !== initialSelectedModel ? initialSelectedModel : prev);
|
|
@@ -319,26 +322,43 @@ function useChat({
|
|
|
319
322
|
}
|
|
320
323
|
break;
|
|
321
324
|
case "client_tool_call":
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
325
|
+
{
|
|
326
|
+
const needsConsent = toolConsentSettingsRef.current?.[parsed.tool_name]?.requires_consent === true;
|
|
327
|
+
onToolCall?.({
|
|
328
|
+
type: "start",
|
|
329
|
+
toolName: parsed.tool_name,
|
|
330
|
+
arguments: parsed.arguments
|
|
331
|
+
});
|
|
332
|
+
if (needsConsent) {
|
|
333
|
+
const consentClientTc = {
|
|
334
|
+
id: parsed.tool_call_id || `tool-${Date.now()}`,
|
|
335
|
+
name: parsed.tool_name,
|
|
336
|
+
displayName: parsed.display_name || void 0,
|
|
337
|
+
arguments: parsed.arguments || {},
|
|
338
|
+
status: "awaiting_consent",
|
|
339
|
+
requiresConsent: true,
|
|
340
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
341
|
+
};
|
|
342
|
+
streamingToolCallsRef.current = [...streamingToolCallsRef.current, consentClientTc];
|
|
343
|
+
setActiveToolCalls((prev) => [...prev, consentClientTc]);
|
|
344
|
+
} else {
|
|
345
|
+
const clientToolCall = {
|
|
346
|
+
id: parsed.tool_call_id || `tool-${Date.now()}`,
|
|
347
|
+
name: parsed.tool_name,
|
|
348
|
+
displayName: parsed.display_name || void 0,
|
|
349
|
+
arguments: parsed.arguments || {},
|
|
350
|
+
status: "executing",
|
|
351
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
352
|
+
};
|
|
353
|
+
streamingToolCallsRef.current = [...streamingToolCallsRef.current, clientToolCall];
|
|
354
|
+
setActiveToolCalls((prev) => [...prev, clientToolCall]);
|
|
355
|
+
pendingClientTools.push({
|
|
356
|
+
toolName: parsed.tool_name,
|
|
357
|
+
toolCallId: parsed.tool_call_id,
|
|
358
|
+
arguments: parsed.arguments
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
}
|
|
342
362
|
break;
|
|
343
363
|
case "tool_consent_required":
|
|
344
364
|
onToolCall?.({
|
|
@@ -720,21 +740,36 @@ function useChat({
|
|
|
720
740
|
break;
|
|
721
741
|
case "client_tool_call":
|
|
722
742
|
{
|
|
723
|
-
const
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
743
|
+
const needsConsent2 = toolConsentSettingsRef.current?.[parsed.tool_name]?.requires_consent === true;
|
|
744
|
+
if (needsConsent2) {
|
|
745
|
+
const consentEntry2 = {
|
|
746
|
+
id: parsed.tool_call_id || `tool-${Date.now()}`,
|
|
747
|
+
name: parsed.tool_name,
|
|
748
|
+
displayName: parsed.display_name || void 0,
|
|
749
|
+
arguments: parsed.arguments || {},
|
|
750
|
+
status: "awaiting_consent",
|
|
751
|
+
requiresConsent: true,
|
|
752
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
753
|
+
};
|
|
754
|
+
streamingToolCallsRef.current = [...streamingToolCallsRef.current, consentEntry2];
|
|
755
|
+
setActiveToolCalls((prev) => [...prev, consentEntry2]);
|
|
756
|
+
} else {
|
|
757
|
+
const toolCallEntry = {
|
|
758
|
+
id: parsed.tool_call_id || `tool-${Date.now()}`,
|
|
759
|
+
name: parsed.tool_name,
|
|
760
|
+
displayName: parsed.display_name || void 0,
|
|
761
|
+
arguments: parsed.arguments || {},
|
|
762
|
+
status: "executing",
|
|
763
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
764
|
+
};
|
|
765
|
+
streamingToolCallsRef.current = [...streamingToolCallsRef.current, toolCallEntry];
|
|
766
|
+
setActiveToolCalls((prev) => [...prev, toolCallEntry]);
|
|
767
|
+
pendingClientTools.push({
|
|
768
|
+
toolName: parsed.tool_name,
|
|
769
|
+
toolCallId: parsed.tool_call_id,
|
|
770
|
+
arguments: parsed.arguments
|
|
771
|
+
});
|
|
772
|
+
}
|
|
738
773
|
}
|
|
739
774
|
break;
|
|
740
775
|
case "tool_consent_required":
|
|
@@ -1501,6 +1536,9 @@ function useWidgetStyles({
|
|
|
1501
1536
|
const [initialSuggestions, setInitialSuggestions] = useState(
|
|
1502
1537
|
styleCache.get(key)?.initialSuggestions || []
|
|
1503
1538
|
);
|
|
1539
|
+
const [toolConsentSettings, setToolConsentSettings] = useState(
|
|
1540
|
+
styleCache.get(key)?.toolConsentSettings || {}
|
|
1541
|
+
);
|
|
1504
1542
|
const [agentName, setAgentName] = useState(
|
|
1505
1543
|
styleCache.get(key)?.agentName || "Assistant"
|
|
1506
1544
|
);
|
|
@@ -1541,6 +1579,7 @@ function useWidgetStyles({
|
|
|
1541
1579
|
setWelcomeMessage(config.welcomeMessage ?? void 0);
|
|
1542
1580
|
setSelectedModel(config.model ?? void 0);
|
|
1543
1581
|
setInitialSuggestions(config.initialSuggestions || []);
|
|
1582
|
+
setToolConsentSettings(config.toolConsentSettings || {});
|
|
1544
1583
|
} catch (err) {
|
|
1545
1584
|
console.error("[CrowWidget] Failed to fetch styles:", err);
|
|
1546
1585
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -1579,6 +1618,7 @@ function useWidgetStyles({
|
|
|
1579
1618
|
welcomeMessage,
|
|
1580
1619
|
selectedModel,
|
|
1581
1620
|
initialSuggestions,
|
|
1621
|
+
toolConsentSettings,
|
|
1582
1622
|
refetch: fetchStyles
|
|
1583
1623
|
};
|
|
1584
1624
|
}
|
|
@@ -1614,6 +1654,9 @@ function useCopilotStyles({
|
|
|
1614
1654
|
const [selectedModel, setSelectedModel] = useState(
|
|
1615
1655
|
styleCache.get(key)?.model ?? void 0
|
|
1616
1656
|
);
|
|
1657
|
+
const [toolConsentSettings, setToolConsentSettings] = useState(
|
|
1658
|
+
styleCache.get(key)?.toolConsentSettings || {}
|
|
1659
|
+
);
|
|
1617
1660
|
const hasFetchedRef = useRef(false);
|
|
1618
1661
|
const fetchStyles = async () => {
|
|
1619
1662
|
if (skip) return;
|
|
@@ -1630,6 +1673,7 @@ function useCopilotStyles({
|
|
|
1630
1673
|
setPersistAnonymousConversations(config.persistAnonymousConversations ?? true);
|
|
1631
1674
|
setWelcomeMessage(config.welcomeMessage ?? void 0);
|
|
1632
1675
|
setSelectedModel(config.model ?? void 0);
|
|
1676
|
+
setToolConsentSettings(config.toolConsentSettings || {});
|
|
1633
1677
|
} catch (err) {
|
|
1634
1678
|
console.error("[CrowCopilot] Failed to fetch styles:", err);
|
|
1635
1679
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -1667,6 +1711,7 @@ function useCopilotStyles({
|
|
|
1667
1711
|
persistAnonymousConversations,
|
|
1668
1712
|
welcomeMessage,
|
|
1669
1713
|
selectedModel,
|
|
1714
|
+
toolConsentSettings,
|
|
1670
1715
|
refetch: fetchStyles
|
|
1671
1716
|
};
|
|
1672
1717
|
}
|
|
@@ -1911,7 +1956,6 @@ function WidgetHeader({
|
|
|
1911
1956
|
onNewChat,
|
|
1912
1957
|
onToggleHistory,
|
|
1913
1958
|
showMinimize = false,
|
|
1914
|
-
isMinimized = false,
|
|
1915
1959
|
onToggleMinimize
|
|
1916
1960
|
}) {
|
|
1917
1961
|
const { agentName, styles } = useWidgetStyleContext();
|
|
@@ -1933,7 +1977,7 @@ function WidgetHeader({
|
|
|
1933
1977
|
}
|
|
1934
1978
|
) }),
|
|
1935
1979
|
/* @__PURE__ */ jsxs("div", { className: "crow-flex crow-items-center crow-gap-1", children: [
|
|
1936
|
-
/* @__PURE__ */ jsx(
|
|
1980
|
+
isVerifiedUser ? /* @__PURE__ */ jsx(
|
|
1937
1981
|
"button",
|
|
1938
1982
|
{
|
|
1939
1983
|
onClick: onNewChat,
|
|
@@ -1942,6 +1986,15 @@ function WidgetHeader({
|
|
|
1942
1986
|
title: "New Chat",
|
|
1943
1987
|
children: /* @__PURE__ */ jsx(Plus, { size: 18, className: "crow-text-gray-700" })
|
|
1944
1988
|
}
|
|
1989
|
+
) : /* @__PURE__ */ jsx(
|
|
1990
|
+
"button",
|
|
1991
|
+
{
|
|
1992
|
+
onClick: onNewChat,
|
|
1993
|
+
className: "crow-p-1.5 hover:crow-bg-gray-200 crow-rounded crow-transition-colors",
|
|
1994
|
+
"aria-label": "Restart Chat",
|
|
1995
|
+
title: "Restart Chat",
|
|
1996
|
+
children: /* @__PURE__ */ jsx(RotateCcw, { size: 16, className: "crow-text-gray-700" })
|
|
1997
|
+
}
|
|
1945
1998
|
),
|
|
1946
1999
|
isVerifiedUser && /* @__PURE__ */ jsx(
|
|
1947
2000
|
"button",
|
|
@@ -1957,9 +2010,10 @@ function WidgetHeader({
|
|
|
1957
2010
|
"button",
|
|
1958
2011
|
{
|
|
1959
2012
|
onClick: onToggleMinimize,
|
|
1960
|
-
className: "crow-p-1 hover:crow-bg-gray-200 crow-rounded crow-transition-colors",
|
|
1961
|
-
"aria-label":
|
|
1962
|
-
|
|
2013
|
+
className: "crow-p-1.5 hover:crow-bg-gray-200 crow-rounded crow-transition-colors",
|
|
2014
|
+
"aria-label": "Close chat",
|
|
2015
|
+
title: "Close chat",
|
|
2016
|
+
children: /* @__PURE__ */ jsx(X, { size: 18, className: "crow-text-gray-700" })
|
|
1963
2017
|
}
|
|
1964
2018
|
)
|
|
1965
2019
|
] })
|
|
@@ -3322,7 +3376,8 @@ function CrowWidget({
|
|
|
3322
3376
|
persistAnonymousConversations,
|
|
3323
3377
|
welcomeMessage: welcomeMessageFromAPI,
|
|
3324
3378
|
selectedModel: selectedModelFromAPI,
|
|
3325
|
-
initialSuggestions
|
|
3379
|
+
initialSuggestions,
|
|
3380
|
+
toolConsentSettings
|
|
3326
3381
|
} = useWidgetStyles({
|
|
3327
3382
|
productId,
|
|
3328
3383
|
apiUrl,
|
|
@@ -3365,6 +3420,7 @@ function CrowWidget({
|
|
|
3365
3420
|
persistAnonymousConversations,
|
|
3366
3421
|
welcomeMessage,
|
|
3367
3422
|
selectedModel,
|
|
3423
|
+
toolConsentSettings,
|
|
3368
3424
|
onVerificationStatus: (isVerified) => {
|
|
3369
3425
|
setIsVerifiedUser(isVerified);
|
|
3370
3426
|
},
|
|
@@ -3667,14 +3723,47 @@ function CrowWidget({
|
|
|
3667
3723
|
const handleToolConsent = async (toolCallId, approved) => {
|
|
3668
3724
|
const toolCall = chat.activeToolCalls.find((tc) => tc.id === toolCallId) || chat.messages.flatMap((m) => m.toolCalls || []).find((tc) => tc.id === toolCallId);
|
|
3669
3725
|
if (!toolCall) return;
|
|
3726
|
+
const isClientSide = !toolCall.serverSideExecution;
|
|
3670
3727
|
if (approved) {
|
|
3671
3728
|
chat.updateToolCallStatus(toolCallId, "executing");
|
|
3672
|
-
if (
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3729
|
+
if (isClientSide) {
|
|
3730
|
+
try {
|
|
3731
|
+
const result = await executeClientToolRef.current?.(
|
|
3732
|
+
toolCall.name,
|
|
3733
|
+
toolCall.arguments || {}
|
|
3734
|
+
);
|
|
3735
|
+
const resultObj = result;
|
|
3736
|
+
const dataObj = resultObj?.data;
|
|
3737
|
+
const wasUserCancelled = dataObj?.declined === true || typeof resultObj?.error === "string" && resultObj.error.includes("cancelled by user") || typeof resultObj?.error === "string" && resultObj.error.includes("declined");
|
|
3738
|
+
if (wasUserCancelled) {
|
|
3739
|
+
console.log("[Crow Widget] Tool was cancelled by user after consent");
|
|
3740
|
+
return;
|
|
3741
|
+
}
|
|
3742
|
+
if (result && submitToolResultRef.current) {
|
|
3743
|
+
await submitToolResultRef.current(
|
|
3744
|
+
toolCallId,
|
|
3745
|
+
toolCall.name,
|
|
3746
|
+
result
|
|
3747
|
+
);
|
|
3748
|
+
}
|
|
3749
|
+
} catch (e) {
|
|
3750
|
+
console.error("[Crow Widget] Tool error after consent:", e);
|
|
3751
|
+
if (submitToolResultRef.current) {
|
|
3752
|
+
await submitToolResultRef.current(
|
|
3753
|
+
toolCallId,
|
|
3754
|
+
toolCall.name,
|
|
3755
|
+
{ success: false, error: String(e) }
|
|
3756
|
+
);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
} else {
|
|
3760
|
+
if (submitToolResultRef.current) {
|
|
3761
|
+
await submitToolResultRef.current(
|
|
3762
|
+
toolCallId,
|
|
3763
|
+
toolCall.name,
|
|
3764
|
+
{ consent_approved: true, tool_arguments: toolCall.arguments || {} }
|
|
3765
|
+
);
|
|
3766
|
+
}
|
|
3678
3767
|
}
|
|
3679
3768
|
} else {
|
|
3680
3769
|
chat.updateToolCallStatus(toolCallId, "denied");
|
|
@@ -3722,7 +3811,9 @@ function CrowWidget({
|
|
|
3722
3811
|
isVerifiedUser,
|
|
3723
3812
|
showConversationList,
|
|
3724
3813
|
onNewChat: handleNewChat,
|
|
3725
|
-
onToggleHistory: handleToggleHistory
|
|
3814
|
+
onToggleHistory: handleToggleHistory,
|
|
3815
|
+
showMinimize: variant === "floating",
|
|
3816
|
+
onToggleMinimize: () => setIsCollapsed(true)
|
|
3726
3817
|
}
|
|
3727
3818
|
),
|
|
3728
3819
|
/* @__PURE__ */ jsx(AnimatePresence, { children: showConversationList && isVerifiedUser && /* @__PURE__ */ jsx(
|
|
@@ -4103,7 +4194,8 @@ function CrowCopilot({
|
|
|
4103
4194
|
pageNavigationRoutes,
|
|
4104
4195
|
persistAnonymousConversations,
|
|
4105
4196
|
welcomeMessage: welcomeMessageFromAPI,
|
|
4106
|
-
selectedModel
|
|
4197
|
+
selectedModel,
|
|
4198
|
+
toolConsentSettings
|
|
4107
4199
|
} = useCopilotStyles({
|
|
4108
4200
|
productId,
|
|
4109
4201
|
apiUrl,
|
|
@@ -4294,6 +4386,7 @@ function CrowCopilot({
|
|
|
4294
4386
|
persistAnonymousConversations,
|
|
4295
4387
|
welcomeMessage,
|
|
4296
4388
|
selectedModel,
|
|
4389
|
+
toolConsentSettings,
|
|
4297
4390
|
onVerificationStatus: (isVerified) => {
|
|
4298
4391
|
setIsVerifiedUser(isVerified);
|
|
4299
4392
|
},
|
|
@@ -4492,14 +4585,54 @@ function CrowCopilot({
|
|
|
4492
4585
|
const handleToolConsent = async (toolCallId, approved) => {
|
|
4493
4586
|
const toolCall = chat.activeToolCalls.find((tc) => tc.id === toolCallId) || chat.messages.flatMap((m) => m.toolCalls || []).find((tc) => tc.id === toolCallId);
|
|
4494
4587
|
if (!toolCall) return;
|
|
4588
|
+
const isClientSide = !toolCall.serverSideExecution;
|
|
4495
4589
|
if (approved) {
|
|
4496
4590
|
chat.updateToolCallStatus(toolCallId, "executing");
|
|
4497
|
-
if (
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4591
|
+
if (isClientSide) {
|
|
4592
|
+
try {
|
|
4593
|
+
const result = await executeClientToolRef.current?.(
|
|
4594
|
+
toolCall.name,
|
|
4595
|
+
toolCall.arguments || {}
|
|
4596
|
+
);
|
|
4597
|
+
const resultObj = result;
|
|
4598
|
+
const dataObj = resultObj?.data;
|
|
4599
|
+
const wasUserCancelled = dataObj?.declined === true || typeof resultObj?.error === "string" && resultObj.error.includes("cancelled by user") || typeof resultObj?.error === "string" && resultObj.error.includes("declined");
|
|
4600
|
+
if (wasUserCancelled) {
|
|
4601
|
+
console.log("[Crow Copilot] Tool was cancelled by user after consent");
|
|
4602
|
+
if (submitToolResultRef.current) {
|
|
4603
|
+
await submitToolResultRef.current(
|
|
4604
|
+
toolCallId,
|
|
4605
|
+
toolCall.name,
|
|
4606
|
+
{ success: false, cancelled: true, error: "Action was cancelled by the user." }
|
|
4607
|
+
);
|
|
4608
|
+
}
|
|
4609
|
+
return;
|
|
4610
|
+
}
|
|
4611
|
+
if (result && submitToolResultRef.current) {
|
|
4612
|
+
await submitToolResultRef.current(
|
|
4613
|
+
toolCallId,
|
|
4614
|
+
toolCall.name,
|
|
4615
|
+
result
|
|
4616
|
+
);
|
|
4617
|
+
}
|
|
4618
|
+
} catch (e) {
|
|
4619
|
+
console.error("[Crow Copilot] Tool error after consent:", e);
|
|
4620
|
+
if (submitToolResultRef.current) {
|
|
4621
|
+
await submitToolResultRef.current(
|
|
4622
|
+
toolCallId,
|
|
4623
|
+
toolCall.name,
|
|
4624
|
+
{ success: false, error: String(e) }
|
|
4625
|
+
);
|
|
4626
|
+
}
|
|
4627
|
+
}
|
|
4628
|
+
} else {
|
|
4629
|
+
if (submitToolResultRef.current) {
|
|
4630
|
+
await submitToolResultRef.current(
|
|
4631
|
+
toolCallId,
|
|
4632
|
+
toolCall.name,
|
|
4633
|
+
{ consent_approved: true, tool_arguments: toolCall.arguments || {} }
|
|
4634
|
+
);
|
|
4635
|
+
}
|
|
4503
4636
|
}
|
|
4504
4637
|
} else {
|
|
4505
4638
|
chat.updateToolCallStatus(toolCallId, "denied");
|