research-agent-ui 0.1.69 → 0.1.71

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.mjs CHANGED
@@ -8,7 +8,7 @@ import { clsx as _ } from "clsx";
8
8
  import { twMerge as v } from "tailwind-merge";
9
9
  import y from "markdown-to-jsx";
10
10
  import * as b from "lucide-react";
11
- import { AlertCircle as x, Archive as S, ArrowLeftRight as C, ArrowUp as w, BookMarked as T, Bot as E, BrainCircuit as D, CalendarDays as O, Check as k, CheckIcon as A, ChevronDown as j, ChevronRight as M, ChevronRightIcon as N, ChevronUp as P, Clipboard as F, ClipboardList as I, Clock as L, Cloud as R, CloudIcon as z, Copy as ee, Cpu as te, Download as B, ExternalLink as V, EyeOff as ne, File as re, FileDown as ie, FileSpreadsheet as ae, FileText as oe, FileType as se, FolderOpen as ce, Highlighter as le, History as ue, Link as de, Loader2 as H, Lock as fe, MessageCircleQuestion as pe, Mic as me, Paperclip as he, Pencil as ge, Pin as _e, Plus as ve, Search as ye, Settings as be, Settings2 as xe, Share2 as Se, SlidersHorizontal as Ce, Square as we, SquarePen as Te, Star as Ee, StopCircle as De, Sun as Oe, Trash as ke, Trash2 as Ae, Upload as je, Video as Me, Volume2 as Ne, X as Pe, XIcon as Fe } from "lucide-react";
11
+ import { AlertCircle as x, Archive as S, ArrowLeftRight as C, ArrowUp as w, BookMarked as T, Bot as E, BrainCircuit as D, CalendarDays as O, Check as k, CheckIcon as A, ChevronDown as j, ChevronRight as M, ChevronRightIcon as N, ChevronUp as P, Clipboard as F, ClipboardList as I, Clock as L, Cloud as R, CloudIcon as z, Copy as B, Cpu as ee, Download as te, ExternalLink as V, EyeOff as ne, File as re, FileDown as ie, FileSpreadsheet as ae, FileText as oe, FileType as se, FolderOpen as ce, Highlighter as le, History as ue, Link as de, Loader2 as H, Lock as fe, MessageCircleQuestion as pe, Mic as me, Paperclip as he, Pencil as ge, Pin as _e, Plus as ve, Search as ye, Settings as be, Settings2 as xe, Share2 as Se, SlidersHorizontal as Ce, Square as we, SquarePen as Te, Star as Ee, StopCircle as De, Sun as Oe, Trash as ke, Trash2 as Ae, Upload as je, Video as Me, Volume2 as Ne, X as Pe, XIcon as Fe } from "lucide-react";
12
12
  import { addFavorite as Ie, agentChat as Le, agentSearch as Re, articleFollowups as ze, articleQa as Be, autocomplete as Ve, createDocument as He, deleteAllChats as Ue, deleteChatById as We, getArticle as Ge, getChatById as Ke, getGoogleDriveFile as qe, getGoogleToken as Je, googleDocsAuth as Ye, googleDocsAuthStatus as Xe, listChats as Ze, listFavorites as Qe, listProviders as $e, removeFavorite as et, saveMessage as tt, searchChats as nt, shareChat as rt, updateArticle as it, uploadFiles as at } from "qwksearch-api-client";
13
13
  import { convertURLSafeHTMLToHTML as ot } from "extract-webpage/html-to-content/html-utils";
14
14
  import { AnimatePresence as st, animate as ct, motion as lt } from "motion/react";
@@ -1654,7 +1654,7 @@ function _n(e) {
1654
1654
  let [t, n] = p(e), [r, i] = p(!1), [a, o] = p(!1), [s, c] = p(!1), [l, u] = p(!1), [m, h] = p(!1), [g, _] = p(!1), [v, y] = p(!1), [b, x] = p(!1), [S, C] = p([]), [w, T] = p([]), [E, D] = p([]), [O, k] = p([]), [A, j] = p("webSearch"), [M, N] = p("general"), [P, F] = p("speed"), [I, L] = p({
1655
1655
  key: "",
1656
1656
  providerId: ""
1657
- }), R = f([]), z = d(() => w.filter((e) => e.role === "user" || e.role === "assistant"), [w]), ee = d(() => ln(w), [w]);
1657
+ }), R = f([]), z = d(() => w.filter((e) => e.role === "user" || e.role === "assistant"), [w]), B = d(() => ln(w), [w]);
1658
1658
  return {
1659
1659
  state: {
1660
1660
  chatId: t,
@@ -1696,7 +1696,7 @@ function _n(e) {
1696
1696
  },
1697
1697
  messagesRef: R,
1698
1698
  chatTurns: z,
1699
- sections: ee
1699
+ sections: B
1700
1700
  };
1701
1701
  }
