@tangle-network/agent-app 0.45.64 → 0.45.65
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/assistant/index.js +2 -2
- package/dist/chat-react/index.js +1 -1
- package/dist/{chunk-FZKNVQYP.js → chunk-23J72UUA.js} +104 -15
- package/dist/chunk-23J72UUA.js.map +1 -0
- package/dist/{chunk-OMGV3CX2.js → chunk-AWM4H5XR.js} +142 -34
- package/dist/chunk-AWM4H5XR.js.map +1 -0
- package/dist/stories/chat-controls/fixtures.d.ts +5 -1
- package/dist/web-react/chat-composer.d.ts +87 -5
- package/dist/web-react/composer-file-accept.d.ts +77 -0
- package/dist/web-react/index.d.ts +1 -0
- package/dist/web-react/index.js +10 -2
- package/dist/web-react/use-composer-attachments.d.ts +3 -4
- package/package.json +1 -1
- package/dist/chunk-FZKNVQYP.js.map +0 -1
- package/dist/chunk-OMGV3CX2.js.map +0 -1
|
@@ -12,9 +12,11 @@ import {
|
|
|
12
12
|
POPOVER_OPTION_FOCUS,
|
|
13
13
|
POPOVER_SURFACE_ATTR,
|
|
14
14
|
PopoverSurface,
|
|
15
|
+
filterAcceptedFiles,
|
|
16
|
+
renamePastedImages,
|
|
15
17
|
usePending,
|
|
16
18
|
usePopover
|
|
17
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-23J72UUA.js";
|
|
18
20
|
import {
|
|
19
21
|
AsyncView
|
|
20
22
|
} from "./chunk-3UBAO3N5.js";
|
|
@@ -1575,6 +1577,12 @@ function FolderGlyph({ className }) {
|
|
|
1575
1577
|
function CloseGlyph({ className }) {
|
|
1576
1578
|
return /* @__PURE__ */ jsx7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx7("path", { d: "M18 6 6 18M6 6l12 12" }) });
|
|
1577
1579
|
}
|
|
1580
|
+
function RetryGlyph({ className }) {
|
|
1581
|
+
return /* @__PURE__ */ jsxs5("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
1582
|
+
/* @__PURE__ */ jsx7("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
|
|
1583
|
+
/* @__PURE__ */ jsx7("path", { d: "M3 3v5h5" })
|
|
1584
|
+
] });
|
|
1585
|
+
}
|
|
1578
1586
|
function UploadGlyph({ className }) {
|
|
1579
1587
|
return /* @__PURE__ */ jsx7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx7("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M17 8l-5-5-5 5M12 3v12" }) });
|
|
1580
1588
|
}
|
|
@@ -1584,7 +1592,9 @@ function MicGlyph({ className }) {
|
|
|
1584
1592
|
/* @__PURE__ */ jsx7("path", { d: "M5 10v1a7 7 0 0 0 14 0v-1M12 18v4" })
|
|
1585
1593
|
] });
|
|
1586
1594
|
}
|
|
1587
|
-
var
|
|
1595
|
+
var DEFAULT_MAX_HEIGHT = 168;
|
|
1596
|
+
var LINE_HEIGHT = 24;
|
|
1597
|
+
var TEXTAREA_PADDING_Y = 8;
|
|
1588
1598
|
var DEFAULT_SEND_FAILURE = "Message not sent. Your draft is still here \u2014 try again.";
|
|
1589
1599
|
function isRejectedOutcome(outcome) {
|
|
1590
1600
|
return typeof outcome === "object" && outcome !== null && outcome.ok === false;
|
|
@@ -1622,9 +1632,19 @@ function ChatComposer({
|
|
|
1622
1632
|
onAttachFolder,
|
|
1623
1633
|
pendingFiles = [],
|
|
1624
1634
|
onRemoveFile,
|
|
1635
|
+
onRetryFile,
|
|
1625
1636
|
accept,
|
|
1637
|
+
onRejectFiles,
|
|
1626
1638
|
dropTitle = "Drop files to add context",
|
|
1627
1639
|
dropDescription = "They attach to your next message.",
|
|
1640
|
+
contextItems = [],
|
|
1641
|
+
canSubmitAttachmentsOnly = false,
|
|
1642
|
+
attachmentsNotReadyMessage,
|
|
1643
|
+
canSubmitWhileBusy = false,
|
|
1644
|
+
autoFocus,
|
|
1645
|
+
minRows = 2,
|
|
1646
|
+
maxHeight = DEFAULT_MAX_HEIGHT,
|
|
1647
|
+
trailing,
|
|
1628
1648
|
slashCommands,
|
|
1629
1649
|
onDictate,
|
|
1630
1650
|
onDictateError,
|
|
@@ -1644,6 +1664,7 @@ function ChatComposer({
|
|
|
1644
1664
|
const folderInputRef = useRef6(null);
|
|
1645
1665
|
const [dragOver, setDragOver] = useState8(false);
|
|
1646
1666
|
const dragDepth = useRef6(0);
|
|
1667
|
+
const pastedImageCount = useRef6(0);
|
|
1647
1668
|
const setText = useCallback3(
|
|
1648
1669
|
(next) => {
|
|
1649
1670
|
if (!isControlled) setInternal(next);
|
|
@@ -1671,8 +1692,8 @@ function ChatComposer({
|
|
|
1671
1692
|
const el = textareaRef.current;
|
|
1672
1693
|
if (!el) return;
|
|
1673
1694
|
el.style.height = "auto";
|
|
1674
|
-
el.style.height = `${Math.min(el.scrollHeight,
|
|
1675
|
-
}, [text]);
|
|
1695
|
+
el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;
|
|
1696
|
+
}, [text, maxHeight, minRows]);
|
|
1676
1697
|
const prevSeedRef = useRef6(null);
|
|
1677
1698
|
const pendingCaretRef = useRef6(null);
|
|
1678
1699
|
useEffect6(() => {
|
|
@@ -1721,9 +1742,10 @@ function ChatComposer({
|
|
|
1721
1742
|
document.addEventListener("keydown", onKeyDown);
|
|
1722
1743
|
return () => document.removeEventListener("keydown", onKeyDown);
|
|
1723
1744
|
}, [focusShortcut, disabled]);
|
|
1724
|
-
const
|
|
1725
|
-
const hasSendable = text.trim().length > 0 ||
|
|
1726
|
-
const
|
|
1745
|
+
const sendableFiles = canSubmitAttachmentsOnly ? pendingFiles : pendingFiles.filter((f) => f.status === "ready");
|
|
1746
|
+
const hasSendable = text.trim().length > 0 || sendableFiles.length > 0;
|
|
1747
|
+
const sendBlockedByStream = isStreaming && !canSubmitWhileBusy;
|
|
1748
|
+
const canSend = hasSendable && !sendBlockedByStream && !disabled;
|
|
1727
1749
|
const [failedSend, setFailedSend] = useState8(null);
|
|
1728
1750
|
const failSend = useCallback3(
|
|
1729
1751
|
(error, draft, trimmed, parts, caret) => {
|
|
@@ -1768,9 +1790,15 @@ function ChatComposer({
|
|
|
1768
1790
|
);
|
|
1769
1791
|
const send = useCallback3(() => {
|
|
1770
1792
|
const trimmed = text.trim();
|
|
1771
|
-
if (
|
|
1793
|
+
if (sendBlockedByStream || disabled) return;
|
|
1772
1794
|
const readyFiles = pendingFiles.filter((f) => f.status === "ready");
|
|
1773
|
-
|
|
1795
|
+
const sendable = canSubmitAttachmentsOnly ? pendingFiles : readyFiles;
|
|
1796
|
+
if (!trimmed && sendable.length === 0) return;
|
|
1797
|
+
if (!trimmed && readyFiles.length === 0) {
|
|
1798
|
+
const message = attachmentsNotReadyMessage ?? (pendingFiles.some((f) => f.status === "error") ? "Retry or remove the failed attachment before sending." : "Wait for the attachment to finish uploading.");
|
|
1799
|
+
setFailedSend({ message, text: "", trimmed: "", parts: [], restored: true });
|
|
1800
|
+
return;
|
|
1801
|
+
}
|
|
1774
1802
|
const parts = onSendParts ? readyFiles.filter((f) => f.part).map((f) => f.part) : [];
|
|
1775
1803
|
const el = textareaRef.current;
|
|
1776
1804
|
const caret = { start: el?.selectionStart ?? text.length, end: el?.selectionEnd ?? text.length };
|
|
@@ -1778,14 +1806,24 @@ function ChatComposer({
|
|
|
1778
1806
|
setText("");
|
|
1779
1807
|
textRef.current = "";
|
|
1780
1808
|
dispatchSend(text, trimmed, parts, caret);
|
|
1781
|
-
}, [
|
|
1809
|
+
}, [
|
|
1810
|
+
text,
|
|
1811
|
+
sendBlockedByStream,
|
|
1812
|
+
disabled,
|
|
1813
|
+
canSubmitAttachmentsOnly,
|
|
1814
|
+
attachmentsNotReadyMessage,
|
|
1815
|
+
onSendParts,
|
|
1816
|
+
pendingFiles,
|
|
1817
|
+
setText,
|
|
1818
|
+
dispatchSend
|
|
1819
|
+
]);
|
|
1782
1820
|
const retryFailedSend = useCallback3(() => {
|
|
1783
1821
|
const failure = failedSend;
|
|
1784
|
-
if (!failure ||
|
|
1822
|
+
if (!failure || sendBlockedByStream || disabled) return;
|
|
1785
1823
|
setFailedSend(null);
|
|
1786
1824
|
const caret = { start: failure.text.length, end: failure.text.length };
|
|
1787
1825
|
dispatchSend(failure.text, failure.trimmed, failure.parts, caret);
|
|
1788
|
-
}, [failedSend,
|
|
1826
|
+
}, [failedSend, sendBlockedByStream, disabled, dispatchSend]);
|
|
1789
1827
|
const slashPanelRef = useRef6(null);
|
|
1790
1828
|
const cardRef = useRef6(null);
|
|
1791
1829
|
const slashListId = useId();
|
|
@@ -1868,10 +1906,40 @@ function ChatComposer({
|
|
|
1868
1906
|
send();
|
|
1869
1907
|
}
|
|
1870
1908
|
};
|
|
1909
|
+
const deliverFiles = useCallback3(
|
|
1910
|
+
(files, original) => {
|
|
1911
|
+
if (!onAttach || files.length === 0) return;
|
|
1912
|
+
const { accepted, rejected } = filterAcceptedFiles(files, accept);
|
|
1913
|
+
if (rejected.length > 0) onRejectFiles?.(rejected);
|
|
1914
|
+
if (accepted.length === 0) return;
|
|
1915
|
+
const unchanged = accepted.length === original.length && accepted.every((file, i) => file === original[i]);
|
|
1916
|
+
if (unchanged) {
|
|
1917
|
+
onAttach(original);
|
|
1918
|
+
return;
|
|
1919
|
+
}
|
|
1920
|
+
const transfer = new DataTransfer();
|
|
1921
|
+
for (const file of accepted) transfer.items.add(file);
|
|
1922
|
+
onAttach(transfer.files);
|
|
1923
|
+
},
|
|
1924
|
+
[onAttach, onRejectFiles, accept]
|
|
1925
|
+
);
|
|
1871
1926
|
const handleFileChange = (e) => {
|
|
1872
|
-
if (e.target.files?.length)
|
|
1927
|
+
if (e.target.files?.length) deliverFiles(Array.from(e.target.files), e.target.files);
|
|
1873
1928
|
e.target.value = "";
|
|
1874
1929
|
};
|
|
1930
|
+
const handlePaste = (e) => {
|
|
1931
|
+
if (!onAttach) return;
|
|
1932
|
+
const clipboardFiles = e.clipboardData?.files;
|
|
1933
|
+
if (!clipboardFiles || clipboardFiles.length === 0) return;
|
|
1934
|
+
e.preventDefault();
|
|
1935
|
+
const { files, nextIndex } = renamePastedImages(
|
|
1936
|
+
Array.from(clipboardFiles),
|
|
1937
|
+
pastedImageCount.current,
|
|
1938
|
+
pendingFiles.map((f) => f.name)
|
|
1939
|
+
);
|
|
1940
|
+
pastedImageCount.current = nextIndex;
|
|
1941
|
+
deliverFiles(files, clipboardFiles);
|
|
1942
|
+
};
|
|
1875
1943
|
const handleFolderChange = (e) => {
|
|
1876
1944
|
if (e.target.files?.length) (onAttachFolder ?? onAttach)?.(e.target.files);
|
|
1877
1945
|
e.target.value = "";
|
|
@@ -1903,9 +1971,9 @@ function ChatComposer({
|
|
|
1903
1971
|
dragDepth.current = 0;
|
|
1904
1972
|
setDragOver(false);
|
|
1905
1973
|
const files = e.dataTransfer?.files;
|
|
1906
|
-
if (files?.length)
|
|
1974
|
+
if (files?.length) deliverFiles(Array.from(files), files);
|
|
1907
1975
|
},
|
|
1908
|
-
[
|
|
1976
|
+
[deliverFiles]
|
|
1909
1977
|
);
|
|
1910
1978
|
const folderChips = pendingFiles.filter((f) => f.kind === "folder");
|
|
1911
1979
|
const fileChips = pendingFiles.filter((f) => f.kind !== "folder");
|
|
@@ -1982,7 +2050,7 @@ function ChatComposer({
|
|
|
1982
2050
|
type: "button",
|
|
1983
2051
|
"aria-label": "Retry sending the unsent message",
|
|
1984
2052
|
onClick: retryFailedSend,
|
|
1985
|
-
disabled:
|
|
2053
|
+
disabled: sendBlockedByStream || disabled,
|
|
1986
2054
|
className: "mt-1.5 font-medium underline-offset-2 hover:underline disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-destructive/50",
|
|
1987
2055
|
children: "Retry"
|
|
1988
2056
|
}
|
|
@@ -1991,33 +2059,69 @@ function ChatComposer({
|
|
|
1991
2059
|
]
|
|
1992
2060
|
}
|
|
1993
2061
|
),
|
|
1994
|
-
|
|
2062
|
+
contextItems.length > 0 && /* @__PURE__ */ jsx7("div", { "aria-label": "Message context", className: "mb-2 flex min-w-0 flex-wrap gap-1.5", children: contextItems.map((item) => /* @__PURE__ */ jsxs5(
|
|
1995
2063
|
"span",
|
|
1996
2064
|
{
|
|
1997
|
-
className:
|
|
2065
|
+
className: "inline-flex min-w-0 max-w-full items-center gap-1.5 rounded-md border border-primary/30 bg-primary/10 px-2.5 py-1 text-xs text-primary",
|
|
1998
2066
|
children: [
|
|
1999
|
-
|
|
2000
|
-
/* @__PURE__ */ jsx7("span", { className: "
|
|
2001
|
-
|
|
2002
|
-
"(",
|
|
2003
|
-
f.fileCount,
|
|
2004
|
-
")"
|
|
2005
|
-
] }),
|
|
2006
|
-
f.status === "uploading" && /* @__PURE__ */ jsx7("span", { className: "h-3 w-3 animate-spin rounded-full border-2 border-primary border-t-transparent" }),
|
|
2007
|
-
onRemoveFile && /* @__PURE__ */ jsx7(
|
|
2067
|
+
item.icon && /* @__PURE__ */ jsx7("span", { className: "shrink-0", "aria-hidden": true, children: item.icon }),
|
|
2068
|
+
/* @__PURE__ */ jsx7("span", { className: "min-w-0 truncate", children: item.label }),
|
|
2069
|
+
item.onRemove && /* @__PURE__ */ jsx7(
|
|
2008
2070
|
"button",
|
|
2009
2071
|
{
|
|
2010
2072
|
type: "button",
|
|
2011
|
-
"aria-label": `Remove ${
|
|
2012
|
-
onClick:
|
|
2013
|
-
className: "rounded p-0.5 text-
|
|
2073
|
+
"aria-label": `Remove context ${item.label}`,
|
|
2074
|
+
onClick: item.onRemove,
|
|
2075
|
+
className: "shrink-0 rounded p-0.5 text-primary/70 transition hover:text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
2014
2076
|
children: /* @__PURE__ */ jsx7(CloseGlyph, { className: "h-3 w-3" })
|
|
2015
2077
|
}
|
|
2016
2078
|
)
|
|
2017
2079
|
]
|
|
2018
2080
|
},
|
|
2019
|
-
|
|
2081
|
+
item.id
|
|
2020
2082
|
)) }),
|
|
2083
|
+
pendingFiles.length > 0 && /* @__PURE__ */ jsx7("div", { className: "mb-2 flex flex-wrap gap-1.5", children: [...folderChips, ...fileChips].map((f) => {
|
|
2084
|
+
const isError = f.status === "error";
|
|
2085
|
+
return /* @__PURE__ */ jsxs5(
|
|
2086
|
+
"span",
|
|
2087
|
+
{
|
|
2088
|
+
title: isError ? f.errorMessage : void 0,
|
|
2089
|
+
className: `inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs ${isError ? "border-destructive/40 text-destructive" : "border-border bg-secondary text-foreground"} ${f.status === "pending" ? "opacity-60" : ""}`,
|
|
2090
|
+
children: [
|
|
2091
|
+
f.kind !== "folder" && f.previewUrl ? /* @__PURE__ */ jsx7("img", { src: f.previewUrl, alt: "", className: "h-8 w-8 shrink-0 rounded object-cover" }) : f.kind === "folder" ? /* @__PURE__ */ jsx7(FolderGlyph, { className: "h-3 w-3 shrink-0" }) : /* @__PURE__ */ jsx7(PaperclipGlyph, { className: "h-3 w-3 shrink-0" }),
|
|
2092
|
+
/* @__PURE__ */ jsx7("span", { className: "max-w-[150px] truncate", children: f.name }),
|
|
2093
|
+
f.fileCount !== void 0 && /* @__PURE__ */ jsxs5("span", { className: "text-muted-foreground", children: [
|
|
2094
|
+
"(",
|
|
2095
|
+
f.fileCount,
|
|
2096
|
+
")"
|
|
2097
|
+
] }),
|
|
2098
|
+
f.status === "uploading" && /* @__PURE__ */ jsx7("span", { className: "h-3 w-3 animate-spin rounded-full border-2 border-primary border-t-transparent" }),
|
|
2099
|
+
isError && f.errorMessage && /* @__PURE__ */ jsx7("span", { className: "max-w-[150px] truncate text-destructive/80", children: f.errorMessage }),
|
|
2100
|
+
isError && onRetryFile && /* @__PURE__ */ jsx7(
|
|
2101
|
+
"button",
|
|
2102
|
+
{
|
|
2103
|
+
type: "button",
|
|
2104
|
+
"aria-label": `Retry upload ${f.name}`,
|
|
2105
|
+
onClick: () => onRetryFile(f.id),
|
|
2106
|
+
className: "rounded p-0.5 text-muted-foreground transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
2107
|
+
children: /* @__PURE__ */ jsx7(RetryGlyph, { className: "h-3 w-3" })
|
|
2108
|
+
}
|
|
2109
|
+
),
|
|
2110
|
+
onRemoveFile && /* @__PURE__ */ jsx7(
|
|
2111
|
+
"button",
|
|
2112
|
+
{
|
|
2113
|
+
type: "button",
|
|
2114
|
+
"aria-label": `Remove ${f.name}`,
|
|
2115
|
+
onClick: () => onRemoveFile(f.id),
|
|
2116
|
+
className: "rounded p-0.5 text-muted-foreground transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
2117
|
+
children: /* @__PURE__ */ jsx7(CloseGlyph, { className: "h-3 w-3" })
|
|
2118
|
+
}
|
|
2119
|
+
)
|
|
2120
|
+
]
|
|
2121
|
+
},
|
|
2122
|
+
f.id
|
|
2123
|
+
);
|
|
2124
|
+
}) }),
|
|
2021
2125
|
/* @__PURE__ */ jsxs5(
|
|
2022
2126
|
"div",
|
|
2023
2127
|
{
|
|
@@ -2032,11 +2136,14 @@ function ChatComposer({
|
|
|
2032
2136
|
value: text,
|
|
2033
2137
|
onChange: (e) => setText(e.target.value),
|
|
2034
2138
|
onKeyDown: handleKeyDown,
|
|
2139
|
+
onPaste: onAttach ? handlePaste : void 0,
|
|
2035
2140
|
placeholder,
|
|
2036
2141
|
disabled,
|
|
2037
|
-
|
|
2142
|
+
autoFocus,
|
|
2143
|
+
rows: minRows,
|
|
2144
|
+
style: { minHeight: minRows * LINE_HEIGHT + TEXTAREA_PADDING_Y, maxHeight },
|
|
2038
2145
|
"aria-label": "Message input",
|
|
2039
|
-
className: "
|
|
2146
|
+
className: "w-full resize-none bg-transparent px-1.5 py-1 text-base leading-6 text-foreground outline-none placeholder:text-muted-foreground disabled:opacity-50"
|
|
2040
2147
|
}
|
|
2041
2148
|
),
|
|
2042
2149
|
/* @__PURE__ */ jsxs5("div", { className: "flex items-end gap-2", children: [
|
|
@@ -2088,6 +2195,7 @@ function ChatComposer({
|
|
|
2088
2195
|
children: showInline && controls
|
|
2089
2196
|
}
|
|
2090
2197
|
),
|
|
2198
|
+
trailing && /* @__PURE__ */ jsx7("div", { "data-testid": "composer-trailing", className: "flex shrink-0 items-center gap-1.5", children: trailing }),
|
|
2091
2199
|
onDictate && dictation.supported ? dictation.recording ? /* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
2092
2200
|
/* @__PURE__ */ jsx7("span", { "aria-hidden": "true", className: "h-2 w-2 animate-pulse rounded-full bg-destructive" }),
|
|
2093
2201
|
/* @__PURE__ */ jsx7(
|
|
@@ -7569,4 +7677,4 @@ export {
|
|
|
7569
7677
|
useThinkingSeconds,
|
|
7570
7678
|
ChatMessages
|
|
7571
7679
|
};
|
|
7572
|
-
//# sourceMappingURL=chunk-
|
|
7680
|
+
//# sourceMappingURL=chunk-AWM4H5XR.js.map
|