@firstlovecenter/ai-chat 0.2.1 → 0.2.3
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/CHANGELOG.md +23 -0
- package/dist/server/index.cjs +38 -0
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +38 -0
- package/dist/server/index.js.map +1 -1
- package/dist/ui/index.cjs +57 -5
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.js +57 -5
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
package/dist/ui/index.js
CHANGED
|
@@ -381,8 +381,22 @@ function sanitiseBlock(input) {
|
|
|
381
381
|
}
|
|
382
382
|
return { kind: "callout", tone: input.tone, text: input.text };
|
|
383
383
|
}
|
|
384
|
+
function isBlockEmpty(b) {
|
|
385
|
+
if (b.kind === "paragraph_brief") {
|
|
386
|
+
if (b.prose && b.prose.trim()) return false;
|
|
387
|
+
return b.key_facts.length === 0 || b.key_facts.every((f) => !f.trim());
|
|
388
|
+
}
|
|
389
|
+
if (b.kind === "list") {
|
|
390
|
+
return b.items.length === 0 || b.items.every((i) => !i.trim());
|
|
391
|
+
}
|
|
392
|
+
if (b.kind === "callout") return !b.text.trim();
|
|
393
|
+
if (b.kind === "chart") return b.data.length === 0;
|
|
394
|
+
if (b.kind === "table") return b.rows.length === 0;
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
384
397
|
function AnswerBlocks({ blocks }) {
|
|
385
|
-
|
|
398
|
+
const visible = blocks.filter((b) => !isBlockEmpty(b));
|
|
399
|
+
return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: visible.map((b, i) => /* @__PURE__ */ jsx(BlockView, { block: b }, i)) });
|
|
386
400
|
}
|
|
387
401
|
function BlockView({ block }) {
|
|
388
402
|
if (block.kind === "paragraph_brief") {
|
|
@@ -523,6 +537,14 @@ function AiLineChart({
|
|
|
523
537
|
))
|
|
524
538
|
] }) }) });
|
|
525
539
|
}
|
|
540
|
+
function formatDuration(ms) {
|
|
541
|
+
if (ms < 0) ms = 0;
|
|
542
|
+
const totalSec = Math.round(ms / 1e3);
|
|
543
|
+
if (totalSec < 60) return `${totalSec}s`;
|
|
544
|
+
const m = Math.floor(totalSec / 60);
|
|
545
|
+
const s = totalSec % 60;
|
|
546
|
+
return s === 0 ? `${m}m` : `${m}m ${s}s`;
|
|
547
|
+
}
|
|
526
548
|
var PROVIDER_LABELS = {
|
|
527
549
|
claude: "Claude",
|
|
528
550
|
grok: "Grok",
|
|
@@ -697,7 +719,7 @@ function AiChat({
|
|
|
697
719
|
}
|
|
698
720
|
setAnswers((prev) => [
|
|
699
721
|
...prev,
|
|
700
|
-
{ question: trimmed, blocks: [], done: false }
|
|
722
|
+
{ question: trimmed, blocks: [], done: false, startedAt: Date.now() }
|
|
701
723
|
]);
|
|
702
724
|
const ac = new AbortController();
|
|
703
725
|
abortRef.current = ac;
|
|
@@ -718,6 +740,7 @@ function AiChat({
|
|
|
718
740
|
(prev) => updateLast(prev, (a) => ({
|
|
719
741
|
...a,
|
|
720
742
|
done: true,
|
|
743
|
+
durationMs: a.startedAt != null ? Date.now() - a.startedAt : void 0,
|
|
721
744
|
error: { code: "NETWORK", message }
|
|
722
745
|
}))
|
|
723
746
|
);
|
|
@@ -729,6 +752,7 @@ function AiChat({
|
|
|
729
752
|
(prev) => updateLast(prev, (a) => ({
|
|
730
753
|
...a,
|
|
731
754
|
done: true,
|
|
755
|
+
durationMs: a.startedAt != null ? Date.now() - a.startedAt : void 0,
|
|
732
756
|
error: { code: "NO_BODY", message: "No response stream." }
|
|
733
757
|
}))
|
|
734
758
|
);
|
|
@@ -755,6 +779,7 @@ function AiChat({
|
|
|
755
779
|
(prev) => updateLast(prev, (a) => ({
|
|
756
780
|
...a,
|
|
757
781
|
done: true,
|
|
782
|
+
durationMs: a.startedAt != null ? Date.now() - a.startedAt : void 0,
|
|
758
783
|
error: { code: "STREAM", message }
|
|
759
784
|
}))
|
|
760
785
|
);
|
|
@@ -787,7 +812,7 @@ function AiChat({
|
|
|
787
812
|
/* @__PURE__ */ jsxs(
|
|
788
813
|
"aside",
|
|
789
814
|
{
|
|
790
|
-
|
|
815
|
+
inert: !sidebarOpen,
|
|
791
816
|
className: cn(
|
|
792
817
|
"absolute inset-y-0 left-0 z-20 flex w-72 max-w-[85vw] flex-col border-r border-border bg-sidebar text-sidebar-foreground shadow-lg transition-transform duration-200 ease-out",
|
|
793
818
|
sidebarOpen ? "translate-x-0" : "-translate-x-full"
|
|
@@ -1053,6 +1078,14 @@ function AnswerView({
|
|
|
1053
1078
|
}, [answer.blocks, answer.error]);
|
|
1054
1079
|
const showActions = answer.done && (answer.blocks.length > 0 || answer.error != null);
|
|
1055
1080
|
const isThinking = !answer.done && answer.blocks.length === 0 && !answer.error;
|
|
1081
|
+
const [, forceTick] = useState(0);
|
|
1082
|
+
useEffect(() => {
|
|
1083
|
+
if (answer.done || answer.startedAt == null) return;
|
|
1084
|
+
const id = window.setInterval(() => forceTick((n) => n + 1), 1e3);
|
|
1085
|
+
return () => window.clearInterval(id);
|
|
1086
|
+
}, [answer.done, answer.startedAt]);
|
|
1087
|
+
const liveElapsed = answer.startedAt != null ? Date.now() - answer.startedAt : null;
|
|
1088
|
+
const finalDuration = answer.durationMs;
|
|
1056
1089
|
return /* @__PURE__ */ jsxs(
|
|
1057
1090
|
"div",
|
|
1058
1091
|
{
|
|
@@ -1071,7 +1104,12 @@ function AnswerView({
|
|
|
1071
1104
|
/* @__PURE__ */ jsx("div", { className: "flex size-7 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Sparkles, { className: "size-4" }) }),
|
|
1072
1105
|
/* @__PURE__ */ jsxs("p", { className: "flex items-center text-sm text-muted-foreground", children: [
|
|
1073
1106
|
/* @__PURE__ */ jsx(Loader2, { className: "mr-1 inline size-3.5 animate-spin" }),
|
|
1074
|
-
"Thinking\u2026"
|
|
1107
|
+
"Thinking\u2026",
|
|
1108
|
+
liveElapsed != null && liveElapsed >= 1e3 && /* @__PURE__ */ jsxs("span", { className: "ml-2 text-xs tabular-nums", children: [
|
|
1109
|
+
"(",
|
|
1110
|
+
formatDuration(liveElapsed),
|
|
1111
|
+
")"
|
|
1112
|
+
] })
|
|
1075
1113
|
] })
|
|
1076
1114
|
] }) : /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
1077
1115
|
/* @__PURE__ */ jsx("div", { className: "mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Sparkles, { className: "size-4" }) }),
|
|
@@ -1104,6 +1142,14 @@ function AnswerView({
|
|
|
1104
1142
|
className: "inline-flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
1105
1143
|
children: /* @__PURE__ */ jsx(RotateCcw, { className: "size-4" })
|
|
1106
1144
|
}
|
|
1145
|
+
),
|
|
1146
|
+
finalDuration != null && finalDuration >= 1e3 && /* @__PURE__ */ jsx(
|
|
1147
|
+
"span",
|
|
1148
|
+
{
|
|
1149
|
+
className: "ml-1 text-xs text-muted-foreground tabular-nums",
|
|
1150
|
+
title: "Time taken to generate this response",
|
|
1151
|
+
children: formatDuration(finalDuration)
|
|
1152
|
+
}
|
|
1107
1153
|
)
|
|
1108
1154
|
] })
|
|
1109
1155
|
] })
|
|
@@ -1309,7 +1355,13 @@ function handleEvent(raw, setAnswers) {
|
|
|
1309
1355
|
})
|
|
1310
1356
|
);
|
|
1311
1357
|
} else if (event === "done") {
|
|
1312
|
-
setAnswers(
|
|
1358
|
+
setAnswers(
|
|
1359
|
+
(prev) => updateLast(prev, (a) => ({
|
|
1360
|
+
...a,
|
|
1361
|
+
done: true,
|
|
1362
|
+
durationMs: a.startedAt != null ? Date.now() - a.startedAt : void 0
|
|
1363
|
+
}))
|
|
1364
|
+
);
|
|
1313
1365
|
} else if (event === "error") {
|
|
1314
1366
|
setAnswers(
|
|
1315
1367
|
(prev) => updateLast(prev, (a) => ({
|