@pactor-app/ui 1.44.0 → 1.46.0
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/{chunk-SD2XSQIP.js → chunk-FU4P7CAM.js} +4 -0
- package/dist/{chunk-A6WUHUJL.js → chunk-JV2V4HCI.js} +1 -1
- package/dist/{chunk-3PQOJRJD.js → chunk-QB2RZXDD.js} +35 -2450
- package/dist/{chunk-T3TGKYAB.js → chunk-XA7J5SGA.js} +16 -121
- package/dist/components/index.cjs +39 -2524
- package/dist/components/index.d.cts +16 -846
- package/dist/components/index.d.ts +16 -846
- package/dist/components/index.js +7 -43
- package/dist/index.cjs +375 -2860
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +16 -52
- package/dist/layout/index.cjs +2 -0
- package/dist/layout/index.js +2 -2
- package/dist/ui/index.cjs +1138 -560
- package/dist/ui/index.d.cts +219 -16
- package/dist/ui/index.d.ts +219 -16
- package/dist/ui/index.js +721 -44
- package/package.json +10 -8
- package/src/theme-bridge.css +54 -0
- package/styles.css +87 -183
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
Icon,
|
|
3
3
|
Menu,
|
|
4
4
|
Sidebar
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-FU4P7CAM.js";
|
|
6
6
|
import {
|
|
7
7
|
Alert,
|
|
8
8
|
AlertDescription,
|
|
@@ -27,8 +27,6 @@ import {
|
|
|
27
27
|
BreadcrumbList,
|
|
28
28
|
BreadcrumbPage,
|
|
29
29
|
BreadcrumbSeparator,
|
|
30
|
-
Bubble,
|
|
31
|
-
BubbleContent,
|
|
32
30
|
ButtonGroup,
|
|
33
31
|
Calendar,
|
|
34
32
|
Carousel,
|
|
@@ -140,7 +138,20 @@ import {
|
|
|
140
138
|
Typography,
|
|
141
139
|
navigationMenuTriggerStyle,
|
|
142
140
|
toast
|
|
143
|
-
} from "./chunk-
|
|
141
|
+
} from "./chunk-XA7J5SGA.js";
|
|
142
|
+
import {
|
|
143
|
+
Dialog,
|
|
144
|
+
DialogContent,
|
|
145
|
+
DialogDescription,
|
|
146
|
+
DialogHeader,
|
|
147
|
+
DialogTitle,
|
|
148
|
+
DialogTrigger,
|
|
149
|
+
Drawer,
|
|
150
|
+
DrawerContent,
|
|
151
|
+
DrawerFooter,
|
|
152
|
+
DrawerHeader,
|
|
153
|
+
DrawerTitle
|
|
154
|
+
} from "./chunk-YVHPJHW3.js";
|
|
144
155
|
import {
|
|
145
156
|
Accordion,
|
|
146
157
|
AccordionContent,
|
|
@@ -164,19 +175,6 @@ import {
|
|
|
164
175
|
TooltipContent,
|
|
165
176
|
TooltipTrigger
|
|
166
177
|
} from "./chunk-7OBUSV5S.js";
|
|
167
|
-
import {
|
|
168
|
-
Dialog,
|
|
169
|
-
DialogContent,
|
|
170
|
-
DialogDescription,
|
|
171
|
-
DialogHeader,
|
|
172
|
-
DialogTitle,
|
|
173
|
-
DialogTrigger,
|
|
174
|
-
Drawer,
|
|
175
|
-
DrawerContent,
|
|
176
|
-
DrawerFooter,
|
|
177
|
-
DrawerHeader,
|
|
178
|
-
DrawerTitle
|
|
179
|
-
} from "./chunk-YVHPJHW3.js";
|
|
180
178
|
import {
|
|
181
179
|
Button,
|
|
182
180
|
buttonVariants,
|
|
@@ -184,7 +182,7 @@ import {
|
|
|
184
182
|
} from "./chunk-WKJUCGV4.js";
|
|
185
183
|
|
|
186
184
|
// src/components/register.ts
|
|
187
|
-
import { Registry
|
|
185
|
+
import { Registry } from "@pactor-app/core";
|
|
188
186
|
|
|
189
187
|
// src/components/components/Accordion/index.tsx
|
|
190
188
|
import { useRenderer } from "@pactor-app/runtime";
|
|
@@ -1821,19 +1819,28 @@ function Command2({
|
|
|
1821
1819
|
// src/components/components/ChatInput/index.tsx
|
|
1822
1820
|
import { useI18n as useI18n8 } from "@pactor-app/runtime";
|
|
1823
1821
|
import { useRenderer as useRenderer6 } from "@pactor-app/runtime";
|
|
1824
|
-
import { ArrowUp } from "lucide-react";
|
|
1822
|
+
import { ArrowUp, Square } from "lucide-react";
|
|
1825
1823
|
import {
|
|
1826
1824
|
isValidElement,
|
|
1827
1825
|
useRef as useRef3,
|
|
1828
1826
|
useState as useState10
|
|
1829
1827
|
} from "react";
|
|
1830
1828
|
import { jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1829
|
+
function useOptionalRenderer() {
|
|
1830
|
+
try {
|
|
1831
|
+
return useRenderer6();
|
|
1832
|
+
} catch {
|
|
1833
|
+
return null;
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1831
1836
|
function ChatInput({
|
|
1832
1837
|
value,
|
|
1833
1838
|
placeholder,
|
|
1834
1839
|
disabled,
|
|
1835
1840
|
rows = 3,
|
|
1836
1841
|
hideSend,
|
|
1842
|
+
streaming = false,
|
|
1843
|
+
onStop,
|
|
1837
1844
|
toolbarStart,
|
|
1838
1845
|
toolbarEnd,
|
|
1839
1846
|
header,
|
|
@@ -1844,14 +1851,14 @@ function ChatInput({
|
|
|
1844
1851
|
className,
|
|
1845
1852
|
style
|
|
1846
1853
|
}) {
|
|
1847
|
-
const
|
|
1854
|
+
const renderer = useOptionalRenderer();
|
|
1848
1855
|
const controlled = value !== void 0;
|
|
1849
1856
|
const [draft, setDraft] = useState10("");
|
|
1850
1857
|
const { t } = useI18n8();
|
|
1851
1858
|
const text = controlled ? value : draft;
|
|
1852
1859
|
const canSubmit = !disabled && text.trim() !== "";
|
|
1853
1860
|
const customField = field !== void 0 && field !== null;
|
|
1854
|
-
const renderSlot = (slot) => isValidElement(slot) || typeof slot !== "object" || slot === null ? slot : renderChildren([slot]);
|
|
1861
|
+
const renderSlot = (slot) => isValidElement(slot) || typeof slot !== "object" || slot === null ? slot : renderer?.renderChildren([slot]) ?? null;
|
|
1855
1862
|
const composingRef = useRef3(false);
|
|
1856
1863
|
const handleChange = (next) => {
|
|
1857
1864
|
if (!controlled) {
|
|
@@ -1911,11 +1918,11 @@ function ChatInput({
|
|
|
1911
1918
|
{
|
|
1912
1919
|
type: "button",
|
|
1913
1920
|
size: "icon",
|
|
1914
|
-
"aria-label": t("pactor.chatInput.send"),
|
|
1915
|
-
disabled: !canSubmit,
|
|
1916
|
-
onClick: submit,
|
|
1921
|
+
"aria-label": streaming ? t("pactor.chatInput.stop") : t("pactor.chatInput.send"),
|
|
1922
|
+
disabled: streaming ? false : !canSubmit,
|
|
1923
|
+
onClick: streaming ? () => onStop?.() : submit,
|
|
1917
1924
|
className: "size-8 rounded-full",
|
|
1918
|
-
children: /* @__PURE__ */ jsx29(ArrowUp, {})
|
|
1925
|
+
children: streaming ? /* @__PURE__ */ jsx29(Square, {}) : /* @__PURE__ */ jsx29(ArrowUp, {})
|
|
1919
1926
|
}
|
|
1920
1927
|
)
|
|
1921
1928
|
] }) : null,
|
|
@@ -8730,2391 +8737,6 @@ function Watermark({
|
|
|
8730
8737
|
);
|
|
8731
8738
|
}
|
|
8732
8739
|
|
|
8733
|
-
// src/components/chat/AgentStatus/index.tsx
|
|
8734
|
-
import { jsx as jsx117, jsxs as jsxs78 } from "react/jsx-runtime";
|
|
8735
|
-
var statusMeta = {
|
|
8736
|
-
running: { icon: "loader-circle", className: "text-info", spin: true },
|
|
8737
|
-
waiting: { icon: "clock", className: "text-warning" },
|
|
8738
|
-
done: { icon: "circle-check", className: "text-success" },
|
|
8739
|
-
error: { icon: "circle-x", className: "text-destructive" }
|
|
8740
|
-
};
|
|
8741
|
-
function AgentStatus({ status = "running", text, elapsed, className, style }) {
|
|
8742
|
-
const meta = statusMeta[status];
|
|
8743
|
-
return /* @__PURE__ */ jsxs78(
|
|
8744
|
-
"div",
|
|
8745
|
-
{
|
|
8746
|
-
"data-slot": "agent-status",
|
|
8747
|
-
"data-status": status,
|
|
8748
|
-
className: cn("flex items-center gap-2 text-sm", className),
|
|
8749
|
-
style,
|
|
8750
|
-
children: [
|
|
8751
|
-
/* @__PURE__ */ jsx117("span", { className: cn(meta.className, meta.spin && "animate-spin motion-reduce:animate-none"), children: /* @__PURE__ */ jsx117(Icon, { name: meta.icon, size: "sm" }) }),
|
|
8752
|
-
text ? /* @__PURE__ */ jsx117("span", { "data-slot": "agent-status-text", children: text }) : null,
|
|
8753
|
-
elapsed !== void 0 ? /* @__PURE__ */ jsxs78("span", { "data-slot": "agent-status-elapsed", className: "text-xs text-muted-foreground", children: [
|
|
8754
|
-
"\u5DF2\u7528\u65F6 ",
|
|
8755
|
-
elapsed,
|
|
8756
|
-
"s"
|
|
8757
|
-
] }) : null
|
|
8758
|
-
]
|
|
8759
|
-
}
|
|
8760
|
-
);
|
|
8761
|
-
}
|
|
8762
|
-
|
|
8763
|
-
// src/components/chat/ArtifactPanel/index.tsx
|
|
8764
|
-
import { useEffect as useEffect35, useState as useState39 } from "react";
|
|
8765
|
-
|
|
8766
|
-
// src/components/chat/ArtifactPanel/artifact.ts
|
|
8767
|
-
var ARTIFACT_IMAGE_EXTENSIONS = [
|
|
8768
|
-
"png",
|
|
8769
|
-
"jpg",
|
|
8770
|
-
"jpeg",
|
|
8771
|
-
"gif",
|
|
8772
|
-
"svg",
|
|
8773
|
-
"webp",
|
|
8774
|
-
"avif",
|
|
8775
|
-
"bmp",
|
|
8776
|
-
"ico"
|
|
8777
|
-
];
|
|
8778
|
-
function resolveArtifactFileType(artifact) {
|
|
8779
|
-
const declared = artifact.fileType?.trim().toLowerCase().replace(/^\./, "");
|
|
8780
|
-
if (declared) {
|
|
8781
|
-
return declared;
|
|
8782
|
-
}
|
|
8783
|
-
const match = /\.([A-Za-z0-9]+)$/.exec(artifact.title.trim());
|
|
8784
|
-
return match ? match[1].toLowerCase() : null;
|
|
8785
|
-
}
|
|
8786
|
-
function isImageArtifact(artifact) {
|
|
8787
|
-
const ext = resolveArtifactFileType(artifact);
|
|
8788
|
-
return ext !== null && ARTIFACT_IMAGE_EXTENSIONS.includes(ext);
|
|
8789
|
-
}
|
|
8790
|
-
var ARTIFACT_ICON_BY_EXTENSION = {
|
|
8791
|
-
// 表格数据
|
|
8792
|
-
csv: "table",
|
|
8793
|
-
tsv: "table",
|
|
8794
|
-
xls: "table",
|
|
8795
|
-
xlsx: "table",
|
|
8796
|
-
// 数据 / 数据库
|
|
8797
|
-
json: "database",
|
|
8798
|
-
sql: "database",
|
|
8799
|
-
// 脚本
|
|
8800
|
-
sh: "terminal",
|
|
8801
|
-
bash: "terminal",
|
|
8802
|
-
zsh: "terminal",
|
|
8803
|
-
// 代码 / 配置
|
|
8804
|
-
js: "code",
|
|
8805
|
-
mjs: "code",
|
|
8806
|
-
cjs: "code",
|
|
8807
|
-
jsx: "code",
|
|
8808
|
-
ts: "code",
|
|
8809
|
-
mts: "code",
|
|
8810
|
-
cts: "code",
|
|
8811
|
-
tsx: "code",
|
|
8812
|
-
py: "code",
|
|
8813
|
-
rb: "code",
|
|
8814
|
-
go: "code",
|
|
8815
|
-
rs: "code",
|
|
8816
|
-
java: "code",
|
|
8817
|
-
kt: "code",
|
|
8818
|
-
c: "code",
|
|
8819
|
-
h: "code",
|
|
8820
|
-
cc: "code",
|
|
8821
|
-
cpp: "code",
|
|
8822
|
-
cs: "code",
|
|
8823
|
-
swift: "code",
|
|
8824
|
-
php: "code",
|
|
8825
|
-
css: "code",
|
|
8826
|
-
scss: "code",
|
|
8827
|
-
less: "code",
|
|
8828
|
-
html: "code",
|
|
8829
|
-
vue: "code",
|
|
8830
|
-
svelte: "code",
|
|
8831
|
-
yaml: "code",
|
|
8832
|
-
yml: "code",
|
|
8833
|
-
toml: "code",
|
|
8834
|
-
xml: "code",
|
|
8835
|
-
// 文档 / 文本
|
|
8836
|
-
md: "file-text",
|
|
8837
|
-
markdown: "file-text",
|
|
8838
|
-
mdx: "file-text",
|
|
8839
|
-
txt: "file-text",
|
|
8840
|
-
text: "file-text",
|
|
8841
|
-
log: "file-text",
|
|
8842
|
-
rst: "file-text",
|
|
8843
|
-
pdf: "file-text",
|
|
8844
|
-
doc: "file-text",
|
|
8845
|
-
docx: "file-text"
|
|
8846
|
-
};
|
|
8847
|
-
function resolveArtifactIconName(artifact) {
|
|
8848
|
-
const ext = resolveArtifactFileType(artifact);
|
|
8849
|
-
if (ext !== null) {
|
|
8850
|
-
if (ARTIFACT_IMAGE_EXTENSIONS.includes(ext)) {
|
|
8851
|
-
return "image";
|
|
8852
|
-
}
|
|
8853
|
-
const name = ARTIFACT_ICON_BY_EXTENSION[ext];
|
|
8854
|
-
if (name !== void 0) {
|
|
8855
|
-
return name;
|
|
8856
|
-
}
|
|
8857
|
-
}
|
|
8858
|
-
if (artifact.kind === "code") {
|
|
8859
|
-
return "code";
|
|
8860
|
-
}
|
|
8861
|
-
if (artifact.kind === "dsl") {
|
|
8862
|
-
return "layout-grid";
|
|
8863
|
-
}
|
|
8864
|
-
return ext === null ? "file-text" : "file";
|
|
8865
|
-
}
|
|
8866
|
-
function buildArtifactTree(artifacts) {
|
|
8867
|
-
const root = { name: "", path: "", children: [] };
|
|
8868
|
-
for (const artifact of artifacts) {
|
|
8869
|
-
const segments = artifact.id.split("/").filter(Boolean);
|
|
8870
|
-
let node = root;
|
|
8871
|
-
for (let i = 0; i < segments.length - 1; i++) {
|
|
8872
|
-
const path = segments.slice(0, i + 1).join("/");
|
|
8873
|
-
let child = node.children.find(
|
|
8874
|
-
(item) => item.path === path && item.artifact === void 0
|
|
8875
|
-
);
|
|
8876
|
-
if (!child) {
|
|
8877
|
-
child = { name: segments[i], path, children: [] };
|
|
8878
|
-
node.children.push(child);
|
|
8879
|
-
}
|
|
8880
|
-
node = child;
|
|
8881
|
-
}
|
|
8882
|
-
node.children.push({
|
|
8883
|
-
name: artifact.title,
|
|
8884
|
-
path: artifact.id,
|
|
8885
|
-
artifact,
|
|
8886
|
-
children: []
|
|
8887
|
-
});
|
|
8888
|
-
}
|
|
8889
|
-
const sortLevel = (nodes) => {
|
|
8890
|
-
nodes.sort((a, b) => {
|
|
8891
|
-
const dirDelta = Number(b.artifact === void 0) - Number(a.artifact === void 0);
|
|
8892
|
-
return dirDelta !== 0 ? dirDelta : a.name.localeCompare(b.name);
|
|
8893
|
-
});
|
|
8894
|
-
for (const item of nodes) {
|
|
8895
|
-
sortLevel(item.children);
|
|
8896
|
-
}
|
|
8897
|
-
};
|
|
8898
|
-
sortLevel(root.children);
|
|
8899
|
-
return root.children;
|
|
8900
|
-
}
|
|
8901
|
-
|
|
8902
|
-
// src/components/chat/ArtifactPanel/download.ts
|
|
8903
|
-
var KIND_EXTENSIONS = {
|
|
8904
|
-
markdown: "md",
|
|
8905
|
-
text: "txt",
|
|
8906
|
-
code: "txt",
|
|
8907
|
-
dsl: "json"
|
|
8908
|
-
};
|
|
8909
|
-
function resolveArtifactFilename(artifact) {
|
|
8910
|
-
const title = artifact.title.trim() || "artifact";
|
|
8911
|
-
if (/\.[A-Za-z0-9]+$/.test(title)) {
|
|
8912
|
-
return title;
|
|
8913
|
-
}
|
|
8914
|
-
const ext = resolveArtifactFileType(artifact) ?? KIND_EXTENSIONS[artifact.kind];
|
|
8915
|
-
return `${title}.${ext}`;
|
|
8916
|
-
}
|
|
8917
|
-
function dataUrlToBlob(dataUrl) {
|
|
8918
|
-
const comma = dataUrl.indexOf(",");
|
|
8919
|
-
const meta = dataUrl.slice(0, comma);
|
|
8920
|
-
const payload = dataUrl.slice(comma + 1);
|
|
8921
|
-
const mime = /^data:([^;,]+)/.exec(meta)?.[1] ?? "application/octet-stream";
|
|
8922
|
-
if (meta.includes(";base64")) {
|
|
8923
|
-
const binary = atob(payload);
|
|
8924
|
-
const bytes = new Uint8Array(binary.length);
|
|
8925
|
-
for (let i = 0; i < binary.length; i++) {
|
|
8926
|
-
bytes[i] = binary.charCodeAt(i);
|
|
8927
|
-
}
|
|
8928
|
-
return new Blob([bytes], { type: mime });
|
|
8929
|
-
}
|
|
8930
|
-
return new Blob([decodeURIComponent(payload)], { type: mime });
|
|
8931
|
-
}
|
|
8932
|
-
function isRemoteUrl(raw) {
|
|
8933
|
-
return /^https?:\/\//.test(raw.trim());
|
|
8934
|
-
}
|
|
8935
|
-
function buildArtifactBlob(artifact) {
|
|
8936
|
-
if (artifact.kind === "dsl" && typeof artifact.content === "object") {
|
|
8937
|
-
return new Blob([JSON.stringify(artifact.content, null, 2)], {
|
|
8938
|
-
type: "application/json"
|
|
8939
|
-
});
|
|
8940
|
-
}
|
|
8941
|
-
const raw = String(artifact.content);
|
|
8942
|
-
if (isImageArtifact(artifact)) {
|
|
8943
|
-
const trimmed = raw.trim();
|
|
8944
|
-
if (trimmed.startsWith("data:")) {
|
|
8945
|
-
return dataUrlToBlob(trimmed);
|
|
8946
|
-
}
|
|
8947
|
-
if (trimmed.startsWith("<svg") || trimmed.startsWith("<?xml")) {
|
|
8948
|
-
return new Blob([raw], { type: "image/svg+xml" });
|
|
8949
|
-
}
|
|
8950
|
-
if (isRemoteUrl(trimmed)) {
|
|
8951
|
-
return null;
|
|
8952
|
-
}
|
|
8953
|
-
}
|
|
8954
|
-
const ext = resolveArtifactFileType(artifact);
|
|
8955
|
-
const mime = ext === "md" || artifact.kind === "markdown" ? "text/markdown" : "text/plain";
|
|
8956
|
-
return new Blob([raw], { type: `${mime};charset=utf-8` });
|
|
8957
|
-
}
|
|
8958
|
-
function saveBlob(blob, filename) {
|
|
8959
|
-
const url = URL.createObjectURL(blob);
|
|
8960
|
-
const anchor = document.createElement("a");
|
|
8961
|
-
anchor.href = url;
|
|
8962
|
-
anchor.download = filename;
|
|
8963
|
-
document.body.appendChild(anchor);
|
|
8964
|
-
anchor.click();
|
|
8965
|
-
anchor.remove();
|
|
8966
|
-
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
8967
|
-
}
|
|
8968
|
-
async function downloadArtifact(artifact) {
|
|
8969
|
-
const filename = resolveArtifactFilename(artifact);
|
|
8970
|
-
const raw = String(artifact.content ?? "").trim();
|
|
8971
|
-
if (isImageArtifact(artifact) && isRemoteUrl(raw)) {
|
|
8972
|
-
try {
|
|
8973
|
-
const response = await fetch(raw);
|
|
8974
|
-
if (!response.ok) {
|
|
8975
|
-
throw new Error(`HTTP ${response.status}`);
|
|
8976
|
-
}
|
|
8977
|
-
saveBlob(await response.blob(), filename);
|
|
8978
|
-
return;
|
|
8979
|
-
} catch {
|
|
8980
|
-
window.open(raw, "_blank", "noopener");
|
|
8981
|
-
return;
|
|
8982
|
-
}
|
|
8983
|
-
}
|
|
8984
|
-
const blob = buildArtifactBlob(artifact);
|
|
8985
|
-
if (blob) {
|
|
8986
|
-
saveBlob(blob, filename);
|
|
8987
|
-
}
|
|
8988
|
-
}
|
|
8989
|
-
|
|
8990
|
-
// src/components/chat/ArtifactPanel/dsl-preview.tsx
|
|
8991
|
-
import { isDslSourceRef as isDslSourceRef2, Registry } from "@pactor-app/core";
|
|
8992
|
-
import {
|
|
8993
|
-
ActionEngine,
|
|
8994
|
-
createRuntimeContext,
|
|
8995
|
-
DslRenderer,
|
|
8996
|
-
registerBuiltinActions,
|
|
8997
|
-
useRenderer as useRenderer20
|
|
8998
|
-
} from "@pactor-app/runtime";
|
|
8999
|
-
import {
|
|
9000
|
-
Component,
|
|
9001
|
-
useMemo as useMemo6
|
|
9002
|
-
} from "react";
|
|
9003
|
-
import { Fragment as Fragment13, jsx as jsx118, jsxs as jsxs79 } from "react/jsx-runtime";
|
|
9004
|
-
var ARTIFACT_DENIED_TYPE = "ChatDenied";
|
|
9005
|
-
function ArtifactDenied({ deniedType }) {
|
|
9006
|
-
return /* @__PURE__ */ jsxs79(
|
|
9007
|
-
"div",
|
|
9008
|
-
{
|
|
9009
|
-
"data-slot": "artifact-denied",
|
|
9010
|
-
"data-denied-type": deniedType,
|
|
9011
|
-
className: "rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground",
|
|
9012
|
-
children: [
|
|
9013
|
-
"\u8BE5\u7EC4\u4EF6\u4E0D\u5141\u8BB8\u5728\u4EA7\u7269\u9884\u89C8\u4E2D\u4F7F\u7528",
|
|
9014
|
-
deniedType ? `\uFF1A${deniedType}` : ""
|
|
9015
|
-
]
|
|
9016
|
-
}
|
|
9017
|
-
);
|
|
9018
|
-
}
|
|
9019
|
-
function guardArtifactDsl(node, registry) {
|
|
9020
|
-
const type = node.type ?? "(reference)";
|
|
9021
|
-
if (type !== ARTIFACT_DENIED_TYPE && !registry.has(type)) {
|
|
9022
|
-
return {
|
|
9023
|
-
type: ARTIFACT_DENIED_TYPE,
|
|
9024
|
-
props: { deniedType: type }
|
|
9025
|
-
};
|
|
9026
|
-
}
|
|
9027
|
-
if (node.children === void 0) {
|
|
9028
|
-
return node;
|
|
9029
|
-
}
|
|
9030
|
-
if (!Array.isArray(node.children)) {
|
|
9031
|
-
return {
|
|
9032
|
-
type: ARTIFACT_DENIED_TYPE,
|
|
9033
|
-
props: { deniedType: `${type}(remote)` }
|
|
9034
|
-
};
|
|
9035
|
-
}
|
|
9036
|
-
if (node.children.length === 0) {
|
|
9037
|
-
return node;
|
|
9038
|
-
}
|
|
9039
|
-
return {
|
|
9040
|
-
...node,
|
|
9041
|
-
// 数组中混排的引用元素同样无法静态过白名单:替换为受控占位
|
|
9042
|
-
children: node.children.map(
|
|
9043
|
-
(child) => isDslSourceRef2(child) ? { type: ARTIFACT_DENIED_TYPE, props: { deniedType: "(remote)" } } : guardArtifactDsl(child, registry)
|
|
9044
|
-
)
|
|
9045
|
-
};
|
|
9046
|
-
}
|
|
9047
|
-
function useArtifactPreviewRuntime(safeRegistry, user) {
|
|
9048
|
-
return useMemo6(() => {
|
|
9049
|
-
if (!safeRegistry) {
|
|
9050
|
-
return void 0;
|
|
9051
|
-
}
|
|
9052
|
-
const components = new Registry("ArtifactPreviewRegistry");
|
|
9053
|
-
components.register(ARTIFACT_DENIED_TYPE, ArtifactDenied);
|
|
9054
|
-
for (const name of safeRegistry.list()) {
|
|
9055
|
-
components.register(name, safeRegistry.get(name));
|
|
9056
|
-
}
|
|
9057
|
-
const context = createRuntimeContext({ components, user });
|
|
9058
|
-
registerBuiltinActions(context.actions);
|
|
9059
|
-
return { context, engine: new ActionEngine(context) };
|
|
9060
|
-
}, [safeRegistry, user]);
|
|
9061
|
-
}
|
|
9062
|
-
var ArtifactDslGuard = class extends Component {
|
|
9063
|
-
constructor() {
|
|
9064
|
-
super(...arguments);
|
|
9065
|
-
this.state = { failed: false };
|
|
9066
|
-
}
|
|
9067
|
-
static getDerivedStateFromError() {
|
|
9068
|
-
return { failed: true };
|
|
9069
|
-
}
|
|
9070
|
-
componentDidCatch(error) {
|
|
9071
|
-
console.warn("[@pactor-app/ui] DSL \u4EA7\u7269\u6E32\u67D3\u5931\u8D25\uFF0C\u5DF2\u964D\u7EA7\u5C55\u793A", error);
|
|
9072
|
-
}
|
|
9073
|
-
render() {
|
|
9074
|
-
return this.state.failed ? /* @__PURE__ */ jsx118(
|
|
9075
|
-
"div",
|
|
9076
|
-
{
|
|
9077
|
-
"data-slot": "artifact-denied",
|
|
9078
|
-
className: "rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground",
|
|
9079
|
-
children: "DSL \u4EA7\u7269\u6E32\u67D3\u5931\u8D25\uFF0C\u5DF2\u964D\u7EA7\u5C55\u793A"
|
|
9080
|
-
}
|
|
9081
|
-
) : this.props.children;
|
|
9082
|
-
}
|
|
9083
|
-
};
|
|
9084
|
-
function ArtifactDslNode({ node }) {
|
|
9085
|
-
const { renderChildren } = useRenderer20();
|
|
9086
|
-
return /* @__PURE__ */ jsx118(Fragment13, { children: renderChildren([node]) });
|
|
9087
|
-
}
|
|
9088
|
-
function ArtifactDslContent({
|
|
9089
|
-
content,
|
|
9090
|
-
runtime,
|
|
9091
|
-
style
|
|
9092
|
-
}) {
|
|
9093
|
-
const node = typeof content === "object" && content !== null && !Array.isArray(content) && typeof content.type === "string" ? content : void 0;
|
|
9094
|
-
if (!node || !runtime) {
|
|
9095
|
-
return /* @__PURE__ */ jsx118(
|
|
9096
|
-
"div",
|
|
9097
|
-
{
|
|
9098
|
-
"data-slot": "artifact-denied",
|
|
9099
|
-
className: "rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground",
|
|
9100
|
-
style,
|
|
9101
|
-
children: node ? "DSL \u9884\u89C8\u4E0D\u53EF\u7528\uFF08\u672A\u6CE8\u5165 Safe Registry\uFF09" : "DSL \u4EA7\u7269\u5185\u5BB9\u65E0\u6548"
|
|
9102
|
-
}
|
|
9103
|
-
);
|
|
9104
|
-
}
|
|
9105
|
-
const guarded = guardArtifactDsl(node, runtime.context.components);
|
|
9106
|
-
return /* @__PURE__ */ jsx118(DslRenderer, { context: runtime.context, engine: runtime.engine, children: /* @__PURE__ */ jsx118(ArtifactDslGuard, { children: /* @__PURE__ */ jsx118(ArtifactDslNode, { node: guarded }) }) });
|
|
9107
|
-
}
|
|
9108
|
-
|
|
9109
|
-
// src/components/chat/ArtifactPanel/index.tsx
|
|
9110
|
-
import { Fragment as Fragment14, jsx as jsx119, jsxs as jsxs80 } from "react/jsx-runtime";
|
|
9111
|
-
function ArtifactKindIcon({ artifact }) {
|
|
9112
|
-
return /* @__PURE__ */ jsx119(Icon, { name: resolveArtifactIconName(artifact), size: 13 });
|
|
9113
|
-
}
|
|
9114
|
-
function ArtifactListView({
|
|
9115
|
-
nodes,
|
|
9116
|
-
activeId,
|
|
9117
|
-
onSelect
|
|
9118
|
-
}) {
|
|
9119
|
-
return /* @__PURE__ */ jsx119("ul", { "data-slot": "artifact-panel-list", className: "flex flex-col gap-0.5", children: nodes.map((node) => /* @__PURE__ */ jsx119(
|
|
9120
|
-
ArtifactTreeRow,
|
|
9121
|
-
{
|
|
9122
|
-
node,
|
|
9123
|
-
activeId,
|
|
9124
|
-
onSelect
|
|
9125
|
-
},
|
|
9126
|
-
node.path
|
|
9127
|
-
)) });
|
|
9128
|
-
}
|
|
9129
|
-
function ArtifactTreeRow({
|
|
9130
|
-
node,
|
|
9131
|
-
activeId,
|
|
9132
|
-
onSelect
|
|
9133
|
-
}) {
|
|
9134
|
-
const [open, setOpen] = useState39(true);
|
|
9135
|
-
if (node.artifact) {
|
|
9136
|
-
return /* @__PURE__ */ jsx119("li", { children: /* @__PURE__ */ jsxs80(
|
|
9137
|
-
"button",
|
|
9138
|
-
{
|
|
9139
|
-
type: "button",
|
|
9140
|
-
"data-slot": "artifact-panel-list-item",
|
|
9141
|
-
"data-active": node.artifact.id === activeId,
|
|
9142
|
-
className: "flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm hover:bg-accent data-[active=true]:bg-accent",
|
|
9143
|
-
onClick: () => onSelect?.(node.artifact.id),
|
|
9144
|
-
children: [
|
|
9145
|
-
/* @__PURE__ */ jsx119(ArtifactKindIcon, { artifact: node.artifact }),
|
|
9146
|
-
/* @__PURE__ */ jsx119("span", { className: "min-w-0 flex-1 truncate", children: node.artifact.title }),
|
|
9147
|
-
/* @__PURE__ */ jsx119("span", { className: "shrink-0 text-xs text-muted-foreground", children: node.artifact.kind })
|
|
9148
|
-
]
|
|
9149
|
-
}
|
|
9150
|
-
) });
|
|
9151
|
-
}
|
|
9152
|
-
return /* @__PURE__ */ jsxs80("li", { children: [
|
|
9153
|
-
/* @__PURE__ */ jsxs80(
|
|
9154
|
-
"button",
|
|
9155
|
-
{
|
|
9156
|
-
type: "button",
|
|
9157
|
-
"data-slot": "artifact-panel-list-folder",
|
|
9158
|
-
"aria-expanded": open,
|
|
9159
|
-
"data-open": open,
|
|
9160
|
-
className: "flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm hover:bg-accent",
|
|
9161
|
-
onClick: () => setOpen((value) => !value),
|
|
9162
|
-
children: [
|
|
9163
|
-
/* @__PURE__ */ jsx119(
|
|
9164
|
-
"span",
|
|
9165
|
-
{
|
|
9166
|
-
className: "inline-flex transition-transform data-[open=true]:rotate-90",
|
|
9167
|
-
"data-open": open,
|
|
9168
|
-
children: /* @__PURE__ */ jsx119(Icon, { name: "chevron-right", size: 12 })
|
|
9169
|
-
}
|
|
9170
|
-
),
|
|
9171
|
-
/* @__PURE__ */ jsx119(Icon, { name: "folder", size: 13 }),
|
|
9172
|
-
/* @__PURE__ */ jsx119("span", { className: "min-w-0 flex-1 truncate", children: node.name })
|
|
9173
|
-
]
|
|
9174
|
-
}
|
|
9175
|
-
),
|
|
9176
|
-
open && /* @__PURE__ */ jsx119("div", { className: "pl-4", children: /* @__PURE__ */ jsx119(
|
|
9177
|
-
ArtifactListView,
|
|
9178
|
-
{
|
|
9179
|
-
nodes: node.children,
|
|
9180
|
-
activeId,
|
|
9181
|
-
onSelect
|
|
9182
|
-
}
|
|
9183
|
-
) })
|
|
9184
|
-
] });
|
|
9185
|
-
}
|
|
9186
|
-
function ArtifactImageContent({ artifact }) {
|
|
9187
|
-
const raw = String(artifact.content).trim();
|
|
9188
|
-
const src = raw.startsWith("<svg") || raw.startsWith("<?xml") ? `data:image/svg+xml;utf8,${encodeURIComponent(raw)}` : raw;
|
|
9189
|
-
return /* @__PURE__ */ jsx119("div", { "data-slot": "artifact-panel-image", className: "flex justify-center", children: /* @__PURE__ */ jsx119("img", { src, alt: artifact.title, className: "max-w-full rounded-md" }) });
|
|
9190
|
-
}
|
|
9191
|
-
function ArtifactContent({
|
|
9192
|
-
artifact,
|
|
9193
|
-
runtime,
|
|
9194
|
-
viewers
|
|
9195
|
-
}) {
|
|
9196
|
-
const ext = resolveArtifactFileType(artifact);
|
|
9197
|
-
const custom = (ext ? viewers?.[ext] : void 0) ?? viewers?.[artifact.kind];
|
|
9198
|
-
if (custom) {
|
|
9199
|
-
return /* @__PURE__ */ jsx119(Fragment14, { children: custom(artifact) });
|
|
9200
|
-
}
|
|
9201
|
-
if (isImageArtifact(artifact)) {
|
|
9202
|
-
return /* @__PURE__ */ jsx119(ArtifactImageContent, { artifact });
|
|
9203
|
-
}
|
|
9204
|
-
switch (artifact.kind) {
|
|
9205
|
-
case "markdown":
|
|
9206
|
-
return /* @__PURE__ */ jsx119(MarkdownDslComponent, { content: String(artifact.content) });
|
|
9207
|
-
case "code":
|
|
9208
|
-
return /* @__PURE__ */ jsx119(
|
|
9209
|
-
CodeBlock,
|
|
9210
|
-
{
|
|
9211
|
-
code: String(artifact.content),
|
|
9212
|
-
language: artifact.language
|
|
9213
|
-
}
|
|
9214
|
-
);
|
|
9215
|
-
case "text":
|
|
9216
|
-
return /* @__PURE__ */ jsx119(
|
|
9217
|
-
"pre",
|
|
9218
|
-
{
|
|
9219
|
-
"data-slot": "artifact-panel-text",
|
|
9220
|
-
className: "text-sm break-words whitespace-pre-wrap",
|
|
9221
|
-
children: String(artifact.content)
|
|
9222
|
-
}
|
|
9223
|
-
);
|
|
9224
|
-
case "dsl":
|
|
9225
|
-
return /* @__PURE__ */ jsx119(ArtifactDslContent, { content: artifact.content, runtime });
|
|
9226
|
-
default:
|
|
9227
|
-
return null;
|
|
9228
|
-
}
|
|
9229
|
-
}
|
|
9230
|
-
function ArtifactPanel({
|
|
9231
|
-
artifact,
|
|
9232
|
-
artifacts,
|
|
9233
|
-
activeArtifactId,
|
|
9234
|
-
onSelectArtifact,
|
|
9235
|
-
title = "\u4EA7\u7269",
|
|
9236
|
-
emptyText = "\u6682\u65E0\u4EA7\u7269",
|
|
9237
|
-
onClose,
|
|
9238
|
-
onDownload,
|
|
9239
|
-
safeRegistry,
|
|
9240
|
-
user,
|
|
9241
|
-
artifactViewers,
|
|
9242
|
-
className,
|
|
9243
|
-
style
|
|
9244
|
-
}) {
|
|
9245
|
-
const runtime = useArtifactPreviewRuntime(safeRegistry, user);
|
|
9246
|
-
const [view, setView] = useState39("content");
|
|
9247
|
-
const activeId = activeArtifactId ?? artifact?.id;
|
|
9248
|
-
useEffect35(() => {
|
|
9249
|
-
setView("content");
|
|
9250
|
-
}, [activeId]);
|
|
9251
|
-
const hasArtifacts = artifacts !== void 0 && artifacts.length > 0;
|
|
9252
|
-
const headerTitle = view === "list" ? "\u4EA7\u7269\u76EE\u5F55" : artifact?.title ?? title;
|
|
9253
|
-
return /* @__PURE__ */ jsxs80(
|
|
9254
|
-
"aside",
|
|
9255
|
-
{
|
|
9256
|
-
"data-slot": "artifact-panel",
|
|
9257
|
-
"data-kind": artifact?.kind,
|
|
9258
|
-
className: cn("flex h-full min-w-0 flex-col", className),
|
|
9259
|
-
style,
|
|
9260
|
-
children: [
|
|
9261
|
-
/* @__PURE__ */ jsxs80("div", { className: "flex shrink-0 items-center gap-1 border-b border-border px-2 py-2.5", children: [
|
|
9262
|
-
hasArtifacts ? /* @__PURE__ */ jsx119(
|
|
9263
|
-
Button2,
|
|
9264
|
-
{
|
|
9265
|
-
icon: "list",
|
|
9266
|
-
variant: "text",
|
|
9267
|
-
tooltip: view === "list" ? "\u8FD4\u56DE\u5185\u5BB9" : "\u4EA7\u7269\u76EE\u5F55",
|
|
9268
|
-
onClick: () => setView((value) => value === "list" ? "content" : "list")
|
|
9269
|
-
}
|
|
9270
|
-
) : null,
|
|
9271
|
-
hasArtifacts ? /* @__PURE__ */ jsx119(
|
|
9272
|
-
DropdownMenu2,
|
|
9273
|
-
{
|
|
9274
|
-
items: artifacts.map((item) => ({
|
|
9275
|
-
label: item.title,
|
|
9276
|
-
value: item.id,
|
|
9277
|
-
icon: resolveArtifactIconName(item)
|
|
9278
|
-
})),
|
|
9279
|
-
onSelect: (id) => onSelectArtifact?.(id),
|
|
9280
|
-
children: /* @__PURE__ */ jsxs80(
|
|
9281
|
-
"span",
|
|
9282
|
-
{
|
|
9283
|
-
"data-slot": "artifact-panel-menu-trigger",
|
|
9284
|
-
className: "flex min-w-0 cursor-pointer items-center gap-1 rounded-md px-1.5 py-1 text-sm font-medium hover:bg-accent",
|
|
9285
|
-
children: [
|
|
9286
|
-
view !== "list" && artifact ? /* @__PURE__ */ jsx119(ArtifactKindIcon, { artifact }) : null,
|
|
9287
|
-
/* @__PURE__ */ jsx119("span", { className: "truncate", children: headerTitle }),
|
|
9288
|
-
/* @__PURE__ */ jsx119(Icon, { name: "chevron-down", size: 12 })
|
|
9289
|
-
]
|
|
9290
|
-
}
|
|
9291
|
-
)
|
|
9292
|
-
}
|
|
9293
|
-
) : /* @__PURE__ */ jsx119("span", { className: "min-w-0 flex-1 truncate px-1.5 text-sm font-medium", children: headerTitle }),
|
|
9294
|
-
view !== "list" && artifact ? /* @__PURE__ */ jsx119("span", { className: "shrink-0 rounded-md bg-accent px-1.5 py-0.5 text-xs text-muted-foreground", children: artifact.kind }) : null,
|
|
9295
|
-
/* @__PURE__ */ jsx119("span", { className: "flex-1" }),
|
|
9296
|
-
artifact ? /* @__PURE__ */ jsx119(
|
|
9297
|
-
Button2,
|
|
9298
|
-
{
|
|
9299
|
-
icon: "download",
|
|
9300
|
-
variant: "text",
|
|
9301
|
-
tooltip: "\u4E0B\u8F7D\u4EA7\u7269",
|
|
9302
|
-
className: "px-2",
|
|
9303
|
-
onClick: () => onDownload ? onDownload(artifact) : void downloadArtifact(artifact)
|
|
9304
|
-
}
|
|
9305
|
-
) : null,
|
|
9306
|
-
/* @__PURE__ */ jsx119(
|
|
9307
|
-
Button2,
|
|
9308
|
-
{
|
|
9309
|
-
icon: "x",
|
|
9310
|
-
variant: "text",
|
|
9311
|
-
tooltip: "\u6536\u8D77\u4EA7\u7269\u533A",
|
|
9312
|
-
className: "px-2",
|
|
9313
|
-
onClick: () => onClose?.()
|
|
9314
|
-
}
|
|
9315
|
-
)
|
|
9316
|
-
] }),
|
|
9317
|
-
/* @__PURE__ */ jsx119("div", { className: "scrollbar-subtle min-h-0 flex-1 overflow-auto p-4", children: view === "list" && artifacts !== void 0 ? /* @__PURE__ */ jsx119(
|
|
9318
|
-
ArtifactListView,
|
|
9319
|
-
{
|
|
9320
|
-
nodes: buildArtifactTree(artifacts),
|
|
9321
|
-
activeId,
|
|
9322
|
-
onSelect: onSelectArtifact
|
|
9323
|
-
}
|
|
9324
|
-
) : artifact ? /* @__PURE__ */ jsx119(
|
|
9325
|
-
ArtifactContent,
|
|
9326
|
-
{
|
|
9327
|
-
artifact,
|
|
9328
|
-
runtime,
|
|
9329
|
-
viewers: artifactViewers
|
|
9330
|
-
}
|
|
9331
|
-
) : /* @__PURE__ */ jsx119("p", { className: "text-sm text-muted-foreground", children: emptyText }) })
|
|
9332
|
-
]
|
|
9333
|
-
}
|
|
9334
|
-
);
|
|
9335
|
-
}
|
|
9336
|
-
|
|
9337
|
-
// src/components/chat/Attachment/index.tsx
|
|
9338
|
-
import { jsx as jsx120, jsxs as jsxs81 } from "react/jsx-runtime";
|
|
9339
|
-
var kindIcon2 = { image: "image", text: "file-text", video: "video", audio: "music", other: "file" };
|
|
9340
|
-
function formatSize3(bytes) {
|
|
9341
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
9342
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
9343
|
-
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
9344
|
-
}
|
|
9345
|
-
function Attachment({ items = [], onRemove, onRetry, className, style }) {
|
|
9346
|
-
return /* @__PURE__ */ jsx120("div", { "data-slot": "attachment", className: cn("flex flex-wrap gap-2", className), style, children: items.map((item, index) => {
|
|
9347
|
-
const key = item.id ?? index;
|
|
9348
|
-
const kind = inferKind(item.name, item.fileType);
|
|
9349
|
-
const status = item.status ?? "done";
|
|
9350
|
-
return /* @__PURE__ */ jsxs81(
|
|
9351
|
-
"div",
|
|
9352
|
-
{
|
|
9353
|
-
"data-slot": "attachment-item",
|
|
9354
|
-
"data-status": status,
|
|
9355
|
-
className: "flex w-56 flex-col rounded-md border border-border px-2 py-1.5",
|
|
9356
|
-
children: [
|
|
9357
|
-
/* @__PURE__ */ jsxs81("div", { className: "flex items-center gap-1.5", children: [
|
|
9358
|
-
/* @__PURE__ */ jsx120("span", { className: "shrink-0 text-muted-foreground", children: /* @__PURE__ */ jsx120(Icon, { name: kindIcon2[kind], size: "sm" }) }),
|
|
9359
|
-
/* @__PURE__ */ jsx120("span", { className: "min-w-0 flex-1 truncate text-sm", children: item.name }),
|
|
9360
|
-
status === "uploading" ? /* @__PURE__ */ jsx120("span", { className: "shrink-0 animate-spin text-muted-foreground motion-reduce:animate-none", children: /* @__PURE__ */ jsx120(Icon, { name: "loader-circle", size: "sm" }) }) : null,
|
|
9361
|
-
status === "error" && onRetry ? /* @__PURE__ */ jsx120(
|
|
9362
|
-
"button",
|
|
9363
|
-
{
|
|
9364
|
-
type: "button",
|
|
9365
|
-
"data-slot": "attachment-retry",
|
|
9366
|
-
"aria-label": `\u91CD\u8BD5 ${item.name}`,
|
|
9367
|
-
className: "shrink-0 text-destructive hover:opacity-80",
|
|
9368
|
-
onClick: () => onRetry(key),
|
|
9369
|
-
children: /* @__PURE__ */ jsx120(Icon, { name: "refresh-ccw", size: "sm" })
|
|
9370
|
-
}
|
|
9371
|
-
) : null,
|
|
9372
|
-
onRemove ? /* @__PURE__ */ jsx120(
|
|
9373
|
-
"button",
|
|
9374
|
-
{
|
|
9375
|
-
type: "button",
|
|
9376
|
-
"data-slot": "attachment-remove",
|
|
9377
|
-
"aria-label": `\u79FB\u9664 ${item.name}`,
|
|
9378
|
-
className: "shrink-0 text-muted-foreground hover:text-foreground",
|
|
9379
|
-
onClick: () => onRemove(key),
|
|
9380
|
-
children: /* @__PURE__ */ jsx120(Icon, { name: "x", size: "sm" })
|
|
9381
|
-
}
|
|
9382
|
-
) : null
|
|
9383
|
-
] }),
|
|
9384
|
-
/* @__PURE__ */ jsxs81("div", { className: "mt-0.5 flex items-center gap-1.5 pl-5 text-xs", children: [
|
|
9385
|
-
item.fileSize !== void 0 ? /* @__PURE__ */ jsx120("span", { className: "text-muted-foreground", children: formatSize3(item.fileSize) }) : null,
|
|
9386
|
-
status === "error" ? /* @__PURE__ */ jsx120("span", { className: "text-destructive", children: "\u4E0A\u4F20\u5931\u8D25" }) : null
|
|
9387
|
-
] }),
|
|
9388
|
-
status === "uploading" && item.progress !== void 0 ? /* @__PURE__ */ jsx120("div", { "data-slot": "attachment-progress", className: "mt-1 ml-5 h-1 overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx120("div", { className: "h-full bg-primary transition-[width]", style: { width: `${item.progress}%` } }) }) : null
|
|
9389
|
-
]
|
|
9390
|
-
},
|
|
9391
|
-
key
|
|
9392
|
-
);
|
|
9393
|
-
}) });
|
|
9394
|
-
}
|
|
9395
|
-
|
|
9396
|
-
// src/components/chat/Bubble/index.tsx
|
|
9397
|
-
import { jsx as jsx121 } from "react/jsx-runtime";
|
|
9398
|
-
function Bubble2({ align = "start", variant = "muted", className, style, children }) {
|
|
9399
|
-
return /* @__PURE__ */ jsx121(Bubble, { variant, align, className, style, children: /* @__PURE__ */ jsx121(BubbleContent, { children }) });
|
|
9400
|
-
}
|
|
9401
|
-
|
|
9402
|
-
// src/components/chat/Sender/index.tsx
|
|
9403
|
-
import { jsx as jsx122, jsxs as jsxs82 } from "react/jsx-runtime";
|
|
9404
|
-
function Sender({ name, avatar, avatarText, role, time, align = "start", className, style }) {
|
|
9405
|
-
return /* @__PURE__ */ jsxs82(
|
|
9406
|
-
"div",
|
|
9407
|
-
{
|
|
9408
|
-
"data-slot": "sender",
|
|
9409
|
-
className: cn("flex items-center gap-2", align === "end" && "flex-row-reverse", className),
|
|
9410
|
-
style,
|
|
9411
|
-
children: [
|
|
9412
|
-
/* @__PURE__ */ jsx122(Avatar2, { src: avatar, fallback: avatarText ?? name?.slice(0, 1) ?? "?", className: "size-7" }),
|
|
9413
|
-
/* @__PURE__ */ jsxs82("div", { className: cn("flex min-w-0 items-baseline gap-1.5", align === "end" && "flex-row-reverse"), children: [
|
|
9414
|
-
name ? /* @__PURE__ */ jsx122("span", { "data-slot": "sender-name", className: "truncate text-sm font-medium", children: name }) : null,
|
|
9415
|
-
role ? /* @__PURE__ */ jsx122("span", { "data-slot": "sender-role", className: "shrink-0 text-xs text-muted-foreground", children: role }) : null,
|
|
9416
|
-
time ? /* @__PURE__ */ jsx122("span", { "data-slot": "sender-time", className: "shrink-0 text-xs text-muted-foreground", children: time }) : null
|
|
9417
|
-
] })
|
|
9418
|
-
]
|
|
9419
|
-
}
|
|
9420
|
-
);
|
|
9421
|
-
}
|
|
9422
|
-
|
|
9423
|
-
// src/components/chat/StreamingText/index.tsx
|
|
9424
|
-
import { useEffect as useEffect36, useState as useState40 } from "react";
|
|
9425
|
-
import { jsx as jsx123, jsxs as jsxs83 } from "react/jsx-runtime";
|
|
9426
|
-
function StreamingText({ content = "", streaming, typing, speed = 2, className, style }) {
|
|
9427
|
-
const [revealed, setRevealed] = useState40(typing ? 0 : content.length);
|
|
9428
|
-
useEffect36(() => {
|
|
9429
|
-
if (!typing) {
|
|
9430
|
-
setRevealed(content.length);
|
|
9431
|
-
return;
|
|
9432
|
-
}
|
|
9433
|
-
setRevealed(0);
|
|
9434
|
-
const timer = window.setInterval(() => {
|
|
9435
|
-
setRevealed((value) => {
|
|
9436
|
-
if (value >= content.length) {
|
|
9437
|
-
window.clearInterval(timer);
|
|
9438
|
-
return value;
|
|
9439
|
-
}
|
|
9440
|
-
return Math.min(content.length, value + speed);
|
|
9441
|
-
});
|
|
9442
|
-
}, 24);
|
|
9443
|
-
return () => window.clearInterval(timer);
|
|
9444
|
-
}, [content, typing, speed]);
|
|
9445
|
-
const typingDone = !typing || revealed >= content.length;
|
|
9446
|
-
const showCursor = streaming || typing && !typingDone;
|
|
9447
|
-
return /* @__PURE__ */ jsxs83("span", { "data-slot": "streaming-text", className: cn("whitespace-pre-wrap", className), style, children: [
|
|
9448
|
-
typing ? content.slice(0, revealed) : content,
|
|
9449
|
-
showCursor ? /* @__PURE__ */ jsx123(
|
|
9450
|
-
"span",
|
|
9451
|
-
{
|
|
9452
|
-
"data-slot": "streaming-text-cursor",
|
|
9453
|
-
"aria-hidden": "true",
|
|
9454
|
-
className: "ml-0.5 inline-block animate-pulse text-primary motion-reduce:animate-none",
|
|
9455
|
-
children: "\u258D"
|
|
9456
|
-
}
|
|
9457
|
-
) : null
|
|
9458
|
-
] });
|
|
9459
|
-
}
|
|
9460
|
-
|
|
9461
|
-
// src/components/chat/Thinking/index.tsx
|
|
9462
|
-
import { useState as useState41 } from "react";
|
|
9463
|
-
import { jsx as jsx124, jsxs as jsxs84 } from "react/jsx-runtime";
|
|
9464
|
-
function Thinking({
|
|
9465
|
-
content,
|
|
9466
|
-
status = "thinking",
|
|
9467
|
-
title,
|
|
9468
|
-
expanded,
|
|
9469
|
-
defaultExpanded,
|
|
9470
|
-
onToggle,
|
|
9471
|
-
className,
|
|
9472
|
-
style
|
|
9473
|
-
}) {
|
|
9474
|
-
const [innerExpanded, setInnerExpanded] = useState41(defaultExpanded ?? status === "thinking");
|
|
9475
|
-
const isExpanded = expanded ?? innerExpanded;
|
|
9476
|
-
const resolvedTitle = title ?? (status === "thinking" ? "\u601D\u8003\u4E2D\u2026" : "\u601D\u8003\u5B8C\u6210");
|
|
9477
|
-
const toggle = () => {
|
|
9478
|
-
if (expanded === void 0) {
|
|
9479
|
-
setInnerExpanded(!isExpanded);
|
|
9480
|
-
}
|
|
9481
|
-
onToggle?.(!isExpanded);
|
|
9482
|
-
};
|
|
9483
|
-
return /* @__PURE__ */ jsxs84(
|
|
9484
|
-
"div",
|
|
9485
|
-
{
|
|
9486
|
-
"data-slot": "thinking",
|
|
9487
|
-
"data-status": status,
|
|
9488
|
-
className: cn("w-full", className),
|
|
9489
|
-
style,
|
|
9490
|
-
children: [
|
|
9491
|
-
/* @__PURE__ */ jsxs84(
|
|
9492
|
-
"button",
|
|
9493
|
-
{
|
|
9494
|
-
type: "button",
|
|
9495
|
-
"data-slot": "thinking-trigger",
|
|
9496
|
-
"aria-expanded": isExpanded,
|
|
9497
|
-
className: "flex w-full cursor-pointer items-center gap-2 py-1 text-left text-sm",
|
|
9498
|
-
onClick: toggle,
|
|
9499
|
-
children: [
|
|
9500
|
-
/* @__PURE__ */ jsx124("span", { className: cn("text-muted-foreground", status === "thinking" && "animate-pulse motion-reduce:animate-none"), children: /* @__PURE__ */ jsx124(Icon, { name: "brain", size: "sm" }) }),
|
|
9501
|
-
/* @__PURE__ */ jsx124("span", { "data-slot": "thinking-title", className: "text-muted-foreground", children: resolvedTitle }),
|
|
9502
|
-
/* @__PURE__ */ jsx124("span", { className: "text-muted-foreground", children: /* @__PURE__ */ jsx124(Icon, { name: isExpanded ? "chevron-down" : "chevron-right", size: "sm" }) })
|
|
9503
|
-
]
|
|
9504
|
-
}
|
|
9505
|
-
),
|
|
9506
|
-
isExpanded && content ? /* @__PURE__ */ jsx124(
|
|
9507
|
-
"div",
|
|
9508
|
-
{
|
|
9509
|
-
"data-slot": "thinking-content",
|
|
9510
|
-
className: "py-1 pl-6 text-sm whitespace-pre-wrap text-muted-foreground",
|
|
9511
|
-
children: content
|
|
9512
|
-
}
|
|
9513
|
-
) : null
|
|
9514
|
-
]
|
|
9515
|
-
}
|
|
9516
|
-
);
|
|
9517
|
-
}
|
|
9518
|
-
|
|
9519
|
-
// src/components/chat/ToolCall/index.tsx
|
|
9520
|
-
import { useState as useState42 } from "react";
|
|
9521
|
-
import { Fragment as Fragment15, jsx as jsx125, jsxs as jsxs85 } from "react/jsx-runtime";
|
|
9522
|
-
var statusIcon3 = {
|
|
9523
|
-
running: { icon: "loader-circle", className: "text-info", spin: true },
|
|
9524
|
-
done: { icon: "circle-check", className: "text-success" },
|
|
9525
|
-
error: { icon: "circle-x", className: "text-destructive" }
|
|
9526
|
-
};
|
|
9527
|
-
function renderValue(value) {
|
|
9528
|
-
if (value === void 0 || value === null) return "";
|
|
9529
|
-
if (typeof value === "string") return value;
|
|
9530
|
-
try {
|
|
9531
|
-
return JSON.stringify(value, null, 2);
|
|
9532
|
-
} catch {
|
|
9533
|
-
return String(value);
|
|
9534
|
-
}
|
|
9535
|
-
}
|
|
9536
|
-
function ToolCall({ name, params, status = "done", result, durationMs, defaultExpanded, className, style }) {
|
|
9537
|
-
const [expanded, setExpanded] = useState42(defaultExpanded ?? status === "running");
|
|
9538
|
-
const meta = statusIcon3[status];
|
|
9539
|
-
const paramsText = renderValue(params);
|
|
9540
|
-
const hasDetail = Boolean(paramsText) || Boolean(result);
|
|
9541
|
-
const headerInner = /* @__PURE__ */ jsxs85(Fragment15, { children: [
|
|
9542
|
-
/* @__PURE__ */ jsx125("span", { className: "shrink-0 text-muted-foreground", children: /* @__PURE__ */ jsx125(Icon, { name: "terminal", size: "sm" }) }),
|
|
9543
|
-
/* @__PURE__ */ jsx125("span", { "data-slot": "tool-call-name", className: "min-w-0 truncate font-medium", children: name ?? "\u5DE5\u5177\u8C03\u7528" }),
|
|
9544
|
-
/* @__PURE__ */ jsx125("span", { className: cn("shrink-0", meta.className, meta.spin && "animate-spin motion-reduce:animate-none"), children: /* @__PURE__ */ jsx125(Icon, { name: meta.icon, size: "sm" }) }),
|
|
9545
|
-
durationMs !== void 0 ? /* @__PURE__ */ jsxs85("span", { className: "shrink-0 text-xs text-muted-foreground", children: [
|
|
9546
|
-
(durationMs / 1e3).toFixed(1),
|
|
9547
|
-
"s"
|
|
9548
|
-
] }) : null,
|
|
9549
|
-
hasDetail ? /* @__PURE__ */ jsx125("span", { className: "shrink-0 text-muted-foreground", children: /* @__PURE__ */ jsx125(Icon, { name: expanded ? "chevron-down" : "chevron-right", size: "sm" }) }) : null
|
|
9550
|
-
] });
|
|
9551
|
-
return /* @__PURE__ */ jsxs85(
|
|
9552
|
-
"div",
|
|
9553
|
-
{
|
|
9554
|
-
"data-slot": "tool-call",
|
|
9555
|
-
"data-status": status,
|
|
9556
|
-
className: cn("w-full", className),
|
|
9557
|
-
style,
|
|
9558
|
-
children: [
|
|
9559
|
-
hasDetail ? /* @__PURE__ */ jsx125(
|
|
9560
|
-
"button",
|
|
9561
|
-
{
|
|
9562
|
-
type: "button",
|
|
9563
|
-
"data-slot": "tool-call-trigger",
|
|
9564
|
-
"aria-expanded": expanded,
|
|
9565
|
-
className: "flex w-full cursor-pointer items-center gap-2 py-1 text-left text-sm",
|
|
9566
|
-
onClick: () => setExpanded((value) => !value),
|
|
9567
|
-
children: headerInner
|
|
9568
|
-
}
|
|
9569
|
-
) : /* @__PURE__ */ jsx125(
|
|
9570
|
-
"div",
|
|
9571
|
-
{
|
|
9572
|
-
"data-slot": "tool-call-trigger",
|
|
9573
|
-
className: "flex w-full items-center gap-2 py-1 text-left text-sm",
|
|
9574
|
-
children: headerInner
|
|
9575
|
-
}
|
|
9576
|
-
),
|
|
9577
|
-
hasDetail && expanded ? /* @__PURE__ */ jsxs85("div", { "data-slot": "tool-call-body", className: "flex flex-col gap-2 py-1 pl-6", children: [
|
|
9578
|
-
paramsText ? /* @__PURE__ */ jsxs85("div", { children: [
|
|
9579
|
-
/* @__PURE__ */ jsx125("div", { className: "text-xs font-medium text-muted-foreground", children: "\u53C2\u6570" }),
|
|
9580
|
-
/* @__PURE__ */ jsx125("pre", { "data-slot": "tool-call-params", className: "mt-1 overflow-x-auto text-xs whitespace-pre-wrap text-muted-foreground", children: paramsText })
|
|
9581
|
-
] }) : null,
|
|
9582
|
-
result ? /* @__PURE__ */ jsxs85("div", { children: [
|
|
9583
|
-
/* @__PURE__ */ jsx125("div", { className: "text-xs font-medium text-muted-foreground", children: "\u7ED3\u679C" }),
|
|
9584
|
-
/* @__PURE__ */ jsx125("pre", { "data-slot": "tool-call-result", className: "mt-1 overflow-x-auto text-xs whitespace-pre-wrap text-muted-foreground", children: result })
|
|
9585
|
-
] }) : null
|
|
9586
|
-
] }) : null
|
|
9587
|
-
]
|
|
9588
|
-
}
|
|
9589
|
-
);
|
|
9590
|
-
}
|
|
9591
|
-
|
|
9592
|
-
// src/components/chat/ChatMessage/index.tsx
|
|
9593
|
-
import { jsx as jsx126, jsxs as jsxs86 } from "react/jsx-runtime";
|
|
9594
|
-
function PartView({
|
|
9595
|
-
part,
|
|
9596
|
-
role,
|
|
9597
|
-
onOpenArtifacts
|
|
9598
|
-
}) {
|
|
9599
|
-
if (role === "system" && (part.type === "text" || part.type === "markdown")) {
|
|
9600
|
-
return /* @__PURE__ */ jsx126(
|
|
9601
|
-
"div",
|
|
9602
|
-
{
|
|
9603
|
-
"data-slot": "chat-message-system-part",
|
|
9604
|
-
className: "w-full text-center text-xs text-muted-foreground",
|
|
9605
|
-
children: part.type === "markdown" ? /* @__PURE__ */ jsx126(MarkdownDslComponent, { content: part.content }) : part.content
|
|
9606
|
-
}
|
|
9607
|
-
);
|
|
9608
|
-
}
|
|
9609
|
-
switch (part.type) {
|
|
9610
|
-
case "text":
|
|
9611
|
-
return /* @__PURE__ */ jsx126(Bubble2, { align: role === "user" ? "end" : "start", variant: role === "user" ? "default" : "muted", children: /* @__PURE__ */ jsx126("span", { className: "text-sm whitespace-pre-wrap", children: part.content }) });
|
|
9612
|
-
case "markdown":
|
|
9613
|
-
return /* @__PURE__ */ jsx126(Bubble2, { align: role === "user" ? "end" : "start", variant: role === "user" ? "default" : "ghost", children: /* @__PURE__ */ jsx126(MarkdownDslComponent, { content: part.content }) });
|
|
9614
|
-
case "thinking":
|
|
9615
|
-
return /* @__PURE__ */ jsx126(Thinking, { content: part.content, status: part.status ?? "done" });
|
|
9616
|
-
case "tool-call":
|
|
9617
|
-
return /* @__PURE__ */ jsx126(ToolCall, { name: part.name, params: part.params, status: part.status ?? "done", result: part.result });
|
|
9618
|
-
case "tool-result":
|
|
9619
|
-
return /* @__PURE__ */ jsx126("pre", { "data-slot": "chat-message-tool-result", className: "overflow-x-auto rounded-md bg-muted p-2 text-xs whitespace-pre-wrap", children: part.content });
|
|
9620
|
-
case "status":
|
|
9621
|
-
return /* @__PURE__ */ jsxs86("div", { "data-slot": "chat-message-status", className: "flex w-fit items-center gap-1.5 text-muted-foreground", children: [
|
|
9622
|
-
/* @__PURE__ */ jsx126(Icon, { name: "clock", size: "sm" }),
|
|
9623
|
-
part.text
|
|
9624
|
-
] });
|
|
9625
|
-
case "artifacts": {
|
|
9626
|
-
const artifactsClass = "flex w-fit items-center gap-1.5 text-muted-foreground";
|
|
9627
|
-
const label = `\u5DF2\u751F\u6210 ${part.count} \u4E2A\u4EA7\u7269`;
|
|
9628
|
-
return onOpenArtifacts ? /* @__PURE__ */ jsxs86(
|
|
9629
|
-
"button",
|
|
9630
|
-
{
|
|
9631
|
-
type: "button",
|
|
9632
|
-
"data-slot": "chat-message-artifacts",
|
|
9633
|
-
className: cn(artifactsClass, "cursor-pointer hover:text-foreground"),
|
|
9634
|
-
onClick: onOpenArtifacts,
|
|
9635
|
-
children: [
|
|
9636
|
-
/* @__PURE__ */ jsx126(Icon, { name: "package", size: "sm" }),
|
|
9637
|
-
label,
|
|
9638
|
-
/* @__PURE__ */ jsx126(Icon, { name: "chevron-right", size: 12 })
|
|
9639
|
-
]
|
|
9640
|
-
}
|
|
9641
|
-
) : /* @__PURE__ */ jsxs86("div", { "data-slot": "chat-message-artifacts", className: artifactsClass, children: [
|
|
9642
|
-
/* @__PURE__ */ jsx126(Icon, { name: "package", size: "sm" }),
|
|
9643
|
-
label
|
|
9644
|
-
] });
|
|
9645
|
-
}
|
|
9646
|
-
case "error":
|
|
9647
|
-
return /* @__PURE__ */ jsxs86("div", { "data-slot": "chat-message-error", className: "flex items-center gap-1.5 text-sm text-destructive", children: [
|
|
9648
|
-
/* @__PURE__ */ jsx126(Icon, { name: "circle-alert", size: "sm" }),
|
|
9649
|
-
part.message
|
|
9650
|
-
] });
|
|
9651
|
-
default:
|
|
9652
|
-
return null;
|
|
9653
|
-
}
|
|
9654
|
-
}
|
|
9655
|
-
var ACTION_ICON_BY_NAME = {
|
|
9656
|
-
copy: "copy",
|
|
9657
|
-
retry: "rotate-ccw",
|
|
9658
|
-
regenerate: "refresh-ccw",
|
|
9659
|
-
edit: "pencil",
|
|
9660
|
-
like: "thumbs-up",
|
|
9661
|
-
dislike: "thumbs-down",
|
|
9662
|
-
share: "share",
|
|
9663
|
-
delete: "trash"
|
|
9664
|
-
};
|
|
9665
|
-
function ChatMessage({
|
|
9666
|
-
role = "assistant",
|
|
9667
|
-
parts = [],
|
|
9668
|
-
status = "completed",
|
|
9669
|
-
agent,
|
|
9670
|
-
time,
|
|
9671
|
-
showSender = false,
|
|
9672
|
-
actions = [],
|
|
9673
|
-
onAction,
|
|
9674
|
-
onOpenArtifacts,
|
|
9675
|
-
className,
|
|
9676
|
-
style
|
|
9677
|
-
}) {
|
|
9678
|
-
const isUser = role === "user";
|
|
9679
|
-
const isSystem = role === "system";
|
|
9680
|
-
const senderName = isUser ? "\u6211" : agent?.name ?? "\u52A9\u624B";
|
|
9681
|
-
return /* @__PURE__ */ jsxs86(
|
|
9682
|
-
"div",
|
|
9683
|
-
{
|
|
9684
|
-
"data-slot": "chat-message",
|
|
9685
|
-
"data-role": role,
|
|
9686
|
-
"data-status": status,
|
|
9687
|
-
className: cn(
|
|
9688
|
-
"flex w-full flex-col gap-1.5",
|
|
9689
|
-
isUser && "items-end",
|
|
9690
|
-
// system 居中弱提示(参考 @pactor-app/chat MessageBubble)
|
|
9691
|
-
isSystem && "items-center text-muted-foreground",
|
|
9692
|
-
className
|
|
9693
|
-
),
|
|
9694
|
-
style,
|
|
9695
|
-
children: [
|
|
9696
|
-
showSender ? /* @__PURE__ */ jsx126(
|
|
9697
|
-
Sender,
|
|
9698
|
-
{
|
|
9699
|
-
name: senderName,
|
|
9700
|
-
avatarText: isUser ? void 0 : agent?.icon ? void 0 : senderName.slice(0, 1),
|
|
9701
|
-
time,
|
|
9702
|
-
align: isUser ? "end" : "start"
|
|
9703
|
-
}
|
|
9704
|
-
) : null,
|
|
9705
|
-
/* @__PURE__ */ jsxs86("div", { className: cn("flex min-w-0 w-full max-w-full flex-col gap-2", isUser && "items-end", isSystem && "items-center"), children: [
|
|
9706
|
-
parts.map((part, index) => /* @__PURE__ */ jsx126(PartView, { part, role, onOpenArtifacts }, index)),
|
|
9707
|
-
status === "streaming" ? /* @__PURE__ */ jsx126(StreamingText, { content: "", streaming: true }) : null
|
|
9708
|
-
] }),
|
|
9709
|
-
actions.length > 0 && (status === "completed" || status === "error") ? /* @__PURE__ */ jsx126("div", { "data-slot": "chat-message-actions", className: "flex items-center gap-1 mt-2", children: actions.map((action) => {
|
|
9710
|
-
const label = action.label ?? action.name;
|
|
9711
|
-
const iconName = action.icon ?? ACTION_ICON_BY_NAME[action.name];
|
|
9712
|
-
if (iconName) {
|
|
9713
|
-
return /* @__PURE__ */ jsx126(Tooltip2, { content: label, side: "top", children: /* @__PURE__ */ jsx126(
|
|
9714
|
-
"button",
|
|
9715
|
-
{
|
|
9716
|
-
type: "button",
|
|
9717
|
-
"data-slot": "chat-message-action",
|
|
9718
|
-
"data-action": action.name,
|
|
9719
|
-
"aria-label": label,
|
|
9720
|
-
className: "flex cursor-pointer items-center rounded-sm p-1 text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
9721
|
-
onClick: () => onAction?.(action.name),
|
|
9722
|
-
children: /* @__PURE__ */ jsx126(Icon, { name: iconName, size: "sm" })
|
|
9723
|
-
}
|
|
9724
|
-
) }, action.name);
|
|
9725
|
-
}
|
|
9726
|
-
return /* @__PURE__ */ jsx126(
|
|
9727
|
-
"button",
|
|
9728
|
-
{
|
|
9729
|
-
type: "button",
|
|
9730
|
-
"data-slot": "chat-message-action",
|
|
9731
|
-
"data-action": action.name,
|
|
9732
|
-
className: "flex items-center cursor-pointer gap-1 rounded-sm px-1.5 py-0.5 text-xs text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
9733
|
-
onClick: () => onAction?.(action.name),
|
|
9734
|
-
children: label
|
|
9735
|
-
},
|
|
9736
|
-
action.name
|
|
9737
|
-
);
|
|
9738
|
-
}) }) : null
|
|
9739
|
-
]
|
|
9740
|
-
}
|
|
9741
|
-
);
|
|
9742
|
-
}
|
|
9743
|
-
|
|
9744
|
-
// src/components/chat/ChatPage/index.tsx
|
|
9745
|
-
import { useRenderer as useRenderer21 } from "@pactor-app/runtime";
|
|
9746
|
-
import { isValidElement as isValidElement3, useEffect as useEffect39, useState as useState46 } from "react";
|
|
9747
|
-
|
|
9748
|
-
// src/components/chat/Composer/index.tsx
|
|
9749
|
-
import {
|
|
9750
|
-
useRef as useRef12,
|
|
9751
|
-
useState as useState44
|
|
9752
|
-
} from "react";
|
|
9753
|
-
|
|
9754
|
-
// src/components/chat/Composer/mention-input.tsx
|
|
9755
|
-
import {
|
|
9756
|
-
forwardRef,
|
|
9757
|
-
useEffect as useEffect37,
|
|
9758
|
-
useImperativeHandle,
|
|
9759
|
-
useRef as useRef11,
|
|
9760
|
-
useState as useState43
|
|
9761
|
-
} from "react";
|
|
9762
|
-
import { renderToStaticMarkup } from "react-dom/server";
|
|
9763
|
-
import { Fragment as Fragment16, jsx as jsx127, jsxs as jsxs87 } from "react/jsx-runtime";
|
|
9764
|
-
var NBSP = "\xA0";
|
|
9765
|
-
var CHIP_ATTR = "data-mention-chip";
|
|
9766
|
-
function escapeRegExp(text) {
|
|
9767
|
-
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9768
|
-
}
|
|
9769
|
-
function isChipElement(node) {
|
|
9770
|
-
return node instanceof HTMLElement && node.hasAttribute(CHIP_ATTR);
|
|
9771
|
-
}
|
|
9772
|
-
function serializeNode(node) {
|
|
9773
|
-
let out = "";
|
|
9774
|
-
node.childNodes.forEach((child) => {
|
|
9775
|
-
if (child.nodeType === Node.TEXT_NODE) {
|
|
9776
|
-
out += (child.textContent ?? "").replace(/\u00A0/g, " ");
|
|
9777
|
-
} else if (isChipElement(child)) {
|
|
9778
|
-
out += `${child.dataset["trigger"] ?? ""}${child.dataset["label"] ?? ""}`;
|
|
9779
|
-
} else if (child instanceof HTMLBRElement) {
|
|
9780
|
-
out += "\n";
|
|
9781
|
-
} else if (child instanceof HTMLElement) {
|
|
9782
|
-
const inner = serializeNode(child).replace(/\n$/, "");
|
|
9783
|
-
out += (out === "" || out.endsWith("\n") ? "" : "\n") + inner + "\n";
|
|
9784
|
-
}
|
|
9785
|
-
});
|
|
9786
|
-
return out;
|
|
9787
|
-
}
|
|
9788
|
-
function collectChips(field) {
|
|
9789
|
-
return Array.from(field.querySelectorAll(`[${CHIP_ATTR}]`)).map((el) => ({
|
|
9790
|
-
id: el.dataset["id"] ?? "",
|
|
9791
|
-
label: el.dataset["label"] ?? "",
|
|
9792
|
-
trigger: el.dataset["trigger"] ?? ""
|
|
9793
|
-
}));
|
|
9794
|
-
}
|
|
9795
|
-
function detectActiveMention(field, sources) {
|
|
9796
|
-
const selection = window.getSelection();
|
|
9797
|
-
if (!selection || selection.rangeCount === 0 || !selection.isCollapsed) {
|
|
9798
|
-
return null;
|
|
9799
|
-
}
|
|
9800
|
-
const anchor = selection.anchorNode;
|
|
9801
|
-
if (!anchor || anchor.nodeType !== Node.TEXT_NODE || !field.contains(anchor)) {
|
|
9802
|
-
return null;
|
|
9803
|
-
}
|
|
9804
|
-
const caretOffset = selection.anchorOffset;
|
|
9805
|
-
const beforeCaret = (anchor.textContent ?? "").slice(0, caretOffset);
|
|
9806
|
-
for (const source of sources) {
|
|
9807
|
-
const trigger = source.trigger;
|
|
9808
|
-
const match = new RegExp(
|
|
9809
|
-
`(?:^|\\s)${escapeRegExp(trigger)}([^\\s${escapeRegExp(trigger)}]*)$`
|
|
9810
|
-
).exec(beforeCaret);
|
|
9811
|
-
if (match) {
|
|
9812
|
-
const query = match[1] ?? "";
|
|
9813
|
-
return {
|
|
9814
|
-
source,
|
|
9815
|
-
query,
|
|
9816
|
-
node: anchor,
|
|
9817
|
-
triggerStart: caretOffset - query.length - trigger.length,
|
|
9818
|
-
caretOffset
|
|
9819
|
-
};
|
|
9820
|
-
}
|
|
9821
|
-
}
|
|
9822
|
-
return null;
|
|
9823
|
-
}
|
|
9824
|
-
function chipIcon(item, source) {
|
|
9825
|
-
return item.icon ?? source.icon ?? (source.trigger === "@" ? "user" : "file-text");
|
|
9826
|
-
}
|
|
9827
|
-
var MentionInput = forwardRef(
|
|
9828
|
-
function MentionInput2({
|
|
9829
|
-
value,
|
|
9830
|
-
placeholder,
|
|
9831
|
-
disabled,
|
|
9832
|
-
sources,
|
|
9833
|
-
chips,
|
|
9834
|
-
onChipsChange,
|
|
9835
|
-
onChange,
|
|
9836
|
-
onSubmit,
|
|
9837
|
-
className,
|
|
9838
|
-
style
|
|
9839
|
-
}, ref) {
|
|
9840
|
-
const fieldRef = useRef11(null);
|
|
9841
|
-
const [menu, setMenu] = useState43(null);
|
|
9842
|
-
const [empty, setEmpty] = useState43(true);
|
|
9843
|
-
const suppressSyncRef = useRef11(false);
|
|
9844
|
-
const composingRef = useRef11(false);
|
|
9845
|
-
const emitChips = () => {
|
|
9846
|
-
if (suppressSyncRef.current || !fieldRef.current) {
|
|
9847
|
-
return;
|
|
9848
|
-
}
|
|
9849
|
-
onChipsChange?.(collectChips(fieldRef.current));
|
|
9850
|
-
};
|
|
9851
|
-
const serialize = () => fieldRef.current ? serializeNode(fieldRef.current).replace(/\n$/, "") : "";
|
|
9852
|
-
const buildChipElement = (item, source) => {
|
|
9853
|
-
const chip = document.createElement("span");
|
|
9854
|
-
chip.setAttribute(CHIP_ATTR, "");
|
|
9855
|
-
chip.dataset["id"] = item.id;
|
|
9856
|
-
chip.dataset["label"] = item.label;
|
|
9857
|
-
chip.dataset["trigger"] = item.trigger ?? source.trigger;
|
|
9858
|
-
chip.contentEditable = "false";
|
|
9859
|
-
chip.className = "mx-0.5 inline-flex items-center gap-1 rounded-md bg-muted px-1.5 py-0.5 align-middle text-xs text-foreground";
|
|
9860
|
-
const iconMarkup = renderToStaticMarkup(
|
|
9861
|
-
/* @__PURE__ */ jsx127(Icon, { name: chipIcon(item, source), size: 12 })
|
|
9862
|
-
);
|
|
9863
|
-
const label = document.createElement("span");
|
|
9864
|
-
label.textContent = item.label;
|
|
9865
|
-
chip.innerHTML = iconMarkup;
|
|
9866
|
-
chip.appendChild(label);
|
|
9867
|
-
return chip;
|
|
9868
|
-
};
|
|
9869
|
-
const insertChipElement = (item, source, replace) => {
|
|
9870
|
-
const field = fieldRef.current;
|
|
9871
|
-
if (!field) {
|
|
9872
|
-
return;
|
|
9873
|
-
}
|
|
9874
|
-
const chip = buildChipElement(item, source);
|
|
9875
|
-
let caretNode;
|
|
9876
|
-
if (replace) {
|
|
9877
|
-
const { node, start, end } = replace;
|
|
9878
|
-
const text = node.textContent ?? "";
|
|
9879
|
-
node.textContent = text.slice(0, start);
|
|
9880
|
-
caretNode = document.createTextNode(`${NBSP}${text.slice(end)}`);
|
|
9881
|
-
node.after(chip, caretNode);
|
|
9882
|
-
} else {
|
|
9883
|
-
caretNode = document.createTextNode(NBSP);
|
|
9884
|
-
const selection2 = window.getSelection();
|
|
9885
|
-
if (selection2 && selection2.rangeCount > 0 && selection2.anchorNode !== null && field.contains(selection2.anchorNode)) {
|
|
9886
|
-
const range = selection2.getRangeAt(0);
|
|
9887
|
-
range.deleteContents();
|
|
9888
|
-
range.insertNode(caretNode);
|
|
9889
|
-
range.insertNode(chip);
|
|
9890
|
-
} else {
|
|
9891
|
-
field.append(chip, caretNode);
|
|
9892
|
-
}
|
|
9893
|
-
}
|
|
9894
|
-
const selection = window.getSelection();
|
|
9895
|
-
if (selection) {
|
|
9896
|
-
const range = document.createRange();
|
|
9897
|
-
range.setStart(caretNode, 1);
|
|
9898
|
-
range.collapse(true);
|
|
9899
|
-
selection.removeAllRanges();
|
|
9900
|
-
selection.addRange(range);
|
|
9901
|
-
}
|
|
9902
|
-
setEmpty(false);
|
|
9903
|
-
onChange?.(serialize());
|
|
9904
|
-
emitChips();
|
|
9905
|
-
};
|
|
9906
|
-
useImperativeHandle(ref, () => ({
|
|
9907
|
-
insertChip: (item, source) => {
|
|
9908
|
-
fieldRef.current?.focus();
|
|
9909
|
-
insertChipElement(item, source);
|
|
9910
|
-
},
|
|
9911
|
-
focus: () => fieldRef.current?.focus()
|
|
9912
|
-
}));
|
|
9913
|
-
useEffect37(() => {
|
|
9914
|
-
const field = fieldRef.current;
|
|
9915
|
-
if (field && value === "" && serializeNode(field).trim() !== "") {
|
|
9916
|
-
suppressSyncRef.current = true;
|
|
9917
|
-
field.innerHTML = "";
|
|
9918
|
-
setEmpty(true);
|
|
9919
|
-
setMenu(null);
|
|
9920
|
-
suppressSyncRef.current = false;
|
|
9921
|
-
}
|
|
9922
|
-
}, [value]);
|
|
9923
|
-
useEffect37(() => {
|
|
9924
|
-
const field = fieldRef.current;
|
|
9925
|
-
if (!field) {
|
|
9926
|
-
return;
|
|
9927
|
-
}
|
|
9928
|
-
const keep = new Set(chips.map((chip) => `${chip.trigger}:${chip.id}`));
|
|
9929
|
-
const stale = Array.from(field.querySelectorAll(`[${CHIP_ATTR}]`)).filter(
|
|
9930
|
-
(el) => !keep.has(
|
|
9931
|
-
`${el.dataset["trigger"]}:${el.dataset["id"]}`
|
|
9932
|
-
)
|
|
9933
|
-
);
|
|
9934
|
-
if (stale.length > 0) {
|
|
9935
|
-
suppressSyncRef.current = true;
|
|
9936
|
-
stale.forEach((el) => el.remove());
|
|
9937
|
-
suppressSyncRef.current = false;
|
|
9938
|
-
setEmpty(serializeNode(field).trim() === "");
|
|
9939
|
-
}
|
|
9940
|
-
}, [chips]);
|
|
9941
|
-
const closeMenu = () => setMenu(null);
|
|
9942
|
-
const filteredItems = (state) => state.query ? state.source.items.filter((item) => item.label.includes(state.query)) : state.source.items;
|
|
9943
|
-
const refreshMenu = () => {
|
|
9944
|
-
const field = fieldRef.current;
|
|
9945
|
-
if (!field) {
|
|
9946
|
-
return;
|
|
9947
|
-
}
|
|
9948
|
-
const active = detectActiveMention(field, sources);
|
|
9949
|
-
if (!active) {
|
|
9950
|
-
setMenu(null);
|
|
9951
|
-
return;
|
|
9952
|
-
}
|
|
9953
|
-
const range = document.createRange();
|
|
9954
|
-
range.setStart(active.node, active.triggerStart);
|
|
9955
|
-
range.setEnd(active.node, active.caretOffset);
|
|
9956
|
-
const rect = typeof range.getBoundingClientRect === "function" ? range.getBoundingClientRect() : field.getBoundingClientRect();
|
|
9957
|
-
setMenu((prev) => ({
|
|
9958
|
-
source: active.source,
|
|
9959
|
-
query: active.query,
|
|
9960
|
-
left: rect.left,
|
|
9961
|
-
top: rect.top,
|
|
9962
|
-
// 过滤结果变化后候选下标钳制在有效范围内(DSL 每次渲染产出新
|
|
9963
|
-
// props 对象,source 按 trigger 比较而非引用)
|
|
9964
|
-
activeIndex: Math.min(
|
|
9965
|
-
prev?.source.trigger === active.source.trigger ? prev.activeIndex : 0,
|
|
9966
|
-
Math.max(filteredItems({ source: active.source, query: active.query, left: 0, top: 0, activeIndex: 0 }).length - 1, 0)
|
|
9967
|
-
)
|
|
9968
|
-
}));
|
|
9969
|
-
};
|
|
9970
|
-
const selectMenuItem = (item) => {
|
|
9971
|
-
const field = fieldRef.current;
|
|
9972
|
-
if (!field || !menu) {
|
|
9973
|
-
return;
|
|
9974
|
-
}
|
|
9975
|
-
const active = detectActiveMention(field, sources);
|
|
9976
|
-
insertChipElement(
|
|
9977
|
-
{ ...item, trigger: item.trigger ?? menu.source.trigger },
|
|
9978
|
-
menu.source,
|
|
9979
|
-
active && active.source.trigger === menu.source.trigger ? { node: active.node, start: active.triggerStart, end: active.caretOffset } : void 0
|
|
9980
|
-
);
|
|
9981
|
-
setMenu(null);
|
|
9982
|
-
};
|
|
9983
|
-
const handleInput = () => {
|
|
9984
|
-
const field = fieldRef.current;
|
|
9985
|
-
if (!field) {
|
|
9986
|
-
return;
|
|
9987
|
-
}
|
|
9988
|
-
if ((field.textContent ?? "") === "" && field.querySelector(`[${CHIP_ATTR}]`) === null) {
|
|
9989
|
-
field.innerHTML = "";
|
|
9990
|
-
}
|
|
9991
|
-
setEmpty(serializeNode(field).trim() === "");
|
|
9992
|
-
onChange?.(serialize());
|
|
9993
|
-
refreshMenu();
|
|
9994
|
-
};
|
|
9995
|
-
const handleKeyDown = (event) => {
|
|
9996
|
-
if (menu) {
|
|
9997
|
-
const items = filteredItems(menu);
|
|
9998
|
-
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
9999
|
-
event.preventDefault();
|
|
10000
|
-
if (items.length > 0) {
|
|
10001
|
-
const delta = event.key === "ArrowDown" ? 1 : -1;
|
|
10002
|
-
setMenu({
|
|
10003
|
-
...menu,
|
|
10004
|
-
activeIndex: (menu.activeIndex + delta + items.length) % items.length
|
|
10005
|
-
});
|
|
10006
|
-
}
|
|
10007
|
-
return;
|
|
10008
|
-
}
|
|
10009
|
-
if (event.key === "Enter" && !composingRef.current && !event.nativeEvent.isComposing) {
|
|
10010
|
-
event.preventDefault();
|
|
10011
|
-
const item = items[Math.min(menu.activeIndex, items.length - 1)];
|
|
10012
|
-
if (item) {
|
|
10013
|
-
selectMenuItem(item);
|
|
10014
|
-
} else {
|
|
10015
|
-
closeMenu();
|
|
10016
|
-
}
|
|
10017
|
-
return;
|
|
10018
|
-
}
|
|
10019
|
-
if (event.key === "Escape") {
|
|
10020
|
-
event.preventDefault();
|
|
10021
|
-
closeMenu();
|
|
10022
|
-
return;
|
|
10023
|
-
}
|
|
10024
|
-
}
|
|
10025
|
-
if (event.key === "Enter" && !event.shiftKey && !composingRef.current && !event.nativeEvent.isComposing) {
|
|
10026
|
-
event.preventDefault();
|
|
10027
|
-
const text = serialize();
|
|
10028
|
-
if (text.trim() !== "" && !disabled) {
|
|
10029
|
-
onSubmit?.(text);
|
|
10030
|
-
}
|
|
10031
|
-
return;
|
|
10032
|
-
}
|
|
10033
|
-
if (event.key === "Backspace") {
|
|
10034
|
-
const selection = window.getSelection();
|
|
10035
|
-
const field = fieldRef.current;
|
|
10036
|
-
if (!selection || !selection.isCollapsed || !field) {
|
|
10037
|
-
return;
|
|
10038
|
-
}
|
|
10039
|
-
let chip = null;
|
|
10040
|
-
const anchor = selection.anchorNode;
|
|
10041
|
-
if (anchor === field && selection.anchorOffset > 0) {
|
|
10042
|
-
const before = field.childNodes[selection.anchorOffset - 1];
|
|
10043
|
-
if (isChipElement(before)) {
|
|
10044
|
-
chip = before;
|
|
10045
|
-
}
|
|
10046
|
-
} else if (anchor?.nodeType === Node.TEXT_NODE && selection.anchorOffset === 0) {
|
|
10047
|
-
if (isChipElement(anchor.previousSibling)) {
|
|
10048
|
-
chip = anchor.previousSibling;
|
|
10049
|
-
}
|
|
10050
|
-
}
|
|
10051
|
-
if (chip) {
|
|
10052
|
-
event.preventDefault();
|
|
10053
|
-
chip.remove();
|
|
10054
|
-
onChange?.(serialize());
|
|
10055
|
-
emitChips();
|
|
10056
|
-
setEmpty(serializeNode(field).trim() === "");
|
|
10057
|
-
}
|
|
10058
|
-
}
|
|
10059
|
-
};
|
|
10060
|
-
const menuItems = menu ? filteredItems(menu) : [];
|
|
10061
|
-
const activeIndex = Math.min(menu?.activeIndex ?? 0, Math.max(menuItems.length - 1, 0));
|
|
10062
|
-
return /* @__PURE__ */ jsxs87("div", { className: "relative", children: [
|
|
10063
|
-
/* @__PURE__ */ jsx127(
|
|
10064
|
-
"div",
|
|
10065
|
-
{
|
|
10066
|
-
ref: fieldRef,
|
|
10067
|
-
"data-slot": "mention-input",
|
|
10068
|
-
role: "textbox",
|
|
10069
|
-
"aria-multiline": "true",
|
|
10070
|
-
"aria-placeholder": placeholder,
|
|
10071
|
-
contentEditable: !disabled,
|
|
10072
|
-
suppressContentEditableWarning: true,
|
|
10073
|
-
className: cn(
|
|
10074
|
-
"min-h-[60px] w-full px-4 pt-3 pb-1 text-sm whitespace-pre-wrap break-words outline-none",
|
|
10075
|
-
className
|
|
10076
|
-
),
|
|
10077
|
-
style,
|
|
10078
|
-
onInput: handleInput,
|
|
10079
|
-
onKeyDown: handleKeyDown,
|
|
10080
|
-
onCompositionStart: () => {
|
|
10081
|
-
composingRef.current = true;
|
|
10082
|
-
},
|
|
10083
|
-
onCompositionEnd: () => {
|
|
10084
|
-
composingRef.current = false;
|
|
10085
|
-
},
|
|
10086
|
-
onPaste: (event) => {
|
|
10087
|
-
event.preventDefault();
|
|
10088
|
-
const text = event.clipboardData?.getData("text/plain") ?? "";
|
|
10089
|
-
if (text) {
|
|
10090
|
-
document.execCommand("insertText", false, text);
|
|
10091
|
-
}
|
|
10092
|
-
}
|
|
10093
|
-
}
|
|
10094
|
-
),
|
|
10095
|
-
empty && placeholder !== void 0 ? /* @__PURE__ */ jsx127("span", { className: "pointer-events-none absolute top-3 left-4 text-sm text-muted-foreground", children: placeholder }) : null,
|
|
10096
|
-
menu ? /* @__PURE__ */ jsxs87(Fragment16, { children: [
|
|
10097
|
-
/* @__PURE__ */ jsx127(
|
|
10098
|
-
"div",
|
|
10099
|
-
{
|
|
10100
|
-
className: "fixed inset-0 z-40",
|
|
10101
|
-
onMouseDown: (event) => {
|
|
10102
|
-
event.preventDefault();
|
|
10103
|
-
closeMenu();
|
|
10104
|
-
}
|
|
10105
|
-
}
|
|
10106
|
-
),
|
|
10107
|
-
/* @__PURE__ */ jsxs87(
|
|
10108
|
-
"div",
|
|
10109
|
-
{
|
|
10110
|
-
"data-slot": "mention-menu",
|
|
10111
|
-
role: "listbox",
|
|
10112
|
-
className: "scrollbar-subtle fixed z-50 max-h-72 w-64 overflow-y-auto rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md",
|
|
10113
|
-
style: {
|
|
10114
|
-
left: menu.left,
|
|
10115
|
-
bottom: typeof window === "undefined" ? void 0 : window.innerHeight - menu.top + 6
|
|
10116
|
-
},
|
|
10117
|
-
children: [
|
|
10118
|
-
/* @__PURE__ */ jsx127("div", { className: "px-2 py-1 text-xs text-muted-foreground", children: menu.source.label }),
|
|
10119
|
-
menuItems.length === 0 ? /* @__PURE__ */ jsx127("div", { className: "px-2 py-2 text-xs text-muted-foreground", children: "\u65E0\u5339\u914D\u9879" }) : menuItems.map((item, index) => /* @__PURE__ */ jsxs87(
|
|
10120
|
-
"button",
|
|
10121
|
-
{
|
|
10122
|
-
type: "button",
|
|
10123
|
-
role: "option",
|
|
10124
|
-
"aria-selected": index === activeIndex,
|
|
10125
|
-
className: cn(
|
|
10126
|
-
"flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm",
|
|
10127
|
-
index === activeIndex ? "bg-accent" : "hover:bg-accent"
|
|
10128
|
-
),
|
|
10129
|
-
onMouseDown: (event) => {
|
|
10130
|
-
event.preventDefault();
|
|
10131
|
-
selectMenuItem(item);
|
|
10132
|
-
},
|
|
10133
|
-
children: [
|
|
10134
|
-
/* @__PURE__ */ jsx127(Icon, { name: chipIcon(item, menu.source), size: "sm" }),
|
|
10135
|
-
/* @__PURE__ */ jsx127("span", { className: "min-w-0 flex-1 truncate", children: item.label })
|
|
10136
|
-
]
|
|
10137
|
-
},
|
|
10138
|
-
item.id
|
|
10139
|
-
))
|
|
10140
|
-
]
|
|
10141
|
-
}
|
|
10142
|
-
)
|
|
10143
|
-
] }) : null
|
|
10144
|
-
] });
|
|
10145
|
-
}
|
|
10146
|
-
);
|
|
10147
|
-
|
|
10148
|
-
// src/components/chat/Composer/index.tsx
|
|
10149
|
-
import { Fragment as Fragment17, jsx as jsx128, jsxs as jsxs88 } from "react/jsx-runtime";
|
|
10150
|
-
var toolButtonClass3 = "flex cursor-pointer items-center rounded-md p-1.5 text-muted-foreground hover:bg-accent hover:text-foreground";
|
|
10151
|
-
var popoverPanelClass = "absolute bottom-full left-0 z-50 mb-2 max-h-72 w-64 overflow-y-auto rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md";
|
|
10152
|
-
var popoverItemClass = "flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm hover:bg-accent";
|
|
10153
|
-
function Composer({
|
|
10154
|
-
value,
|
|
10155
|
-
placeholder,
|
|
10156
|
-
disabled,
|
|
10157
|
-
loading,
|
|
10158
|
-
rows,
|
|
10159
|
-
attachments = [],
|
|
10160
|
-
onRemoveAttachment,
|
|
10161
|
-
onRetryAttachment,
|
|
10162
|
-
onAttachFiles,
|
|
10163
|
-
onChange,
|
|
10164
|
-
onSubmit,
|
|
10165
|
-
models,
|
|
10166
|
-
model,
|
|
10167
|
-
onModelChange,
|
|
10168
|
-
contexts,
|
|
10169
|
-
contextItems,
|
|
10170
|
-
onContextItemsChange,
|
|
10171
|
-
footer,
|
|
10172
|
-
className,
|
|
10173
|
-
style
|
|
10174
|
-
}) {
|
|
10175
|
-
const textControlled = value !== void 0;
|
|
10176
|
-
const [innerText, setInnerText] = useState44("");
|
|
10177
|
-
const text = textControlled ? value : innerText;
|
|
10178
|
-
const [dragOver, setDragOver] = useState44(false);
|
|
10179
|
-
const [plusOpen, setPlusOpen] = useState44(false);
|
|
10180
|
-
const [modelOpen, setModelOpen] = useState44(false);
|
|
10181
|
-
const fileInputRef = useRef12(null);
|
|
10182
|
-
const mentionRef = useRef12(null);
|
|
10183
|
-
const sources = contexts ?? [];
|
|
10184
|
-
const rich = sources.length > 0;
|
|
10185
|
-
const plusSources = sources.filter((s) => s.trigger === "+");
|
|
10186
|
-
const plusEnabled = plusSources.length > 0;
|
|
10187
|
-
const modelEnabled = models !== void 0 && models.length > 0;
|
|
10188
|
-
const currentModel = models?.find((m) => m.value === model) ?? models?.[0];
|
|
10189
|
-
const [innerChips, setInnerChips] = useState44([]);
|
|
10190
|
-
const chipsControlled = contextItems !== void 0;
|
|
10191
|
-
const chips = chipsControlled ? contextItems : innerChips;
|
|
10192
|
-
const handleChipsChange = (next) => {
|
|
10193
|
-
if (!chipsControlled) {
|
|
10194
|
-
setInnerChips(next);
|
|
10195
|
-
}
|
|
10196
|
-
onContextItemsChange?.(next);
|
|
10197
|
-
};
|
|
10198
|
-
const closePopovers = () => {
|
|
10199
|
-
setPlusOpen(false);
|
|
10200
|
-
setModelOpen(false);
|
|
10201
|
-
};
|
|
10202
|
-
const handleChange = (next) => {
|
|
10203
|
-
if (!textControlled) {
|
|
10204
|
-
setInnerText(next);
|
|
10205
|
-
}
|
|
10206
|
-
onChange?.(next);
|
|
10207
|
-
};
|
|
10208
|
-
const handleSubmit = (submitted) => {
|
|
10209
|
-
onSubmit?.(submitted);
|
|
10210
|
-
if (!textControlled) {
|
|
10211
|
-
setInnerText("");
|
|
10212
|
-
}
|
|
10213
|
-
closePopovers();
|
|
10214
|
-
};
|
|
10215
|
-
const selectContext = (item, source) => {
|
|
10216
|
-
if (rich) {
|
|
10217
|
-
mentionRef.current?.insertChip(item, source);
|
|
10218
|
-
} else {
|
|
10219
|
-
const chip = { ...item, trigger: item.trigger ?? source.trigger };
|
|
10220
|
-
const duplicated = chips.some(
|
|
10221
|
-
(existing) => existing.id === chip.id && existing.trigger === chip.trigger
|
|
10222
|
-
);
|
|
10223
|
-
if (!duplicated) {
|
|
10224
|
-
handleChipsChange([...chips, chip]);
|
|
10225
|
-
}
|
|
10226
|
-
}
|
|
10227
|
-
closePopovers();
|
|
10228
|
-
};
|
|
10229
|
-
const emitFiles = (files) => {
|
|
10230
|
-
if (files.length > 0 && onAttachFiles) {
|
|
10231
|
-
onAttachFiles(files);
|
|
10232
|
-
}
|
|
10233
|
-
};
|
|
10234
|
-
const handleDrop = (event) => {
|
|
10235
|
-
if (!onAttachFiles) {
|
|
10236
|
-
return;
|
|
10237
|
-
}
|
|
10238
|
-
event.preventDefault();
|
|
10239
|
-
setDragOver(false);
|
|
10240
|
-
emitFiles(Array.from(event.dataTransfer?.files ?? []));
|
|
10241
|
-
};
|
|
10242
|
-
const toolbarStart = plusEnabled || onAttachFiles ? /* @__PURE__ */ jsxs88(Fragment17, { children: [
|
|
10243
|
-
plusEnabled ? /* @__PURE__ */ jsx128(
|
|
10244
|
-
"button",
|
|
10245
|
-
{
|
|
10246
|
-
type: "button",
|
|
10247
|
-
"aria-label": "\u6DFB\u52A0\u4E0A\u4E0B\u6587",
|
|
10248
|
-
title: "\u6DFB\u52A0\u4E0A\u4E0B\u6587",
|
|
10249
|
-
className: toolButtonClass3,
|
|
10250
|
-
onClick: () => {
|
|
10251
|
-
setPlusOpen((prev) => !prev);
|
|
10252
|
-
setModelOpen(false);
|
|
10253
|
-
},
|
|
10254
|
-
children: /* @__PURE__ */ jsx128(Icon, { name: "plus", size: "sm" })
|
|
10255
|
-
}
|
|
10256
|
-
) : null,
|
|
10257
|
-
onAttachFiles ? /* @__PURE__ */ jsx128(
|
|
10258
|
-
"button",
|
|
10259
|
-
{
|
|
10260
|
-
type: "button",
|
|
10261
|
-
"aria-label": "\u6DFB\u52A0\u9644\u4EF6",
|
|
10262
|
-
title: "\u6DFB\u52A0\u9644\u4EF6",
|
|
10263
|
-
className: toolButtonClass3,
|
|
10264
|
-
onClick: () => fileInputRef.current?.click(),
|
|
10265
|
-
children: /* @__PURE__ */ jsx128(Icon, { name: "paperclip", size: "sm" })
|
|
10266
|
-
}
|
|
10267
|
-
) : null
|
|
10268
|
-
] }) : void 0;
|
|
10269
|
-
const toolbarEnd = modelEnabled ? /* @__PURE__ */ jsxs88(
|
|
10270
|
-
"button",
|
|
10271
|
-
{
|
|
10272
|
-
type: "button",
|
|
10273
|
-
"aria-label": "\u9009\u62E9\u6A21\u578B",
|
|
10274
|
-
title: "\u9009\u62E9\u6A21\u578B",
|
|
10275
|
-
className: "flex cursor-pointer items-center gap-1 rounded-md px-2 py-1 text-xs text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
10276
|
-
onClick: () => {
|
|
10277
|
-
setModelOpen((prev) => !prev);
|
|
10278
|
-
setPlusOpen(false);
|
|
10279
|
-
},
|
|
10280
|
-
children: [
|
|
10281
|
-
currentModel?.label,
|
|
10282
|
-
/* @__PURE__ */ jsx128(Icon, { name: "chevrons-up-down", size: 12 })
|
|
10283
|
-
]
|
|
10284
|
-
}
|
|
10285
|
-
) : void 0;
|
|
10286
|
-
const activePopover = plusOpen ? "plus" : modelOpen ? "model" : null;
|
|
10287
|
-
return /* @__PURE__ */ jsxs88(
|
|
10288
|
-
"div",
|
|
10289
|
-
{
|
|
10290
|
-
"data-slot": "composer",
|
|
10291
|
-
className: cn("relative flex w-full flex-col gap-2", className),
|
|
10292
|
-
style,
|
|
10293
|
-
onDragOver: (event) => {
|
|
10294
|
-
if (onAttachFiles) {
|
|
10295
|
-
event.preventDefault();
|
|
10296
|
-
setDragOver(true);
|
|
10297
|
-
}
|
|
10298
|
-
},
|
|
10299
|
-
onDragLeave: () => setDragOver(false),
|
|
10300
|
-
onDrop: handleDrop,
|
|
10301
|
-
onPaste: (event) => {
|
|
10302
|
-
const files = Array.from(event.clipboardData?.files ?? []);
|
|
10303
|
-
if (files.length > 0 && onAttachFiles) {
|
|
10304
|
-
event.preventDefault();
|
|
10305
|
-
emitFiles(files);
|
|
10306
|
-
}
|
|
10307
|
-
},
|
|
10308
|
-
children: [
|
|
10309
|
-
attachments.length > 0 ? /* @__PURE__ */ jsx128(Attachment, { items: attachments, onRemove: onRemoveAttachment, onRetry: onRetryAttachment }) : null,
|
|
10310
|
-
/* @__PURE__ */ jsx128("div", { className: cn(dragOver && "rounded-xl ring-2 ring-ring/50"), children: /* @__PURE__ */ jsx128(
|
|
10311
|
-
ChatInput,
|
|
10312
|
-
{
|
|
10313
|
-
value: text,
|
|
10314
|
-
placeholder,
|
|
10315
|
-
disabled: disabled || loading,
|
|
10316
|
-
rows,
|
|
10317
|
-
toolbarStart,
|
|
10318
|
-
toolbarEnd,
|
|
10319
|
-
footer,
|
|
10320
|
-
field: rich ? /* @__PURE__ */ jsx128(
|
|
10321
|
-
MentionInput,
|
|
10322
|
-
{
|
|
10323
|
-
ref: mentionRef,
|
|
10324
|
-
value: text,
|
|
10325
|
-
placeholder,
|
|
10326
|
-
disabled: disabled || loading,
|
|
10327
|
-
sources,
|
|
10328
|
-
chips,
|
|
10329
|
-
onChipsChange: handleChipsChange,
|
|
10330
|
-
onChange: handleChange,
|
|
10331
|
-
onSubmit: handleSubmit
|
|
10332
|
-
}
|
|
10333
|
-
) : void 0,
|
|
10334
|
-
onChange: handleChange,
|
|
10335
|
-
onSubmit: handleSubmit
|
|
10336
|
-
}
|
|
10337
|
-
) }),
|
|
10338
|
-
onAttachFiles ? /* @__PURE__ */ jsx128(
|
|
10339
|
-
"input",
|
|
10340
|
-
{
|
|
10341
|
-
ref: fileInputRef,
|
|
10342
|
-
type: "file",
|
|
10343
|
-
multiple: true,
|
|
10344
|
-
hidden: true,
|
|
10345
|
-
onChange: (event) => {
|
|
10346
|
-
emitFiles(Array.from(event.target.files ?? []));
|
|
10347
|
-
event.target.value = "";
|
|
10348
|
-
}
|
|
10349
|
-
}
|
|
10350
|
-
) : null,
|
|
10351
|
-
activePopover !== null ? /* @__PURE__ */ jsxs88(Fragment17, { children: [
|
|
10352
|
-
/* @__PURE__ */ jsx128("div", { className: "fixed inset-0 z-40", onClick: closePopovers }),
|
|
10353
|
-
activePopover === "model" ? /* @__PURE__ */ jsx128("div", { "data-slot": "composer-model-popover", className: cn(popoverPanelClass, "right-0 left-auto w-48"), role: "listbox", children: models.map((option) => /* @__PURE__ */ jsxs88(
|
|
10354
|
-
"button",
|
|
10355
|
-
{
|
|
10356
|
-
type: "button",
|
|
10357
|
-
role: "option",
|
|
10358
|
-
"aria-selected": option.value === currentModel?.value,
|
|
10359
|
-
className: popoverItemClass,
|
|
10360
|
-
onClick: () => {
|
|
10361
|
-
onModelChange?.(option.value);
|
|
10362
|
-
closePopovers();
|
|
10363
|
-
},
|
|
10364
|
-
children: [
|
|
10365
|
-
/* @__PURE__ */ jsx128("span", { className: "min-w-0 flex-1 truncate", children: option.label }),
|
|
10366
|
-
option.value === currentModel?.value ? /* @__PURE__ */ jsx128(Icon, { name: "check", size: 14 }) : null
|
|
10367
|
-
]
|
|
10368
|
-
},
|
|
10369
|
-
option.value
|
|
10370
|
-
)) }) : /* @__PURE__ */ jsx128("div", { "data-slot": "composer-context-popover", className: popoverPanelClass, role: "listbox", children: plusSources.map(
|
|
10371
|
-
(source) => source.items.length === 0 ? null : /* @__PURE__ */ jsxs88("div", { children: [
|
|
10372
|
-
/* @__PURE__ */ jsx128("div", { className: "px-2 py-1 text-xs text-muted-foreground", children: source.label }),
|
|
10373
|
-
source.items.map((item) => /* @__PURE__ */ jsxs88(
|
|
10374
|
-
"button",
|
|
10375
|
-
{
|
|
10376
|
-
type: "button",
|
|
10377
|
-
className: popoverItemClass,
|
|
10378
|
-
onClick: () => selectContext(item, source),
|
|
10379
|
-
children: [
|
|
10380
|
-
/* @__PURE__ */ jsx128(Icon, { name: item.icon ?? source.icon ?? "file-text", size: "sm" }),
|
|
10381
|
-
/* @__PURE__ */ jsx128("span", { className: "min-w-0 flex-1 truncate", children: item.label })
|
|
10382
|
-
]
|
|
10383
|
-
},
|
|
10384
|
-
item.id
|
|
10385
|
-
))
|
|
10386
|
-
] }, source.trigger)
|
|
10387
|
-
) })
|
|
10388
|
-
] }) : null
|
|
10389
|
-
]
|
|
10390
|
-
}
|
|
10391
|
-
);
|
|
10392
|
-
}
|
|
10393
|
-
|
|
10394
|
-
// src/components/chat/ConversationList/index.tsx
|
|
10395
|
-
import { useMemo as useMemo7, useState as useState45 } from "react";
|
|
10396
|
-
import { jsx as jsx129, jsxs as jsxs89 } from "react/jsx-runtime";
|
|
10397
|
-
function ConversationList({ items = [], activeId, searchable, onSelect, onDelete, className, style }) {
|
|
10398
|
-
const [innerActive, setInnerActive] = useState45();
|
|
10399
|
-
const [keyword, setKeyword] = useState45("");
|
|
10400
|
-
const active = activeId ?? innerActive;
|
|
10401
|
-
const filtered = useMemo7(() => {
|
|
10402
|
-
const query = keyword.trim().toLowerCase();
|
|
10403
|
-
if (!query) return items;
|
|
10404
|
-
return items.filter(
|
|
10405
|
-
(item) => item.title.toLowerCase().includes(query) || (item.description ?? "").toLowerCase().includes(query)
|
|
10406
|
-
);
|
|
10407
|
-
}, [items, keyword]);
|
|
10408
|
-
const select = (id) => {
|
|
10409
|
-
if (activeId === void 0) {
|
|
10410
|
-
setInnerActive(id);
|
|
10411
|
-
}
|
|
10412
|
-
onSelect?.(id);
|
|
10413
|
-
};
|
|
10414
|
-
return /* @__PURE__ */ jsxs89("div", { "data-slot": "conversation-list", className: cn("flex w-full flex-col gap-1", className), style, children: [
|
|
10415
|
-
searchable ? /* @__PURE__ */ jsxs89("div", { className: "relative mb-1", children: [
|
|
10416
|
-
/* @__PURE__ */ jsx129("span", { className: "absolute top-1/2 left-2 -translate-y-1/2 text-muted-foreground", children: /* @__PURE__ */ jsx129(Icon, { name: "search", size: "sm" }) }),
|
|
10417
|
-
/* @__PURE__ */ jsx129(
|
|
10418
|
-
"input",
|
|
10419
|
-
{
|
|
10420
|
-
"data-slot": "conversation-list-search",
|
|
10421
|
-
value: keyword,
|
|
10422
|
-
placeholder: "\u641C\u7D22\u4F1A\u8BDD",
|
|
10423
|
-
className: "h-8 w-full rounded-md border border-border bg-background pr-2 pl-7 text-sm outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
10424
|
-
onChange: (event) => setKeyword(event.target.value)
|
|
10425
|
-
}
|
|
10426
|
-
)
|
|
10427
|
-
] }) : null,
|
|
10428
|
-
filtered.map((item) => /* @__PURE__ */ jsxs89(
|
|
10429
|
-
"div",
|
|
10430
|
-
{
|
|
10431
|
-
"data-slot": "conversation-list-item",
|
|
10432
|
-
"data-active": item.id === active || void 0,
|
|
10433
|
-
className: cn(
|
|
10434
|
-
"group flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 hover:bg-accent",
|
|
10435
|
-
item.id === active && "bg-accent"
|
|
10436
|
-
),
|
|
10437
|
-
onClick: () => select(item.id),
|
|
10438
|
-
children: [
|
|
10439
|
-
/* @__PURE__ */ jsxs89("div", { className: "min-w-0 flex-1", children: [
|
|
10440
|
-
/* @__PURE__ */ jsx129("div", { className: cn("truncate text-sm", item.id === active && "font-medium"), children: item.title }),
|
|
10441
|
-
item.description ? /* @__PURE__ */ jsx129("div", { className: "truncate text-xs text-muted-foreground", children: item.description }) : null
|
|
10442
|
-
] }),
|
|
10443
|
-
item.time ? /* @__PURE__ */ jsx129("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.time }) : null,
|
|
10444
|
-
onDelete ? /* @__PURE__ */ jsx129(
|
|
10445
|
-
"button",
|
|
10446
|
-
{
|
|
10447
|
-
type: "button",
|
|
10448
|
-
"data-slot": "conversation-list-delete",
|
|
10449
|
-
"aria-label": `\u5220\u9664 ${item.title}`,
|
|
10450
|
-
className: "shrink-0 text-muted-foreground opacity-0 group-hover:opacity-100 hover:text-destructive",
|
|
10451
|
-
onClick: (event) => {
|
|
10452
|
-
event.stopPropagation();
|
|
10453
|
-
onDelete(item.id);
|
|
10454
|
-
},
|
|
10455
|
-
children: /* @__PURE__ */ jsx129(Icon, { name: "trash-2", size: "sm" })
|
|
10456
|
-
}
|
|
10457
|
-
) : null
|
|
10458
|
-
]
|
|
10459
|
-
},
|
|
10460
|
-
item.id
|
|
10461
|
-
)),
|
|
10462
|
-
filtered.length === 0 ? /* @__PURE__ */ jsx129("div", { className: "px-2 py-4 text-center text-sm text-muted-foreground", children: "\u65E0\u5339\u914D\u4F1A\u8BDD" }) : null
|
|
10463
|
-
] });
|
|
10464
|
-
}
|
|
10465
|
-
|
|
10466
|
-
// src/components/chat/MessageList/index.tsx
|
|
10467
|
-
import { useEffect as useEffect38, useRef as useRef13 } from "react";
|
|
10468
|
-
import { jsx as jsx130 } from "react/jsx-runtime";
|
|
10469
|
-
function MessageList({ messages = [], autoScroll = true, onAction, onOpenArtifacts, className, style }) {
|
|
10470
|
-
const listRef = useRef13(null);
|
|
10471
|
-
useEffect38(() => {
|
|
10472
|
-
if (!autoScroll) return;
|
|
10473
|
-
const el = listRef.current;
|
|
10474
|
-
if (el) {
|
|
10475
|
-
el.scrollTop = el.scrollHeight;
|
|
10476
|
-
}
|
|
10477
|
-
}, [messages, autoScroll]);
|
|
10478
|
-
return /* @__PURE__ */ jsx130(
|
|
10479
|
-
"div",
|
|
10480
|
-
{
|
|
10481
|
-
ref: listRef,
|
|
10482
|
-
"data-slot": "message-list",
|
|
10483
|
-
className: cn("flex w-full flex-col gap-4 overflow-y-auto", className),
|
|
10484
|
-
style,
|
|
10485
|
-
children: messages.map((message, index) => /* @__PURE__ */ jsx130(
|
|
10486
|
-
ChatMessage,
|
|
10487
|
-
{
|
|
10488
|
-
...message,
|
|
10489
|
-
onAction: (action) => onAction?.({ id: message.id, action }),
|
|
10490
|
-
onOpenArtifacts: onOpenArtifacts ? () => onOpenArtifacts({ id: message.id }) : void 0
|
|
10491
|
-
},
|
|
10492
|
-
message.id ?? index
|
|
10493
|
-
))
|
|
10494
|
-
}
|
|
10495
|
-
);
|
|
10496
|
-
}
|
|
10497
|
-
|
|
10498
|
-
// src/components/chat/Prompt/index.tsx
|
|
10499
|
-
import { jsx as jsx131, jsxs as jsxs90 } from "react/jsx-runtime";
|
|
10500
|
-
function Prompt({ title, description, icon, value, disabled, onSelect, className, style }) {
|
|
10501
|
-
return /* @__PURE__ */ jsxs90(
|
|
10502
|
-
"button",
|
|
10503
|
-
{
|
|
10504
|
-
type: "button",
|
|
10505
|
-
"data-slot": "prompt",
|
|
10506
|
-
disabled,
|
|
10507
|
-
className: cn(
|
|
10508
|
-
"flex items-start gap-2.5 rounded-md border border-border p-3 text-left transition-colors hover:border-primary disabled:pointer-events-none disabled:opacity-50",
|
|
10509
|
-
className
|
|
10510
|
-
),
|
|
10511
|
-
style,
|
|
10512
|
-
onClick: () => onSelect?.(value ?? title ?? ""),
|
|
10513
|
-
children: [
|
|
10514
|
-
icon ? /* @__PURE__ */ jsx131("span", { className: "mt-0.5 shrink-0 text-primary", children: /* @__PURE__ */ jsx131(Icon, { name: icon, size: "sm" }) }) : null,
|
|
10515
|
-
/* @__PURE__ */ jsxs90("span", { className: "min-w-0", children: [
|
|
10516
|
-
/* @__PURE__ */ jsx131("span", { "data-slot": "prompt-title", className: "block text-sm font-medium", children: title }),
|
|
10517
|
-
description ? /* @__PURE__ */ jsx131("span", { "data-slot": "prompt-description", className: "mt-0.5 block text-xs text-muted-foreground", children: description }) : null
|
|
10518
|
-
] })
|
|
10519
|
-
]
|
|
10520
|
-
}
|
|
10521
|
-
);
|
|
10522
|
-
}
|
|
10523
|
-
|
|
10524
|
-
// src/components/chat/Welcome/index.tsx
|
|
10525
|
-
import { jsx as jsx132, jsxs as jsxs91 } from "react/jsx-runtime";
|
|
10526
|
-
function Welcome({
|
|
10527
|
-
title = "\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u4F60\uFF1F",
|
|
10528
|
-
description,
|
|
10529
|
-
icon = "chat",
|
|
10530
|
-
prompts = [],
|
|
10531
|
-
onSelect,
|
|
10532
|
-
className,
|
|
10533
|
-
style
|
|
10534
|
-
}) {
|
|
10535
|
-
return /* @__PURE__ */ jsxs91(
|
|
10536
|
-
"div",
|
|
10537
|
-
{
|
|
10538
|
-
"data-slot": "welcome",
|
|
10539
|
-
className: cn("flex w-full flex-col items-center gap-4 py-10 text-center", className),
|
|
10540
|
-
style,
|
|
10541
|
-
children: [
|
|
10542
|
-
/* @__PURE__ */ jsx132("span", { "data-slot": "welcome-icon", className: "text-primary", children: /* @__PURE__ */ jsx132(Icon, { name: icon, size: "lg" }) }),
|
|
10543
|
-
/* @__PURE__ */ jsxs91("div", { children: [
|
|
10544
|
-
/* @__PURE__ */ jsx132("div", { "data-slot": "welcome-title", className: "text-xl font-semibold", children: title }),
|
|
10545
|
-
description ? /* @__PURE__ */ jsx132("div", { "data-slot": "welcome-description", className: "mt-1 text-sm text-muted-foreground", children: description }) : null
|
|
10546
|
-
] }),
|
|
10547
|
-
prompts.length > 0 ? /* @__PURE__ */ jsx132("div", { "data-slot": "welcome-prompts", className: "grid w-full max-w-xl grid-cols-1 gap-3 text-left sm:grid-cols-2", children: prompts.map((item, index) => /* @__PURE__ */ jsx132(
|
|
10548
|
-
Prompt,
|
|
10549
|
-
{
|
|
10550
|
-
title: item.title,
|
|
10551
|
-
description: item.description,
|
|
10552
|
-
icon: item.icon,
|
|
10553
|
-
value: item.value,
|
|
10554
|
-
onSelect
|
|
10555
|
-
},
|
|
10556
|
-
`${item.title}-${index}`
|
|
10557
|
-
)) }) : null
|
|
10558
|
-
]
|
|
10559
|
-
}
|
|
10560
|
-
);
|
|
10561
|
-
}
|
|
10562
|
-
|
|
10563
|
-
// src/components/chat/ChatPage/index.tsx
|
|
10564
|
-
import { jsx as jsx133, jsxs as jsxs92 } from "react/jsx-runtime";
|
|
10565
|
-
function ChatPage({
|
|
10566
|
-
brand,
|
|
10567
|
-
menuItems = [],
|
|
10568
|
-
activeMenuKey,
|
|
10569
|
-
railItems = [],
|
|
10570
|
-
railFooterItems = [],
|
|
10571
|
-
menuAction,
|
|
10572
|
-
onMenuSelect,
|
|
10573
|
-
onMenuAction,
|
|
10574
|
-
conversationSectionTitle,
|
|
10575
|
-
conversationSectionCollapsed,
|
|
10576
|
-
defaultConversationSectionCollapsed = false,
|
|
10577
|
-
onConversationSectionToggle,
|
|
10578
|
-
conversations = [],
|
|
10579
|
-
activeConversationId,
|
|
10580
|
-
onSelectConversation,
|
|
10581
|
-
onDeleteConversation,
|
|
10582
|
-
moreLabel,
|
|
10583
|
-
onMore,
|
|
10584
|
-
footerSectionTitle,
|
|
10585
|
-
footerItems = [],
|
|
10586
|
-
footerSectionCollapsed,
|
|
10587
|
-
defaultFooterSectionCollapsed = false,
|
|
10588
|
-
onFooterSectionToggle,
|
|
10589
|
-
conversationTitle,
|
|
10590
|
-
conversationHeaderAction,
|
|
10591
|
-
onConversationHeaderAction,
|
|
10592
|
-
conversationRailItems = [],
|
|
10593
|
-
hideArtifactRailItem = false,
|
|
10594
|
-
activeConversationRailKey,
|
|
10595
|
-
onConversationRailChange,
|
|
10596
|
-
messages = [],
|
|
10597
|
-
sending,
|
|
10598
|
-
composerPlaceholder,
|
|
10599
|
-
welcome,
|
|
10600
|
-
onSend,
|
|
10601
|
-
onMessageAction,
|
|
10602
|
-
models,
|
|
10603
|
-
model,
|
|
10604
|
-
onModelChange,
|
|
10605
|
-
contexts,
|
|
10606
|
-
contextItems,
|
|
10607
|
-
onContextItemsChange,
|
|
10608
|
-
attachments,
|
|
10609
|
-
onAttachFiles,
|
|
10610
|
-
onRemoveAttachment,
|
|
10611
|
-
onRetryAttachment,
|
|
10612
|
-
composerFooter,
|
|
10613
|
-
composerBottom,
|
|
10614
|
-
artifactTitle = "\u4EA7\u7269",
|
|
10615
|
-
artifacts = [],
|
|
10616
|
-
activeArtifactId,
|
|
10617
|
-
onSelectArtifact,
|
|
10618
|
-
artifactEmptyText = "\u6682\u65E0\u4EA7\u7269\uFF0C\u53D1\u9001\u6D88\u606F\u540E\u751F\u6210\u7684\u6587\u4EF6\u5C06\u5C55\u793A\u5728\u8FD9\u91CC",
|
|
10619
|
-
safeRegistry,
|
|
10620
|
-
user,
|
|
10621
|
-
artifactViewers,
|
|
10622
|
-
onDownloadArtifact,
|
|
10623
|
-
artifactOpen,
|
|
10624
|
-
defaultArtifactOpen = false,
|
|
10625
|
-
onArtifactOpenChange,
|
|
10626
|
-
content,
|
|
10627
|
-
className,
|
|
10628
|
-
style
|
|
10629
|
-
}) {
|
|
10630
|
-
const controlled = artifactOpen !== void 0;
|
|
10631
|
-
const [innerOpen, setInnerOpen] = useState46(defaultArtifactOpen);
|
|
10632
|
-
const open = controlled ? artifactOpen === true : innerOpen;
|
|
10633
|
-
const setOpen = (next) => {
|
|
10634
|
-
if (!controlled) setInnerOpen(next);
|
|
10635
|
-
onArtifactOpenChange?.(next);
|
|
10636
|
-
};
|
|
10637
|
-
const railControlled = activeConversationRailKey !== void 0;
|
|
10638
|
-
const [activeRailInner, setActiveRailInner] = useState46(null);
|
|
10639
|
-
const activeRailKey = railControlled ? activeConversationRailKey : activeRailInner;
|
|
10640
|
-
const setActiveRailKey = (next) => {
|
|
10641
|
-
if (!railControlled) setActiveRailInner(next);
|
|
10642
|
-
onConversationRailChange?.(next);
|
|
10643
|
-
};
|
|
10644
|
-
const visibleRailItems = conversationRailItems.filter((item) => item.hidden !== true);
|
|
10645
|
-
const activeRailItem = visibleRailItems.find(
|
|
10646
|
-
(item) => item.key === activeRailKey
|
|
10647
|
-
);
|
|
10648
|
-
const activePanelItem = activeRailItem?.display === "panel" && activeRailItem.content !== void 0 ? activeRailItem : void 0;
|
|
10649
|
-
const activePopoverItem = activeRailItem !== void 0 && activeRailItem.display !== "panel" && activeRailItem.content !== void 0 ? activeRailItem : void 0;
|
|
10650
|
-
const toggleRailItem = (item) => {
|
|
10651
|
-
const next = activeRailKey === item.key ? null : item.key;
|
|
10652
|
-
if (next !== null && item.display === "panel") {
|
|
10653
|
-
setOpen(false);
|
|
10654
|
-
}
|
|
10655
|
-
setActiveRailKey(next);
|
|
10656
|
-
};
|
|
10657
|
-
const toggleArtifact = () => {
|
|
10658
|
-
if (!open && activePanelItem) {
|
|
10659
|
-
setActiveRailKey(null);
|
|
10660
|
-
}
|
|
10661
|
-
setOpen(!open);
|
|
10662
|
-
};
|
|
10663
|
-
useEffect39(() => {
|
|
10664
|
-
if (!activePopoverItem) return;
|
|
10665
|
-
const onKeyDown = (event) => {
|
|
10666
|
-
if (event.key === "Escape") setActiveRailKey(null);
|
|
10667
|
-
};
|
|
10668
|
-
const onPointerDown = (event) => {
|
|
10669
|
-
const target = event.target;
|
|
10670
|
-
if (target.closest("[data-slot=chat-page-rail-popover]") || target.closest("[data-slot=chat-page-conv-rail]")) {
|
|
10671
|
-
return;
|
|
10672
|
-
}
|
|
10673
|
-
setActiveRailKey(null);
|
|
10674
|
-
};
|
|
10675
|
-
document.addEventListener("keydown", onKeyDown);
|
|
10676
|
-
document.addEventListener("mousedown", onPointerDown);
|
|
10677
|
-
return () => {
|
|
10678
|
-
document.removeEventListener("keydown", onKeyDown);
|
|
10679
|
-
document.removeEventListener("mousedown", onPointerDown);
|
|
10680
|
-
};
|
|
10681
|
-
});
|
|
10682
|
-
const { renderChildren } = useRenderer21();
|
|
10683
|
-
const renderSlot = (slot) => isValidElement3(slot) || typeof slot !== "object" || slot === null ? slot : renderChildren([slot]);
|
|
10684
|
-
const convCollControlled = conversationSectionCollapsed !== void 0;
|
|
10685
|
-
const [convCollapsedInner, setConvCollapsedInner] = useState46(
|
|
10686
|
-
defaultConversationSectionCollapsed
|
|
10687
|
-
);
|
|
10688
|
-
const convCollapsed = convCollControlled ? conversationSectionCollapsed === true : convCollapsedInner;
|
|
10689
|
-
const toggleConvSection = () => {
|
|
10690
|
-
const next = !convCollapsed;
|
|
10691
|
-
if (!convCollControlled) setConvCollapsedInner(next);
|
|
10692
|
-
onConversationSectionToggle?.(next);
|
|
10693
|
-
};
|
|
10694
|
-
const footerCollControlled = footerSectionCollapsed !== void 0;
|
|
10695
|
-
const [footerCollapsedInner, setFooterCollapsedInner] = useState46(
|
|
10696
|
-
defaultFooterSectionCollapsed
|
|
10697
|
-
);
|
|
10698
|
-
const footerCollapsed = footerCollControlled ? footerSectionCollapsed === true : footerCollapsedInner;
|
|
10699
|
-
const toggleFooterSection = () => {
|
|
10700
|
-
const next = !footerCollapsed;
|
|
10701
|
-
if (!footerCollControlled) setFooterCollapsedInner(next);
|
|
10702
|
-
onFooterSectionToggle?.(next);
|
|
10703
|
-
};
|
|
10704
|
-
const railVisible = railItems.length > 0 || railFooterItems.length > 0;
|
|
10705
|
-
const railButton = (item) => /* @__PURE__ */ jsx133(Tooltip2, { content: item.label, side: "right", children: /* @__PURE__ */ jsx133(
|
|
10706
|
-
Button2,
|
|
10707
|
-
{
|
|
10708
|
-
icon: item.icon,
|
|
10709
|
-
variant: "text",
|
|
10710
|
-
onClick: () => onMenuSelect?.(item.key)
|
|
10711
|
-
}
|
|
10712
|
-
) }, item.key);
|
|
10713
|
-
const convRailButton = (item, active, onClick) => {
|
|
10714
|
-
const button = /* @__PURE__ */ jsx133(
|
|
10715
|
-
Button2,
|
|
10716
|
-
{
|
|
10717
|
-
icon: item.icon,
|
|
10718
|
-
variant: "text",
|
|
10719
|
-
className: cn(active ? "bg-accent text-accent-foreground" : void 0, "px-2"),
|
|
10720
|
-
onClick
|
|
10721
|
-
}
|
|
10722
|
-
);
|
|
10723
|
-
return item.label !== void 0 ? /* @__PURE__ */ jsx133(Tooltip2, { content: item.label, side: "left", children: button }, item.key) : /* @__PURE__ */ jsx133("span", { children: button }, item.key);
|
|
10724
|
-
};
|
|
10725
|
-
const convRailVisible = !hideArtifactRailItem || visibleRailItems.length > 0;
|
|
10726
|
-
const convRail = convRailVisible ? /* @__PURE__ */ jsxs92(
|
|
10727
|
-
"div",
|
|
10728
|
-
{
|
|
10729
|
-
"data-slot": "chat-page-conv-rail",
|
|
10730
|
-
className: "relative flex w-(--pactor-chat-rail-width) shrink-0 flex-col items-center gap-1 px-1 py-2",
|
|
10731
|
-
children: [
|
|
10732
|
-
!hideArtifactRailItem ? convRailButton(
|
|
10733
|
-
{
|
|
10734
|
-
key: "artifact",
|
|
10735
|
-
icon: open ? "panel-right-close" : "package",
|
|
10736
|
-
label: open ? "\u6536\u8D77\u4EA7\u7269\u533A" : artifactTitle
|
|
10737
|
-
},
|
|
10738
|
-
open,
|
|
10739
|
-
toggleArtifact
|
|
10740
|
-
) : null,
|
|
10741
|
-
visibleRailItems.map(
|
|
10742
|
-
(item) => convRailButton(item, activeRailKey === item.key, () => toggleRailItem(item))
|
|
10743
|
-
),
|
|
10744
|
-
activePopoverItem ? /* @__PURE__ */ jsx133(
|
|
10745
|
-
"div",
|
|
10746
|
-
{
|
|
10747
|
-
"data-slot": "chat-page-rail-popover",
|
|
10748
|
-
className: "absolute right-full top-0 z-10 mr-2 overflow-auto rounded-lg border border-border bg-popover shadow-md",
|
|
10749
|
-
style: {
|
|
10750
|
-
width: "var(--pactor-chat-rail-popover-width)",
|
|
10751
|
-
maxWidth: "calc(100cqw - 2rem)",
|
|
10752
|
-
maxHeight: "calc(100% - 1rem)"
|
|
10753
|
-
},
|
|
10754
|
-
children: renderSlot(activePopoverItem.content)
|
|
10755
|
-
}
|
|
10756
|
-
) : null
|
|
10757
|
-
]
|
|
10758
|
-
}
|
|
10759
|
-
) : null;
|
|
10760
|
-
const chatArea = /* @__PURE__ */ jsxs92("div", { "data-slot": "chat-page-conversation", className: "flex h-full min-w-0 flex-1 flex-col", children: [
|
|
10761
|
-
/* @__PURE__ */ jsxs92(
|
|
10762
|
-
"div",
|
|
10763
|
-
{
|
|
10764
|
-
"data-slot": "chat-page-conversation-header",
|
|
10765
|
-
className: "flex shrink-0 items-center justify-between border-b border-border px-4 py-2.5",
|
|
10766
|
-
children: [
|
|
10767
|
-
/* @__PURE__ */ jsx133(Text, { text: conversationTitle, strong: true }),
|
|
10768
|
-
conversationHeaderAction ? /* @__PURE__ */ jsx133(Tooltip2, { content: conversationHeaderAction.tooltip ?? conversationHeaderAction.label, side: "bottom", children: /* @__PURE__ */ jsx133(
|
|
10769
|
-
Button2,
|
|
10770
|
-
{
|
|
10771
|
-
text: conversationHeaderAction.label,
|
|
10772
|
-
icon: conversationHeaderAction.icon,
|
|
10773
|
-
variant: "text",
|
|
10774
|
-
onClick: () => onConversationHeaderAction?.()
|
|
10775
|
-
}
|
|
10776
|
-
) }) : null
|
|
10777
|
-
]
|
|
10778
|
-
}
|
|
10779
|
-
),
|
|
10780
|
-
/* @__PURE__ */ jsxs92("div", { className: "flex min-h-0 flex-1", children: [
|
|
10781
|
-
/* @__PURE__ */ jsxs92(
|
|
10782
|
-
"div",
|
|
10783
|
-
{
|
|
10784
|
-
"data-slot": "chat-page-conversation-body",
|
|
10785
|
-
className: "mx-auto flex min-h-0 w-[61.8cqw] max-w-full flex-col",
|
|
10786
|
-
children: [
|
|
10787
|
-
messages.length === 0 ? /* @__PURE__ */ jsx133(
|
|
10788
|
-
Welcome,
|
|
10789
|
-
{
|
|
10790
|
-
title: welcome?.title,
|
|
10791
|
-
description: welcome?.description,
|
|
10792
|
-
prompts: welcome?.prompts,
|
|
10793
|
-
style: { flex: 1 },
|
|
10794
|
-
onSelect: (value) => onSend?.(value)
|
|
10795
|
-
}
|
|
10796
|
-
) : /* @__PURE__ */ jsx133(
|
|
10797
|
-
MessageList,
|
|
10798
|
-
{
|
|
10799
|
-
messages,
|
|
10800
|
-
className: "scrollbar-subtle",
|
|
10801
|
-
style: { flex: 1, minHeight: 0, padding: 16 },
|
|
10802
|
-
onAction: onMessageAction,
|
|
10803
|
-
onOpenArtifacts: () => setOpen(true)
|
|
10804
|
-
}
|
|
10805
|
-
),
|
|
10806
|
-
/* @__PURE__ */ jsx133(
|
|
10807
|
-
Composer,
|
|
10808
|
-
{
|
|
10809
|
-
placeholder: composerPlaceholder,
|
|
10810
|
-
loading: sending,
|
|
10811
|
-
models,
|
|
10812
|
-
model,
|
|
10813
|
-
contexts,
|
|
10814
|
-
contextItems,
|
|
10815
|
-
attachments,
|
|
10816
|
-
footer: composerFooter,
|
|
10817
|
-
style: { padding: 16, paddingBottom: composerBottom ? 8 : 16, flexShrink: 0 },
|
|
10818
|
-
onModelChange,
|
|
10819
|
-
onContextItemsChange,
|
|
10820
|
-
onAttachFiles,
|
|
10821
|
-
onRemoveAttachment,
|
|
10822
|
-
onRetryAttachment,
|
|
10823
|
-
onSubmit: (text) => onSend?.(text)
|
|
10824
|
-
}
|
|
10825
|
-
),
|
|
10826
|
-
composerBottom ? /* @__PURE__ */ jsx133("div", { "data-slot": "chat-page-composer-bottom", className: "shrink-0 px-4 pb-2 text-center", children: renderSlot(composerBottom) }) : null
|
|
10827
|
-
]
|
|
10828
|
-
}
|
|
10829
|
-
),
|
|
10830
|
-
convRail
|
|
10831
|
-
] })
|
|
10832
|
-
] });
|
|
10833
|
-
const activeArtifact = artifacts.find((item) => item.id === activeArtifactId) ?? (activeArtifactId === void 0 || activeArtifactId === "" ? artifacts[artifacts.length - 1] : void 0);
|
|
10834
|
-
const artifactPanel = /* @__PURE__ */ jsx133(
|
|
10835
|
-
"div",
|
|
10836
|
-
{
|
|
10837
|
-
"data-slot": "chat-page-artifact",
|
|
10838
|
-
className: "flex h-full min-w-0 flex-col border-l border-border bg-muted",
|
|
10839
|
-
children: /* @__PURE__ */ jsx133(
|
|
10840
|
-
ArtifactPanel,
|
|
10841
|
-
{
|
|
10842
|
-
artifact: activeArtifact,
|
|
10843
|
-
artifacts,
|
|
10844
|
-
activeArtifactId,
|
|
10845
|
-
title: artifactTitle,
|
|
10846
|
-
emptyText: artifactEmptyText,
|
|
10847
|
-
safeRegistry,
|
|
10848
|
-
user,
|
|
10849
|
-
artifactViewers,
|
|
10850
|
-
onSelectArtifact: (id) => onSelectArtifact?.(id),
|
|
10851
|
-
onDownload: onDownloadArtifact,
|
|
10852
|
-
onClose: () => setOpen(false)
|
|
10853
|
-
}
|
|
10854
|
-
)
|
|
10855
|
-
}
|
|
10856
|
-
);
|
|
10857
|
-
return /* @__PURE__ */ jsxs92(
|
|
10858
|
-
"div",
|
|
10859
|
-
{
|
|
10860
|
-
"data-slot": "chat-page",
|
|
10861
|
-
className: cn("flex w-full overflow-hidden", className),
|
|
10862
|
-
style: { height: "100vh", ...style },
|
|
10863
|
-
children: [
|
|
10864
|
-
railVisible ? /* @__PURE__ */ jsxs92(
|
|
10865
|
-
"div",
|
|
10866
|
-
{
|
|
10867
|
-
"data-slot": "chat-page-rail",
|
|
10868
|
-
className: "flex h-full w-[52px] shrink-0 flex-col items-center gap-1 border-r border-border py-2.5",
|
|
10869
|
-
children: [
|
|
10870
|
-
railItems.map(railButton),
|
|
10871
|
-
/* @__PURE__ */ jsx133("div", { className: "flex-1" }),
|
|
10872
|
-
railFooterItems.map(railButton)
|
|
10873
|
-
]
|
|
10874
|
-
}
|
|
10875
|
-
) : null,
|
|
10876
|
-
/* @__PURE__ */ jsxs92(
|
|
10877
|
-
"div",
|
|
10878
|
-
{
|
|
10879
|
-
"data-slot": "chat-page-menu",
|
|
10880
|
-
className: "flex h-full w-[250px] shrink-0 flex-col gap-2 overflow-hidden border-r border-border px-2 py-3",
|
|
10881
|
-
children: [
|
|
10882
|
-
brand ? /* @__PURE__ */ jsxs92("div", { className: "flex shrink-0 items-center justify-between px-2", children: [
|
|
10883
|
-
/* @__PURE__ */ jsxs92("div", { className: "flex flex-col gap-0.5", children: [
|
|
10884
|
-
/* @__PURE__ */ jsx133(Text, { text: brand.title, strong: true, size: "large" }),
|
|
10885
|
-
brand.version !== void 0 ? /* @__PURE__ */ jsx133(Text, { text: brand.version, type: "secondary", size: "small" }) : null
|
|
10886
|
-
] }),
|
|
10887
|
-
menuAction ? /* @__PURE__ */ jsx133(
|
|
10888
|
-
Button2,
|
|
10889
|
-
{
|
|
10890
|
-
text: menuAction.label,
|
|
10891
|
-
icon: menuAction.icon,
|
|
10892
|
-
size: "small",
|
|
10893
|
-
onClick: () => onMenuAction?.()
|
|
10894
|
-
}
|
|
10895
|
-
) : null
|
|
10896
|
-
] }) : null,
|
|
10897
|
-
/* @__PURE__ */ jsx133("div", { className: "scrollbar-subtle max-h-[40%] min-h-0 shrink-0 overflow-y-auto", children: /* @__PURE__ */ jsx133(
|
|
10898
|
-
Menu,
|
|
10899
|
-
{
|
|
10900
|
-
items: menuItems,
|
|
10901
|
-
selectedKey: activeMenuKey,
|
|
10902
|
-
onSelect: (key) => onMenuSelect?.(key)
|
|
10903
|
-
}
|
|
10904
|
-
) }),
|
|
10905
|
-
conversationSectionTitle !== void 0 ? /* @__PURE__ */ jsxs92(
|
|
10906
|
-
"button",
|
|
10907
|
-
{
|
|
10908
|
-
type: "button",
|
|
10909
|
-
"data-slot": "chat-page-section-toggle",
|
|
10910
|
-
"aria-expanded": !convCollapsed,
|
|
10911
|
-
className: "flex w-full shrink-0 cursor-pointer items-center justify-between px-2 pt-2",
|
|
10912
|
-
onClick: toggleConvSection,
|
|
10913
|
-
children: [
|
|
10914
|
-
/* @__PURE__ */ jsx133(
|
|
10915
|
-
Text,
|
|
10916
|
-
{
|
|
10917
|
-
text: `${conversationSectionTitle} (${conversations.length})`,
|
|
10918
|
-
type: "secondary",
|
|
10919
|
-
className: "text-sm",
|
|
10920
|
-
strong: true
|
|
10921
|
-
}
|
|
10922
|
-
),
|
|
10923
|
-
/* @__PURE__ */ jsx133(Icon, { name: convCollapsed ? "chevron-right" : "chevron-down", size: 14 })
|
|
10924
|
-
]
|
|
10925
|
-
}
|
|
10926
|
-
) : null,
|
|
10927
|
-
!convCollapsed ? /* @__PURE__ */ jsxs92("div", { "data-slot": "chat-page-section-body", className: "scrollbar-subtle flex min-h-0 flex-1 flex-col overflow-y-auto", children: [
|
|
10928
|
-
/* @__PURE__ */ jsx133(
|
|
10929
|
-
ConversationList,
|
|
10930
|
-
{
|
|
10931
|
-
items: conversations,
|
|
10932
|
-
activeId: activeConversationId,
|
|
10933
|
-
onSelect: (id) => onSelectConversation?.(id),
|
|
10934
|
-
onDelete: (id) => onDeleteConversation?.(id)
|
|
10935
|
-
}
|
|
10936
|
-
),
|
|
10937
|
-
moreLabel !== void 0 ? /* @__PURE__ */ jsx133("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx133(Button2, { text: `${moreLabel} >>`, variant: "link", size: "small", onClick: () => onMore?.() }) }) : null
|
|
10938
|
-
] }) : null,
|
|
10939
|
-
footerSectionTitle !== void 0 ? /* @__PURE__ */ jsxs92(
|
|
10940
|
-
"button",
|
|
10941
|
-
{
|
|
10942
|
-
type: "button",
|
|
10943
|
-
"data-slot": "chat-page-section-toggle",
|
|
10944
|
-
"aria-expanded": !footerCollapsed,
|
|
10945
|
-
className: "flex w-full shrink-0 cursor-pointer items-center justify-between px-2 pt-2",
|
|
10946
|
-
onClick: toggleFooterSection,
|
|
10947
|
-
children: [
|
|
10948
|
-
/* @__PURE__ */ jsx133(Text, { text: footerSectionTitle, type: "secondary", className: "text-sm", strong: true }),
|
|
10949
|
-
/* @__PURE__ */ jsx133(Icon, { name: footerCollapsed ? "chevron-right" : "chevron-down", size: 14 })
|
|
10950
|
-
]
|
|
10951
|
-
}
|
|
10952
|
-
) : null,
|
|
10953
|
-
!footerCollapsed && footerItems.length > 0 ? /* @__PURE__ */ jsx133("div", { "data-slot": "chat-page-section-body", className: "scrollbar-subtle min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx133(
|
|
10954
|
-
Menu,
|
|
10955
|
-
{
|
|
10956
|
-
items: footerItems,
|
|
10957
|
-
onSelect: (key) => onMenuSelect?.(key)
|
|
10958
|
-
}
|
|
10959
|
-
) }) : null
|
|
10960
|
-
]
|
|
10961
|
-
}
|
|
10962
|
-
),
|
|
10963
|
-
/* @__PURE__ */ jsx133("div", { className: "@container h-full min-w-0 flex-1", children: content !== void 0 ? renderSlot(content) : open || activePanelItem ? /* @__PURE__ */ jsxs92(PanelGroup, { orientation: "horizontal", style: { width: "100%", height: "100%" }, children: [
|
|
10964
|
-
/* @__PURE__ */ jsx133(Panel, { defaultSize: "62%", children: chatArea }),
|
|
10965
|
-
/* @__PURE__ */ jsx133(ResizableHandle, { withHandle: true }),
|
|
10966
|
-
/* @__PURE__ */ jsx133(Panel, { defaultSize: "38%", minSize: "380px", maxSize: "760px", children: activePanelItem ? /* @__PURE__ */ jsx133(
|
|
10967
|
-
"div",
|
|
10968
|
-
{
|
|
10969
|
-
"data-slot": "chat-page-rail-panel",
|
|
10970
|
-
className: "flex h-full min-w-0 flex-col border-l border-border bg-muted",
|
|
10971
|
-
children: renderSlot(activePanelItem.content)
|
|
10972
|
-
}
|
|
10973
|
-
) : artifactPanel })
|
|
10974
|
-
] }) : chatArea })
|
|
10975
|
-
]
|
|
10976
|
-
}
|
|
10977
|
-
);
|
|
10978
|
-
}
|
|
10979
|
-
|
|
10980
|
-
// src/components/chat/Citation/index.tsx
|
|
10981
|
-
import { jsx as jsx134, jsxs as jsxs93 } from "react/jsx-runtime";
|
|
10982
|
-
function Citation({ items = [], start = 1, className, style }) {
|
|
10983
|
-
return /* @__PURE__ */ jsx134("span", { "data-slot": "citation", className: cn("inline-flex gap-1 align-super", className), style, children: items.map((item, index) => /* @__PURE__ */ jsxs93(HoverCard, { children: [
|
|
10984
|
-
/* @__PURE__ */ jsxs93(
|
|
10985
|
-
HoverCardTrigger,
|
|
10986
|
-
{
|
|
10987
|
-
"data-slot": "citation-marker",
|
|
10988
|
-
className: "cursor-pointer rounded-sm border border-border px-1 text-xs leading-4 text-primary hover:bg-accent",
|
|
10989
|
-
children: [
|
|
10990
|
-
"[",
|
|
10991
|
-
start + index,
|
|
10992
|
-
"]"
|
|
10993
|
-
]
|
|
10994
|
-
}
|
|
10995
|
-
),
|
|
10996
|
-
/* @__PURE__ */ jsxs93(HoverCardContent, { "data-slot": "citation-card", className: "w-72", children: [
|
|
10997
|
-
/* @__PURE__ */ jsx134("div", { className: "text-sm font-medium", children: item.title }),
|
|
10998
|
-
item.snippet ? /* @__PURE__ */ jsx134("div", { className: "mt-1 line-clamp-3 text-xs text-muted-foreground", children: item.snippet }) : null,
|
|
10999
|
-
item.url ? /* @__PURE__ */ jsx134(
|
|
11000
|
-
"a",
|
|
11001
|
-
{
|
|
11002
|
-
href: item.url,
|
|
11003
|
-
target: "_blank",
|
|
11004
|
-
rel: "noreferrer",
|
|
11005
|
-
className: "mt-1 block truncate text-xs text-primary hover:underline",
|
|
11006
|
-
children: item.url
|
|
11007
|
-
}
|
|
11008
|
-
) : null
|
|
11009
|
-
] })
|
|
11010
|
-
] }, `${item.title}-${index}`)) });
|
|
11011
|
-
}
|
|
11012
|
-
|
|
11013
|
-
// src/components/chat/StepsPanel/index.tsx
|
|
11014
|
-
import { jsx as jsx135, jsxs as jsxs94 } from "react/jsx-runtime";
|
|
11015
|
-
function StepsPanel({
|
|
11016
|
-
title = "\u6267\u884C\u6B65\u9AA4",
|
|
11017
|
-
steps = [],
|
|
11018
|
-
emptyText = "\u5F53\u524D\u4F1A\u8BDD\u6682\u65E0\u6267\u884C\u6B65\u9AA4",
|
|
11019
|
-
className,
|
|
11020
|
-
style
|
|
11021
|
-
}) {
|
|
11022
|
-
return /* @__PURE__ */ jsxs94(
|
|
11023
|
-
"div",
|
|
11024
|
-
{
|
|
11025
|
-
"data-slot": "steps-panel",
|
|
11026
|
-
className: cn("px-3.5 py-3 text-foreground", className),
|
|
11027
|
-
style,
|
|
11028
|
-
children: [
|
|
11029
|
-
/* @__PURE__ */ jsx135("div", { className: "mb-1 text-[13px] font-semibold", children: title }),
|
|
11030
|
-
steps.length === 0 ? /* @__PURE__ */ jsx135("div", { className: "py-4 text-center text-[13px] text-muted-foreground", children: emptyText }) : /* @__PURE__ */ jsx135("ol", { children: steps.map((step, index) => {
|
|
11031
|
-
const status = step.status ?? "pending";
|
|
11032
|
-
return /* @__PURE__ */ jsxs94(
|
|
11033
|
-
"li",
|
|
11034
|
-
{
|
|
11035
|
-
"data-status": status,
|
|
11036
|
-
className: cn(
|
|
11037
|
-
"relative flex gap-2 py-1.5",
|
|
11038
|
-
// 步骤之间的连接线(对齐 16px 图标中心)
|
|
11039
|
-
'not-last:before:absolute not-last:before:left-[7.5px] not-last:before:top-7 not-last:before:-bottom-1 not-last:before:w-px not-last:before:bg-border not-last:before:content-[""]'
|
|
11040
|
-
),
|
|
11041
|
-
children: [
|
|
11042
|
-
/* @__PURE__ */ jsx135(
|
|
11043
|
-
"span",
|
|
11044
|
-
{
|
|
11045
|
-
className: cn(
|
|
11046
|
-
"flex h-5 w-4 shrink-0 items-center justify-center",
|
|
11047
|
-
status !== "pending" && "text-primary"
|
|
11048
|
-
),
|
|
11049
|
-
children: status === "done" ? /* @__PURE__ */ jsx135(Icon, { name: "check-circle", size: 16 }) : status === "running" ? /* @__PURE__ */ jsx135(
|
|
11050
|
-
Icon,
|
|
11051
|
-
{
|
|
11052
|
-
name: "loading",
|
|
11053
|
-
size: 16,
|
|
11054
|
-
className: "animate-spin motion-reduce:animate-none"
|
|
11055
|
-
}
|
|
11056
|
-
) : /* @__PURE__ */ jsx135("span", { className: "size-1.5 rounded-full bg-muted-foreground/50" })
|
|
11057
|
-
}
|
|
11058
|
-
),
|
|
11059
|
-
/* @__PURE__ */ jsxs94("div", { className: "min-w-0 flex-1", children: [
|
|
11060
|
-
/* @__PURE__ */ jsx135(
|
|
11061
|
-
"div",
|
|
11062
|
-
{
|
|
11063
|
-
className: cn(
|
|
11064
|
-
"text-[13px] leading-5",
|
|
11065
|
-
status === "pending" && "text-muted-foreground"
|
|
11066
|
-
),
|
|
11067
|
-
children: step.title
|
|
11068
|
-
}
|
|
11069
|
-
),
|
|
11070
|
-
step.description ? /* @__PURE__ */ jsx135("div", { className: "mt-0.5 text-xs leading-[18px] text-muted-foreground", children: step.description }) : null
|
|
11071
|
-
] }),
|
|
11072
|
-
step.duration ? /* @__PURE__ */ jsx135("span", { className: "shrink-0 text-xs leading-5 text-muted-foreground", children: step.duration }) : null
|
|
11073
|
-
]
|
|
11074
|
-
},
|
|
11075
|
-
`${step.title}-${index}`
|
|
11076
|
-
);
|
|
11077
|
-
}) })
|
|
11078
|
-
]
|
|
11079
|
-
}
|
|
11080
|
-
);
|
|
11081
|
-
}
|
|
11082
|
-
|
|
11083
|
-
// src/components/chat/Suggestion/index.tsx
|
|
11084
|
-
import { jsx as jsx136, jsxs as jsxs95 } from "react/jsx-runtime";
|
|
11085
|
-
function normalize(item) {
|
|
11086
|
-
if (typeof item === "string") return { label: item, value: item };
|
|
11087
|
-
return { label: item.label, value: item.value ?? item.label, icon: item.icon };
|
|
11088
|
-
}
|
|
11089
|
-
function Suggestion({ items = [], justify = "start", onSelect, className, style }) {
|
|
11090
|
-
return /* @__PURE__ */ jsx136(
|
|
11091
|
-
"div",
|
|
11092
|
-
{
|
|
11093
|
-
"data-slot": "suggestion",
|
|
11094
|
-
className: cn("flex flex-wrap gap-2", justify === "center" && "justify-center", className),
|
|
11095
|
-
style,
|
|
11096
|
-
children: items.map((item, index) => {
|
|
11097
|
-
const { label, value, icon } = normalize(item);
|
|
11098
|
-
return /* @__PURE__ */ jsxs95(
|
|
11099
|
-
"button",
|
|
11100
|
-
{
|
|
11101
|
-
type: "button",
|
|
11102
|
-
"data-slot": "suggestion-item",
|
|
11103
|
-
"data-value": value,
|
|
11104
|
-
className: "flex items-center gap-1.5 rounded-full border border-border px-3 py-1 text-sm transition-colors hover:bg-accent",
|
|
11105
|
-
onClick: () => onSelect?.(value),
|
|
11106
|
-
children: [
|
|
11107
|
-
icon ? /* @__PURE__ */ jsx136(Icon, { name: icon, size: "sm" }) : null,
|
|
11108
|
-
label
|
|
11109
|
-
]
|
|
11110
|
-
},
|
|
11111
|
-
`${value}-${index}`
|
|
11112
|
-
);
|
|
11113
|
-
})
|
|
11114
|
-
}
|
|
11115
|
-
);
|
|
11116
|
-
}
|
|
11117
|
-
|
|
11118
8740
|
// src/components/register.ts
|
|
11119
8741
|
var builtinComponents = {
|
|
11120
8742
|
Page,
|
|
@@ -11245,26 +8867,7 @@ var builtinComponents = {
|
|
|
11245
8867
|
Markdown: MarkdownDslComponent,
|
|
11246
8868
|
CodeBlock,
|
|
11247
8869
|
DiffViewer,
|
|
11248
|
-
JSONViewer
|
|
11249
|
-
// AI 与会话类扩展组件(第八批:chat 子目录)
|
|
11250
|
-
Bubble: Bubble2,
|
|
11251
|
-
Sender,
|
|
11252
|
-
Thinking,
|
|
11253
|
-
AgentStatus,
|
|
11254
|
-
StreamingText,
|
|
11255
|
-
Suggestion,
|
|
11256
|
-
Prompt,
|
|
11257
|
-
Welcome,
|
|
11258
|
-
Citation,
|
|
11259
|
-
Attachment,
|
|
11260
|
-
ToolCall,
|
|
11261
|
-
ChatMessage,
|
|
11262
|
-
ChatPage,
|
|
11263
|
-
ArtifactPanel,
|
|
11264
|
-
MessageList,
|
|
11265
|
-
Composer,
|
|
11266
|
-
ConversationList,
|
|
11267
|
-
StepsPanel
|
|
8870
|
+
JSONViewer
|
|
11268
8871
|
};
|
|
11269
8872
|
function registerBuiltinComponents(registry) {
|
|
11270
8873
|
for (const [type, component] of Object.entries(builtinComponents)) {
|
|
@@ -11272,7 +8875,7 @@ function registerBuiltinComponents(registry) {
|
|
|
11272
8875
|
}
|
|
11273
8876
|
}
|
|
11274
8877
|
function createComponentRegistry() {
|
|
11275
|
-
const registry = new
|
|
8878
|
+
const registry = new Registry("ComponentRegistry");
|
|
11276
8879
|
registerBuiltinComponents(registry);
|
|
11277
8880
|
return registry;
|
|
11278
8881
|
}
|
|
@@ -11310,6 +8913,7 @@ export {
|
|
|
11310
8913
|
ColorPicker,
|
|
11311
8914
|
Combobox2 as Combobox,
|
|
11312
8915
|
Command2 as Command,
|
|
8916
|
+
useOptionalRenderer,
|
|
11313
8917
|
ChatInput,
|
|
11314
8918
|
Container,
|
|
11315
8919
|
Content,
|
|
@@ -11402,25 +9006,6 @@ export {
|
|
|
11402
9006
|
Upload,
|
|
11403
9007
|
Video,
|
|
11404
9008
|
Watermark,
|
|
11405
|
-
AgentStatus,
|
|
11406
|
-
buildArtifactTree,
|
|
11407
|
-
ArtifactPanel,
|
|
11408
|
-
Attachment,
|
|
11409
|
-
Bubble2 as Bubble,
|
|
11410
|
-
Sender,
|
|
11411
|
-
StreamingText,
|
|
11412
|
-
Thinking,
|
|
11413
|
-
ToolCall,
|
|
11414
|
-
ChatMessage,
|
|
11415
|
-
Composer,
|
|
11416
|
-
ConversationList,
|
|
11417
|
-
MessageList,
|
|
11418
|
-
Prompt,
|
|
11419
|
-
Welcome,
|
|
11420
|
-
ChatPage,
|
|
11421
|
-
Citation,
|
|
11422
|
-
StepsPanel,
|
|
11423
|
-
Suggestion,
|
|
11424
9009
|
builtinComponents,
|
|
11425
9010
|
registerBuiltinComponents,
|
|
11426
9011
|
createComponentRegistry
|