@usecrow/ui 0.1.43 → 0.1.44

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
@@ -198,65 +198,6 @@ interface WidgetConfigResponse {
198
198
  }>;
199
199
  }
200
200
 
201
- /** Identity data passed to the identify function */
202
- interface IdentifyData {
203
- /** JWT token from your backend */
204
- token: string;
205
- /** User's display name */
206
- name?: string;
207
- /** Additional metadata */
208
- [key: string]: unknown;
209
- }
210
- /** Function to identify a user */
211
- type IdentifyFunction = (data: IdentifyData) => void;
212
- /** Client-side tool handler */
213
- type ToolHandler = (args: Record<string, unknown>) => Promise<unknown> | unknown;
214
- /** Map of tool names to handlers */
215
- type ToolsMap = Record<string, ToolHandler>;
216
- interface CrowWidgetProps {
217
- /** Product ID for this widget */
218
- productId: string;
219
- /** API URL (defaults to relative path) */
220
- apiUrl?: string;
221
- /** Widget variant: floating (with bubble) or embedded (for preview) */
222
- variant?: "floating" | "embedded";
223
- /** Custom styles to override DB and default styles */
224
- styles?: Partial<WidgetStyleConfig>;
225
- /** Skip fetching styles from API (use for preview mode with local state) */
226
- previewMode?: boolean;
227
- /** Whether to show AI thinking/reasoning to users (overrides API setting if provided) */
228
- showThinking?: boolean;
229
- /** Custom agent name shown in header (overrides API setting if provided) */
230
- agentName?: string;
231
- /** Custom welcome message (overrides API setting if provided) */
232
- welcomeMessage?: string;
233
- /** Callback when widget is ready */
234
- onReady?: () => void;
235
- /**
236
- * Callback to identify the user. Called with an identify function
237
- * that you should call with the user's token when available.
238
- */
239
- onIdentify?: (identify: IdentifyFunction) => void;
240
- /** Client-side tools the agent can call */
241
- tools?: ToolsMap;
242
- /** Custom navigation function for SPA-safe page navigation (e.g. router.push from Next.js or React Router) */
243
- navigate?: (path: string) => void;
244
- /** Callback fired when a server-side tool completes, with the tool name and full result data */
245
- onToolResult?: (toolName: string, result: Record<string, unknown>) => void;
246
- /**
247
- * Async function that returns a JWT for user identity verification.
248
- * Called on mount and automatically on 401 (token refresh).
249
- * Preferred over onIdentify for simpler integration.
250
- */
251
- getIdentityToken?: () => Promise<string>;
252
- /**
253
- * Page context data sent with every message. Reactive — updates whenever
254
- * the object reference changes. Replaces window.crow('setContext', ...).
255
- */
256
- context?: Record<string, unknown>;
257
- }
258
- declare function CrowWidget({ productId, apiUrl, variant, styles: propStyles, previewMode, showThinking: showThinkingProp, agentName: agentNameProp, welcomeMessage: welcomeMessageProp, onReady, onIdentify, tools, navigate, onToolResult, getIdentityToken, context, }: CrowWidgetProps): react_jsx_runtime.JSX.Element;
259
-
260
201
  /**
261
202
  * Shared TypeScript interfaces for the widget and copilot
262
203
  */
@@ -300,14 +241,18 @@ interface ToolCall {
300
241
  timestamp: Date;
301
242
  }
302
243
  /**
303
- * Map of tool name → custom React renderer.
304
- * When a tool completes and a renderer exists for its name,
305
- * the widget renders that component inline instead of the default status.
244
+ * Map of tool name → custom renderer for inline tool results.
245
+ *
246
+ * Return types:
247
+ * - ReactNode (React SDK) — rendered directly
248
+ * - string (script tag) — sanitized HTML rendered via innerHTML
249
+ * - HTMLElement (script tag) — mounted into a container (for Chart.js, D3, etc.)
306
250
  */
251
+ type ToolRendererResult = ReactNode | string | HTMLElement;
307
252
  type ToolRenderers = Record<string, (props: {
308
253
  result: unknown;
309
254
  status: string;
310
- }) => ReactNode>;
255
+ }) => ToolRendererResult>;
311
256
  interface WorkflowTodo {
312
257
  id: string;
313
258
  text: string;
@@ -359,9 +304,76 @@ declare global {
359
304
  __crow_journey_callback?: (event: JourneyEvent) => void;
360
305
  __crow_client_tools?: Record<string, ClientToolHandler>;
361
306
  __crow_page_context?: Record<string, unknown>;
307
+ __crow_identity_token_fetcher?: () => Promise<string>;
308
+ __crow_on_tool_result?: (toolName: string, result: Record<string, unknown>) => void;
309
+ __crow_tool_renderers?: ToolRenderers;
362
310
  }
363
311
  }
