@usecrow/ui 0.1.75 → 0.1.77

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 CHANGED
@@ -75,6 +75,8 @@ function useChat({
75
75
  subdomain,
76
76
  toolConsentSettings,
77
77
  language,
78
+ agentMode,
79
+ onOnboardingComplete,
78
80
  onVerificationStatus,
79
81
  onConversationId,
80
82
  onWorkflowEvent,
@@ -167,7 +169,8 @@ function useChat({
167
169
  user_local_time: (/* @__PURE__ */ new Date()).toLocaleString("en-US", { year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "numeric", hour12: true }),
168
170
  page_path: typeof window !== "undefined" ? window.location.pathname : void 0,
169
171
  context: typeof window !== "undefined" ? window.__crow_page_context : void 0,
170
- ...language && language !== "en" ? { language } : {}
172
+ ...language && language !== "en" ? { language } : {},
173
+ ...agentMode ? { agent_mode: agentMode } : {}
171
174
  }),
172
175
  signal: abortControllerRef.current.signal
173
176
  });
@@ -495,6 +498,9 @@ function useChat({
495
498
  setSuggestedActions(parsed.actions);
496
499
  }
497
500
  break;
501
+ case "onboarding_complete":
502
+ onOnboardingComplete?.(parsed.summary || "");
503
+ break;
498
504
  }
499
505
  } catch (e) {
500
506
  console.error("[Crow] Parse error:", e);
@@ -527,7 +533,7 @@ function useChat({
527
533
  abortControllerRef.current = null;
528
534
  }
529
535
  },
530
- [apiUrl, productId, conversationId, selectedModel, subdomain, persistAnonymousConversations, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall, onToolResult]
536
+ [apiUrl, productId, conversationId, selectedModel, subdomain, persistAnonymousConversations, agentMode, onOnboardingComplete, onVerificationStatus, onConversationId, onWorkflowEvent, onToolCall, onToolResult]
531
537
  );
