@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
|
@@ -32,19 +32,15 @@ var components_exports = {};
|
|
|
32
32
|
__export(components_exports, {
|
|
33
33
|
Accordion: () => Accordion2,
|
|
34
34
|
Affix: () => Affix,
|
|
35
|
-
AgentStatus: () => AgentStatus,
|
|
36
35
|
Alert: () => Alert2,
|
|
37
36
|
AlertDialog: () => AlertDialog2,
|
|
38
37
|
Anchor: () => Anchor,
|
|
39
|
-
ArtifactPanel: () => ArtifactPanel,
|
|
40
38
|
AspectRatio: () => AspectRatio2,
|
|
41
|
-
Attachment: () => Attachment,
|
|
42
39
|
Audio: () => Audio,
|
|
43
40
|
Avatar: () => Avatar2,
|
|
44
41
|
BackTop: () => BackTop,
|
|
45
42
|
Badge: () => Badge2,
|
|
46
43
|
Breadcrumb: () => Breadcrumb2,
|
|
47
|
-
Bubble: () => Bubble2,
|
|
48
44
|
Button: () => Button2,
|
|
49
45
|
ButtonGroup: () => ButtonGroup2,
|
|
50
46
|
CONTROL_SIZE_AREA: () => CONTROL_SIZE_AREA,
|
|
@@ -57,12 +53,9 @@ __export(components_exports, {
|
|
|
57
53
|
Carousel: () => Carousel2,
|
|
58
54
|
Cascader: () => Cascader,
|
|
59
55
|
ChatInput: () => ChatInput,
|
|
60
|
-
ChatMessage: () => ChatMessage,
|
|
61
|
-
ChatPage: () => ChatPage,
|
|
62
56
|
Checkbox: () => Checkbox2,
|
|
63
57
|
ChipFilter: () => ChipFilter,
|
|
64
58
|
ChipNode: () => ChipNode,
|
|
65
|
-
Citation: () => Citation,
|
|
66
59
|
ClearHoverButton: () => ClearHoverButton,
|
|
67
60
|
CodeBlock: () => CodeBlock,
|
|
68
61
|
Col: () => Col,
|
|
@@ -70,11 +63,9 @@ __export(components_exports, {
|
|
|
70
63
|
ColorPicker: () => ColorPicker,
|
|
71
64
|
Combobox: () => Combobox2,
|
|
72
65
|
Command: () => Command2,
|
|
73
|
-
Composer: () => Composer,
|
|
74
66
|
Container: () => Container,
|
|
75
67
|
Content: () => Content,
|
|
76
68
|
ContextMenu: () => ContextMenu2,
|
|
77
|
-
ConversationList: () => ConversationList,
|
|
78
69
|
DataTable: () => DataTable,
|
|
79
70
|
DatePicker: () => DatePicker,
|
|
80
71
|
Descriptions: () => Descriptions,
|
|
@@ -115,7 +106,6 @@ __export(components_exports, {
|
|
|
115
106
|
Menu: () => Menu2,
|
|
116
107
|
Menubar: () => Menubar2,
|
|
117
108
|
Message: () => Message,
|
|
118
|
-
MessageList: () => MessageList,
|
|
119
109
|
NavigationMenu: () => NavigationMenu2,
|
|
120
110
|
Notification: () => Notification,
|
|
121
111
|
NumberInput: () => NumberInput,
|
|
@@ -124,7 +114,6 @@ __export(components_exports, {
|
|
|
124
114
|
Popconfirm: () => Popconfirm,
|
|
125
115
|
Popover: () => Popover2,
|
|
126
116
|
Progress: () => Progress2,
|
|
127
|
-
Prompt: () => Prompt,
|
|
128
117
|
QRCode: () => QRCode,
|
|
129
118
|
RadioGroup: () => RadioGroup2,
|
|
130
119
|
RailTooltip: () => RailTooltip,
|
|
@@ -136,7 +125,6 @@ __export(components_exports, {
|
|
|
136
125
|
ScrollArea: () => ScrollArea2,
|
|
137
126
|
Segmented: () => Segmented,
|
|
138
127
|
Select: () => Select2,
|
|
139
|
-
Sender: () => Sender,
|
|
140
128
|
Separator: () => Separator2,
|
|
141
129
|
Sheet: () => Sheet2,
|
|
142
130
|
Sidebar: () => Sidebar,
|
|
@@ -149,21 +137,16 @@ __export(components_exports, {
|
|
|
149
137
|
Statistic: () => Statistic,
|
|
150
138
|
Status: () => Status,
|
|
151
139
|
Steps: () => Steps,
|
|
152
|
-
StepsPanel: () => StepsPanel,
|
|
153
|
-
StreamingText: () => StreamingText,
|
|
154
|
-
Suggestion: () => Suggestion,
|
|
155
140
|
Switch: () => Switch2,
|
|
156
141
|
Table: () => Table3,
|
|
157
142
|
Tabs: () => Tabs2,
|
|
158
143
|
Tag: () => Tag2,
|
|
159
144
|
Text: () => Text,
|
|
160
145
|
Textarea: () => Textarea2,
|
|
161
|
-
Thinking: () => Thinking,
|
|
162
146
|
TimePicker: () => TimePicker,
|
|
163
147
|
Timeline: () => Timeline,
|
|
164
148
|
Toggle: () => Toggle2,
|
|
165
149
|
ToggleGroup: () => ToggleGroup2,
|
|
166
|
-
ToolCall: () => ToolCall,
|
|
167
150
|
Tooltip: () => Tooltip2,
|
|
168
151
|
Tour: () => Tour,
|
|
169
152
|
Transfer: () => Transfer,
|
|
@@ -173,8 +156,6 @@ __export(components_exports, {
|
|
|
173
156
|
Upload: () => Upload2,
|
|
174
157
|
Video: () => Video2,
|
|
175
158
|
Watermark: () => Watermark,
|
|
176
|
-
Welcome: () => Welcome,
|
|
177
|
-
buildArtifactTree: () => buildArtifactTree,
|
|
178
159
|
builtinComponents: () => builtinComponents,
|
|
179
160
|
createComponentRegistry: () => createComponentRegistry,
|
|
180
161
|
diffLines: () => diffLines,
|
|
@@ -182,12 +163,13 @@ __export(components_exports, {
|
|
|
182
163
|
normalizeIconName: () => normalizeIconName,
|
|
183
164
|
registerBuiltinComponents: () => registerBuiltinComponents,
|
|
184
165
|
useFormContext: () => useFormContext,
|
|
166
|
+
useOptionalRenderer: () => useOptionalRenderer,
|
|
185
167
|
useSidebarDrawer: () => useSidebarDrawer
|
|
186
168
|
});
|
|
187
169
|
module.exports = __toCommonJS(components_exports);
|
|
188
170
|
|
|
189
171
|
// src/components/register.ts
|
|
190
|
-
var
|
|
172
|
+
var import_core2 = require("@pactor-app/core");
|
|
191
173
|
|
|
192
174
|
// src/components/components/Accordion/index.tsx
|
|
193
175
|
var import_runtime = require("@pactor-app/runtime");
|
|
@@ -505,6 +487,8 @@ var ICONS = {
|
|
|
505
487
|
"chart-column": import_lucide_react2.ChartColumn,
|
|
506
488
|
"layout-grid": import_lucide_react2.LayoutGrid,
|
|
507
489
|
"layout-template": import_lucide_react2.LayoutTemplate,
|
|
490
|
+
"maximize-2": import_lucide_react2.Maximize2,
|
|
491
|
+
"minimize-2": import_lucide_react2.Minimize2,
|
|
508
492
|
palette: import_lucide_react2.Palette,
|
|
509
493
|
paintbrush: import_lucide_react2.Paintbrush,
|
|
510
494
|
funnel: import_lucide_react2.Funnel,
|
|
@@ -3278,12 +3262,21 @@ function Textarea({
|
|
|
3278
3262
|
|
|
3279
3263
|
// src/components/components/ChatInput/index.tsx
|
|
3280
3264
|
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
3265
|
+
function useOptionalRenderer() {
|
|
3266
|
+
try {
|
|
3267
|
+
return (0, import_runtime13.useRenderer)();
|
|
3268
|
+
} catch {
|
|
3269
|
+
return null;
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3281
3272
|
function ChatInput({
|
|
3282
3273
|
value,
|
|
3283
3274
|
placeholder,
|
|
3284
3275
|
disabled,
|
|
3285
3276
|
rows = 3,
|
|
3286
3277
|
hideSend,
|
|
3278
|
+
streaming = false,
|
|
3279
|
+
onStop,
|
|
3287
3280
|
toolbarStart,
|
|
3288
3281
|
toolbarEnd,
|
|
3289
3282
|
header,
|
|
@@ -3294,14 +3287,14 @@ function ChatInput({
|
|
|
3294
3287
|
className,
|
|
3295
3288
|
style
|
|
3296
3289
|
}) {
|
|
3297
|
-
const
|
|
3290
|
+
const renderer = useOptionalRenderer();
|
|
3298
3291
|
const controlled = value !== void 0;
|
|
3299
3292
|
const [draft, setDraft] = (0, import_react14.useState)("");
|
|
3300
3293
|
const { t } = (0, import_runtime12.useI18n)();
|
|
3301
3294
|
const text = controlled ? value : draft;
|
|
3302
3295
|
const canSubmit = !disabled && text.trim() !== "";
|
|
3303
3296
|
const customField = field !== void 0 && field !== null;
|
|
3304
|
-
const renderSlot = (slot) => (0, import_react14.isValidElement)(slot) || typeof slot !== "object" || slot === null ? slot : renderChildren([slot]);
|
|
3297
|
+
const renderSlot = (slot) => (0, import_react14.isValidElement)(slot) || typeof slot !== "object" || slot === null ? slot : renderer?.renderChildren([slot]) ?? null;
|
|
3305
3298
|
const composingRef = (0, import_react14.useRef)(false);
|
|
3306
3299
|
const handleChange = (next) => {
|
|
3307
3300
|
if (!controlled) {
|
|
@@ -3361,11 +3354,11 @@ function ChatInput({
|
|
|
3361
3354
|
{
|
|
3362
3355
|
type: "button",
|
|
3363
3356
|
size: "icon",
|
|
3364
|
-
"aria-label": t("pactor.chatInput.send"),
|
|
3365
|
-
disabled: !canSubmit,
|
|
3366
|
-
onClick: submit,
|
|
3357
|
+
"aria-label": streaming ? t("pactor.chatInput.stop") : t("pactor.chatInput.send"),
|
|
3358
|
+
disabled: streaming ? false : !canSubmit,
|
|
3359
|
+
onClick: streaming ? () => onStop?.() : submit,
|
|
3367
3360
|
className: "size-8 rounded-full",
|
|
3368
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_lucide_react13.ArrowUp, {})
|
|
3361
|
+
children: streaming ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_lucide_react13.Square, {}) : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_lucide_react13.ArrowUp, {})
|
|
3369
3362
|
}
|
|
3370
3363
|
)
|
|
3371
3364
|
] }) : null,
|
|
@@ -7480,7 +7473,7 @@ function useSidebarDrawer() {
|
|
|
7480
7473
|
return null;
|
|
7481
7474
|
}
|
|
7482
7475
|
}
|
|
7483
|
-
function
|
|
7476
|
+
function useOptionalRenderer2() {
|
|
7484
7477
|
try {
|
|
7485
7478
|
return (0, import_runtime31.useRenderer)();
|
|
7486
7479
|
} catch {
|
|
@@ -7488,7 +7481,7 @@ function useOptionalRenderer() {
|
|
|
7488
7481
|
}
|
|
7489
7482
|
}
|
|
7490
7483
|
function SidebarContentSlot({ content }) {
|
|
7491
|
-
const renderer =
|
|
7484
|
+
const renderer = useOptionalRenderer2();
|
|
7492
7485
|
if (renderer !== null && typeof content === "object" && content !== null && !("$$typeof" in content) && "type" in content) {
|
|
7493
7486
|
return /* @__PURE__ */ (0, import_jsx_runtime108.jsx)(import_jsx_runtime108.Fragment, { children: renderer.renderChildren([content]) });
|
|
7494
7487
|
}
|
|
@@ -10971,16 +10964,26 @@ var tabsListVariants = (0, import_class_variance_authority7.cva)(
|
|
|
10971
10964
|
default: "h-9 rounded-lg bg-muted p-[3px]",
|
|
10972
10965
|
// line:页签栏通栏(下划线轨道占满容器宽),触发器自然宽度靠左排列
|
|
10973
10966
|
line: "h-auto w-full justify-start gap-1 rounded-none border-b border-border bg-transparent p-0"
|
|
10967
|
+
},
|
|
10968
|
+
/** 尺寸(对齐 Button 的 size 语义):sm 经 compoundVariants 仅压缩胶囊变体 */
|
|
10969
|
+
size: {
|
|
10970
|
+
default: "",
|
|
10971
|
+
sm: ""
|
|
10974
10972
|
}
|
|
10975
10973
|
},
|
|
10974
|
+
compoundVariants: [
|
|
10975
|
+
{ variant: "default", size: "sm", class: "h-8" }
|
|
10976
|
+
],
|
|
10976
10977
|
defaultVariants: {
|
|
10977
|
-
variant: "default"
|
|
10978
|
+
variant: "default",
|
|
10979
|
+
size: "default"
|
|
10978
10980
|
}
|
|
10979
10981
|
}
|
|
10980
10982
|
);
|
|
10981
10983
|
function TabsList({
|
|
10982
10984
|
className,
|
|
10983
10985
|
variant,
|
|
10986
|
+
size,
|
|
10984
10987
|
...props
|
|
10985
10988
|
}) {
|
|
10986
10989
|
return /* @__PURE__ */ (0, import_jsx_runtime153.jsx)(
|
|
@@ -10988,7 +10991,8 @@ function TabsList({
|
|
|
10988
10991
|
{
|
|
10989
10992
|
"data-slot": "tabs-list",
|
|
10990
10993
|
"data-variant": variant ?? "default",
|
|
10991
|
-
|
|
10994
|
+
"data-size": size ?? "default",
|
|
10995
|
+
className: cn(tabsListVariants({ variant, size }), className),
|
|
10992
10996
|
...props
|
|
10993
10997
|
}
|
|
10994
10998
|
);
|
|
@@ -11009,6 +11013,8 @@ function TabsTrigger({
|
|
|
11009
11013
|
//(叠在 List 的底边轨道上),无底色/圆角/阴影;通栏 List 下取消
|
|
11010
11014
|
// flex-1 拉伸,触发器保持自然宽度
|
|
11011
11015
|
"group-data-[variant=line]/tabs-list:-mb-px group-data-[variant=line]/tabs-list:h-9 group-data-[variant=line]/tabs-list:flex-none group-data-[variant=line]/tabs-list:rounded-none group-data-[variant=line]/tabs-list:border-x-0 group-data-[variant=line]/tabs-list:border-t-0 group-data-[variant=line]/tabs-list:border-b-2 group-data-[variant=line]/tabs-list:py-1.5 group-data-[variant=line]/tabs-list:text-muted-foreground group-data-[variant=line]/tabs-list:data-active:border-b-primary group-data-[variant=line]/tabs-list:data-active:text-foreground",
|
|
11016
|
+
// size=sm:小字号 + 收紧纵向 padding(高度随 List h-8 自动收缩)
|
|
11017
|
+
"group-data-[size=sm]/tabs-list:py-0.5 group-data-[size=sm]/tabs-list:text-xs",
|
|
11012
11018
|
className
|
|
11013
11019
|
),
|
|
11014
11020
|
...props
|
|
@@ -12939,2460 +12945,6 @@ function Watermark({
|
|
|
12939
12945
|
);
|
|
12940
12946
|
}
|
|
12941
12947
|
|
|
12942
|
-
// src/components/chat/AgentStatus/index.tsx
|
|
12943
|
-
var import_jsx_runtime174 = require("react/jsx-runtime");
|
|
12944
|
-
var statusMeta = {
|
|
12945
|
-
running: { icon: "loader-circle", className: "text-info", spin: true },
|
|
12946
|
-
waiting: { icon: "clock", className: "text-warning" },
|
|
12947
|
-
done: { icon: "circle-check", className: "text-success" },
|
|
12948
|
-
error: { icon: "circle-x", className: "text-destructive" }
|
|
12949
|
-
};
|
|
12950
|
-
function AgentStatus({ status = "running", text, elapsed, className, style }) {
|
|
12951
|
-
const meta = statusMeta[status];
|
|
12952
|
-
return /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)(
|
|
12953
|
-
"div",
|
|
12954
|
-
{
|
|
12955
|
-
"data-slot": "agent-status",
|
|
12956
|
-
"data-status": status,
|
|
12957
|
-
className: cn("flex items-center gap-2 text-sm", className),
|
|
12958
|
-
style,
|
|
12959
|
-
children: [
|
|
12960
|
-
/* @__PURE__ */ (0, import_jsx_runtime174.jsx)("span", { className: cn(meta.className, meta.spin && "animate-spin motion-reduce:animate-none"), children: /* @__PURE__ */ (0, import_jsx_runtime174.jsx)(Icon, { name: meta.icon, size: "sm" }) }),
|
|
12961
|
-
text ? /* @__PURE__ */ (0, import_jsx_runtime174.jsx)("span", { "data-slot": "agent-status-text", children: text }) : null,
|
|
12962
|
-
elapsed !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)("span", { "data-slot": "agent-status-elapsed", className: "text-xs text-muted-foreground", children: [
|
|
12963
|
-
"\u5DF2\u7528\u65F6 ",
|
|
12964
|
-
elapsed,
|
|
12965
|
-
"s"
|
|
12966
|
-
] }) : null
|
|
12967
|
-
]
|
|
12968
|
-
}
|
|
12969
|
-
);
|
|
12970
|
-
}
|
|
12971
|
-
|
|
12972
|
-
// src/components/chat/ArtifactPanel/index.tsx
|
|
12973
|
-
var import_react62 = require("react");
|
|
12974
|
-
|
|
12975
|
-
// src/components/chat/ArtifactPanel/artifact.ts
|
|
12976
|
-
var ARTIFACT_IMAGE_EXTENSIONS = [
|
|
12977
|
-
"png",
|
|
12978
|
-
"jpg",
|
|
12979
|
-
"jpeg",
|
|
12980
|
-
"gif",
|
|
12981
|
-
"svg",
|
|
12982
|
-
"webp",
|
|
12983
|
-
"avif",
|
|
12984
|
-
"bmp",
|
|
12985
|
-
"ico"
|
|
12986
|
-
];
|
|
12987
|
-
function resolveArtifactFileType(artifact) {
|
|
12988
|
-
const declared = artifact.fileType?.trim().toLowerCase().replace(/^\./, "");
|
|
12989
|
-
if (declared) {
|
|
12990
|
-
return declared;
|
|
12991
|
-
}
|
|
12992
|
-
const match = /\.([A-Za-z0-9]+)$/.exec(artifact.title.trim());
|
|
12993
|
-
return match ? match[1].toLowerCase() : null;
|
|
12994
|
-
}
|
|
12995
|
-
function isImageArtifact(artifact) {
|
|
12996
|
-
const ext = resolveArtifactFileType(artifact);
|
|
12997
|
-
return ext !== null && ARTIFACT_IMAGE_EXTENSIONS.includes(ext);
|
|
12998
|
-
}
|
|
12999
|
-
var ARTIFACT_ICON_BY_EXTENSION = {
|
|
13000
|
-
// 表格数据
|
|
13001
|
-
csv: "table",
|
|
13002
|
-
tsv: "table",
|
|
13003
|
-
xls: "table",
|
|
13004
|
-
xlsx: "table",
|
|
13005
|
-
// 数据 / 数据库
|
|
13006
|
-
json: "database",
|
|
13007
|
-
sql: "database",
|
|
13008
|
-
// 脚本
|
|
13009
|
-
sh: "terminal",
|
|
13010
|
-
bash: "terminal",
|
|
13011
|
-
zsh: "terminal",
|
|
13012
|
-
// 代码 / 配置
|
|
13013
|
-
js: "code",
|
|
13014
|
-
mjs: "code",
|
|
13015
|
-
cjs: "code",
|
|
13016
|
-
jsx: "code",
|
|
13017
|
-
ts: "code",
|
|
13018
|
-
mts: "code",
|
|
13019
|
-
cts: "code",
|
|
13020
|
-
tsx: "code",
|
|
13021
|
-
py: "code",
|
|
13022
|
-
rb: "code",
|
|
13023
|
-
go: "code",
|
|
13024
|
-
rs: "code",
|
|
13025
|
-
java: "code",
|
|
13026
|
-
kt: "code",
|
|
13027
|
-
c: "code",
|
|
13028
|
-
h: "code",
|
|
13029
|
-
cc: "code",
|
|
13030
|
-
cpp: "code",
|
|
13031
|
-
cs: "code",
|
|
13032
|
-
swift: "code",
|
|
13033
|
-
php: "code",
|
|
13034
|
-
css: "code",
|
|
13035
|
-
scss: "code",
|
|
13036
|
-
less: "code",
|
|
13037
|
-
html: "code",
|
|
13038
|
-
vue: "code",
|
|
13039
|
-
svelte: "code",
|
|
13040
|
-
yaml: "code",
|
|
13041
|
-
yml: "code",
|
|
13042
|
-
toml: "code",
|
|
13043
|
-
xml: "code",
|
|
13044
|
-
// 文档 / 文本
|
|
13045
|
-
md: "file-text",
|
|
13046
|
-
markdown: "file-text",
|
|
13047
|
-
mdx: "file-text",
|
|
13048
|
-
txt: "file-text",
|
|
13049
|
-
text: "file-text",
|
|
13050
|
-
log: "file-text",
|
|
13051
|
-
rst: "file-text",
|
|
13052
|
-
pdf: "file-text",
|
|
13053
|
-
doc: "file-text",
|
|
13054
|
-
docx: "file-text"
|
|
13055
|
-
};
|
|
13056
|
-
function resolveArtifactIconName(artifact) {
|
|
13057
|
-
const ext = resolveArtifactFileType(artifact);
|
|
13058
|
-
if (ext !== null) {
|
|
13059
|
-
if (ARTIFACT_IMAGE_EXTENSIONS.includes(ext)) {
|
|
13060
|
-
return "image";
|
|
13061
|
-
}
|
|
13062
|
-
const name = ARTIFACT_ICON_BY_EXTENSION[ext];
|
|
13063
|
-
if (name !== void 0) {
|
|
13064
|
-
return name;
|
|
13065
|
-
}
|
|
13066
|
-
}
|
|
13067
|
-
if (artifact.kind === "code") {
|
|
13068
|
-
return "code";
|
|
13069
|
-
}
|
|
13070
|
-
if (artifact.kind === "dsl") {
|
|
13071
|
-
return "layout-grid";
|
|
13072
|
-
}
|
|
13073
|
-
return ext === null ? "file-text" : "file";
|
|
13074
|
-
}
|
|
13075
|
-
function buildArtifactTree(artifacts) {
|
|
13076
|
-
const root = { name: "", path: "", children: [] };
|
|
13077
|
-
for (const artifact of artifacts) {
|
|
13078
|
-
const segments = artifact.id.split("/").filter(Boolean);
|
|
13079
|
-
let node = root;
|
|
13080
|
-
for (let i = 0; i < segments.length - 1; i++) {
|
|
13081
|
-
const path = segments.slice(0, i + 1).join("/");
|
|
13082
|
-
let child = node.children.find(
|
|
13083
|
-
(item) => item.path === path && item.artifact === void 0
|
|
13084
|
-
);
|
|
13085
|
-
if (!child) {
|
|
13086
|
-
child = { name: segments[i], path, children: [] };
|
|
13087
|
-
node.children.push(child);
|
|
13088
|
-
}
|
|
13089
|
-
node = child;
|
|
13090
|
-
}
|
|
13091
|
-
node.children.push({
|
|
13092
|
-
name: artifact.title,
|
|
13093
|
-
path: artifact.id,
|
|
13094
|
-
artifact,
|
|
13095
|
-
children: []
|
|
13096
|
-
});
|
|
13097
|
-
}
|
|
13098
|
-
const sortLevel = (nodes) => {
|
|
13099
|
-
nodes.sort((a, b) => {
|
|
13100
|
-
const dirDelta = Number(b.artifact === void 0) - Number(a.artifact === void 0);
|
|
13101
|
-
return dirDelta !== 0 ? dirDelta : a.name.localeCompare(b.name);
|
|
13102
|
-
});
|
|
13103
|
-
for (const item of nodes) {
|
|
13104
|
-
sortLevel(item.children);
|
|
13105
|
-
}
|
|
13106
|
-
};
|
|
13107
|
-
sortLevel(root.children);
|
|
13108
|
-
return root.children;
|
|
13109
|
-
}
|
|
13110
|
-
|
|
13111
|
-
// src/components/chat/ArtifactPanel/download.ts
|
|
13112
|
-
var KIND_EXTENSIONS = {
|
|
13113
|
-
markdown: "md",
|
|
13114
|
-
text: "txt",
|
|
13115
|
-
code: "txt",
|
|
13116
|
-
dsl: "json"
|
|
13117
|
-
};
|
|
13118
|
-
function resolveArtifactFilename(artifact) {
|
|
13119
|
-
const title = artifact.title.trim() || "artifact";
|
|
13120
|
-
if (/\.[A-Za-z0-9]+$/.test(title)) {
|
|
13121
|
-
return title;
|
|
13122
|
-
}
|
|
13123
|
-
const ext = resolveArtifactFileType(artifact) ?? KIND_EXTENSIONS[artifact.kind];
|
|
13124
|
-
return `${title}.${ext}`;
|
|
13125
|
-
}
|
|
13126
|
-
function dataUrlToBlob(dataUrl) {
|
|
13127
|
-
const comma = dataUrl.indexOf(",");
|
|
13128
|
-
const meta = dataUrl.slice(0, comma);
|
|
13129
|
-
const payload = dataUrl.slice(comma + 1);
|
|
13130
|
-
const mime = /^data:([^;,]+)/.exec(meta)?.[1] ?? "application/octet-stream";
|
|
13131
|
-
if (meta.includes(";base64")) {
|
|
13132
|
-
const binary = atob(payload);
|
|
13133
|
-
const bytes = new Uint8Array(binary.length);
|
|
13134
|
-
for (let i = 0; i < binary.length; i++) {
|
|
13135
|
-
bytes[i] = binary.charCodeAt(i);
|
|
13136
|
-
}
|
|
13137
|
-
return new Blob([bytes], { type: mime });
|
|
13138
|
-
}
|
|
13139
|
-
return new Blob([decodeURIComponent(payload)], { type: mime });
|
|
13140
|
-
}
|
|
13141
|
-
function isRemoteUrl(raw) {
|
|
13142
|
-
return /^https?:\/\//.test(raw.trim());
|
|
13143
|
-
}
|
|
13144
|
-
function buildArtifactBlob(artifact) {
|
|
13145
|
-
if (artifact.kind === "dsl" && typeof artifact.content === "object") {
|
|
13146
|
-
return new Blob([JSON.stringify(artifact.content, null, 2)], {
|
|
13147
|
-
type: "application/json"
|
|
13148
|
-
});
|
|
13149
|
-
}
|
|
13150
|
-
const raw = String(artifact.content);
|
|
13151
|
-
if (isImageArtifact(artifact)) {
|
|
13152
|
-
const trimmed = raw.trim();
|
|
13153
|
-
if (trimmed.startsWith("data:")) {
|
|
13154
|
-
return dataUrlToBlob(trimmed);
|
|
13155
|
-
}
|
|
13156
|
-
if (trimmed.startsWith("<svg") || trimmed.startsWith("<?xml")) {
|
|
13157
|
-
return new Blob([raw], { type: "image/svg+xml" });
|
|
13158
|
-
}
|
|
13159
|
-
if (isRemoteUrl(trimmed)) {
|
|
13160
|
-
return null;
|
|
13161
|
-
}
|
|
13162
|
-
}
|
|
13163
|
-
const ext = resolveArtifactFileType(artifact);
|
|
13164
|
-
const mime = ext === "md" || artifact.kind === "markdown" ? "text/markdown" : "text/plain";
|
|
13165
|
-
return new Blob([raw], { type: `${mime};charset=utf-8` });
|
|
13166
|
-
}
|
|
13167
|
-
function saveBlob(blob, filename) {
|
|
13168
|
-
const url = URL.createObjectURL(blob);
|
|
13169
|
-
const anchor = document.createElement("a");
|
|
13170
|
-
anchor.href = url;
|
|
13171
|
-
anchor.download = filename;
|
|
13172
|
-
document.body.appendChild(anchor);
|
|
13173
|
-
anchor.click();
|
|
13174
|
-
anchor.remove();
|
|
13175
|
-
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
13176
|
-
}
|
|
13177
|
-
async function downloadArtifact(artifact) {
|
|
13178
|
-
const filename = resolveArtifactFilename(artifact);
|
|
13179
|
-
const raw = String(artifact.content ?? "").trim();
|
|
13180
|
-
if (isImageArtifact(artifact) && isRemoteUrl(raw)) {
|
|
13181
|
-
try {
|
|
13182
|
-
const response = await fetch(raw);
|
|
13183
|
-
if (!response.ok) {
|
|
13184
|
-
throw new Error(`HTTP ${response.status}`);
|
|
13185
|
-
}
|
|
13186
|
-
saveBlob(await response.blob(), filename);
|
|
13187
|
-
return;
|
|
13188
|
-
} catch {
|
|
13189
|
-
window.open(raw, "_blank", "noopener");
|
|
13190
|
-
return;
|
|
13191
|
-
}
|
|
13192
|
-
}
|
|
13193
|
-
const blob = buildArtifactBlob(artifact);
|
|
13194
|
-
if (blob) {
|
|
13195
|
-
saveBlob(blob, filename);
|
|
13196
|
-
}
|
|
13197
|
-
}
|
|
13198
|
-
|
|
13199
|
-
// src/components/chat/ArtifactPanel/dsl-preview.tsx
|
|
13200
|
-
var import_core2 = require("@pactor-app/core");
|
|
13201
|
-
var import_runtime50 = require("@pactor-app/runtime");
|
|
13202
|
-
var import_react61 = require("react");
|
|
13203
|
-
var import_jsx_runtime175 = require("react/jsx-runtime");
|
|
13204
|
-
var ARTIFACT_DENIED_TYPE = "ChatDenied";
|
|
13205
|
-
function ArtifactDenied({ deniedType }) {
|
|
13206
|
-
return /* @__PURE__ */ (0, import_jsx_runtime175.jsxs)(
|
|
13207
|
-
"div",
|
|
13208
|
-
{
|
|
13209
|
-
"data-slot": "artifact-denied",
|
|
13210
|
-
"data-denied-type": deniedType,
|
|
13211
|
-
className: "rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground",
|
|
13212
|
-
children: [
|
|
13213
|
-
"\u8BE5\u7EC4\u4EF6\u4E0D\u5141\u8BB8\u5728\u4EA7\u7269\u9884\u89C8\u4E2D\u4F7F\u7528",
|
|
13214
|
-
deniedType ? `\uFF1A${deniedType}` : ""
|
|
13215
|
-
]
|
|
13216
|
-
}
|
|
13217
|
-
);
|
|
13218
|
-
}
|
|
13219
|
-
function guardArtifactDsl(node, registry) {
|
|
13220
|
-
const type = node.type ?? "(reference)";
|
|
13221
|
-
if (type !== ARTIFACT_DENIED_TYPE && !registry.has(type)) {
|
|
13222
|
-
return {
|
|
13223
|
-
type: ARTIFACT_DENIED_TYPE,
|
|
13224
|
-
props: { deniedType: type }
|
|
13225
|
-
};
|
|
13226
|
-
}
|
|
13227
|
-
if (node.children === void 0) {
|
|
13228
|
-
return node;
|
|
13229
|
-
}
|
|
13230
|
-
if (!Array.isArray(node.children)) {
|
|
13231
|
-
return {
|
|
13232
|
-
type: ARTIFACT_DENIED_TYPE,
|
|
13233
|
-
props: { deniedType: `${type}(remote)` }
|
|
13234
|
-
};
|
|
13235
|
-
}
|
|
13236
|
-
if (node.children.length === 0) {
|
|
13237
|
-
return node;
|
|
13238
|
-
}
|
|
13239
|
-
return {
|
|
13240
|
-
...node,
|
|
13241
|
-
// 数组中混排的引用元素同样无法静态过白名单:替换为受控占位
|
|
13242
|
-
children: node.children.map(
|
|
13243
|
-
(child) => (0, import_core2.isDslSourceRef)(child) ? { type: ARTIFACT_DENIED_TYPE, props: { deniedType: "(remote)" } } : guardArtifactDsl(child, registry)
|
|
13244
|
-
)
|
|
13245
|
-
};
|
|
13246
|
-
}
|
|
13247
|
-
function useArtifactPreviewRuntime(safeRegistry, user) {
|
|
13248
|
-
return (0, import_react61.useMemo)(() => {
|
|
13249
|
-
if (!safeRegistry) {
|
|
13250
|
-
return void 0;
|
|
13251
|
-
}
|
|
13252
|
-
const components = new import_core2.Registry("ArtifactPreviewRegistry");
|
|
13253
|
-
components.register(ARTIFACT_DENIED_TYPE, ArtifactDenied);
|
|
13254
|
-
for (const name of safeRegistry.list()) {
|
|
13255
|
-
components.register(name, safeRegistry.get(name));
|
|
13256
|
-
}
|
|
13257
|
-
const context = (0, import_runtime50.createRuntimeContext)({ components, user });
|
|
13258
|
-
(0, import_runtime50.registerBuiltinActions)(context.actions);
|
|
13259
|
-
return { context, engine: new import_runtime50.ActionEngine(context) };
|
|
13260
|
-
}, [safeRegistry, user]);
|
|
13261
|
-
}
|
|
13262
|
-
var ArtifactDslGuard = class extends import_react61.Component {
|
|
13263
|
-
constructor() {
|
|
13264
|
-
super(...arguments);
|
|
13265
|
-
this.state = { failed: false };
|
|
13266
|
-
}
|
|
13267
|
-
static getDerivedStateFromError() {
|
|
13268
|
-
return { failed: true };
|
|
13269
|
-
}
|
|
13270
|
-
componentDidCatch(error) {
|
|
13271
|
-
console.warn("[@pactor-app/ui] DSL \u4EA7\u7269\u6E32\u67D3\u5931\u8D25\uFF0C\u5DF2\u964D\u7EA7\u5C55\u793A", error);
|
|
13272
|
-
}
|
|
13273
|
-
render() {
|
|
13274
|
-
return this.state.failed ? /* @__PURE__ */ (0, import_jsx_runtime175.jsx)(
|
|
13275
|
-
"div",
|
|
13276
|
-
{
|
|
13277
|
-
"data-slot": "artifact-denied",
|
|
13278
|
-
className: "rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground",
|
|
13279
|
-
children: "DSL \u4EA7\u7269\u6E32\u67D3\u5931\u8D25\uFF0C\u5DF2\u964D\u7EA7\u5C55\u793A"
|
|
13280
|
-
}
|
|
13281
|
-
) : this.props.children;
|
|
13282
|
-
}
|
|
13283
|
-
};
|
|
13284
|
-
function ArtifactDslNode({ node }) {
|
|
13285
|
-
const { renderChildren } = (0, import_runtime50.useRenderer)();
|
|
13286
|
-
return /* @__PURE__ */ (0, import_jsx_runtime175.jsx)(import_jsx_runtime175.Fragment, { children: renderChildren([node]) });
|
|
13287
|
-
}
|
|
13288
|
-
function ArtifactDslContent({
|
|
13289
|
-
content,
|
|
13290
|
-
runtime,
|
|
13291
|
-
style
|
|
13292
|
-
}) {
|
|
13293
|
-
const node = typeof content === "object" && content !== null && !Array.isArray(content) && typeof content.type === "string" ? content : void 0;
|
|
13294
|
-
if (!node || !runtime) {
|
|
13295
|
-
return /* @__PURE__ */ (0, import_jsx_runtime175.jsx)(
|
|
13296
|
-
"div",
|
|
13297
|
-
{
|
|
13298
|
-
"data-slot": "artifact-denied",
|
|
13299
|
-
className: "rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground",
|
|
13300
|
-
style,
|
|
13301
|
-
children: node ? "DSL \u9884\u89C8\u4E0D\u53EF\u7528\uFF08\u672A\u6CE8\u5165 Safe Registry\uFF09" : "DSL \u4EA7\u7269\u5185\u5BB9\u65E0\u6548"
|
|
13302
|
-
}
|
|
13303
|
-
);
|
|
13304
|
-
}
|
|
13305
|
-
const guarded = guardArtifactDsl(node, runtime.context.components);
|
|
13306
|
-
return /* @__PURE__ */ (0, import_jsx_runtime175.jsx)(import_runtime50.DslRenderer, { context: runtime.context, engine: runtime.engine, children: /* @__PURE__ */ (0, import_jsx_runtime175.jsx)(ArtifactDslGuard, { children: /* @__PURE__ */ (0, import_jsx_runtime175.jsx)(ArtifactDslNode, { node: guarded }) }) });
|
|
13307
|
-
}
|
|
13308
|
-
|
|
13309
|
-
// src/components/chat/ArtifactPanel/index.tsx
|
|
13310
|
-
var import_jsx_runtime176 = require("react/jsx-runtime");
|
|
13311
|
-
function ArtifactKindIcon({ artifact }) {
|
|
13312
|
-
return /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(Icon, { name: resolveArtifactIconName(artifact), size: 13 });
|
|
13313
|
-
}
|
|
13314
|
-
function ArtifactListView({
|
|
13315
|
-
nodes,
|
|
13316
|
-
activeId,
|
|
13317
|
-
onSelect
|
|
13318
|
-
}) {
|
|
13319
|
-
return /* @__PURE__ */ (0, import_jsx_runtime176.jsx)("ul", { "data-slot": "artifact-panel-list", className: "flex flex-col gap-0.5", children: nodes.map((node) => /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(
|
|
13320
|
-
ArtifactTreeRow,
|
|
13321
|
-
{
|
|
13322
|
-
node,
|
|
13323
|
-
activeId,
|
|
13324
|
-
onSelect
|
|
13325
|
-
},
|
|
13326
|
-
node.path
|
|
13327
|
-
)) });
|
|
13328
|
-
}
|
|
13329
|
-
function ArtifactTreeRow({
|
|
13330
|
-
node,
|
|
13331
|
-
activeId,
|
|
13332
|
-
onSelect
|
|
13333
|
-
}) {
|
|
13334
|
-
const [open, setOpen] = (0, import_react62.useState)(true);
|
|
13335
|
-
if (node.artifact) {
|
|
13336
|
-
return /* @__PURE__ */ (0, import_jsx_runtime176.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime176.jsxs)(
|
|
13337
|
-
"button",
|
|
13338
|
-
{
|
|
13339
|
-
type: "button",
|
|
13340
|
-
"data-slot": "artifact-panel-list-item",
|
|
13341
|
-
"data-active": node.artifact.id === activeId,
|
|
13342
|
-
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",
|
|
13343
|
-
onClick: () => onSelect?.(node.artifact.id),
|
|
13344
|
-
children: [
|
|
13345
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsx)(ArtifactKindIcon, { artifact: node.artifact }),
|
|
13346
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsx)("span", { className: "min-w-0 flex-1 truncate", children: node.artifact.title }),
|
|
13347
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: node.artifact.kind })
|
|
13348
|
-
]
|
|
13349
|
-
}
|
|
13350
|
-
) });
|
|
13351
|
-
}
|
|
13352
|
-
return /* @__PURE__ */ (0, import_jsx_runtime176.jsxs)("li", { children: [
|
|
13353
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsxs)(
|
|
13354
|
-
"button",
|
|
13355
|
-
{
|
|
13356
|
-
type: "button",
|
|
13357
|
-
"data-slot": "artifact-panel-list-folder",
|
|
13358
|
-
"aria-expanded": open,
|
|
13359
|
-
"data-open": open,
|
|
13360
|
-
className: "flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm hover:bg-accent",
|
|
13361
|
-
onClick: () => setOpen((value) => !value),
|
|
13362
|
-
children: [
|
|
13363
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsx)(
|
|
13364
|
-
"span",
|
|
13365
|
-
{
|
|
13366
|
-
className: "inline-flex transition-transform data-[open=true]:rotate-90",
|
|
13367
|
-
"data-open": open,
|
|
13368
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(Icon, { name: "chevron-right", size: 12 })
|
|
13369
|
-
}
|
|
13370
|
-
),
|
|
13371
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsx)(Icon, { name: "folder", size: 13 }),
|
|
13372
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsx)("span", { className: "min-w-0 flex-1 truncate", children: node.name })
|
|
13373
|
-
]
|
|
13374
|
-
}
|
|
13375
|
-
),
|
|
13376
|
-
open && /* @__PURE__ */ (0, import_jsx_runtime176.jsx)("div", { className: "pl-4", children: /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(
|
|
13377
|
-
ArtifactListView,
|
|
13378
|
-
{
|
|
13379
|
-
nodes: node.children,
|
|
13380
|
-
activeId,
|
|
13381
|
-
onSelect
|
|
13382
|
-
}
|
|
13383
|
-
) })
|
|
13384
|
-
] });
|
|
13385
|
-
}
|
|
13386
|
-
function ArtifactImageContent({ artifact }) {
|
|
13387
|
-
const raw = String(artifact.content).trim();
|
|
13388
|
-
const src = raw.startsWith("<svg") || raw.startsWith("<?xml") ? `data:image/svg+xml;utf8,${encodeURIComponent(raw)}` : raw;
|
|
13389
|
-
return /* @__PURE__ */ (0, import_jsx_runtime176.jsx)("div", { "data-slot": "artifact-panel-image", className: "flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime176.jsx)("img", { src, alt: artifact.title, className: "max-w-full rounded-md" }) });
|
|
13390
|
-
}
|
|
13391
|
-
function ArtifactContent({
|
|
13392
|
-
artifact,
|
|
13393
|
-
runtime,
|
|
13394
|
-
viewers
|
|
13395
|
-
}) {
|
|
13396
|
-
const ext = resolveArtifactFileType(artifact);
|
|
13397
|
-
const custom = (ext ? viewers?.[ext] : void 0) ?? viewers?.[artifact.kind];
|
|
13398
|
-
if (custom) {
|
|
13399
|
-
return /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(import_jsx_runtime176.Fragment, { children: custom(artifact) });
|
|
13400
|
-
}
|
|
13401
|
-
if (isImageArtifact(artifact)) {
|
|
13402
|
-
return /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(ArtifactImageContent, { artifact });
|
|
13403
|
-
}
|
|
13404
|
-
switch (artifact.kind) {
|
|
13405
|
-
case "markdown":
|
|
13406
|
-
return /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(import_markdown2.MarkdownDslComponent, { content: String(artifact.content) });
|
|
13407
|
-
case "code":
|
|
13408
|
-
return /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(
|
|
13409
|
-
CodeBlock,
|
|
13410
|
-
{
|
|
13411
|
-
code: String(artifact.content),
|
|
13412
|
-
language: artifact.language
|
|
13413
|
-
}
|
|
13414
|
-
);
|
|
13415
|
-
case "text":
|
|
13416
|
-
return /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(
|
|
13417
|
-
"pre",
|
|
13418
|
-
{
|
|
13419
|
-
"data-slot": "artifact-panel-text",
|
|
13420
|
-
className: "text-sm break-words whitespace-pre-wrap",
|
|
13421
|
-
children: String(artifact.content)
|
|
13422
|
-
}
|
|
13423
|
-
);
|
|
13424
|
-
case "dsl":
|
|
13425
|
-
return /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(ArtifactDslContent, { content: artifact.content, runtime });
|
|
13426
|
-
default:
|
|
13427
|
-
return null;
|
|
13428
|
-
}
|
|
13429
|
-
}
|
|
13430
|
-
function ArtifactPanel({
|
|
13431
|
-
artifact,
|
|
13432
|
-
artifacts,
|
|
13433
|
-
activeArtifactId,
|
|
13434
|
-
onSelectArtifact,
|
|
13435
|
-
title = "\u4EA7\u7269",
|
|
13436
|
-
emptyText = "\u6682\u65E0\u4EA7\u7269",
|
|
13437
|
-
onClose,
|
|
13438
|
-
onDownload,
|
|
13439
|
-
safeRegistry,
|
|
13440
|
-
user,
|
|
13441
|
-
artifactViewers,
|
|
13442
|
-
className,
|
|
13443
|
-
style
|
|
13444
|
-
}) {
|
|
13445
|
-
const runtime = useArtifactPreviewRuntime(safeRegistry, user);
|
|
13446
|
-
const [view, setView] = (0, import_react62.useState)("content");
|
|
13447
|
-
const activeId = activeArtifactId ?? artifact?.id;
|
|
13448
|
-
(0, import_react62.useEffect)(() => {
|
|
13449
|
-
setView("content");
|
|
13450
|
-
}, [activeId]);
|
|
13451
|
-
const hasArtifacts = artifacts !== void 0 && artifacts.length > 0;
|
|
13452
|
-
const headerTitle = view === "list" ? "\u4EA7\u7269\u76EE\u5F55" : artifact?.title ?? title;
|
|
13453
|
-
return /* @__PURE__ */ (0, import_jsx_runtime176.jsxs)(
|
|
13454
|
-
"aside",
|
|
13455
|
-
{
|
|
13456
|
-
"data-slot": "artifact-panel",
|
|
13457
|
-
"data-kind": artifact?.kind,
|
|
13458
|
-
className: cn("flex h-full min-w-0 flex-col", className),
|
|
13459
|
-
style,
|
|
13460
|
-
children: [
|
|
13461
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsxs)("div", { className: "flex shrink-0 items-center gap-1 border-b border-border px-2 py-2.5", children: [
|
|
13462
|
-
hasArtifacts ? /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(
|
|
13463
|
-
Button2,
|
|
13464
|
-
{
|
|
13465
|
-
icon: "list",
|
|
13466
|
-
variant: "text",
|
|
13467
|
-
tooltip: view === "list" ? "\u8FD4\u56DE\u5185\u5BB9" : "\u4EA7\u7269\u76EE\u5F55",
|
|
13468
|
-
onClick: () => setView((value) => value === "list" ? "content" : "list")
|
|
13469
|
-
}
|
|
13470
|
-
) : null,
|
|
13471
|
-
hasArtifacts ? /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(
|
|
13472
|
-
DropdownMenu2,
|
|
13473
|
-
{
|
|
13474
|
-
items: artifacts.map((item) => ({
|
|
13475
|
-
label: item.title,
|
|
13476
|
-
value: item.id,
|
|
13477
|
-
icon: resolveArtifactIconName(item)
|
|
13478
|
-
})),
|
|
13479
|
-
onSelect: (id) => onSelectArtifact?.(id),
|
|
13480
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime176.jsxs)(
|
|
13481
|
-
"span",
|
|
13482
|
-
{
|
|
13483
|
-
"data-slot": "artifact-panel-menu-trigger",
|
|
13484
|
-
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",
|
|
13485
|
-
children: [
|
|
13486
|
-
view !== "list" && artifact ? /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(ArtifactKindIcon, { artifact }) : null,
|
|
13487
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsx)("span", { className: "truncate", children: headerTitle }),
|
|
13488
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsx)(Icon, { name: "chevron-down", size: 12 })
|
|
13489
|
-
]
|
|
13490
|
-
}
|
|
13491
|
-
)
|
|
13492
|
-
}
|
|
13493
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime176.jsx)("span", { className: "min-w-0 flex-1 truncate px-1.5 text-sm font-medium", children: headerTitle }),
|
|
13494
|
-
view !== "list" && artifact ? /* @__PURE__ */ (0, import_jsx_runtime176.jsx)("span", { className: "shrink-0 rounded-md bg-accent px-1.5 py-0.5 text-xs text-muted-foreground", children: artifact.kind }) : null,
|
|
13495
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsx)("span", { className: "flex-1" }),
|
|
13496
|
-
artifact ? /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(
|
|
13497
|
-
Button2,
|
|
13498
|
-
{
|
|
13499
|
-
icon: "download",
|
|
13500
|
-
variant: "text",
|
|
13501
|
-
tooltip: "\u4E0B\u8F7D\u4EA7\u7269",
|
|
13502
|
-
className: "px-2",
|
|
13503
|
-
onClick: () => onDownload ? onDownload(artifact) : void downloadArtifact(artifact)
|
|
13504
|
-
}
|
|
13505
|
-
) : null,
|
|
13506
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsx)(
|
|
13507
|
-
Button2,
|
|
13508
|
-
{
|
|
13509
|
-
icon: "x",
|
|
13510
|
-
variant: "text",
|
|
13511
|
-
tooltip: "\u6536\u8D77\u4EA7\u7269\u533A",
|
|
13512
|
-
className: "px-2",
|
|
13513
|
-
onClick: () => onClose?.()
|
|
13514
|
-
}
|
|
13515
|
-
)
|
|
13516
|
-
] }),
|
|
13517
|
-
/* @__PURE__ */ (0, import_jsx_runtime176.jsx)("div", { className: "scrollbar-subtle min-h-0 flex-1 overflow-auto p-4", children: view === "list" && artifacts !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(
|
|
13518
|
-
ArtifactListView,
|
|
13519
|
-
{
|
|
13520
|
-
nodes: buildArtifactTree(artifacts),
|
|
13521
|
-
activeId,
|
|
13522
|
-
onSelect: onSelectArtifact
|
|
13523
|
-
}
|
|
13524
|
-
) : artifact ? /* @__PURE__ */ (0, import_jsx_runtime176.jsx)(
|
|
13525
|
-
ArtifactContent,
|
|
13526
|
-
{
|
|
13527
|
-
artifact,
|
|
13528
|
-
runtime,
|
|
13529
|
-
viewers: artifactViewers
|
|
13530
|
-
}
|
|
13531
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime176.jsx)("p", { className: "text-sm text-muted-foreground", children: emptyText }) })
|
|
13532
|
-
]
|
|
13533
|
-
}
|
|
13534
|
-
);
|
|
13535
|
-
}
|
|
13536
|
-
|
|
13537
|
-
// src/components/chat/Attachment/index.tsx
|
|
13538
|
-
var import_jsx_runtime177 = require("react/jsx-runtime");
|
|
13539
|
-
var kindIcon2 = { image: "image", text: "file-text", video: "video", audio: "music", other: "file" };
|
|
13540
|
-
function formatSize3(bytes) {
|
|
13541
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
13542
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
13543
|
-
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
13544
|
-
}
|
|
13545
|
-
function Attachment({ items = [], onRemove, onRetry, className, style }) {
|
|
13546
|
-
return /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("div", { "data-slot": "attachment", className: cn("flex flex-wrap gap-2", className), style, children: items.map((item, index) => {
|
|
13547
|
-
const key = item.id ?? index;
|
|
13548
|
-
const kind = inferKind(item.name, item.fileType);
|
|
13549
|
-
const status = item.status ?? "done";
|
|
13550
|
-
return /* @__PURE__ */ (0, import_jsx_runtime177.jsxs)(
|
|
13551
|
-
"div",
|
|
13552
|
-
{
|
|
13553
|
-
"data-slot": "attachment-item",
|
|
13554
|
-
"data-status": status,
|
|
13555
|
-
className: "flex w-56 flex-col rounded-md border border-border px-2 py-1.5",
|
|
13556
|
-
children: [
|
|
13557
|
-
/* @__PURE__ */ (0, import_jsx_runtime177.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
13558
|
-
/* @__PURE__ */ (0, import_jsx_runtime177.jsx)("span", { className: "shrink-0 text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(Icon, { name: kindIcon2[kind], size: "sm" }) }),
|
|
13559
|
-
/* @__PURE__ */ (0, import_jsx_runtime177.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm", children: item.name }),
|
|
13560
|
-
status === "uploading" ? /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("span", { className: "shrink-0 animate-spin text-muted-foreground motion-reduce:animate-none", children: /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(Icon, { name: "loader-circle", size: "sm" }) }) : null,
|
|
13561
|
-
status === "error" && onRetry ? /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(
|
|
13562
|
-
"button",
|
|
13563
|
-
{
|
|
13564
|
-
type: "button",
|
|
13565
|
-
"data-slot": "attachment-retry",
|
|
13566
|
-
"aria-label": `\u91CD\u8BD5 ${item.name}`,
|
|
13567
|
-
className: "shrink-0 text-destructive hover:opacity-80",
|
|
13568
|
-
onClick: () => onRetry(key),
|
|
13569
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(Icon, { name: "refresh-ccw", size: "sm" })
|
|
13570
|
-
}
|
|
13571
|
-
) : null,
|
|
13572
|
-
onRemove ? /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(
|
|
13573
|
-
"button",
|
|
13574
|
-
{
|
|
13575
|
-
type: "button",
|
|
13576
|
-
"data-slot": "attachment-remove",
|
|
13577
|
-
"aria-label": `\u79FB\u9664 ${item.name}`,
|
|
13578
|
-
className: "shrink-0 text-muted-foreground hover:text-foreground",
|
|
13579
|
-
onClick: () => onRemove(key),
|
|
13580
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime177.jsx)(Icon, { name: "x", size: "sm" })
|
|
13581
|
-
}
|
|
13582
|
-
) : null
|
|
13583
|
-
] }),
|
|
13584
|
-
/* @__PURE__ */ (0, import_jsx_runtime177.jsxs)("div", { className: "mt-0.5 flex items-center gap-1.5 pl-5 text-xs", children: [
|
|
13585
|
-
item.fileSize !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("span", { className: "text-muted-foreground", children: formatSize3(item.fileSize) }) : null,
|
|
13586
|
-
status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("span", { className: "text-destructive", children: "\u4E0A\u4F20\u5931\u8D25" }) : null
|
|
13587
|
-
] }),
|
|
13588
|
-
status === "uploading" && item.progress !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("div", { "data-slot": "attachment-progress", className: "mt-1 ml-5 h-1 overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ (0, import_jsx_runtime177.jsx)("div", { className: "h-full bg-primary transition-[width]", style: { width: `${item.progress}%` } }) }) : null
|
|
13589
|
-
]
|
|
13590
|
-
},
|
|
13591
|
-
key
|
|
13592
|
-
);
|
|
13593
|
-
}) });
|
|
13594
|
-
}
|
|
13595
|
-
|
|
13596
|
-
// src/ui/bubble.tsx
|
|
13597
|
-
var React7 = __toESM(require("react"), 1);
|
|
13598
|
-
var import_class_variance_authority10 = require("class-variance-authority");
|
|
13599
|
-
var import_jsx_runtime178 = require("react/jsx-runtime");
|
|
13600
|
-
var bubbleVariants = (0, import_class_variance_authority10.cva)(
|
|
13601
|
-
"group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full",
|
|
13602
|
-
{
|
|
13603
|
-
variants: {
|
|
13604
|
-
variant: {
|
|
13605
|
-
default: "*:data-[slot=bubble-content]:bg-primary *:data-[slot=bubble-content]:text-primary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-primary/80",
|
|
13606
|
-
secondary: "*:data-[slot=bubble-content]:bg-secondary *:data-[slot=bubble-content]:text-secondary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)]",
|
|
13607
|
-
muted: "*:data-[slot=bubble-content]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--muted),var(--foreground)_5%)]",
|
|
13608
|
-
tinted: "*:data-[slot=bubble-content]:bg-(--bubble-background) *:data-[slot=bubble-content]:text-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-(--bubble-hover-background)",
|
|
13609
|
-
outline: "*:data-[slot=bubble-content]:border-border *:data-[slot=bubble-content]:bg-card [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-input/30",
|
|
13610
|
-
ghost: "border-none *:data-[slot=bubble-content]:rounded-none *:data-[slot=bubble-content]:bg-transparent *:data-[slot=bubble-content]:p-0 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted/50",
|
|
13611
|
-
destructive: "*:data-[slot=bubble-content]:bg-destructive/10 *:data-[slot=bubble-content]:text-destructive dark:*:data-[slot=bubble-content]:bg-destructive/20 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/20 dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/30"
|
|
13612
|
-
}
|
|
13613
|
-
},
|
|
13614
|
-
defaultVariants: {
|
|
13615
|
-
variant: "default"
|
|
13616
|
-
}
|
|
13617
|
-
}
|
|
13618
|
-
);
|
|
13619
|
-
function Bubble({
|
|
13620
|
-
variant = "default",
|
|
13621
|
-
align = "start",
|
|
13622
|
-
className,
|
|
13623
|
-
...props
|
|
13624
|
-
}) {
|
|
13625
|
-
return /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(
|
|
13626
|
-
"div",
|
|
13627
|
-
{
|
|
13628
|
-
"data-slot": "bubble",
|
|
13629
|
-
"data-variant": variant,
|
|
13630
|
-
"data-align": align,
|
|
13631
|
-
className: cn(bubbleVariants({ variant }), className),
|
|
13632
|
-
...props
|
|
13633
|
-
}
|
|
13634
|
-
);
|
|
13635
|
-
}
|
|
13636
|
-
function BubbleContent({
|
|
13637
|
-
asChild = false,
|
|
13638
|
-
className,
|
|
13639
|
-
children,
|
|
13640
|
-
...props
|
|
13641
|
-
}) {
|
|
13642
|
-
const cls = cn(
|
|
13643
|
-
"w-fit max-w-full min-w-0 overflow-hidden rounded-xl border border-transparent px-3 py-2 text-sm leading-relaxed wrap-break-word group-data-[align=end]/bubble:self-end [button]:text-left [button,a]:transition-colors [button,a]:outline-none [button,a]:focus-visible:border-ring [button,a]:focus-visible:ring-3 [button,a]:focus-visible:ring-ring/50",
|
|
13644
|
-
className
|
|
13645
|
-
);
|
|
13646
|
-
if (asChild && React7.isValidElement(children)) {
|
|
13647
|
-
return React7.cloneElement(children, {
|
|
13648
|
-
"data-slot": "bubble-content",
|
|
13649
|
-
className: cn(cls, children.props.className),
|
|
13650
|
-
...props
|
|
13651
|
-
});
|
|
13652
|
-
}
|
|
13653
|
-
return /* @__PURE__ */ (0, import_jsx_runtime178.jsx)(
|
|
13654
|
-
"div",
|
|
13655
|
-
{
|
|
13656
|
-
"data-slot": "bubble-content",
|
|
13657
|
-
className: cls,
|
|
13658
|
-
...props,
|
|
13659
|
-
children
|
|
13660
|
-
}
|
|
13661
|
-
);
|
|
13662
|
-
}
|
|
13663
|
-
var bubbleReactionsVariants = (0, import_class_variance_authority10.cva)(
|
|
13664
|
-
"absolute z-10 flex w-fit shrink-0 items-center justify-center gap-1 rounded-full bg-muted px-1.5 py-0.5 text-sm ring-3 ring-card has-[button]:p-0",
|
|
13665
|
-
{
|
|
13666
|
-
variants: {
|
|
13667
|
-
side: {
|
|
13668
|
-
top: "top-0 -translate-y-3/4",
|
|
13669
|
-
bottom: "bottom-0 translate-y-3/4"
|
|
13670
|
-
},
|
|
13671
|
-
align: {
|
|
13672
|
-
start: "left-3",
|
|
13673
|
-
end: "right-3"
|
|
13674
|
-
}
|
|
13675
|
-
},
|
|
13676
|
-
defaultVariants: {
|
|
13677
|
-
side: "bottom",
|
|
13678
|
-
align: "end"
|
|
13679
|
-
}
|
|
13680
|
-
}
|
|
13681
|
-
);
|
|
13682
|
-
|
|
13683
|
-
// src/components/chat/Bubble/index.tsx
|
|
13684
|
-
var import_jsx_runtime179 = require("react/jsx-runtime");
|
|
13685
|
-
function Bubble2({ align = "start", variant = "muted", className, style, children }) {
|
|
13686
|
-
return /* @__PURE__ */ (0, import_jsx_runtime179.jsx)(Bubble, { variant, align, className, style, children: /* @__PURE__ */ (0, import_jsx_runtime179.jsx)(BubbleContent, { children }) });
|
|
13687
|
-
}
|
|
13688
|
-
|
|
13689
|
-
// src/components/chat/Sender/index.tsx
|
|
13690
|
-
var import_jsx_runtime180 = require("react/jsx-runtime");
|
|
13691
|
-
function Sender({ name, avatar, avatarText, role, time, align = "start", className, style }) {
|
|
13692
|
-
return /* @__PURE__ */ (0, import_jsx_runtime180.jsxs)(
|
|
13693
|
-
"div",
|
|
13694
|
-
{
|
|
13695
|
-
"data-slot": "sender",
|
|
13696
|
-
className: cn("flex items-center gap-2", align === "end" && "flex-row-reverse", className),
|
|
13697
|
-
style,
|
|
13698
|
-
children: [
|
|
13699
|
-
/* @__PURE__ */ (0, import_jsx_runtime180.jsx)(Avatar2, { src: avatar, fallback: avatarText ?? name?.slice(0, 1) ?? "?", className: "size-7" }),
|
|
13700
|
-
/* @__PURE__ */ (0, import_jsx_runtime180.jsxs)("div", { className: cn("flex min-w-0 items-baseline gap-1.5", align === "end" && "flex-row-reverse"), children: [
|
|
13701
|
-
name ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("span", { "data-slot": "sender-name", className: "truncate text-sm font-medium", children: name }) : null,
|
|
13702
|
-
role ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("span", { "data-slot": "sender-role", className: "shrink-0 text-xs text-muted-foreground", children: role }) : null,
|
|
13703
|
-
time ? /* @__PURE__ */ (0, import_jsx_runtime180.jsx)("span", { "data-slot": "sender-time", className: "shrink-0 text-xs text-muted-foreground", children: time }) : null
|
|
13704
|
-
] })
|
|
13705
|
-
]
|
|
13706
|
-
}
|
|
13707
|
-
);
|
|
13708
|
-
}
|
|
13709
|
-
|
|
13710
|
-
// src/components/chat/StreamingText/index.tsx
|
|
13711
|
-
var import_react63 = require("react");
|
|
13712
|
-
var import_jsx_runtime181 = require("react/jsx-runtime");
|
|
13713
|
-
function StreamingText({ content = "", streaming, typing, speed = 2, className, style }) {
|
|
13714
|
-
const [revealed, setRevealed] = (0, import_react63.useState)(typing ? 0 : content.length);
|
|
13715
|
-
(0, import_react63.useEffect)(() => {
|
|
13716
|
-
if (!typing) {
|
|
13717
|
-
setRevealed(content.length);
|
|
13718
|
-
return;
|
|
13719
|
-
}
|
|
13720
|
-
setRevealed(0);
|
|
13721
|
-
const timer = window.setInterval(() => {
|
|
13722
|
-
setRevealed((value) => {
|
|
13723
|
-
if (value >= content.length) {
|
|
13724
|
-
window.clearInterval(timer);
|
|
13725
|
-
return value;
|
|
13726
|
-
}
|
|
13727
|
-
return Math.min(content.length, value + speed);
|
|
13728
|
-
});
|
|
13729
|
-
}, 24);
|
|
13730
|
-
return () => window.clearInterval(timer);
|
|
13731
|
-
}, [content, typing, speed]);
|
|
13732
|
-
const typingDone = !typing || revealed >= content.length;
|
|
13733
|
-
const showCursor = streaming || typing && !typingDone;
|
|
13734
|
-
return /* @__PURE__ */ (0, import_jsx_runtime181.jsxs)("span", { "data-slot": "streaming-text", className: cn("whitespace-pre-wrap", className), style, children: [
|
|
13735
|
-
typing ? content.slice(0, revealed) : content,
|
|
13736
|
-
showCursor ? /* @__PURE__ */ (0, import_jsx_runtime181.jsx)(
|
|
13737
|
-
"span",
|
|
13738
|
-
{
|
|
13739
|
-
"data-slot": "streaming-text-cursor",
|
|
13740
|
-
"aria-hidden": "true",
|
|
13741
|
-
className: "ml-0.5 inline-block animate-pulse text-primary motion-reduce:animate-none",
|
|
13742
|
-
children: "\u258D"
|
|
13743
|
-
}
|
|
13744
|
-
) : null
|
|
13745
|
-
] });
|
|
13746
|
-
}
|
|
13747
|
-
|
|
13748
|
-
// src/components/chat/Thinking/index.tsx
|
|
13749
|
-
var import_react64 = require("react");
|
|
13750
|
-
var import_jsx_runtime182 = require("react/jsx-runtime");
|
|
13751
|
-
function Thinking({
|
|
13752
|
-
content,
|
|
13753
|
-
status = "thinking",
|
|
13754
|
-
title,
|
|
13755
|
-
expanded,
|
|
13756
|
-
defaultExpanded,
|
|
13757
|
-
onToggle,
|
|
13758
|
-
className,
|
|
13759
|
-
style
|
|
13760
|
-
}) {
|
|
13761
|
-
const [innerExpanded, setInnerExpanded] = (0, import_react64.useState)(defaultExpanded ?? status === "thinking");
|
|
13762
|
-
const isExpanded = expanded ?? innerExpanded;
|
|
13763
|
-
const resolvedTitle = title ?? (status === "thinking" ? "\u601D\u8003\u4E2D\u2026" : "\u601D\u8003\u5B8C\u6210");
|
|
13764
|
-
const toggle = () => {
|
|
13765
|
-
if (expanded === void 0) {
|
|
13766
|
-
setInnerExpanded(!isExpanded);
|
|
13767
|
-
}
|
|
13768
|
-
onToggle?.(!isExpanded);
|
|
13769
|
-
};
|
|
13770
|
-
return /* @__PURE__ */ (0, import_jsx_runtime182.jsxs)(
|
|
13771
|
-
"div",
|
|
13772
|
-
{
|
|
13773
|
-
"data-slot": "thinking",
|
|
13774
|
-
"data-status": status,
|
|
13775
|
-
className: cn("w-full", className),
|
|
13776
|
-
style,
|
|
13777
|
-
children: [
|
|
13778
|
-
/* @__PURE__ */ (0, import_jsx_runtime182.jsxs)(
|
|
13779
|
-
"button",
|
|
13780
|
-
{
|
|
13781
|
-
type: "button",
|
|
13782
|
-
"data-slot": "thinking-trigger",
|
|
13783
|
-
"aria-expanded": isExpanded,
|
|
13784
|
-
className: "flex w-full cursor-pointer items-center gap-2 py-1 text-left text-sm",
|
|
13785
|
-
onClick: toggle,
|
|
13786
|
-
children: [
|
|
13787
|
-
/* @__PURE__ */ (0, import_jsx_runtime182.jsx)("span", { className: cn("text-muted-foreground", status === "thinking" && "animate-pulse motion-reduce:animate-none"), children: /* @__PURE__ */ (0, import_jsx_runtime182.jsx)(Icon, { name: "brain", size: "sm" }) }),
|
|
13788
|
-
/* @__PURE__ */ (0, import_jsx_runtime182.jsx)("span", { "data-slot": "thinking-title", className: "text-muted-foreground", children: resolvedTitle }),
|
|
13789
|
-
/* @__PURE__ */ (0, import_jsx_runtime182.jsx)("span", { className: "text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime182.jsx)(Icon, { name: isExpanded ? "chevron-down" : "chevron-right", size: "sm" }) })
|
|
13790
|
-
]
|
|
13791
|
-
}
|
|
13792
|
-
),
|
|
13793
|
-
isExpanded && content ? /* @__PURE__ */ (0, import_jsx_runtime182.jsx)(
|
|
13794
|
-
"div",
|
|
13795
|
-
{
|
|
13796
|
-
"data-slot": "thinking-content",
|
|
13797
|
-
className: "py-1 pl-6 text-sm whitespace-pre-wrap text-muted-foreground",
|
|
13798
|
-
children: content
|
|
13799
|
-
}
|
|
13800
|
-
) : null
|
|
13801
|
-
]
|
|
13802
|
-
}
|
|
13803
|
-
);
|
|
13804
|
-
}
|
|
13805
|
-
|
|
13806
|
-
// src/components/chat/ToolCall/index.tsx
|
|
13807
|
-
var import_react65 = require("react");
|
|
13808
|
-
var import_jsx_runtime183 = require("react/jsx-runtime");
|
|
13809
|
-
var statusIcon3 = {
|
|
13810
|
-
running: { icon: "loader-circle", className: "text-info", spin: true },
|
|
13811
|
-
done: { icon: "circle-check", className: "text-success" },
|
|
13812
|
-
error: { icon: "circle-x", className: "text-destructive" }
|
|
13813
|
-
};
|
|
13814
|
-
function renderValue(value) {
|
|
13815
|
-
if (value === void 0 || value === null) return "";
|
|
13816
|
-
if (typeof value === "string") return value;
|
|
13817
|
-
try {
|
|
13818
|
-
return JSON.stringify(value, null, 2);
|
|
13819
|
-
} catch {
|
|
13820
|
-
return String(value);
|
|
13821
|
-
}
|
|
13822
|
-
}
|
|
13823
|
-
function ToolCall({ name, params, status = "done", result, durationMs, defaultExpanded, className, style }) {
|
|
13824
|
-
const [expanded, setExpanded] = (0, import_react65.useState)(defaultExpanded ?? status === "running");
|
|
13825
|
-
const meta = statusIcon3[status];
|
|
13826
|
-
const paramsText = renderValue(params);
|
|
13827
|
-
const hasDetail = Boolean(paramsText) || Boolean(result);
|
|
13828
|
-
const headerInner = /* @__PURE__ */ (0, import_jsx_runtime183.jsxs)(import_jsx_runtime183.Fragment, { children: [
|
|
13829
|
-
/* @__PURE__ */ (0, import_jsx_runtime183.jsx)("span", { className: "shrink-0 text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime183.jsx)(Icon, { name: "terminal", size: "sm" }) }),
|
|
13830
|
-
/* @__PURE__ */ (0, import_jsx_runtime183.jsx)("span", { "data-slot": "tool-call-name", className: "min-w-0 truncate font-medium", children: name ?? "\u5DE5\u5177\u8C03\u7528" }),
|
|
13831
|
-
/* @__PURE__ */ (0, import_jsx_runtime183.jsx)("span", { className: cn("shrink-0", meta.className, meta.spin && "animate-spin motion-reduce:animate-none"), children: /* @__PURE__ */ (0, import_jsx_runtime183.jsx)(Icon, { name: meta.icon, size: "sm" }) }),
|
|
13832
|
-
durationMs !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime183.jsxs)("span", { className: "shrink-0 text-xs text-muted-foreground", children: [
|
|
13833
|
-
(durationMs / 1e3).toFixed(1),
|
|
13834
|
-
"s"
|
|
13835
|
-
] }) : null,
|
|
13836
|
-
hasDetail ? /* @__PURE__ */ (0, import_jsx_runtime183.jsx)("span", { className: "shrink-0 text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime183.jsx)(Icon, { name: expanded ? "chevron-down" : "chevron-right", size: "sm" }) }) : null
|
|
13837
|
-
] });
|
|
13838
|
-
return /* @__PURE__ */ (0, import_jsx_runtime183.jsxs)(
|
|
13839
|
-
"div",
|
|
13840
|
-
{
|
|
13841
|
-
"data-slot": "tool-call",
|
|
13842
|
-
"data-status": status,
|
|
13843
|
-
className: cn("w-full", className),
|
|
13844
|
-
style,
|
|
13845
|
-
children: [
|
|
13846
|
-
hasDetail ? /* @__PURE__ */ (0, import_jsx_runtime183.jsx)(
|
|
13847
|
-
"button",
|
|
13848
|
-
{
|
|
13849
|
-
type: "button",
|
|
13850
|
-
"data-slot": "tool-call-trigger",
|
|
13851
|
-
"aria-expanded": expanded,
|
|
13852
|
-
className: "flex w-full cursor-pointer items-center gap-2 py-1 text-left text-sm",
|
|
13853
|
-
onClick: () => setExpanded((value) => !value),
|
|
13854
|
-
children: headerInner
|
|
13855
|
-
}
|
|
13856
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime183.jsx)(
|
|
13857
|
-
"div",
|
|
13858
|
-
{
|
|
13859
|
-
"data-slot": "tool-call-trigger",
|
|
13860
|
-
className: "flex w-full items-center gap-2 py-1 text-left text-sm",
|
|
13861
|
-
children: headerInner
|
|
13862
|
-
}
|
|
13863
|
-
),
|
|
13864
|
-
hasDetail && expanded ? /* @__PURE__ */ (0, import_jsx_runtime183.jsxs)("div", { "data-slot": "tool-call-body", className: "flex flex-col gap-2 py-1 pl-6", children: [
|
|
13865
|
-
paramsText ? /* @__PURE__ */ (0, import_jsx_runtime183.jsxs)("div", { children: [
|
|
13866
|
-
/* @__PURE__ */ (0, import_jsx_runtime183.jsx)("div", { className: "text-xs font-medium text-muted-foreground", children: "\u53C2\u6570" }),
|
|
13867
|
-
/* @__PURE__ */ (0, import_jsx_runtime183.jsx)("pre", { "data-slot": "tool-call-params", className: "mt-1 overflow-x-auto text-xs whitespace-pre-wrap text-muted-foreground", children: paramsText })
|
|
13868
|
-
] }) : null,
|
|
13869
|
-
result ? /* @__PURE__ */ (0, import_jsx_runtime183.jsxs)("div", { children: [
|
|
13870
|
-
/* @__PURE__ */ (0, import_jsx_runtime183.jsx)("div", { className: "text-xs font-medium text-muted-foreground", children: "\u7ED3\u679C" }),
|
|
13871
|
-
/* @__PURE__ */ (0, import_jsx_runtime183.jsx)("pre", { "data-slot": "tool-call-result", className: "mt-1 overflow-x-auto text-xs whitespace-pre-wrap text-muted-foreground", children: result })
|
|
13872
|
-
] }) : null
|
|
13873
|
-
] }) : null
|
|
13874
|
-
]
|
|
13875
|
-
}
|
|
13876
|
-
);
|
|
13877
|
-
}
|
|
13878
|
-
|
|
13879
|
-
// src/components/chat/ChatMessage/index.tsx
|
|
13880
|
-
var import_jsx_runtime184 = require("react/jsx-runtime");
|
|
13881
|
-
function PartView({
|
|
13882
|
-
part,
|
|
13883
|
-
role,
|
|
13884
|
-
onOpenArtifacts
|
|
13885
|
-
}) {
|
|
13886
|
-
if (role === "system" && (part.type === "text" || part.type === "markdown")) {
|
|
13887
|
-
return /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
|
|
13888
|
-
"div",
|
|
13889
|
-
{
|
|
13890
|
-
"data-slot": "chat-message-system-part",
|
|
13891
|
-
className: "w-full text-center text-xs text-muted-foreground",
|
|
13892
|
-
children: part.type === "markdown" ? /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(import_markdown2.MarkdownDslComponent, { content: part.content }) : part.content
|
|
13893
|
-
}
|
|
13894
|
-
);
|
|
13895
|
-
}
|
|
13896
|
-
switch (part.type) {
|
|
13897
|
-
case "text":
|
|
13898
|
-
return /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Bubble2, { align: role === "user" ? "end" : "start", variant: role === "user" ? "default" : "muted", children: /* @__PURE__ */ (0, import_jsx_runtime184.jsx)("span", { className: "text-sm whitespace-pre-wrap", children: part.content }) });
|
|
13899
|
-
case "markdown":
|
|
13900
|
-
return /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Bubble2, { align: role === "user" ? "end" : "start", variant: role === "user" ? "default" : "ghost", children: /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(import_markdown2.MarkdownDslComponent, { content: part.content }) });
|
|
13901
|
-
case "thinking":
|
|
13902
|
-
return /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Thinking, { content: part.content, status: part.status ?? "done" });
|
|
13903
|
-
case "tool-call":
|
|
13904
|
-
return /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(ToolCall, { name: part.name, params: part.params, status: part.status ?? "done", result: part.result });
|
|
13905
|
-
case "tool-result":
|
|
13906
|
-
return /* @__PURE__ */ (0, import_jsx_runtime184.jsx)("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 });
|
|
13907
|
-
case "status":
|
|
13908
|
-
return /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)("div", { "data-slot": "chat-message-status", className: "flex w-fit items-center gap-1.5 text-muted-foreground", children: [
|
|
13909
|
-
/* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Icon, { name: "clock", size: "sm" }),
|
|
13910
|
-
part.text
|
|
13911
|
-
] });
|
|
13912
|
-
case "artifacts": {
|
|
13913
|
-
const artifactsClass = "flex w-fit items-center gap-1.5 text-muted-foreground";
|
|
13914
|
-
const label = `\u5DF2\u751F\u6210 ${part.count} \u4E2A\u4EA7\u7269`;
|
|
13915
|
-
return onOpenArtifacts ? /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)(
|
|
13916
|
-
"button",
|
|
13917
|
-
{
|
|
13918
|
-
type: "button",
|
|
13919
|
-
"data-slot": "chat-message-artifacts",
|
|
13920
|
-
className: cn(artifactsClass, "cursor-pointer hover:text-foreground"),
|
|
13921
|
-
onClick: onOpenArtifacts,
|
|
13922
|
-
children: [
|
|
13923
|
-
/* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Icon, { name: "package", size: "sm" }),
|
|
13924
|
-
label,
|
|
13925
|
-
/* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Icon, { name: "chevron-right", size: 12 })
|
|
13926
|
-
]
|
|
13927
|
-
}
|
|
13928
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)("div", { "data-slot": "chat-message-artifacts", className: artifactsClass, children: [
|
|
13929
|
-
/* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Icon, { name: "package", size: "sm" }),
|
|
13930
|
-
label
|
|
13931
|
-
] });
|
|
13932
|
-
}
|
|
13933
|
-
case "error":
|
|
13934
|
-
return /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)("div", { "data-slot": "chat-message-error", className: "flex items-center gap-1.5 text-sm text-destructive", children: [
|
|
13935
|
-
/* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Icon, { name: "circle-alert", size: "sm" }),
|
|
13936
|
-
part.message
|
|
13937
|
-
] });
|
|
13938
|
-
default:
|
|
13939
|
-
return null;
|
|
13940
|
-
}
|
|
13941
|
-
}
|
|
13942
|
-
var ACTION_ICON_BY_NAME = {
|
|
13943
|
-
copy: "copy",
|
|
13944
|
-
retry: "rotate-ccw",
|
|
13945
|
-
regenerate: "refresh-ccw",
|
|
13946
|
-
edit: "pencil",
|
|
13947
|
-
like: "thumbs-up",
|
|
13948
|
-
dislike: "thumbs-down",
|
|
13949
|
-
share: "share",
|
|
13950
|
-
delete: "trash"
|
|
13951
|
-
};
|
|
13952
|
-
function ChatMessage({
|
|
13953
|
-
role = "assistant",
|
|
13954
|
-
parts = [],
|
|
13955
|
-
status = "completed",
|
|
13956
|
-
agent,
|
|
13957
|
-
time,
|
|
13958
|
-
showSender = false,
|
|
13959
|
-
actions = [],
|
|
13960
|
-
onAction,
|
|
13961
|
-
onOpenArtifacts,
|
|
13962
|
-
className,
|
|
13963
|
-
style
|
|
13964
|
-
}) {
|
|
13965
|
-
const isUser = role === "user";
|
|
13966
|
-
const isSystem = role === "system";
|
|
13967
|
-
const senderName = isUser ? "\u6211" : agent?.name ?? "\u52A9\u624B";
|
|
13968
|
-
return /* @__PURE__ */ (0, import_jsx_runtime184.jsxs)(
|
|
13969
|
-
"div",
|
|
13970
|
-
{
|
|
13971
|
-
"data-slot": "chat-message",
|
|
13972
|
-
"data-role": role,
|
|
13973
|
-
"data-status": status,
|
|
13974
|
-
className: cn(
|
|
13975
|
-
"flex w-full flex-col gap-1.5",
|
|
13976
|
-
isUser && "items-end",
|
|
13977
|
-
// system 居中弱提示(参考 @pactor-app/chat MessageBubble)
|
|
13978
|
-
isSystem && "items-center text-muted-foreground",
|
|
13979
|
-
className
|
|
13980
|
-
),
|
|
13981
|
-
style,
|
|
13982
|
-
children: [
|
|
13983
|
-
showSender ? /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
|
|
13984
|
-
Sender,
|
|
13985
|
-
{
|
|
13986
|
-
name: senderName,
|
|
13987
|
-
avatarText: isUser ? void 0 : agent?.icon ? void 0 : senderName.slice(0, 1),
|
|
13988
|
-
time,
|
|
13989
|
-
align: isUser ? "end" : "start"
|
|
13990
|
-
}
|
|
13991
|
-
) : null,
|
|
13992
|
-
/* @__PURE__ */ (0, import_jsx_runtime184.jsxs)("div", { className: cn("flex min-w-0 w-full max-w-full flex-col gap-2", isUser && "items-end", isSystem && "items-center"), children: [
|
|
13993
|
-
parts.map((part, index) => /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(PartView, { part, role, onOpenArtifacts }, index)),
|
|
13994
|
-
status === "streaming" ? /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(StreamingText, { content: "", streaming: true }) : null
|
|
13995
|
-
] }),
|
|
13996
|
-
actions.length > 0 && (status === "completed" || status === "error") ? /* @__PURE__ */ (0, import_jsx_runtime184.jsx)("div", { "data-slot": "chat-message-actions", className: "flex items-center gap-1 mt-2", children: actions.map((action) => {
|
|
13997
|
-
const label = action.label ?? action.name;
|
|
13998
|
-
const iconName = action.icon ?? ACTION_ICON_BY_NAME[action.name];
|
|
13999
|
-
if (iconName) {
|
|
14000
|
-
return /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Tooltip2, { content: label, side: "top", children: /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
|
|
14001
|
-
"button",
|
|
14002
|
-
{
|
|
14003
|
-
type: "button",
|
|
14004
|
-
"data-slot": "chat-message-action",
|
|
14005
|
-
"data-action": action.name,
|
|
14006
|
-
"aria-label": label,
|
|
14007
|
-
className: "flex cursor-pointer items-center rounded-sm p-1 text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
14008
|
-
onClick: () => onAction?.(action.name),
|
|
14009
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(Icon, { name: iconName, size: "sm" })
|
|
14010
|
-
}
|
|
14011
|
-
) }, action.name);
|
|
14012
|
-
}
|
|
14013
|
-
return /* @__PURE__ */ (0, import_jsx_runtime184.jsx)(
|
|
14014
|
-
"button",
|
|
14015
|
-
{
|
|
14016
|
-
type: "button",
|
|
14017
|
-
"data-slot": "chat-message-action",
|
|
14018
|
-
"data-action": action.name,
|
|
14019
|
-
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",
|
|
14020
|
-
onClick: () => onAction?.(action.name),
|
|
14021
|
-
children: label
|
|
14022
|
-
},
|
|
14023
|
-
action.name
|
|
14024
|
-
);
|
|
14025
|
-
}) }) : null
|
|
14026
|
-
]
|
|
14027
|
-
}
|
|
14028
|
-
);
|
|
14029
|
-
}
|
|
14030
|
-
|
|
14031
|
-
// src/components/chat/ChatPage/index.tsx
|
|
14032
|
-
var import_runtime51 = require("@pactor-app/runtime");
|
|
14033
|
-
var import_react70 = require("react");
|
|
14034
|
-
|
|
14035
|
-
// src/components/chat/Composer/index.tsx
|
|
14036
|
-
var import_react67 = require("react");
|
|
14037
|
-
|
|
14038
|
-
// src/components/chat/Composer/mention-input.tsx
|
|
14039
|
-
var import_react66 = require("react");
|
|
14040
|
-
var import_server = require("react-dom/server");
|
|
14041
|
-
var import_jsx_runtime185 = require("react/jsx-runtime");
|
|
14042
|
-
var NBSP = "\xA0";
|
|
14043
|
-
var CHIP_ATTR = "data-mention-chip";
|
|
14044
|
-
function escapeRegExp(text) {
|
|
14045
|
-
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14046
|
-
}
|
|
14047
|
-
function isChipElement(node) {
|
|
14048
|
-
return node instanceof HTMLElement && node.hasAttribute(CHIP_ATTR);
|
|
14049
|
-
}
|
|
14050
|
-
function serializeNode(node) {
|
|
14051
|
-
let out = "";
|
|
14052
|
-
node.childNodes.forEach((child) => {
|
|
14053
|
-
if (child.nodeType === Node.TEXT_NODE) {
|
|
14054
|
-
out += (child.textContent ?? "").replace(/\u00A0/g, " ");
|
|
14055
|
-
} else if (isChipElement(child)) {
|
|
14056
|
-
out += `${child.dataset["trigger"] ?? ""}${child.dataset["label"] ?? ""}`;
|
|
14057
|
-
} else if (child instanceof HTMLBRElement) {
|
|
14058
|
-
out += "\n";
|
|
14059
|
-
} else if (child instanceof HTMLElement) {
|
|
14060
|
-
const inner = serializeNode(child).replace(/\n$/, "");
|
|
14061
|
-
out += (out === "" || out.endsWith("\n") ? "" : "\n") + inner + "\n";
|
|
14062
|
-
}
|
|
14063
|
-
});
|
|
14064
|
-
return out;
|
|
14065
|
-
}
|
|
14066
|
-
function collectChips(field) {
|
|
14067
|
-
return Array.from(field.querySelectorAll(`[${CHIP_ATTR}]`)).map((el) => ({
|
|
14068
|
-
id: el.dataset["id"] ?? "",
|
|
14069
|
-
label: el.dataset["label"] ?? "",
|
|
14070
|
-
trigger: el.dataset["trigger"] ?? ""
|
|
14071
|
-
}));
|
|
14072
|
-
}
|
|
14073
|
-
function detectActiveMention(field, sources) {
|
|
14074
|
-
const selection = window.getSelection();
|
|
14075
|
-
if (!selection || selection.rangeCount === 0 || !selection.isCollapsed) {
|
|
14076
|
-
return null;
|
|
14077
|
-
}
|
|
14078
|
-
const anchor = selection.anchorNode;
|
|
14079
|
-
if (!anchor || anchor.nodeType !== Node.TEXT_NODE || !field.contains(anchor)) {
|
|
14080
|
-
return null;
|
|
14081
|
-
}
|
|
14082
|
-
const caretOffset = selection.anchorOffset;
|
|
14083
|
-
const beforeCaret = (anchor.textContent ?? "").slice(0, caretOffset);
|
|
14084
|
-
for (const source of sources) {
|
|
14085
|
-
const trigger = source.trigger;
|
|
14086
|
-
const match = new RegExp(
|
|
14087
|
-
`(?:^|\\s)${escapeRegExp(trigger)}([^\\s${escapeRegExp(trigger)}]*)$`
|
|
14088
|
-
).exec(beforeCaret);
|
|
14089
|
-
if (match) {
|
|
14090
|
-
const query = match[1] ?? "";
|
|
14091
|
-
return {
|
|
14092
|
-
source,
|
|
14093
|
-
query,
|
|
14094
|
-
node: anchor,
|
|
14095
|
-
triggerStart: caretOffset - query.length - trigger.length,
|
|
14096
|
-
caretOffset
|
|
14097
|
-
};
|
|
14098
|
-
}
|
|
14099
|
-
}
|
|
14100
|
-
return null;
|
|
14101
|
-
}
|
|
14102
|
-
function chipIcon(item, source) {
|
|
14103
|
-
return item.icon ?? source.icon ?? (source.trigger === "@" ? "user" : "file-text");
|
|
14104
|
-
}
|
|
14105
|
-
var MentionInput = (0, import_react66.forwardRef)(
|
|
14106
|
-
function MentionInput2({
|
|
14107
|
-
value,
|
|
14108
|
-
placeholder,
|
|
14109
|
-
disabled,
|
|
14110
|
-
sources,
|
|
14111
|
-
chips,
|
|
14112
|
-
onChipsChange,
|
|
14113
|
-
onChange,
|
|
14114
|
-
onSubmit,
|
|
14115
|
-
className,
|
|
14116
|
-
style
|
|
14117
|
-
}, ref) {
|
|
14118
|
-
const fieldRef = (0, import_react66.useRef)(null);
|
|
14119
|
-
const [menu, setMenu] = (0, import_react66.useState)(null);
|
|
14120
|
-
const [empty, setEmpty] = (0, import_react66.useState)(true);
|
|
14121
|
-
const suppressSyncRef = (0, import_react66.useRef)(false);
|
|
14122
|
-
const composingRef = (0, import_react66.useRef)(false);
|
|
14123
|
-
const emitChips = () => {
|
|
14124
|
-
if (suppressSyncRef.current || !fieldRef.current) {
|
|
14125
|
-
return;
|
|
14126
|
-
}
|
|
14127
|
-
onChipsChange?.(collectChips(fieldRef.current));
|
|
14128
|
-
};
|
|
14129
|
-
const serialize = () => fieldRef.current ? serializeNode(fieldRef.current).replace(/\n$/, "") : "";
|
|
14130
|
-
const buildChipElement = (item, source) => {
|
|
14131
|
-
const chip = document.createElement("span");
|
|
14132
|
-
chip.setAttribute(CHIP_ATTR, "");
|
|
14133
|
-
chip.dataset["id"] = item.id;
|
|
14134
|
-
chip.dataset["label"] = item.label;
|
|
14135
|
-
chip.dataset["trigger"] = item.trigger ?? source.trigger;
|
|
14136
|
-
chip.contentEditable = "false";
|
|
14137
|
-
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";
|
|
14138
|
-
const iconMarkup = (0, import_server.renderToStaticMarkup)(
|
|
14139
|
-
/* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Icon, { name: chipIcon(item, source), size: 12 })
|
|
14140
|
-
);
|
|
14141
|
-
const label = document.createElement("span");
|
|
14142
|
-
label.textContent = item.label;
|
|
14143
|
-
chip.innerHTML = iconMarkup;
|
|
14144
|
-
chip.appendChild(label);
|
|
14145
|
-
return chip;
|
|
14146
|
-
};
|
|
14147
|
-
const insertChipElement = (item, source, replace) => {
|
|
14148
|
-
const field = fieldRef.current;
|
|
14149
|
-
if (!field) {
|
|
14150
|
-
return;
|
|
14151
|
-
}
|
|
14152
|
-
const chip = buildChipElement(item, source);
|
|
14153
|
-
let caretNode;
|
|
14154
|
-
if (replace) {
|
|
14155
|
-
const { node, start, end } = replace;
|
|
14156
|
-
const text = node.textContent ?? "";
|
|
14157
|
-
node.textContent = text.slice(0, start);
|
|
14158
|
-
caretNode = document.createTextNode(`${NBSP}${text.slice(end)}`);
|
|
14159
|
-
node.after(chip, caretNode);
|
|
14160
|
-
} else {
|
|
14161
|
-
caretNode = document.createTextNode(NBSP);
|
|
14162
|
-
const selection2 = window.getSelection();
|
|
14163
|
-
if (selection2 && selection2.rangeCount > 0 && selection2.anchorNode !== null && field.contains(selection2.anchorNode)) {
|
|
14164
|
-
const range = selection2.getRangeAt(0);
|
|
14165
|
-
range.deleteContents();
|
|
14166
|
-
range.insertNode(caretNode);
|
|
14167
|
-
range.insertNode(chip);
|
|
14168
|
-
} else {
|
|
14169
|
-
field.append(chip, caretNode);
|
|
14170
|
-
}
|
|
14171
|
-
}
|
|
14172
|
-
const selection = window.getSelection();
|
|
14173
|
-
if (selection) {
|
|
14174
|
-
const range = document.createRange();
|
|
14175
|
-
range.setStart(caretNode, 1);
|
|
14176
|
-
range.collapse(true);
|
|
14177
|
-
selection.removeAllRanges();
|
|
14178
|
-
selection.addRange(range);
|
|
14179
|
-
}
|
|
14180
|
-
setEmpty(false);
|
|
14181
|
-
onChange?.(serialize());
|
|
14182
|
-
emitChips();
|
|
14183
|
-
};
|
|
14184
|
-
(0, import_react66.useImperativeHandle)(ref, () => ({
|
|
14185
|
-
insertChip: (item, source) => {
|
|
14186
|
-
fieldRef.current?.focus();
|
|
14187
|
-
insertChipElement(item, source);
|
|
14188
|
-
},
|
|
14189
|
-
focus: () => fieldRef.current?.focus()
|
|
14190
|
-
}));
|
|
14191
|
-
(0, import_react66.useEffect)(() => {
|
|
14192
|
-
const field = fieldRef.current;
|
|
14193
|
-
if (field && value === "" && serializeNode(field).trim() !== "") {
|
|
14194
|
-
suppressSyncRef.current = true;
|
|
14195
|
-
field.innerHTML = "";
|
|
14196
|
-
setEmpty(true);
|
|
14197
|
-
setMenu(null);
|
|
14198
|
-
suppressSyncRef.current = false;
|
|
14199
|
-
}
|
|
14200
|
-
}, [value]);
|
|
14201
|
-
(0, import_react66.useEffect)(() => {
|
|
14202
|
-
const field = fieldRef.current;
|
|
14203
|
-
if (!field) {
|
|
14204
|
-
return;
|
|
14205
|
-
}
|
|
14206
|
-
const keep = new Set(chips.map((chip) => `${chip.trigger}:${chip.id}`));
|
|
14207
|
-
const stale = Array.from(field.querySelectorAll(`[${CHIP_ATTR}]`)).filter(
|
|
14208
|
-
(el) => !keep.has(
|
|
14209
|
-
`${el.dataset["trigger"]}:${el.dataset["id"]}`
|
|
14210
|
-
)
|
|
14211
|
-
);
|
|
14212
|
-
if (stale.length > 0) {
|
|
14213
|
-
suppressSyncRef.current = true;
|
|
14214
|
-
stale.forEach((el) => el.remove());
|
|
14215
|
-
suppressSyncRef.current = false;
|
|
14216
|
-
setEmpty(serializeNode(field).trim() === "");
|
|
14217
|
-
}
|
|
14218
|
-
}, [chips]);
|
|
14219
|
-
const closeMenu = () => setMenu(null);
|
|
14220
|
-
const filteredItems = (state) => state.query ? state.source.items.filter((item) => item.label.includes(state.query)) : state.source.items;
|
|
14221
|
-
const refreshMenu = () => {
|
|
14222
|
-
const field = fieldRef.current;
|
|
14223
|
-
if (!field) {
|
|
14224
|
-
return;
|
|
14225
|
-
}
|
|
14226
|
-
const active = detectActiveMention(field, sources);
|
|
14227
|
-
if (!active) {
|
|
14228
|
-
setMenu(null);
|
|
14229
|
-
return;
|
|
14230
|
-
}
|
|
14231
|
-
const range = document.createRange();
|
|
14232
|
-
range.setStart(active.node, active.triggerStart);
|
|
14233
|
-
range.setEnd(active.node, active.caretOffset);
|
|
14234
|
-
const rect = typeof range.getBoundingClientRect === "function" ? range.getBoundingClientRect() : field.getBoundingClientRect();
|
|
14235
|
-
setMenu((prev) => ({
|
|
14236
|
-
source: active.source,
|
|
14237
|
-
query: active.query,
|
|
14238
|
-
left: rect.left,
|
|
14239
|
-
top: rect.top,
|
|
14240
|
-
// 过滤结果变化后候选下标钳制在有效范围内(DSL 每次渲染产出新
|
|
14241
|
-
// props 对象,source 按 trigger 比较而非引用)
|
|
14242
|
-
activeIndex: Math.min(
|
|
14243
|
-
prev?.source.trigger === active.source.trigger ? prev.activeIndex : 0,
|
|
14244
|
-
Math.max(filteredItems({ source: active.source, query: active.query, left: 0, top: 0, activeIndex: 0 }).length - 1, 0)
|
|
14245
|
-
)
|
|
14246
|
-
}));
|
|
14247
|
-
};
|
|
14248
|
-
const selectMenuItem = (item) => {
|
|
14249
|
-
const field = fieldRef.current;
|
|
14250
|
-
if (!field || !menu) {
|
|
14251
|
-
return;
|
|
14252
|
-
}
|
|
14253
|
-
const active = detectActiveMention(field, sources);
|
|
14254
|
-
insertChipElement(
|
|
14255
|
-
{ ...item, trigger: item.trigger ?? menu.source.trigger },
|
|
14256
|
-
menu.source,
|
|
14257
|
-
active && active.source.trigger === menu.source.trigger ? { node: active.node, start: active.triggerStart, end: active.caretOffset } : void 0
|
|
14258
|
-
);
|
|
14259
|
-
setMenu(null);
|
|
14260
|
-
};
|
|
14261
|
-
const handleInput = () => {
|
|
14262
|
-
const field = fieldRef.current;
|
|
14263
|
-
if (!field) {
|
|
14264
|
-
return;
|
|
14265
|
-
}
|
|
14266
|
-
if ((field.textContent ?? "") === "" && field.querySelector(`[${CHIP_ATTR}]`) === null) {
|
|
14267
|
-
field.innerHTML = "";
|
|
14268
|
-
}
|
|
14269
|
-
setEmpty(serializeNode(field).trim() === "");
|
|
14270
|
-
onChange?.(serialize());
|
|
14271
|
-
refreshMenu();
|
|
14272
|
-
};
|
|
14273
|
-
const handleKeyDown = (event) => {
|
|
14274
|
-
if (menu) {
|
|
14275
|
-
const items = filteredItems(menu);
|
|
14276
|
-
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
14277
|
-
event.preventDefault();
|
|
14278
|
-
if (items.length > 0) {
|
|
14279
|
-
const delta = event.key === "ArrowDown" ? 1 : -1;
|
|
14280
|
-
setMenu({
|
|
14281
|
-
...menu,
|
|
14282
|
-
activeIndex: (menu.activeIndex + delta + items.length) % items.length
|
|
14283
|
-
});
|
|
14284
|
-
}
|
|
14285
|
-
return;
|
|
14286
|
-
}
|
|
14287
|
-
if (event.key === "Enter" && !composingRef.current && !event.nativeEvent.isComposing) {
|
|
14288
|
-
event.preventDefault();
|
|
14289
|
-
const item = items[Math.min(menu.activeIndex, items.length - 1)];
|
|
14290
|
-
if (item) {
|
|
14291
|
-
selectMenuItem(item);
|
|
14292
|
-
} else {
|
|
14293
|
-
closeMenu();
|
|
14294
|
-
}
|
|
14295
|
-
return;
|
|
14296
|
-
}
|
|
14297
|
-
if (event.key === "Escape") {
|
|
14298
|
-
event.preventDefault();
|
|
14299
|
-
closeMenu();
|
|
14300
|
-
return;
|
|
14301
|
-
}
|
|
14302
|
-
}
|
|
14303
|
-
if (event.key === "Enter" && !event.shiftKey && !composingRef.current && !event.nativeEvent.isComposing) {
|
|
14304
|
-
event.preventDefault();
|
|
14305
|
-
const text = serialize();
|
|
14306
|
-
if (text.trim() !== "" && !disabled) {
|
|
14307
|
-
onSubmit?.(text);
|
|
14308
|
-
}
|
|
14309
|
-
return;
|
|
14310
|
-
}
|
|
14311
|
-
if (event.key === "Backspace") {
|
|
14312
|
-
const selection = window.getSelection();
|
|
14313
|
-
const field = fieldRef.current;
|
|
14314
|
-
if (!selection || !selection.isCollapsed || !field) {
|
|
14315
|
-
return;
|
|
14316
|
-
}
|
|
14317
|
-
let chip = null;
|
|
14318
|
-
const anchor = selection.anchorNode;
|
|
14319
|
-
if (anchor === field && selection.anchorOffset > 0) {
|
|
14320
|
-
const before = field.childNodes[selection.anchorOffset - 1];
|
|
14321
|
-
if (isChipElement(before)) {
|
|
14322
|
-
chip = before;
|
|
14323
|
-
}
|
|
14324
|
-
} else if (anchor?.nodeType === Node.TEXT_NODE && selection.anchorOffset === 0) {
|
|
14325
|
-
if (isChipElement(anchor.previousSibling)) {
|
|
14326
|
-
chip = anchor.previousSibling;
|
|
14327
|
-
}
|
|
14328
|
-
}
|
|
14329
|
-
if (chip) {
|
|
14330
|
-
event.preventDefault();
|
|
14331
|
-
chip.remove();
|
|
14332
|
-
onChange?.(serialize());
|
|
14333
|
-
emitChips();
|
|
14334
|
-
setEmpty(serializeNode(field).trim() === "");
|
|
14335
|
-
}
|
|
14336
|
-
}
|
|
14337
|
-
};
|
|
14338
|
-
const menuItems = menu ? filteredItems(menu) : [];
|
|
14339
|
-
const activeIndex = Math.min(menu?.activeIndex ?? 0, Math.max(menuItems.length - 1, 0));
|
|
14340
|
-
return /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)("div", { className: "relative", children: [
|
|
14341
|
-
/* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
|
|
14342
|
-
"div",
|
|
14343
|
-
{
|
|
14344
|
-
ref: fieldRef,
|
|
14345
|
-
"data-slot": "mention-input",
|
|
14346
|
-
role: "textbox",
|
|
14347
|
-
"aria-multiline": "true",
|
|
14348
|
-
"aria-placeholder": placeholder,
|
|
14349
|
-
contentEditable: !disabled,
|
|
14350
|
-
suppressContentEditableWarning: true,
|
|
14351
|
-
className: cn(
|
|
14352
|
-
"min-h-[60px] w-full px-4 pt-3 pb-1 text-sm whitespace-pre-wrap break-words outline-none",
|
|
14353
|
-
className
|
|
14354
|
-
),
|
|
14355
|
-
style,
|
|
14356
|
-
onInput: handleInput,
|
|
14357
|
-
onKeyDown: handleKeyDown,
|
|
14358
|
-
onCompositionStart: () => {
|
|
14359
|
-
composingRef.current = true;
|
|
14360
|
-
},
|
|
14361
|
-
onCompositionEnd: () => {
|
|
14362
|
-
composingRef.current = false;
|
|
14363
|
-
},
|
|
14364
|
-
onPaste: (event) => {
|
|
14365
|
-
event.preventDefault();
|
|
14366
|
-
const text = event.clipboardData?.getData("text/plain") ?? "";
|
|
14367
|
-
if (text) {
|
|
14368
|
-
document.execCommand("insertText", false, text);
|
|
14369
|
-
}
|
|
14370
|
-
}
|
|
14371
|
-
}
|
|
14372
|
-
),
|
|
14373
|
-
empty && placeholder !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime185.jsx)("span", { className: "pointer-events-none absolute top-3 left-4 text-sm text-muted-foreground", children: placeholder }) : null,
|
|
14374
|
-
menu ? /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(import_jsx_runtime185.Fragment, { children: [
|
|
14375
|
-
/* @__PURE__ */ (0, import_jsx_runtime185.jsx)(
|
|
14376
|
-
"div",
|
|
14377
|
-
{
|
|
14378
|
-
className: "fixed inset-0 z-40",
|
|
14379
|
-
onMouseDown: (event) => {
|
|
14380
|
-
event.preventDefault();
|
|
14381
|
-
closeMenu();
|
|
14382
|
-
}
|
|
14383
|
-
}
|
|
14384
|
-
),
|
|
14385
|
-
/* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(
|
|
14386
|
-
"div",
|
|
14387
|
-
{
|
|
14388
|
-
"data-slot": "mention-menu",
|
|
14389
|
-
role: "listbox",
|
|
14390
|
-
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",
|
|
14391
|
-
style: {
|
|
14392
|
-
left: menu.left,
|
|
14393
|
-
bottom: typeof window === "undefined" ? void 0 : window.innerHeight - menu.top + 6
|
|
14394
|
-
},
|
|
14395
|
-
children: [
|
|
14396
|
-
/* @__PURE__ */ (0, import_jsx_runtime185.jsx)("div", { className: "px-2 py-1 text-xs text-muted-foreground", children: menu.source.label }),
|
|
14397
|
-
menuItems.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime185.jsx)("div", { className: "px-2 py-2 text-xs text-muted-foreground", children: "\u65E0\u5339\u914D\u9879" }) : menuItems.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime185.jsxs)(
|
|
14398
|
-
"button",
|
|
14399
|
-
{
|
|
14400
|
-
type: "button",
|
|
14401
|
-
role: "option",
|
|
14402
|
-
"aria-selected": index === activeIndex,
|
|
14403
|
-
className: cn(
|
|
14404
|
-
"flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm",
|
|
14405
|
-
index === activeIndex ? "bg-accent" : "hover:bg-accent"
|
|
14406
|
-
),
|
|
14407
|
-
onMouseDown: (event) => {
|
|
14408
|
-
event.preventDefault();
|
|
14409
|
-
selectMenuItem(item);
|
|
14410
|
-
},
|
|
14411
|
-
children: [
|
|
14412
|
-
/* @__PURE__ */ (0, import_jsx_runtime185.jsx)(Icon, { name: chipIcon(item, menu.source), size: "sm" }),
|
|
14413
|
-
/* @__PURE__ */ (0, import_jsx_runtime185.jsx)("span", { className: "min-w-0 flex-1 truncate", children: item.label })
|
|
14414
|
-
]
|
|
14415
|
-
},
|
|
14416
|
-
item.id
|
|
14417
|
-
))
|
|
14418
|
-
]
|
|
14419
|
-
}
|
|
14420
|
-
)
|
|
14421
|
-
] }) : null
|
|
14422
|
-
] });
|
|
14423
|
-
}
|
|
14424
|
-
);
|
|
14425
|
-
|
|
14426
|
-
// src/components/chat/Composer/index.tsx
|
|
14427
|
-
var import_jsx_runtime186 = require("react/jsx-runtime");
|
|
14428
|
-
var toolButtonClass3 = "flex cursor-pointer items-center rounded-md p-1.5 text-muted-foreground hover:bg-accent hover:text-foreground";
|
|
14429
|
-
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";
|
|
14430
|
-
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";
|
|
14431
|
-
function Composer({
|
|
14432
|
-
value,
|
|
14433
|
-
placeholder,
|
|
14434
|
-
disabled,
|
|
14435
|
-
loading,
|
|
14436
|
-
rows,
|
|
14437
|
-
attachments = [],
|
|
14438
|
-
onRemoveAttachment,
|
|
14439
|
-
onRetryAttachment,
|
|
14440
|
-
onAttachFiles,
|
|
14441
|
-
onChange,
|
|
14442
|
-
onSubmit,
|
|
14443
|
-
models,
|
|
14444
|
-
model,
|
|
14445
|
-
onModelChange,
|
|
14446
|
-
contexts,
|
|
14447
|
-
contextItems,
|
|
14448
|
-
onContextItemsChange,
|
|
14449
|
-
footer,
|
|
14450
|
-
className,
|
|
14451
|
-
style
|
|
14452
|
-
}) {
|
|
14453
|
-
const textControlled = value !== void 0;
|
|
14454
|
-
const [innerText, setInnerText] = (0, import_react67.useState)("");
|
|
14455
|
-
const text = textControlled ? value : innerText;
|
|
14456
|
-
const [dragOver, setDragOver] = (0, import_react67.useState)(false);
|
|
14457
|
-
const [plusOpen, setPlusOpen] = (0, import_react67.useState)(false);
|
|
14458
|
-
const [modelOpen, setModelOpen] = (0, import_react67.useState)(false);
|
|
14459
|
-
const fileInputRef = (0, import_react67.useRef)(null);
|
|
14460
|
-
const mentionRef = (0, import_react67.useRef)(null);
|
|
14461
|
-
const sources = contexts ?? [];
|
|
14462
|
-
const rich = sources.length > 0;
|
|
14463
|
-
const plusSources = sources.filter((s) => s.trigger === "+");
|
|
14464
|
-
const plusEnabled = plusSources.length > 0;
|
|
14465
|
-
const modelEnabled = models !== void 0 && models.length > 0;
|
|
14466
|
-
const currentModel = models?.find((m) => m.value === model) ?? models?.[0];
|
|
14467
|
-
const [innerChips, setInnerChips] = (0, import_react67.useState)([]);
|
|
14468
|
-
const chipsControlled = contextItems !== void 0;
|
|
14469
|
-
const chips = chipsControlled ? contextItems : innerChips;
|
|
14470
|
-
const handleChipsChange = (next) => {
|
|
14471
|
-
if (!chipsControlled) {
|
|
14472
|
-
setInnerChips(next);
|
|
14473
|
-
}
|
|
14474
|
-
onContextItemsChange?.(next);
|
|
14475
|
-
};
|
|
14476
|
-
const closePopovers = () => {
|
|
14477
|
-
setPlusOpen(false);
|
|
14478
|
-
setModelOpen(false);
|
|
14479
|
-
};
|
|
14480
|
-
const handleChange = (next) => {
|
|
14481
|
-
if (!textControlled) {
|
|
14482
|
-
setInnerText(next);
|
|
14483
|
-
}
|
|
14484
|
-
onChange?.(next);
|
|
14485
|
-
};
|
|
14486
|
-
const handleSubmit = (submitted) => {
|
|
14487
|
-
onSubmit?.(submitted);
|
|
14488
|
-
if (!textControlled) {
|
|
14489
|
-
setInnerText("");
|
|
14490
|
-
}
|
|
14491
|
-
closePopovers();
|
|
14492
|
-
};
|
|
14493
|
-
const selectContext = (item, source) => {
|
|
14494
|
-
if (rich) {
|
|
14495
|
-
mentionRef.current?.insertChip(item, source);
|
|
14496
|
-
} else {
|
|
14497
|
-
const chip = { ...item, trigger: item.trigger ?? source.trigger };
|
|
14498
|
-
const duplicated = chips.some(
|
|
14499
|
-
(existing) => existing.id === chip.id && existing.trigger === chip.trigger
|
|
14500
|
-
);
|
|
14501
|
-
if (!duplicated) {
|
|
14502
|
-
handleChipsChange([...chips, chip]);
|
|
14503
|
-
}
|
|
14504
|
-
}
|
|
14505
|
-
closePopovers();
|
|
14506
|
-
};
|
|
14507
|
-
const emitFiles = (files) => {
|
|
14508
|
-
if (files.length > 0 && onAttachFiles) {
|
|
14509
|
-
onAttachFiles(files);
|
|
14510
|
-
}
|
|
14511
|
-
};
|
|
14512
|
-
const handleDrop = (event) => {
|
|
14513
|
-
if (!onAttachFiles) {
|
|
14514
|
-
return;
|
|
14515
|
-
}
|
|
14516
|
-
event.preventDefault();
|
|
14517
|
-
setDragOver(false);
|
|
14518
|
-
emitFiles(Array.from(event.dataTransfer?.files ?? []));
|
|
14519
|
-
};
|
|
14520
|
-
const toolbarStart = plusEnabled || onAttachFiles ? /* @__PURE__ */ (0, import_jsx_runtime186.jsxs)(import_jsx_runtime186.Fragment, { children: [
|
|
14521
|
-
plusEnabled ? /* @__PURE__ */ (0, import_jsx_runtime186.jsx)(
|
|
14522
|
-
"button",
|
|
14523
|
-
{
|
|
14524
|
-
type: "button",
|
|
14525
|
-
"aria-label": "\u6DFB\u52A0\u4E0A\u4E0B\u6587",
|
|
14526
|
-
title: "\u6DFB\u52A0\u4E0A\u4E0B\u6587",
|
|
14527
|
-
className: toolButtonClass3,
|
|
14528
|
-
onClick: () => {
|
|
14529
|
-
setPlusOpen((prev) => !prev);
|
|
14530
|
-
setModelOpen(false);
|
|
14531
|
-
},
|
|
14532
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime186.jsx)(Icon, { name: "plus", size: "sm" })
|
|
14533
|
-
}
|
|
14534
|
-
) : null,
|
|
14535
|
-
onAttachFiles ? /* @__PURE__ */ (0, import_jsx_runtime186.jsx)(
|
|
14536
|
-
"button",
|
|
14537
|
-
{
|
|
14538
|
-
type: "button",
|
|
14539
|
-
"aria-label": "\u6DFB\u52A0\u9644\u4EF6",
|
|
14540
|
-
title: "\u6DFB\u52A0\u9644\u4EF6",
|
|
14541
|
-
className: toolButtonClass3,
|
|
14542
|
-
onClick: () => fileInputRef.current?.click(),
|
|
14543
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime186.jsx)(Icon, { name: "paperclip", size: "sm" })
|
|
14544
|
-
}
|
|
14545
|
-
) : null
|
|
14546
|
-
] }) : void 0;
|
|
14547
|
-
const toolbarEnd = modelEnabled ? /* @__PURE__ */ (0, import_jsx_runtime186.jsxs)(
|
|
14548
|
-
"button",
|
|
14549
|
-
{
|
|
14550
|
-
type: "button",
|
|
14551
|
-
"aria-label": "\u9009\u62E9\u6A21\u578B",
|
|
14552
|
-
title: "\u9009\u62E9\u6A21\u578B",
|
|
14553
|
-
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",
|
|
14554
|
-
onClick: () => {
|
|
14555
|
-
setModelOpen((prev) => !prev);
|
|
14556
|
-
setPlusOpen(false);
|
|
14557
|
-
},
|
|
14558
|
-
children: [
|
|
14559
|
-
currentModel?.label,
|
|
14560
|
-
/* @__PURE__ */ (0, import_jsx_runtime186.jsx)(Icon, { name: "chevrons-up-down", size: 12 })
|
|
14561
|
-
]
|
|
14562
|
-
}
|
|
14563
|
-
) : void 0;
|
|
14564
|
-
const activePopover = plusOpen ? "plus" : modelOpen ? "model" : null;
|
|
14565
|
-
return /* @__PURE__ */ (0, import_jsx_runtime186.jsxs)(
|
|
14566
|
-
"div",
|
|
14567
|
-
{
|
|
14568
|
-
"data-slot": "composer",
|
|
14569
|
-
className: cn("relative flex w-full flex-col gap-2", className),
|
|
14570
|
-
style,
|
|
14571
|
-
onDragOver: (event) => {
|
|
14572
|
-
if (onAttachFiles) {
|
|
14573
|
-
event.preventDefault();
|
|
14574
|
-
setDragOver(true);
|
|
14575
|
-
}
|
|
14576
|
-
},
|
|
14577
|
-
onDragLeave: () => setDragOver(false),
|
|
14578
|
-
onDrop: handleDrop,
|
|
14579
|
-
onPaste: (event) => {
|
|
14580
|
-
const files = Array.from(event.clipboardData?.files ?? []);
|
|
14581
|
-
if (files.length > 0 && onAttachFiles) {
|
|
14582
|
-
event.preventDefault();
|
|
14583
|
-
emitFiles(files);
|
|
14584
|
-
}
|
|
14585
|
-
},
|
|
14586
|
-
children: [
|
|
14587
|
-
attachments.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime186.jsx)(Attachment, { items: attachments, onRemove: onRemoveAttachment, onRetry: onRetryAttachment }) : null,
|
|
14588
|
-
/* @__PURE__ */ (0, import_jsx_runtime186.jsx)("div", { className: cn(dragOver && "rounded-xl ring-2 ring-ring/50"), children: /* @__PURE__ */ (0, import_jsx_runtime186.jsx)(
|
|
14589
|
-
ChatInput,
|
|
14590
|
-
{
|
|
14591
|
-
value: text,
|
|
14592
|
-
placeholder,
|
|
14593
|
-
disabled: disabled || loading,
|
|
14594
|
-
rows,
|
|
14595
|
-
toolbarStart,
|
|
14596
|
-
toolbarEnd,
|
|
14597
|
-
footer,
|
|
14598
|
-
field: rich ? /* @__PURE__ */ (0, import_jsx_runtime186.jsx)(
|
|
14599
|
-
MentionInput,
|
|
14600
|
-
{
|
|
14601
|
-
ref: mentionRef,
|
|
14602
|
-
value: text,
|
|
14603
|
-
placeholder,
|
|
14604
|
-
disabled: disabled || loading,
|
|
14605
|
-
sources,
|
|
14606
|
-
chips,
|
|
14607
|
-
onChipsChange: handleChipsChange,
|
|
14608
|
-
onChange: handleChange,
|
|
14609
|
-
onSubmit: handleSubmit
|
|
14610
|
-
}
|
|
14611
|
-
) : void 0,
|
|
14612
|
-
onChange: handleChange,
|
|
14613
|
-
onSubmit: handleSubmit
|
|
14614
|
-
}
|
|
14615
|
-
) }),
|
|
14616
|
-
onAttachFiles ? /* @__PURE__ */ (0, import_jsx_runtime186.jsx)(
|
|
14617
|
-
"input",
|
|
14618
|
-
{
|
|
14619
|
-
ref: fileInputRef,
|
|
14620
|
-
type: "file",
|
|
14621
|
-
multiple: true,
|
|
14622
|
-
hidden: true,
|
|
14623
|
-
onChange: (event) => {
|
|
14624
|
-
emitFiles(Array.from(event.target.files ?? []));
|
|
14625
|
-
event.target.value = "";
|
|
14626
|
-
}
|
|
14627
|
-
}
|
|
14628
|
-
) : null,
|
|
14629
|
-
activePopover !== null ? /* @__PURE__ */ (0, import_jsx_runtime186.jsxs)(import_jsx_runtime186.Fragment, { children: [
|
|
14630
|
-
/* @__PURE__ */ (0, import_jsx_runtime186.jsx)("div", { className: "fixed inset-0 z-40", onClick: closePopovers }),
|
|
14631
|
-
activePopover === "model" ? /* @__PURE__ */ (0, import_jsx_runtime186.jsx)("div", { "data-slot": "composer-model-popover", className: cn(popoverPanelClass, "right-0 left-auto w-48"), role: "listbox", children: models.map((option) => /* @__PURE__ */ (0, import_jsx_runtime186.jsxs)(
|
|
14632
|
-
"button",
|
|
14633
|
-
{
|
|
14634
|
-
type: "button",
|
|
14635
|
-
role: "option",
|
|
14636
|
-
"aria-selected": option.value === currentModel?.value,
|
|
14637
|
-
className: popoverItemClass,
|
|
14638
|
-
onClick: () => {
|
|
14639
|
-
onModelChange?.(option.value);
|
|
14640
|
-
closePopovers();
|
|
14641
|
-
},
|
|
14642
|
-
children: [
|
|
14643
|
-
/* @__PURE__ */ (0, import_jsx_runtime186.jsx)("span", { className: "min-w-0 flex-1 truncate", children: option.label }),
|
|
14644
|
-
option.value === currentModel?.value ? /* @__PURE__ */ (0, import_jsx_runtime186.jsx)(Icon, { name: "check", size: 14 }) : null
|
|
14645
|
-
]
|
|
14646
|
-
},
|
|
14647
|
-
option.value
|
|
14648
|
-
)) }) : /* @__PURE__ */ (0, import_jsx_runtime186.jsx)("div", { "data-slot": "composer-context-popover", className: popoverPanelClass, role: "listbox", children: plusSources.map(
|
|
14649
|
-
(source) => source.items.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime186.jsxs)("div", { children: [
|
|
14650
|
-
/* @__PURE__ */ (0, import_jsx_runtime186.jsx)("div", { className: "px-2 py-1 text-xs text-muted-foreground", children: source.label }),
|
|
14651
|
-
source.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime186.jsxs)(
|
|
14652
|
-
"button",
|
|
14653
|
-
{
|
|
14654
|
-
type: "button",
|
|
14655
|
-
className: popoverItemClass,
|
|
14656
|
-
onClick: () => selectContext(item, source),
|
|
14657
|
-
children: [
|
|
14658
|
-
/* @__PURE__ */ (0, import_jsx_runtime186.jsx)(Icon, { name: item.icon ?? source.icon ?? "file-text", size: "sm" }),
|
|
14659
|
-
/* @__PURE__ */ (0, import_jsx_runtime186.jsx)("span", { className: "min-w-0 flex-1 truncate", children: item.label })
|
|
14660
|
-
]
|
|
14661
|
-
},
|
|
14662
|
-
item.id
|
|
14663
|
-
))
|
|
14664
|
-
] }, source.trigger)
|
|
14665
|
-
) })
|
|
14666
|
-
] }) : null
|
|
14667
|
-
]
|
|
14668
|
-
}
|
|
14669
|
-
);
|
|
14670
|
-
}
|
|
14671
|
-
|
|
14672
|
-
// src/components/chat/ConversationList/index.tsx
|
|
14673
|
-
var import_react68 = require("react");
|
|
14674
|
-
var import_jsx_runtime187 = require("react/jsx-runtime");
|
|
14675
|
-
function ConversationList({ items = [], activeId, searchable, onSelect, onDelete, className, style }) {
|
|
14676
|
-
const [innerActive, setInnerActive] = (0, import_react68.useState)();
|
|
14677
|
-
const [keyword, setKeyword] = (0, import_react68.useState)("");
|
|
14678
|
-
const active = activeId ?? innerActive;
|
|
14679
|
-
const filtered = (0, import_react68.useMemo)(() => {
|
|
14680
|
-
const query = keyword.trim().toLowerCase();
|
|
14681
|
-
if (!query) return items;
|
|
14682
|
-
return items.filter(
|
|
14683
|
-
(item) => item.title.toLowerCase().includes(query) || (item.description ?? "").toLowerCase().includes(query)
|
|
14684
|
-
);
|
|
14685
|
-
}, [items, keyword]);
|
|
14686
|
-
const select = (id) => {
|
|
14687
|
-
if (activeId === void 0) {
|
|
14688
|
-
setInnerActive(id);
|
|
14689
|
-
}
|
|
14690
|
-
onSelect?.(id);
|
|
14691
|
-
};
|
|
14692
|
-
return /* @__PURE__ */ (0, import_jsx_runtime187.jsxs)("div", { "data-slot": "conversation-list", className: cn("flex w-full flex-col gap-1", className), style, children: [
|
|
14693
|
-
searchable ? /* @__PURE__ */ (0, import_jsx_runtime187.jsxs)("div", { className: "relative mb-1", children: [
|
|
14694
|
-
/* @__PURE__ */ (0, import_jsx_runtime187.jsx)("span", { className: "absolute top-1/2 left-2 -translate-y-1/2 text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime187.jsx)(Icon, { name: "search", size: "sm" }) }),
|
|
14695
|
-
/* @__PURE__ */ (0, import_jsx_runtime187.jsx)(
|
|
14696
|
-
"input",
|
|
14697
|
-
{
|
|
14698
|
-
"data-slot": "conversation-list-search",
|
|
14699
|
-
value: keyword,
|
|
14700
|
-
placeholder: "\u641C\u7D22\u4F1A\u8BDD",
|
|
14701
|
-
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",
|
|
14702
|
-
onChange: (event) => setKeyword(event.target.value)
|
|
14703
|
-
}
|
|
14704
|
-
)
|
|
14705
|
-
] }) : null,
|
|
14706
|
-
filtered.map((item) => /* @__PURE__ */ (0, import_jsx_runtime187.jsxs)(
|
|
14707
|
-
"div",
|
|
14708
|
-
{
|
|
14709
|
-
"data-slot": "conversation-list-item",
|
|
14710
|
-
"data-active": item.id === active || void 0,
|
|
14711
|
-
className: cn(
|
|
14712
|
-
"group flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 hover:bg-accent",
|
|
14713
|
-
item.id === active && "bg-accent"
|
|
14714
|
-
),
|
|
14715
|
-
onClick: () => select(item.id),
|
|
14716
|
-
children: [
|
|
14717
|
-
/* @__PURE__ */ (0, import_jsx_runtime187.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
14718
|
-
/* @__PURE__ */ (0, import_jsx_runtime187.jsx)("div", { className: cn("truncate text-sm", item.id === active && "font-medium"), children: item.title }),
|
|
14719
|
-
item.description ? /* @__PURE__ */ (0, import_jsx_runtime187.jsx)("div", { className: "truncate text-xs text-muted-foreground", children: item.description }) : null
|
|
14720
|
-
] }),
|
|
14721
|
-
item.time ? /* @__PURE__ */ (0, import_jsx_runtime187.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.time }) : null,
|
|
14722
|
-
onDelete ? /* @__PURE__ */ (0, import_jsx_runtime187.jsx)(
|
|
14723
|
-
"button",
|
|
14724
|
-
{
|
|
14725
|
-
type: "button",
|
|
14726
|
-
"data-slot": "conversation-list-delete",
|
|
14727
|
-
"aria-label": `\u5220\u9664 ${item.title}`,
|
|
14728
|
-
className: "shrink-0 text-muted-foreground opacity-0 group-hover:opacity-100 hover:text-destructive",
|
|
14729
|
-
onClick: (event) => {
|
|
14730
|
-
event.stopPropagation();
|
|
14731
|
-
onDelete(item.id);
|
|
14732
|
-
},
|
|
14733
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime187.jsx)(Icon, { name: "trash-2", size: "sm" })
|
|
14734
|
-
}
|
|
14735
|
-
) : null
|
|
14736
|
-
]
|
|
14737
|
-
},
|
|
14738
|
-
item.id
|
|
14739
|
-
)),
|
|
14740
|
-
filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime187.jsx)("div", { className: "px-2 py-4 text-center text-sm text-muted-foreground", children: "\u65E0\u5339\u914D\u4F1A\u8BDD" }) : null
|
|
14741
|
-
] });
|
|
14742
|
-
}
|
|
14743
|
-
|
|
14744
|
-
// src/components/chat/MessageList/index.tsx
|
|
14745
|
-
var import_react69 = require("react");
|
|
14746
|
-
var import_jsx_runtime188 = require("react/jsx-runtime");
|
|
14747
|
-
function MessageList({ messages = [], autoScroll = true, onAction, onOpenArtifacts, className, style }) {
|
|
14748
|
-
const listRef = (0, import_react69.useRef)(null);
|
|
14749
|
-
(0, import_react69.useEffect)(() => {
|
|
14750
|
-
if (!autoScroll) return;
|
|
14751
|
-
const el = listRef.current;
|
|
14752
|
-
if (el) {
|
|
14753
|
-
el.scrollTop = el.scrollHeight;
|
|
14754
|
-
}
|
|
14755
|
-
}, [messages, autoScroll]);
|
|
14756
|
-
return /* @__PURE__ */ (0, import_jsx_runtime188.jsx)(
|
|
14757
|
-
"div",
|
|
14758
|
-
{
|
|
14759
|
-
ref: listRef,
|
|
14760
|
-
"data-slot": "message-list",
|
|
14761
|
-
className: cn("flex w-full flex-col gap-4 overflow-y-auto", className),
|
|
14762
|
-
style,
|
|
14763
|
-
children: messages.map((message, index) => /* @__PURE__ */ (0, import_jsx_runtime188.jsx)(
|
|
14764
|
-
ChatMessage,
|
|
14765
|
-
{
|
|
14766
|
-
...message,
|
|
14767
|
-
onAction: (action) => onAction?.({ id: message.id, action }),
|
|
14768
|
-
onOpenArtifacts: onOpenArtifacts ? () => onOpenArtifacts({ id: message.id }) : void 0
|
|
14769
|
-
},
|
|
14770
|
-
message.id ?? index
|
|
14771
|
-
))
|
|
14772
|
-
}
|
|
14773
|
-
);
|
|
14774
|
-
}
|
|
14775
|
-
|
|
14776
|
-
// src/components/chat/Prompt/index.tsx
|
|
14777
|
-
var import_jsx_runtime189 = require("react/jsx-runtime");
|
|
14778
|
-
function Prompt({ title, description, icon, value, disabled, onSelect, className, style }) {
|
|
14779
|
-
return /* @__PURE__ */ (0, import_jsx_runtime189.jsxs)(
|
|
14780
|
-
"button",
|
|
14781
|
-
{
|
|
14782
|
-
type: "button",
|
|
14783
|
-
"data-slot": "prompt",
|
|
14784
|
-
disabled,
|
|
14785
|
-
className: cn(
|
|
14786
|
-
"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",
|
|
14787
|
-
className
|
|
14788
|
-
),
|
|
14789
|
-
style,
|
|
14790
|
-
onClick: () => onSelect?.(value ?? title ?? ""),
|
|
14791
|
-
children: [
|
|
14792
|
-
icon ? /* @__PURE__ */ (0, import_jsx_runtime189.jsx)("span", { className: "mt-0.5 shrink-0 text-primary", children: /* @__PURE__ */ (0, import_jsx_runtime189.jsx)(Icon, { name: icon, size: "sm" }) }) : null,
|
|
14793
|
-
/* @__PURE__ */ (0, import_jsx_runtime189.jsxs)("span", { className: "min-w-0", children: [
|
|
14794
|
-
/* @__PURE__ */ (0, import_jsx_runtime189.jsx)("span", { "data-slot": "prompt-title", className: "block text-sm font-medium", children: title }),
|
|
14795
|
-
description ? /* @__PURE__ */ (0, import_jsx_runtime189.jsx)("span", { "data-slot": "prompt-description", className: "mt-0.5 block text-xs text-muted-foreground", children: description }) : null
|
|
14796
|
-
] })
|
|
14797
|
-
]
|
|
14798
|
-
}
|
|
14799
|
-
);
|
|
14800
|
-
}
|
|
14801
|
-
|
|
14802
|
-
// src/components/chat/Welcome/index.tsx
|
|
14803
|
-
var import_jsx_runtime190 = require("react/jsx-runtime");
|
|
14804
|
-
function Welcome({
|
|
14805
|
-
title = "\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u4F60\uFF1F",
|
|
14806
|
-
description,
|
|
14807
|
-
icon = "chat",
|
|
14808
|
-
prompts = [],
|
|
14809
|
-
onSelect,
|
|
14810
|
-
className,
|
|
14811
|
-
style
|
|
14812
|
-
}) {
|
|
14813
|
-
return /* @__PURE__ */ (0, import_jsx_runtime190.jsxs)(
|
|
14814
|
-
"div",
|
|
14815
|
-
{
|
|
14816
|
-
"data-slot": "welcome",
|
|
14817
|
-
className: cn("flex w-full flex-col items-center gap-4 py-10 text-center", className),
|
|
14818
|
-
style,
|
|
14819
|
-
children: [
|
|
14820
|
-
/* @__PURE__ */ (0, import_jsx_runtime190.jsx)("span", { "data-slot": "welcome-icon", className: "text-primary", children: /* @__PURE__ */ (0, import_jsx_runtime190.jsx)(Icon, { name: icon, size: "lg" }) }),
|
|
14821
|
-
/* @__PURE__ */ (0, import_jsx_runtime190.jsxs)("div", { children: [
|
|
14822
|
-
/* @__PURE__ */ (0, import_jsx_runtime190.jsx)("div", { "data-slot": "welcome-title", className: "text-xl font-semibold", children: title }),
|
|
14823
|
-
description ? /* @__PURE__ */ (0, import_jsx_runtime190.jsx)("div", { "data-slot": "welcome-description", className: "mt-1 text-sm text-muted-foreground", children: description }) : null
|
|
14824
|
-
] }),
|
|
14825
|
-
prompts.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime190.jsx)("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__ */ (0, import_jsx_runtime190.jsx)(
|
|
14826
|
-
Prompt,
|
|
14827
|
-
{
|
|
14828
|
-
title: item.title,
|
|
14829
|
-
description: item.description,
|
|
14830
|
-
icon: item.icon,
|
|
14831
|
-
value: item.value,
|
|
14832
|
-
onSelect
|
|
14833
|
-
},
|
|
14834
|
-
`${item.title}-${index}`
|
|
14835
|
-
)) }) : null
|
|
14836
|
-
]
|
|
14837
|
-
}
|
|
14838
|
-
);
|
|
14839
|
-
}
|
|
14840
|
-
|
|
14841
|
-
// src/components/chat/ChatPage/index.tsx
|
|
14842
|
-
var import_jsx_runtime191 = require("react/jsx-runtime");
|
|
14843
|
-
function ChatPage({
|
|
14844
|
-
brand,
|
|
14845
|
-
menuItems = [],
|
|
14846
|
-
activeMenuKey,
|
|
14847
|
-
railItems = [],
|
|
14848
|
-
railFooterItems = [],
|
|
14849
|
-
menuAction,
|
|
14850
|
-
onMenuSelect,
|
|
14851
|
-
onMenuAction,
|
|
14852
|
-
conversationSectionTitle,
|
|
14853
|
-
conversationSectionCollapsed,
|
|
14854
|
-
defaultConversationSectionCollapsed = false,
|
|
14855
|
-
onConversationSectionToggle,
|
|
14856
|
-
conversations = [],
|
|
14857
|
-
activeConversationId,
|
|
14858
|
-
onSelectConversation,
|
|
14859
|
-
onDeleteConversation,
|
|
14860
|
-
moreLabel,
|
|
14861
|
-
onMore,
|
|
14862
|
-
footerSectionTitle,
|
|
14863
|
-
footerItems = [],
|
|
14864
|
-
footerSectionCollapsed,
|
|
14865
|
-
defaultFooterSectionCollapsed = false,
|
|
14866
|
-
onFooterSectionToggle,
|
|
14867
|
-
conversationTitle,
|
|
14868
|
-
conversationHeaderAction,
|
|
14869
|
-
onConversationHeaderAction,
|
|
14870
|
-
conversationRailItems = [],
|
|
14871
|
-
hideArtifactRailItem = false,
|
|
14872
|
-
activeConversationRailKey,
|
|
14873
|
-
onConversationRailChange,
|
|
14874
|
-
messages = [],
|
|
14875
|
-
sending,
|
|
14876
|
-
composerPlaceholder,
|
|
14877
|
-
welcome,
|
|
14878
|
-
onSend,
|
|
14879
|
-
onMessageAction,
|
|
14880
|
-
models,
|
|
14881
|
-
model,
|
|
14882
|
-
onModelChange,
|
|
14883
|
-
contexts,
|
|
14884
|
-
contextItems,
|
|
14885
|
-
onContextItemsChange,
|
|
14886
|
-
attachments,
|
|
14887
|
-
onAttachFiles,
|
|
14888
|
-
onRemoveAttachment,
|
|
14889
|
-
onRetryAttachment,
|
|
14890
|
-
composerFooter,
|
|
14891
|
-
composerBottom,
|
|
14892
|
-
artifactTitle = "\u4EA7\u7269",
|
|
14893
|
-
artifacts = [],
|
|
14894
|
-
activeArtifactId,
|
|
14895
|
-
onSelectArtifact,
|
|
14896
|
-
artifactEmptyText = "\u6682\u65E0\u4EA7\u7269\uFF0C\u53D1\u9001\u6D88\u606F\u540E\u751F\u6210\u7684\u6587\u4EF6\u5C06\u5C55\u793A\u5728\u8FD9\u91CC",
|
|
14897
|
-
safeRegistry,
|
|
14898
|
-
user,
|
|
14899
|
-
artifactViewers,
|
|
14900
|
-
onDownloadArtifact,
|
|
14901
|
-
artifactOpen,
|
|
14902
|
-
defaultArtifactOpen = false,
|
|
14903
|
-
onArtifactOpenChange,
|
|
14904
|
-
content,
|
|
14905
|
-
className,
|
|
14906
|
-
style
|
|
14907
|
-
}) {
|
|
14908
|
-
const controlled = artifactOpen !== void 0;
|
|
14909
|
-
const [innerOpen, setInnerOpen] = (0, import_react70.useState)(defaultArtifactOpen);
|
|
14910
|
-
const open = controlled ? artifactOpen === true : innerOpen;
|
|
14911
|
-
const setOpen = (next) => {
|
|
14912
|
-
if (!controlled) setInnerOpen(next);
|
|
14913
|
-
onArtifactOpenChange?.(next);
|
|
14914
|
-
};
|
|
14915
|
-
const railControlled = activeConversationRailKey !== void 0;
|
|
14916
|
-
const [activeRailInner, setActiveRailInner] = (0, import_react70.useState)(null);
|
|
14917
|
-
const activeRailKey = railControlled ? activeConversationRailKey : activeRailInner;
|
|
14918
|
-
const setActiveRailKey = (next) => {
|
|
14919
|
-
if (!railControlled) setActiveRailInner(next);
|
|
14920
|
-
onConversationRailChange?.(next);
|
|
14921
|
-
};
|
|
14922
|
-
const visibleRailItems = conversationRailItems.filter((item) => item.hidden !== true);
|
|
14923
|
-
const activeRailItem = visibleRailItems.find(
|
|
14924
|
-
(item) => item.key === activeRailKey
|
|
14925
|
-
);
|
|
14926
|
-
const activePanelItem = activeRailItem?.display === "panel" && activeRailItem.content !== void 0 ? activeRailItem : void 0;
|
|
14927
|
-
const activePopoverItem = activeRailItem !== void 0 && activeRailItem.display !== "panel" && activeRailItem.content !== void 0 ? activeRailItem : void 0;
|
|
14928
|
-
const toggleRailItem = (item) => {
|
|
14929
|
-
const next = activeRailKey === item.key ? null : item.key;
|
|
14930
|
-
if (next !== null && item.display === "panel") {
|
|
14931
|
-
setOpen(false);
|
|
14932
|
-
}
|
|
14933
|
-
setActiveRailKey(next);
|
|
14934
|
-
};
|
|
14935
|
-
const toggleArtifact = () => {
|
|
14936
|
-
if (!open && activePanelItem) {
|
|
14937
|
-
setActiveRailKey(null);
|
|
14938
|
-
}
|
|
14939
|
-
setOpen(!open);
|
|
14940
|
-
};
|
|
14941
|
-
(0, import_react70.useEffect)(() => {
|
|
14942
|
-
if (!activePopoverItem) return;
|
|
14943
|
-
const onKeyDown = (event) => {
|
|
14944
|
-
if (event.key === "Escape") setActiveRailKey(null);
|
|
14945
|
-
};
|
|
14946
|
-
const onPointerDown = (event) => {
|
|
14947
|
-
const target = event.target;
|
|
14948
|
-
if (target.closest("[data-slot=chat-page-rail-popover]") || target.closest("[data-slot=chat-page-conv-rail]")) {
|
|
14949
|
-
return;
|
|
14950
|
-
}
|
|
14951
|
-
setActiveRailKey(null);
|
|
14952
|
-
};
|
|
14953
|
-
document.addEventListener("keydown", onKeyDown);
|
|
14954
|
-
document.addEventListener("mousedown", onPointerDown);
|
|
14955
|
-
return () => {
|
|
14956
|
-
document.removeEventListener("keydown", onKeyDown);
|
|
14957
|
-
document.removeEventListener("mousedown", onPointerDown);
|
|
14958
|
-
};
|
|
14959
|
-
});
|
|
14960
|
-
const { renderChildren } = (0, import_runtime51.useRenderer)();
|
|
14961
|
-
const renderSlot = (slot) => (0, import_react70.isValidElement)(slot) || typeof slot !== "object" || slot === null ? slot : renderChildren([slot]);
|
|
14962
|
-
const convCollControlled = conversationSectionCollapsed !== void 0;
|
|
14963
|
-
const [convCollapsedInner, setConvCollapsedInner] = (0, import_react70.useState)(
|
|
14964
|
-
defaultConversationSectionCollapsed
|
|
14965
|
-
);
|
|
14966
|
-
const convCollapsed = convCollControlled ? conversationSectionCollapsed === true : convCollapsedInner;
|
|
14967
|
-
const toggleConvSection = () => {
|
|
14968
|
-
const next = !convCollapsed;
|
|
14969
|
-
if (!convCollControlled) setConvCollapsedInner(next);
|
|
14970
|
-
onConversationSectionToggle?.(next);
|
|
14971
|
-
};
|
|
14972
|
-
const footerCollControlled = footerSectionCollapsed !== void 0;
|
|
14973
|
-
const [footerCollapsedInner, setFooterCollapsedInner] = (0, import_react70.useState)(
|
|
14974
|
-
defaultFooterSectionCollapsed
|
|
14975
|
-
);
|
|
14976
|
-
const footerCollapsed = footerCollControlled ? footerSectionCollapsed === true : footerCollapsedInner;
|
|
14977
|
-
const toggleFooterSection = () => {
|
|
14978
|
-
const next = !footerCollapsed;
|
|
14979
|
-
if (!footerCollControlled) setFooterCollapsedInner(next);
|
|
14980
|
-
onFooterSectionToggle?.(next);
|
|
14981
|
-
};
|
|
14982
|
-
const railVisible = railItems.length > 0 || railFooterItems.length > 0;
|
|
14983
|
-
const railButton = (item) => /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Tooltip2, { content: item.label, side: "right", children: /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
14984
|
-
Button2,
|
|
14985
|
-
{
|
|
14986
|
-
icon: item.icon,
|
|
14987
|
-
variant: "text",
|
|
14988
|
-
onClick: () => onMenuSelect?.(item.key)
|
|
14989
|
-
}
|
|
14990
|
-
) }, item.key);
|
|
14991
|
-
const convRailButton = (item, active, onClick) => {
|
|
14992
|
-
const button = /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
14993
|
-
Button2,
|
|
14994
|
-
{
|
|
14995
|
-
icon: item.icon,
|
|
14996
|
-
variant: "text",
|
|
14997
|
-
className: cn(active ? "bg-accent text-accent-foreground" : void 0, "px-2"),
|
|
14998
|
-
onClick
|
|
14999
|
-
}
|
|
15000
|
-
);
|
|
15001
|
-
return item.label !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Tooltip2, { content: item.label, side: "left", children: button }, item.key) : /* @__PURE__ */ (0, import_jsx_runtime191.jsx)("span", { children: button }, item.key);
|
|
15002
|
-
};
|
|
15003
|
-
const convRailVisible = !hideArtifactRailItem || visibleRailItems.length > 0;
|
|
15004
|
-
const convRail = convRailVisible ? /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)(
|
|
15005
|
-
"div",
|
|
15006
|
-
{
|
|
15007
|
-
"data-slot": "chat-page-conv-rail",
|
|
15008
|
-
className: "relative flex w-(--pactor-chat-rail-width) shrink-0 flex-col items-center gap-1 px-1 py-2",
|
|
15009
|
-
children: [
|
|
15010
|
-
!hideArtifactRailItem ? convRailButton(
|
|
15011
|
-
{
|
|
15012
|
-
key: "artifact",
|
|
15013
|
-
icon: open ? "panel-right-close" : "package",
|
|
15014
|
-
label: open ? "\u6536\u8D77\u4EA7\u7269\u533A" : artifactTitle
|
|
15015
|
-
},
|
|
15016
|
-
open,
|
|
15017
|
-
toggleArtifact
|
|
15018
|
-
) : null,
|
|
15019
|
-
visibleRailItems.map(
|
|
15020
|
-
(item) => convRailButton(item, activeRailKey === item.key, () => toggleRailItem(item))
|
|
15021
|
-
),
|
|
15022
|
-
activePopoverItem ? /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15023
|
-
"div",
|
|
15024
|
-
{
|
|
15025
|
-
"data-slot": "chat-page-rail-popover",
|
|
15026
|
-
className: "absolute right-full top-0 z-10 mr-2 overflow-auto rounded-lg border border-border bg-popover shadow-md",
|
|
15027
|
-
style: {
|
|
15028
|
-
width: "var(--pactor-chat-rail-popover-width)",
|
|
15029
|
-
maxWidth: "calc(100cqw - 2rem)",
|
|
15030
|
-
maxHeight: "calc(100% - 1rem)"
|
|
15031
|
-
},
|
|
15032
|
-
children: renderSlot(activePopoverItem.content)
|
|
15033
|
-
}
|
|
15034
|
-
) : null
|
|
15035
|
-
]
|
|
15036
|
-
}
|
|
15037
|
-
) : null;
|
|
15038
|
-
const chatArea = /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)("div", { "data-slot": "chat-page-conversation", className: "flex h-full min-w-0 flex-1 flex-col", children: [
|
|
15039
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsxs)(
|
|
15040
|
-
"div",
|
|
15041
|
-
{
|
|
15042
|
-
"data-slot": "chat-page-conversation-header",
|
|
15043
|
-
className: "flex shrink-0 items-center justify-between border-b border-border px-4 py-2.5",
|
|
15044
|
-
children: [
|
|
15045
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Text, { text: conversationTitle, strong: true }),
|
|
15046
|
-
conversationHeaderAction ? /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Tooltip2, { content: conversationHeaderAction.tooltip ?? conversationHeaderAction.label, side: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15047
|
-
Button2,
|
|
15048
|
-
{
|
|
15049
|
-
text: conversationHeaderAction.label,
|
|
15050
|
-
icon: conversationHeaderAction.icon,
|
|
15051
|
-
variant: "text",
|
|
15052
|
-
onClick: () => onConversationHeaderAction?.()
|
|
15053
|
-
}
|
|
15054
|
-
) }) : null
|
|
15055
|
-
]
|
|
15056
|
-
}
|
|
15057
|
-
),
|
|
15058
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsxs)("div", { className: "flex min-h-0 flex-1", children: [
|
|
15059
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsxs)(
|
|
15060
|
-
"div",
|
|
15061
|
-
{
|
|
15062
|
-
"data-slot": "chat-page-conversation-body",
|
|
15063
|
-
className: "mx-auto flex min-h-0 w-[61.8cqw] max-w-full flex-col",
|
|
15064
|
-
children: [
|
|
15065
|
-
messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15066
|
-
Welcome,
|
|
15067
|
-
{
|
|
15068
|
-
title: welcome?.title,
|
|
15069
|
-
description: welcome?.description,
|
|
15070
|
-
prompts: welcome?.prompts,
|
|
15071
|
-
style: { flex: 1 },
|
|
15072
|
-
onSelect: (value) => onSend?.(value)
|
|
15073
|
-
}
|
|
15074
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15075
|
-
MessageList,
|
|
15076
|
-
{
|
|
15077
|
-
messages,
|
|
15078
|
-
className: "scrollbar-subtle",
|
|
15079
|
-
style: { flex: 1, minHeight: 0, padding: 16 },
|
|
15080
|
-
onAction: onMessageAction,
|
|
15081
|
-
onOpenArtifacts: () => setOpen(true)
|
|
15082
|
-
}
|
|
15083
|
-
),
|
|
15084
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15085
|
-
Composer,
|
|
15086
|
-
{
|
|
15087
|
-
placeholder: composerPlaceholder,
|
|
15088
|
-
loading: sending,
|
|
15089
|
-
models,
|
|
15090
|
-
model,
|
|
15091
|
-
contexts,
|
|
15092
|
-
contextItems,
|
|
15093
|
-
attachments,
|
|
15094
|
-
footer: composerFooter,
|
|
15095
|
-
style: { padding: 16, paddingBottom: composerBottom ? 8 : 16, flexShrink: 0 },
|
|
15096
|
-
onModelChange,
|
|
15097
|
-
onContextItemsChange,
|
|
15098
|
-
onAttachFiles,
|
|
15099
|
-
onRemoveAttachment,
|
|
15100
|
-
onRetryAttachment,
|
|
15101
|
-
onSubmit: (text) => onSend?.(text)
|
|
15102
|
-
}
|
|
15103
|
-
),
|
|
15104
|
-
composerBottom ? /* @__PURE__ */ (0, import_jsx_runtime191.jsx)("div", { "data-slot": "chat-page-composer-bottom", className: "shrink-0 px-4 pb-2 text-center", children: renderSlot(composerBottom) }) : null
|
|
15105
|
-
]
|
|
15106
|
-
}
|
|
15107
|
-
),
|
|
15108
|
-
convRail
|
|
15109
|
-
] })
|
|
15110
|
-
] });
|
|
15111
|
-
const activeArtifact = artifacts.find((item) => item.id === activeArtifactId) ?? (activeArtifactId === void 0 || activeArtifactId === "" ? artifacts[artifacts.length - 1] : void 0);
|
|
15112
|
-
const artifactPanel = /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15113
|
-
"div",
|
|
15114
|
-
{
|
|
15115
|
-
"data-slot": "chat-page-artifact",
|
|
15116
|
-
className: "flex h-full min-w-0 flex-col border-l border-border bg-muted",
|
|
15117
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15118
|
-
ArtifactPanel,
|
|
15119
|
-
{
|
|
15120
|
-
artifact: activeArtifact,
|
|
15121
|
-
artifacts,
|
|
15122
|
-
activeArtifactId,
|
|
15123
|
-
title: artifactTitle,
|
|
15124
|
-
emptyText: artifactEmptyText,
|
|
15125
|
-
safeRegistry,
|
|
15126
|
-
user,
|
|
15127
|
-
artifactViewers,
|
|
15128
|
-
onSelectArtifact: (id) => onSelectArtifact?.(id),
|
|
15129
|
-
onDownload: onDownloadArtifact,
|
|
15130
|
-
onClose: () => setOpen(false)
|
|
15131
|
-
}
|
|
15132
|
-
)
|
|
15133
|
-
}
|
|
15134
|
-
);
|
|
15135
|
-
return /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)(
|
|
15136
|
-
"div",
|
|
15137
|
-
{
|
|
15138
|
-
"data-slot": "chat-page",
|
|
15139
|
-
className: cn("flex w-full overflow-hidden", className),
|
|
15140
|
-
style: { height: "100vh", ...style },
|
|
15141
|
-
children: [
|
|
15142
|
-
railVisible ? /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)(
|
|
15143
|
-
"div",
|
|
15144
|
-
{
|
|
15145
|
-
"data-slot": "chat-page-rail",
|
|
15146
|
-
className: "flex h-full w-[52px] shrink-0 flex-col items-center gap-1 border-r border-border py-2.5",
|
|
15147
|
-
children: [
|
|
15148
|
-
railItems.map(railButton),
|
|
15149
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)("div", { className: "flex-1" }),
|
|
15150
|
-
railFooterItems.map(railButton)
|
|
15151
|
-
]
|
|
15152
|
-
}
|
|
15153
|
-
) : null,
|
|
15154
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsxs)(
|
|
15155
|
-
"div",
|
|
15156
|
-
{
|
|
15157
|
-
"data-slot": "chat-page-menu",
|
|
15158
|
-
className: "flex h-full w-[250px] shrink-0 flex-col gap-2 overflow-hidden border-r border-border px-2 py-3",
|
|
15159
|
-
children: [
|
|
15160
|
-
brand ? /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)("div", { className: "flex shrink-0 items-center justify-between px-2", children: [
|
|
15161
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
|
|
15162
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Text, { text: brand.title, strong: true, size: "large" }),
|
|
15163
|
-
brand.version !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Text, { text: brand.version, type: "secondary", size: "small" }) : null
|
|
15164
|
-
] }),
|
|
15165
|
-
menuAction ? /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15166
|
-
Button2,
|
|
15167
|
-
{
|
|
15168
|
-
text: menuAction.label,
|
|
15169
|
-
icon: menuAction.icon,
|
|
15170
|
-
size: "small",
|
|
15171
|
-
onClick: () => onMenuAction?.()
|
|
15172
|
-
}
|
|
15173
|
-
) : null
|
|
15174
|
-
] }) : null,
|
|
15175
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)("div", { className: "scrollbar-subtle max-h-[40%] min-h-0 shrink-0 overflow-y-auto", children: /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15176
|
-
Menu2,
|
|
15177
|
-
{
|
|
15178
|
-
items: menuItems,
|
|
15179
|
-
selectedKey: activeMenuKey,
|
|
15180
|
-
onSelect: (key) => onMenuSelect?.(key)
|
|
15181
|
-
}
|
|
15182
|
-
) }),
|
|
15183
|
-
conversationSectionTitle !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)(
|
|
15184
|
-
"button",
|
|
15185
|
-
{
|
|
15186
|
-
type: "button",
|
|
15187
|
-
"data-slot": "chat-page-section-toggle",
|
|
15188
|
-
"aria-expanded": !convCollapsed,
|
|
15189
|
-
className: "flex w-full shrink-0 cursor-pointer items-center justify-between px-2 pt-2",
|
|
15190
|
-
onClick: toggleConvSection,
|
|
15191
|
-
children: [
|
|
15192
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15193
|
-
Text,
|
|
15194
|
-
{
|
|
15195
|
-
text: `${conversationSectionTitle} (${conversations.length})`,
|
|
15196
|
-
type: "secondary",
|
|
15197
|
-
className: "text-sm",
|
|
15198
|
-
strong: true
|
|
15199
|
-
}
|
|
15200
|
-
),
|
|
15201
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Icon, { name: convCollapsed ? "chevron-right" : "chevron-down", size: 14 })
|
|
15202
|
-
]
|
|
15203
|
-
}
|
|
15204
|
-
) : null,
|
|
15205
|
-
!convCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)("div", { "data-slot": "chat-page-section-body", className: "scrollbar-subtle flex min-h-0 flex-1 flex-col overflow-y-auto", children: [
|
|
15206
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15207
|
-
ConversationList,
|
|
15208
|
-
{
|
|
15209
|
-
items: conversations,
|
|
15210
|
-
activeId: activeConversationId,
|
|
15211
|
-
onSelect: (id) => onSelectConversation?.(id),
|
|
15212
|
-
onDelete: (id) => onDeleteConversation?.(id)
|
|
15213
|
-
}
|
|
15214
|
-
),
|
|
15215
|
-
moreLabel !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime191.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Button2, { text: `${moreLabel} >>`, variant: "link", size: "small", onClick: () => onMore?.() }) }) : null
|
|
15216
|
-
] }) : null,
|
|
15217
|
-
footerSectionTitle !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)(
|
|
15218
|
-
"button",
|
|
15219
|
-
{
|
|
15220
|
-
type: "button",
|
|
15221
|
-
"data-slot": "chat-page-section-toggle",
|
|
15222
|
-
"aria-expanded": !footerCollapsed,
|
|
15223
|
-
className: "flex w-full shrink-0 cursor-pointer items-center justify-between px-2 pt-2",
|
|
15224
|
-
onClick: toggleFooterSection,
|
|
15225
|
-
children: [
|
|
15226
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Text, { text: footerSectionTitle, type: "secondary", className: "text-sm", strong: true }),
|
|
15227
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Icon, { name: footerCollapsed ? "chevron-right" : "chevron-down", size: 14 })
|
|
15228
|
-
]
|
|
15229
|
-
}
|
|
15230
|
-
) : null,
|
|
15231
|
-
!footerCollapsed && footerItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime191.jsx)("div", { "data-slot": "chat-page-section-body", className: "scrollbar-subtle min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15232
|
-
Menu2,
|
|
15233
|
-
{
|
|
15234
|
-
items: footerItems,
|
|
15235
|
-
onSelect: (key) => onMenuSelect?.(key)
|
|
15236
|
-
}
|
|
15237
|
-
) }) : null
|
|
15238
|
-
]
|
|
15239
|
-
}
|
|
15240
|
-
),
|
|
15241
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)("div", { className: "@container h-full min-w-0 flex-1", children: content !== void 0 ? renderSlot(content) : open || activePanelItem ? /* @__PURE__ */ (0, import_jsx_runtime191.jsxs)(PanelGroup, { orientation: "horizontal", style: { width: "100%", height: "100%" }, children: [
|
|
15242
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Panel, { defaultSize: "62%", children: chatArea }),
|
|
15243
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)(ResizableHandle, { withHandle: true }),
|
|
15244
|
-
/* @__PURE__ */ (0, import_jsx_runtime191.jsx)(Panel, { defaultSize: "38%", minSize: "380px", maxSize: "760px", children: activePanelItem ? /* @__PURE__ */ (0, import_jsx_runtime191.jsx)(
|
|
15245
|
-
"div",
|
|
15246
|
-
{
|
|
15247
|
-
"data-slot": "chat-page-rail-panel",
|
|
15248
|
-
className: "flex h-full min-w-0 flex-col border-l border-border bg-muted",
|
|
15249
|
-
children: renderSlot(activePanelItem.content)
|
|
15250
|
-
}
|
|
15251
|
-
) : artifactPanel })
|
|
15252
|
-
] }) : chatArea })
|
|
15253
|
-
]
|
|
15254
|
-
}
|
|
15255
|
-
);
|
|
15256
|
-
}
|
|
15257
|
-
|
|
15258
|
-
// src/components/chat/Citation/index.tsx
|
|
15259
|
-
var import_jsx_runtime192 = require("react/jsx-runtime");
|
|
15260
|
-
function Citation({ items = [], start = 1, className, style }) {
|
|
15261
|
-
return /* @__PURE__ */ (0, import_jsx_runtime192.jsx)("span", { "data-slot": "citation", className: cn("inline-flex gap-1 align-super", className), style, children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime192.jsxs)(HoverCard, { children: [
|
|
15262
|
-
/* @__PURE__ */ (0, import_jsx_runtime192.jsxs)(
|
|
15263
|
-
HoverCardTrigger,
|
|
15264
|
-
{
|
|
15265
|
-
"data-slot": "citation-marker",
|
|
15266
|
-
className: "cursor-pointer rounded-sm border border-border px-1 text-xs leading-4 text-primary hover:bg-accent",
|
|
15267
|
-
children: [
|
|
15268
|
-
"[",
|
|
15269
|
-
start + index,
|
|
15270
|
-
"]"
|
|
15271
|
-
]
|
|
15272
|
-
}
|
|
15273
|
-
),
|
|
15274
|
-
/* @__PURE__ */ (0, import_jsx_runtime192.jsxs)(HoverCardContent, { "data-slot": "citation-card", className: "w-72", children: [
|
|
15275
|
-
/* @__PURE__ */ (0, import_jsx_runtime192.jsx)("div", { className: "text-sm font-medium", children: item.title }),
|
|
15276
|
-
item.snippet ? /* @__PURE__ */ (0, import_jsx_runtime192.jsx)("div", { className: "mt-1 line-clamp-3 text-xs text-muted-foreground", children: item.snippet }) : null,
|
|
15277
|
-
item.url ? /* @__PURE__ */ (0, import_jsx_runtime192.jsx)(
|
|
15278
|
-
"a",
|
|
15279
|
-
{
|
|
15280
|
-
href: item.url,
|
|
15281
|
-
target: "_blank",
|
|
15282
|
-
rel: "noreferrer",
|
|
15283
|
-
className: "mt-1 block truncate text-xs text-primary hover:underline",
|
|
15284
|
-
children: item.url
|
|
15285
|
-
}
|
|
15286
|
-
) : null
|
|
15287
|
-
] })
|
|
15288
|
-
] }, `${item.title}-${index}`)) });
|
|
15289
|
-
}
|
|
15290
|
-
|
|
15291
|
-
// src/components/chat/StepsPanel/index.tsx
|
|
15292
|
-
var import_jsx_runtime193 = require("react/jsx-runtime");
|
|
15293
|
-
function StepsPanel({
|
|
15294
|
-
title = "\u6267\u884C\u6B65\u9AA4",
|
|
15295
|
-
steps = [],
|
|
15296
|
-
emptyText = "\u5F53\u524D\u4F1A\u8BDD\u6682\u65E0\u6267\u884C\u6B65\u9AA4",
|
|
15297
|
-
className,
|
|
15298
|
-
style
|
|
15299
|
-
}) {
|
|
15300
|
-
return /* @__PURE__ */ (0, import_jsx_runtime193.jsxs)(
|
|
15301
|
-
"div",
|
|
15302
|
-
{
|
|
15303
|
-
"data-slot": "steps-panel",
|
|
15304
|
-
className: cn("px-3.5 py-3 text-foreground", className),
|
|
15305
|
-
style,
|
|
15306
|
-
children: [
|
|
15307
|
-
/* @__PURE__ */ (0, import_jsx_runtime193.jsx)("div", { className: "mb-1 text-[13px] font-semibold", children: title }),
|
|
15308
|
-
steps.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime193.jsx)("div", { className: "py-4 text-center text-[13px] text-muted-foreground", children: emptyText }) : /* @__PURE__ */ (0, import_jsx_runtime193.jsx)("ol", { children: steps.map((step, index) => {
|
|
15309
|
-
const status = step.status ?? "pending";
|
|
15310
|
-
return /* @__PURE__ */ (0, import_jsx_runtime193.jsxs)(
|
|
15311
|
-
"li",
|
|
15312
|
-
{
|
|
15313
|
-
"data-status": status,
|
|
15314
|
-
className: cn(
|
|
15315
|
-
"relative flex gap-2 py-1.5",
|
|
15316
|
-
// 步骤之间的连接线(对齐 16px 图标中心)
|
|
15317
|
-
'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-[""]'
|
|
15318
|
-
),
|
|
15319
|
-
children: [
|
|
15320
|
-
/* @__PURE__ */ (0, import_jsx_runtime193.jsx)(
|
|
15321
|
-
"span",
|
|
15322
|
-
{
|
|
15323
|
-
className: cn(
|
|
15324
|
-
"flex h-5 w-4 shrink-0 items-center justify-center",
|
|
15325
|
-
status !== "pending" && "text-primary"
|
|
15326
|
-
),
|
|
15327
|
-
children: status === "done" ? /* @__PURE__ */ (0, import_jsx_runtime193.jsx)(Icon, { name: "check-circle", size: 16 }) : status === "running" ? /* @__PURE__ */ (0, import_jsx_runtime193.jsx)(
|
|
15328
|
-
Icon,
|
|
15329
|
-
{
|
|
15330
|
-
name: "loading",
|
|
15331
|
-
size: 16,
|
|
15332
|
-
className: "animate-spin motion-reduce:animate-none"
|
|
15333
|
-
}
|
|
15334
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime193.jsx)("span", { className: "size-1.5 rounded-full bg-muted-foreground/50" })
|
|
15335
|
-
}
|
|
15336
|
-
),
|
|
15337
|
-
/* @__PURE__ */ (0, import_jsx_runtime193.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
15338
|
-
/* @__PURE__ */ (0, import_jsx_runtime193.jsx)(
|
|
15339
|
-
"div",
|
|
15340
|
-
{
|
|
15341
|
-
className: cn(
|
|
15342
|
-
"text-[13px] leading-5",
|
|
15343
|
-
status === "pending" && "text-muted-foreground"
|
|
15344
|
-
),
|
|
15345
|
-
children: step.title
|
|
15346
|
-
}
|
|
15347
|
-
),
|
|
15348
|
-
step.description ? /* @__PURE__ */ (0, import_jsx_runtime193.jsx)("div", { className: "mt-0.5 text-xs leading-[18px] text-muted-foreground", children: step.description }) : null
|
|
15349
|
-
] }),
|
|
15350
|
-
step.duration ? /* @__PURE__ */ (0, import_jsx_runtime193.jsx)("span", { className: "shrink-0 text-xs leading-5 text-muted-foreground", children: step.duration }) : null
|
|
15351
|
-
]
|
|
15352
|
-
},
|
|
15353
|
-
`${step.title}-${index}`
|
|
15354
|
-
);
|
|
15355
|
-
}) })
|
|
15356
|
-
]
|
|
15357
|
-
}
|
|
15358
|
-
);
|
|
15359
|
-
}
|
|
15360
|
-
|
|
15361
|
-
// src/components/chat/Suggestion/index.tsx
|
|
15362
|
-
var import_jsx_runtime194 = require("react/jsx-runtime");
|
|
15363
|
-
function normalize(item) {
|
|
15364
|
-
if (typeof item === "string") return { label: item, value: item };
|
|
15365
|
-
return { label: item.label, value: item.value ?? item.label, icon: item.icon };
|
|
15366
|
-
}
|
|
15367
|
-
function Suggestion({ items = [], justify = "start", onSelect, className, style }) {
|
|
15368
|
-
return /* @__PURE__ */ (0, import_jsx_runtime194.jsx)(
|
|
15369
|
-
"div",
|
|
15370
|
-
{
|
|
15371
|
-
"data-slot": "suggestion",
|
|
15372
|
-
className: cn("flex flex-wrap gap-2", justify === "center" && "justify-center", className),
|
|
15373
|
-
style,
|
|
15374
|
-
children: items.map((item, index) => {
|
|
15375
|
-
const { label, value, icon } = normalize(item);
|
|
15376
|
-
return /* @__PURE__ */ (0, import_jsx_runtime194.jsxs)(
|
|
15377
|
-
"button",
|
|
15378
|
-
{
|
|
15379
|
-
type: "button",
|
|
15380
|
-
"data-slot": "suggestion-item",
|
|
15381
|
-
"data-value": value,
|
|
15382
|
-
className: "flex items-center gap-1.5 rounded-full border border-border px-3 py-1 text-sm transition-colors hover:bg-accent",
|
|
15383
|
-
onClick: () => onSelect?.(value),
|
|
15384
|
-
children: [
|
|
15385
|
-
icon ? /* @__PURE__ */ (0, import_jsx_runtime194.jsx)(Icon, { name: icon, size: "sm" }) : null,
|
|
15386
|
-
label
|
|
15387
|
-
]
|
|
15388
|
-
},
|
|
15389
|
-
`${value}-${index}`
|
|
15390
|
-
);
|
|
15391
|
-
})
|
|
15392
|
-
}
|
|
15393
|
-
);
|
|
15394
|
-
}
|
|
15395
|
-
|
|
15396
12948
|
// src/components/register.ts
|
|
15397
12949
|
var builtinComponents = {
|
|
15398
12950
|
Page,
|
|
@@ -15523,26 +13075,7 @@ var builtinComponents = {
|
|
|
15523
13075
|
Markdown: import_markdown2.MarkdownDslComponent,
|
|
15524
13076
|
CodeBlock,
|
|
15525
13077
|
DiffViewer,
|
|
15526
|
-
JSONViewer
|
|
15527
|
-
// AI 与会话类扩展组件(第八批:chat 子目录)
|
|
15528
|
-
Bubble: Bubble2,
|
|
15529
|
-
Sender,
|
|
15530
|
-
Thinking,
|
|
15531
|
-
AgentStatus,
|
|
15532
|
-
StreamingText,
|
|
15533
|
-
Suggestion,
|
|
15534
|
-
Prompt,
|
|
15535
|
-
Welcome,
|
|
15536
|
-
Citation,
|
|
15537
|
-
Attachment,
|
|
15538
|
-
ToolCall,
|
|
15539
|
-
ChatMessage,
|
|
15540
|
-
ChatPage,
|
|
15541
|
-
ArtifactPanel,
|
|
15542
|
-
MessageList,
|
|
15543
|
-
Composer,
|
|
15544
|
-
ConversationList,
|
|
15545
|
-
StepsPanel
|
|
13078
|
+
JSONViewer
|
|
15546
13079
|
};
|
|
15547
13080
|
function registerBuiltinComponents(registry) {
|
|
15548
13081
|
for (const [type, component] of Object.entries(builtinComponents)) {
|
|
@@ -15550,7 +13083,7 @@ function registerBuiltinComponents(registry) {
|
|
|
15550
13083
|
}
|
|
15551
13084
|
}
|
|
15552
13085
|
function createComponentRegistry() {
|
|
15553
|
-
const registry = new
|
|
13086
|
+
const registry = new import_core2.Registry("ComponentRegistry");
|
|
15554
13087
|
registerBuiltinComponents(registry);
|
|
15555
13088
|
return registry;
|
|
15556
13089
|
}
|
|
@@ -15558,19 +13091,15 @@ function createComponentRegistry() {
|
|
|
15558
13091
|
0 && (module.exports = {
|
|
15559
13092
|
Accordion,
|
|
15560
13093
|
Affix,
|
|
15561
|
-
AgentStatus,
|
|
15562
13094
|
Alert,
|
|
15563
13095
|
AlertDialog,
|
|
15564
13096
|
Anchor,
|
|
15565
|
-
ArtifactPanel,
|
|
15566
13097
|
AspectRatio,
|
|
15567
|
-
Attachment,
|
|
15568
13098
|
Audio,
|
|
15569
13099
|
Avatar,
|
|
15570
13100
|
BackTop,
|
|
15571
13101
|
Badge,
|
|
15572
13102
|
Breadcrumb,
|
|
15573
|
-
Bubble,
|
|
15574
13103
|
Button,
|
|
15575
13104
|
ButtonGroup,
|
|
15576
13105
|
CONTROL_SIZE_AREA,
|
|
@@ -15583,12 +13112,9 @@ function createComponentRegistry() {
|
|
|
15583
13112
|
Carousel,
|
|
15584
13113
|
Cascader,
|
|
15585
13114
|
ChatInput,
|
|
15586
|
-
ChatMessage,
|
|
15587
|
-
ChatPage,
|
|
15588
13115
|
Checkbox,
|
|
15589
13116
|
ChipFilter,
|
|
15590
13117
|
ChipNode,
|
|
15591
|
-
Citation,
|
|
15592
13118
|
ClearHoverButton,
|
|
15593
13119
|
CodeBlock,
|
|
15594
13120
|
Col,
|
|
@@ -15596,11 +13122,9 @@ function createComponentRegistry() {
|
|
|
15596
13122
|
ColorPicker,
|
|
15597
13123
|
Combobox,
|
|
15598
13124
|
Command,
|
|
15599
|
-
Composer,
|
|
15600
13125
|
Container,
|
|
15601
13126
|
Content,
|
|
15602
13127
|
ContextMenu,
|
|
15603
|
-
ConversationList,
|
|
15604
13128
|
DataTable,
|
|
15605
13129
|
DatePicker,
|
|
15606
13130
|
Descriptions,
|
|
@@ -15641,7 +13165,6 @@ function createComponentRegistry() {
|
|
|
15641
13165
|
Menu,
|
|
15642
13166
|
Menubar,
|
|
15643
13167
|
Message,
|
|
15644
|
-
MessageList,
|
|
15645
13168
|
NavigationMenu,
|
|
15646
13169
|
Notification,
|
|
15647
13170
|
NumberInput,
|
|
@@ -15650,7 +13173,6 @@ function createComponentRegistry() {
|
|
|
15650
13173
|
Popconfirm,
|
|
15651
13174
|
Popover,
|
|
15652
13175
|
Progress,
|
|
15653
|
-
Prompt,
|
|
15654
13176
|
QRCode,
|
|
15655
13177
|
RadioGroup,
|
|
15656
13178
|
RailTooltip,
|
|
@@ -15662,7 +13184,6 @@ function createComponentRegistry() {
|
|
|
15662
13184
|
ScrollArea,
|
|
15663
13185
|
Segmented,
|
|
15664
13186
|
Select,
|
|
15665
|
-
Sender,
|
|
15666
13187
|
Separator,
|
|
15667
13188
|
Sheet,
|
|
15668
13189
|
Sidebar,
|
|
@@ -15675,21 +13196,16 @@ function createComponentRegistry() {
|
|
|
15675
13196
|
Statistic,
|
|
15676
13197
|
Status,
|
|
15677
13198
|
Steps,
|
|
15678
|
-
StepsPanel,
|
|
15679
|
-
StreamingText,
|
|
15680
|
-
Suggestion,
|
|
15681
13199
|
Switch,
|
|
15682
13200
|
Table,
|
|
15683
13201
|
Tabs,
|
|
15684
13202
|
Tag,
|
|
15685
13203
|
Text,
|
|
15686
13204
|
Textarea,
|
|
15687
|
-
Thinking,
|
|
15688
13205
|
TimePicker,
|
|
15689
13206
|
Timeline,
|
|
15690
13207
|
Toggle,
|
|
15691
13208
|
ToggleGroup,
|
|
15692
|
-
ToolCall,
|
|
15693
13209
|
Tooltip,
|
|
15694
13210
|
Tour,
|
|
15695
13211
|
Transfer,
|
|
@@ -15699,8 +13215,6 @@ function createComponentRegistry() {
|
|
|
15699
13215
|
Upload,
|
|
15700
13216
|
Video,
|
|
15701
13217
|
Watermark,
|
|
15702
|
-
Welcome,
|
|
15703
|
-
buildArtifactTree,
|
|
15704
13218
|
builtinComponents,
|
|
15705
13219
|
createComponentRegistry,
|
|
15706
13220
|
diffLines,
|
|
@@ -15708,5 +13222,6 @@ function createComponentRegistry() {
|
|
|
15708
13222
|
normalizeIconName,
|
|
15709
13223
|
registerBuiltinComponents,
|
|
15710
13224
|
useFormContext,
|
|
13225
|
+
useOptionalRenderer,
|
|
15711
13226
|
useSidebarDrawer
|
|
15712
13227
|
});
|