@meistrari/chat-nuxt 3.15.0-rc.0 → 3.15.0-rc.2
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/module.json +1 -1
- package/dist/runtime/messages/composables/chat-message-terminal.js +3 -4
- package/dist/runtime/messages/composables/chat.js +62 -41
- package/dist/runtime/server/api/chat/conversations/generate-title.d.ts +2 -0
- package/dist/runtime/server/api/chat/conversations/generate-title.js +3 -0
- package/dist/runtime/server/api/chat/conversations/groups/[groupId].d.ts +2 -0
- package/dist/runtime/server/api/chat/conversations/groups/[groupId].js +6 -0
- package/dist/runtime/server/api/chat/conversations/groups.d.ts +2 -0
- package/dist/runtime/server/api/chat/conversations/groups.js +3 -0
- package/dist/runtime/server/api/chat/conversations/metadata.d.ts +2 -0
- package/dist/runtime/server/api/chat/conversations/metadata.js +3 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -10,16 +10,15 @@ export function terminalMessageTransitions(previousMessages, nextMessages) {
|
|
|
10
10
|
const previousById = new Map(previousMessages.map((message) => [message.id, message]));
|
|
11
11
|
const transitions = [];
|
|
12
12
|
for (const message of nextMessages) {
|
|
13
|
-
|
|
14
|
-
if (message.role !== "assistant" || !previous)
|
|
13
|
+
if (message.role !== "assistant" || previousById.get(message.id)?.status !== "pending" /* Pending */)
|
|
15
14
|
continue;
|
|
16
|
-
if (
|
|
15
|
+
if (message.status === "completed" /* Completed */) {
|
|
17
16
|
transitions.push({
|
|
18
17
|
conversationId: message.conversationId,
|
|
19
18
|
messageId: message.id,
|
|
20
19
|
status: "completed" /* Completed */
|
|
21
20
|
});
|
|
22
|
-
} else if (message.status === "failed" /* Failed */
|
|
21
|
+
} else if (message.status === "failed" /* Failed */) {
|
|
23
22
|
transitions.push({
|
|
24
23
|
conversationId: message.conversationId,
|
|
25
24
|
messageId: message.id,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
CANCELLATION_FAILED_TEXT,
|
|
17
17
|
GENERATION_FAILED_TEXT
|
|
18
18
|
} from "../message-state.js";
|
|
19
|
+
import { useConversations } from "../../conversations/composables/conversations.js";
|
|
19
20
|
import { exportConversationToMarkdown } from "../../conversations/export.js";
|
|
20
21
|
import { resolveChatStateScope } from "../../conversations/scope.js";
|
|
21
22
|
import { getChatApiErrorCode, getChatApiErrorMessage, getChatApiErrorStatus } from "../../shared/chat-api-error.js";
|
|
@@ -45,6 +46,7 @@ export function useChat(options = {}) {
|
|
|
45
46
|
const embedConfig = useEmbedConfig();
|
|
46
47
|
const { user: authUser, activeOrganization } = useChatAuth();
|
|
47
48
|
const { addFilesToConversation } = useConversationFileActions();
|
|
49
|
+
const { updateConversationInList } = useConversations();
|
|
48
50
|
const chatScope = computed(() => resolveChatStateScope(
|
|
49
51
|
embedConfig?.workspaceId.value || activeOrganization.value?.id,
|
|
50
52
|
embedConfig?.telaAgentId.value,
|
|
@@ -118,9 +120,26 @@ export function useChat(options = {}) {
|
|
|
118
120
|
schedulePreparingStep(0);
|
|
119
121
|
}
|
|
120
122
|
const error = ref(null);
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
const
|
|
123
|
+
const titleGeneratedBuckets = useState("chat-title-generated", () => ({}));
|
|
124
|
+
const generatingTitleBuckets = useState("chat-generating-title", () => ({}));
|
|
125
|
+
const animatedTitleBuckets = useState("chat-animated-title", () => ({}));
|
|
126
|
+
const generatingTitle = computed(() => {
|
|
127
|
+
const conversationId = currentConversation.value?.id;
|
|
128
|
+
return conversationId ? generatingTitleBuckets.value[conversationId] ?? false : false;
|
|
129
|
+
});
|
|
130
|
+
const animatedTitle = computed(() => {
|
|
131
|
+
const conversationId = currentConversation.value?.id;
|
|
132
|
+
return conversationId ? animatedTitleBuckets.value[conversationId] ?? null : null;
|
|
133
|
+
});
|
|
134
|
+
function markTitleGenerated(conversationId, generated) {
|
|
135
|
+
titleGeneratedBuckets.value = { ...titleGeneratedBuckets.value, [conversationId]: generated };
|
|
136
|
+
}
|
|
137
|
+
function setGeneratingTitle(conversationId, generating) {
|
|
138
|
+
generatingTitleBuckets.value = { ...generatingTitleBuckets.value, [conversationId]: generating };
|
|
139
|
+
}
|
|
140
|
+
function setAnimatedTitle(conversationId, title) {
|
|
141
|
+
animatedTitleBuckets.value = { ...animatedTitleBuckets.value, [conversationId]: title };
|
|
142
|
+
}
|
|
124
143
|
const hasPendingMessage = computed(
|
|
125
144
|
() => messages.value.some((m) => m.status === "pending")
|
|
126
145
|
);
|
|
@@ -142,10 +161,10 @@ export function useChat(options = {}) {
|
|
|
142
161
|
const messageId = streamingMessageId.value;
|
|
143
162
|
if (!messageId)
|
|
144
163
|
return;
|
|
145
|
-
const
|
|
164
|
+
const isPendingAssistant = messages.value.some(
|
|
146
165
|
(message) => message.id === messageId && message.role === "assistant" && message.status === ChatMessageStatus.Pending
|
|
147
166
|
);
|
|
148
|
-
if (!
|
|
167
|
+
if (!isPendingAssistant)
|
|
149
168
|
return;
|
|
150
169
|
pendingStreamReconciliationIds.value = /* @__PURE__ */ new Set([
|
|
151
170
|
...pendingStreamReconciliationIds.value,
|
|
@@ -160,11 +179,9 @@ export function useChat(options = {}) {
|
|
|
160
179
|
content: resolveStreamingContent(message.content, result.text),
|
|
161
180
|
status: ChatMessageStatus.Completed
|
|
162
181
|
} : message);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
status: ChatMessageStatus.Completed
|
|
167
|
-
});
|
|
182
|
+
}
|
|
183
|
+
function durableKnownMessages() {
|
|
184
|
+
return messages.value.map((message) => pendingStreamReconciliationIds.value.has(message.id) ? { ...message, status: ChatMessageStatus.Pending } : message);
|
|
168
185
|
}
|
|
169
186
|
function confirmStreamedResult(result) {
|
|
170
187
|
if (result.status === "waiting_messages") {
|
|
@@ -242,7 +259,7 @@ export function useChat(options = {}) {
|
|
|
242
259
|
const optimisticMessage = currentMessagesById.get(message.id);
|
|
243
260
|
return optimisticMessage?.status === ChatMessageStatus.Completed ? optimisticMessage : message;
|
|
244
261
|
});
|
|
245
|
-
const terminalMessages = terminalMessageTransitions(
|
|
262
|
+
const terminalMessages = terminalMessageTransitions(durableKnownMessages(), response.messages);
|
|
246
263
|
pendingStreamReconciliationIds.value = remainingReconciliationIds;
|
|
247
264
|
pendingRealResultIds.value = remainingRealResultIds;
|
|
248
265
|
messages.value = reconciledMessages;
|
|
@@ -284,7 +301,7 @@ export function useChat(options = {}) {
|
|
|
284
301
|
status: ChatMessageStatus.Failed
|
|
285
302
|
};
|
|
286
303
|
});
|
|
287
|
-
const terminalMessages = terminalMessageTransitions(
|
|
304
|
+
const terminalMessages = terminalMessageTransitions(durableKnownMessages(), failedMessages);
|
|
288
305
|
pendingStreamReconciliationIds.value = /* @__PURE__ */ new Set();
|
|
289
306
|
pendingRealResultIds.value = /* @__PURE__ */ new Set();
|
|
290
307
|
messages.value = failedMessages;
|
|
@@ -338,7 +355,6 @@ export function useChat(options = {}) {
|
|
|
338
355
|
};
|
|
339
356
|
const adoptConversation = (conv) => {
|
|
340
357
|
currentConversation.value = { ...conv, messages: messages.value };
|
|
341
|
-
titleGenerated.value = false;
|
|
342
358
|
};
|
|
343
359
|
const setConversation = (conv) => {
|
|
344
360
|
if (currentConversation.value && currentConversation.value.id !== conv.id) {
|
|
@@ -353,13 +369,11 @@ export function useChat(options = {}) {
|
|
|
353
369
|
agentSessionStatus.value = null;
|
|
354
370
|
agentSessionExecutable.value = false;
|
|
355
371
|
agentSessionRewakeable.value = false;
|
|
356
|
-
titleGenerated.value = false;
|
|
357
372
|
error.value = null;
|
|
358
373
|
};
|
|
359
374
|
const loadConversation = async (id) => {
|
|
360
375
|
loading.value = true;
|
|
361
376
|
error.value = null;
|
|
362
|
-
titleGenerated.value = false;
|
|
363
377
|
try {
|
|
364
378
|
const data = await $fetch(
|
|
365
379
|
chatApi.path(`/conversations/${id}`),
|
|
@@ -369,9 +383,8 @@ export function useChat(options = {}) {
|
|
|
369
383
|
messages.value = data.messages;
|
|
370
384
|
pendingStreamReconciliationIds.value = /* @__PURE__ */ new Set();
|
|
371
385
|
pendingRealResultIds.value = /* @__PURE__ */ new Set();
|
|
372
|
-
if (shouldTreatLoadedConversationTitleAsGenerated(data.messages))
|
|
373
|
-
|
|
374
|
-
}
|
|
386
|
+
if (shouldTreatLoadedConversationTitleAsGenerated(data.messages))
|
|
387
|
+
markTitleGenerated(data.id, true);
|
|
375
388
|
const pendingAssistant = data.messages.findLast((m) => m.role === "assistant" && m.status === "pending");
|
|
376
389
|
if (pendingAssistant) {
|
|
377
390
|
streamingMessageId.value = pendingAssistant.id;
|
|
@@ -750,30 +763,35 @@ export function useChat(options = {}) {
|
|
|
750
763
|
return false;
|
|
751
764
|
}
|
|
752
765
|
};
|
|
753
|
-
const animateTitle = (title) => {
|
|
766
|
+
const animateTitle = (title, conversationId) => {
|
|
754
767
|
return new Promise((resolve) => {
|
|
755
|
-
|
|
768
|
+
setAnimatedTitle(conversationId, "");
|
|
756
769
|
let index = 0;
|
|
757
770
|
const interval = setInterval(() => {
|
|
758
|
-
if (
|
|
759
|
-
|
|
771
|
+
if (currentConversation.value?.id !== conversationId) {
|
|
772
|
+
clearInterval(interval);
|
|
773
|
+
setAnimatedTitle(conversationId, null);
|
|
774
|
+
resolve(false);
|
|
775
|
+
} else if (index < title.length) {
|
|
776
|
+
setAnimatedTitle(conversationId, title.slice(0, index + 1));
|
|
760
777
|
index++;
|
|
761
778
|
} else {
|
|
762
779
|
clearInterval(interval);
|
|
763
|
-
|
|
764
|
-
resolve();
|
|
780
|
+
setAnimatedTitle(conversationId, null);
|
|
781
|
+
resolve(true);
|
|
765
782
|
}
|
|
766
783
|
}, 30);
|
|
767
784
|
});
|
|
768
785
|
};
|
|
769
786
|
const generateTitle = async () => {
|
|
770
|
-
|
|
787
|
+
const conversation = currentConversation.value;
|
|
788
|
+
if (!conversation || titleGeneratedBuckets.value[conversation.id])
|
|
771
789
|
return;
|
|
772
790
|
const titleMessages = selectTitleGenerationMessages(messages.value);
|
|
773
791
|
if (!titleMessages)
|
|
774
792
|
return;
|
|
775
|
-
|
|
776
|
-
|
|
793
|
+
markTitleGenerated(conversation.id, true);
|
|
794
|
+
setGeneratingTitle(conversation.id, true);
|
|
777
795
|
try {
|
|
778
796
|
const { title } = await $fetch(
|
|
779
797
|
chatApi.path("/conversations/generate-title"),
|
|
@@ -785,24 +803,27 @@ export function useChat(options = {}) {
|
|
|
785
803
|
}
|
|
786
804
|
})
|
|
787
805
|
);
|
|
788
|
-
if (title
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
}
|
|
795
|
-
})
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
806
|
+
if (!title)
|
|
807
|
+
return;
|
|
808
|
+
const updated = await $fetch(
|
|
809
|
+
chatApi.path(`/conversations/${conversation.id}`),
|
|
810
|
+
chatApi.withChatHeaders({
|
|
811
|
+
method: "PATCH",
|
|
812
|
+
body: { title }
|
|
813
|
+
})
|
|
814
|
+
);
|
|
815
|
+
updateConversationInList(updated);
|
|
816
|
+
if (currentConversation.value?.id === conversation.id && await animateTitle(title, conversation.id)) {
|
|
817
|
+
const current = currentConversation.value;
|
|
818
|
+
if (current?.id === conversation.id)
|
|
819
|
+
currentConversation.value = { ...current, title };
|
|
800
820
|
}
|
|
801
821
|
} catch (err) {
|
|
822
|
+
markTitleGenerated(conversation.id, false);
|
|
802
823
|
Sentry.captureException(err);
|
|
803
824
|
} finally {
|
|
804
|
-
|
|
805
|
-
|
|
825
|
+
setGeneratingTitle(conversation.id, false);
|
|
826
|
+
setAnimatedTitle(conversation.id, null);
|
|
806
827
|
}
|
|
807
828
|
};
|
|
808
829
|
const exportToMarkdown = () => {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { defineEventHandler, getRouterParam } from "h3";
|
|
2
|
+
import { prefixProxyPath, proxyChatApiRequest } from "../../../../utils/chat-api-proxy.js";
|
|
3
|
+
export default defineEventHandler((event) => {
|
|
4
|
+
const groupId = getRouterParam(event, "groupId") || "";
|
|
5
|
+
return proxyChatApiRequest(event, prefixProxyPath("conversations/groups", groupId));
|
|
6
|
+
});
|