@arbidocs/react 0.3.103 → 0.3.105
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 +773 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +245 -3
- package/dist/index.d.ts +245 -3
- package/dist/index.js +752 -3
- package/dist/index.js.map +1 -1
- package/package.json +8 -3
package/dist/index.cjs
CHANGED
|
@@ -11,11 +11,18 @@ var AvatarPrimitive = require('@radix-ui/react-avatar');
|
|
|
11
11
|
var classVarianceAuthority = require('class-variance-authority');
|
|
12
12
|
var reactSlot = require('@radix-ui/react-slot');
|
|
13
13
|
var HoverCardPrimitive = require('@radix-ui/react-hover-card');
|
|
14
|
+
var diff = require('diff');
|
|
15
|
+
var ReactMarkdown = require('react-markdown');
|
|
16
|
+
var remarkGfm = require('remark-gfm');
|
|
17
|
+
var rehypeRaw = require('rehype-raw');
|
|
14
18
|
var lucideReact = require('lucide-react');
|
|
19
|
+
var framerMotion = require('framer-motion');
|
|
15
20
|
var agGridReact = require('ag-grid-react');
|
|
16
21
|
var agGridCommunity = require('ag-grid-community');
|
|
17
22
|
var zustand = require('zustand');
|
|
18
23
|
|
|
24
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
25
|
+
|
|
19
26
|
function _interopNamespace(e) {
|
|
20
27
|
if (e && e.__esModule) return e;
|
|
21
28
|
var n = Object.create(null);
|
|
@@ -37,6 +44,9 @@ function _interopNamespace(e) {
|
|
|
37
44
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
38
45
|
var AvatarPrimitive__namespace = /*#__PURE__*/_interopNamespace(AvatarPrimitive);
|
|
39
46
|
var HoverCardPrimitive__namespace = /*#__PURE__*/_interopNamespace(HoverCardPrimitive);
|
|
47
|
+
var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
|
|
48
|
+
var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
|
|
49
|
+
var rehypeRaw__default = /*#__PURE__*/_interopDefault(rehypeRaw);
|
|
40
50
|
|
|
41
51
|
// src/ArbiProvider.tsx
|
|
42
52
|
var ArbiContext = React.createContext(null);
|
|
@@ -1414,6 +1424,7 @@ var badgeVariants = classVarianceAuthority.cva(
|
|
|
1414
1424
|
variants: {
|
|
1415
1425
|
variant: {
|
|
1416
1426
|
default: "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
|
1427
|
+
accent: "border-transparent bg-ai-accent-soft text-ai-accent",
|
|
1417
1428
|
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
1418
1429
|
destructive: "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
|
1419
1430
|
outline: "text-foreground"
|
|
@@ -1433,6 +1444,7 @@ var buttonVariants = classVarianceAuthority.cva(
|
|
|
1433
1444
|
variants: {
|
|
1434
1445
|
variant: {
|
|
1435
1446
|
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
|
1447
|
+
accent: "bg-ai-accent text-ai-accent-foreground shadow hover:bg-ai-accent/90",
|
|
1436
1448
|
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
|
1437
1449
|
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
1438
1450
|
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
@@ -1475,6 +1487,748 @@ var HoverCardContent = React__namespace.forwardRef(({ className, align = "center
|
|
|
1475
1487
|
}
|
|
1476
1488
|
) }));
|
|
1477
1489
|
HoverCardContent.displayName = HoverCardPrimitive__namespace.Content.displayName;
|
|
1490
|
+
function Card({ className, ...props }) {
|
|
1491
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1492
|
+
"div",
|
|
1493
|
+
{
|
|
1494
|
+
"data-slot": "card",
|
|
1495
|
+
className: cn(
|
|
1496
|
+
"rounded-xl border border-border bg-card text-card-foreground shadow-sm",
|
|
1497
|
+
className
|
|
1498
|
+
),
|
|
1499
|
+
...props
|
|
1500
|
+
}
|
|
1501
|
+
);
|
|
1502
|
+
}
|
|
1503
|
+
function CardHeader({ className, ...props }) {
|
|
1504
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1505
|
+
"div",
|
|
1506
|
+
{
|
|
1507
|
+
"data-slot": "card-header",
|
|
1508
|
+
className: cn("flex flex-col gap-1.5 p-6", className),
|
|
1509
|
+
...props
|
|
1510
|
+
}
|
|
1511
|
+
);
|
|
1512
|
+
}
|
|
1513
|
+
function CardTitle({ className, ...props }) {
|
|
1514
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1515
|
+
"div",
|
|
1516
|
+
{
|
|
1517
|
+
"data-slot": "card-title",
|
|
1518
|
+
className: cn("text-lg font-semibold leading-none tracking-tight", className),
|
|
1519
|
+
...props
|
|
1520
|
+
}
|
|
1521
|
+
);
|
|
1522
|
+
}
|
|
1523
|
+
function CardDescription({ className, ...props }) {
|
|
1524
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1525
|
+
"div",
|
|
1526
|
+
{
|
|
1527
|
+
"data-slot": "card-description",
|
|
1528
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
1529
|
+
...props
|
|
1530
|
+
}
|
|
1531
|
+
);
|
|
1532
|
+
}
|
|
1533
|
+
function CardContent({ className, ...props }) {
|
|
1534
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "card-content", className: cn("p-6 pt-0", className), ...props });
|
|
1535
|
+
}
|
|
1536
|
+
function CardFooter({ className, ...props }) {
|
|
1537
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1538
|
+
"div",
|
|
1539
|
+
{
|
|
1540
|
+
"data-slot": "card-footer",
|
|
1541
|
+
className: cn("flex items-center p-6 pt-0", className),
|
|
1542
|
+
...props
|
|
1543
|
+
}
|
|
1544
|
+
);
|
|
1545
|
+
}
|
|
1546
|
+
function Input({ className, type, ...props }) {
|
|
1547
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1548
|
+
"input",
|
|
1549
|
+
{
|
|
1550
|
+
type,
|
|
1551
|
+
"data-slot": "input",
|
|
1552
|
+
className: cn(
|
|
1553
|
+
"flex h-9 w-full rounded-md border border-input bg-card px-3 py-1 text-sm shadow-sm transition-colors",
|
|
1554
|
+
"placeholder:text-muted-foreground/70",
|
|
1555
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:border-ring/60",
|
|
1556
|
+
"disabled:cursor-not-allowed disabled:opacity-50 file:border-0 file:bg-transparent file:text-sm file:font-medium",
|
|
1557
|
+
className
|
|
1558
|
+
),
|
|
1559
|
+
...props
|
|
1560
|
+
}
|
|
1561
|
+
);
|
|
1562
|
+
}
|
|
1563
|
+
function useWorkspaceDocs(workspaceId) {
|
|
1564
|
+
const { data: docs = [], isLoading, isError } = useDocuments(workspaceId);
|
|
1565
|
+
const docIds = React.useMemo(
|
|
1566
|
+
() => docs.map((d) => d.external_id).filter((id) => !!id),
|
|
1567
|
+
[docs]
|
|
1568
|
+
);
|
|
1569
|
+
return { wsId: workspaceId, docs, docIds, isLoading, isError, ready: docIds.length > 0 };
|
|
1570
|
+
}
|
|
1571
|
+
function useAiTask() {
|
|
1572
|
+
const mutation = useAssistantQuery();
|
|
1573
|
+
const [status, setStatus] = React.useState("idle");
|
|
1574
|
+
const [text, setText] = React.useState("");
|
|
1575
|
+
const [stepCount, setStepCount] = React.useState(0);
|
|
1576
|
+
const [error, setError] = React.useState(null);
|
|
1577
|
+
const [responseId, setResponseId] = React.useState(null);
|
|
1578
|
+
const [artifacts, setArtifacts] = React.useState([]);
|
|
1579
|
+
const bufferRef = React.useRef("");
|
|
1580
|
+
const artifactsRef = React.useRef(/* @__PURE__ */ new Map());
|
|
1581
|
+
const reset = React.useCallback(() => {
|
|
1582
|
+
setStatus("idle");
|
|
1583
|
+
setText("");
|
|
1584
|
+
setStepCount(0);
|
|
1585
|
+
setError(null);
|
|
1586
|
+
setResponseId(null);
|
|
1587
|
+
setArtifacts([]);
|
|
1588
|
+
artifactsRef.current = /* @__PURE__ */ new Map();
|
|
1589
|
+
bufferRef.current = "";
|
|
1590
|
+
}, []);
|
|
1591
|
+
const run = React.useCallback(
|
|
1592
|
+
async (question, docIds, opts) => {
|
|
1593
|
+
setStatus("running");
|
|
1594
|
+
setText("");
|
|
1595
|
+
setStepCount(0);
|
|
1596
|
+
setError(null);
|
|
1597
|
+
setArtifacts([]);
|
|
1598
|
+
artifactsRef.current = /* @__PURE__ */ new Map();
|
|
1599
|
+
bufferRef.current = "";
|
|
1600
|
+
let streamError = null;
|
|
1601
|
+
try {
|
|
1602
|
+
const result = await mutation.mutateAsync({
|
|
1603
|
+
question,
|
|
1604
|
+
docIds,
|
|
1605
|
+
previousResponseId: opts?.previousResponseId ?? void 0,
|
|
1606
|
+
model: opts?.model,
|
|
1607
|
+
onToken: (c) => {
|
|
1608
|
+
bufferRef.current += c;
|
|
1609
|
+
setText(bufferRef.current);
|
|
1610
|
+
},
|
|
1611
|
+
onAgentStep: () => setStepCount((n) => n + 1),
|
|
1612
|
+
onArtifact: (a) => {
|
|
1613
|
+
artifactsRef.current.set(a.doc_ext_id, a);
|
|
1614
|
+
setArtifacts([...artifactsRef.current.values()]);
|
|
1615
|
+
},
|
|
1616
|
+
onError: (m) => {
|
|
1617
|
+
streamError = m;
|
|
1618
|
+
}
|
|
1619
|
+
});
|
|
1620
|
+
const finalText = result.text || bufferRef.current;
|
|
1621
|
+
setText(finalText);
|
|
1622
|
+
setResponseId(result.assistantMessageExtId);
|
|
1623
|
+
setStepCount(result.agentSteps.length || 0);
|
|
1624
|
+
if (result.artifacts?.length) {
|
|
1625
|
+
for (const a of result.artifacts) artifactsRef.current.set(a.doc_ext_id, a);
|
|
1626
|
+
setArtifacts([...artifactsRef.current.values()]);
|
|
1627
|
+
}
|
|
1628
|
+
const err = streamError || result.errors[0] || null;
|
|
1629
|
+
if (err && !finalText) {
|
|
1630
|
+
setError(err);
|
|
1631
|
+
setStatus("error");
|
|
1632
|
+
} else {
|
|
1633
|
+
setStatus("done");
|
|
1634
|
+
}
|
|
1635
|
+
return result;
|
|
1636
|
+
} catch (e) {
|
|
1637
|
+
setError(e instanceof Error ? e.message : "The assistant request failed.");
|
|
1638
|
+
setStatus("error");
|
|
1639
|
+
return null;
|
|
1640
|
+
}
|
|
1641
|
+
},
|
|
1642
|
+
[mutation]
|
|
1643
|
+
);
|
|
1644
|
+
return {
|
|
1645
|
+
status,
|
|
1646
|
+
text,
|
|
1647
|
+
stepCount,
|
|
1648
|
+
error,
|
|
1649
|
+
responseId,
|
|
1650
|
+
artifacts,
|
|
1651
|
+
run,
|
|
1652
|
+
reset,
|
|
1653
|
+
isRunning: status === "running",
|
|
1654
|
+
isDone: status === "done"
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
function useSemanticSearch(docIds) {
|
|
1658
|
+
const arbi = useArbi();
|
|
1659
|
+
const [results, setResults] = React.useState([]);
|
|
1660
|
+
const [status, setStatus] = React.useState("idle");
|
|
1661
|
+
const [error, setError] = React.useState(null);
|
|
1662
|
+
const [query, setQuery] = React.useState("");
|
|
1663
|
+
const search = React.useCallback(
|
|
1664
|
+
async (q, mode = "hybrid") => {
|
|
1665
|
+
const trimmed = q.trim();
|
|
1666
|
+
setQuery(trimmed);
|
|
1667
|
+
if (!trimmed || docIds.length === 0) {
|
|
1668
|
+
setResults([]);
|
|
1669
|
+
setStatus("idle");
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1672
|
+
setStatus("running");
|
|
1673
|
+
setError(null);
|
|
1674
|
+
try {
|
|
1675
|
+
const res = await arbi.assistant.retrieve(trimmed, docIds, { searchMode: mode });
|
|
1676
|
+
const byTool = res.retrieval_chunk?.tool_responses ?? {};
|
|
1677
|
+
const chunks = Object.values(byTool).flat().map(
|
|
1678
|
+
(c) => ({
|
|
1679
|
+
docId: c.metadata.doc_ext_id,
|
|
1680
|
+
docTitle: c.metadata.doc_title,
|
|
1681
|
+
page: c.metadata.page_number,
|
|
1682
|
+
score: c.metadata.rerank_score ?? c.metadata.score,
|
|
1683
|
+
content: c.content
|
|
1684
|
+
})
|
|
1685
|
+
).sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
|
|
1686
|
+
setResults(chunks);
|
|
1687
|
+
setStatus("done");
|
|
1688
|
+
} catch (e) {
|
|
1689
|
+
setError(e instanceof Error ? e.message : "Search failed.");
|
|
1690
|
+
setStatus("error");
|
|
1691
|
+
}
|
|
1692
|
+
},
|
|
1693
|
+
[arbi, docIds]
|
|
1694
|
+
);
|
|
1695
|
+
return { query, results, status, error, search, isRunning: status === "running" };
|
|
1696
|
+
}
|
|
1697
|
+
function toRedlineMarkdown(original, revised) {
|
|
1698
|
+
const parts = diff.diffWords(original ?? "", revised ?? "");
|
|
1699
|
+
return parts.map((p) => {
|
|
1700
|
+
if (p.added) return `<ins>${p.value}</ins>`;
|
|
1701
|
+
if (p.removed) return `<del>${p.value}</del>`;
|
|
1702
|
+
return p.value;
|
|
1703
|
+
}).join("");
|
|
1704
|
+
}
|
|
1705
|
+
function redlineStats(original, revised) {
|
|
1706
|
+
let added = 0;
|
|
1707
|
+
let removed = 0;
|
|
1708
|
+
for (const p of diff.diffWords(original ?? "", revised ?? "")) {
|
|
1709
|
+
const words = p.value.trim() ? p.value.trim().split(/\s+/).length : 0;
|
|
1710
|
+
if (p.added) added += words;
|
|
1711
|
+
else if (p.removed) removed += words;
|
|
1712
|
+
}
|
|
1713
|
+
return { added, removed };
|
|
1714
|
+
}
|
|
1715
|
+
function textToArtifact(title, content, opts) {
|
|
1716
|
+
return {
|
|
1717
|
+
type: "arbi.artifact",
|
|
1718
|
+
doc_ext_id: opts?.id ?? `local-${title.replace(/\W+/g, "-").toLowerCase()}`,
|
|
1719
|
+
title,
|
|
1720
|
+
mode: opts?.mode ?? "markdown",
|
|
1721
|
+
content,
|
|
1722
|
+
is_complete: opts?.isComplete ?? true,
|
|
1723
|
+
version: opts?.version ?? 1,
|
|
1724
|
+
message_ext_id: null,
|
|
1725
|
+
t: null
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
function AiMarkdown({ children, className }) {
|
|
1729
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1730
|
+
"div",
|
|
1731
|
+
{
|
|
1732
|
+
className: cn("text-sm leading-relaxed text-foreground", className),
|
|
1733
|
+
"data-testid": "ai-markdown",
|
|
1734
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1735
|
+
ReactMarkdown__default.default,
|
|
1736
|
+
{
|
|
1737
|
+
remarkPlugins: [remarkGfm__default.default],
|
|
1738
|
+
rehypePlugins: [rehypeRaw__default.default],
|
|
1739
|
+
components: {
|
|
1740
|
+
h1: (p) => /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "mb-2 mt-4 text-lg font-semibold text-foreground first:mt-0", ...p }),
|
|
1741
|
+
h2: (p) => /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "mb-2 mt-4 text-base font-semibold text-foreground first:mt-0", ...p }),
|
|
1742
|
+
h3: (p) => /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-1.5 mt-3 text-sm font-semibold text-foreground first:mt-0", ...p }),
|
|
1743
|
+
p: (p) => /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-3 last:mb-0", ...p }),
|
|
1744
|
+
ul: (p) => /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mb-3 list-disc space-y-1 pl-5 last:mb-0", ...p }),
|
|
1745
|
+
ol: (p) => /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "mb-3 list-decimal space-y-1 pl-5 last:mb-0", ...p }),
|
|
1746
|
+
li: (p) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "pl-1", ...p }),
|
|
1747
|
+
strong: (p) => /* @__PURE__ */ jsxRuntime.jsx("strong", { className: "font-semibold text-foreground", ...p }),
|
|
1748
|
+
a: (p) => /* @__PURE__ */ jsxRuntime.jsx("a", { className: "text-ai-accent underline underline-offset-2", ...p }),
|
|
1749
|
+
// Redline marks: deletions in red strike, <ins>/<mark> additions accented.
|
|
1750
|
+
del: (p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1751
|
+
"del",
|
|
1752
|
+
{
|
|
1753
|
+
className: "rounded bg-destructive/10 text-destructive decoration-destructive/60",
|
|
1754
|
+
...p
|
|
1755
|
+
}
|
|
1756
|
+
),
|
|
1757
|
+
ins: (p) => /* @__PURE__ */ jsxRuntime.jsx("ins", { className: "rounded bg-ai-accent-soft px-0.5 text-ai-accent no-underline", ...p }),
|
|
1758
|
+
mark: (p) => /* @__PURE__ */ jsxRuntime.jsx("mark", { className: "rounded bg-ai-accent-soft px-0.5 text-ai-accent", ...p }),
|
|
1759
|
+
code: (p) => /* @__PURE__ */ jsxRuntime.jsx("code", { className: "rounded bg-secondary px-1 py-0.5 font-mono text-[0.8em]", ...p }),
|
|
1760
|
+
blockquote: (p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1761
|
+
"blockquote",
|
|
1762
|
+
{
|
|
1763
|
+
className: "my-3 border-l-2 border-ai-accent/40 pl-3 italic text-muted-foreground",
|
|
1764
|
+
...p
|
|
1765
|
+
}
|
|
1766
|
+
),
|
|
1767
|
+
table: (p) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "my-3 overflow-x-auto rounded-lg border border-border", children: /* @__PURE__ */ jsxRuntime.jsx("table", { className: "w-full border-collapse text-xs", ...p }) }),
|
|
1768
|
+
thead: (p) => /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-secondary/60", ...p }),
|
|
1769
|
+
th: (p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1770
|
+
"th",
|
|
1771
|
+
{
|
|
1772
|
+
className: "border-b border-border px-3 py-2 text-left font-semibold text-foreground",
|
|
1773
|
+
...p
|
|
1774
|
+
}
|
|
1775
|
+
),
|
|
1776
|
+
td: (p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1777
|
+
"td",
|
|
1778
|
+
{
|
|
1779
|
+
className: "border-b border-border px-3 py-2 align-top text-muted-foreground",
|
|
1780
|
+
...p
|
|
1781
|
+
}
|
|
1782
|
+
)
|
|
1783
|
+
},
|
|
1784
|
+
children
|
|
1785
|
+
}
|
|
1786
|
+
)
|
|
1787
|
+
}
|
|
1788
|
+
);
|
|
1789
|
+
}
|
|
1790
|
+
function AiAnswer({
|
|
1791
|
+
status,
|
|
1792
|
+
text,
|
|
1793
|
+
stepCount,
|
|
1794
|
+
error,
|
|
1795
|
+
className,
|
|
1796
|
+
emptyHint,
|
|
1797
|
+
groundedNote = "Grounded in the live workspace \xB7 verify citations before relying on it",
|
|
1798
|
+
runningHint = "Reading the documents\u2026",
|
|
1799
|
+
testId = "ai-answer"
|
|
1800
|
+
}) {
|
|
1801
|
+
const [copied, setCopied] = React.useState(false);
|
|
1802
|
+
const running = status === "running";
|
|
1803
|
+
const hasText = text.trim().length > 0;
|
|
1804
|
+
const copy = async () => {
|
|
1805
|
+
await navigator.clipboard.writeText(text);
|
|
1806
|
+
setCopied(true);
|
|
1807
|
+
setTimeout(() => setCopied(false), 1600);
|
|
1808
|
+
};
|
|
1809
|
+
if (status === "idle" && !hasText) {
|
|
1810
|
+
return emptyHint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("text-sm text-muted-foreground", className), "data-testid": `${testId}-empty`, children: emptyHint }) : null;
|
|
1811
|
+
}
|
|
1812
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-3", className), "data-testid": testId, "data-status": status, children: [
|
|
1813
|
+
running && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1814
|
+
"div",
|
|
1815
|
+
{
|
|
1816
|
+
className: "flex items-center gap-2 text-xs font-medium text-ai-accent",
|
|
1817
|
+
"data-testid": `${testId}-thinking`,
|
|
1818
|
+
children: [
|
|
1819
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-3.5 animate-spin" }),
|
|
1820
|
+
stepCount && stepCount > 0 ? `Working \u2014 ${stepCount} step${stepCount === 1 ? "" : "s"}\u2026` : "Thinking\u2026"
|
|
1821
|
+
]
|
|
1822
|
+
}
|
|
1823
|
+
),
|
|
1824
|
+
status === "error" && !hasText && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1825
|
+
"div",
|
|
1826
|
+
{
|
|
1827
|
+
className: "flex items-start gap-2 rounded-lg border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive",
|
|
1828
|
+
"data-testid": `${testId}-error`,
|
|
1829
|
+
children: [
|
|
1830
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "mt-0.5 size-4 shrink-0" }),
|
|
1831
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: error ?? "The assistant request failed." })
|
|
1832
|
+
]
|
|
1833
|
+
}
|
|
1834
|
+
),
|
|
1835
|
+
hasText && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1836
|
+
/* @__PURE__ */ jsxRuntime.jsx(AiMarkdown, { children: text }),
|
|
1837
|
+
!running && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-t border-border pt-2.5", children: [
|
|
1838
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
1839
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldCheck, { className: "size-3.5 text-ai-accent" }),
|
|
1840
|
+
groundedNote
|
|
1841
|
+
] }),
|
|
1842
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1843
|
+
"button",
|
|
1844
|
+
{
|
|
1845
|
+
type: "button",
|
|
1846
|
+
onClick: copy,
|
|
1847
|
+
className: "inline-flex items-center gap-1 text-xs font-medium text-muted-foreground hover:text-foreground",
|
|
1848
|
+
"data-testid": `${testId}-copy`,
|
|
1849
|
+
children: [
|
|
1850
|
+
copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3.5 text-ai-accent" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "size-3.5" }),
|
|
1851
|
+
copied ? "Copied" : "Copy"
|
|
1852
|
+
]
|
|
1853
|
+
}
|
|
1854
|
+
)
|
|
1855
|
+
] })
|
|
1856
|
+
] }),
|
|
1857
|
+
running && !hasText && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-sm text-muted-foreground", children: [
|
|
1858
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "size-4 animate-pulse text-ai-accent" }),
|
|
1859
|
+
" ",
|
|
1860
|
+
runningHint
|
|
1861
|
+
] })
|
|
1862
|
+
] });
|
|
1863
|
+
}
|
|
1864
|
+
function AiActionCard({
|
|
1865
|
+
icon: Icon = lucideReact.Sparkles,
|
|
1866
|
+
title,
|
|
1867
|
+
description,
|
|
1868
|
+
prompt,
|
|
1869
|
+
docIds,
|
|
1870
|
+
runLabel = "Run",
|
|
1871
|
+
noDocsHint = "Connect to the workspace to run this.",
|
|
1872
|
+
disabled,
|
|
1873
|
+
testId
|
|
1874
|
+
}) {
|
|
1875
|
+
const task = useAiTask();
|
|
1876
|
+
const noDocs = docIds.length === 0;
|
|
1877
|
+
const onRun = () => {
|
|
1878
|
+
const p = typeof prompt === "function" ? prompt() : prompt;
|
|
1879
|
+
void task.run(p, docIds);
|
|
1880
|
+
};
|
|
1881
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "p-5", "data-testid": testId, children: [
|
|
1882
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
|
|
1883
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
|
|
1884
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-9 shrink-0 items-center justify-center rounded-lg bg-ai-accent-soft text-ai-accent", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-4" }) }),
|
|
1885
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1886
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: title }),
|
|
1887
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs leading-relaxed text-muted-foreground", children: description })
|
|
1888
|
+
] })
|
|
1889
|
+
] }),
|
|
1890
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1891
|
+
Button,
|
|
1892
|
+
{
|
|
1893
|
+
variant: task.isDone ? "outline" : "accent",
|
|
1894
|
+
size: "sm",
|
|
1895
|
+
onClick: onRun,
|
|
1896
|
+
disabled: disabled || noDocs || task.isRunning,
|
|
1897
|
+
"data-testid": testId && `${testId}-run`,
|
|
1898
|
+
children: [
|
|
1899
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "size-3.5" }),
|
|
1900
|
+
task.isRunning ? "Running\u2026" : task.isDone ? "Re-run" : runLabel
|
|
1901
|
+
]
|
|
1902
|
+
}
|
|
1903
|
+
)
|
|
1904
|
+
] }),
|
|
1905
|
+
(task.status !== "idle" || noDocs) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4", children: noDocs ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: noDocsHint }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1906
|
+
AiAnswer,
|
|
1907
|
+
{
|
|
1908
|
+
status: task.status,
|
|
1909
|
+
text: task.text,
|
|
1910
|
+
stepCount: task.stepCount,
|
|
1911
|
+
error: task.error,
|
|
1912
|
+
testId: testId && `${testId}-answer`
|
|
1913
|
+
}
|
|
1914
|
+
) })
|
|
1915
|
+
] });
|
|
1916
|
+
}
|
|
1917
|
+
function ArtifactCanvas({
|
|
1918
|
+
artifacts,
|
|
1919
|
+
className,
|
|
1920
|
+
emptyHint = "Draft artifacts produced by the agent will open here.",
|
|
1921
|
+
busy = false,
|
|
1922
|
+
busyHint = "The agent is working through the documents\u2026",
|
|
1923
|
+
stepCount,
|
|
1924
|
+
error = null
|
|
1925
|
+
}) {
|
|
1926
|
+
const [activeId, setActiveId] = React.useState(null);
|
|
1927
|
+
const [copied, setCopied] = React.useState(false);
|
|
1928
|
+
React.useEffect(() => {
|
|
1929
|
+
if (artifacts.length && (!activeId || !artifacts.some((a) => a.doc_ext_id === activeId))) {
|
|
1930
|
+
setActiveId(artifacts[artifacts.length - 1].doc_ext_id);
|
|
1931
|
+
}
|
|
1932
|
+
}, [artifacts, activeId]);
|
|
1933
|
+
if (artifacts.length === 0) {
|
|
1934
|
+
if (error && !busy) {
|
|
1935
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1936
|
+
"div",
|
|
1937
|
+
{
|
|
1938
|
+
className: cn(
|
|
1939
|
+
"flex h-full min-h-[280px] flex-col items-center justify-center rounded-xl border border-destructive/30 bg-destructive/5 p-8 text-center",
|
|
1940
|
+
className
|
|
1941
|
+
),
|
|
1942
|
+
"data-testid": "artifact-canvas-error",
|
|
1943
|
+
children: [
|
|
1944
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "size-8 text-destructive/70" }),
|
|
1945
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 max-w-md text-sm text-foreground", children: error })
|
|
1946
|
+
]
|
|
1947
|
+
}
|
|
1948
|
+
);
|
|
1949
|
+
}
|
|
1950
|
+
if (busy) {
|
|
1951
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1952
|
+
"div",
|
|
1953
|
+
{
|
|
1954
|
+
className: cn(
|
|
1955
|
+
"flex h-full min-h-[280px] flex-col items-center justify-center rounded-xl border border-border bg-ai-surface/40 p-8 text-center",
|
|
1956
|
+
className
|
|
1957
|
+
),
|
|
1958
|
+
"data-testid": "artifact-canvas-busy",
|
|
1959
|
+
children: [
|
|
1960
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-8 animate-spin text-ai-accent" }),
|
|
1961
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-4 max-w-xs text-sm font-medium text-foreground", children: busyHint }),
|
|
1962
|
+
typeof stepCount === "number" && stepCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 text-xs text-muted-foreground", "data-testid": "artifact-canvas-steps", children: [
|
|
1963
|
+
stepCount,
|
|
1964
|
+
" ",
|
|
1965
|
+
stepCount === 1 ? "step" : "steps",
|
|
1966
|
+
" so far"
|
|
1967
|
+
] })
|
|
1968
|
+
]
|
|
1969
|
+
}
|
|
1970
|
+
);
|
|
1971
|
+
}
|
|
1972
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1973
|
+
"div",
|
|
1974
|
+
{
|
|
1975
|
+
className: cn(
|
|
1976
|
+
"flex h-full min-h-[280px] flex-col items-center justify-center rounded-xl border border-dashed border-border bg-secondary/30 p-8 text-center",
|
|
1977
|
+
className
|
|
1978
|
+
),
|
|
1979
|
+
"data-testid": "artifact-canvas-empty",
|
|
1980
|
+
children: [
|
|
1981
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-8 text-muted-foreground/50" }),
|
|
1982
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 max-w-xs text-sm text-muted-foreground", children: emptyHint })
|
|
1983
|
+
]
|
|
1984
|
+
}
|
|
1985
|
+
);
|
|
1986
|
+
}
|
|
1987
|
+
const active = artifacts.find((a) => a.doc_ext_id === activeId) ?? artifacts[artifacts.length - 1];
|
|
1988
|
+
const isRedline = /~~|<ins|<del|<mark/i.test(active.content);
|
|
1989
|
+
const copy = async () => {
|
|
1990
|
+
await navigator.clipboard.writeText(active.content);
|
|
1991
|
+
setCopied(true);
|
|
1992
|
+
setTimeout(() => setCopied(false), 1600);
|
|
1993
|
+
};
|
|
1994
|
+
const download = () => {
|
|
1995
|
+
const ext = active.mode === "html" ? "html" : active.mode === "text" ? "txt" : "md";
|
|
1996
|
+
const blob = new Blob([active.content], { type: "text/plain" });
|
|
1997
|
+
const url = URL.createObjectURL(blob);
|
|
1998
|
+
const a = document.createElement("a");
|
|
1999
|
+
a.href = url;
|
|
2000
|
+
a.download = `${active.title.replace(/[^\w.-]+/g, "_") || "artifact"}.${ext}`;
|
|
2001
|
+
a.click();
|
|
2002
|
+
URL.revokeObjectURL(url);
|
|
2003
|
+
};
|
|
2004
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2005
|
+
"div",
|
|
2006
|
+
{
|
|
2007
|
+
className: cn(
|
|
2008
|
+
"flex h-full flex-col overflow-hidden rounded-xl border border-border bg-card",
|
|
2009
|
+
className
|
|
2010
|
+
),
|
|
2011
|
+
"data-testid": "artifact-canvas",
|
|
2012
|
+
children: [
|
|
2013
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border-b border-border bg-secondary/40 px-4 py-2.5", children: [
|
|
2014
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-4 shrink-0 text-ai-accent" }),
|
|
2015
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2016
|
+
"span",
|
|
2017
|
+
{
|
|
2018
|
+
className: "min-w-0 flex-1 truncate text-sm font-medium text-foreground",
|
|
2019
|
+
"data-testid": "artifact-title",
|
|
2020
|
+
children: active.title
|
|
2021
|
+
}
|
|
2022
|
+
),
|
|
2023
|
+
isRedline && /* @__PURE__ */ jsxRuntime.jsxs(Badge, { variant: "accent", className: "gap-1", children: [
|
|
2024
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitCompareArrows, { className: "size-3" }),
|
|
2025
|
+
" Redline"
|
|
2026
|
+
] }),
|
|
2027
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { variant: "secondary", children: [
|
|
2028
|
+
"v",
|
|
2029
|
+
active.version
|
|
2030
|
+
] }),
|
|
2031
|
+
!active.is_complete ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2032
|
+
"span",
|
|
2033
|
+
{
|
|
2034
|
+
className: "inline-flex items-center gap-1 text-xs text-ai-accent",
|
|
2035
|
+
"data-testid": "artifact-streaming",
|
|
2036
|
+
children: [
|
|
2037
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-3 animate-spin" }),
|
|
2038
|
+
" drafting"
|
|
2039
|
+
]
|
|
2040
|
+
}
|
|
2041
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
2042
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2043
|
+
"button",
|
|
2044
|
+
{
|
|
2045
|
+
onClick: copy,
|
|
2046
|
+
className: "rounded p-1 text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
2047
|
+
title: "Copy",
|
|
2048
|
+
"data-testid": "artifact-copy",
|
|
2049
|
+
children: copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3.5 text-ai-accent" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "size-3.5" })
|
|
2050
|
+
}
|
|
2051
|
+
),
|
|
2052
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2053
|
+
"button",
|
|
2054
|
+
{
|
|
2055
|
+
onClick: download,
|
|
2056
|
+
className: "rounded p-1 text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
2057
|
+
title: "Download",
|
|
2058
|
+
"data-testid": "artifact-download",
|
|
2059
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "size-3.5" })
|
|
2060
|
+
}
|
|
2061
|
+
)
|
|
2062
|
+
] })
|
|
2063
|
+
] }),
|
|
2064
|
+
artifacts.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1 overflow-x-auto border-b border-border bg-card px-2 py-1.5", children: artifacts.map((a) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2065
|
+
"button",
|
|
2066
|
+
{
|
|
2067
|
+
onClick: () => setActiveId(a.doc_ext_id),
|
|
2068
|
+
className: cn(
|
|
2069
|
+
"shrink-0 rounded-md px-2.5 py-1 text-xs font-medium",
|
|
2070
|
+
a.doc_ext_id === active.doc_ext_id ? "bg-ai-accent-soft text-ai-accent" : "text-muted-foreground hover:bg-accent"
|
|
2071
|
+
),
|
|
2072
|
+
children: a.title.slice(0, 28)
|
|
2073
|
+
},
|
|
2074
|
+
a.doc_ext_id
|
|
2075
|
+
)) }),
|
|
2076
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto bg-ai-surface/40 p-6", children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2077
|
+
framerMotion.motion.div,
|
|
2078
|
+
{
|
|
2079
|
+
initial: { opacity: 0, y: 6 },
|
|
2080
|
+
animate: { opacity: 1, y: 0 },
|
|
2081
|
+
transition: { duration: 0.2 },
|
|
2082
|
+
className: "mx-auto max-w-2xl rounded-lg bg-card p-8 shadow-sm ring-1 ring-border",
|
|
2083
|
+
children: active.mode === "html" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm", dangerouslySetInnerHTML: { __html: active.content } }) : active.mode === "text" ? /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre-wrap font-mono text-xs text-foreground", children: active.content }) : /* @__PURE__ */ jsxRuntime.jsx(AiMarkdown, { children: active.content })
|
|
2084
|
+
},
|
|
2085
|
+
active.doc_ext_id
|
|
2086
|
+
) }) })
|
|
2087
|
+
]
|
|
2088
|
+
}
|
|
2089
|
+
);
|
|
2090
|
+
}
|
|
2091
|
+
function DocSearch({
|
|
2092
|
+
docIds,
|
|
2093
|
+
onOpenDoc,
|
|
2094
|
+
placeholder = "Semantic search across your documents\u2026",
|
|
2095
|
+
className
|
|
2096
|
+
}) {
|
|
2097
|
+
const { results, status, error, search, isRunning, query } = useSemanticSearch(docIds);
|
|
2098
|
+
const [value, setValue] = React.useState("");
|
|
2099
|
+
const submit = () => {
|
|
2100
|
+
if (value.trim()) void search(value, "hybrid");
|
|
2101
|
+
};
|
|
2102
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-3", className), "data-testid": "doc-search", children: [
|
|
2103
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
2104
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" }),
|
|
2105
|
+
isRunning && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "absolute right-3 top-1/2 size-4 -translate-y-1/2 animate-spin text-ai-accent" }),
|
|
2106
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2107
|
+
"input",
|
|
2108
|
+
{
|
|
2109
|
+
value,
|
|
2110
|
+
onChange: (e) => setValue(e.target.value),
|
|
2111
|
+
onKeyDown: (e) => e.key === "Enter" && (e.preventDefault(), submit()),
|
|
2112
|
+
placeholder,
|
|
2113
|
+
className: "h-11 w-full rounded-lg border border-input bg-background pl-9 pr-24 text-sm outline-none focus:border-ai-accent/50 focus:ring-2 focus:ring-ai-accent/15",
|
|
2114
|
+
"data-testid": "doc-search-input"
|
|
2115
|
+
}
|
|
2116
|
+
),
|
|
2117
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2118
|
+
"button",
|
|
2119
|
+
{
|
|
2120
|
+
type: "button",
|
|
2121
|
+
onClick: submit,
|
|
2122
|
+
className: "absolute right-2 top-1/2 flex -translate-y-1/2 items-center gap-1 rounded-md bg-ai-accent px-2.5 py-1 text-xs font-medium text-ai-accent-foreground",
|
|
2123
|
+
"data-testid": "doc-search-submit",
|
|
2124
|
+
children: [
|
|
2125
|
+
"Search ",
|
|
2126
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerDownLeft, { className: "size-3" })
|
|
2127
|
+
]
|
|
2128
|
+
}
|
|
2129
|
+
)
|
|
2130
|
+
] }),
|
|
2131
|
+
status === "error" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": "doc-search-error", children: error }),
|
|
2132
|
+
status === "done" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", "data-testid": "doc-search-results", children: [
|
|
2133
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: results.length === 0 ? `No passages matched \u201C${query}\u201D.` : `${results.length} passage${results.length === 1 ? "" : "s"} for \u201C${query}\u201D` }),
|
|
2134
|
+
results.slice(0, 8).map((r, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2135
|
+
Card,
|
|
2136
|
+
{
|
|
2137
|
+
className: cn(
|
|
2138
|
+
"p-3",
|
|
2139
|
+
onOpenDoc && r.docId && "cursor-pointer transition-colors hover:border-ai-accent/40"
|
|
2140
|
+
),
|
|
2141
|
+
onClick: () => r.docId && onOpenDoc?.(r.docId),
|
|
2142
|
+
"data-testid": `doc-search-hit-${i}`,
|
|
2143
|
+
children: [
|
|
2144
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-1 flex items-center gap-2", children: [
|
|
2145
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-3.5 text-ai-accent" }),
|
|
2146
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs font-medium text-foreground", children: r.docTitle ?? "Document" }),
|
|
2147
|
+
r.page != null && /* @__PURE__ */ jsxRuntime.jsxs(Badge, { variant: "secondary", children: [
|
|
2148
|
+
"p.",
|
|
2149
|
+
r.page
|
|
2150
|
+
] }),
|
|
2151
|
+
r.score != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-auto text-[10px] text-muted-foreground", children: [
|
|
2152
|
+
"score ",
|
|
2153
|
+
r.score.toFixed(2)
|
|
2154
|
+
] })
|
|
2155
|
+
] }),
|
|
2156
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "line-clamp-3 text-xs leading-relaxed text-muted-foreground", children: r.content })
|
|
2157
|
+
]
|
|
2158
|
+
},
|
|
2159
|
+
`${r.docId}-${r.page}-${i}`
|
|
2160
|
+
))
|
|
2161
|
+
] })
|
|
2162
|
+
] });
|
|
2163
|
+
}
|
|
2164
|
+
function DocQaPanel({ docId, docName }) {
|
|
2165
|
+
const task = useAiTask();
|
|
2166
|
+
const [q, setQ] = React.useState("");
|
|
2167
|
+
const ask = () => {
|
|
2168
|
+
const question = q.trim();
|
|
2169
|
+
if (!question || task.isRunning) return;
|
|
2170
|
+
void task.run(
|
|
2171
|
+
`You are answering strictly from the single document "${docName ?? docId}". Cite the page/section for each point and say if the document does not address the question.
|
|
2172
|
+
|
|
2173
|
+
Question: ${question}`,
|
|
2174
|
+
[docId]
|
|
2175
|
+
);
|
|
2176
|
+
};
|
|
2177
|
+
const suggestTags = () => void task.run(
|
|
2178
|
+
`Suggest 3-6 concise, reusable labels for the document "${docName ?? docId}" \u2014 covering document type, the key issues it touches, and any key parties. Return them as a short comma-separated list with a one-line rationale for each.`,
|
|
2179
|
+
[docId]
|
|
2180
|
+
);
|
|
2181
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", "data-testid": "doc-qa", children: [
|
|
2182
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2183
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2184
|
+
Input,
|
|
2185
|
+
{
|
|
2186
|
+
value: q,
|
|
2187
|
+
onChange: (e) => setQ(e.target.value),
|
|
2188
|
+
onKeyDown: (e) => e.key === "Enter" && (e.preventDefault(), ask()),
|
|
2189
|
+
placeholder: "Ask about this document\u2026",
|
|
2190
|
+
"data-testid": "doc-qa-input"
|
|
2191
|
+
}
|
|
2192
|
+
),
|
|
2193
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2194
|
+
Button,
|
|
2195
|
+
{
|
|
2196
|
+
variant: "accent",
|
|
2197
|
+
size: "icon",
|
|
2198
|
+
onClick: ask,
|
|
2199
|
+
disabled: task.isRunning || !q.trim(),
|
|
2200
|
+
"data-testid": "doc-qa-send",
|
|
2201
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "size-4" })
|
|
2202
|
+
}
|
|
2203
|
+
),
|
|
2204
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2205
|
+
Button,
|
|
2206
|
+
{
|
|
2207
|
+
variant: "outline",
|
|
2208
|
+
size: "sm",
|
|
2209
|
+
onClick: suggestTags,
|
|
2210
|
+
disabled: task.isRunning,
|
|
2211
|
+
"data-testid": "doc-qa-tags",
|
|
2212
|
+
children: [
|
|
2213
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tags, { className: "size-4" }),
|
|
2214
|
+
" Tags"
|
|
2215
|
+
]
|
|
2216
|
+
}
|
|
2217
|
+
)
|
|
2218
|
+
] }),
|
|
2219
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2220
|
+
AiAnswer,
|
|
2221
|
+
{
|
|
2222
|
+
status: task.status,
|
|
2223
|
+
text: task.text,
|
|
2224
|
+
stepCount: task.stepCount,
|
|
2225
|
+
error: task.error,
|
|
2226
|
+
emptyHint: "Ask a question, or suggest tags \u2014 answered from this document only.",
|
|
2227
|
+
testId: "doc-qa-answer"
|
|
2228
|
+
}
|
|
2229
|
+
)
|
|
2230
|
+
] });
|
|
2231
|
+
}
|
|
1478
2232
|
|
|
1479
2233
|
// src/icons/colors.ts
|
|
1480
2234
|
var NEUTRAL_GRAY = "#64748b";
|
|
@@ -2492,15 +3246,27 @@ Object.defineProperty(exports, "ArbiError", {
|
|
|
2492
3246
|
enumerable: true,
|
|
2493
3247
|
get: function () { return browser.ArbiError; }
|
|
2494
3248
|
});
|
|
3249
|
+
exports.AiActionCard = AiActionCard;
|
|
3250
|
+
exports.AiAnswer = AiAnswer;
|
|
3251
|
+
exports.AiMarkdown = AiMarkdown;
|
|
2495
3252
|
exports.ArbiChat = ArbiChat;
|
|
2496
3253
|
exports.ArbiChatPanel = ArbiChatPanel;
|
|
2497
3254
|
exports.ArbiProvider = ArbiProvider;
|
|
3255
|
+
exports.ArtifactCanvas = ArtifactCanvas;
|
|
2498
3256
|
exports.AudIcon = AudIcon;
|
|
2499
3257
|
exports.Avatar = Avatar;
|
|
2500
3258
|
exports.AvatarFallback = AvatarFallback;
|
|
2501
3259
|
exports.AvatarImage = AvatarImage;
|
|
2502
3260
|
exports.Badge = Badge;
|
|
2503
3261
|
exports.Button = Button;
|
|
3262
|
+
exports.Card = Card;
|
|
3263
|
+
exports.CardContent = CardContent;
|
|
3264
|
+
exports.CardDescription = CardDescription;
|
|
3265
|
+
exports.CardFooter = CardFooter;
|
|
3266
|
+
exports.CardHeader = CardHeader;
|
|
3267
|
+
exports.CardTitle = CardTitle;
|
|
3268
|
+
exports.DocQaPanel = DocQaPanel;
|
|
3269
|
+
exports.DocSearch = DocSearch;
|
|
2504
3270
|
exports.DocumentEntity = DocumentEntity;
|
|
2505
3271
|
exports.DocumentTable = DocumentTable;
|
|
2506
3272
|
exports.EmlIcon = EmlIcon;
|
|
@@ -2511,6 +3277,7 @@ exports.HoverCard = HoverCard;
|
|
|
2511
3277
|
exports.HoverCardContent = HoverCardContent;
|
|
2512
3278
|
exports.HoverCardTrigger = HoverCardTrigger;
|
|
2513
3279
|
exports.ImgIcon = ImgIcon;
|
|
3280
|
+
exports.Input = Input;
|
|
2514
3281
|
exports.PdfIcon = PdfIcon;
|
|
2515
3282
|
exports.ProjectEntity = ProjectEntity;
|
|
2516
3283
|
exports.TagEntity = TagEntity;
|
|
@@ -2523,7 +3290,11 @@ exports.arbiQueryKeys = arbiQueryKeys;
|
|
|
2523
3290
|
exports.badgeVariants = badgeVariants;
|
|
2524
3291
|
exports.buttonVariants = buttonVariants;
|
|
2525
3292
|
exports.cn = cn;
|
|
3293
|
+
exports.redlineStats = redlineStats;
|
|
3294
|
+
exports.textToArtifact = textToArtifact;
|
|
3295
|
+
exports.toRedlineMarkdown = toRedlineMarkdown;
|
|
2526
3296
|
exports.useAgents = useAgents;
|
|
3297
|
+
exports.useAiTask = useAiTask;
|
|
2527
3298
|
exports.useArbi = useArbi;
|
|
2528
3299
|
exports.useArbiUiStore = useArbiUiStore;
|
|
2529
3300
|
exports.useAssistantQuery = useAssistantQuery;
|
|
@@ -2533,9 +3304,11 @@ exports.useDeleteAgents = useDeleteAgents;
|
|
|
2533
3304
|
exports.useDocuments = useDocuments;
|
|
2534
3305
|
exports.useHealth = useHealth;
|
|
2535
3306
|
exports.useMemories = useMemories;
|
|
3307
|
+
exports.useSemanticSearch = useSemanticSearch;
|
|
2536
3308
|
exports.useSessions = useSessions;
|
|
2537
3309
|
exports.useTags = useTags;
|
|
2538
3310
|
exports.useTasks = useTasks;
|
|
3311
|
+
exports.useWorkspaceDocs = useWorkspaceDocs;
|
|
2539
3312
|
exports.useWorkspaces = useWorkspaces;
|
|
2540
3313
|
//# sourceMappingURL=index.cjs.map
|
|
2541
3314
|
//# sourceMappingURL=index.cjs.map
|