@firstlovecenter/ai-chat 0.5.0 → 0.6.1

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/ui/index.js CHANGED
@@ -468,17 +468,22 @@ function sanitiseBlock(input) {
468
468
  }
469
469
  return { kind: "callout", tone: input.tone, text: input.text };
470
470
  }
471
+ function isBlankString(v) {
472
+ return typeof v !== "string" || !v.trim();
473
+ }
471
474
  function isBlockEmpty(b) {
472
475
  if (b.kind === "paragraph_brief") {
473
- if (b.prose && b.prose.trim()) return false;
474
- return b.key_facts.length === 0 || b.key_facts.every((f) => !f.trim());
476
+ if (typeof b.prose === "string" && b.prose.trim()) return false;
477
+ const facts = Array.isArray(b.key_facts) ? b.key_facts : [];
478
+ return facts.length === 0 || facts.every(isBlankString);
475
479
  }
476
480
  if (b.kind === "list") {
477
- return b.items.length === 0 || b.items.every((i) => !i.trim());
481
+ const items = Array.isArray(b.items) ? b.items : [];
482
+ return items.length === 0 || items.every(isBlankString);
478
483
  }
479
- if (b.kind === "callout") return !b.text.trim();
480
- if (b.kind === "chart") return b.data.length === 0;
481
- if (b.kind === "table") return b.rows.length === 0;
484
+ if (b.kind === "callout") return isBlankString(b.text);
485
+ if (b.kind === "chart") return !Array.isArray(b.data) || b.data.length === 0;
486
+ if (b.kind === "table") return !Array.isArray(b.rows) || b.rows.length === 0;
482
487
  return false;
483
488
  }
484
489
  function AnswerBlocks({ blocks }) {
@@ -663,6 +668,7 @@ function AiChat({
663
668
  const textareaRef = useRef(null);
664
669
  const lastAnswerRef = useRef(null);
665
670
  const prevAnswersLen = useRef(0);
671
+ const autoOpenedRef = useRef(false);
666
672
  useLayoutEffect(() => {
667
673
  const el = textareaRef.current;
668
674
  if (!el) return;
@@ -677,7 +683,34 @@ function AiChat({
677
683
  const res = await fetch("/api/chat/sessions", { cache: "no-store" });
678
684
  if (!res.ok) return;
679
685
  const data = await res.json();
680
- if (!cancelled) setSessions(data.sessions ?? []);
686
+ if (cancelled) return;
687
+ const list = data.sessions ?? [];
688
+ setSessions(list);
689
+ if (!autoOpenedRef.current && list.length > 0) {
690
+ autoOpenedRef.current = true;
691
+ const mostRecentId = list[0].id;
692
+ setLoadingSession(true);
693
+ setActiveSessionId(mostRecentId);
694
+ try {
695
+ const sres = await fetch(`/api/chat/sessions/${mostRecentId}`, {
696
+ cache: "no-store"
697
+ });
698
+ if (cancelled) return;
699
+ if (!sres.ok) {
700
+ setAnswers([]);
701
+ return;
702
+ }
703
+ const sdata = await sres.json();
704
+ if (cancelled) return;
705
+ setAnswers(messagesToAnswers(sdata.messages ?? []));
706
+ } catch {
707
+ if (!cancelled) setAnswers([]);
708
+ } finally {
709
+ if (!cancelled) setLoadingSession(false);
710
+ }
711
+ } else if (!autoOpenedRef.current) {
712
+ autoOpenedRef.current = true;
713
+ }
681
714
  } catch {
682
715
  }
683
716
  }
@@ -1454,6 +1487,7 @@ function VercelChat({
1454
1487
  const textareaRef = useRef(null);
1455
1488
  const lastAnswerRef = useRef(null);
1456
1489
  const prevAnswersLen = useRef(0);
1490
+ const autoOpenedRef = useRef(false);
1457
1491
  const activeSessionIdRef = useRef(activeSessionId);
1458
1492
  const providerRef = useRef(provider);
1459
1493
  useEffect(() => {
@@ -1508,7 +1542,49 @@ function VercelChat({
1508
1542
  const res = await fetch("/api/chat/sessions", { cache: "no-store" });
1509
1543
  if (!res.ok) return;
1510
1544
  const json = await res.json();
1511
- if (!cancelled) setSessions(json.sessions ?? []);
1545
+ if (cancelled) return;
1546
+ const list = json.sessions ?? [];
1547
+ setSessions(list);
1548
+ if (!autoOpenedRef.current && list.length > 0) {
1549
+ autoOpenedRef.current = true;
1550
+ const mostRecentId = list[0].id;
1551
+ setLoadingSession(true);
1552
+ setActiveSessionId(mostRecentId);
1553
+ try {
1554
+ const sres = await fetch(`/api/chat/sessions/${mostRecentId}`, {
1555
+ cache: "no-store"
1556
+ });
1557
+ if (cancelled) return;
1558
+ if (!sres.ok) {
1559
+ setMessages([]);
1560
+ setHydratedBlocks({});
1561
+ setHydratedProse({});
1562
+ setHydratedErrors({});
1563
+ return;
1564
+ }
1565
+ const sjson = await sres.json();
1566
+ if (cancelled) return;
1567
+ const { uiMessages, blocksMap, proseMap, errorsMap } = storedToUseChat(
1568
+ sjson.messages ?? []
1569
+ );
1570
+ setMessages(uiMessages);
1571
+ setHydratedBlocks(blocksMap);
1572
+ setHydratedProse(proseMap);
1573
+ setHydratedErrors(errorsMap);
1574
+ setStartedAt({});
1575
+ } catch {
1576
+ if (!cancelled) {
1577
+ setMessages([]);
1578
+ setHydratedBlocks({});
1579
+ setHydratedProse({});
1580
+ setHydratedErrors({});
1581
+ }
1582
+ } finally {
1583
+ if (!cancelled) setLoadingSession(false);
1584
+ }
1585
+ } else if (!autoOpenedRef.current) {
1586
+ autoOpenedRef.current = true;
1587
+ }
1512
1588
  } catch {
1513
1589
  }
1514
1590
  }
@@ -1516,7 +1592,7 @@ function VercelChat({
1516
1592
  return () => {
1517
1593
  cancelled = true;
1518
1594
  };
1519
- }, []);
1595
+ }, [setMessages]);
1520
1596
  const answers = useMemo(() => {
1521
1597
  const liveBlocks = [];
1522
1598
  const liveErrors = [];