@meistrari/chat-nuxt 1.11.0 → 1.13.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/module.json +1 -1
- package/dist/module.mjs +15 -0
- package/dist/runtime/components/chat/conversation-item.d.vue.ts +6 -1
- package/dist/runtime/components/chat/conversation-item.vue +30 -141
- package/dist/runtime/components/chat/conversation-item.vue.d.ts +6 -1
- package/dist/runtime/components/chat/conversation-list.d.vue.ts +1 -0
- package/dist/runtime/components/chat/conversation-list.vue +300 -72
- package/dist/runtime/components/chat/conversation-list.vue.d.ts +1 -0
- package/dist/runtime/components/chat/conversation-new-group-button.d.vue.ts +7 -0
- package/dist/runtime/components/chat/conversation-new-group-button.vue +90 -0
- package/dist/runtime/components/chat/conversation-new-group-button.vue.d.ts +7 -0
- package/dist/runtime/components/chat/conversation-new-group-popover-content.d.vue.ts +23 -0
- package/dist/runtime/components/chat/conversation-new-group-popover-content.vue +75 -0
- package/dist/runtime/components/chat/conversation-new-group-popover-content.vue.d.ts +23 -0
- package/dist/runtime/components/chat/mobile/shell/drawer.d.vue.ts +2 -2
- package/dist/runtime/components/chat/mobile/shell/drawer.vue +370 -41
- package/dist/runtime/components/chat/mobile/shell/drawer.vue.d.ts +2 -2
- package/dist/runtime/components/chat/mobile/shell/shell.d.vue.ts +6 -6
- package/dist/runtime/components/chat/mobile/shell/shell.vue +1 -1
- package/dist/runtime/components/chat/mobile/shell/shell.vue.d.ts +6 -6
- package/dist/runtime/components/chat/reasoning-message.vue +4 -1
- package/dist/runtime/components/chat/topbar.d.vue.ts +2 -2
- package/dist/runtime/components/chat/topbar.vue.d.ts +2 -2
- package/dist/runtime/composables/useConversationGroups.d.ts +12 -0
- package/dist/runtime/composables/useConversationGroups.js +160 -0
- package/dist/runtime/composables/useConversationItem.d.ts +48 -0
- package/dist/runtime/composables/useConversationItem.js +176 -0
- package/dist/runtime/composables/useConversationList.d.ts +128 -0
- package/dist/runtime/composables/useConversationList.js +553 -0
- package/dist/runtime/composables/useConversations.d.ts +2 -0
- package/dist/runtime/composables/useConversations.js +45 -1
- package/dist/runtime/composables/usePendingConversationGroup.d.ts +5 -0
- package/dist/runtime/composables/usePendingConversationGroup.js +33 -0
- package/dist/runtime/composables/useVerbConjugation.d.ts +1 -0
- package/dist/runtime/composables/useVerbConjugation.js +14 -1
- package/dist/runtime/embed/components/ChatConfigurationModal.d.vue.ts +1 -1
- package/dist/runtime/embed/components/ChatConfigurationModal.vue.d.ts +1 -1
- package/dist/runtime/embed/components/ChatEmbedInner.vue +24 -5
- package/dist/runtime/server/api/chat/conversations/[id]/group.patch.d.ts +1 -0
- package/dist/runtime/server/api/chat/conversations/[id]/group.patch.js +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/[groupId]/index.delete.d.ts +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/[groupId]/index.delete.js +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/[groupId]/index.patch.d.ts +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/[groupId]/index.patch.js +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/index.get.d.ts +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/index.get.js +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/index.post.d.ts +1 -0
- package/dist/runtime/server/api/chat/conversations/groups/index.post.js +1 -0
- package/dist/runtime/server/api/conversations/[id]/duplicate.post.js +1 -0
- package/dist/runtime/server/api/conversations/[id]/group.patch.d.ts +2 -0
- package/dist/runtime/server/api/conversations/[id]/group.patch.js +46 -0
- package/dist/runtime/server/api/conversations/[id]/messages/[messageId]/retry.post.js +2 -0
- package/dist/runtime/server/api/conversations/[id]/messages/index.get.js +26 -4
- package/dist/runtime/server/api/conversations/groups/[groupId]/index.delete.d.ts +4 -0
- package/dist/runtime/server/api/conversations/groups/[groupId]/index.delete.js +25 -0
- package/dist/runtime/server/api/conversations/groups/[groupId]/index.patch.d.ts +2 -0
- package/dist/runtime/server/api/conversations/groups/[groupId]/index.patch.js +30 -0
- package/dist/runtime/server/api/conversations/groups/index.get.d.ts +2 -0
- package/dist/runtime/server/api/conversations/groups/index.get.js +13 -0
- package/dist/runtime/server/api/conversations/groups/index.post.d.ts +2 -0
- package/dist/runtime/server/api/conversations/groups/index.post.js +26 -0
- package/dist/runtime/server/api/conversations/index.post.js +1 -0
- package/dist/runtime/server/db/schema/conversation-groups.d.ts +143 -0
- package/dist/runtime/server/db/schema/conversation-groups.js +20 -0
- package/dist/runtime/server/db/schema/conversations.d.ts +17 -0
- package/dist/runtime/server/db/schema/conversations.js +3 -0
- package/dist/runtime/server/db/schema/index.d.ts +1 -0
- package/dist/runtime/server/db/schema/index.js +1 -0
- package/dist/runtime/server/db/schema/messages.d.ts +34 -0
- package/dist/runtime/server/db/schema/messages.js +3 -1
- package/dist/runtime/server/utils/conversation-group.d.ts +4 -0
- package/dist/runtime/server/utils/conversation-group.js +48 -0
- package/dist/runtime/server/utils/conversation-message-sync.d.ts +1 -1
- package/dist/runtime/server/utils/conversation-message-sync.js +2 -2
- package/dist/runtime/server/utils/tela-agent-api.d.ts +3 -1
- package/dist/runtime/server/utils/tela-agent-api.js +285 -26
- package/dist/runtime/server/utils/tela-agent-session.d.ts +14 -4
- package/dist/runtime/server/utils/tela-agent-session.js +57 -22
- package/dist/runtime/types/chat.d.ts +2 -1
- package/dist/runtime/types/tela-agent.d.ts +155 -43
- package/dist/runtime/types/tela-agent.js +49 -11
- package/dist/runtime/utils/conversation-groups.d.ts +18 -0
- package/dist/runtime/utils/conversation-groups.js +30 -0
- package/drizzle/0016_dry_aaron_stack.sql +16 -0
- package/drizzle/0017_typical_dexter_bennett.sql +2 -0
- package/drizzle/meta/0016_snapshot.json +887 -0
- package/drizzle/meta/0017_snapshot.json +899 -0
- package/drizzle/meta/_journal.json +14 -0
- package/package.json +1 -1
|
@@ -186,6 +186,12 @@ const gerundToPast = new Map(
|
|
|
186
186
|
const infinitiveToPast = new Map(
|
|
187
187
|
ptValues.map((v) => [v.infinitive, v.past])
|
|
188
188
|
);
|
|
189
|
+
const readFileStepLabels = {
|
|
190
|
+
"instructions.md": "instru\xE7\xF5es",
|
|
191
|
+
"output-format.json": "estrutura de sa\xEDda esperada",
|
|
192
|
+
"input-list.json": "lista de arquivos de entrada",
|
|
193
|
+
"result.json": "resultado"
|
|
194
|
+
};
|
|
189
195
|
export function useVerbConjugation() {
|
|
190
196
|
function isEnglish(text) {
|
|
191
197
|
const firstWord = text.trim().split(/\s+/)[0]?.toLowerCase() || "";
|
|
@@ -247,10 +253,17 @@ export function useVerbConjugation() {
|
|
|
247
253
|
}
|
|
248
254
|
return conjugatePortugueseVerb(text);
|
|
249
255
|
}
|
|
256
|
+
function resolveReadFileStepTitle(fileName, wasExecuted) {
|
|
257
|
+
const label = readFileStepLabels[fileName];
|
|
258
|
+
if (!label)
|
|
259
|
+
return null;
|
|
260
|
+
return conjugateText(`Lendo ${label}`, wasExecuted);
|
|
261
|
+
}
|
|
250
262
|
return {
|
|
251
263
|
conjugateText,
|
|
252
264
|
isEnglish,
|
|
253
265
|
translateEnglishText,
|
|
254
|
-
conjugatePortugueseVerb
|
|
266
|
+
conjugatePortugueseVerb,
|
|
267
|
+
resolveReadFileStepTitle
|
|
255
268
|
};
|
|
256
269
|
}
|
|
@@ -18,8 +18,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
18
18
|
onSave?: ((payload: ChatConfigurationSavePayload) => any) | undefined;
|
|
19
19
|
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
20
20
|
}>, {
|
|
21
|
-
initialTab: ChatConfigurationTab;
|
|
22
21
|
saving: boolean;
|
|
22
|
+
initialTab: ChatConfigurationTab;
|
|
23
23
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
24
24
|
declare const _default: typeof __VLS_export;
|
|
25
25
|
export default _default;
|
|
@@ -18,8 +18,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
18
18
|
onSave?: ((payload: ChatConfigurationSavePayload) => any) | undefined;
|
|
19
19
|
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
20
20
|
}>, {
|
|
21
|
-
initialTab: ChatConfigurationTab;
|
|
22
21
|
saving: boolean;
|
|
22
|
+
initialTab: ChatConfigurationTab;
|
|
23
23
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
24
24
|
declare const _default: typeof __VLS_export;
|
|
25
25
|
export default _default;
|
|
@@ -25,7 +25,7 @@ const chatAction = useChatAction();
|
|
|
25
25
|
const { user: authUser, activeOrganization, logout } = useChatAuth();
|
|
26
26
|
const { getMember, getMemberImage } = useWorkspaceMembers();
|
|
27
27
|
const statusToast = useStatusToast();
|
|
28
|
-
const { conversations, loading: conversationsLoading, fetchConversations, createConversation, deleteConversation, renameConversation, duplicateConversation, updateConversationInList } = useConversations();
|
|
28
|
+
const { conversations, loading: conversationsLoading, fetchConversations, createConversation, deleteConversation, renameConversation, duplicateConversation, moveConversationToGroup, updateConversationInList } = useConversations();
|
|
29
29
|
const { settings: workspaceSettingsState, fetchSettings } = useWorkspaceSettings();
|
|
30
30
|
const { metadata: telaAgentMetadata, loading: telaAgentMetadataLoading, fetchAgentMetadata } = useTelaAgentMetadata();
|
|
31
31
|
const isTelaAgentMode = computed(() => !!embedConfig?.telaAgentId.value);
|
|
@@ -46,6 +46,11 @@ const activeConversationId = ref(
|
|
|
46
46
|
);
|
|
47
47
|
const loadingConversationId = ref(null);
|
|
48
48
|
const isReady = ref(false);
|
|
49
|
+
const {
|
|
50
|
+
pendingConversationGroupId,
|
|
51
|
+
setPendingConversationGroup,
|
|
52
|
+
clearPendingConversationGroup
|
|
53
|
+
} = usePendingConversationGroup();
|
|
49
54
|
const resolvedFeatures = computed(() => resolveChatFeatures(props.features));
|
|
50
55
|
const dropZoneRef = ref(null);
|
|
51
56
|
const activeTab = ref("chat");
|
|
@@ -154,6 +159,7 @@ async function openConversation(nextConversationId) {
|
|
|
154
159
|
if (!normalizedConversationId) {
|
|
155
160
|
return;
|
|
156
161
|
}
|
|
162
|
+
clearPendingConversationGroup();
|
|
157
163
|
if (activeConversationId.value !== normalizedConversationId) {
|
|
158
164
|
closePreview();
|
|
159
165
|
}
|
|
@@ -165,6 +171,9 @@ watch(() => props.conversationId, async (nextConversationId) => {
|
|
|
165
171
|
return;
|
|
166
172
|
}
|
|
167
173
|
const normalizedConversationId = normalizeConversationId(nextConversationId);
|
|
174
|
+
if (normalizedConversationId) {
|
|
175
|
+
clearPendingConversationGroup();
|
|
176
|
+
}
|
|
168
177
|
if (!isReady.value) {
|
|
169
178
|
syncConversationId(normalizedConversationId);
|
|
170
179
|
return;
|
|
@@ -272,7 +281,14 @@ async function handleSend(content, files, model, agentInputs) {
|
|
|
272
281
|
const conversation = await createConversation(isTelaAgentMode.value ? void 0 : { model: model ?? selectedModel.value });
|
|
273
282
|
if (!conversation)
|
|
274
283
|
return;
|
|
275
|
-
|
|
284
|
+
const groupId = pendingConversationGroupId.value;
|
|
285
|
+
clearPendingConversationGroup();
|
|
286
|
+
if (groupId && await moveConversationToGroup(conversation.id, groupId)) {
|
|
287
|
+
const groupedConversation = { ...conversation, groupId };
|
|
288
|
+
setConversation(groupedConversation);
|
|
289
|
+
} else {
|
|
290
|
+
setConversation(conversation);
|
|
291
|
+
}
|
|
276
292
|
createdConversationId = conversation.id;
|
|
277
293
|
}
|
|
278
294
|
if (!currentConversation.value)
|
|
@@ -286,7 +302,8 @@ async function handleSend(content, files, model, agentInputs) {
|
|
|
286
302
|
async function handleRetry(messageId) {
|
|
287
303
|
await retryMessage(messageId);
|
|
288
304
|
}
|
|
289
|
-
async function handleNewConversation() {
|
|
305
|
+
async function handleNewConversation(groupId) {
|
|
306
|
+
setPendingConversationGroup(groupId);
|
|
290
307
|
resetConversation();
|
|
291
308
|
}
|
|
292
309
|
const workspaceSheetOpen = ref(false);
|
|
@@ -407,10 +424,10 @@ async function handleDelete() {
|
|
|
407
424
|
w-240px h-full flex="~ col" flex-shrink-0
|
|
408
425
|
bg-neutral-50 b-r=".5px neutral-200"
|
|
409
426
|
>
|
|
410
|
-
<div px-12px pt-16px pb-8px flex
|
|
427
|
+
<div px-12px pt-16px pb-8px flex gap-8px>
|
|
411
428
|
<button
|
|
412
429
|
flex items-center justify-center gap-6px
|
|
413
|
-
h-32px px-12px w-
|
|
430
|
+
h-32px px-12px flex-1 min-w-0
|
|
414
431
|
bg-white b=".5px neutral-300" rounded-10px
|
|
415
432
|
hover:bg-neutral-50 transition-colors cursor-pointer
|
|
416
433
|
@click="handleNewConversation"
|
|
@@ -420,6 +437,7 @@ async function handleDelete() {
|
|
|
420
437
|
Nova conversa
|
|
421
438
|
</span>
|
|
422
439
|
</button>
|
|
440
|
+
<ChatConversationNewGroupButton />
|
|
423
441
|
</div>
|
|
424
442
|
|
|
425
443
|
<div flex-1 overflow-y-auto px-4px>
|
|
@@ -429,6 +447,7 @@ async function handleDelete() {
|
|
|
429
447
|
:get-member-image="getMemberImage"
|
|
430
448
|
:select-conversation="openConversation"
|
|
431
449
|
:reset-conversation="handleNewConversation"
|
|
450
|
+
:start-conversation="handleNewConversation"
|
|
432
451
|
:loading="conversationsLoading"
|
|
433
452
|
/>
|
|
434
453
|
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../../conversations/[id]/group.patch.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../../conversations/[id]/group.patch.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../../../conversations/groups/[groupId]/index.delete.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../../../conversations/groups/[groupId]/index.delete.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../../../conversations/groups/[groupId]/index.patch.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../../../conversations/groups/[groupId]/index.patch.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../../conversations/groups/index.get.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../../conversations/groups/index.get.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '../../../conversations/groups/index.post.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../../conversations/groups/index.post.js";
|
|
@@ -26,6 +26,7 @@ export default defineEventHandler(async (event) => {
|
|
|
26
26
|
const duplicated = await db.transaction(async (tx) => {
|
|
27
27
|
const [newConversation] = await tx.insert(schema.conversations).values({
|
|
28
28
|
workspaceId: context.workspaceId,
|
|
29
|
+
groupId: null,
|
|
29
30
|
userId: context.user.id,
|
|
30
31
|
title: `${original.title} (copy)`,
|
|
31
32
|
createdBy: context.user.email,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getRouterParam, readBody } from "h3";
|
|
2
|
+
import { useDb, schema } from "#chat-runtime/server/db";
|
|
3
|
+
import { resolveChatRuntimeContext } from "#chat-runtime/server/utils/chat-context";
|
|
4
|
+
import { resolveOptionalConversationGroupId, conversationGroupScopeConditions } from "#chat-runtime/server/utils/conversation-group";
|
|
5
|
+
import { conversationScopeConditions } from "#chat-runtime/server/utils/conversation-scope";
|
|
6
|
+
import { logger } from "#chat-runtime/server/utils/logger";
|
|
7
|
+
function hasGroupId(body) {
|
|
8
|
+
return !!body && typeof body === "object" && Object.prototype.hasOwnProperty.call(body, "groupId");
|
|
9
|
+
}
|
|
10
|
+
export default defineEventHandler(async (event) => {
|
|
11
|
+
const context = resolveChatRuntimeContext(event);
|
|
12
|
+
const db = useDb();
|
|
13
|
+
const id = getRouterParam(event, "id");
|
|
14
|
+
if (!id) {
|
|
15
|
+
throw createError({
|
|
16
|
+
statusCode: 400,
|
|
17
|
+
statusMessage: "Conversation ID is required"
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
const body = await readBody(event);
|
|
21
|
+
if (!hasGroupId(body)) {
|
|
22
|
+
throw createError({
|
|
23
|
+
statusCode: 400,
|
|
24
|
+
statusMessage: "Group ID is required"
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const groupId = resolveOptionalConversationGroupId(body.groupId);
|
|
28
|
+
if (groupId) {
|
|
29
|
+
const [group] = await db.select({ id: schema.conversationGroups.id }).from(schema.conversationGroups).where(conversationGroupScopeConditions(context, groupId)).limit(1);
|
|
30
|
+
if (!group) {
|
|
31
|
+
throw createError({
|
|
32
|
+
statusCode: 404,
|
|
33
|
+
statusMessage: "Conversation group not found"
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const [updated] = await db.update(schema.conversations).set({ groupId }).where(conversationScopeConditions(context, id)).returning();
|
|
38
|
+
if (!updated) {
|
|
39
|
+
throw createError({
|
|
40
|
+
statusCode: 404,
|
|
41
|
+
statusMessage: "Conversation not found"
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
logger.info({ conversationId: id, groupId, workspaceId: context.workspaceId }, "Conversation moved between groups");
|
|
45
|
+
return updated;
|
|
46
|
+
});
|
|
@@ -64,6 +64,8 @@ export default defineEventHandler(async (event) => {
|
|
|
64
64
|
reasoningData: null,
|
|
65
65
|
files: null,
|
|
66
66
|
ttft: null,
|
|
67
|
+
agentSessionCursor: null,
|
|
68
|
+
agentSessionId: null,
|
|
67
69
|
updatedAt: null
|
|
68
70
|
}).where(eq(schema.messages.id, messageId));
|
|
69
71
|
logger.info({ conversationId, messageId }, "Message retry initiated");
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
hasPendingMessageExceededGraceWindow,
|
|
12
12
|
isTerminalMessageUpdate,
|
|
13
13
|
mapAgentApiSessionToMessageUpdate,
|
|
14
|
+
PENDING_RESPONSE_GRACE_MS,
|
|
14
15
|
SESSION_STATUS_CHECK_ERROR,
|
|
15
16
|
THREAD_SESSION_START_ERROR,
|
|
16
17
|
trackAgentApiConversationUsage,
|
|
@@ -18,8 +19,9 @@ import {
|
|
|
18
19
|
} from "#chat-runtime/server/utils/conversation-message-sync";
|
|
19
20
|
import { conversationScopeConditions } from "#chat-runtime/server/utils/conversation-scope";
|
|
20
21
|
import { getTelaAgentSession } from "#chat-runtime/server/utils/tela-agent-api";
|
|
21
|
-
import { mapTelaAgentSessionToMessageUpdate, mapTelaAgentUsage } from "#chat-runtime/server/utils/tela-agent-session";
|
|
22
|
+
import { mapTelaAgentSessionToMessageUpdate, mapTelaAgentUsage, resolveTelaAgentRequestCursor } from "#chat-runtime/server/utils/tela-agent-session";
|
|
22
23
|
import { logger } from "#chat-runtime/server/utils/logger";
|
|
24
|
+
const TELA_AGENT_PROGRESS_RECOVERY_MS = 5 * 6e4;
|
|
23
25
|
export default defineEventHandler(async (event) => {
|
|
24
26
|
const context = resolveChatRuntimeContext(event);
|
|
25
27
|
const token = getAgentDataToken(event);
|
|
@@ -70,18 +72,38 @@ export default defineEventHandler(async (event) => {
|
|
|
70
72
|
}
|
|
71
73
|
logger.debug({ conversationId, messageId: pendingMessage.id, sessionId: conversation.threadSessionId }, "Polling pending message");
|
|
72
74
|
if (conversation.telaAgentId) {
|
|
73
|
-
const
|
|
75
|
+
const agentSessionCursor = resolveTelaAgentRequestCursor({
|
|
76
|
+
pendingMessage,
|
|
77
|
+
lastTerminalMessage: lastTerminalAssistantMessage,
|
|
78
|
+
threadSessionId: conversation.threadSessionId
|
|
79
|
+
});
|
|
80
|
+
const sessionResult2 = await getTelaAgentSession(event, conversation.threadSessionId, {
|
|
81
|
+
cursor: agentSessionCursor
|
|
82
|
+
});
|
|
74
83
|
if (!sessionResult2.success) {
|
|
75
|
-
|
|
84
|
+
const lastProgressAt = pendingMessage.updatedAt ?? pendingMessage.createdAt;
|
|
85
|
+
const hasTelaAgentProgress = typeof pendingMessage.agentSessionCursor === "number" || !!pendingMessage.externalUuid || Array.isArray(pendingMessage.reasoningData) && pendingMessage.reasoningData.length > 0;
|
|
86
|
+
const recoveryMs = hasTelaAgentProgress ? TELA_AGENT_PROGRESS_RECOVERY_MS : PENDING_RESPONSE_GRACE_MS;
|
|
87
|
+
if (!hasPendingMessageExceededGraceWindow({ createdAt: lastProgressAt }, /* @__PURE__ */ new Date(), recoveryMs)) {
|
|
88
|
+
logger.debug({ conversationId, messageId: pendingMessage.id, sessionId: conversation.threadSessionId, error: sessionResult2.error }, "Tela agent session status check failed within grace window");
|
|
89
|
+
return { messages };
|
|
90
|
+
}
|
|
91
|
+
const updateData3 = buildFailedPendingMessageUpdate(SESSION_STATUS_CHECK_ERROR);
|
|
92
|
+
logger.warn({ conversationId, messageId: pendingMessage.id, sessionId: conversation.threadSessionId, error: sessionResult2.error }, "Pending message failed because Tela agent session status check did not recover");
|
|
93
|
+
await db.update(schema.messages).set(updateData3).where(eq(schema.messages.id, pendingMessage.id));
|
|
94
|
+
return buildMessageUpdateResponse(messages, pendingMessage.id, updateData3);
|
|
76
95
|
}
|
|
77
96
|
const agentSession2 = sessionResult2.data;
|
|
78
97
|
const userMessage2 = messages.findLast((message) => message.role === "user");
|
|
79
98
|
const updateData2 = mapTelaAgentSessionToMessageUpdate(agentSession2, {
|
|
80
|
-
lastSyncedStepId: pendingMessage.externalUuid ?? lastTerminalAssistantMessage?.externalUuid,
|
|
81
99
|
existingReasoningData: Array.isArray(pendingMessage.reasoningData) ? pendingMessage.reasoningData : null,
|
|
82
100
|
pendingMessageTtft: pendingMessage.ttft,
|
|
83
101
|
userMessageCreatedAt: userMessage2?.createdAt ?? null
|
|
84
102
|
});
|
|
103
|
+
if (typeof agentSessionCursor === "number" && pendingMessage.agentSessionCursor !== agentSessionCursor && updateData2.agentSessionCursor === void 0) {
|
|
104
|
+
updateData2.agentSessionCursor = agentSessionCursor;
|
|
105
|
+
updateData2.agentSessionId = conversation.threadSessionId;
|
|
106
|
+
}
|
|
85
107
|
await attachNewAssistantFilesToMessageUpdate(db, conversationId, updateData2, token);
|
|
86
108
|
if (!hasMessageUpdate(updateData2)) {
|
|
87
109
|
return { messages };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getRouterParam } from "h3";
|
|
2
|
+
import { useDb, schema } from "#chat-runtime/server/db";
|
|
3
|
+
import { resolveChatRuntimeContext } from "#chat-runtime/server/utils/chat-context";
|
|
4
|
+
import { conversationGroupScopeConditions } from "#chat-runtime/server/utils/conversation-group";
|
|
5
|
+
import { logger } from "#chat-runtime/server/utils/logger";
|
|
6
|
+
export default defineEventHandler(async (event) => {
|
|
7
|
+
const context = resolveChatRuntimeContext(event);
|
|
8
|
+
const db = useDb();
|
|
9
|
+
const groupId = getRouterParam(event, "groupId");
|
|
10
|
+
if (!groupId) {
|
|
11
|
+
throw createError({
|
|
12
|
+
statusCode: 400,
|
|
13
|
+
statusMessage: "Group ID is required"
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
const [group] = await db.delete(schema.conversationGroups).where(conversationGroupScopeConditions(context, groupId)).returning();
|
|
17
|
+
if (!group) {
|
|
18
|
+
throw createError({
|
|
19
|
+
statusCode: 404,
|
|
20
|
+
statusMessage: "Conversation group not found"
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
logger.info({ groupId, workspaceId: context.workspaceId }, "Conversation group deleted");
|
|
24
|
+
return { success: true };
|
|
25
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getRouterParam, readBody } from "h3";
|
|
2
|
+
import { useDb, schema } from "#chat-runtime/server/db";
|
|
3
|
+
import { resolveChatRuntimeContext } from "#chat-runtime/server/utils/chat-context";
|
|
4
|
+
import { conversationGroupScopeConditions, resolveConversationGroupName } from "#chat-runtime/server/utils/conversation-group";
|
|
5
|
+
import { logger } from "#chat-runtime/server/utils/logger";
|
|
6
|
+
export default defineEventHandler(async (event) => {
|
|
7
|
+
const context = resolveChatRuntimeContext(event);
|
|
8
|
+
const db = useDb();
|
|
9
|
+
const groupId = getRouterParam(event, "groupId");
|
|
10
|
+
if (!groupId) {
|
|
11
|
+
throw createError({
|
|
12
|
+
statusCode: 400,
|
|
13
|
+
statusMessage: "Group ID is required"
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
const body = await readBody(event);
|
|
17
|
+
const name = resolveConversationGroupName(body?.name);
|
|
18
|
+
const [group] = await db.update(schema.conversationGroups).set({
|
|
19
|
+
name,
|
|
20
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
21
|
+
}).where(conversationGroupScopeConditions(context, groupId)).returning();
|
|
22
|
+
if (!group) {
|
|
23
|
+
throw createError({
|
|
24
|
+
statusCode: 404,
|
|
25
|
+
statusMessage: "Conversation group not found"
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
logger.info({ groupId, workspaceId: context.workspaceId }, "Conversation group renamed");
|
|
29
|
+
return group;
|
|
30
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineEventHandler } from "h3";
|
|
2
|
+
import { asc } from "drizzle-orm";
|
|
3
|
+
import { useDb, schema } from "#chat-runtime/server/db";
|
|
4
|
+
import { resolveChatRuntimeContext } from "#chat-runtime/server/utils/chat-context";
|
|
5
|
+
import { conversationGroupScopeConditions } from "#chat-runtime/server/utils/conversation-group";
|
|
6
|
+
import { logger } from "#chat-runtime/server/utils/logger";
|
|
7
|
+
export default defineEventHandler(async (event) => {
|
|
8
|
+
const context = resolveChatRuntimeContext(event);
|
|
9
|
+
const db = useDb();
|
|
10
|
+
const groups = await db.select().from(schema.conversationGroups).where(conversationGroupScopeConditions(context)).orderBy(asc(schema.conversationGroups.createdAt), asc(schema.conversationGroups.name));
|
|
11
|
+
logger.debug({ workspaceId: context.workspaceId, count: groups.length }, "Conversation groups listed");
|
|
12
|
+
return groups;
|
|
13
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createError, defineEventHandler, readBody } from "h3";
|
|
2
|
+
import { useDb, schema } from "#chat-runtime/server/db";
|
|
3
|
+
import { resolveChatRuntimeContext } from "#chat-runtime/server/utils/chat-context";
|
|
4
|
+
import { resolveConversationGroupName } from "#chat-runtime/server/utils/conversation-group";
|
|
5
|
+
import { logger } from "#chat-runtime/server/utils/logger";
|
|
6
|
+
export default defineEventHandler(async (event) => {
|
|
7
|
+
const context = resolveChatRuntimeContext(event);
|
|
8
|
+
const db = useDb();
|
|
9
|
+
const body = await readBody(event);
|
|
10
|
+
const name = resolveConversationGroupName(body?.name);
|
|
11
|
+
const [group] = await db.insert(schema.conversationGroups).values({
|
|
12
|
+
workspaceId: context.workspaceId,
|
|
13
|
+
telaAgentId: context.telaAgentId,
|
|
14
|
+
conversationScope: context.conversationScope,
|
|
15
|
+
name,
|
|
16
|
+
createdBy: context.user.email
|
|
17
|
+
}).returning();
|
|
18
|
+
if (!group) {
|
|
19
|
+
throw createError({
|
|
20
|
+
statusCode: 500,
|
|
21
|
+
statusMessage: "Failed to create conversation group"
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
logger.info({ groupId: group.id, workspaceId: context.workspaceId }, "Conversation group created");
|
|
25
|
+
return group;
|
|
26
|
+
});
|
|
@@ -27,6 +27,7 @@ export default defineEventHandler(async (event) => {
|
|
|
27
27
|
}
|
|
28
28
|
const [conversation] = await db.insert(schema.conversations).values({
|
|
29
29
|
workspaceId: context.workspaceId,
|
|
30
|
+
groupId: null,
|
|
30
31
|
userId: context.user.id,
|
|
31
32
|
createdBy: context.user.email,
|
|
32
33
|
telaAgentId: context.telaAgentId,
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
export declare const conversationGroups: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
2
|
+
name: "conversation_groups";
|
|
3
|
+
schema: "chat";
|
|
4
|
+
columns: {
|
|
5
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
6
|
+
name: "id";
|
|
7
|
+
tableName: "conversation_groups";
|
|
8
|
+
dataType: "string";
|
|
9
|
+
columnType: "PgUUID";
|
|
10
|
+
data: string;
|
|
11
|
+
driverParam: string;
|
|
12
|
+
notNull: true;
|
|
13
|
+
hasDefault: true;
|
|
14
|
+
isPrimaryKey: true;
|
|
15
|
+
isAutoincrement: false;
|
|
16
|
+
hasRuntimeDefault: false;
|
|
17
|
+
enumValues: undefined;
|
|
18
|
+
baseColumn: never;
|
|
19
|
+
identity: undefined;
|
|
20
|
+
generated: undefined;
|
|
21
|
+
}, {}, {}>;
|
|
22
|
+
workspaceId: import("drizzle-orm/pg-core").PgColumn<{
|
|
23
|
+
name: "workspace_id";
|
|
24
|
+
tableName: "conversation_groups";
|
|
25
|
+
dataType: "string";
|
|
26
|
+
columnType: "PgText";
|
|
27
|
+
data: string;
|
|
28
|
+
driverParam: string;
|
|
29
|
+
notNull: true;
|
|
30
|
+
hasDefault: false;
|
|
31
|
+
isPrimaryKey: false;
|
|
32
|
+
isAutoincrement: false;
|
|
33
|
+
hasRuntimeDefault: false;
|
|
34
|
+
enumValues: [string, ...string[]];
|
|
35
|
+
baseColumn: never;
|
|
36
|
+
identity: undefined;
|
|
37
|
+
generated: undefined;
|
|
38
|
+
}, {}, {}>;
|
|
39
|
+
telaAgentId: import("drizzle-orm/pg-core").PgColumn<{
|
|
40
|
+
name: "tela_agent_id";
|
|
41
|
+
tableName: "conversation_groups";
|
|
42
|
+
dataType: "string";
|
|
43
|
+
columnType: "PgText";
|
|
44
|
+
data: string;
|
|
45
|
+
driverParam: string;
|
|
46
|
+
notNull: false;
|
|
47
|
+
hasDefault: false;
|
|
48
|
+
isPrimaryKey: false;
|
|
49
|
+
isAutoincrement: false;
|
|
50
|
+
hasRuntimeDefault: false;
|
|
51
|
+
enumValues: [string, ...string[]];
|
|
52
|
+
baseColumn: never;
|
|
53
|
+
identity: undefined;
|
|
54
|
+
generated: undefined;
|
|
55
|
+
}, {}, {}>;
|
|
56
|
+
conversationScope: import("drizzle-orm/pg-core").PgColumn<{
|
|
57
|
+
name: "conversation_scope";
|
|
58
|
+
tableName: "conversation_groups";
|
|
59
|
+
dataType: "string";
|
|
60
|
+
columnType: "PgText";
|
|
61
|
+
data: string;
|
|
62
|
+
driverParam: string;
|
|
63
|
+
notNull: false;
|
|
64
|
+
hasDefault: false;
|
|
65
|
+
isPrimaryKey: false;
|
|
66
|
+
isAutoincrement: false;
|
|
67
|
+
hasRuntimeDefault: false;
|
|
68
|
+
enumValues: [string, ...string[]];
|
|
69
|
+
baseColumn: never;
|
|
70
|
+
identity: undefined;
|
|
71
|
+
generated: undefined;
|
|
72
|
+
}, {}, {}>;
|
|
73
|
+
name: import("drizzle-orm/pg-core").PgColumn<{
|
|
74
|
+
name: "name";
|
|
75
|
+
tableName: "conversation_groups";
|
|
76
|
+
dataType: "string";
|
|
77
|
+
columnType: "PgText";
|
|
78
|
+
data: string;
|
|
79
|
+
driverParam: string;
|
|
80
|
+
notNull: true;
|
|
81
|
+
hasDefault: false;
|
|
82
|
+
isPrimaryKey: false;
|
|
83
|
+
isAutoincrement: false;
|
|
84
|
+
hasRuntimeDefault: false;
|
|
85
|
+
enumValues: [string, ...string[]];
|
|
86
|
+
baseColumn: never;
|
|
87
|
+
identity: undefined;
|
|
88
|
+
generated: undefined;
|
|
89
|
+
}, {}, {}>;
|
|
90
|
+
createdBy: import("drizzle-orm/pg-core").PgColumn<{
|
|
91
|
+
name: "created_by";
|
|
92
|
+
tableName: "conversation_groups";
|
|
93
|
+
dataType: "string";
|
|
94
|
+
columnType: "PgText";
|
|
95
|
+
data: string;
|
|
96
|
+
driverParam: string;
|
|
97
|
+
notNull: false;
|
|
98
|
+
hasDefault: false;
|
|
99
|
+
isPrimaryKey: false;
|
|
100
|
+
isAutoincrement: false;
|
|
101
|
+
hasRuntimeDefault: false;
|
|
102
|
+
enumValues: [string, ...string[]];
|
|
103
|
+
baseColumn: never;
|
|
104
|
+
identity: undefined;
|
|
105
|
+
generated: undefined;
|
|
106
|
+
}, {}, {}>;
|
|
107
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
108
|
+
name: "created_at";
|
|
109
|
+
tableName: "conversation_groups";
|
|
110
|
+
dataType: "date";
|
|
111
|
+
columnType: "PgTimestamp";
|
|
112
|
+
data: Date;
|
|
113
|
+
driverParam: string;
|
|
114
|
+
notNull: true;
|
|
115
|
+
hasDefault: true;
|
|
116
|
+
isPrimaryKey: false;
|
|
117
|
+
isAutoincrement: false;
|
|
118
|
+
hasRuntimeDefault: false;
|
|
119
|
+
enumValues: undefined;
|
|
120
|
+
baseColumn: never;
|
|
121
|
+
identity: undefined;
|
|
122
|
+
generated: undefined;
|
|
123
|
+
}, {}, {}>;
|
|
124
|
+
updatedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
125
|
+
name: "updated_at";
|
|
126
|
+
tableName: "conversation_groups";
|
|
127
|
+
dataType: "date";
|
|
128
|
+
columnType: "PgTimestamp";
|
|
129
|
+
data: Date;
|
|
130
|
+
driverParam: string;
|
|
131
|
+
notNull: true;
|
|
132
|
+
hasDefault: true;
|
|
133
|
+
isPrimaryKey: false;
|
|
134
|
+
isAutoincrement: false;
|
|
135
|
+
hasRuntimeDefault: false;
|
|
136
|
+
enumValues: undefined;
|
|
137
|
+
baseColumn: never;
|
|
138
|
+
identity: undefined;
|
|
139
|
+
generated: undefined;
|
|
140
|
+
}, {}, {}>;
|
|
141
|
+
};
|
|
142
|
+
dialect: "pg";
|
|
143
|
+
}>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { index, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
|
2
|
+
import { chatSchema } from "./_schema.js";
|
|
3
|
+
export const conversationGroups = chatSchema.table("conversation_groups", {
|
|
4
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
5
|
+
workspaceId: text("workspace_id").notNull(),
|
|
6
|
+
telaAgentId: text("tela_agent_id"),
|
|
7
|
+
conversationScope: text("conversation_scope"),
|
|
8
|
+
name: text("name").notNull(),
|
|
9
|
+
createdBy: text("created_by"),
|
|
10
|
+
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
11
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
12
|
+
}, (table) => [
|
|
13
|
+
index("idx_conversation_groups_workspace").on(table.workspaceId),
|
|
14
|
+
index("idx_conversation_groups_runtime_created_at").on(
|
|
15
|
+
table.workspaceId,
|
|
16
|
+
table.telaAgentId,
|
|
17
|
+
table.conversationScope,
|
|
18
|
+
table.createdAt
|
|
19
|
+
)
|
|
20
|
+
]);
|
|
@@ -37,6 +37,23 @@ export declare const conversations: import("drizzle-orm/pg-core").PgTableWithCol
|
|
|
37
37
|
identity: undefined;
|
|
38
38
|
generated: undefined;
|
|
39
39
|
}, {}, {}>;
|
|
40
|
+
groupId: import("drizzle-orm/pg-core").PgColumn<{
|
|
41
|
+
name: "group_id";
|
|
42
|
+
tableName: "conversations";
|
|
43
|
+
dataType: "string";
|
|
44
|
+
columnType: "PgUUID";
|
|
45
|
+
data: string;
|
|
46
|
+
driverParam: string;
|
|
47
|
+
notNull: false;
|
|
48
|
+
hasDefault: false;
|
|
49
|
+
isPrimaryKey: false;
|
|
50
|
+
isAutoincrement: false;
|
|
51
|
+
hasRuntimeDefault: false;
|
|
52
|
+
enumValues: undefined;
|
|
53
|
+
baseColumn: never;
|
|
54
|
+
identity: undefined;
|
|
55
|
+
generated: undefined;
|
|
56
|
+
}, {}, {}>;
|
|
40
57
|
userId: import("drizzle-orm/pg-core").PgColumn<{
|
|
41
58
|
name: "user_id";
|
|
42
59
|
tableName: "conversations";
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { uuid, text, timestamp, index, jsonb } from "drizzle-orm/pg-core";
|
|
2
2
|
import { chatSchema } from "./_schema.js";
|
|
3
|
+
import { conversationGroups } from "./conversation-groups.js";
|
|
3
4
|
export const conversations = chatSchema.table("conversations", {
|
|
4
5
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
5
6
|
workspaceId: text("workspace_id").notNull(),
|
|
7
|
+
groupId: uuid("group_id").references(() => conversationGroups.id, { onDelete: "set null" }),
|
|
6
8
|
userId: text("user_id").notNull(),
|
|
7
9
|
title: text("title").notNull().default("Nova conversa"),
|
|
8
10
|
threadSessionId: text("thread_session_id"),
|
|
@@ -16,6 +18,7 @@ export const conversations = chatSchema.table("conversations", {
|
|
|
16
18
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
17
19
|
}, (table) => [
|
|
18
20
|
index("idx_conversations_workspace").on(table.workspaceId),
|
|
21
|
+
index("idx_conversations_group").on(table.groupId),
|
|
19
22
|
index("idx_conversations_user").on(table.userId),
|
|
20
23
|
index("idx_conversations_updated").on(table.updatedAt),
|
|
21
24
|
index("idx_conversations_workspace_tela_agent_updated").on(table.workspaceId, table.telaAgentId, table.updatedAt)
|