@touchvue/chat 1.0.0-beta.29 → 1.0.0-beta.30

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.
Files changed (37) hide show
  1. package/es/package.json.mjs +1 -1
  2. package/es/packages/components/touchchat/component/ModuleSelect.vue2.mjs.map +1 -1
  3. package/es/packages/components/touchchat/src/AiChat/ChatInput.vue2.mjs +17 -18
  4. package/es/packages/components/touchchat/src/AiChat/ChatInput.vue2.mjs.map +1 -1
  5. package/es/packages/components/touchchat/src/AiChat/TouchAgent.vue.mjs +7 -0
  6. package/es/packages/components/touchchat/src/AiChat/TouchAgent.vue.mjs.map +1 -0
  7. package/es/packages/components/touchchat/src/AiChat/TouchAgent.vue2.mjs +929 -0
  8. package/es/packages/components/touchchat/src/AiChat/TouchAgent.vue2.mjs.map +1 -0
  9. package/es/packages/components/touchchat/src/AiChat/TouchChat.vue2.mjs +23 -19
  10. package/es/packages/components/touchchat/src/AiChat/TouchChat.vue2.mjs.map +1 -1
  11. package/es/packages/components/touchchat/src/AiChat/TouchHistory.vue2.mjs +74 -3
  12. package/es/packages/components/touchchat/src/AiChat/TouchHistory.vue2.mjs.map +1 -1
  13. package/es/packages/components/touchchat/src/index.vue2.mjs +32 -2
  14. package/es/packages/components/touchchat/src/index.vue2.mjs.map +1 -1
  15. package/es/packages/components/touchchat/src/types/a2a.mjs +11 -0
  16. package/es/packages/components/touchchat/src/types/a2a.mjs.map +1 -0
  17. package/es/packages/components/touchchat/utils/a2aService.mjs +292 -0
  18. package/es/packages/components/touchchat/utils/a2aService.mjs.map +1 -0
  19. package/lib/package.json.js +1 -1
  20. package/lib/packages/components/touchchat/component/ModuleSelect.vue2.js.map +1 -1
  21. package/lib/packages/components/touchchat/src/AiChat/ChatInput.vue2.js +16 -17
  22. package/lib/packages/components/touchchat/src/AiChat/ChatInput.vue2.js.map +1 -1
  23. package/lib/packages/components/touchchat/src/AiChat/TouchAgent.vue.js +11 -0
  24. package/lib/packages/components/touchchat/src/AiChat/TouchAgent.vue.js.map +1 -0
  25. package/lib/packages/components/touchchat/src/AiChat/TouchAgent.vue2.js +933 -0
  26. package/lib/packages/components/touchchat/src/AiChat/TouchAgent.vue2.js.map +1 -0
  27. package/lib/packages/components/touchchat/src/AiChat/TouchChat.vue2.js +23 -19
  28. package/lib/packages/components/touchchat/src/AiChat/TouchChat.vue2.js.map +1 -1
  29. package/lib/packages/components/touchchat/src/AiChat/TouchHistory.vue2.js +73 -2
  30. package/lib/packages/components/touchchat/src/AiChat/TouchHistory.vue2.js.map +1 -1
  31. package/lib/packages/components/touchchat/src/index.vue2.js +32 -2
  32. package/lib/packages/components/touchchat/src/index.vue2.js.map +1 -1
  33. package/lib/packages/components/touchchat/src/types/a2a.js +13 -0
  34. package/lib/packages/components/touchchat/src/types/a2a.js.map +1 -0
  35. package/lib/packages/components/touchchat/utils/a2aService.js +295 -0
  36. package/lib/packages/components/touchchat/utils/a2aService.js.map +1 -0
  37. package/package.json +1 -1