532
538
  const sendMessage = React3.useCallback(
533
539
  (content) => {
@@ -1697,6 +1703,18 @@ function useWidgetStyles({
1697
1703
  const [availableModels, setAvailableModels] = React3.useState(
1698
1704
  styleCache.get(key)?.availableModels || []
1699
1705
  );
1706
+ const [onboardingEnabled, setOnboardingEnabled] = React3.useState(
1707
+ styleCache.get(key)?.onboardingEnabled || false
1708
+ );
1709
+ const [onboardingAgentName, setOnboardingAgentName] = React3.useState(
1710
+ styleCache.get(key)?.onboardingAgentName ?? void 0
1711
+ );
1712
+ const [onboardingWelcomeMessage, setOnboardingWelcomeMessage] = React3.useState(
1713
+ styleCache.get(key)?.onboardingWelcomeMessage ?? void 0
1714
+ );
1715
+ const [onboardingIntroSequence, setOnboardingIntroSequence] = React3.useState(
1716
+ styleCache.get(key)?.onboardingIntroSequence ?? void 0
1717
+ );
1700
1718
  const hasFetchedRef = React3.useRef(false);
1701
1719
  const fetchStyles = async () => {
1702
1720
  if (skip) return;
@@ -1718,6 +1736,10 @@ function useWidgetStyles({
1718
1736
  setToolConsentSettings(config.toolConsentSettings || {});
1719
1737
  setModelSelectionEnabled(config.modelSelectionEnabled || false);
1720
1738
  setAvailableModels(config.availableModels || []);
1739
+ setOnboardingEnabled(config.onboardingEnabled || false);
1740
+ setOnboardingAgentName(config.onboardingAgentName ?? void 0);
1741
+ setOnboardingWelcomeMessage(config.onboardingWelcomeMessage ?? void 0);
1742
+ setOnboardingIntroSequence(config.onboardingIntroSequence ?? void 0);
1721
1743
  } catch (err) {
1722
1744
  console.error("[CrowWidget] Failed to fetch styles:", err);
1723
1745
  setError(err instanceof Error ? err : new Error(String(err)));
@@ -1761,6 +1783,10 @@ function useWidgetStyles({
1761
1783
  toolConsentSettings,
1762
1784
  modelSelectionEnabled,
1763
1785
  availableModels,
1786
+ onboardingEnabled,
1787
+ onboardingAgentName,
1788
+ onboardingWelcomeMessage,
1789
+ onboardingIntroSequence,
1764
1790
  refetch: fetchStyles
1765
1791
  };
1766
1792
  }
@@ -1809,6 +1835,18 @@ function useCopilotStyles({
1809
1835
  const [initialSuggestions, setInitialSuggestions] = React3.useState(
1810
1836
  styleCache.get(key)?.initialSuggestions || []
1811
1837
  );
1838
+ const [onboardingEnabled, setOnboardingEnabled] = React3.useState(
1839
+ styleCache.get(key)?.onboardingEnabled || false
1840
+ );
1841
+ const [onboardingAgentName, setOnboardingAgentName] = React3.useState(
1842
+ styleCache.get(key)?.onboardingAgentName ?? void 0
1843
+ );
1844
+ const [onboardingWelcomeMessage, setOnboardingWelcomeMessage] = React3.useState(
1845
+ styleCache.get(key)?.onboardingWelcomeMessage ?? void 0
1846
+ );
1847
+ const [onboardingIntroSequence, setOnboardingIntroSequence] = React3.useState(
1848
+ styleCache.get(key)?.onboardingIntroSequence ?? void 0
1849
+ );
1812
1850
  const hasFetchedRef = React3.useRef(false);
1813
1851
  const fetchStyles = async () => {
1814
1852
  if (skip) return;
@@ -1829,6 +1867,10 @@ function useCopilotStyles({
1829
1867
  setModelSelectionEnabled(config.modelSelectionEnabled || false);
1830
1868
  setAvailableModels(config.availableModels || []);
1831
1869
  setInitialSuggestions(config.initialSuggestions || []);
1870
+ setOnboardingEnabled(config.onboardingEnabled || false);
1871
+ setOnboardingAgentName(config.onboardingAgentName ?? void 0);
1872
+ setOnboardingWelcomeMessage(config.onboardingWelcomeMessage ?? void 0);
1873
+ setOnboardingIntroSequence(config.onboardingIntroSequence ?? void 0);
1832
1874
  } catch (err) {
1833
1875
  console.error("[CrowCopilot] Failed to fetch styles:", err);
1834
1876
  setError(err instanceof Error ? err : new Error(String(err)));
@@ -1851,6 +1893,10 @@ function useCopilotStyles({
1851
1893
  setModelSelectionEnabled(cached.modelSelectionEnabled || false);
1852
1894
  setAvailableModels(cached.availableModels || []);
1853
1895
  setInitialSuggestions(cached.initialSuggestions || []);
1896
+ setOnboardingEnabled(cached.onboardingEnabled || false);
1897
+ setOnboardingAgentName(cached.onboardingAgentName ?? void 0);
1898
+ setOnboardingWelcomeMessage(cached.onboardingWelcomeMessage ?? void 0);
1899
+ setOnboardingIntroSequence(cached.onboardingIntroSequence ?? void 0);
1854
1900
  setIsLoading(false);
1855
1901
  return;
1856
1902
  }
@@ -1873,6 +1919,10 @@ function useCopilotStyles({
1873
1919
  modelSelectionEnabled,
1874
1920
  availableModels,
1875
1921
  initialSuggestions,
1922
+ onboardingEnabled,
1923
+ onboardingAgentName,
1924
+ onboardingWelcomeMessage,
1925
+ onboardingIntroSequence,
1876
1926
  refetch: fetchStyles
1877
1927
  };
1878
1928
  }
@@ -4531,6 +4581,84 @@ function injectStyles(target = document) {
4531
4581
  target.prepend(style);
4532
4582
  }
4533
4583
  }
4584
+ function OnboardingIntroInline({
4585
+ lines,
4586
+ primaryColor,
4587
+ onComplete
4588
+ }) {
4589
+ const [lineIndex, setLineIndex] = React3.useState(0);
4590
+ const [charIndex, setCharIndex] = React3.useState(0);
4591
+ const [done, setDone] = React3.useState(false);
4592
+ React3.useEffect(() => {
4593
+ if (lineIndex >= lines.length) {
4594
+ setDone(true);
4595
+ return;
4596
+ }
4597
+ const currentLine = lines[lineIndex];
4598
+ if (charIndex < currentLine.length) {
4599
+ const t = setTimeout(() => setCharIndex((c) => c + 1), 35);
4600
+ return () => clearTimeout(t);
4601
+ } else {
4602
+ const t = setTimeout(() => {
4603
+ setLineIndex((l) => l + 1);
4604
+ setCharIndex(0);
4605
+ }, 500);
4606
+ return () => clearTimeout(t);
4607
+ }
4608
+ }, [lineIndex, charIndex, lines]);
4609
+ const displayedLines = lines.slice(0, lineIndex + 1).map(
4610
+ (line, i) => i < lineIndex ? line : line.slice(0, charIndex)
4611
+ );
4612
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
4613
+ display: "flex",
4614
+ flexDirection: "column",
4615
+ alignItems: "center",
4616
+ justifyContent: "center",
4617
+ flex: 1,
4618
+ padding: "24px 16px",
4619
+ textAlign: "center"
4620
+ }, children: [
4621
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { minHeight: "4rem", marginBottom: "1.5rem" }, children: displayedLines.map((text, i) => /* @__PURE__ */ jsxRuntime.jsxs("p", { style: {
4622
+ fontSize: i === 0 ? 18 : 14,
4623
+ fontWeight: i === 0 ? 600 : 400,
4624
+ color: i === 0 ? "var(--crow-text, #111827)" : "var(--crow-text-secondary, #6b7280)",
4625
+ lineHeight: 1.4,
4626
+ margin: "0 0 6px 0"
4627
+ }, children: [
4628
+ text,
4629
+ i === lineIndex && !done && /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
4630
+ display: "inline-block",
4631
+ width: 2,
4632
+ height: i === 0 ? 18 : 14,
4633
+ backgroundColor: "var(--crow-text, #111827)",
4634
+ marginLeft: 2,
4635
+ verticalAlign: "middle",
4636
+ animation: "crow-blink 1s step-end infinite"
4637
+ } })
4638
+ ] }, i)) }),
4639
+ /* @__PURE__ */ jsxRuntime.jsx(
4640
+ "button",
4641
+ {
4642
+ onClick: onComplete,
4643
+ style: {
4644
+ padding: "8px 24px",
4645
+ borderRadius: 8,
4646
+ backgroundColor: primaryColor,
4647
+ color: "#fff",
4648
+ fontSize: 13,
4649
+ fontWeight: 500,
4650
+ border: "none",
4651
+ cursor: "pointer",
4652
+ opacity: done ? 1 : 0,
4653
+ pointerEvents: done ? "auto" : "none",
4654
+ transition: "opacity 0.5s ease"
4655
+ },
4656
+ children: "Get Started \u2192"
4657
+ }
4658
+ ),
4659
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `@keyframes crow-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }` })
4660
+ ] });
4661
+ }
4534
4662
  function CrowWidget({
4535
4663
  productId,
4536
4664
  apiUrl = "",
@@ -4551,7 +4679,9 @@ function CrowWidget({
4551
4679
  toolRenderers,
4552
4680
  language,
4553
4681
  customCss,
4554
- contextLabel: contextLabelProp
4682
+ contextLabel: contextLabelProp,
4683
+ forceOnboarding = false,
4684
+ fullscreenTopOffset: _fullscreenTopOffset = 0
4555
4685
  }) {
4556
4686
  const effectiveGetIdentityToken = getIdentityToken || window.__crow_identity_token_fetcher;
4557
4687
  const effectiveOnToolResult = onToolResult || window.__crow_on_tool_result;
@@ -4570,7 +4700,11 @@ function CrowWidget({
4570
4700
  initialSuggestions,
4571
4701
  toolConsentSettings,
4572
4702
  modelSelectionEnabled,
4573
- availableModels: availableModelsFromAPI
4703
+ availableModels: availableModelsFromAPI,
4704
+ onboardingEnabled,
4705
+ onboardingAgentName,
4706
+ onboardingWelcomeMessage,
4707
+ onboardingIntroSequence
4574
4708
  } = useWidgetStyles({
4575
4709
  productId,
4576
4710
  apiUrl,
@@ -4607,6 +4741,25 @@ function CrowWidget({
4607
4741
  const welcomeMessage = greetingOverride ?? welcomeMessageProp ?? welcomeMessageFromAPI;
4608
4742
  const selectedModel = selectedModelFromAPI;
4609
4743
  const showThinking = showThinkingProp ?? showThinkingFromAPI;
4744
+ const [isOnboarding, setIsOnboarding] = React3.useState(false);
4745
+ const [onboardingChecked, setOnboardingChecked] = React3.useState(false);
4746
+ const [onboardingPhase, setOnboardingPhase] = React3.useState("intro");
4747
+ React3.useEffect(() => {
4748
+ if (!isLoadingStyles && !onboardingChecked && (forceOnboarding || onboardingEnabled)) {
4749
+ setIsOnboarding(true);
4750
+ setOnboardingChecked(true);
4751
+ }
4752
+ }, [forceOnboarding, isLoadingStyles, onboardingEnabled, onboardingChecked]);
4753
+ React3.useEffect(() => {
4754
+ if (isOnboarding) {
4755
+ setIsCollapsed(false);
4756
+ }
4757
+ }, [isOnboarding]);
4758
+ React3.useEffect(() => {
4759
+ if (isOnboarding && !isLoadingStyles && onboardingIntroSequence !== void 0 && onboardingIntroSequence.length === 0) {
4760
+ setOnboardingPhase("chat");
4761
+ }
4762
+ }, [isOnboarding, isLoadingStyles, onboardingIntroSequence]);
4610
4763
  const [autoTools, setAutoTools] = React3.useState({});
4611
4764
  const cssVars = stylesToCssVars(styles);
4612
4765
  const transform = useWidgetTransform({
@@ -4656,11 +4809,17 @@ function CrowWidget({
4656
4809
  const conversations = useConversations({ productId, apiUrl });
4657
4810
  const [shouldRestoreHistory, setShouldRestoreHistory] = React3.useState(false);
4658
4811
  const hasRestoredHistoryRef = React3.useRef(false);
4812
+ const effectiveWelcomeMessage = isOnboarding ? onboardingWelcomeMessage || `Hi! I'm ${onboardingAgentName || agentName}. Let me help you get started.` : welcomeMessage;
4659
4813
  const chat = useChat({
4660
4814
  productId,
4661
4815
  apiUrl,
4662
4816
  persistAnonymousConversations,
4663
- welcomeMessage,
4817
+ welcomeMessage: effectiveWelcomeMessage,
4818
+ agentMode: isOnboarding ? "onboarding" : void 0,
4819
+ onOnboardingComplete: (summary) => {
4820
+ console.log("[Crow] Onboarding complete:", summary);
4821
+ setIsOnboarding(false);
4822
+ },
4664
4823
  selectedModel,
4665
4824
  subdomain,
4666
4825
  toolConsentSettings,
@@ -4748,10 +4907,10 @@ function CrowWidget({
4748
4907
  wasLoadingRef.current = chat.isLoading;
4749
4908
  }, [chat.isLoading, chat.messages]);
4750
4909
  React3.useEffect(() => {
4751
- if (initialSuggestions.length > 0 && chat.suggestedActions.length === 0) {
4910
+ if (!isOnboarding && initialSuggestions.length > 0 && chat.suggestedActions.length === 0) {
4752
4911
  chat.setSuggestedActions(initialSuggestions);
4753
4912
  }
4754
- }, [initialSuggestions]);
4913
+ }, [initialSuggestions, isOnboarding]);
4755
4914
  React3.useEffect(() => {
4756
4915
  if (shouldRestoreHistory && chat.conversationId && !hasRestoredHistoryRef.current) {
4757
4916
  hasRestoredHistoryRef.current = true;
@@ -4786,6 +4945,33 @@ function CrowWidget({
4786
4945
  const { executeClientTool } = useCrowAPI({
4787
4946
  onIdentified: async () => {
4788
4947
  setIsVerifiedUser(true);
4948
+ if (forceOnboarding) {
4949
+ setIsOnboarding(true);
4950
+ setOnboardingChecked(true);
4951
+ } else if (onboardingEnabled && !onboardingChecked) {
4952
+ try {
4953
+ const identityToken = window.__crow_identity_token;
4954
+ if (identityToken) {
4955
+ const res = await fetch(`${apiUrl}/api/chat/resolve-agent`, {
4956
+ method: "POST",
4957
+ headers: { "Content-Type": "application/json" },
4958
+ body: JSON.stringify({
4959
+ product_id: productId,
4960
+ identity_token: identityToken
4961
+ })
4962
+ });
4963
+ if (res.ok) {
4964
+ const data = await res.json();
4965
+ if (data.agent === "onboarding") {
4966
+ setIsOnboarding(true);
4967
+ }
4968
+ }
4969
+ }
4970
+ } catch (e) {
4971
+ console.error("[Crow] resolve-agent failed:", e);
4972
+ }
4973
+ setOnboardingChecked(true);
4974
+ }
4789
4975
  const convs = await conversations.loadConversations();
4790
4976
  if (convs.length > 0) {
4791
4977
  const mostRecent = convs[0];
@@ -4803,6 +4989,17 @@ function CrowWidget({
4803
4989
  });
4804
4990
  executeClientToolRef.current = executeClientTool;
4805
4991
  submitToolResultRef.current = chat.submitToolResult;
4992
+ const prevOnboardingRef = React3.useRef(isOnboarding);
4993
+ React3.useEffect(() => {
4994
+ if (isOnboarding && !prevOnboardingRef.current) {
4995
+ chat.setSuggestedActions([]);
4996
+ }
4997
+ if (prevOnboardingRef.current && !isOnboarding) {
4998
+ chat.resetMessages();
4999
+ endWorkflow(0);
5000
+ }
5001
+ prevOnboardingRef.current = isOnboarding;
5002
+ }, [isOnboarding]);
4806
5003
  React3.useEffect(() => {
4807
5004
  if (!isLoadingStyles) {
4808
5005
  onReady?.();
@@ -5087,7 +5284,59 @@ function CrowWidget({
5087
5284
  setIsCollapsed(!isCollapsed);
5088
5285
  };
5089
5286
  const renderWidgetContent = () => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5090
- /* @__PURE__ */ jsxRuntime.jsx(
5287
+ isOnboarding ? /* @__PURE__ */ jsxRuntime.jsxs(
5288
+ "div",
5289
+ {
5290
+ style: {
5291
+ display: "flex",
5292
+ alignItems: "center",
5293
+ justifyContent: "space-between",
5294
+ padding: "10px 16px",
5295
+ borderBottom: "1px solid var(--crow-border, #e5e7eb)",
5296
+ flexShrink: 0,
5297
+ cursor: variant === "floating" ? "grab" : void 0
5298
+ },
5299
+ onPointerDown: variant === "floating" ? transform.onDragPointerDown : void 0,
5300
+ children: [
5301
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 13, fontWeight: 600, color: "var(--crow-text, #111827)" }, children: onboardingAgentName || agentName }),
5302
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
5303
+ /* @__PURE__ */ jsxRuntime.jsx(
5304
+ "button",
5305
+ {
5306
+ onClick: () => {
5307
+ setIsOnboarding(false);
5308
+ chat.resetMessages();
5309
+ },
5310
+ style: {
5311
+ fontSize: 12,
5312
+ color: "#9ca3af",
5313
+ background: "none",
5314
+ border: "none",
5315
+ cursor: "pointer",
5316
+ padding: "4px 8px"
5317
+ },
5318
+ children: "Skip"
5319
+ }
5320
+ ),
5321
+ variant === "floating" && /* @__PURE__ */ jsxRuntime.jsx(
5322
+ "button",
5323
+ {
5324
+ onClick: () => setIsCollapsed(true),
5325
+ style: {
5326
+ background: "none",
5327
+ border: "none",
5328
+ cursor: "pointer",
5329
+ padding: "4px",
5330
+ color: "#9ca3af",
5331
+ display: "flex"
5332
+ },
5333
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 18L18 6M6 6l12 12" }) })
5334
+ }
5335
+ )
5336
+ ] })
5337
+ ]
5338
+ }
5339
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
5091
5340
  WidgetHeader,
5092
5341
  {
5093
5342
  isVerifiedUser,
@@ -5103,82 +5352,92 @@ function CrowWidget({
5103
5352
  contextLabel
5104
5353
  }
5105
5354
  ),
5106
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: showConversationList && isVerifiedUser && /* @__PURE__ */ jsxRuntime.jsx(
5107
- ConversationList,
5108
- {
5109
- conversations: conversations.conversations,
5110
- currentConversationId: chat.conversationId,
5111
- onSelect: handleSelectConversation,
5112
- onClose: handleCloseConversationList
5113
- }
5114
- ) }),
5115
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: activeWorkflow && /* @__PURE__ */ jsxRuntime.jsx(
5116
- WorkflowPanel,
5355
+ isOnboarding && onboardingPhase === "intro" && /* @__PURE__ */ jsxRuntime.jsx(
5356
+ OnboardingIntroInline,
5117
5357
  {
5118
- workflow: activeWorkflow,
5119
- onExit: handleExitWorkflow
5358
+ lines: onboardingIntroSequence || [],
5359
+ primaryColor: styles.colors.primary,
5360
+ onComplete: () => setOnboardingPhase("chat")
5120
5361
  }
5121
- ) }),
5122
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: (chat.messages.length > 0 || conversations.isLoadingHistory || pendingConfirmation) && /* @__PURE__ */ jsxRuntime.jsxs(MessagesContainer, { ref: messagesContainerRef, children: [
5123
- /* @__PURE__ */ jsxRuntime.jsx(
5124
- MessageList,
5362
+ ),
5363
+ !(isOnboarding && onboardingPhase === "intro") && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5364
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: showConversationList && isVerifiedUser && /* @__PURE__ */ jsxRuntime.jsx(
5365
+ ConversationList,
5125
5366
  {
5126
- messages: chat.messages,
5127
- activeToolCalls: chat.activeToolCalls,
5128
- isLoadingHistory: conversations.isLoadingHistory,
5129
- isGenerating: chat.isLoading,
5130
- toolRenderers: effectiveToolRenderers,
5131
- onToolConsent: handleToolConsent
5367
+ conversations: conversations.conversations,
5368
+ currentConversationId: chat.conversationId,
5369
+ onSelect: handleSelectConversation,
5370
+ onClose: handleCloseConversationList
5132
5371
  }
5133
- ),
5134
- pendingConfirmation && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-px-4 crow-py-2", children: /* @__PURE__ */ jsxRuntime.jsx(
5135
- BrowserUseConfirmation,
5372
+ ) }),
5373
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: activeWorkflow && !isOnboarding && /* @__PURE__ */ jsxRuntime.jsx(
5374
+ WorkflowPanel,
5136
5375
  {
5137
- instruction: pendingConfirmation.instruction,
5138
- onAllow: () => {
5139
- setIsBrowserUseActive(true);
5140
- pendingConfirmation.resolve(true);
5141
- setPendingConfirmation(null);
5142
- },
5143
- onDeny: () => {
5144
- pendingConfirmation.resolve(false);
5145
- setPendingConfirmation(null);
5146
- }
5376
+ workflow: activeWorkflow,
5377
+ onExit: handleExitWorkflow
5147
5378
  }
5148
- ) })
5149
- ] }) }),
5150
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "crow-mt-auto crow-w-full", children: [
5151
- toolStatus && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "crow-mx-3 crow-mb-1 crow-flex crow-items-center crow-gap-2 crow-rounded-lg crow-border crow-border-[var(--crow-border,#e5e7eb)] crow-bg-[var(--crow-bg-secondary,#f3f4f6)] crow-px-3 crow-py-2 crow-text-sm", children: [
5152
- /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "crow-animate-spin crow-h-4 crow-w-4 crow-shrink-0 crow-text-[var(--crow-primary,#7c3aed)]", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
5153
- /* @__PURE__ */ jsxRuntime.jsx("circle", { className: "crow-opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
5154
- /* @__PURE__ */ jsxRuntime.jsx("path", { className: "crow-opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
5379
+ ) }),
5380
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: (chat.messages.length > 0 || conversations.isLoadingHistory || pendingConfirmation) && /* @__PURE__ */ jsxRuntime.jsxs(MessagesContainer, { ref: messagesContainerRef, children: [
5381
+ /* @__PURE__ */ jsxRuntime.jsx(
5382
+ MessageList,
5383
+ {
5384
+ messages: chat.messages,
5385
+ activeToolCalls: chat.activeToolCalls,
5386
+ isLoadingHistory: conversations.isLoadingHistory,
5387
+ isGenerating: chat.isLoading,
5388
+ toolRenderers: effectiveToolRenderers,
5389
+ onToolConsent: handleToolConsent
5390
+ }
5391
+ ),
5392
+ pendingConfirmation && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-px-4 crow-py-2", children: /* @__PURE__ */ jsxRuntime.jsx(
5393
+ BrowserUseConfirmation,
5394
+ {
5395
+ instruction: pendingConfirmation.instruction,
5396
+ onAllow: () => {
5397
+ setIsBrowserUseActive(true);
5398
+ pendingConfirmation.resolve(true);
5399
+ setPendingConfirmation(null);
5400
+ },
5401
+ onDeny: () => {
5402
+ pendingConfirmation.resolve(false);
5403
+ setPendingConfirmation(null);
5404
+ }
5405
+ }
5406
+ ) })
5407
+ ] }) }),
5408
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "crow-mt-auto crow-w-full", children: [
5409
+ toolStatus && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "crow-mx-3 crow-mb-1 crow-flex crow-items-center crow-gap-2 crow-rounded-lg crow-border crow-border-[var(--crow-border,#e5e7eb)] crow-bg-[var(--crow-bg-secondary,#f3f4f6)] crow-px-3 crow-py-2 crow-text-sm", children: [
5410
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "crow-animate-spin crow-h-4 crow-w-4 crow-shrink-0 crow-text-[var(--crow-primary,#7c3aed)]", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
5411
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { className: "crow-opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
5412
+ /* @__PURE__ */ jsxRuntime.jsx("path", { className: "crow-opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
5413
+ ] }),
5414
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "crow-font-medium crow-text-[var(--crow-text,#111827)]", children: toolStatus })
5155
5415
  ] }),
5156
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "crow-font-medium crow-text-[var(--crow-text,#111827)]", children: toolStatus })
5157
- ] }),
5158
- (chat.suggestedActions.length > 0 || !chat.isLoading && defaultSuggestedActionsRef.current.length > 0) && /* @__PURE__ */ jsxRuntime.jsx(
5159
- SuggestedActions,
5160
- {
5161
- actions: chat.suggestedActions.length > 0 ? chat.suggestedActions : defaultSuggestedActionsRef.current,
5162
- onActionClick: (action) => handleSend(action.message)
5163
- }
5164
- ),
5165
- /* @__PURE__ */ jsxRuntime.jsx(PoweredByBadge, { apiUrl }),
5166
- /* @__PURE__ */ jsxRuntime.jsx(
5167
- PromptInputBox,
5168
- {
5169
- onSend: handleSend,
5170
- onStop: handleStop,
5171
- placeholder: "Type your message...",
5172
- isLoading: chat.isLoading,
5173
- showStopButton: isBrowserUseActive || !!askUserResolver || !!pendingConfirmation,
5174
- highlighted: !!askUserResolver,
5175
- className: "crow-backdrop-blur-md",
5176
- backendUrl: apiUrl,
5177
- selectedModel: chat.selectedModel || selectedModelFromAPI,
5178
- onModelChange: chat.setSelectedModel,
5179
- availableModels: modelSelectionEnabled ? availableModelsFromAPI : []
5180
- }
5181
- )
5416
+ (chat.suggestedActions.length > 0 || !isOnboarding && !chat.isLoading && defaultSuggestedActionsRef.current.length > 0) && /* @__PURE__ */ jsxRuntime.jsx(
5417
+ SuggestedActions,
5418
+ {
5419
+ actions: chat.suggestedActions.length > 0 ? chat.suggestedActions : defaultSuggestedActionsRef.current,
5420
+ onActionClick: (action) => handleSend(action.message)
5421
+ }
5422
+ ),
5423
+ /* @__PURE__ */ jsxRuntime.jsx(PoweredByBadge, { apiUrl }),
5424
+ /* @__PURE__ */ jsxRuntime.jsx(
5425
+ PromptInputBox,
5426
+ {
5427
+ onSend: handleSend,
5428
+ onStop: handleStop,
5429
+ placeholder: "Type your message...",
5430
+ isLoading: chat.isLoading,
5431
+ showStopButton: isBrowserUseActive || !!askUserResolver || !!pendingConfirmation,
5432
+ highlighted: !!askUserResolver,
5433
+ className: "crow-backdrop-blur-md",
5434
+ backendUrl: apiUrl,
5435
+ selectedModel: chat.selectedModel || selectedModelFromAPI,
5436
+ onModelChange: chat.setSelectedModel,
5437
+ availableModels: modelSelectionEnabled ? availableModelsFromAPI : []
5438
+ }
5439
+ )
5440
+ ] })
5182
5441
  ] })