364
312
 
313
+ /** Identity data passed to the identify function */
314
+ interface IdentifyData {
315
+ /** JWT token from your backend */
316
+ token: string;
317
+ /** User's display name */
318
+ name?: string;
319
+ /** Additional metadata */
320
+ [key: string]: unknown;
321
+ }
322
+ /** Function to identify a user */
323
+ type IdentifyFunction = (data: IdentifyData) => void;
324
+ /** Client-side tool handler */
325
+ type ToolHandler = (args: Record<string, unknown>) => Promise<unknown> | unknown;
326
+ /** Map of tool names to handlers */
327
+ type ToolsMap = Record<string, ToolHandler>;
328
+ interface CrowWidgetProps {
329
+ /** Product ID for this widget */
330
+ productId: string;
331
+ /** API URL (defaults to relative path) */
332
+ apiUrl?: string;
333
+ /** Widget variant: floating (with bubble) or embedded (for preview) */
334
+ variant?: "floating" | "embedded";
335
+ /** Custom styles to override DB and default styles */
336
+ styles?: Partial<WidgetStyleConfig>;
337
+ /** Skip fetching styles from API (use for preview mode with local state) */
338
+ previewMode?: boolean;
339
+ /** Whether to show AI thinking/reasoning to users (overrides API setting if provided) */
340
+ showThinking?: boolean;
341
+ /** Custom agent name shown in header (overrides API setting if provided) */
342
+ agentName?: string;
343
+ /** Custom welcome message (overrides API setting if provided) */
344
+ welcomeMessage?: string;
345
+ /** Callback when widget is ready */
346
+ onReady?: () => void;
347
+ /**
348
+ * Callback to identify the user. Called with an identify function
349
+ * that you should call with the user's token when available.
350
+ */
351
+ onIdentify?: (identify: IdentifyFunction) => void;
352
+ /** Client-side tools the agent can call */
353
+ tools?: ToolsMap;
354
+ /** Custom navigation function for SPA-safe page navigation (e.g. router.push from Next.js or React Router) */
355
+ navigate?: (path: string) => void;
356
+ /** Callback fired when a server-side tool completes, with the tool name and full result data */
357
+ onToolResult?: (toolName: string, result: Record<string, unknown>) => void;
358
+ /**
359
+ * Async function that returns a JWT for user identity verification.
360
+ * Called on mount and automatically on 401 (token refresh).
361
+ * Preferred over onIdentify for simpler integration.
362
+ */
363
+ getIdentityToken?: () => Promise<string>;
364
+ /**
365
+ * Page context data sent with every message. Reactive — updates whenever
366
+ * the object reference changes. Replaces window.crow('setContext', ...).
367
+ */
368
+ context?: Record<string, unknown>;
369
+ /**
370
+ * Custom renderers for tool results. When a tool completes and a renderer
371
+ * exists for its name, that component is rendered inline in the chat.
372
+ */
373
+ toolRenderers?: ToolRenderers;
374
+ }
375
+ declare function CrowWidget({ productId, apiUrl, variant, styles: propStyles, previewMode, showThinking: showThinkingProp, agentName: agentNameProp, welcomeMessage: welcomeMessageProp, onReady, onIdentify, tools, navigate, onToolResult, getIdentityToken, context, toolRenderers, }: CrowWidgetProps): react_jsx_runtime.JSX.Element;
376
+
365
377
  interface CrowCopilotProps {
366
378
  /** Product ID for this copilot */
367
379
  productId: string;
package/dist/index.d.ts CHANGED
@@ -198,65 +198,6 @@ interface WidgetConfigResponse {
198
198
  }>;
199
199
  }
200
200
 