@@ -0,0 +1,933 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var vue = require('vue');
6
+ var UserMessage = require('./UserMessage.vue.js');
7
+ var AiMessage = require('./AiMessage.vue.js');
8
+ var ChatInput = require('./ChatInput.vue.js');
9
+ var HelloChat = require('../../component/HelloChat.vue.js');
10
+ var index = require('../../../../../node_modules/.pnpm/throttle-debounce@5.0.2/node_modules/throttle-debounce/esm/index.js');
11
+ var markdown = require('../../utils/markdown.js');
12
+ var tools = require('../../utils/tools.js');
13
+ var TouchChat = require('./Chat/TouchChat.js');
14
+ var a2aService = require('../../utils/a2aService.js');
15
+
16
+ const MULTI_AGENT_HOST = "/mas/host_agent";
17
+ var _sfc_main = /* @__PURE__ */ vue.defineComponent({
18
+ __name: "TouchAgent",
19
+ props: {
20
+ value: {
21
+ type: Array,
22
+ default: () => []
23
+ }
24
+ },
25
+ emits: ["sendMessage", "toggleSidebar", "beforeSendMessage"],
26
+ setup(__props, { expose: __expose, emit: __emit }) {
27
+ const DEFAULT_AGENT = {
28
+ id: "agent-1",
29
+ name: "A2A Agent",
30
+ version: "1.0",
31
+ endpoint: "http://10.19.93.128:30015/engine/api/v1/a2a/7b8f4d0eeee643859a812a166c606b13/1.0",
32
+ authToken: "c09f1251-e979-4a1a-ac67-6a11a8ab49f7",
33
+ // endpoint: '/agent-api/Njd8NnwxfDUy',
34
+ // authToken: 'a7ef44a7-9e85-4989-a2eb-34ae4dc76b7a',
35
+ description: "Default A2A agent"
36
+ };
37
+ const agentConfigListRef = vue.inject("agentConfigList", vue.ref([]));
38
+ const iAgentConfigList = vue.ref(agentConfigListRef.value);
39
+ const selectedAgents = vue.ref(["agent-1"]);
40
+ const availableAgents = vue.ref(iAgentConfigList.value || [DEFAULT_AGENT]);
41
+ vue.watch(
42
+ agentConfigListRef,
43
+ (newVal) => {
44
+ iAgentConfigList.value = newVal;
45
+ availableAgents.value = newVal || [DEFAULT_AGENT];
46
+ availableAgents.value.forEach((agent) => {
47
+ a2aService.a2aService.registerAgent(agent);
48
+ });
49
+ if (availableAgents.value.length > 0) {
50
+ selectedAgents.value = [availableAgents.value[0].id];
51
+ }
52
+ console.log("availableAgents === TouchAgent.vue === 119", availableAgents.value);
53
+ },
54
+ { immediate: true, deep: true }
55
+ );
56
+ const emit = __emit;
57
+ const afterSend = vue.inject("afterSend", () => {
58
+ console.warn("\u672A\u63D0\u4F9BafterSend\u51FD\u6570");
59
+ });
60
+ const sendMessageInject = vue.inject("send", () => {
61
+ console.warn("\u672A\u63D0\u4F9BhandleSend\u51FD\u6570");
62
+ });
63
+ const beforeSend = vue.inject("beforeSend", () => ({
64
+ result: true,
65
+ componentName: ""
66
+ }));
67
+ const bottom = vue.inject("bottom", () => {
68
+ console.warn("\u672A\u63D0\u4F9Bbottom\u51FD\u6570");
69
+ });
70
+ const props = __props;
71
+ const chatContainer = vue.ref(null);
72
+ const htmlContentRef = vue.ref([]);
73
+ const thinkingContentRef = vue.ref([]);
74
+ const reasoningContentRef = vue.ref([]);
75
+ const isMounted = vue.ref(false);
76
+ const isChating = vue.ref(false);
77
+ const inputValue = vue.ref("");
78
+ const chatList = vue.ref([]);
79
+ const currIndex = vue.ref(0);
80
+ const isUnmounting = vue.ref(false);
81
+ const currentComponentName = vue.ref("");
82
+ const fileData = vue.ref([]);
83
+ const ChatInputRef = vue.ref(null);
84
+ const isDragging = vue.ref(false);
85
+ const typeFlag = vue.ref("");
86
+ const renderQueue = vue.ref([]);
87
+ const isRendering = vue.ref(false);
88
+ const currentMessageProcessor = vue.ref(null);
89
+ const messageUtils = {
90
+ updateMessage: (index, updates) => {
91
+ if (index < 0 || index >= chatList.value.length)
92
+ return;
93
+ chatList.value.splice(index, 1, { ...chatList.value[index], ...updates });
94
+ vue.nextTick(() => {
95
+ const message = chatList.value[index];
96
+ if (message) {
97
+ renderContent(message.content, "main", index);
98
+ if (message.thinkContent) {
99
+ renderContent(message.thinkContent, "thinking", index);
100
+ }
101
+ if (message.reasoningContent) {
102
+ renderContent(message.reasoningContent, "reasoning", index);
103
+ }
104
+ }
105
+ });
106
+ },
107
+ deleteMessageChain: (index) => {
108
+ if (index < 0 || index >= chatList.value.length)
109
+ return;
110
+ if (chatList.value[index].user === "u") {
111
+ let deleteCount = 1;
112
+ for (let i = index + 1; i < chatList.value.length; i++) {
113
+ if (chatList.value[i].user === "ai") {
114
+ deleteCount++;
115
+ } else {
116
+ break;
117
+ }
118
+ }
119
+ chatList.value.splice(index, deleteCount);
120
+ } else {
121
+ chatList.value.splice(index, 1);
122
+ }
123
+ },
124
+ createStandardMessage: (data) => {
125
+ var _a, _b, _c, _d, _e;
126
+ return {
127
+ // chatId: data.chatId || 'ai_' + crypto.randomUUID().replace(/-/gi, ''),
128
+ chatId: data.chatId || "ai_" + Math.random().toString(36).slice(2).padEnd(10, "0").slice(0, 10),
129
+ user: data.user || "ai",
130
+ type: data.type || "text",
131
+ content: data.content || "",
132
+ isChating: (_a = data.isChating) != null ? _a : false,
133
+ thinkContent: data.thinkContent || "",
134
+ reasoningContent: data.reasoningContent || "",
135
+ isLiked: (_b = data.isLiked) != null ? _b : false,
136
+ isDisliked: (_c = data.isDisliked) != null ? _c : false,
137
+ isEditing: (_d = data.isEditing) != null ? _d : false,
138
+ editContent: (_e = data.editContent) != null ? _e : ""
139
+ };
140
+ }
141
+ };
142
+ const update = (index, message) => {
143
+ chatList.value[index] = { ...chatList.value[index], ...message };
144
+ console.log("update", chatList.value[index]);
145
+ };
146
+ const completeRendered = (chatId) => {
147
+ console.log("completeRendered", "\u6E32\u67D3\u5B8C\u6210", chatId);
148
+ if (currentMessageProcessor.value) {
149
+ currentMessageProcessor.value.handleMessageComplete(chatId);
150
+ }
151
+ };
152
+ const toggleSidebarClick = (item, index) => {
153
+ emit("toggleSidebar", item, index);
154
+ };
155
+ const init = () => {
156
+ try {
157
+ if (Array.isArray(props.value) && props.value.length) {
158
+ chatList.value = props.value.map((item) => ({
159
+ ...item,
160
+ content: item.thinkContent ? item.content || "" : item.content || "",
161
+ thinkContent: item.thinkContent || ""
162
+ }));
163
+ vue.nextTick(() => {
164
+ requestAnimationFrame(() => {
165
+ chatList.value.forEach((item) => {
166
+ if (item.thinkContent) {
167
+ renderContent(item.thinkContent, "thinking");
168
+ }
169
+ if (item.reasoningContent) {
170
+ renderContent(item.reasoningContent, "reasoning");
171
+ }
172
+ if (item.content) {
173
+ renderContent(item.content, "main");
174
+ }
175
+ });
176
+ vue.nextTick(() => {
177
+ scrollToBottom();
178
+ });
179
+ });
180
+ });
181
+ }
182
+ } catch (error) {
183
+ console.error("\u521D\u59CB\u5316\u5931\u8D25:", error);
184
+ }
185
+ };
186
+ const onScrollToBottom = () => {
187
+ bottom();
188
+ };
189
+ const throttledScrollToBottom = index.throttle(300, onScrollToBottom);
190
+ const handleScroll = () => {
191
+ if (!chatContainer.value)
192
+ return;
193
+ const { scrollTop, scrollHeight, clientHeight } = chatContainer.value;
194
+ if (scrollTop + clientHeight >= scrollHeight) {
195
+ throttledScrollToBottom();
196
+ }
197
+ };
198
+ const enqueueRender = (data) => {
199
+ if (isUnmounting.value || !isMounted.value)
200
+ return;
201
+ if (currIndex.value < 0 || currIndex.value >= chatList.value.length)
202
+ return;
203
+ renderQueue.value.push(data);
204
+ if (!isRendering.value) {
205
+ isRendering.value = true;
206
+ processRenderQueue();
207
+ }
208
+ };
209
+ const processRenderQueue = () => {
210
+ if (isUnmounting.value || !isMounted.value) {
211
+ renderQueue.value = [];
212
+ isRendering.value = false;
213
+ return;
214
+ }
215
+ if (renderQueue.value.length === 0) {
216
+ isRendering.value = false;
217
+ return;
218
+ }
219
+ requestAnimationFrame(() => {
220
+ const data = renderQueue.value.shift();
221
+ if (data) {
222
+ formatMarkdown(data);
223
+ }
224
+ processRenderQueue();
225
+ });
226
+ };
227
+ const formatMarkdown = (data) => {
228
+ if (!isMounted.value)
229
+ return;
230
+ if (currIndex.value < 0 || currIndex.value >= chatList.value.length)
231
+ return;
232
+ const currentItem = chatList.value[currIndex.value];
233
+ currentItem.thinkContent = data.thinkContent;
234
+ currentItem.content = data.mainContent;
235
+ currentItem.reasoningContent = data.reasoningContent;
236
+ vue.nextTick(() => {
237
+ const thinkingContainer = thinkingContentRef.value[currIndex.value];
238
+ if (thinkingContainer) {
239
+ if (data.thinkContent) {
240
+ renderContent(data.thinkContent, "thinking");
241
+ thinkingContainer.style.display = "block";
242
+ thinkingContainer.style.visibility = "visible";
243
+ } else {
244
+ thinkingContainer.style.display = "none";
245
+ thinkingContainer.style.visibility = "hidden";
246
+ }
247
+ }
248
+ const reasoningContainer = reasoningContentRef.value[currIndex.value];
249
+ if (reasoningContainer) {
250
+ if (data.reasoningContent) {
251
+ renderContent(data.reasoningContent, "reasoning");
252
+ reasoningContainer.style.display = "block";
253
+ reasoningContainer.style.visibility = "visible";
254
+ } else {
255
+ reasoningContainer.style.display = "none";
256
+ reasoningContainer.style.visibility = "hidden";
257
+ }
258
+ }
259
+ renderContent(data.mainContent, "main");
260
+ });
261
+ };
262
+ const generateMessageId = () => {
263
+ return `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
264
+ };
265
+ const createTextMessage = (text, role) => ({
266
+ messageId: generateMessageId(),
267
+ role,
268
+ parts: [{ type: "text", text }],
269
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
270
+ });
271
+ const randerAngentMessage = (fullResponseText, chatId) => {
272
+ if (chatList.value.some((ele) => ele.chatId === chatId)) {
273
+ enqueueRender({
274
+ mainContent: fullResponseText,
275
+ thinkContent: "",
276
+ reasoningContent: ""
277
+ });
278
+ }
279
+ };
280
+ const sendSingleAgentMessage = async (userContent, chatId) => {
281
+ var _a, _b, _c, _d, _e;
282
+ const agentMessage = createTextMessage(userContent, "user");
283
+ const agentId = selectedAgents.value[0];
284
+ const stream = await a2aService.a2aService.streamMessage(agentId, agentMessage);
285
+ let fullResponseText = "";
286
+ const reader = stream.getReader();
287
+ try {
288
+ let isDone = false;
289
+ while (!isDone) {
290
+ const { done, value: chunk } = await reader.read();
291
+ if (done) {
292
+ isDone = true;
293
+ break;
294
+ }
295
+ if (chunk.result) {
296
+ if ("artifact" in chunk.result) {
297
+ const artifact = chunk.result.artifact;
298
+ if (artifact && artifact.parts) {
299
+ const textParts = artifact.parts.filter((p) => p.kind === "text");
300
+ const newText = textParts.map((p) => p.text).join("");
301
+ fullResponseText += newText;
302
+ randerAngentMessage(fullResponseText, chatId);
303
+ }
304
+ }
305
+ if ("status" in chunk.result) {
306
+ const status = chunk.result.status;
307
+ if ((_a = status == null ? void 0 : status.message) == null ? void 0 : _a.parts) {
308
+ const textParts = status.message.parts.filter((p) => p.kind === "text");
309
+ const newText = textParts.map((p) => p.text).join("");
310
+ fullResponseText += newText;
311
+ randerAngentMessage(fullResponseText, chatId);
312
+ }
313
+ }
314
+ }
315
+ if ((_c = (_b = chunk.params) == null ? void 0 : _b.message) == null ? void 0 : _c.parts) {
316
+ const allParts = chunk.params.message.parts;
317
+ const textParts = allParts.filter((p) => p.type === "text" || p.kind === "text");
318
+ const newText = textParts.map((p) => p.text).join("");
319
+ fullResponseText += newText;
320
+ randerAngentMessage(fullResponseText, chatId);
321
+ }
322
+ if ((_d = chunk.params) == null ? void 0 : _d.status) {
323
+ console.log("Task status:", chunk.params.status);
324
+ }
325
+ if ((_e = chunk.params) == null ? void 0 : _e.artifact) {
326
+ console.log("Artifact received:", chunk.params.artifact);
327
+ }
328
+ }
329
+ } finally {
330
+ reader.releaseLock();
331
+ }
332
+ vue.nextTick(() => {
333
+ emit("sendMessage", [...chatList.value]);
334
+ });
335
+ isChating.value = false;
336
+ chatList.value[currIndex.value].isChating = false;
337
+ if (fullResponseText) {
338
+ afterSend({ allAiContent: fullResponseText });
339
+ }
340
+ };
341
+ const getSubAgents = () => {
342
+ return availableAgents.value.map((agent) => ({
343
+ agent_name: agent.agent_name,
344
+ agent_url: agent.agent_url,
345
+ headers: agent.headers
346
+ }));
347
+ };
348
+ const sendMultiAgentMessage = async (text, chatId) => {
349
+ var _a;
350
+ let fullResponseText = "";
351
+ try {
352
+ const userMessage = createTextMessage(text, "user");
353
+ const subAgents = getSubAgents();
354
+ const stream = a2aService.a2aService.streamMultiAgentMessage(MULTI_AGENT_HOST, subAgents, userMessage);
355
+ for await (const chunk of stream) {
356
+ if (chunk.result) {
357
+ if ("artifact" in chunk.result) {
358
+ const artifact = chunk.result.artifact;
359
+ if (artifact && artifact.parts) {
360
+ const textParts = artifact.parts.filter((p) => p.kind === "text");
361
+ const newText = textParts.map((p) => p.text).join("");
362
+ fullResponseText += newText;
363
+ randerAngentMessage(fullResponseText, chatId);
364
+ console.log("Multi-agent newText artifact", newText);
365
+ }
366
+ }
367
+ if ("status" in chunk.result) {
368
+ const status = chunk.result.status;
369
+ if ((_a = status == null ? void 0 : status.message) == null ? void 0 : _a.parts) {
370
+ const textParts = status.message.parts.filter((p) => p.kind === "text");
371
+ const newText = textParts.map((p) => p.text).join("");
372
+ console.log("Multi-agent newText status", newText);
373
+ fullResponseText += newText;
374
+ randerAngentMessage(fullResponseText, chatId);
375
+ }
376
+ }
377
+ }
378
+ }
379
+ const lastMessage = chatList.value[chatList.value.length - 1];
380
+ if (lastMessage && lastMessage.role === "agent") {
381
+ lastMessage.timestamp = (/* @__PURE__ */ new Date()).toISOString();
382
+ }
383
+ } catch (err) {
384
+ console.error("Error in multi-agent mode:", err);
385
+ const lastMessage = chatList.value[chatList.value.length - 1];
386
+ if (lastMessage && lastMessage.role === "agent") {
387
+ chatList.value.pop();
388
+ }
389
+ } finally {
390
+ }
391
+ vue.nextTick(() => {
392
+ emit("sendMessage", [...chatList.value]);
393
+ });
394
+ isChating.value = false;
395
+ chatList.value[currIndex.value].isChating = false;
396
+ if (fullResponseText) {
397
+ afterSend({ allAiContent: fullResponseText });
398
+ }
399
+ };
400
+ const openSSE = async (userContent, insertIndex) => {
401
+ try {
402
+ if (isUnmounting.value)
403
+ return;
404
+ isChating.value = true;
405
+ const currentAiMessage = chatList.value.find((item) => item.isChating);
406
+ if (currentAiMessage) {
407
+ currentAiMessage.isShowLike = true;
408
+ currentAiMessage.isShowCopy = true;
409
+ currentAiMessage.componentName = currentComponentName.value;
410
+ }
411
+ const chatId = (currentAiMessage == null ? void 0 : currentAiMessage.chatId) || "ai_" + Math.random().toString(36).slice(2).padEnd(10, "0").slice(0, 10);
412
+ if (!currentAiMessage) {
413
+ const chatItem = {
414
+ chatId,
415
+ user: "ai",
416
+ type: "text",
417
+ isChating: true,
418
+ content: "",
419
+ thinkContent: "",
420
+ reasoningContent: "",
421
+ thinkStatus: TouchChat.ThinkStatus.THINKING,
422
+ thinkStartTime: Date.now(),
423
+ isShowLike: true,
424
+ isShowCopy: true,
425
+ componentName: currentComponentName.value,
426
+ typeFlag: typeFlag.value
427
+ };
428
+ if (insertIndex !== void 0 && insertIndex <= chatList.value.length) {
429
+ chatList.value.splice(insertIndex, 0, chatItem);
430
+ } else {
431
+ chatList.value.push(chatItem);
432
+ }
433
+ }
434
+ currIndex.value = insertIndex != null ? insertIndex : chatList.value.length - 1;
435
+ if (availableAgents.value.length === 1) {
436
+ sendSingleAgentMessage(userContent, chatId);
437
+ } else {
438
+ sendMultiAgentMessage(userContent, chatId);
439
+ }
440
+ } catch (error) {
441
+ console.error("OpenSSE\u9519\u8BEF:", error);
442
+ isChating.value = false;
443
+ chatList.value[currIndex.value].content = `<div style="color: red; display: flex; align-items: center;"><svg xmlns="http://www.w3.org/2000/svg" width="15" height="16" viewBox="0 0 15 16" fill="none">
444
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M7.5 15.5C11.6421 15.5 15 12.1421 15 8C15 3.85786 11.6421 0.5 7.5 0.5C3.35786 0.5 0 3.85786 0 8C0 12.1421 3.35786 15.5 7.5 15.5ZM9.7539 4.9506L10.5494 5.7461L8.2951 8.0001L10.5494 10.2539L9.7539 11.0494L7.5001 8.7951L5.2461 11.0494L4.4506 10.2539L6.7051 8.0001L4.4506 5.7461L5.2461 4.9506L7.5001 7.2051L9.7539 4.9506Z" fill="#F93920"/>
445
+ </svg>${"\u8BF7\u6C42\u5931\u8D25"}</div>`;
446
+ chatList.value[currIndex.value].isChating = false;
447
+ chatList.value[currIndex.value].isShowCopy = false;
448
+ chatList.value[currIndex.value].isShowLike = false;
449
+ tools.showToast("\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5", "error", 3e3);
450
+ }
451
+ };
452
+ const attachCopyButtons = (container) => {
453
+ const codeBlocks = container.querySelectorAll("pre code");
454
+ codeBlocks.forEach((codeBlock) => {
455
+ const pre = codeBlock.parentElement;
456
+ if (pre) {
457
+ const copyBtn = document.createElement("button");
458
+ copyBtn.className = "touchchat-code-copy";
459
+ copyBtn.addEventListener("click", () => {
460
+ const code = codeBlock.textContent || "";
461
+ navigator.clipboard.writeText(code).then(() => {
462
+ tools.showToast("\u590D\u5236\u6210\u529F", "info", 2e3);
463
+ copyBtn.textContent = "\u5DF2\u590D\u5236";
464
+ setTimeout(() => {
465
+ copyBtn.textContent = "";
466
+ }, 2e3);
467
+ }).catch((err) => {
468
+ console.error("\u590D\u5236\u5931\u8D25:", err);
469
+ tools.showToast("\u590D\u5236\u5931\u8D25", "error", 2e3);
470
+ });
471
+ });
472
+ pre.style.position = "relative";
473
+ pre.appendChild(copyBtn);
474
+ }
475
+ });
476
+ };
477
+ const renderContent = (content, type, index) => {
478
+ const renderIndex = index != null ? index : currIndex.value;
479
+ if (renderIndex < 0 || renderIndex >= chatList.value.length)
480
+ return;
481
+ const refArrays = {
482
+ main: htmlContentRef,
483
+ thinking: thinkingContentRef,
484
+ reasoning: reasoningContentRef
485
+ };
486
+ const processors = {
487
+ main: (content2) => {
488
+ var _a;
489
+ return ((_a = markdown.default) == null ? void 0 : _a.render(content2, { isReasoning: false })) || "";
490
+ },
491
+ thinking: (content2) => {
492
+ var _a;
493
+ return ((_a = markdown.default) == null ? void 0 : _a.render(content2, { isReasoning: false })) || "";
494
+ },
495
+ reasoning: (content2) => {
496
+ var _a;
497
+ return ((_a = markdown.default) == null ? void 0 : _a.render(content2, { isReasoning: false })) || "";
498
+ }
499
+ };
500
+ const container = refArrays[type].value[renderIndex];
501
+ if (!container)
502
+ return;
503
+ container.innerHTML = processors[type](content || "");
504
+ attachCopyButtons(container);
505
+ };
506
+ const sendMessage = (content, fileList, auto, type) => {
507
+ inputValue.value = content || "";
508
+ handleBeforeSend(content, fileList, auto, type);
509
+ };
510
+ const handleBeforeSend = (content, fileList, auto, type) => {
511
+ fileData.value = fileList || [];
512
+ if (beforeSend) {
513
+ const fn = beforeSend();
514
+ if (fn && typeof fn.then === "function") {
515
+ Promise.resolve(fn).then((res) => {
516
+ if (res.result) {
517
+ currentComponentName.value = res.componentName || "";
518
+ handleSend(content, fileList, auto, type);
519
+ }
520
+ }).catch((error) => {
521
+ console.log(error);
522
+ });
523
+ } else {
524
+ if (fn.result) {
525
+ currentComponentName.value = fn.componentName || "";
526
+ handleSend(content, fileList, auto, type);
527
+ }
528
+ }
529
+ }
530
+ };
531
+ const handleSend = (content, fileList, auto, type) => {
532
+ emit("beforeSendMessage");
533
+ sendMessageInject(inputValue.value, fileData.value);
534
+ typeFlag.value = type || "";
535
+ if (content) {
536
+ inputValue.value = content;
537
+ }
538
+ if ((isChating.value || !inputValue.value.trim() && !(fileList == null ? void 0 : fileList.length)) && !auto)
539
+ return;
540
+ const userChatId = "user_" + Math.random().toString(36).slice(2).padEnd(10, "0").slice(0, 10);
541
+ const userMessage = {
542
+ chatId: userChatId,
543
+ user: "u",
544
+ type: "text",
545
+ content: inputValue.value,
546
+ files: fileList || []
547
+ };
548
+ chatList.value.push(userMessage);
549
+ const index = chatList.value.length - 1;
550
+ vue.nextTick(() => {
551
+ renderContent(userMessage.content, "main", index);
552
+ scrollToBottom();
553
+ });
554
+ openSSE(inputValue.value, index + 1);
555
+ inputValue.value = "";
556
+ };
557
+ const scrollObserver = vue.ref(null);
558
+ const scrollToBottom = () => {
559
+ if (!isMounted.value || isUnmounting.value || !chatContainer.value)
560
+ return;
561
+ vue.nextTick(() => {
562
+ requestAnimationFrame(() => {
563
+ const chatContainerEl = chatContainer.value;
564
+ const lastMessage = chatContainerEl.querySelector(".touchchat-dialog-content > *:last-child");
565
+ if (lastMessage) {
566
+ const { height: messageHeight } = lastMessage.getBoundingClientRect();
567
+ const containerHeight = chatContainerEl.clientHeight;
568
+ const messageBottom = lastMessage.offsetTop + lastMessage.offsetHeight;
569
+ if (messageHeight > containerHeight) {
570
+ chatContainerEl.scrollTop = lastMessage.offsetTop;
571
+ } else {
572
+ chatContainerEl.scrollTop = messageBottom - containerHeight;
573
+ }
574
+ if (scrollObserver.value) {
575
+ scrollObserver.value.disconnect();
576
+ }
577
+ scrollObserver.value = new MutationObserver(() => {
578
+ const updatedMessageBottom = lastMessage.offsetTop + lastMessage.offsetHeight;
579
+ chatContainerEl.scrollTop = Math.max(updatedMessageBottom - containerHeight, chatContainerEl.scrollTop);
580
+ });
581
+ scrollObserver.value.observe(lastMessage, {
582
+ childList: true,
583
+ subtree: true,
584
+ characterData: true,
585
+ attributes: true,
586
+ // 新增监听属性变化(如高度)
587
+ attributeFilter: ["style", "class"]
588
+ // 只监听样式相关属性
589
+ });
590
+ } else {
591
+ chatContainerEl.scrollTo({
592
+ top: chatContainerEl.scrollHeight,
593
+ behavior: "smooth"
594
+ });
595
+ }
596
+ });
597
+ });
598
+ };
599
+ const handleMessageAction = (action, index) => {
600
+ const message = chatList.value[index];
601
+ if (!message)
602
+ return;
603
+ switch (action) {
604
+ case TouchChat.MessageAction.COPY: {
605
+ const textContent = message.content;
606
+ navigator.clipboard.writeText(textContent).then(() => {
607
+ tools.showToast("\u590D\u5236\u6210\u529F", "info");
608
+ }).catch((err) => {
609
+ console.error("\u590D\u5236\u5931\u8D25:", err);
610
+ tools.showToast("\u590D\u5236\u5931\u8D25", "error");
611
+ });
612
+ break;
613
+ }
614
+ case TouchChat.MessageAction.EDIT:
615
+ message.isEditing = true;
616
+ message.editContent = message.content;
617
+ break;
618
+ case TouchChat.MessageAction.DELETE:
619
+ messageUtils.deleteMessageChain(index);
620
+ emit("sendMessage", chatList.value);
621
+ break;
622
+ case TouchChat.MessageAction.RETRY: {
623
+ const aiMessage = chatList.value[index];
624
+ const userMessageIndex = index - 1;
625
+ const userMessage = chatList.value[userMessageIndex];
626
+ if (userMessage && userMessage.user === "u") {
627
+ const updatedAiMessage = {
628
+ ...aiMessage,
629
+ content: "",
630
+ thinkContent: "",
631
+ reasoningContent: "",
632
+ isLiked: false,
633
+ isDisliked: false,
634
+ isChating: true,
635
+ chatId: aiMessage.chatId,
636
+ user: aiMessage.user,
637
+ type: aiMessage.type,
638
+ thinkStatus: TouchChat.ThinkStatus.COMPLETED,
639
+ thinkStartTime: 0,
640
+ thinkEndTime: 0
641
+ };
642
+ chatList.value.splice(index, 1, updatedAiMessage);
643
+ vue.nextTick(() => {
644
+ if (htmlContentRef.value[index])
645
+ htmlContentRef.value[index].innerHTML = "";
646
+ if (thinkingContentRef.value[index])
647
+ thinkingContentRef.value[index].innerHTML = "";
648
+ if (reasoningContentRef.value[index])
649
+ reasoningContentRef.value[index].innerHTML = "";
650
+ setTimeout(() => {
651
+ openSSE(userMessage.content || "", index);
652
+ }, 50);
653
+ });
654
+ }
655
+ break;
656
+ }
657
+ case TouchChat.MessageAction.LIKE:
658
+ messageUtils.updateMessage(index, {
659
+ isLiked: true,
660
+ isDisliked: false
661
+ });
662
+ break;
663
+ case TouchChat.MessageAction.DISLIKE:
664
+ messageUtils.updateMessage(index, {
665
+ isLiked: false,
666
+ isDisliked: true
667
+ });
668
+ break;
669
+ }
670
+ };
671
+ const saveEdit = (index, newContent) => {
672
+ const message = chatList.value[index];
673
+ if (!message || !message.editContent)
674
+ return;
675
+ chatList.value[index] = {
676
+ ...message,
677
+ content: newContent,
678
+ isEditing: false,
679
+ editContent: void 0
680
+ };
681
+ vue.nextTick(() => {
682
+ renderContent(message.content, "main", index);
683
+ });
684
+ if (index + 1 < chatList.value.length && chatList.value[index + 1].user === "ai") {
685
+ chatList.value.splice(index + 1, 1);
686
+ }
687
+ openSSE(newContent, index + 1);
688
+ emit("sendMessage", chatList.value);
689
+ };
690
+ const cancelEdit = (index) => {
691
+ const message = chatList.value[index];
692
+ if (!message)
693
+ return;
694
+ message.isEditing = false;
695
+ message.editContent = "";
696
+ vue.nextTick(() => {
697
+ renderContent(message.content, "main", index);
698
+ });
699
+ };
700
+ vue.onMounted(async () => {
701
+ if (isMounted.value) {
702
+ init();
703
+ }
704
+ isMounted.value = true;
705
+ availableAgents.value.forEach((agent) => {
706
+ a2aService.a2aService.registerAgent(agent);
707
+ });
708
+ if (availableAgents.value.length > 0) {
709
+ selectedAgents.value = [availableAgents.value[0].id];
710
+ }
711
+ });
712
+ vue.onBeforeUnmount(() => {
713
+ if (!isUnmounting.value) {
714
+ isUnmounting.value = true;
715
+ isMounted.value = false;
716
+ htmlContentRef.value = [];
717
+ thinkingContentRef.value = [];
718
+ reasoningContentRef.value = [];
719
+ }
720
+ if (scrollObserver.value) {
721
+ scrollObserver.value.disconnect();
722
+ scrollObserver.value = null;
723
+ }
724
+ });
725
+ const handleDragEnter = () => {
726
+ if (ChatInputRef.value) {
727
+ ChatInputRef.value.openMarkLayer();
728
+ }
729
+ isDragging.value = true;
730
+ };
731
+ const handleDragLeave = (e) => {
732
+ const rect = e.target.getBoundingClientRect();
733
+ if (e.clientX < rect.left || e.clientX > rect.right || e.clientY < rect.top || e.clientY > rect.bottom) {
734
+ isDragging.value = false;
735
+ }
736
+ };
737
+ const handleDrop = async (e) => {
738
+ var _a;
739
+ isDragging.value = false;
740
+ const files = (_a = e.dataTransfer) == null ? void 0 : _a.files;
741
+ if (files && files.length > 0) {
742
+ const fileList = await Promise.all(
743
+ Array.from(files).map(async (file) => {
744
+ let base64 = "";
745
+ if (file.type.startsWith("image/")) {
746
+ base64 = await new Promise((resolve) => {
747
+ const reader = new FileReader();
748
+ reader.onload = (e2) => {
749
+ var _a2;
750
+ resolve((_a2 = e2.target) == null ? void 0 : _a2.result);
751
+ };
752
+ reader.readAsDataURL(file);
753
+ });
754
+ }
755
+ return {
756
+ // id: crypto.randomUUID().replace(/-/gi, ''),
757
+ id: Math.random().toString(36).slice(2).padEnd(10, "0").slice(0, 10),
758
+ file,
759
+ name: file.name,
760
+ fileType: file.type,
761
+ fileSize: file.size,
762
+ lastModified: file.lastModified,
763
+ preview: URL.createObjectURL(file),
764
+ base64
765
+ };
766
+ })
767
+ );
768
+ if (ChatInputRef.value) {
769
+ ChatInputRef.value.handlePaste(fileList, "drop");
770
+ }
771
+ }
772
+ if (ChatInputRef.value) {
773
+ ChatInputRef.value.colseMarkLayer();
774
+ }
775
+ };
776
+ const itemUploadFile = (item, index) => {
777
+ console.log("itemUploadFile", item, index);
778
+ if (ChatInputRef.value) {
779
+ ChatInputRef.value.itemUploadFile(index, "drop");
780
+ }
781
+ };
782
+ vue.provide("touchchat", {
783
+ send: sendMessage,
784
+ retry: handleMessageAction
785
+ });
786
+ __expose({
787
+ send: (value, fileList, auto, type) => {
788
+ handleSend(value, fileList, auto, type);
789
+ },
790
+ retry: (index) => {
791
+ handleMessageAction(TouchChat.MessageAction.RETRY, index);
792
+ },
793
+ update
794
+ });
795
+ return (_ctx, _cache) => {
796
+ return vue.openBlock(), vue.createElementBlock("div", {
797
+ class: "touchchat-main",
798
+ onDragover: vue.withModifiers(() => {
799
+ }, ["prevent"]),
800
+ onDragenter: vue.withModifiers(handleDragEnter, ["prevent"]),
801
+ onDragleave: handleDragLeave,
802
+ onDrop: vue.withModifiers(handleDrop, ["prevent"])
803
+ }, [
804
+ vue.createElementVNode(
805
+ "div",
806
+ {
807
+ ref_key: "chatContainer",
808
+ ref: chatContainer,
809
+ class: "touchchat-dialog",
810
+ onScroll: handleScroll
811
+ },
812
+ [
813
+ vue.renderSlot(_ctx.$slots, "top"),
814
+ chatList.value.length === 0 ? (vue.openBlock(), vue.createElementBlock("div", {
815
+ key: 0,
816
+ class: "touchchat-welcome"
817
+ }, [
818
+ vue.renderSlot(_ctx.$slots, "welcome", {}, () => [
819
+ vue.createVNode(HelloChat.default, { onSendMessage: sendMessage })
820
+ ])
821
+ ])) : vue.createCommentVNode("v-if", true),
822
+ vue.createElementVNode("div", { class: "touchchat-dialog-content" }, [
823
+ (vue.openBlock(true), vue.createElementBlock(
824
+ vue.Fragment,
825
+ null,
826
+ vue.renderList(chatList.value, (item, index) => {
827
+ return vue.openBlock(), vue.createElementBlock(
828
+ vue.Fragment,
829
+ {
830
+ key: item.chatId
831
+ },
832
+ [
833
+ item.user === "u" ? (vue.openBlock(), vue.createBlock(UserMessage.default, {
834
+ key: 0,
835
+ item,
836
+ index,
837
+ onUserMessageFileList: itemUploadFile,
838
+ onCopy: ($event) => handleMessageAction(vue.unref(TouchChat.MessageAction).COPY, index),
839
+ onEdit: ($event) => handleMessageAction(vue.unref(TouchChat.MessageAction).EDIT, index),
840
+ onDelete: ($event) => handleMessageAction(vue.unref(TouchChat.MessageAction).DELETE, index),
841
+ onSaveEdit: saveEdit,
842
+ onCancelEdit: ($event) => cancelEdit(index)
843
+ }, {
844
+ userAvatar: vue.withCtx(() => [
845
+ vue.renderSlot(_ctx.$slots, "userAvatar")
846
+ ]),
847
+ fn: vue.withCtx(() => [
848
+ vue.renderSlot(_ctx.$slots, "fn", {
849
+ item,
850
+ index
851
+ })
852
+ ]),
853
+ _: 2
854
+ /* DYNAMIC */
855
+ }, 1032, ["item", "index", "onCopy", "onEdit", "onDelete", "onCancelEdit"])) : (vue.openBlock(), vue.createBlock(AiMessage.default, {
856
+ key: 1,
857
+ item,
858
+ index,
859
+ "has-retry": true,
860
+ onCopy: ($event) => handleMessageAction(vue.unref(TouchChat.MessageAction).COPY, index),
861
+ onRetry: ($event) => handleMessageAction(vue.unref(TouchChat.MessageAction).RETRY, index),
862
+ onLike: ($event) => handleMessageAction(vue.unref(TouchChat.MessageAction).LIKE, index),
863
+ onDislike: ($event) => handleMessageAction(vue.unref(TouchChat.MessageAction).DISLIKE, index),
864
+ onContentRendered: attachCopyButtons,
865
+ onCompleteRendered: (chatId) => completeRendered(chatId),
866
+ onToggleSidebar: toggleSidebarClick
867
+ }, {
868
+ aimsg: vue.withCtx(() => [
869
+ vue.renderSlot(_ctx.$slots, "aimsg", {
870
+ item,
871
+ index
872
+ })
873
+ ]),
874
+ msg: vue.withCtx(() => [
875
+ vue.renderSlot(_ctx.$slots, "msg", {
876
+ item,
877
+ index
878
+ })
879
+ ]),
880
+ aiAvatar: vue.withCtx(() => [
881
+ vue.renderSlot(_ctx.$slots, "aiAvatar")
882
+ ]),
883
+ fn: vue.withCtx(() => [
884
+ vue.renderSlot(_ctx.$slots, "fn", {
885
+ item,
886
+ index
887
+ })
888
+ ]),
889
+ extendsFn: vue.withCtx(() => [
890
+ vue.renderSlot(_ctx.$slots, "extendsFn", {
891
+ item,
892
+ index
893
+ })
894
+ ]),
895
+ _: 2
896
+ /* DYNAMIC */
897
+ }, 1032, ["item", "index", "onCopy", "onRetry", "onLike", "onDislike", "onCompleteRendered"]))
898
+ ],
899
+ 64
900
+ /* STABLE_FRAGMENT */
901
+ );
902
+ }),
903
+ 128
904
+ /* KEYED_FRAGMENT */
905
+ ))
906
+ ])
907
+ ],
908
+ 544
909
+ /* NEED_HYDRATION, NEED_PATCH */
910
+ ),
911
+ _ctx.$slots.shortcut ? (vue.openBlock(), vue.createElementBlock("div", {
912
+ key: 0,
913
+ class: "touchchat-edit-shortcut"
914
+ }, [
915
+ vue.renderSlot(_ctx.$slots, "shortcut")
916
+ ])) : vue.createCommentVNode("v-if", true),
917
+ vue.renderSlot(_ctx.$slots, "edit", {}, () => [
918
+ vue.createVNode(ChatInput.default, {
919
+ ref_key: "ChatInputRef",
920
+ ref: ChatInputRef,
921
+ "input-value": inputValue.value,
922
+ "onUpdate:inputValue": ($event) => inputValue.value = $event,
923
+ "is-chating": isChating.value,
924
+ onSend: handleBeforeSend
925
+ }, null, 8, ["input-value", "onUpdate:inputValue", "is-chating"])
926
+ ])
927
+ ], 40, ["onDragover"]);
928
+ };
929
+ }
930
+ });
931
+
932
+ exports.default = _sfc_main;
933
+ //# sourceMappingURL=TouchAgent.vue2.js.map