5183
5442
  ] });
5184
5443
  const combinedStyles = React3.useMemo(
@@ -5192,7 +5451,7 @@ ${customCss}` : WIDGET_CSS,
5192
5451
  WidgetStyleProvider,
5193
5452
  {
5194
5453
  styles,
5195
- agentName,
5454
+ agentName: isOnboarding ? onboardingAgentName || agentName : agentName,
5196
5455
  isLoading: isLoadingStyles,
5197
5456
  variant,
5198
5457
  showThinking,
@@ -5489,6 +5748,78 @@ function CopilotContainer({
5489
5748
  )
5490
5749
  ] });
5491
5750
  }
5751
+ function OnboardingIntroInline2({
5752
+ lines,
5753
+ primaryColor,
5754
+ textColor,
5755
+ textMutedColor,
5756
+ onComplete
5757
+ }) {
5758
+ const [lineIndex, setLineIndex] = React3.useState(0);
5759
+ const [charIndex, setCharIndex] = React3.useState(0);
5760
+ const [done, setDone] = React3.useState(false);
5761
+ React3.useEffect(() => {
5762
+ if (lineIndex >= lines.length) {
5763
+ setDone(true);
5764
+ return;
5765
+ }
5766
+ const currentLine = lines[lineIndex];
5767
+ if (charIndex < currentLine.length) {
5768
+ const t = setTimeout(() => setCharIndex((c) => c + 1), 35);
5769
+ return () => clearTimeout(t);
5770
+ } else {
5771
+ const t = setTimeout(() => {
5772
+ setLineIndex((l) => l + 1);
5773
+ setCharIndex(0);
5774
+ }, 500);
5775
+ return () => clearTimeout(t);
5776
+ }
5777
+ }, [lineIndex, charIndex, lines]);
5778
+ const displayedLines = lines.slice(0, lineIndex + 1).map(
5779
+ (line, i) => i < lineIndex ? line : line.slice(0, charIndex)
5780
+ );
5781
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5782
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { minHeight: "4rem", marginBottom: "1.5rem" }, children: displayedLines.map((text, i) => /* @__PURE__ */ jsxRuntime.jsxs("p", { style: {
5783
+ fontSize: i === 0 ? 18 : 14,
5784
+ fontWeight: i === 0 ? 600 : 400,
5785
+ color: i === 0 ? textColor : textMutedColor,
5786
+ lineHeight: 1.4,
5787
+ margin: "0 0 6px 0"
5788
+ }, children: [
5789
+ text,
5790
+ i === lineIndex && !done && /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
5791
+ display: "inline-block",
5792
+ width: 2,
5793
+ height: i === 0 ? 18 : 14,
5794
+ backgroundColor: textColor,
5795
+ marginLeft: 2,
5796
+ verticalAlign: "middle",
5797
+ animation: "crow-blink 1s step-end infinite"
5798
+ } })
5799
+ ] }, i)) }),
5800
+ /* @__PURE__ */ jsxRuntime.jsx(
5801
+ "button",
5802
+ {
5803
+ onClick: onComplete,
5804
+ style: {
5805
+ padding: "8px 24px",
5806
+ borderRadius: 8,
5807
+ backgroundColor: primaryColor,
5808
+ color: "#fff",
5809
+ fontSize: 13,
5810
+ fontWeight: 500,
5811
+ border: "none",
5812
+ cursor: "pointer",
5813
+ opacity: done ? 1 : 0,
5814
+ pointerEvents: done ? "auto" : "none",
5815
+ transition: "opacity 0.5s ease"
5816
+ },
5817
+ children: "Get Started \u2192"
5818
+ }
5819
+ ),
5820
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `@keyframes crow-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }` })
5821
+ ] });
5822
+ }
5492
5823
  function CrowCopilot({
5493
5824
  productId,
5494
5825
  apiUrl = "",
@@ -5512,7 +5843,10 @@ function CrowCopilot({
5512
5843
  getIdentityToken,
5513
5844
  context,
5514
5845
  language,
5515
- contextLabel: contextLabelProp
5846
+ contextLabel: contextLabelProp,
5847
+ forceOnboarding = false,
5848
+ fullscreenTopOffset: _fullscreenTopOffset = 0,
5849
+ mode: _mode
5516
5850
  }) {
5517
5851
  const effectiveGetIdentityToken = getIdentityToken || window.__crow_identity_token_fetcher;
5518
5852
  const effectiveOnToolResult = onToolResult || window.__crow_on_tool_result;
@@ -5530,7 +5864,11 @@ function CrowCopilot({
5530
5864
  toolConsentSettings,
5531
5865
  modelSelectionEnabled,
5532
5866
  availableModels: availableModelsFromAPI,
5533
- initialSuggestions
5867
+ initialSuggestions,
5868
+ onboardingEnabled,
5869
+ onboardingAgentName,
5870
+ onboardingWelcomeMessage,
5871
+ onboardingIntroSequence
5534
5872
  } = useCopilotStyles({
5535
5873
  productId,
5536
5874
  apiUrl,
@@ -5539,6 +5877,20 @@ function CrowCopilot({
5539
5877
  language
5540
5878
  });
5541
5879
  const agentName = agentNameProp ?? agentNameFromAPI ?? title;
5880
+ const [isOnboarding, setIsOnboarding] = React3.useState(false);
5881
+ const [onboardingChecked, setOnboardingChecked] = React3.useState(false);
5882
+ const [onboardingPhase, setOnboardingPhase] = React3.useState("intro");
5883
+ React3.useEffect(() => {
5884
+ if (!isLoadingStyles && !onboardingChecked && (forceOnboarding || onboardingEnabled)) {
5885
+ setIsOnboarding(true);
5886
+ setOnboardingChecked(true);
5887
+ }
5888
+ }, [forceOnboarding, isLoadingStyles, onboardingEnabled, onboardingChecked]);
5889
+ React3.useEffect(() => {
5890
+ if (isOnboarding && !isLoadingStyles && onboardingIntroSequence !== void 0 && onboardingIntroSequence.length === 0) {
5891
+ setOnboardingPhase("chat");
5892
+ }
5893
+ }, [isOnboarding, isLoadingStyles, onboardingIntroSequence]);
5542
5894
  const [toolStatus, setToolStatus] = React3.useState(
5543
5895
  () => window.__crow_tool_status ?? ""
5544
5896
  );
@@ -5719,10 +6071,10 @@ function CrowCopilot({
5719
6071
  };
5720
6072
  }, []);
5721
6073
  React3.useEffect(() => {
5722
- if (initialSuggestions.length > 0 && chat.suggestedActions.length === 0) {
6074
+ if (!isOnboarding && initialSuggestions.length > 0 && chat.suggestedActions.length === 0) {
5723
6075
  chat.setSuggestedActions(initialSuggestions);
5724
6076
  }
5725
- }, [initialSuggestions]);
6077
+ }, [initialSuggestions, isOnboarding]);
5726
6078
  const messagesContainerRef = React3.useRef(null);
5727
6079
  const tabsScrollRef = React3.useRef(null);
5728
6080
  const executeClientToolRef = React3.useRef(null);
@@ -5752,11 +6104,17 @@ function CrowCopilot({
5752
6104
  pendingRestoreConvId.current = "";
5753
6105
  }
5754
6106
  }
6107
+ const effectiveWelcomeMessage = isOnboarding ? onboardingWelcomeMessage || `Hi! I'm ${onboardingAgentName || agentName}. Let me help you get started.` : welcomeMessage;
5755
6108
  const chat = useChat({
5756
6109
  productId,
5757
6110
  apiUrl,
5758
6111
  persistAnonymousConversations,
5759
- welcomeMessage,
6112
+ welcomeMessage: effectiveWelcomeMessage,
6113
+ agentMode: isOnboarding ? "onboarding" : void 0,
6114
+ onOnboardingComplete: (summary) => {
6115
+ console.log("[Crow] Onboarding complete:", summary);
6116
+ setIsOnboarding(false);
6117
+ },
5760
6118
  selectedModel,
5761
6119
  subdomain,
5762
6120
  toolConsentSettings,
@@ -5900,6 +6258,33 @@ function CrowCopilot({
5900
6258
  const { executeClientTool } = useCrowAPI({
5901
6259
  onIdentified: async () => {
5902
6260
  setIsVerifiedUser(true);
6261
+ if (forceOnboarding) {
6262
+ setIsOnboarding(true);
6263
+ setOnboardingChecked(true);
6264
+ } else if (onboardingEnabled && !onboardingChecked) {
6265
+ try {
6266
+ const identityToken = window.__crow_identity_token;
6267
+ if (identityToken) {
6268
+ const res = await fetch(`${apiUrl}/api/chat/resolve-agent`, {
6269
+ method: "POST",
6270
+ headers: { "Content-Type": "application/json" },
6271
+ body: JSON.stringify({
6272
+ product_id: productId,
6273
+ identity_token: identityToken
6274
+ })
6275
+ });
6276
+ if (res.ok) {
6277
+ const data = await res.json();
6278
+ if (data.agent === "onboarding") {
6279
+ setIsOnboarding(true);
6280
+ }
6281
+ }
6282
+ }
6283
+ } catch (e) {
6284
+ console.error("[Crow] resolve-agent failed:", e);
6285
+ }
6286
+ setOnboardingChecked(true);
6287
+ }
5903
6288
  await conversations.loadConversations();
5904
6289
  const savedId = pendingRestoreConvId.current;
5905
6290
  if (savedId && !hasRestoredActiveConvRef.current) {
@@ -5922,6 +6307,17 @@ function CrowCopilot({
5922
6307
  });
5923
6308
  executeClientToolRef.current = executeClientTool;
5924
6309
  submitToolResultRef.current = chat.submitToolResult;
6310
+ const prevOnboardingRef = React3.useRef(isOnboarding);
6311
+ React3.useEffect(() => {
6312
+ if (isOnboarding && !prevOnboardingRef.current) {
6313
+ chat.setSuggestedActions([]);
6314
+ }
6315
+ if (prevOnboardingRef.current && !isOnboarding) {
6316
+ chat.resetMessages();
6317
+ endWorkflow(0);
6318
+ }
6319
+ prevOnboardingRef.current = isOnboarding;
6320
+ }, [isOnboarding]);
5925
6321
  const handleBrowserConfirmation = React3.useCallback(
5926
6322
  (instruction) => {
5927
6323
  return new Promise((resolve) => {
@@ -6262,312 +6658,347 @@ function CrowCopilot({
6262
6658
  "--crow-bg-active": styles.colors.text + "18"
6263
6659
  },
6264
6660
  children: [
6265
- /* @__PURE__ */ jsxRuntime.jsxs(
6266
- "div",
6267
- {
6268
- className: "crow-flex crow-items-stretch crow-border-b crow-min-h-[40px]",
6269
- style: { borderColor: styles.colors.border },
6270
- children: [
6271
- /* @__PURE__ */ jsxRuntime.jsx(
6272
- "div",
6273
- {
6274
- ref: tabsScrollRef,
6275
- className: "crow-flex crow-items-stretch crow-flex-1 crow-min-w-0 crow-overflow-x-auto",
6276
- style: {
6277
- scrollbarWidth: "none",
6278
- msOverflowStyle: "none"
6279
- },
6280
- onScroll: handleTabsScroll,
6281
- children: tabs.map((tab, idx) => {
6282
- const isActive = activeTabId === tab.id;
6283
- const isHovered = hoveredTabId === tab.id;
6284
- const isCloseable = tab.type !== "new" && (tab.type !== "local" || localTabs.length > 1);
6285
- return /* @__PURE__ */ jsxRuntime.jsxs(
6286
- "div",
6287
- {
6288
- className: "crow-relative crow-flex-shrink-0 crow-flex crow-items-center crow-text-[13px] crow-leading-tight crow-py-2.5 crow-transition-colors crow-select-none crow-cursor-pointer",
6289
- style: {
6290
- color: isActive ? styles.colors.text : styles.colors.text + "80",
6291
- fontWeight: isActive ? 500 : void 0,
6292
- maxWidth: "180px",
6293
- borderRight: idx < tabs.length - 1 ? `1px solid ${styles.colors.border}` : "none",
6294
- paddingLeft: "16px",
6295
- paddingRight: isCloseable ? "8px" : "16px"
6296
- },
6297
- title: tab.name,
6298
- onMouseEnter: () => setHoveredTabId(tab.id),
6299
- onMouseLeave: () => setHoveredTabId(null),
6300
- onClick: () => {
6301
- if (tab.type === "new") {
6302
- handleNewChat();
6303
- return;
6304
- }
6305
- if (tab.type === "server") {
6306
- handleSelectConversation(tab.id);
6307
- return;
6308
- }
6309
- handleSelectLocalTab(tab.id);
6310
- },
6311
- children: [
6312
- /* @__PURE__ */ jsxRuntime.jsx(
6313
- "span",
6314
- {
6315
- className: "crow-block crow-truncate",
6316
- style: { maxWidth: isCloseable ? "112px" : "128px" },
6317
- children: tab.name
6318
- }
6319
- ),
6320
- isCloseable && /* @__PURE__ */ jsxRuntime.jsx(
6321
- "span",
6322
- {
6323
- className: "crow-rounded crow-p-0.5 crow-flex-shrink-0 crow-inline-flex crow-items-center crow-justify-center crow-transition-opacity",
6324
- style: {
6325
- marginLeft: "6px",
6326
- opacity: isHovered ? 1 : 0,
6327
- pointerEvents: isHovered ? "auto" : "none"
6328
- },
6329
- onClick: (e) => {
6330
- e.stopPropagation();
6331
- handleCloseTab(tab.id, tab.type);
6332
- },
6333
- role: "button",
6334
- "aria-label": `Close ${tab.name}`,
6335
- children: /* @__PURE__ */ jsxRuntime.jsx(TabCloseIcon, { className: "crow-w-3 crow-h-3", style: { color: styles.colors.text + "80" } })
6336
- }
6337
- ),
6338
- isActive && /* @__PURE__ */ jsxRuntime.jsx(
6339
- "span",
6340
- {
6341
- className: "crow-absolute crow-bottom-0 crow-left-0 crow-right-0",
6342
- style: {
6343
- height: "2px",
6344
- background: styles.colors.primary || "#2563eb"
6345
- }
6346
- }
6347
- )
6348
- ]
6349
- },
6350
- `${tab.id}-${idx}`
6351
- );
6352
- })
6353
- }
6354
- ),
6355
- /* @__PURE__ */ jsxRuntime.jsxs(
6356
- "div",
6357
- {
6358
- className: "crow-flex crow-items-center crow-flex-shrink-0 crow-border-l",
6359
- style: { borderColor: styles.colors.border },
6360
- children: [
6361
- /* @__PURE__ */ jsxRuntime.jsx(
6362
- "button",
6363
- {
6364
- onClick: handleNewChat,
6365
- className: "crow-p-2 crow-transition-colors crow-rounded",
6366
- style: { color: styles.colors.text + "80" },
6367
- onMouseEnter: (e) => {
6368
- e.currentTarget.style.background = styles.colors.text + "10";
6369
- },
6370
- onMouseLeave: (e) => {
6371
- e.currentTarget.style.background = "transparent";
6372
- },
6373
- "aria-label": "New Chat",
6374
- title: "New Chat",
6375
- children: /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, { className: "crow-w-4 crow-h-4" })
6376
- }
6377
- ),
6378
- /* @__PURE__ */ jsxRuntime.jsx(
6379
- "button",
6380
- {
6381
- onClick: handleToggleHistory,
6382
- disabled: !isVerifiedUser,
6383
- "aria-disabled": !isVerifiedUser,
6384
- className: `crow-p-2 crow-transition-colors crow-rounded ${!isVerifiedUser ? "crow-opacity-40 crow-cursor-not-allowed" : ""}`,
6385
- style: {
6386
- color: styles.colors.text + "80",
6387
- background: showConversationList ? styles.colors.text + "10" : "transparent"
6388
- },
6389
- onMouseEnter: (e) => {
6390
- if (isVerifiedUser) e.currentTarget.style.background = styles.colors.text + "10";
6391
- },
6392
- onMouseLeave: (e) => {
6393
- if (!showConversationList) e.currentTarget.style.background = "transparent";
6394
- },
6395
- "aria-label": "Conversation History",
6396
- title: isVerifiedUser ? "Conversation History" : "Sign in to view history",
6397
- children: /* @__PURE__ */ jsxRuntime.jsx(HistoryIcon, { className: "crow-w-4 crow-h-4" })
6398
- }
6399
- ),
6400
- canScrollRight && /* @__PURE__ */ jsxRuntime.jsx(
6401
- "button",
6402
- {
6403
- onClick: handleScrollRight,
6404
- className: "crow-p-2 crow-transition-colors crow-rounded",
6405
- style: { color: styles.colors.text + "80" },
6406
- onMouseEnter: (e) => {
6407
- e.currentTarget.style.background = styles.colors.text + "10";
6408
- },
6409
- onMouseLeave: (e) => {
6410
- e.currentTarget.style.background = "transparent";
6411
- },
6412
- "aria-label": "Scroll tabs",
6413
- title: "Scroll tabs",
6414
- children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRightIcon, { className: "crow-w-4 crow-h-4" })
6415
- }
6416
- ),
6417
- (forceShowClose ?? showClose) && (overrideOnClose ?? onClose) && /* @__PURE__ */ jsxRuntime.jsx(
6418
- "button",
6419
- {
6420
- onClick: overrideOnClose ?? onClose,
6421
- className: "crow-p-2 crow-transition-colors crow-rounded",
6422
- style: { color: styles.colors.text + "80" },
6423
- onMouseEnter: (e) => {
6424
- e.currentTarget.style.background = styles.colors.text + "10";
6425
- },
6426
- onMouseLeave: (e) => {
6427
- e.currentTarget.style.background = "transparent";
6428
- },
6429
- "aria-label": "Close",
6430
- children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { className: "crow-w-4 crow-h-4" })
6431
- }
6432
- )
6433
- ]
6434
- }
6435
- )
6436
- ]
6437
- }
6438
- ),
6439
- contextLabel && /* @__PURE__ */ jsxRuntime.jsxs(
6440
- "div",
6441
- {
6442
- className: "crow-flex crow-items-center crow-gap-1.5 crow-px-3 crow-py-1.5 crow-border-b crow-text-xs",
6443
- style: {
6444
- color: styles.colors.text + "80",
6445
- borderColor: styles.colors.border
6446
- },
6447
- children: [
6448
- /* @__PURE__ */ jsxRuntime.jsxs(
6449
- "svg",
6450
- {
6451
- xmlns: "http://www.w3.org/2000/svg",
6452
- width: "12",
6453
- height: "12",
6454
- viewBox: "0 0 24 24",
6455
- fill: "none",
6456
- stroke: "currentColor",
6457
- strokeWidth: "2",
6458
- strokeLinecap: "round",
6459
- strokeLinejoin: "round",
6460
- className: "crow-shrink-0",
6461
- children: [
6462
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" }),
6463
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "10", r: "3" })
6464
- ]
6465
- }
6466
- ),
6467
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "crow-truncate", children: contextLabel })
6468
- ]
6469
- }
6470
- ),
6471
- /* @__PURE__ */ jsxRuntime.jsxs(framerMotion.AnimatePresence, { children: [
6472
- showConversationList && isVerifiedUser && /* @__PURE__ */ jsxRuntime.jsx(
6473
- ConversationList,
6661
+ isOnboarding && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6662
+ /* @__PURE__ */ jsxRuntime.jsxs(
6663
+ "div",
6474
6664
  {
6475
- conversations: conversations.conversations,
6476
- currentConversationId: chat.conversationId,
6477
- onSelect: handleSelectConversation,
6478
- onClose: handleCloseConversationList
6665
+ className: "crow-flex crow-items-center crow-justify-between crow-border-b crow-px-4 crow-py-2.5",
6666
+ style: { borderColor: styles.colors.border },
6667
+ children: [
6668
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "crow-text-[13px] crow-font-semibold", style: { color: styles.colors.text }, children: onboardingAgentName || agentName }),
6669
+ /* @__PURE__ */ jsxRuntime.jsx(
6670
+ "button",
6671
+ {
6672
+ onClick: () => {
6673
+ setIsOnboarding(false);
6674
+ },
6675
+ className: "crow-text-xs crow-border-none crow-bg-transparent crow-cursor-pointer crow-px-2 crow-py-1",
6676
+ style: { color: styles.colors.text + "60" },
6677
+ children: "Skip"
6678
+ }
6679
+ )
6680
+ ]
6479
6681
  }
6480
6682
  ),
6481
- showConversationList && !isVerifiedUser && /* @__PURE__ */ jsxRuntime.jsx(
6482
- "div",
6683
+ onboardingPhase === "intro" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-flex crow-flex-col crow-items-center crow-justify-center crow-flex-1 crow-px-4 crow-py-6 crow-text-center", children: /* @__PURE__ */ jsxRuntime.jsx(
6684
+ OnboardingIntroInline2,
6483
6685
  {
6484
- className: "crow-mb-3 crow-rounded-xl crow-border crow-p-4",
6485
- style: { background: styles.colors.text + "08", borderColor: styles.colors.border },
6486
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-text-sm", style: { color: styles.colors.text + "99" }, children: "Sign in to view conversation history." })
6686
+ lines: onboardingIntroSequence || [],
6687
+ primaryColor: styles.colors.primary,
6688
+ textColor: styles.colors.text,
6689
+ textMutedColor: styles.colors.text + "80",
6690
+ onComplete: () => setOnboardingPhase("chat")
6487
6691
  }
6488
- )
6692
+ ) })
6489
6693
  ] }),
6490
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: activeWorkflow && /* @__PURE__ */ jsxRuntime.jsx(
6491
- WorkflowPanel,
6492
- {
6493
- workflow: activeWorkflow,
6494
- onExit: handleExitWorkflow
6495
- }
6496
- ) }),
6497
- /* @__PURE__ */ jsxRuntime.jsxs(MessagesContainer, { ref: messagesContainerRef, children: [
6498
- /* @__PURE__ */ jsxRuntime.jsx(
6499
- MessageList,
6694
+ !(isOnboarding && onboardingPhase === "intro") && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6695
+ !isOnboarding && /* @__PURE__ */ jsxRuntime.jsxs(
6696
+ "div",
6500
6697
  {
6501
- messages: chat.messages,
6502
- activeToolCalls: chat.activeToolCalls,
6503
- isLoadingHistory: conversations.isLoadingHistory,
6504
- isGenerating: chat.isLoading,
6505
- toolRenderers: effectiveToolRenderers,
6506
- onToolConsent: handleToolConsent
6698
+ className: "crow-flex crow-items-stretch crow-border-b crow-min-h-[40px]",
6699
+ style: { borderColor: styles.colors.border },
6700
+ children: [
6701
+ /* @__PURE__ */ jsxRuntime.jsx(
6702
+ "div",
6703
+ {
6704
+ ref: tabsScrollRef,
6705
+ className: "crow-flex crow-items-stretch crow-flex-1 crow-min-w-0 crow-overflow-x-auto",
6706
+ style: {
6707
+ scrollbarWidth: "none",
6708
+ msOverflowStyle: "none"
6709
+ },
6710
+ onScroll: handleTabsScroll,
6711
+ children: tabs.map((tab, idx) => {
6712
+ const isActive = activeTabId === tab.id;
6713
+ const isHovered = hoveredTabId === tab.id;
6714
+ const isCloseable = tab.type !== "new" && (tab.type !== "local" || localTabs.length > 1);
6715
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6716
+ "div",
6717
+ {
6718
+ className: "crow-relative crow-flex-shrink-0 crow-flex crow-items-center crow-text-[13px] crow-leading-tight crow-py-2.5 crow-transition-colors crow-select-none crow-cursor-pointer",
6719
+ style: {
6720
+ color: isActive ? styles.colors.text : styles.colors.text + "80",
6721
+ fontWeight: isActive ? 500 : void 0,
6722
+ maxWidth: "180px",
6723
+ borderRight: idx < tabs.length - 1 ? `1px solid ${styles.colors.border}` : "none",
6724
+ paddingLeft: "16px",
6725
+ paddingRight: isCloseable ? "8px" : "16px"
6726
+ },
6727
+ title: tab.name,
6728
+ onMouseEnter: () => setHoveredTabId(tab.id),
6729
+ onMouseLeave: () => setHoveredTabId(null),
6730
+ onClick: () => {
6731
+ if (tab.type === "new") {
6732
+ handleNewChat();
6733
+ return;
6734
+ }
6735
+ if (tab.type === "server") {
6736
+ handleSelectConversation(tab.id);
6737
+ return;
6738
+ }
6739
+ handleSelectLocalTab(tab.id);
6740
+ },
6741
+ children: [
6742
+ /* @__PURE__ */ jsxRuntime.jsx(
6743
+ "span",
6744
+ {
6745
+ className: "crow-block crow-truncate",
6746
+ style: { maxWidth: isCloseable ? "112px" : "128px" },
6747
+ children: tab.name
6748
+ }
6749
+ ),
6750
+ isCloseable && /* @__PURE__ */ jsxRuntime.jsx(
6751
+ "span",
6752
+ {
6753
+ className: "crow-rounded crow-p-0.5 crow-flex-shrink-0 crow-inline-flex crow-items-center crow-justify-center crow-transition-opacity",
6754
+ style: {
6755
+ marginLeft: "6px",
6756
+ opacity: isHovered ? 1 : 0,
6757
+ pointerEvents: isHovered ? "auto" : "none"
6758
+ },
6759
+ onClick: (e) => {
6760
+ e.stopPropagation();
6761
+ handleCloseTab(tab.id, tab.type);
6762
+ },
6763
+ role: "button",
6764
+ "aria-label": `Close ${tab.name}`,
6765
+ children: /* @__PURE__ */ jsxRuntime.jsx(TabCloseIcon, { className: "crow-w-3 crow-h-3", style: { color: styles.colors.text + "80" } })
6766
+ }
6767
+ ),
6768
+ isActive && /* @__PURE__ */ jsxRuntime.jsx(
6769
+ "span",
6770
+ {
6771
+ className: "crow-absolute crow-bottom-0 crow-left-0 crow-right-0",
6772
+ style: {
6773
+ height: "2px",
6774
+ background: styles.colors.primary || "#2563eb"
6775
+ }
6776
+ }
6777
+ )
6778
+ ]
6779
+ },
6780
+ `${tab.id}-${idx}`
6781
+ );
6782
+ })
6783
+ }
6784
+ ),
6785
+ /* @__PURE__ */ jsxRuntime.jsxs(
6786
+ "div",
6787
+ {
6788
+ className: "crow-flex crow-items-center crow-flex-shrink-0 crow-border-l",
6789
+ style: { borderColor: styles.colors.border },
6790
+ children: [
6791
+ /* @__PURE__ */ jsxRuntime.jsx(
6792
+ "button",
6793
+ {
6794
+ onClick: handleNewChat,
6795
+ className: "crow-p-2 crow-transition-colors crow-rounded",
6796
+ style: { color: styles.colors.text + "80" },
6797
+ onMouseEnter: (e) => {
6798
+ e.currentTarget.style.background = styles.colors.text + "10";
6799
+ },
6800
+ onMouseLeave: (e) => {
6801
+ e.currentTarget.style.background = "transparent";
6802
+ },
6803
+ "aria-label": "New Chat",
6804
+ title: "New Chat",
6805
+ children: /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, { className: "crow-w-4 crow-h-4" })
6806
+ }
6807
+ ),
6808
+ /* @__PURE__ */ jsxRuntime.jsx(
6809
+ "button",
6810
+ {
6811
+ onClick: handleToggleHistory,
6812
+ disabled: !isVerifiedUser,
6813
+ "aria-disabled": !isVerifiedUser,
6814
+ className: `crow-p-2 crow-transition-colors crow-rounded ${!isVerifiedUser ? "crow-opacity-40 crow-cursor-not-allowed" : ""}`,
6815
+ style: {
6816
+ color: styles.colors.text + "80",
6817
+ background: showConversationList ? styles.colors.text + "10" : "transparent"
6818
+ },
6819
+ onMouseEnter: (e) => {
6820
+ if (isVerifiedUser) e.currentTarget.style.background = styles.colors.text + "10";
6821
+ },
6822
+ onMouseLeave: (e) => {
6823
+ if (!showConversationList) e.currentTarget.style.background = "transparent";
6824
+ },
6825
+ "aria-label": "Conversation History",
6826
+ title: isVerifiedUser ? "Conversation History" : "Sign in to view history",
6827
+ children: /* @__PURE__ */ jsxRuntime.jsx(HistoryIcon, { className: "crow-w-4 crow-h-4" })
6828
+ }
6829
+ ),
6830
+ canScrollRight && /* @__PURE__ */ jsxRuntime.jsx(
6831
+ "button",
6832
+ {
6833
+ onClick: handleScrollRight,
6834
+ className: "crow-p-2 crow-transition-colors crow-rounded",
6835
+ style: { color: styles.colors.text + "80" },
6836
+ onMouseEnter: (e) => {
6837
+ e.currentTarget.style.background = styles.colors.text + "10";
6838
+ },
6839
+ onMouseLeave: (e) => {
6840
+ e.currentTarget.style.background = "transparent";
6841
+ },
6842
+ "aria-label": "Scroll tabs",
6843
+ title: "Scroll tabs",
6844
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRightIcon, { className: "crow-w-4 crow-h-4" })
6845
+ }
6846
+ ),
6847
+ (forceShowClose ?? showClose) && (overrideOnClose ?? onClose) && /* @__PURE__ */ jsxRuntime.jsx(
6848
+ "button",
6849
+ {
6850
+ onClick: overrideOnClose ?? onClose,
6851
+ className: "crow-p-2 crow-transition-colors crow-rounded",
6852
+ style: { color: styles.colors.text + "80" },
6853
+ onMouseEnter: (e) => {
6854
+ e.currentTarget.style.background = styles.colors.text + "10";
6855
+ },
6856
+ onMouseLeave: (e) => {
6857
+ e.currentTarget.style.background = "transparent";
6858
+ },
6859
+ "aria-label": "Close",
6860
+ children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { className: "crow-w-4 crow-h-4" })
6861
+ }
6862
+ )
6863
+ ]
6864
+ }
6865
+ )
6866
+ ]
6507
6867
  }
6508
6868
  ),
6509
- pendingConfirmation && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-px-4 crow-py-2", children: /* @__PURE__ */ jsxRuntime.jsx(
6510
- BrowserUseConfirmation,
6869
+ contextLabel && /* @__PURE__ */ jsxRuntime.jsxs(
6870
+ "div",
6511
6871
  {
6512
- instruction: pendingConfirmation.instruction,
6513
- onAllow: () => {
6514
- pendingConfirmation.resolve(true);
6515
- setPendingConfirmation(null);
6872
+ className: "crow-flex crow-items-center crow-gap-1.5 crow-px-3 crow-py-1.5 crow-border-b crow-text-xs",
6873
+ style: {
6874
+ color: styles.colors.text + "80",
6875
+ borderColor: styles.colors.border
6516
6876
  },
6517
- onDeny: () => {
6518
- pendingConfirmation.resolve(false);
6519
- setPendingConfirmation(null);
6877
+ children: [
6878
+ /* @__PURE__ */ jsxRuntime.jsxs(
6879
+ "svg",
6880
+ {
6881
+ xmlns: "http://www.w3.org/2000/svg",
6882
+ width: "12",
6883
+ height: "12",
6884
+ viewBox: "0 0 24 24",
6885
+ fill: "none",
6886
+ stroke: "currentColor",
6887
+ strokeWidth: "2",
6888
+ strokeLinecap: "round",
6889
+ strokeLinejoin: "round",
6890
+ className: "crow-shrink-0",
6891
+ children: [
6892
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" }),
6893
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "10", r: "3" })
6894
+ ]
6895
+ }
6896
+ ),
6897
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "crow-truncate", children: contextLabel })
6898
+ ]
6899
+ }
6900
+ ),
6901
+ /* @__PURE__ */ jsxRuntime.jsxs(framerMotion.AnimatePresence, { children: [
6902
+ showConversationList && isVerifiedUser && /* @__PURE__ */ jsxRuntime.jsx(
6903
+ ConversationList,
6904
+ {
6905
+ conversations: conversations.conversations,
6906
+ currentConversationId: chat.conversationId,
6907
+ onSelect: handleSelectConversation,
6908
+ onClose: handleCloseConversationList
6520
6909
  }
6910
+ ),
6911
+ showConversationList && !isVerifiedUser && /* @__PURE__ */ jsxRuntime.jsx(
6912
+ "div",
6913
+ {
6914
+ className: "crow-mb-3 crow-rounded-xl crow-border crow-p-4",
6915
+ style: { background: styles.colors.text + "08", borderColor: styles.colors.border },
6916
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-text-sm", style: { color: styles.colors.text + "99" }, children: "Sign in to view conversation history." })
6917
+ }
6918
+ )
6919
+ ] }),
6920
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: activeWorkflow && !isOnboarding && /* @__PURE__ */ jsxRuntime.jsx(
6921
+ WorkflowPanel,
6922
+ {
6923
+ workflow: activeWorkflow,
6924
+ onExit: handleExitWorkflow
6521
6925
  }
6522
6926
  ) }),