1702
1702
  //#endregion
@@ -2379,7 +2379,7 @@ var $ = {
2379
2379
  className: J("px-3 py-2 flex items-center justify-between text-start duration-200 cursor-pointer transition rounded-xl group", n?.providerId === e.id && n?.key === t.key ? "bg-sky-50 dark:bg-sky-500/10" : "hover:bg-bg-100 dark:hover:bg-[#30302E]"),
2380
2380
  children: [/* @__PURE__ */ G("div", {
2381
2381
  className: "flex items-center space-x-2.5 min-w-0 flex-1",
2382
- children: [/* @__PURE__ */ W(te, {
2382
+ children: [/* @__PURE__ */ W(ee, {
2383
2383
  size: 14,
2384
2384
  className: J("shrink-0", n?.providerId === e.id && n?.key === t.key ? "text-sky-500" : "text-text-400 dark:text-[#999999] group-hover:text-text-300 dark:group-hover:text-[#B4B4B4]")
2385
2385
  }), /* @__PURE__ */ W("p", {
@@ -2577,7 +2577,7 @@ var er = ({ section: e, speechStatus: t, start: n, stop: r, handleOpenInLLM: i }
2577
2577
  asChild: !0,
2578
2578
  children: /* @__PURE__ */ W("button", {
2579
2579
  className: "p-2 text-muted-foreground rounded-full backdrop-blur-md bg-white/10 dark:bg-black/10 hover:bg-white/20 dark:hover:bg-black/20 transition duration-200 hover:text-foreground",
2580
- children: /* @__PURE__ */ W(B, { size: 18 })
2580
+ children: /* @__PURE__ */ W(te, { size: 18 })
2581
2581
  })
2582
2582
  })
2583
2583
  }), /* @__PURE__ */ W(Z, {
@@ -3186,7 +3186,7 @@ var mr = () => window.gapi, hr = () => window.google, gr = () => {
3186
3186
  return /* @__PURE__ */ G(Fn, { children: [/* @__PURE__ */ G(In, {
3187
3187
  className: "gap-2",
3188
3188
  children: [
3189
- /* @__PURE__ */ W(te, { className: "w-4 h-4 flex-shrink-0 text-sky-500" }),
3189
+ /* @__PURE__ */ W(ee, { className: "w-4 h-4 flex-shrink-0 text-sky-500" }),
3190
3190
  /* @__PURE__ */ W("span", { children: "Model" }),
3191
3191
  /* @__PURE__ */ W("span", {
3192
3192
  className: "ml-auto text-xs text-muted-foreground truncate max-w-[55px]",
@@ -3211,7 +3211,7 @@ var mr = () => window.gapi, hr = () => window.google, gr = () => {
3211
3211
  onSelect: () => c(t.id, n.key),
3212
3212
  className: J("gap-2", e?.providerId === t.id && e?.key === n.key && "bg-secondary"),
3213
3213
  children: [
3214
- /* @__PURE__ */ W(te, { className: J("h-3.5 w-3.5 flex-shrink-0", e?.providerId === t.id && e?.key === n.key ? "text-sky-500" : "text-muted-foreground") }),
3214
+ /* @__PURE__ */ W(ee, { className: J("h-3.5 w-3.5 flex-shrink-0", e?.providerId === t.id && e?.key === n.key ? "text-sky-500" : "text-muted-foreground") }),
3215
3215
  /* @__PURE__ */ W("span", {
3216
3216
  className: "truncate",
3217
3217
  children: n.name
@@ -3849,7 +3849,7 @@ var Cr = [
3849
3849
  m((e) => (e.trim() && setTimeout(() => {
3850
3850
  n(e), O();
3851
3851
  }, 0), e));
3852
- }), [M, N] = p(0), [P, F] = p(!0), [I, L] = p(!1), [R, z] = p([]), [ee, te] = p([]), [B, V] = p(-1), [ne, re] = p(!1), [ie, ae] = p("below"), oe = f(!1), se = f(null);
3852
+ }), [M, N] = p(0), [P, F] = p(!0), [I, L] = p(!1), [R, z] = p([]), [B, ee] = p([]), [te, V] = p(-1), [ne, re] = p(!1), [ie, ae] = p("below"), oe = f(!1), se = f(null);
3853
3853
  u(() => {
3854
3854
  if (oe.current) {
3855
3855
  oe.current = !1;
@@ -3857,7 +3857,7 @@ var Cr = [
3857
3857
  }
3858
3858
  let { query: e } = ce(d);
3859
3859
  if (!I || e.length < 2) {
3860
- z([]), te([]), re(!1), V(-1);
3860
+ z([]), ee([]), re(!1), V(-1);
3861
3861
  return;
3862
3862
  }
3863
3863
  let t = setTimeout(async () => {
@@ -3874,7 +3874,7 @@ var Cr = [
3874
3874
  });
3875
3875
  if (r) return;
3876
3876
  let i = Array.isArray(n?.suggestions) ? n.suggestions : [], a = Array.isArray(n?.domains) ? n.domains : [];
3877
- if (z(i), te(a), i.length + a.length > 0) {
3877
+ if (z(i), ee(a), i.length + a.length > 0) {
3878
3878
  if (g.current) {
3879
3879
  let e = g.current.getBoundingClientRect(), t = window.innerHeight - e.bottom, n = e.top;
3880
3880
  t < Math.min(288, (i.length + a.length) * 36) && n > t ? ae("above") : ae("below");
@@ -3902,11 +3902,11 @@ var Cr = [
3902
3902
  }, le = (e) => {
3903
3903
  oe.current = !0;
3904
3904
  let { prefix: t } = ce(d);
3905
- m(t + e), z([]), te([]), re(!1), V(-1), h.current?.focus();
3905
+ m(t + e), z([]), ee([]), re(!1), V(-1), h.current?.focus();
3906
3906
  }, ue = (e) => {
3907
3907
  re(!1), V(-1), window.location.href = `https://${e.domain}`;
3908
- }, de = ee.length + R.length, H = (e) => {
3909
- e < ee.length ? ue(ee[e]) : le(R[e - ee.length]);
3908
+ }, de = B.length + R.length, H = (e) => {
3909
+ e < B.length ? ue(B[e]) : le(R[e - B.length]);
3910
3910
  };
3911
3911
  u(() => {
3912
3912
  if (I || d) return;
@@ -3940,12 +3940,12 @@ var Cr = [
3940
3940
  e.preventDefault(), re(!1), V(-1);
3941
3941
  return;
3942
3942
  }
3943
- if (e.key === "Tab" && B >= 0) {
3944
- e.preventDefault(), H(B);
3943
+ if (e.key === "Tab" && te >= 0) {
3944
+ e.preventDefault(), H(te);
3945
3945
  return;
3946
3946
  }
3947
- if (e.key === "Enter" && !e.shiftKey && B >= 0) {
3948
- e.preventDefault(), H(B);
3947
+ if (e.key === "Enter" && !e.shiftKey && te >= 0) {
3948
+ e.preventDefault(), H(te);
3949
3949
  return;
3950
3950
  }
3951
3951
  let t = parseInt(e.key, 10);
@@ -4136,11 +4136,11 @@ var Cr = [
4136
4136
  onMouseDown: (e) => e.preventDefault(),
4137
4137
  children: /* @__PURE__ */ G("ul", {
4138
4138
  className: "max-h-72 overflow-y-auto custom-scrollbar py-1",
4139
- children: [ee.map((e, t) => /* @__PURE__ */ W("li", { children: /* @__PURE__ */ G("button", {
4139
+ children: [B.map((e, t) => /* @__PURE__ */ W("li", { children: /* @__PURE__ */ G("button", {
4140
4140
  type: "button",
4141
4141
  onMouseEnter: () => V(t),
4142
4142
  onClick: () => ue(e),
4143
- className: `w-full text-left px-4 py-1.5 text-[15px] flex items-center gap-3 transition-colors ${t === B ? "bg-bg-200 text-text-100" : "text-text-200 hover:bg-bg-100 dark:hover:bg-[#3A3A38]"}`,
4143
+ className: `w-full text-left px-4 py-1.5 text-[15px] flex items-center gap-3 transition-colors ${t === te ? "bg-bg-200 text-text-100" : "text-text-200 hover:bg-bg-100 dark:hover:bg-[#3A3A38]"}`,
4144
4144
  children: [
4145
4145
  /* @__PURE__ */ W("span", {
4146
4146
  className: "w-5 h-5 flex items-center justify-center rounded bg-bg-200 dark:bg-[#3A3A38] text-[11px] font-semibold text-text-400 shrink-0",
@@ -4161,12 +4161,12 @@ var Cr = [
4161
4161
  })
4162
4162
  ]
4163
4163
  }) }, `domain-${e.domain}`)), R.map((e, t) => {
4164
- let n = ee.length + t;
4164
+ let n = B.length + t;
4165
4165
  return /* @__PURE__ */ W("li", { children: /* @__PURE__ */ G("button", {
4166
4166
  type: "button",
4167
4167
  onMouseEnter: () => V(n),
4168
4168
  onClick: () => le(e),
4169
- className: `w-full text-left px-4 py-1.5 text-[15px] flex items-center gap-3 transition-colors ${n === B ? "bg-bg-200 text-text-100" : "text-text-200 hover:bg-bg-100 dark:hover:bg-[#3A3A38]"}`,
4169
+ className: `w-full text-left px-4 py-1.5 text-[15px] flex items-center gap-3 transition-colors ${n === te ? "bg-bg-200 text-text-100" : "text-text-200 hover:bg-bg-100 dark:hover:bg-[#3A3A38]"}`,
4170
4170
  children: [
4171
4171
  /* @__PURE__ */ W("span", {
4172
4172
  className: "w-5 h-5 flex items-center justify-center rounded bg-bg-200 dark:bg-[#3A3A38] text-[11px] font-semibold text-text-400 shrink-0",
@@ -4548,7 +4548,7 @@ function Qr({ code: e }) {
4548
4548
  }, [e]),
4549
4549
  className: J("absolute top-3 right-3 p-1.5 rounded-md", "opacity-0 group-hover:opacity-100 transition-opacity duration-150", "bg-zinc-200/80 hover:bg-zinc-300 dark:bg-zinc-700/80 dark:hover:bg-zinc-600", "text-zinc-600 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200", "focus:outline-none focus:ring-1 focus:ring-zinc-400 dark:focus:ring-zinc-500"),
4550
4550
  "aria-label": t ? "Copied!" : "Copy code",
4551
- children: t ? /* @__PURE__ */ W(k, { className: "h-4 w-4 text-green-600 dark:text-green-400" }) : /* @__PURE__ */ W(ee, { className: "h-4 w-4" })
4551
+ children: t ? /* @__PURE__ */ W(k, { className: "h-4 w-4 text-green-600 dark:text-green-400" }) : /* @__PURE__ */ W(B, { className: "h-4 w-4" })
4552
4552
  });
4553
4553
  }
4554
4554
  function $r({ children: e }) {
@@ -4732,113 +4732,113 @@ ei.displayName = "UnifiedMarkdown";
4732
4732
  //#endregion
4733
4733
  //#region src/components/ArticleReader/ArticleExtractPanel.tsx
4734
4734
  var ti = (e) => {
4735
- let { isOpen: n, url: r, searchText: i, panelWidth: a, setPanelWidth: o, closePanel: s } = Tt(), { isAuthenticated: c } = Sn(), l = e.isOpen === void 0 ? n : e.isOpen, d = e.onClose || s, m = e.url || r, h = e.searchText === void 0 ? i : e.searchText, [g, _] = p(null), [v, y] = p([]), [b, x] = p(!1), [S, C] = p(t.defaultSummarizePrompt), [w, T] = p(!1), [E, D] = p(!1), [O, k] = p(!1), [A, j] = p(""), [M, N] = p(""), [P, F] = p([]), [I, L] = p(""), [R, z] = p(!1), [ee, te] = p(!1), [B, V] = p(!1), [ne, re] = p(!1), [ie, ae] = p(a), [oe, se] = p(!1), [ce, le] = p(!1), ue = f(null);
4735
+ let { isOpen: n, url: r, searchText: i, panelWidth: a, setPanelWidth: o, closePanel: s } = Tt(), { isAuthenticated: c } = Sn(), { chatModelProvider: l } = yn(), d = e.isOpen === void 0 ? n : e.isOpen, m = e.onClose || s, h = e.url || r, g = e.searchText === void 0 ? i : e.searchText, [_, v] = p(null), [y, b] = p([]), [x, S] = p(!1), [C, w] = p(t.defaultSummarizePrompt), [T, E] = p(!1), [D, O] = p(!1), [k, A] = p(!1), [j, M] = p(""), [N, P] = p(""), [F, I] = p([]), [L, R] = p(""), [z, B] = p(!1), [ee, te] = p(!1), [V, ne] = p(!1), [re, ie] = p(!1), [ae, oe] = p(a), [se, ce] = p(!1), [le, ue] = p(!1), de = f(null);
4736
4736
  u(() => {
4737
4737
  let e = () => {
4738
- re(window.innerWidth >= 1024);
4738
+ ie(window.innerWidth >= 1024);
4739
4739
  };
4740
4740
  return e(), window.addEventListener("resize", e), () => window.removeEventListener("resize", e);
4741
4741
  }, []), u(() => {
4742
4742
  let e = (e) => {
4743
- if (!oe) return;
4743
+ if (!se) return;
4744
4744
  let t = window.innerWidth - e.clientX, n = Math.max(400, Math.min(t, window.innerWidth - 100));
4745
- ae(n), o(n);
4745
+ oe(n), o(n);
4746
4746
  }, t = () => {
4747
- se(!1);
4747
+ ce(!1);
4748
4748
  };
4749
- return oe && (document.addEventListener("mousemove", e), document.addEventListener("mouseup", t), document.body.style.cursor = "ew-resize", document.body.style.userSelect = "none"), () => {
4749
+ return se && (document.addEventListener("mousemove", e), document.addEventListener("mouseup", t), document.body.style.cursor = "ew-resize", document.body.style.userSelect = "none"), () => {
4750
4750
  document.removeEventListener("mousemove", e), document.removeEventListener("mouseup", t), document.body.style.cursor = "", document.body.style.userSelect = "";
4751
4751
  };
4752
- }, [oe, o]), u(() => {
4753
- l && m ? (le(!1), de()) : l || le(!1);
4754
- }, [l, m]);
4755
- let de = async () => {
4756
- console.log("[ArticleExtractPanel] Extracting URL:", m);
4752
+ }, [se, o]), u(() => {
4753
+ d && h ? (ue(!1), H()) : d || ue(!1);
4754
+ }, [d, h]);
4755
+ let H = async () => {
4756
+ console.log("[ArticleExtractPanel] Extracting URL:", h);
4757
4757
  try {
4758
- let e = new URL(m);
4758
+ let e = new URL(h);
4759
4759
  if ([
4760
4760
  /^https?:\/\/(www\.)?google\.[^/]+\/search/i,
4761
4761
  /^https?:\/\/(www\.)?bing\.com\/search/i,
4762
4762
  /^https?:\/\/(www\.)?duckduckgo\.com\/\?/i
4763
- ].some((e) => e.test(m))) {
4764
- K.error("Cannot extract articles from search result pages"), T(!1), le(!0);
4763
+ ].some((e) => e.test(h))) {
4764
+ K.error("Cannot extract articles from search result pages"), E(!1), ue(!0);
4765
4765
  return;
4766
4766
  }
4767
- (e.pathname === "/" || e.pathname === "") && (console.error("[ArticleExtractPanel] URL is domain-only, missing article path:", m), K.error("Invalid article URL - only domain provided"));
4767
+ (e.pathname === "/" || e.pathname === "") && (console.error("[ArticleExtractPanel] URL is domain-only, missing article path:", h), K.error("Invalid article URL - only domain provided"));
4768
4768
  } catch (e) {
4769
- console.error("[ArticleExtractPanel] Invalid URL format:", m, e);
4769
+ console.error("[ArticleExtractPanel] Invalid URL format:", h, e);
4770
4770
  }
4771
- T(!0);
4771
+ E(!0);
4772
4772
  try {
4773
- let { data: e } = await Ge({ query: { url: m } }), t = e?.article, n = t?.html?.replace(/<[^>]*>/g, "").trim() || "";
4773
+ let { data: e } = await Ge({ query: { url: h } }), t = e?.article, n = t?.html?.replace(/<[^>]*>/g, "").trim() || "";
4774
4774
  t?.error || n.length < 20 ? (document.dispatchEvent(new CustomEvent("onInvokeChromeAPI", { detail: {
4775
4775
  type: "extractURL",
4776
- url: m
4776
+ url: h
4777
4777
  } })), await Promise.race([new Promise((e) => {
4778
4778
  let t = async (n) => {
4779
4779
  window.removeEventListener("onExtractionResult", t);
4780
- let { data: r } = await Ge({ query: { url: m } }), i = r?.article;
4781
- i && (_(i), i.followUpQuestions?.length > 0 && F(i.followUpQuestions)), e();
4780
+ let { data: r } = await Ge({ query: { url: h } }), i = r?.article;
4781
+ i && (v(i), i.followUpQuestions?.length > 0 && I(i.followUpQuestions)), e();
4782
4782
  };
4783
4783
  window.addEventListener("onExtractionResult", t);
4784
- }), new Promise((e) => setTimeout(e, 1e4))])) : (_(t), t?.followUpQuestions && t.followUpQuestions.length > 0 && F(t.followUpQuestions)), c && H();
4784
+ }), new Promise((e) => setTimeout(e, 1e4))])) : (v(t), t?.followUpQuestions && t.followUpQuestions.length > 0 && I(t.followUpQuestions)), c && fe();
4785
4785
  } catch (e) {
4786
4786
  console.error("[ArticleExtractPanel] Error extracting URL:", e), K.error("Failed to load article");
4787
4787
  } finally {
4788
- T(!1), le(!0);
4788
+ E(!1), ue(!0);
4789
4789
  }
4790
- }, H = async () => {
4790
+ }, fe = async () => {
4791
4791
  try {
4792
- let { data: e } = await Qe(), t = e?.favorites?.some((e) => e.url === m);
4793
- z(!!t);
4792
+ let { data: e } = await Qe(), t = e?.favorites?.some((e) => e.url === h);
4793
+ B(!!t);
4794
4794
  } catch (e) {
4795
4795
  console.error("Error checking favorite status:", e);
4796
4796
  }
4797
- }, fe = async () => {
4798
- if (g) {
4797
+ }, pe = async () => {
4798
+ if (_) {
4799
4799
  te(!0);
4800
4800
  try {
4801
- R ? (await et({ query: { url: m } }), z(!1), K.info("Removed from favorites")) : (await Ie({ body: {
4802
- url: g.url || m,
4803
- title: g.title,
4804
- cite: g.cite,
4805
- author: g.author,
4806
- author_cite: g.author_cite,
4807
- date: g.date,
4808
- source: g.source,
4809
- word_count: g.word_count,
4810
- html: g.html
4811
- } }), z(!0), K.success("Added to favorites"));
4801
+ z ? (await et({ query: { url: h } }), B(!1), K.info("Removed from favorites")) : (await Ie({ body: {
4802
+ url: _.url || h,
4803
+ title: _.title,
4804
+ cite: _.cite,
4805
+ author: _.author,
4806
+ author_cite: _.author_cite,
4807
+ date: _.date,
4808
+ source: _.source,
4809
+ word_count: _.word_count,
4810
+ html: _.html
4811
+ } }), B(!0), K.success("Added to favorites"));
4812
4812
  } catch (e) {
4813
4813
  console.error("Error toggling favorite:", e), K.error("Failed to toggle favorite");
4814
4814
  } finally {
4815
4815
  te(!1);
4816
4816
  }
4817
4817
  }
4818
- }, pe = async (e) => {
4819
- if (!g) return;
4820
- let n = g.html?.replace(/<[^>]*>?/g, "").slice(0, t.maxArticleLength), r = e === "question", i = r ? D : k, a = r ? N : L;
4818
+ }, me = async (e) => {
4819
+ if (!_) return;
4820
+ let n = _.html?.replace(/<[^>]*>?/g, "").slice(0, t.maxArticleLength), r = e === "question", i = r ? O : A, a = r ? P : R;
4821
4821
  i(!0), a("");
4822
4822
  try {
4823
4823
  if (r) {
4824
- let e = [h, S].filter(Boolean).join("\n");
4824
+ let e = [g, C].filter(Boolean).join("\n");
4825
4825
  if (!n || n.length === 0) throw Error("Article content is empty");
4826
4826
  let { data: t, error: r } = await Be({ body: {
4827
4827
  article: n,
4828
4828
  question: e,
4829
- chatHistory: v.slice(-5),
4830
- provider: "groq"
4829
+ chatHistory: y.slice(-5),
4830
+ chatModel: l
4831
4831
  } });
4832
4832
  if (r) {
4833
4833
  let e = r.error || r.message || "Article QA failed";
4834
4834
  throw Error(e);
4835
4835
  }
4836
4836
  let i = t?.content || "";
4837
- j(i), y((e) => [
4837
+ M(i), b((e) => [
4838
4838
  ...e,
4839
4839
  {
4840
4840
  role: "user",
4841
- content: S,
4841
+ content: C,
4842
4842
  time: (/* @__PURE__ */ new Date()).toISOString()
4843
4843
  },
4844
4844
  {
@@ -4849,8 +4849,8 @@ var ti = (e) => {
4849
4849
  ]);
4850
4850
  try {
4851
4851
  await it({ body: {
4852
- url: m,
4853
- question: S,
4852
+ url: h,
4853
+ question: C,
4854
4854
  answer: i
4855
4855
  } });
4856
4856
  } catch (e) {
@@ -4861,19 +4861,19 @@ var ti = (e) => {
4861
4861
  if (!n || n.length === 0) throw Error("Article content is empty");
4862
4862
  let { data: t, error: r } = await ze({ body: {
4863
4863
  article: n,
4864
- chatHistory: v.slice(-5),
4864
+ chatHistory: y.slice(-5),
4865
4865
  maxQuestions: e,
4866
- provider: "groq"
4866
+ chatModel: l
4867
4867
  } });
4868
4868
  if (r) {
4869
4869
  let e = r.error || r.message || "Article followups failed";
4870
4870
  throw Error(e);
4871
4871
  }
4872
4872
  let i = t?.extract || [];
4873
- F(i);
4873
+ I(i);
4874
4874
  try {
4875
4875
  await it({ body: {
4876
- url: m,
4876
+ url: h,
4877
4877
  followUpQuestions: i
4878
4878
  } });
4879
4879
  } catch (e) {
@@ -4885,17 +4885,17 @@ var ti = (e) => {
4885
4885
  } finally {
4886
4886
  i(!1);
4887
4887
  }
4888
- }, me = (e) => {
4889
- C(e), pe("question");
4890
- }, he = async () => {
4891
- if (!g) return;
4892
- let e = `${A}\n\n\n${g.cite || ""}\n\n\n${g.html}`;
4888
+ }, he = (e) => {
4889
+ w(e), me("question");
4890
+ }, ge = async () => {
4891
+ if (!_) return;
4892
+ let e = `${j}\n\n\n${_.cite || ""}\n\n\n${_.html}`;
4893
4893
  try {
4894
- await navigator.clipboard.writeText(e), x(!0), setTimeout(() => x(!1), 2e3);
4894
+ await navigator.clipboard.writeText(e), S(!0), setTimeout(() => S(!1), 2e3);
4895
4895
  } catch (e) {
4896
4896
  console.error("Failed to copy to clipboard:", e);
4897
4897
  }
4898
- }, ge = () => /* @__PURE__ */ W("div", {
4898
+ }, _e = () => /* @__PURE__ */ W("div", {
4899
4899
  className: "flex h-full flex-col bg-background shadow-xl",
4900
4900
  children: /* @__PURE__ */ W("div", {
4901
4901
  className: "flex-1 overflow-y-auto",
@@ -4905,37 +4905,37 @@ var ti = (e) => {
4905
4905
  className: "space-y-4",
4906
4906
  children: [
4907
4907
  /* @__PURE__ */ W(zr, {
4908
- isLoadingAI: E,
4909
- isLoadingFollowups: O,
4908
+ isLoadingAI: D,
4909
+ isLoadingFollowups: k,
4910
4910
  isLoadingFavorite: ee,
4911
- isFavorited: R,
4912
- isHighlightMode: B,
4913
- articleUrl: g?.url || m,
4914
- onAskClick: () => pe("question"),
4915
- onSuggestClick: () => pe("suggest-followups"),
4916
- onCopyClick: he,
4917
- onFavoriteClick: fe,
4918
- onHighlightToggle: () => V(!B),
4919
- onClose: d
4911
+ isFavorited: z,
4912
+ isHighlightMode: V,
4913
+ articleUrl: _?.url || h,
4914
+ onAskClick: () => me("question"),
4915
+ onSuggestClick: () => me("suggest-followups"),
4916
+ onCopyClick: ge,
4917
+ onFavoriteClick: pe,
4918
+ onHighlightToggle: () => ne(!V),
4919
+ onClose: m
4920
4920
  }),
4921
- b && /* @__PURE__ */ W("div", {
4921
+ x && /* @__PURE__ */ W("div", {
4922
4922
  className: "bg-blue-500 text-white text-sm font-medium px-3 py-2 rounded-md shadow-lg",
4923
4923
  children: "Copied!"
4924
4924
  }),
4925
4925
  /* @__PURE__ */ W(Br, {
4926
- value: S,
4927
- onChange: C,
4928
- onSubmit: () => pe("question")
4926
+ value: C,
4927
+ onChange: w,
4928
+ onSubmit: () => me("question")
4929
4929
  }),
4930
4930
  /* @__PURE__ */ W(Vr, {
4931
- questions: P,
4932
- isLoading: O,
4933
- error: I,
4934
- onQuestionClick: me
4931
+ questions: F,
4932
+ isLoading: k,
4933
+ error: L,
4934
+ onQuestionClick: he
4935
4935
  }),
4936
- v.length > 0 && /* @__PURE__ */ W("div", {
4936
+ y.length > 0 && /* @__PURE__ */ W("div", {
4937
4937
  className: "space-y-4",
4938
- children: v.map((e, t) => /* @__PURE__ */ W("div", {
4938
+ children: y.map((e, t) => /* @__PURE__ */ W("div", {
4939
4939
  className: "space-y-2",
4940
4940
  children: e.role === "user" ? /* @__PURE__ */ G("div", {
4941
4941
  className: "bg-primary/10 border border-primary/20 rounded-lg p-3",
@@ -4958,42 +4958,42 @@ var ti = (e) => {
4958
4958
  })
4959
4959
  }, t))
4960
4960
  }),
4961
- (E || A && v.length === 0) && /* @__PURE__ */ W(Hr, {
4962
- response: A,
4963
- isLoading: E,
4964
- error: M
4961
+ (D || j && y.length === 0) && /* @__PURE__ */ W(Hr, {
4962
+ response: j,
4963
+ isLoading: D,
4964
+ error: N
4965
4965
  }),
4966
- M && !E && /* @__PURE__ */ W("div", {
4966
+ N && !D && /* @__PURE__ */ W("div", {
4967
4967
  className: "bg-red-500 text-white p-2 rounded-md text-sm",
4968
- children: M
4968
+ children: N
4969
4969
  })
4970
4970
  ]
4971
- }), g && /* @__PURE__ */ W(Wr, {
4972
- article: g,
4973
- isHighlightMode: B
4971
+ }), _ && /* @__PURE__ */ W(Wr, {
4972
+ article: _,
4973
+ isHighlightMode: V
4974
4974
  })]
4975
4975
  })
4976
4976
  })
4977
4977
  });
4978
- return !l || !ce ? null : ne ? /* @__PURE__ */ G("div", {
4978
+ return !d || !le ? null : re ? /* @__PURE__ */ G("div", {
4979
4979
  className: "fixed top-0 right-0 h-screen z-40 transition-all duration-300",
4980
- style: { width: `${ie}px` },
4980
+ style: { width: `${ae}px` },
4981
4981
  children: [/* @__PURE__ */ W("div", {
4982
- ref: ue,
4983
- onMouseDown: () => se(!0),
4982
+ ref: de,
4983
+ onMouseDown: () => ce(!0),
4984
4984
  className: "absolute left-0 top-0 bottom-0 w-1 cursor-ew-resize hover:bg-primary bg-transparent transition-colors z-50",
4985
4985
  style: { touchAction: "none" },
4986
4986
  children: /* @__PURE__ */ W("div", { className: "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-1 h-12 rounded-full bg-muted-foreground opacity-50 hover:opacity-100 transition-opacity" })
4987
- }), ge()]
4987
+ }), _e()]
4988
4988
  }) : /* @__PURE__ */ W(Dr, {
4989
- open: l,
4990
- onOpenChange: (e) => !e && d(),
4989
+ open: d,
4990
+ onOpenChange: (e) => !e && m(),
4991
4991
  children: /* @__PURE__ */ G(jr, {
4992
4992
  className: "pointer-events-auto fixed inset-0 !top-0 !left-0 !translate-x-0 !translate-y-0 h-full w-full max-w-none p-0 m-0 rounded-none border-0 overflow-hidden data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right",
4993
4993
  hideCloseButton: !0,
4994
4994
  children: [/* @__PURE__ */ W(Pr, { children: /* @__PURE__ */ W(Mr, { children: "Article Details" }) }), /* @__PURE__ */ W("div", {
4995
4995
  className: "h-full overflow-y-auto",
4996
- children: ge()
4996
+ children: _e()
4997
4997
  })]
4998
4998
  })
4999
4999
  });
@@ -5967,7 +5967,7 @@ function wi({ preloadOnMount: e = !1 }) {
5967
5967
  children: d ? /* @__PURE__ */ W(H, {
5968
5968
  size: 18,
5969
5969
  className: "animate-spin"
5970
- }) : /* @__PURE__ */ W(B, { size: 18 })
5970
+ }) : /* @__PURE__ */ W(te, { size: 18 })
5971
5971
  })
5972
5972
  }), /* @__PURE__ */ W(Z, {
5973
5973
  side: "bottom",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "research-agent-ui",
3
3
  "description": "Chat research agent UI: conversation window, article reader, search config, file uploads, and chat history",
4
- "version": "0.1.69",
4
+ "version": "0.1.71",
5
5
  "author": "vtempest",
6
6
  "repository": {
7
7
  "type": "git",
@@ -63,19 +63,19 @@
63
63
  "@radix-ui/react-slot": "^1.2.5",
64
64
  "@radix-ui/react-tooltip": "^1.2.9",
65
65
  "@ricky0123/vad-web": "^0.0.30",
66
- "chat-agent-toolkit": "^1.2.91",
67
- "domain-rank": "^0.1.80",
66
+ "chat-agent-toolkit": "^1.2.94",
67
+ "domain-rank": "^0.1.83",
68
68
  "drizzle-orm": "^0.45.2",
69
69
  "fuse.js": "^7.1.0",
70
70
  "class-variance-authority": "^0.7.1",
71
71
  "clsx": "^2.1.1",
72
72
  "dompurify": "^3.4.9",
73
- "extract-webpage": "^1.2.92",
74
- "search-web-api": "^1.0.51",
73
+ "extract-webpage": "^1.2.95",
74
+ "search-web-api": "^1.0.53",
75
75
  "framer-motion": "^12.40.0",
76
76
  "grab-url": "^1.6.22",
77
77
  "kokoro-js": "^1.2.1",
78
- "qwksearch-api-client": "^0.9.40",
78
+ "qwksearch-api-client": "^0.9.42",
79
79
  "html2canvas": "^1.4.1",
80
80
  "lucide-react": "^1.17.0",
81
81
  "markdown-to-jsx": "^9.8.2",