201
- /** Identity data passed to the identify function */
202
- interface IdentifyData {
203
- /** JWT token from your backend */
204
- token: string;
205
- /** User's display name */
206
- name?: string;
207
- /** Additional metadata */
208
- [key: string]: unknown;
209
- }
210
- /** Function to identify a user */
211
- type IdentifyFunction = (data: IdentifyData) => void;
212
- /** Client-side tool handler */
213
- type ToolHandler = (args: Record<string, unknown>) => Promise<unknown> | unknown;
214
- /** Map of tool names to handlers */
215
- type ToolsMap = Record<string, ToolHandler>;
216
- interface CrowWidgetProps {
217
- /** Product ID for this widget */
218
- productId: string;
219
- /** API URL (defaults to relative path) */
220
- apiUrl?: string;
221
- /** Widget variant: floating (with bubble) or embedded (for preview) */
222
- variant?: "floating" | "embedded";
223
- /** Custom styles to override DB and default styles */
224
- styles?: Partial<WidgetStyleConfig>;
225
- /** Skip fetching styles from API (use for preview mode with local state) */
226
- previewMode?: boolean;
227
- /** Whether to show AI thinking/reasoning to users (overrides API setting if provided) */
228
- showThinking?: boolean;
229
- /** Custom agent name shown in header (overrides API setting if provided) */
230
- agentName?: string;
231
- /** Custom welcome message (overrides API setting if provided) */
232
- welcomeMessage?: string;
233
- /** Callback when widget is ready */
234
- onReady?: () => void;
235
- /**
236
- * Callback to identify the user. Called with an identify function
237
- * that you should call with the user's token when available.
238
- */
239
- onIdentify?: (identify: IdentifyFunction) => void;
240
- /** Client-side tools the agent can call */
241
- tools?: ToolsMap;
242
- /** Custom navigation function for SPA-safe page navigation (e.g. router.push from Next.js or React Router) */
243
- navigate?: (path: string) => void;
244
- /** Callback fired when a server-side tool completes, with the tool name and full result data */
245
- onToolResult?: (toolName: string, result: Record<string, unknown>) => void;
246
- /**
247
- * Async function that returns a JWT for user identity verification.
248
- * Called on mount and automatically on 401 (token refresh).
249
- * Preferred over onIdentify for simpler integration.
250
- */
251
- getIdentityToken?: () => Promise<string>;
252
- /**
253
- * Page context data sent with every message. Reactive — updates whenever
254
- * the object reference changes. Replaces window.crow('setContext', ...).
255
- */
256
- context?: Record<string, unknown>;
257
- }
258
- declare function CrowWidget({ productId, apiUrl, variant, styles: propStyles, previewMode, showThinking: showThinkingProp, agentName: agentNameProp, welcomeMessage: welcomeMessageProp, onReady, onIdentify, tools, navigate, onToolResult, getIdentityToken, context, }: CrowWidgetProps): react_jsx_runtime.JSX.Element;
259
-
260
201
  /**
261
202
  * Shared TypeScript interfaces for the widget and copilot
262
203
  */
@@ -300,14 +241,18 @@ interface ToolCall {
300
241
  timestamp: Date;
301
242
  }
302
243
  /**
303
- * Map of tool name → custom React renderer.
304
- * When a tool completes and a renderer exists for its name,
305
- * the widget renders that component inline instead of the default status.
244
+ * Map of tool name → custom renderer for inline tool results.
245
+ *
246
+ * Return types:
247
+ * - ReactNode (React SDK) — rendered directly
248
+ * - string (script tag) — sanitized HTML rendered via innerHTML
249
+ * - HTMLElement (script tag) — mounted into a container (for Chart.js, D3, etc.)
306
250
  */
251
+ type ToolRendererResult = ReactNode | string | HTMLElement;
307
252
  type ToolRenderers = Record<string, (props: {
308
253
  result: unknown;
309
254
  status: string;
310
- }) => ReactNode>;
255
+ }) => ToolRendererResult>;
311
256
  interface WorkflowTodo {
312
257
  id: string;
313
258
  text: string;
@@ -359,9 +304,76 @@ declare global {
359
304
  __crow_journey_callback?: (event: JourneyEvent) => void;
360
305
  __crow_client_tools?: Record<string, ClientToolHandler>;
361
306
  __crow_page_context?: Record<string, unknown>;
307
+ __crow_identity_token_fetcher?: () => Promise<string>;
308
+ __crow_on_tool_result?: (toolName: string, result: Record<string, unknown>) => void;
309
+ __crow_tool_renderers?: ToolRenderers;
362
310
  }
363
311
  }
364
312
 