6523
- askUserResolver && browserQuestion && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-px-4 crow-py-2", children: /* @__PURE__ */ jsxRuntime.jsx(
6524
- BrowserUseQuestion,
6525
- {
6526
- question: browserQuestion,
6527
- onSubmit: (answer) => {
6528
- askUserResolver.resolve(answer);
6529
- setAskUserResolver(null);
6530
- setBrowserQuestion(null);
6927
+ /* @__PURE__ */ jsxRuntime.jsxs(MessagesContainer, { ref: messagesContainerRef, children: [
6928
+ /* @__PURE__ */ jsxRuntime.jsx(
6929
+ MessageList,
6930
+ {
6931
+ messages: chat.messages,
6932
+ activeToolCalls: chat.activeToolCalls,
6933
+ isLoadingHistory: conversations.isLoadingHistory,
6934
+ isGenerating: chat.isLoading,
6935
+ toolRenderers: effectiveToolRenderers,
6936
+ onToolConsent: handleToolConsent
6531
6937
  }
6532
- }
6533
- ) })
6534
- ] }),
6535
- /* @__PURE__ */ jsxRuntime.jsxs(
6536
- "div",
6537
- {
6538
- className: "crow-p-3 crow-border-t",
6539
- style: { borderColor: styles.colors.border },
6540
- children: [
6541
- toolStatus && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "crow-mb-1 crow-flex crow-items-center crow-gap-2 crow-rounded-lg crow-border crow-px-3 crow-py-2 crow-text-sm", style: { borderColor: styles.colors.border, background: styles.colors.border + "30" }, children: [
6542
- /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "crow-animate-spin crow-h-4 crow-w-4 crow-shrink-0 crow-text-[var(--crow-primary,#7c3aed)]", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
6543
- /* @__PURE__ */ jsxRuntime.jsx("circle", { className: "crow-opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
6544
- /* @__PURE__ */ jsxRuntime.jsx("path", { className: "crow-opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
6545
- ] }),
6546
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "crow-font-medium crow-text-[var(--crow-text,#111827)]", children: toolStatus })
6547
- ] }),
6548
- (chat.suggestedActions.length > 0 || !chat.isLoading && defaultSuggestedActionsRef.current.length > 0) && /* @__PURE__ */ jsxRuntime.jsx(
6549
- SuggestedActions,
6550
- {
6551
- actions: chat.suggestedActions.length > 0 ? chat.suggestedActions : defaultSuggestedActionsRef.current,
6552
- onActionClick: (action) => handleSend(action.message)
6938
+ ),
6939
+ pendingConfirmation && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-px-4 crow-py-2", children: /* @__PURE__ */ jsxRuntime.jsx(
6940
+ BrowserUseConfirmation,
6941
+ {
6942
+ instruction: pendingConfirmation.instruction,
6943
+ onAllow: () => {
6944
+ pendingConfirmation.resolve(true);
6945
+ setPendingConfirmation(null);
6946
+ },
6947
+ onDeny: () => {
6948
+ pendingConfirmation.resolve(false);
6949
+ setPendingConfirmation(null);
6553
6950
  }
6554
- ),
6555
- styles.branding.showPoweredBy && /* @__PURE__ */ jsxRuntime.jsx(PoweredByBadge, { apiUrl }),
6556
- /* @__PURE__ */ jsxRuntime.jsx(
6557
- PromptInputBox,
6558
- {
6559
- onSend: handleSend,
6560
- onStop: handleStop,
6561
- placeholder: "Ask anything...",
6562
- isLoading: chat.isLoading,
6563
- selectedModel: chat.selectedModel || selectedModel,
6564
- onModelChange: chat.setSelectedModel,
6565
- availableModels: modelSelectionEnabled ? availableModelsFromAPI : []
6951
+ }
6952
+ ) }),
6953
+ askUserResolver && browserQuestion && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-px-4 crow-py-2", children: /* @__PURE__ */ jsxRuntime.jsx(
6954
+ BrowserUseQuestion,
6955
+ {
6956
+ question: browserQuestion,
6957
+ onSubmit: (answer) => {
6958
+ askUserResolver.resolve(answer);
6959
+ setAskUserResolver(null);
6960
+ setBrowserQuestion(null);
6566
6961
  }
6567
- )
6568
- ]
6569
- }
6570
- )
6962
+ }
6963
+ ) })
6964
+ ] }),
6965
+ /* @__PURE__ */ jsxRuntime.jsxs(
6966
+ "div",
6967
+ {
6968
+ className: "crow-p-3 crow-border-t",
6969
+ style: { borderColor: styles.colors.border },
6970
+ children: [
6971
+ toolStatus && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "crow-mb-1 crow-flex crow-items-center crow-gap-2 crow-rounded-lg crow-border crow-px-3 crow-py-2 crow-text-sm", style: { borderColor: styles.colors.border, background: styles.colors.border + "30" }, children: [
6972
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "crow-animate-spin crow-h-4 crow-w-4 crow-shrink-0 crow-text-[var(--crow-primary,#7c3aed)]", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
6973
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { className: "crow-opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
6974
+ /* @__PURE__ */ jsxRuntime.jsx("path", { className: "crow-opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })
6975
+ ] }),
6976
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "crow-font-medium crow-text-[var(--crow-text,#111827)]", children: toolStatus })
6977
+ ] }),
6978
+ (chat.suggestedActions.length > 0 || !isOnboarding && !chat.isLoading && defaultSuggestedActionsRef.current.length > 0) && /* @__PURE__ */ jsxRuntime.jsx(
6979
+ SuggestedActions,
6980
+ {
6981
+ actions: chat.suggestedActions.length > 0 ? chat.suggestedActions : defaultSuggestedActionsRef.current,
6982
+ onActionClick: (action) => handleSend(action.message)
6983
+ }
6984
+ ),
6985
+ styles.branding.showPoweredBy && /* @__PURE__ */ jsxRuntime.jsx(PoweredByBadge, { apiUrl }),
6986
+ /* @__PURE__ */ jsxRuntime.jsx(
6987
+ PromptInputBox,
6988
+ {
6989
+ onSend: handleSend,
6990
+ onStop: handleStop,
6991
+ placeholder: "Ask anything...",
6992
+ isLoading: chat.isLoading,
6993
+ selectedModel: chat.selectedModel || selectedModel,
6994
+ onModelChange: chat.setSelectedModel,
6995
+ availableModels: modelSelectionEnabled ? availableModelsFromAPI : []
6996
+ }
6997
+ )
6998
+ ]
6999
+ }
7000
+ )
7001
+ ] })
6571
7002
  ]
