@meistrari/chat-nuxt 1.11.0 → 1.12.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/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/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/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/utils/conversation-group.d.ts +4 -0
- package/dist/runtime/server/utils/conversation-group.js +48 -0
- package/dist/runtime/types/chat.d.ts +2 -1
- 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/meta/0016_snapshot.json +887 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +1 -1
|
@@ -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
|
+
});
|
|
@@ -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)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { CHAT_SCHEMA_NAME, chatSchema } from './_schema.js';
|
|
2
|
+
export { conversationGroups } from './conversation-groups.js';
|
|
2
3
|
export { conversationUsage, type ConversationUsageMetadata, type ModelUsageEntry } from './conversation-usage.js';
|
|
3
4
|
export { conversations } from './conversations.js';
|
|
4
5
|
export { type ExternalSkillInsert, type ExternalSkillRow, externalSkills, externalSkillsRelations } from './external-skills.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { CHAT_SCHEMA_NAME, chatSchema } from "./_schema.js";
|
|
2
|
+
export { conversationGroups } from "./conversation-groups.js";
|
|
2
3
|
export { conversationUsage } from "./conversation-usage.js";
|
|
3
4
|
export { conversations } from "./conversations.js";
|
|
4
5
|
export { externalSkills, externalSkillsRelations } from "./external-skills.js";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ChatRuntimeContext } from '#chat-runtime/server/utils/chat-context';
|
|
2
|
+
export declare function conversationGroupScopeConditions(context: ChatRuntimeContext, groupId?: string): import("drizzle-orm").SQL<unknown> | undefined;
|
|
3
|
+
export declare function resolveConversationGroupName(name: unknown): string;
|
|
4
|
+
export declare function resolveOptionalConversationGroupId(groupId: unknown): string | null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { and, eq, isNull } from "drizzle-orm";
|
|
2
|
+
import { createError } from "h3";
|
|
3
|
+
import { schema } from "#chat-runtime/server/db";
|
|
4
|
+
const MAX_GROUP_NAME_LENGTH = 80;
|
|
5
|
+
export function conversationGroupScopeConditions(context, groupId) {
|
|
6
|
+
const conditions = [
|
|
7
|
+
eq(schema.conversationGroups.workspaceId, context.workspaceId),
|
|
8
|
+
context.telaAgentId ? eq(schema.conversationGroups.telaAgentId, context.telaAgentId) : isNull(schema.conversationGroups.telaAgentId),
|
|
9
|
+
context.conversationScope ? eq(schema.conversationGroups.conversationScope, context.conversationScope) : isNull(schema.conversationGroups.conversationScope)
|
|
10
|
+
];
|
|
11
|
+
if (groupId) {
|
|
12
|
+
conditions.unshift(eq(schema.conversationGroups.id, groupId));
|
|
13
|
+
}
|
|
14
|
+
return and(...conditions);
|
|
15
|
+
}
|
|
16
|
+
export function resolveConversationGroupName(name) {
|
|
17
|
+
if (typeof name !== "string") {
|
|
18
|
+
throw createError({
|
|
19
|
+
statusCode: 400,
|
|
20
|
+
statusMessage: "Group name is required"
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const trimmedName = name.trim();
|
|
24
|
+
if (!trimmedName) {
|
|
25
|
+
throw createError({
|
|
26
|
+
statusCode: 400,
|
|
27
|
+
statusMessage: "Group name cannot be empty"
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (trimmedName.length > MAX_GROUP_NAME_LENGTH) {
|
|
31
|
+
throw createError({
|
|
32
|
+
statusCode: 400,
|
|
33
|
+
statusMessage: "Group name is too long"
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return trimmedName;
|
|
37
|
+
}
|
|
38
|
+
export function resolveOptionalConversationGroupId(groupId) {
|
|
39
|
+
if (groupId === null)
|
|
40
|
+
return null;
|
|
41
|
+
if (typeof groupId !== "string" || !groupId.trim()) {
|
|
42
|
+
throw createError({
|
|
43
|
+
statusCode: 400,
|
|
44
|
+
statusMessage: "Invalid group ID"
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return groupId.trim();
|
|
48
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { InferSelectModel } from 'drizzle-orm';
|
|
2
|
-
import type { conversations, messages, ContextFile as SchemaContextFile, ExternalSkill as SchemaExternalSkill, MessageFile as SchemaMessageFile } from '#chat-runtime/server/db/schema';
|
|
2
|
+
import type { conversationGroups, conversations, messages, ContextFile as SchemaContextFile, ExternalSkill as SchemaExternalSkill, MessageFile as SchemaMessageFile } from '#chat-runtime/server/db/schema';
|
|
3
3
|
export type ContextFile = SchemaContextFile;
|
|
4
4
|
export type ExternalSkill = SchemaExternalSkill;
|
|
5
5
|
export type MessageFile = SchemaMessageFile;
|
|
6
6
|
export type Conversation = InferSelectModel<typeof conversations>;
|
|
7
|
+
export type ConversationGroup = InferSelectModel<typeof conversationGroups>;
|
|
7
8
|
export type Message = InferSelectModel<typeof messages>;
|
|
8
9
|
export type ConversationCreatorFilter = 'all' | 'mine';
|
|
9
10
|
export type ConversationCreatorFilterCounts = Record<ConversationCreatorFilter, number>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type ConversationGroupLike = {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
createdAt?: Date | string;
|
|
5
|
+
};
|
|
6
|
+
export type ConversationGroupItem = {
|
|
7
|
+
groupId?: string | null;
|
|
8
|
+
updatedAt: Date | string;
|
|
9
|
+
};
|
|
10
|
+
export type ConversationGroupBucket<TGroup extends ConversationGroupLike, TConversation extends ConversationGroupItem> = {
|
|
11
|
+
group: TGroup;
|
|
12
|
+
items: TConversation[];
|
|
13
|
+
};
|
|
14
|
+
export type GroupedConversations<TGroup extends ConversationGroupLike, TConversation extends ConversationGroupItem> = {
|
|
15
|
+
groups: ConversationGroupBucket<TGroup, TConversation>[];
|
|
16
|
+
unfiled: TConversation[];
|
|
17
|
+
};
|
|
18
|
+
export declare function groupConversationsByGroup<TConversation extends ConversationGroupItem, TGroup extends ConversationGroupLike>(conversations: readonly TConversation[], groups: readonly TGroup[]): GroupedConversations<TGroup, TConversation>;
|