313
+ /** Identity data passed to the identify function */
314
+ interface IdentifyData {
315
+ /** JWT token from your backend */
316
+ token: string;
317
+ /** User's display name */
318
+ name?: string;
319
+ /** Additional metadata */
320
+ [key: string]: unknown;
321
+ }
322
+ /** Function to identify a user */
323
+ type IdentifyFunction = (data: IdentifyData) => void;
324
+ /** Client-side tool handler */
325
+ type ToolHandler = (args: Record<string, unknown>) => Promise<unknown> | unknown;
326
+ /** Map of tool names to handlers */
327
+ type ToolsMap = Record<string, ToolHandler>;
328
+ interface CrowWidgetProps {
329
+ /** Product ID for this widget */
330
+ productId: string;
331
+ /** API URL (defaults to relative path) */
332
+ apiUrl?: string;
333
+ /** Widget variant: floating (with bubble) or embedded (for preview) */
334
+ variant?: "floating" | "embedded";
335
+ /** Custom styles to override DB and default styles */
336
+ styles?: Partial<WidgetStyleConfig>;
337
+ /** Skip fetching styles from API (use for preview mode with local state) */
338
+ previewMode?: boolean;
339
+ /** Whether to show AI thinking/reasoning to users (overrides API setting if provided) */
340
+ showThinking?: boolean;
341
+ /** Custom agent name shown in header (overrides API setting if provided) */
342
+ agentName?: string;
343
+ /** Custom welcome message (overrides API setting if provided) */
344
+ welcomeMessage?: string;
345
+ /** Callback when widget is ready */
346
+ onReady?: () => void;
347
+ /**
348
+ * Callback to identify the user. Called with an identify function
349
+ * that you should call with the user's token when available.
350
+ */
351
+ onIdentify?: (identify: IdentifyFunction) => void;
352
+ /** Client-side tools the agent can call */
353
+ tools?: ToolsMap;
354
+ /** Custom navigation function for SPA-safe page navigation (e.g. router.push from Next.js or React Router) */
355
+ navigate?: (path: string) => void;
356
+ /** Callback fired when a server-side tool completes, with the tool name and full result data */
357
+ onToolResult?: (toolName: string, result: Record<string, unknown>) => void;
358
+ /**
359
+ * Async function that returns a JWT for user identity verification.
360
+ * Called on mount and automatically on 401 (token refresh).
361
+ * Preferred over onIdentify for simpler integration.
362
+ */
363
+ getIdentityToken?: () => Promise<string>;
364
+ /**
365
+ * Page context data sent with every message. Reactive — updates whenever
366
+ * the object reference changes. Replaces window.crow('setContext', ...).
367
+ */
368
+ context?: Record<string, unknown>;
369
+ /**
370
+ * Custom renderers for tool results. When a tool completes and a renderer
371
+ * exists for its name, that component is rendered inline in the chat.
372
+ */
373
+ toolRenderers?: ToolRenderers;
374
+ }
375
+ declare function CrowWidget({ productId, apiUrl, variant, styles: propStyles, previewMode, showThinking: showThinkingProp, agentName: agentNameProp, welcomeMessage: welcomeMessageProp, onReady, onIdentify, tools, navigate, onToolResult, getIdentityToken, context, toolRenderers, }: CrowWidgetProps): react_jsx_runtime.JSX.Element;
376
+
365
377
  interface CrowCopilotProps {
366
378
  /** Product ID for this copilot */
367
379
  productId: string;
package/dist/index.js CHANGED
@@ -879,11 +879,44 @@ function useCrowAPI({ onIdentified, onReset } = {}) {
879
879
  window.__crow_page_context = void 0;
880
880
  console.log("[Crow] Context cleared");
881
881
  break;
882
+ case "setIdentityTokenFetcher":
883
+ if (typeof opts !== "function") {
884
+ console.error("[Crow] setIdentityTokenFetcher() requires a function");
885
+ return;
886
+ }
887
+ window.__crow_identity_token_fetcher = opts;
888
+ console.log("[Crow] Identity token fetcher registered");
889
+ break;
890
+ case "onToolResult":
891
+ if (typeof opts !== "function") {
892
+ console.error("[Crow] onToolResult() requires a function");
893
+ return;
894
+ }
895
+ window.__crow_on_tool_result = opts;
896
+ console.log("[Crow] onToolResult callback registered");
897
+ break;
898
+ case "registerToolRenderers":
899
+ if (!opts || typeof opts !== "object") {
900
+ console.error("[Crow] registerToolRenderers() requires an object");
901
+ return;
902
+ }
903
+ window.__crow_tool_renderers = {
904
+ ...window.__crow_tool_renderers || {},
905
+ ...opts
906
+ };
907
+ console.log("[Crow] Tool renderers registered");
908
+ break;
882
909
  default:
883
910
  console.warn(`[Crow] Unknown command: ${command}`);
884
911
  }
885
912
  };