6572
7003
  }
6573
7004
  )
@@ -6589,7 +7020,7 @@ function CrowCopilot({
6589
7020
  const edgeSide = isRight ? "left" : "right";
6590
7021
  const toggleIconColor = styles.colors.text + "80";
6591
7022
  const toggleIcon = isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: toggleIconColor, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7.9 20A9 9 0 1 0 4 16.1L2 22Z" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: toggleIconColor, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: isRight ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) : /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) });
6592
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", flexShrink: 0, height: "100%" }, children: [
7023
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", flexShrink: 0, height: "100%" }, children: [
6593
7024
  /* @__PURE__ */ jsxRuntime.jsx(
6594
7025
  "button",
6595
7026
  {
@@ -6633,7 +7064,7 @@ function CrowCopilot({
6633
7064
  children: /* @__PURE__ */ jsxRuntime.jsx(ShadowContainer, { styles: WIDGET_CSS, children: renderCopilotContent(void 0, false, "100%") })
6634
7065
  }
6635
7066
  )
6636
- ] });
7067
+ ] }) });
6637
7068
  }
6638
7069
  function PlusIcon({ className }) {
6639
7070
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -6739,6 +7170,320 @@ function CloseIcon({ className }) {
6739
7170
  }
6740
7171
  );
6741
7172
  }
