@xto/chat 1.0.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/es/index.mjs ADDED
@@ -0,0 +1,682 @@
1
+ import { defineComponent as b, computed as $, watch as A, openBlock as a, createElementBlock as i, ref as x, createElementVNode as n, toDisplayString as g, Fragment as M, renderList as S, createCommentVNode as m, normalizeClass as B, createBlock as F, withDirectives as V, vModelText as K, nextTick as I, createVNode as D, withModifiers as L, onBeforeUnmount as G } from "vue";
2
+ import J from "markdown-it";
3
+ import U from "highlight.js";
4
+ import z from "dompurify";
5
+ import W from "dayjs";
6
+ const P = ["innerHTML"], H = /* @__PURE__ */ b({
7
+ name: "XMarkdownRenderer",
8
+ __name: "index",
9
+ props: {
10
+ content: { default: "" },
11
+ enableHighlight: { type: Boolean, default: !0 }
12
+ },
13
+ setup(e) {
14
+ const o = e, c = $(() => {
15
+ const t = new J({
16
+ html: !1,
17
+ linkify: !0,
18
+ breaks: !0,
19
+ highlight(l, s) {
20
+ if (s && o.enableHighlight && U.getLanguage(s))
21
+ try {
22
+ return `<pre class="hljs"><code>${U.highlight(l, { language: s }).value}</code></pre>`;
23
+ } catch {
24
+ }
25
+ return `<pre class="hljs"><code>${t.utils.escapeHtml(l)}</code></pre>`;
26
+ }
27
+ });
28
+ return t;
29
+ }), u = $(() => {
30
+ if (!o.content) return "";
31
+ const t = c.value.render(o.content);
32
+ return z.sanitize(t, {
33
+ ADD_ATTR: ["target"],
34
+ ALLOWED_TAGS: z.config.ALLOWED_TAGS
35
+ });
36
+ });
37
+ return A(u, () => {
38
+ }), (t, l) => (a(), i("div", {
39
+ class: "x-markdown-renderer",
40
+ innerHTML: u.value
41
+ }, null, 8, P));
42
+ }
43
+ }), Y = { class: "x-thinking-chain" }, Z = { class: "x-thinking-chain__title" }, ee = { class: "x-thinking-chain__toggle" }, se = {
44
+ key: 0,
45
+ class: "x-thinking-chain__steps"
46
+ }, te = {
47
+ key: 0,
48
+ class: "x-thinking-chain__field"
49
+ }, ae = { class: "x-thinking-chain__value" }, ne = {
50
+ key: 1,
51
+ class: "x-thinking-chain__field"
52
+ }, le = { class: "x-thinking-chain__value x-thinking-chain__value--action" }, oe = {
53
+ key: 2,
54
+ class: "x-thinking-chain__field"
55
+ }, ie = { class: "x-thinking-chain__value" }, ce = {
56
+ key: 3,
57
+ class: "x-thinking-chain__field"
58
+ }, ue = { class: "x-thinking-chain__value" }, X = /* @__PURE__ */ b({
59
+ name: "XThinkingChain",
60
+ __name: "index",
61
+ props: {
62
+ steps: { default: () => [] },
63
+ collapsed: { type: Boolean, default: !1 }
64
+ },
65
+ setup(e) {
66
+ const o = e, c = x(o.collapsed), u = () => {
67
+ c.value = !c.value;
68
+ }, t = $(() => o.steps.length);
69
+ return (l, s) => (a(), i("div", Y, [
70
+ n("div", {
71
+ class: "x-thinking-chain__header",
72
+ onClick: u
73
+ }, [
74
+ s[0] || (s[0] = n("span", { class: "x-thinking-chain__icon" }, "🧠", -1)),
75
+ n("span", Z, "思维链 (" + g(t.value) + " 步)", 1),
76
+ n("span", ee, g(c.value ? "▶" : "▼"), 1)
77
+ ]),
78
+ c.value ? m("", !0) : (a(), i("div", se, [
79
+ (a(!0), i(M, null, S(e.steps, (d, f) => (a(), i("div", {
80
+ key: f,
81
+ class: "x-thinking-chain__step"
82
+ }, [
83
+ d.thought ? (a(), i("div", te, [
84
+ s[1] || (s[1] = n("span", { class: "x-thinking-chain__label" }, "Thought:", -1)),
85
+ n("span", ae, g(d.thought), 1)
86
+ ])) : m("", !0),
87
+ d.action ? (a(), i("div", ne, [
88
+ s[2] || (s[2] = n("span", { class: "x-thinking-chain__label" }, "Action:", -1)),
89
+ n("span", le, g(d.action), 1)
90
+ ])) : m("", !0),
91
+ d.actionInput ? (a(), i("div", oe, [
92
+ s[3] || (s[3] = n("span", { class: "x-thinking-chain__label" }, "Action Input:", -1)),
93
+ n("span", ie, g(d.actionInput), 1)
94
+ ])) : m("", !0),
95
+ d.observation ? (a(), i("div", ce, [
96
+ s[4] || (s[4] = n("span", { class: "x-thinking-chain__label" }, "Observation:", -1)),
97
+ n("span", ue, g(d.observation), 1)
98
+ ])) : m("", !0)
99
+ ]))), 128))
100
+ ]))
101
+ ]));
102
+ }
103
+ }), de = {
104
+ key: 0,
105
+ class: "x-tool-call-display"
106
+ }, re = ["onClick"], me = { class: "x-tool-call-display__name" }, ge = {
107
+ key: 0,
108
+ class: "x-tool-call-display__time"
109
+ }, he = { class: "x-tool-call-display__toggle" }, _e = {
110
+ key: 0,
111
+ class: "x-tool-call-display__body"
112
+ }, fe = {
113
+ key: 0,
114
+ class: "x-tool-call-display__section"
115
+ }, ve = { class: "x-tool-call-display__code" }, pe = {
116
+ key: 1,
117
+ class: "x-tool-call-display__section"
118
+ }, xe = { class: "x-tool-call-display__code" }, ke = {
119
+ key: 2,
120
+ class: "x-tool-call-display__error"
121
+ }, E = /* @__PURE__ */ b({
122
+ name: "XToolCallDisplay",
123
+ __name: "index",
124
+ props: {
125
+ toolCalls: { default: () => [] }
126
+ },
127
+ setup(e) {
128
+ const o = x(/* @__PURE__ */ new Set()), c = (t) => {
129
+ o.value.has(t) ? o.value.delete(t) : o.value.add(t);
130
+ }, u = (t) => o.value.has(t);
131
+ return (t, l) => e.toolCalls.length ? (a(), i("div", de, [
132
+ (a(!0), i(M, null, S(e.toolCalls, (s, d) => (a(), i("div", {
133
+ key: d,
134
+ class: "x-tool-call-display__item"
135
+ }, [
136
+ n("div", {
137
+ class: "x-tool-call-display__header",
138
+ onClick: (f) => c(d)
139
+ }, [
140
+ l[0] || (l[0] = n("span", { class: "x-tool-call-display__icon" }, "🔧", -1)),
141
+ n("span", me, g(s.name), 1),
142
+ n("span", {
143
+ class: B(["x-tool-call-display__status", `x-tool-call-display__status--${s.success ? "success" : "failed"}`])
144
+ }, g(s.success === !1 ? "失败" : "成功"), 3),
145
+ s.elapsedMs ? (a(), i("span", ge, g(s.elapsedMs) + "ms", 1)) : m("", !0),
146
+ n("span", he, g(u(d) ? "▼" : "▶"), 1)
147
+ ], 8, re),
148
+ u(d) ? (a(), i("div", _e, [
149
+ s.arguments ? (a(), i("div", fe, [
150
+ l[1] || (l[1] = n("div", { class: "x-tool-call-display__label" }, "参数:", -1)),
151
+ n("pre", ve, g(JSON.stringify(s.arguments, null, 2)), 1)
152
+ ])) : m("", !0),
153
+ s.result !== void 0 ? (a(), i("div", pe, [
154
+ l[2] || (l[2] = n("div", { class: "x-tool-call-display__label" }, "结果:", -1)),
155
+ n("pre", xe, g(typeof s.result == "string" ? s.result : JSON.stringify(s.result, null, 2)), 1)
156
+ ])) : m("", !0),
157
+ s.errorMessage ? (a(), i("div", ke, g(s.errorMessage), 1)) : m("", !0)
158
+ ])) : m("", !0)
159
+ ]))), 128))
160
+ ])) : m("", !0);
161
+ }
162
+ }), ye = { class: "x-feedback-buttons" }, O = /* @__PURE__ */ b({
163
+ name: "XFeedbackButtons",
164
+ __name: "index",
165
+ props: {
166
+ current: { default: null }
167
+ },
168
+ emits: ["feedback"],
169
+ setup(e, { emit: o }) {
170
+ const c = o;
171
+ return (u, t) => (a(), i("div", ye, [
172
+ n("button", {
173
+ class: B(["x-feedback-buttons__btn", { "x-feedback-buttons__btn--active": e.current === "like" }]),
174
+ onClick: t[0] || (t[0] = (l) => c("feedback", "like"))
175
+ }, "👍", 2),
176
+ n("button", {
177
+ class: B(["x-feedback-buttons__btn", { "x-feedback-buttons__btn--active": e.current === "dislike" }]),
178
+ onClick: t[1] || (t[1] = (l) => c("feedback", "dislike"))
179
+ }, "👎", 2)
180
+ ]));
181
+ }
182
+ }), be = {
183
+ key: 0,
184
+ class: "x-message-item__avatar"
185
+ }, $e = { key: 0 }, we = { key: 1 }, Ce = { key: 2 }, Be = { class: "x-message-item__body" }, Me = {
186
+ key: 0,
187
+ class: "x-message-item__meta"
188
+ }, Se = { class: "x-message-item__time" }, Te = {
189
+ key: 0,
190
+ class: "x-message-item__latency"
191
+ }, Fe = {
192
+ key: 1,
193
+ class: "x-message-item__tokens"
194
+ }, De = { class: "x-message-item__content" }, Le = {
195
+ key: 3,
196
+ class: "x-message-item__cursor"
197
+ }, Q = /* @__PURE__ */ b({
198
+ name: "XMessageItem",
199
+ __name: "index",
200
+ props: {
201
+ message: {},
202
+ showAvatar: { type: Boolean, default: !0 },
203
+ showTimestamp: { type: Boolean, default: !0 },
204
+ showFeedback: { type: Boolean, default: !0 }
205
+ },
206
+ emits: ["feedback"],
207
+ setup(e, { emit: o }) {
208
+ const c = e, u = o, t = $(() => c.message.role === "user"), l = $(() => c.message.role === "assistant"), s = $(() => c.message.timestamp ? W(c.message.timestamp).format("HH:mm:ss") : ""), d = (f) => {
209
+ c.message.id && u("feedback", c.message.id, f);
210
+ };
211
+ return (f, h) => {
212
+ var p, k;
213
+ return a(), i("div", {
214
+ class: B(["x-message-item", `x-message-item--${e.message.role}`])
215
+ }, [
216
+ e.showAvatar ? (a(), i("div", be, [
217
+ t.value ? (a(), i("span", $e, "U")) : l.value ? (a(), i("span", we, "AI")) : (a(), i("span", Ce, "S"))
218
+ ])) : m("", !0),
219
+ n("div", Be, [
220
+ e.showTimestamp ? (a(), i("div", Me, [
221
+ n("span", Se, g(s.value), 1),
222
+ e.message.latency ? (a(), i("span", Te, g((e.message.latency / 1e3).toFixed(2)) + "s", 1)) : m("", !0),
223
+ e.message.tokenUsage ? (a(), i("span", Fe, g(e.message.tokenUsage) + " tokens", 1)) : m("", !0)
224
+ ])) : m("", !0),
225
+ n("div", De, [
226
+ (p = e.message.thinkingChain) != null && p.length ? (a(), F(X, {
227
+ key: 0,
228
+ steps: e.message.thinkingChain
229
+ }, null, 8, ["steps"])) : m("", !0),
230
+ (k = e.message.toolCalls) != null && k.length ? (a(), F(E, {
231
+ key: 1,
232
+ "tool-calls": e.message.toolCalls
233
+ }, null, 8, ["tool-calls"])) : m("", !0),
234
+ e.message.content ? (a(), F(H, {
235
+ key: 2,
236
+ content: e.message.content
237
+ }, null, 8, ["content"])) : m("", !0),
238
+ e.message.status === "streaming" ? (a(), i("span", Le, "|")) : m("", !0)
239
+ ]),
240
+ e.showFeedback && l.value && e.message.status === "completed" ? (a(), F(O, {
241
+ key: 1,
242
+ current: e.message.feedback || null,
243
+ onFeedback: d
244
+ }, null, 8, ["current"])) : m("", !0)
245
+ ])
246
+ ], 2);
247
+ };
248
+ }
249
+ }), Ae = { class: "x-message-list" }, Ie = {
250
+ key: 0,
251
+ class: "x-message-list__loading"
252
+ }, q = /* @__PURE__ */ b({
253
+ name: "XMessageList",
254
+ __name: "index",
255
+ props: {
256
+ messages: { default: () => [] },
257
+ loading: { type: Boolean, default: !1 },
258
+ showAvatar: { type: Boolean, default: !0 },
259
+ showTimestamp: { type: Boolean, default: !0 },
260
+ showFeedback: { type: Boolean, default: !0 }
261
+ },
262
+ emits: ["feedback"],
263
+ setup(e, { emit: o }) {
264
+ const c = o, u = (t, l) => c("feedback", t, l);
265
+ return (t, l) => (a(), i("div", Ae, [
266
+ (a(!0), i(M, null, S(e.messages, (s) => (a(), F(Q, {
267
+ key: s.id || s.timestamp,
268
+ message: s,
269
+ "show-avatar": e.showAvatar,
270
+ "show-timestamp": e.showTimestamp,
271
+ "show-feedback": e.showFeedback,
272
+ onFeedback: u
273
+ }, null, 8, ["message", "show-avatar", "show-timestamp", "show-feedback"]))), 128)),
274
+ e.loading ? (a(), i("div", Ie, [...l[0] || (l[0] = [
275
+ n("span", { class: "x-message-list__dot" }, null, -1),
276
+ n("span", { class: "x-message-list__dot" }, null, -1),
277
+ n("span", { class: "x-message-list__dot" }, null, -1)
278
+ ])])) : m("", !0)
279
+ ]));
280
+ }
281
+ }), Ue = { class: "x-message-input" }, ze = {
282
+ key: 0,
283
+ class: "x-message-input__attachments"
284
+ }, He = { class: "x-message-input__attachment-name" }, Xe = ["onClick"], Ee = { class: "x-message-input__row" }, Oe = {
285
+ key: 0,
286
+ class: "x-message-input__upload"
287
+ }, Qe = ["placeholder", "disabled", "maxlength"], qe = { class: "x-message-input__actions" }, Ne = { class: "x-message-input__count" }, je = ["disabled"], N = /* @__PURE__ */ b({
288
+ name: "XMessageInput",
289
+ __name: "index",
290
+ props: {
291
+ placeholder: { default: "请输入消息..." },
292
+ maxLength: { default: 4e3 },
293
+ disabled: { type: Boolean, default: !1 },
294
+ loading: { type: Boolean, default: !1 },
295
+ enableFileUpload: { type: Boolean, default: !1 }
296
+ },
297
+ emits: ["send", "stop", "regenerate"],
298
+ setup(e, { emit: o }) {
299
+ const c = e, u = o, t = x(""), l = x(null), s = x([]), d = $(() => t.value.length), f = $(() => t.value.trim().length > 0 && !c.disabled), h = () => {
300
+ l.value && (l.value.style.height = "auto", l.value.style.height = Math.min(l.value.scrollHeight, 200) + "px");
301
+ }, p = () => {
302
+ h(), t.value.length > c.maxLength && (t.value = t.value.substring(0, c.maxLength));
303
+ }, k = () => {
304
+ f.value && (u("send", t.value.trim(), s.value.length ? s.value : void 0), t.value = "", s.value = [], I(() => h()));
305
+ }, w = (r) => {
306
+ r.key === "Enter" && !r.shiftKey && (r.preventDefault(), k());
307
+ }, C = (r) => {
308
+ const _ = r.target;
309
+ _.files && (s.value = [...s.value, ...Array.from(_.files)]);
310
+ }, v = (r) => {
311
+ s.value.splice(r, 1);
312
+ };
313
+ return (r, _) => (a(), i("div", Ue, [
314
+ s.value.length ? (a(), i("div", ze, [
315
+ (a(!0), i(M, null, S(s.value, (y, T) => (a(), i("div", {
316
+ key: T,
317
+ class: "x-message-input__attachment"
318
+ }, [
319
+ n("span", He, g(y.name), 1),
320
+ n("button", {
321
+ class: "x-message-input__attachment-remove",
322
+ onClick: (R) => v(T)
323
+ }, "×", 8, Xe)
324
+ ]))), 128))
325
+ ])) : m("", !0),
326
+ n("div", Ee, [
327
+ e.enableFileUpload ? (a(), i("label", Oe, [
328
+ n("input", {
329
+ type: "file",
330
+ multiple: "",
331
+ onChange: C
332
+ }, null, 32),
333
+ _[2] || (_[2] = n("span", null, "📎", -1))
334
+ ])) : m("", !0),
335
+ V(n("textarea", {
336
+ ref_key: "textareaRef",
337
+ ref: l,
338
+ "onUpdate:modelValue": _[0] || (_[0] = (y) => t.value = y),
339
+ placeholder: e.placeholder,
340
+ disabled: e.disabled,
341
+ maxlength: e.maxLength,
342
+ class: "x-message-input__textarea",
343
+ rows: "1",
344
+ onInput: p,
345
+ onKeydown: w
346
+ }, null, 40, Qe), [
347
+ [K, t.value]
348
+ ]),
349
+ n("div", qe, [
350
+ n("span", Ne, g(d.value) + "/" + g(e.maxLength), 1),
351
+ e.loading ? (a(), i("button", {
352
+ key: 0,
353
+ class: "x-message-input__btn x-message-input__btn--stop",
354
+ onClick: _[1] || (_[1] = (y) => u("stop"))
355
+ }, "停止")) : (a(), i("button", {
356
+ key: 1,
357
+ class: "x-message-input__btn x-message-input__btn--send",
358
+ disabled: !f.value,
359
+ onClick: k
360
+ }, "发送", 8, je))
361
+ ])
362
+ ])
363
+ ]));
364
+ }
365
+ }), Re = {
366
+ key: 0,
367
+ class: "x-suggested-questions"
368
+ }, Ve = { class: "x-suggested-questions__list" }, Ke = ["onClick"], j = /* @__PURE__ */ b({
369
+ name: "XSuggestedQuestions",
370
+ __name: "index",
371
+ props: {
372
+ questions: { default: () => [] }
373
+ },
374
+ emits: ["select"],
375
+ setup(e, { emit: o }) {
376
+ const c = o, u = (t) => c("select", t);
377
+ return (t, l) => e.questions.length ? (a(), i("div", Re, [
378
+ l[0] || (l[0] = n("div", { class: "x-suggested-questions__label" }, "推荐问题:", -1)),
379
+ n("div", Ve, [
380
+ (a(!0), i(M, null, S(e.questions, (s, d) => (a(), i("button", {
381
+ key: d,
382
+ class: "x-suggested-questions__item",
383
+ onClick: (f) => u(s)
384
+ }, g(s), 9, Ke))), 128))
385
+ ])
386
+ ])) : m("", !0);
387
+ }
388
+ });
389
+ function Ge(e) {
390
+ const o = x(!0);
391
+ let c = 0;
392
+ const u = () => {
393
+ if (!e.value) return;
394
+ const { scrollTop: s, scrollHeight: d, clientHeight: f } = e.value, h = d - s - f < 50;
395
+ s < c && !h ? o.value = !1 : h && (o.value = !0), c = s;
396
+ }, t = () => {
397
+ I(() => {
398
+ e.value && (e.value.scrollTop = e.value.scrollHeight);
399
+ });
400
+ }, l = () => {
401
+ o.value = !0, t();
402
+ };
403
+ return e.value && e.value.addEventListener("scroll", u), A(e, (s, d, f) => {
404
+ s && (s.addEventListener("scroll", u), f(() => s.removeEventListener("scroll", u)));
405
+ }), { autoScroll: o, scrollToBottom: t, enableAutoScroll: l };
406
+ }
407
+ const Je = { class: "x-chat-container__messages" }, We = {
408
+ key: 0,
409
+ class: "x-chat-container__suggested"
410
+ }, Pe = { class: "x-chat-container__input" }, Ye = /* @__PURE__ */ b({
411
+ name: "XChatContainer",
412
+ __name: "index",
413
+ props: {
414
+ messages: { default: () => [] },
415
+ loading: { type: Boolean, default: !1 },
416
+ readonly: { type: Boolean, default: !1 },
417
+ showAvatar: { type: Boolean, default: !0 },
418
+ showTimestamp: { type: Boolean, default: !0 },
419
+ showFeedback: { type: Boolean, default: !0 },
420
+ suggestedQuestions: { default: () => [] },
421
+ placeholder: { default: "请输入消息..." },
422
+ maxLength: { default: 4e3 },
423
+ enableFileUpload: { type: Boolean, default: !1 }
424
+ },
425
+ emits: ["send", "stop", "regenerate", "feedback", "selectQuestion"],
426
+ setup(e, { expose: o, emit: c }) {
427
+ const u = e, t = c, l = x(null), { autoScroll: s, scrollToBottom: d } = Ge(l), f = $(() => u.messages), h = (v, r) => t("send", v, r), p = () => t("stop"), k = () => t("regenerate"), w = (v, r) => t("feedback", v, r), C = (v) => t("selectQuestion", v);
428
+ return A(() => u.messages.length, () => {
429
+ s.value && I(() => d());
430
+ }), o({
431
+ clearMessages: () => t("send", "__clear__"),
432
+ scrollToBottom: d,
433
+ appendMessage: (v) => {
434
+ u.messages.push(v);
435
+ },
436
+ updateLastMessage: (v) => {
437
+ u.messages.length > 0 && (u.messages[u.messages.length - 1] = v);
438
+ }
439
+ }), (v, r) => (a(), i("div", {
440
+ ref_key: "containerRef",
441
+ ref: l,
442
+ class: "x-chat-container"
443
+ }, [
444
+ n("div", Je, [
445
+ D(q, {
446
+ messages: f.value,
447
+ loading: e.loading,
448
+ "show-avatar": e.showAvatar,
449
+ "show-timestamp": e.showTimestamp,
450
+ "show-feedback": e.showFeedback,
451
+ onFeedback: w
452
+ }, null, 8, ["messages", "loading", "show-avatar", "show-timestamp", "show-feedback"])
453
+ ]),
454
+ e.suggestedQuestions.length ? (a(), i("div", We, [
455
+ D(j, {
456
+ questions: e.suggestedQuestions,
457
+ onSelect: C
458
+ }, null, 8, ["questions"])
459
+ ])) : m("", !0),
460
+ n("div", Pe, [
461
+ D(N, {
462
+ placeholder: e.placeholder,
463
+ "max-length": e.maxLength,
464
+ disabled: e.loading || e.readonly,
465
+ "enable-file-upload": e.enableFileUpload,
466
+ onSend: h,
467
+ onStop: p,
468
+ onRegenerate: k,
469
+ loading: e.loading
470
+ }, null, 8, ["placeholder", "max-length", "disabled", "enable-file-upload", "loading"])
471
+ ])
472
+ ], 512));
473
+ }
474
+ }), Ze = { class: "x-code-block" }, es = { class: "x-code-block__header" }, ss = { class: "x-code-block__language" }, ts = { class: "x-code-block__pre" }, as = /* @__PURE__ */ b({
475
+ name: "XCodeBlock",
476
+ __name: "index",
477
+ props: {
478
+ code: {},
479
+ language: { default: "plaintext" },
480
+ showCopy: { type: Boolean, default: !0 }
481
+ },
482
+ setup(e) {
483
+ const o = e, c = x(!1), u = async () => {
484
+ try {
485
+ await navigator.clipboard.writeText(o.code), c.value = !0, setTimeout(() => {
486
+ c.value = !1;
487
+ }, 2e3);
488
+ } catch {
489
+ }
490
+ };
491
+ return (t, l) => (a(), i("div", Ze, [
492
+ n("div", es, [
493
+ n("span", ss, g(e.language), 1),
494
+ e.showCopy ? (a(), i("button", {
495
+ key: 0,
496
+ class: "x-code-block__copy",
497
+ onClick: u
498
+ }, g(c.value ? "已复制" : "复制"), 1)) : m("", !0)
499
+ ]),
500
+ n("pre", ts, [
501
+ n("code", {
502
+ class: B(`language-${e.language}`)
503
+ }, g(e.code), 3)
504
+ ])
505
+ ]));
506
+ }
507
+ }), ns = { class: "x-file-upload" }, ls = ["accept", "multiple"], os = { class: "x-file-upload__hint" }, is = { class: "x-file-upload__max" }, cs = {
508
+ key: 0,
509
+ class: "x-file-upload__list"
510
+ }, us = { class: "x-file-upload__name" }, ds = { class: "x-file-upload__size" }, rs = ["onClick"], ms = /* @__PURE__ */ b({
511
+ name: "XFileUpload",
512
+ __name: "index",
513
+ props: {
514
+ accept: { default: "" },
515
+ multiple: { type: Boolean, default: !0 },
516
+ maxSize: { default: 50 }
517
+ },
518
+ emits: ["change", "exceed"],
519
+ setup(e, { expose: o, emit: c }) {
520
+ const u = e, t = c, l = x([]), s = x(!1), d = (r) => r < 1024 ? r + "B" : r < 1024 * 1024 ? (r / 1024).toFixed(1) + "KB" : (r / 1024 / 1024).toFixed(1) + "MB", f = (r) => {
521
+ if (!r) return;
522
+ const _ = [];
523
+ for (const y of Array.from(r)) {
524
+ if (y.size > u.maxSize * 1024 * 1024) {
525
+ t("exceed", y);
526
+ continue;
527
+ }
528
+ _.push(y);
529
+ }
530
+ u.multiple ? l.value = [...l.value, ..._] : l.value = _, t("change", l.value);
531
+ }, h = (r) => {
532
+ const _ = r.target;
533
+ f(_.files);
534
+ }, p = (r) => {
535
+ var _;
536
+ s.value = !1, (_ = r.dataTransfer) != null && _.files && f(r.dataTransfer.files);
537
+ }, k = () => {
538
+ s.value = !0;
539
+ }, w = () => {
540
+ s.value = !1;
541
+ }, C = (r) => {
542
+ l.value.splice(r, 1), t("change", l.value);
543
+ };
544
+ return o({ files: l, clear: () => {
545
+ l.value = [], t("change", l.value);
546
+ } }), (r, _) => (a(), i("div", ns, [
547
+ n("div", {
548
+ class: B(["x-file-upload__dropzone", { "x-file-upload__dropzone--active": s.value }]),
549
+ onDrop: L(p, ["prevent"]),
550
+ onDragover: L(k, ["prevent"]),
551
+ onDragleave: L(w, ["prevent"])
552
+ }, [
553
+ n("input", {
554
+ type: "file",
555
+ accept: e.accept,
556
+ multiple: e.multiple,
557
+ onChange: h
558
+ }, null, 40, ls),
559
+ n("div", os, [
560
+ _[0] || (_[0] = n("span", null, "📎 拖拽文件到此处,或点击选择", -1)),
561
+ n("span", is, "最大 " + g(e.maxSize) + "MB", 1)
562
+ ])
563
+ ], 34),
564
+ l.value.length ? (a(), i("div", cs, [
565
+ (a(!0), i(M, null, S(l.value, (y, T) => (a(), i("div", {
566
+ key: T,
567
+ class: "x-file-upload__item"
568
+ }, [
569
+ n("span", us, g(y.name), 1),
570
+ n("span", ds, g(d(y.size)), 1),
571
+ n("button", {
572
+ class: "x-file-upload__remove",
573
+ onClick: (R) => C(T)
574
+ }, "×", 8, rs)
575
+ ]))), 128))
576
+ ])) : m("", !0)
577
+ ]));
578
+ }
579
+ });
580
+ function xs(e) {
581
+ const o = x([]), c = x(!1), u = x(null);
582
+ return { messages: o, loading: c, error: u, send: async (d) => {
583
+ if (!d.trim() || c.value) return;
584
+ const f = {
585
+ id: `user-${Date.now()}`,
586
+ role: "user",
587
+ content: d,
588
+ status: "completed",
589
+ timestamp: Date.now()
590
+ };
591
+ o.value.push(f);
592
+ const h = {
593
+ id: `assistant-${Date.now()}`,
594
+ role: "assistant",
595
+ content: "",
596
+ status: "pending",
597
+ timestamp: Date.now()
598
+ };
599
+ o.value.push(h), c.value = !0, u.value = null;
600
+ try {
601
+ if (e != null && e.sendMessage) {
602
+ const p = await e.sendMessage(d);
603
+ if (p instanceof ReadableStream) {
604
+ const k = p.getReader();
605
+ let w = "";
606
+ for (; ; ) {
607
+ const { done: C, value: v } = await k.read();
608
+ if (C) break;
609
+ v && (w += v.content || "", h.content = w, h.status = "streaming");
610
+ }
611
+ h.status = "completed";
612
+ } else
613
+ Object.assign(h, p), h.status = "completed";
614
+ } else
615
+ h.content = "No sendMessage handler configured.", h.status = "failed";
616
+ } catch (p) {
617
+ h.status = "failed", h.content = `Error: ${p.message || "Unknown error"}`, u.value = p.message;
618
+ } finally {
619
+ c.value = !1;
620
+ }
621
+ }, stop: () => {
622
+ c.value = !1;
623
+ const d = o.value[o.value.length - 1];
624
+ d && d.status === "streaming" && (d.status = "completed");
625
+ }, clear: () => {
626
+ o.value = [], u.value = null;
627
+ } };
628
+ }
629
+ function ks() {
630
+ const e = x(!1);
631
+ let o = null;
632
+ const c = (t, l, s) => {
633
+ u(), o = new EventSource(t), e.value = !0, o.onmessage = (d) => {
634
+ l(d.data);
635
+ }, o.onerror = (d) => {
636
+ e.value = !1, s == null || s(d);
637
+ }, o.onopen = () => {
638
+ e.value = !0;
639
+ };
640
+ }, u = () => {
641
+ o && (o.close(), o = null, e.value = !1);
642
+ };
643
+ return G(() => {
644
+ u();
645
+ }), { isConnected: e, connect: c, disconnect: u };
646
+ }
647
+ const gs = {
648
+ ChatContainer: Ye,
649
+ MessageList: q,
650
+ MessageItem: Q,
651
+ MessageInput: N,
652
+ ThinkingChain: X,
653
+ ToolCallDisplay: E,
654
+ MarkdownRenderer: H,
655
+ CodeBlock: as,
656
+ SuggestedQuestions: j,
657
+ FileUpload: ms,
658
+ FeedbackButtons: O
659
+ }, ys = {
660
+ install(e) {
661
+ Object.entries(gs).forEach(([o, c]) => {
662
+ e.component(o, c);
663
+ });
664
+ }
665
+ };
666
+ export {
667
+ Ye as ChatContainer,
668
+ as as CodeBlock,
669
+ O as FeedbackButtons,
670
+ ms as FileUpload,
671
+ H as MarkdownRenderer,
672
+ N as MessageInput,
673
+ Q as MessageItem,
674
+ q as MessageList,
675
+ j as SuggestedQuestions,
676
+ X as ThinkingChain,
677
+ E as ToolCallDisplay,
678
+ ys as default,
679
+ Ge as useAutoScroll,
680
+ xs as useChat,
681
+ ks as useSSE
682
+ };