886
913
  console.log("[Crow] API ready");
914
+ const queue = window.__crow_queue;
915
+ if (queue?.length) {
916
+ console.log(`[Crow] Replaying ${queue.length} queued command(s)`);
917
+ queue.forEach(([cmd, opts]) => window.crow(cmd, opts));
918
+ window.__crow_queue = void 0;
919
+ }
887
920
  const handleIdentified = () => onIdentifiedRef.current?.();
888
921
  const handleReset = () => onResetRef.current?.();
889
922
  window.addEventListener("crow:identified", handleIdentified);
@@ -1915,6 +1948,23 @@ function ThinkingBlock({
1915
1948
  ) })
1916
1949
  ] });
1917
1950
  }
1951
+ function RenderedToolResult({ renderer, result, status }) {
1952
+ const domRef = useRef(null);
1953
+ const rendered = renderer({ result, status });
1954
+ useEffect(() => {
1955
+ if (domRef.current && rendered instanceof HTMLElement) {
1956
+ domRef.current.innerHTML = "";
1957
+ domRef.current.appendChild(rendered);
1958
+ }
1959
+ }, [rendered]);
1960
+ if (rendered instanceof HTMLElement) {
1961
+ return /* @__PURE__ */ jsx("div", { className: "crow-mt-1.5 crow-mb-0.5", ref: domRef });
1962
+ }
1963
+ if (typeof rendered === "string") {
1964
+ return /* @__PURE__ */ jsx("div", { className: "crow-mt-1.5 crow-mb-0.5", dangerouslySetInnerHTML: { __html: rendered } });
1965
+ }
1966
+ return /* @__PURE__ */ jsx("div", { className: "crow-mt-1.5 crow-mb-0.5", children: rendered });
1967
+ }
1918
1968
  function ToolCallBlock({
1919
1969
  toolCall,
1920
1970
  toolRenderers
@@ -1954,7 +2004,7 @@ function ToolCallBlock({
1954
2004
  ]
1955
2005
  }
1956
2006
  ),
1957
- hasCustomRender && /* @__PURE__ */ jsx("div", { className: "crow-mt-1.5 crow-mb-0.5", children: customRenderer({ result: toolCall.result, status: toolCall.status }) }),
2007
+ hasCustomRender && /* @__PURE__ */ jsx(RenderedToolResult, { renderer: customRenderer, result: toolCall.result, status: toolCall.status }),
1958
2008
  /* @__PURE__ */ jsx(AnimatePresence, { children: expanded && hasArgs && /* @__PURE__ */ jsx(
1959
2009
  motion.div,
1960
2010
  {
@@ -2913,8 +2963,12 @@ function CrowWidget({
2913
2963
  navigate,
2914
2964
  onToolResult,
2915
2965
  getIdentityToken,
2916
- context
2966
+ context,
2967
+ toolRenderers
2917
2968
  }) {
2969
+ const effectiveGetIdentityToken = getIdentityToken || window.__crow_identity_token_fetcher;
2970
+ const effectiveOnToolResult = onToolResult || window.__crow_on_tool_result;
2971
+ const effectiveToolRenderers = toolRenderers || window.__crow_tool_renderers;
2918
2972
  const {
2919
2973
  styles,
2920
2974
  isLoading: isLoadingStyles,
@@ -2993,7 +3047,7 @@ function CrowWidget({
2993
3047
  break;
2994
3048
  }
2995
3049
  },
2996
- onToolResult,
3050
+ onToolResult: effectiveOnToolResult,
2997
3051
  onToolCall: async (event) => {
2998
3052
  if (event.type === "client_call" && event.toolName && event.toolCallId) {
2999
3053
  try {
@@ -3092,11 +3146,11 @@ function CrowWidget({
3092
3146
  }
3093
3147
  }, [isLoadingStyles, onIdentify]);
3094
3148
  useEffect(() => {
3095
- if (!getIdentityToken || isLoadingStyles) return;
3149
+ if (!effectiveGetIdentityToken || isLoadingStyles) return;
3096
3150
  let cancelled = false;
3097
3151
  const identify = async () => {
3098
3152
  try {
3099
- const token = await getIdentityToken();
3153
+ const token = await effectiveGetIdentityToken();
3100
3154
  if (!cancelled && token) {
3101
3155
  window.crow?.("identify", { token });
3102
3156
  }
@@ -3111,7 +3165,7 @@ function CrowWidget({
3111
3165
  cancelled = true;
3112
3166
  window.removeEventListener("crow:token-refresh-needed", handleRefresh);
3113
3167
  };
3114
- }, [getIdentityToken, isLoadingStyles]);
3168
+ }, [effectiveGetIdentityToken, isLoadingStyles]);
3115
3169
  useEffect(() => {
3116
3170
  if (typeof window === "undefined") return;
3117
3171
  if (context && Object.keys(context).length > 0) {
@@ -3298,7 +3352,8 @@ function CrowWidget({
3298
3352
  messages: chat.messages,
3299
3353
  activeToolCalls: chat.activeToolCalls,
3300
3354
  isLoadingHistory: conversations.isLoadingHistory,
3301
- isGenerating: chat.isLoading
3355
+ isGenerating: chat.isLoading,
3356
+ toolRenderers: effectiveToolRenderers
3302
3357
  }
3303
3358
  ),
3304
3359
  pendingConfirmation && /* @__PURE__ */ jsx("div", { className: "crow-px-4 crow-py-2", children: /* @__PURE__ */ jsx(
@@ -3498,6 +3553,9 @@ function CrowCopilot({
3498
3553
  getIdentityToken,
3499
3554
  context
3500
3555
  }) {
3556
+ const effectiveGetIdentityToken = getIdentityToken || window.__crow_identity_token_fetcher;
3557
+ const effectiveOnToolResult = onToolResult || window.__crow_on_tool_result;
3558
+ const effectiveToolRenderers = toolRenderers || window.__crow_tool_renderers;
3501
3559
  const {
3502
3560
  styles,
3503
3561
  isLoading: isLoadingStyles,
@@ -3601,7 +3659,7 @@ function CrowCopilot({
3601
3659
  break;
3602
3660
  }
3603
3661
  },
3604
- onToolResult,
3662
+ onToolResult: effectiveOnToolResult,
3605
3663
  onToolCall: async (event) => {
3606
3664
  if (event.type === "client_call" && event.toolName && event.toolCallId) {
3607
3665
  try {
@@ -3747,11 +3805,11 @@ function CrowCopilot({
3747
3805
  }
3748
3806
  }, [isLoadingStyles, onReady]);
3749
3807
  useEffect(() => {
3750
- if (!getIdentityToken || isLoadingStyles) return;
3808
+ if (!effectiveGetIdentityToken || isLoadingStyles) return;
3751
3809
  let cancelled = false;
3752
3810
  const identify = async () => {
3753
3811
  try {
3754
- const token = await getIdentityToken();
3812
+ const token = await effectiveGetIdentityToken();
3755
3813
  if (!cancelled && token) {
3756
3814
  window.crow?.("identify", { token });
3757
3815
  }
@@ -3766,7 +3824,7 @@ function CrowCopilot({
3766
3824
  cancelled = true;
3767
3825
  window.removeEventListener("crow:token-refresh-needed", handleRefresh);
3768
3826
  };
3769
- }, [getIdentityToken, isLoadingStyles]);
3827
+ }, [effectiveGetIdentityToken, isLoadingStyles]);
3770
3828
  useEffect(() => {
3771
3829
  if (typeof window === "undefined") return;
3772
3830
  if (context && Object.keys(context).length > 0) {
@@ -4129,7 +4187,7 @@ function CrowCopilot({
4129
4187
  activeToolCalls: chat.activeToolCalls,
4130
4188
  isLoadingHistory: conversations.isLoadingHistory,
4131
4189
  isGenerating: chat.isLoading,
4132
- toolRenderers
4190
+ toolRenderers: effectiveToolRenderers
4133
4191
  }
4134
4192
  ),
4135
4193
  pendingConfirmation && /* @__PURE__ */ jsx("div", { className: "crow-px-4 crow-py-2", children: /* @__PURE__ */ jsx(