7173
+ function IntroSequence({ lines, onComplete, onSkip, primaryColor }) {
7174
+ const [lineIndex, setLineIndex] = React3.useState(0);
7175
+ const [charIndex, setCharIndex] = React3.useState(0);
7176
+ const [done, setDone] = React3.useState(false);
7177
+ React3.useEffect(() => {
7178
+ if (lineIndex >= lines.length) {
7179
+ setDone(true);
7180
+ return;
7181
+ }
7182
+ const currentLine = lines[lineIndex];
7183
+ if (charIndex < currentLine.length) {
7184
+ const t = setTimeout(() => setCharIndex((c) => c + 1), 35);
7185
+ return () => clearTimeout(t);
7186
+ } else {
7187
+ const t = setTimeout(() => {
7188
+ setLineIndex((l) => l + 1);
7189
+ setCharIndex(0);
7190
+ }, 500);
7191
+ return () => clearTimeout(t);
7192
+ }
7193
+ }, [lineIndex, charIndex, lines]);
7194
+ const displayedLines = lines.slice(0, lineIndex + 1).map((line, i) => {
7195
+ if (i < lineIndex) return line;
7196
+ return line.slice(0, charIndex);
7197
+ });
7198
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", height: "100%", padding: "2rem" }, children: [
7199
+ /* @__PURE__ */ jsxRuntime.jsx(
7200
+ "button",
7201
+ {
7202
+ onClick: onSkip,
7203
+ style: {
7204
+ position: "absolute",
7205
+ top: 20,
7206
+ right: 24,
7207
+ fontSize: 14,
7208
+ color: "#9ca3af",
7209
+ background: "none",
7210
+ border: "none",
7211
+ cursor: "pointer",
7212
+ padding: "4px 8px"
7213
+ },
7214
+ children: "Skip"
7215
+ }
7216
+ ),
7217
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", minHeight: "5rem", marginBottom: "2.5rem" }, children: displayedLines.map((text, i) => /* @__PURE__ */ jsxRuntime.jsxs(
7218
+ "p",
7219
+ {
7220
+ style: {
7221
+ fontSize: i === 0 ? 30 : 18,
7222
+ fontWeight: i === 0 ? 600 : 400,
7223
+ color: i === 0 ? "#111827" : "#6b7280",
7224
+ lineHeight: 1.4,
7225
+ margin: "0 0 8px 0"
7226
+ },
7227
+ children: [
7228
+ text,
7229
+ i === lineIndex && !done && /* @__PURE__ */ jsxRuntime.jsx(
7230
+ "span",
7231
+ {
7232
+ style: {
7233
+ display: "inline-block",
7234
+ width: 2,
7235
+ height: i === 0 ? 28 : 18,
7236
+ backgroundColor: "#111827",
7237
+ marginLeft: 2,
7238
+ verticalAlign: "middle",
7239
+ animation: "crow-blink 1s step-end infinite"
7240
+ }
7241
+ }
7242
+ )
7243
+ ]
7244
+ },
7245
+ i
7246
+ )) }),
7247
+ /* @__PURE__ */ jsxRuntime.jsx(
7248
+ "button",
7249
+ {
7250
+ onClick: onComplete,
7251
+ style: {
7252
+ padding: "10px 32px",
7253
+ borderRadius: 12,
7254
+ backgroundColor: primaryColor,
7255
+ color: "#fff",
7256
+ fontSize: 15,
7257
+ fontWeight: 500,
7258
+ border: "none",
7259
+ cursor: "pointer",
7260
+ opacity: done ? 1 : 0,
7261
+ pointerEvents: done ? "auto" : "none",
7262
+ transition: "opacity 0.5s ease"
7263
+ },
7264
+ children: "Get Started \u2192"
7265
+ }
7266
+ ),
7267
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
7268
+ @keyframes crow-blink {
7269
+ 0%, 100% { opacity: 1; }
7270
+ 50% { opacity: 0; }
7271
+ }
7272
+ ` })
7273
+ ] });
7274
+ }
7275
+ function CrowOnboarding({
7276
+ productId,
7277
+ apiUrl,
7278
+ subdomain,
7279
+ agentName,
7280
+ welcomeMessage,
7281
+ introSequence,
7282
+ topOffset = 0,
7283
+ onComplete,
7284
+ language,
7285
+ styles: preResolvedStyles,
7286
+ getIdentityToken
7287
+ }) {
7288
+ const [phase, setPhase] = React3.useState(
7289
+ introSequence && introSequence.length > 0 ? "intro" : "chat"
7290
+ );
7291
+ const [isDismissing, setIsDismissing] = React3.useState(false);
7292
+ const bottomRef = React3.useRef(null);
7293
+ const styles = React3.useMemo(
7294
+ () => preResolvedStyles || mergeWidgetStyles(void 0, void 0),
7295
+ [preResolvedStyles]
7296
+ );
7297
+ const cssVars = React3.useMemo(
7298
+ () => stylesToCssVars(styles),
7299
+ [styles]
7300
+ );
7301
+ const dismiss = React3.useCallback(() => {
7302
+ setIsDismissing(true);
7303
+ setTimeout(() => onComplete(), 400);
7304
+ }, [onComplete]);
7305
+ const handleOnboardingComplete = React3.useCallback(
7306
+ (summary) => {
7307
+ console.log("[Crow] Onboarding complete:", summary);
7308
+ dismiss();
7309
+ },
7310
+ [dismiss]
7311
+ );
7312
+ const chat = useChat({
7313
+ productId,
7314
+ apiUrl,
7315
+ subdomain,
7316
+ welcomeMessage: welcomeMessage || `Hi! I'm ${agentName}. Let me help you get started.`,
7317
+ agentMode: "onboarding",
7318
+ onOnboardingComplete: handleOnboardingComplete,
7319
+ language
7320
+ });
7321
+ React3.useEffect(() => {
7322
+ bottomRef.current?.scrollIntoView({ behavior: "smooth" });
7323
+ }, [chat.messages, chat.isLoading]);
7324
+ const handleSend = React3.useCallback(
7325
+ (content) => {
7326
+ chat.sendMessage(content);
7327
+ },
7328
+ [chat]
7329
+ );
7330
+ const handleStop = React3.useCallback(() => {
7331
+ chat.stopGeneration();
7332
+ }, [chat]);
7333
+ const handleSuggestedActionClick = React3.useCallback(
7334
+ (action) => {
7335
+ chat.sendMessage(action.message);
7336
+ },
7337
+ [chat]
7338
+ );
7339
+ React3.useEffect(() => {
7340
+ const effectiveGetIdentityToken = getIdentityToken || window.__crow_identity_token_fetcher;
7341
+ if (!effectiveGetIdentityToken) return;
7342
+ let cancelled = false;
7343
+ const identify = async () => {
7344
+ try {
7345
+ const token = await effectiveGetIdentityToken();
7346
+ if (!cancelled && token) {
7347
+ window.__crow_identity_token = token;
7348
+ }
7349
+ } catch (e) {
7350
+ console.error("[Crow] Onboarding getIdentityToken failed:", e);
7351
+ }
7352
+ };
7353
+ identify();
7354
+ return () => {
7355
+ cancelled = true;
7356
+ };
7357
+ }, [getIdentityToken]);
7358
+ const renderChat = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%", background: "#ffffff" }, children: [
7359
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
7360
+ display: "flex",
7361
+ alignItems: "center",
7362
+ justifyContent: "space-between",
7363
+ padding: "12px 24px",
7364
+ borderBottom: "1px solid #f3f4f6",
7365
+ flexShrink: 0
7366
+ }, children: [
7367
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [
7368
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
7369
+ width: 28,
7370
+ height: 28,
7371
+ borderRadius: "50%",
7372
+ backgroundColor: styles.colors.primary,
7373
+ display: "flex",
7374
+ alignItems: "center",
7375
+ justifyContent: "center",
7376
+ color: "#fff",
7377
+ fontSize: 13,
7378
+ fontWeight: 600,
7379
+ flexShrink: 0
7380
+ }, children: agentName.charAt(0).toUpperCase() }),
7381
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 14, fontWeight: 600, color: "#111827" }, children: agentName })
7382
+ ] }),
7383
+ /* @__PURE__ */ jsxRuntime.jsx(
7384
+ "button",
7385
+ {
7386
+ onClick: dismiss,
7387
+ style: {
7388
+ fontSize: 13,
7389
+ color: "#9ca3af",
7390
+ background: "none",
7391
+ border: "none",
7392
+ cursor: "pointer",
7393
+ padding: "4px 8px"
7394
+ },
7395
+ children: "Skip"
7396
+ }
7397
+ )
7398
+ ] }),
7399
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflowY: "auto", minHeight: 0 }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "crow-widget-root", style: { ...cssVars, maxWidth: 560, margin: "0 auto", padding: "24px 16px" }, children: [
7400
+ /* @__PURE__ */ jsxRuntime.jsx(
7401
+ WidgetStyleProvider,
7402
+ {
7403
+ styles,
7404
+ agentName,
7405
+ isLoading: false,
7406
+ variant: "embedded",
7407
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7408
+ MessageList,
7409
+ {
7410
+ messages: chat.messages,
7411
+ activeToolCalls: chat.activeToolCalls,
7412
+ isLoadingHistory: false,
7413
+ isGenerating: chat.isLoading
7414
+ }
7415
+ )
7416
+ }
7417
+ ),
7418
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: bottomRef })
7419
+ ] }) }),
7420
+ chat.suggestedActions.length > 0 && !chat.isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-widget-root", style: { ...cssVars, maxWidth: 560, margin: "0 auto", width: "100%", padding: "0 16px 8px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
7421
+ WidgetStyleProvider,
7422
+ {
7423
+ styles,
7424
+ agentName,
7425
+ isLoading: false,
7426
+ variant: "embedded",
7427
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7428
+ SuggestedActions,
7429
+ {
7430
+ actions: chat.suggestedActions,
7431
+ onActionClick: handleSuggestedActionClick
7432
+ }
7433
+ )
7434
+ }
7435
+ ) }),
7436
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { borderTop: "1px solid #f3f4f6", flexShrink: 0 }, children: [
7437
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "crow-widget-root", style: { ...cssVars, maxWidth: 560, margin: "0 auto", padding: "12px 16px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
7438
+ WidgetStyleProvider,
7439
+ {
7440
+ styles,
7441
+ agentName,
7442
+ isLoading: false,
7443
+ variant: "embedded",
7444
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7445
+ PromptInputBox,
7446
+ {
7447
+ onSend: handleSend,
7448
+ onStop: handleStop,
7449
+ placeholder: "Type your message...",
7450
+ isLoading: chat.isLoading
7451
+ }
7452
+ )
7453
+ }
7454
+ ) }),
7455
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", padding: "0 0 10px" }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 11, color: "#d1d5db" }, children: "Powered by Crow" }) })
7456
+ ] })
7457
+ ] });
7458
+ return /* @__PURE__ */ jsxRuntime.jsx(ShadowContainer, { styles: WIDGET_CSS, hostId: "crow-onboarding-host", children: /* @__PURE__ */ jsxRuntime.jsx(
7459
+ framerMotion.motion.div,
7460
+ {
7461
+ style: {
7462
+ position: "fixed",
7463
+ top: topOffset,
7464
+ left: 0,
7465
+ right: 0,
7466
+ bottom: 0,
7467
+ zIndex: 999999,
7468
+ background: "#ffffff",
7469
+ fontFamily: styles.typography.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
7470
+ fontSize: 14
7471
+ },
7472
+ initial: { opacity: 0 },
7473
+ animate: { opacity: isDismissing ? 0 : 1 },
7474
+ transition: { duration: 0.35 },
7475
+ children: phase === "intro" ? /* @__PURE__ */ jsxRuntime.jsx(
7476
+ IntroSequence,
7477
+ {
7478
+ lines: introSequence || [],
7479
+ onComplete: () => setPhase("chat"),
7480
+ onSkip: dismiss,
7481
+ primaryColor: styles.colors.primary
7482
+ }
7483
+ ) : renderChat()
7484
+ }
7485
+ ) });
7486
+ }
6742
7487
  var CrowContext = React3.createContext(null);
6743
7488
  function CrowProvider({
6744
7489
  children,
@@ -6769,6 +7514,7 @@ exports.CopilotContainer = CopilotContainer;
6769
7514
  exports.CopilotStyleProvider = CopilotStyleProvider;
6770
7515
  exports.CopilotToggleButton = CopilotToggleButton;
6771
7516
  exports.CrowCopilot = CrowCopilot;
7517
+ exports.CrowOnboarding = CrowOnboarding;
6772
7518
  exports.CrowProvider = CrowProvider;
6773
7519
  exports.CrowWidget = CrowWidget;
6774
7520
  exports.DEFAULT_COPILOT_STYLES = DEFAULT_COPILOT_STYLES;