@lobehub/chat 1.35.9 → 1.35.10

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 (55) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/package.json +1 -1
  4. package/src/app/(main)/repos/[id]/@menu/default.tsx +2 -1
  5. package/src/app/(main)/repos/[id]/page.tsx +2 -1
  6. package/src/database/schemas/topic.ts +3 -1
  7. package/src/database/server/core/dbForTest.ts +4 -6
  8. package/src/database/server/models/__tests__/_test_template.ts +3 -9
  9. package/src/database/server/models/__tests__/agent.test.ts +2 -8
  10. package/src/database/server/models/__tests__/asyncTask.test.ts +1 -7
  11. package/src/database/server/models/__tests__/chunk.test.ts +155 -16
  12. package/src/database/server/models/__tests__/file.test.ts +123 -15
  13. package/src/database/server/models/__tests__/knowledgeBase.test.ts +6 -12
  14. package/src/database/server/models/__tests__/message.test.ts +230 -7
  15. package/src/database/server/models/__tests__/nextauth.test.ts +1 -7
  16. package/src/database/server/models/__tests__/plugin.test.ts +1 -7
  17. package/src/database/server/models/__tests__/session.test.ts +169 -11
  18. package/src/database/server/models/__tests__/sessionGroup.test.ts +2 -8
  19. package/src/database/server/models/__tests__/topic.test.ts +1 -7
  20. package/src/database/server/models/__tests__/user.test.ts +55 -20
  21. package/src/database/server/models/_template.ts +10 -8
  22. package/src/database/server/models/agent.ts +17 -13
  23. package/src/database/server/models/asyncTask.ts +11 -9
  24. package/src/database/server/models/chunk.ts +19 -14
  25. package/src/database/server/models/embedding.ts +10 -8
  26. package/src/database/server/models/file.ts +19 -17
  27. package/src/database/server/models/knowledgeBase.ts +14 -12
  28. package/src/database/server/models/message.ts +36 -34
  29. package/src/database/server/models/plugin.ts +10 -8
  30. package/src/database/server/models/session.ts +23 -64
  31. package/src/database/server/models/sessionGroup.ts +11 -9
  32. package/src/database/server/models/thread.ts +11 -9
  33. package/src/database/server/models/topic.ts +19 -22
  34. package/src/database/server/models/user.ts +96 -84
  35. package/src/database/type.ts +7 -0
  36. package/src/libs/next-auth/adapter/index.ts +10 -10
  37. package/src/libs/trpc/async/asyncAuth.ts +2 -1
  38. package/src/server/routers/async/file.ts +5 -4
  39. package/src/server/routers/async/ragEval.ts +4 -3
  40. package/src/server/routers/lambda/_template.ts +2 -1
  41. package/src/server/routers/lambda/agent.ts +6 -5
  42. package/src/server/routers/lambda/chunk.ts +5 -5
  43. package/src/server/routers/lambda/file.ts +4 -3
  44. package/src/server/routers/lambda/knowledgeBase.ts +2 -1
  45. package/src/server/routers/lambda/message.ts +4 -2
  46. package/src/server/routers/lambda/plugin.ts +4 -2
  47. package/src/server/routers/lambda/ragEval.ts +2 -1
  48. package/src/server/routers/lambda/session.ts +4 -3
  49. package/src/server/routers/lambda/sessionGroup.ts +2 -1
  50. package/src/server/routers/lambda/thread.ts +3 -2
  51. package/src/server/routers/lambda/topic.ts +4 -2
  52. package/src/server/routers/lambda/user.ts +10 -9
  53. package/src/server/services/chunk/index.ts +3 -2
  54. package/src/server/services/nextAuthUser/index.ts +3 -3
  55. package/src/server/services/user/index.ts +7 -6
@@ -1,10 +1,11 @@
1
1
  import { Column, asc, count, inArray, like, sql } from 'drizzle-orm';
2
- import { and, desc, eq, isNull, not, or } from 'drizzle-orm/expressions';
2
+ import { and, desc, eq, not, or } from 'drizzle-orm/expressions';
3
3
 
4
4
  import { appEnv } from '@/config/app';
5
5
  import { INBOX_SESSION_ID } from '@/const/session';
6
6
  import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
7
- import { serverDB } from '@/database/server/core/db';
7
+ import { LobeChatDatabase } from '@/database/type';
8
+ import { idGenerator } from '@/database/utils/idGenerator';
8
9
  import { parseAgentConfig } from '@/server/globalConfig/parseDefaultAgent';
9
10
  import { ChatSessionList, LobeAgentSession } from '@/types/session';
10
11
  import { merge } from '@/utils/merge';
@@ -19,20 +20,21 @@ import {
19
20
  sessionGroups,
20
21
  sessions,
21
22
  } from '../../schemas';
22
- import { idGenerator } from '@/database/utils/idGenerator';
23
23
 
24
24
  export class SessionModel {
25
25
  private userId: string;
26
+ private db: LobeChatDatabase;
26
27
 
27
- constructor(userId: string) {
28
+ constructor(db: LobeChatDatabase, userId: string) {
28
29
  this.userId = userId;
30
+ this.db = db;
29
31
  }
30
32
  // **************** Query *************** //
31
33
 
32
34
  async query({ current = 0, pageSize = 9999 } = {}) {
33
35
  const offset = current * pageSize;
34
36
 
35
- return serverDB.query.sessions.findMany({
37
+ return this.db.query.sessions.findMany({
36
38
  limit: pageSize,
37
39
  offset,
38
40
  orderBy: [desc(sessions.updatedAt)],
@@ -45,7 +47,7 @@ export class SessionModel {
45
47
  // 查询所有会话
46
48
  const result = await this.query();
47
49
 
48
- const groups = await serverDB.query.sessionGroups.findMany({
50
+ const groups = await this.db.query.sessionGroups.findMany({
49
51
  orderBy: [asc(sessionGroups.sort), desc(sessionGroups.createdAt)],
50
52
  where: eq(sessions.userId, this.userId),
51
53
  });
@@ -69,7 +71,7 @@ export class SessionModel {
69
71
  async findByIdOrSlug(
70
72
  idOrSlug: string,
71
73
  ): Promise<(SessionItem & { agent: AgentItem }) | undefined> {
72
- const result = await serverDB.query.sessions.findFirst({
74
+ const result = await this.db.query.sessions.findFirst({
73
75
  where: and(
74
76
  or(eq(sessions.id, idOrSlug), eq(sessions.slug, idOrSlug)),
75
77
  eq(sessions.userId, this.userId),
@@ -83,7 +85,7 @@ export class SessionModel {
83
85
  }
84
86
 
85
87
  async count() {
86
- const result = await serverDB
88
+ const result = await this.db
87
89
  .select({
88
90
  count: count(),
89
91
  })
@@ -109,7 +111,7 @@ export class SessionModel {
109
111
  slug?: string;
110
112
  type: 'agent' | 'group';
111
113
  }): Promise<SessionItem> {
112
- return serverDB.transaction(async (trx) => {
114
+ return this.db.transaction(async (trx) => {
113
115
  const newAgents = await trx
114
116
  .insert(agents)
115
117
  .values({
@@ -144,7 +146,7 @@ export class SessionModel {
144
146
  }
145
147
 
146
148
  async createInbox() {
147
- const item = await serverDB.query.sessions.findFirst({
149
+ const item = await this.db.query.sessions.findFirst({
148
150
  where: and(eq(sessions.userId, this.userId), eq(sessions.slug, INBOX_SESSION_ID)),
149
151
  });
150
152
  if (item) return;
@@ -167,7 +169,7 @@ export class SessionModel {
167
169
  };
168
170
  });
169
171
 
170
- return serverDB.insert(sessions).values(sessionsToInsert);
172
+ return this.db.insert(sessions).values(sessionsToInsert);
171
173
  }
172
174
 
173
175
  async duplicate(id: string, newTitle?: string) {
@@ -199,7 +201,7 @@ export class SessionModel {
199
201
  * Delete a session, also delete all messages and topics associated with it.
200
202
  */
201
203
  async delete(id: string) {
202
- return serverDB
204
+ return this.db
203
205
  .delete(sessions)
204
206
  .where(and(eq(sessions.id, id), eq(sessions.userId, this.userId)));
205
207
  }
@@ -208,18 +210,18 @@ export class SessionModel {
208
210
  * Batch delete sessions, also delete all messages and topics associated with them.
209
211
  */
210
212
  async batchDelete(ids: string[]) {
211
- return serverDB
213
+ return this.db
212
214
  .delete(sessions)
213
215
  .where(and(inArray(sessions.id, ids), eq(sessions.userId, this.userId)));
214
216
  }
215
217
 
216
218
  async deleteAll() {
217
- return serverDB.delete(sessions).where(eq(sessions.userId, this.userId));
219
+ return this.db.delete(sessions).where(eq(sessions.userId, this.userId));
218
220
  }
219
221
  // **************** Update *************** //
220
222
 
221
223
  async update(id: string, data: Partial<SessionItem>) {
222
- return serverDB
224
+ return this.db
223
225
  .update(sessions)
224
226
  .set(data)
225
227
  .where(and(eq(sessions.id, id), eq(sessions.userId, this.userId)))
@@ -227,7 +229,7 @@ export class SessionModel {
227
229
  }
228
230
 
229
231
  async updateConfig(id: string, data: Partial<AgentItem>) {
230
- return serverDB
232
+ return this.db
231
233
  .update(agents)
232
234
  .set(data)
233
235
  .where(and(eq(agents.id, id), eq(agents.userId, this.userId)));
@@ -262,65 +264,22 @@ export class SessionModel {
262
264
  } as any;
263
265
  };
264
266
 
265
- async findSessions(params: {
266
- current?: number;
267
- group?: string;
268
- keyword?: string;
269
- pageSize?: number;
270
- pinned?: boolean;
271
- }) {
272
- const { pinned, keyword, group, pageSize = 9999, current = 0 } = params;
273
-
274
- const offset = current * pageSize;
275
- return serverDB.query.sessions.findMany({
276
- limit: pageSize,
277
- offset,
278
- orderBy: [desc(sessions.updatedAt)],
279
- where: and(
280
- eq(sessions.userId, this.userId),
281
- pinned !== undefined ? eq(sessions.pinned, pinned) : eq(sessions.userId, this.userId),
282
- keyword
283
- ? or(
284
- like(
285
- sql`lower(${sessions.title})` as unknown as Column,
286
- `%${keyword.toLowerCase()}%`,
287
- ),
288
- like(
289
- sql`lower(${sessions.description})` as unknown as Column,
290
- `%${keyword.toLowerCase()}%`,
291
- ),
292
- )
293
- : eq(sessions.userId, this.userId),
294
- group ? eq(sessions.groupId, group) : isNull(sessions.groupId),
295
- ),
296
-
297
- with: { agentsToSessions: { columns: {}, with: { agent: true } }, group: true },
298
- });
299
- }
300
-
301
- async findSessionsByKeywords(params: {
302
- current?: number;
303
- keyword: string;
304
- pageSize?: number;
305
- }) {
267
+ async findSessionsByKeywords(params: { current?: number; keyword: string; pageSize?: number }) {
306
268
  const { keyword, pageSize = 9999, current = 0 } = params;
307
269
  const offset = current * pageSize;
308
- const results = await serverDB.query.agents.findMany({
270
+ const results = await this.db.query.agents.findMany({
309
271
  limit: pageSize,
310
272
  offset,
311
273
  orderBy: [desc(agents.updatedAt)],
312
274
  where: and(
313
275
  eq(agents.userId, this.userId),
314
276
  or(
315
- like(
316
- sql`lower(${agents.title})` as unknown as Column,
317
- `%${keyword.toLowerCase()}%`,
318
- ),
277
+ like(sql`lower(${agents.title})` as unknown as Column, `%${keyword.toLowerCase()}%`),
319
278
  like(
320
279
  sql`lower(${agents.description})` as unknown as Column,
321
280
  `%${keyword.toLowerCase()}%`,
322
281
  ),
323
- )
282
+ ),
324
283
  ),
325
284
  with: { agentsToSessions: { columns: {}, with: { session: true } } },
326
285
  });
@@ -328,6 +287,6 @@ export class SessionModel {
328
287
  // @ts-expect-error
329
288
  return results.map((item) => item.agentsToSessions[0].session);
330
289
  } catch {}
331
- return []
290
+ return [];
332
291
  }
333
292
  }
@@ -1,20 +1,22 @@
1
1
  import { eq } from 'drizzle-orm';
2
2
  import { and, asc, desc } from 'drizzle-orm/expressions';
3
3
 
4
- import { serverDB } from '@/database/server';
4
+ import { LobeChatDatabase } from '@/database/type';
5
5
  import { idGenerator } from '@/database/utils/idGenerator';
6
6
 
7
7
  import { SessionGroupItem, sessionGroups } from '../../schemas';
8
8
 
9
9
  export class SessionGroupModel {
10
10
  private userId: string;
11
+ private db: LobeChatDatabase;
11
12
 
12
- constructor(userId: string) {
13
+ constructor(db: LobeChatDatabase, userId: string) {
13
14
  this.userId = userId;
15
+ this.db = db;
14
16
  }
15
17
 
16
18
  create = async (params: { name: string; sort?: number }) => {
17
- const [result] = await serverDB
19
+ const [result] = await this.db
18
20
  .insert(sessionGroups)
19
21
  .values({ ...params, id: this.genId(), userId: this.userId })
20
22
  .returning();
@@ -23,37 +25,37 @@ export class SessionGroupModel {
23
25
  };
24
26
 
25
27
  delete = async (id: string) => {
26
- return serverDB
28
+ return this.db
27
29
  .delete(sessionGroups)
28
30
  .where(and(eq(sessionGroups.id, id), eq(sessionGroups.userId, this.userId)));
29
31
  };
30
32
 
31
33
  deleteAll = async () => {
32
- return serverDB.delete(sessionGroups).where(eq(sessionGroups.userId, this.userId));
34
+ return this.db.delete(sessionGroups).where(eq(sessionGroups.userId, this.userId));
33
35
  };
34
36
 
35
37
  query = async () => {
36
- return serverDB.query.sessionGroups.findMany({
38
+ return this.db.query.sessionGroups.findMany({
37
39
  orderBy: [asc(sessionGroups.sort), desc(sessionGroups.createdAt)],
38
40
  where: eq(sessionGroups.userId, this.userId),
39
41
  });
40
42
  };
41
43
 
42
44
  findById = async (id: string) => {
43
- return serverDB.query.sessionGroups.findFirst({
45
+ return this.db.query.sessionGroups.findFirst({
44
46
  where: and(eq(sessionGroups.id, id), eq(sessionGroups.userId, this.userId)),
45
47
  });
46
48
  };
47
49
 
48
50
  async update(id: string, value: Partial<SessionGroupItem>) {
49
- return serverDB
51
+ return this.db
50
52
  .update(sessionGroups)
51
53
  .set({ ...value, updatedAt: new Date() })
52
54
  .where(and(eq(sessionGroups.id, id), eq(sessionGroups.userId, this.userId)));
53
55
  }
54
56
 
55
57
  async updateOrder(sortMap: { id: string; sort: number }[]) {
56
- await serverDB.transaction(async (tx) => {
58
+ await this.db.transaction(async (tx) => {
57
59
  const updates = sortMap.map(({ id, sort }) => {
58
60
  return tx
59
61
  .update(sessionGroups)
@@ -1,7 +1,7 @@
1
1
  import { eq } from 'drizzle-orm';
2
2
  import { and, desc } from 'drizzle-orm/expressions';
3
3
 
4
- import { serverDB } from '@/database/server';
4
+ import { LobeChatDatabase } from '@/database/type';
5
5
  import { CreateThreadParams, ThreadStatus } from '@/types/topic';
6
6
 
7
7
  import { ThreadItem, threads } from '../../schemas';
@@ -20,14 +20,16 @@ const queryColumns = {
20
20
 
21
21
  export class ThreadModel {
22
22
  private userId: string;
23
+ private db: LobeChatDatabase;
23
24
 
24
- constructor(userId: string) {
25
+ constructor(db: LobeChatDatabase, userId: string) {
25
26
  this.userId = userId;
27
+ this.db = db;
26
28
  }
27
29
 
28
30
  create = async (params: CreateThreadParams) => {
29
31
  // @ts-ignore
30
- const [result] = await serverDB
32
+ const [result] = await this.db
31
33
  .insert(threads)
32
34
  .values({ ...params, status: ThreadStatus.Active, userId: this.userId })
33
35
  .onConflictDoNothing()
@@ -37,15 +39,15 @@ export class ThreadModel {
37
39
  };
38
40
 
39
41
  delete = async (id: string) => {
40
- return serverDB.delete(threads).where(and(eq(threads.id, id), eq(threads.userId, this.userId)));
42
+ return this.db.delete(threads).where(and(eq(threads.id, id), eq(threads.userId, this.userId)));
41
43
  };
42
44
 
43
45
  deleteAll = async () => {
44
- return serverDB.delete(threads).where(eq(threads.userId, this.userId));
46
+ return this.db.delete(threads).where(eq(threads.userId, this.userId));
45
47
  };
46
48
 
47
49
  query = async () => {
48
- const data = await serverDB
50
+ const data = await this.db
49
51
  .select(queryColumns)
50
52
  .from(threads)
51
53
  .where(eq(threads.userId, this.userId))
@@ -55,7 +57,7 @@ export class ThreadModel {
55
57
  };
56
58
 
57
59
  queryByTopicId = async (topicId: string) => {
58
- const data = await serverDB
60
+ const data = await this.db
59
61
  .select(queryColumns)
60
62
  .from(threads)
61
63
  .where(and(eq(threads.topicId, topicId), eq(threads.userId, this.userId)))
@@ -65,13 +67,13 @@ export class ThreadModel {
65
67
  };
66
68
 
67
69
  findById = async (id: string) => {
68
- return serverDB.query.threads.findFirst({
70
+ return this.db.query.threads.findFirst({
69
71
  where: and(eq(threads.id, id), eq(threads.userId, this.userId)),
70
72
  });
71
73
  };
72
74
 
73
75
  async update(id: string, value: Partial<ThreadItem>) {
74
- return serverDB
76
+ return this.db
75
77
  .update(threads)
76
78
  .set({ ...value, updatedAt: new Date() })
77
79
  .where(and(eq(threads.id, id), eq(threads.userId, this.userId)));
@@ -1,7 +1,7 @@
1
1
  import { Column, count, inArray, sql } from 'drizzle-orm';
2
2
  import { and, desc, eq, exists, isNull, like, or } from 'drizzle-orm/expressions';
3
3
 
4
- import { serverDB } from '@/database/server/core/db';
4
+ import { LobeChatDatabase } from '@/database/type';
5
5
 
6
6
  import { NewMessage, TopicItem, messages, topics } from '../../schemas';
7
7
  import { idGenerator } from '@/database/utils/idGenerator';
@@ -21,9 +21,11 @@ interface QueryTopicParams {
21
21
 
22
22
  export class TopicModel {
23
23
  private userId: string;
24
+ private db: LobeChatDatabase;
24
25
 
25
- constructor(userId: string) {
26
+ constructor(db: LobeChatDatabase, userId: string) {
26
27
  this.userId = userId;
28
+ this.db = db;
27
29
  }
28
30
  // **************** Query *************** //
29
31
 
@@ -31,7 +33,7 @@ export class TopicModel {
31
33
  const offset = current * pageSize;
32
34
 
33
35
  return (
34
- serverDB
36
+ this.db
35
37
  .select({
36
38
  createdAt: topics.createdAt,
37
39
  favorite: topics.favorite,
@@ -52,13 +54,13 @@ export class TopicModel {
52
54
  }
53
55
 
54
56
  async findById(id: string) {
55
- return serverDB.query.topics.findFirst({
57
+ return this.db.query.topics.findFirst({
56
58
  where: and(eq(topics.id, id), eq(topics.userId, this.userId)),
57
59
  });
58
60
  }
59
61
 
60
62
  async queryAll(): Promise<TopicItem[]> {
61
- return serverDB
63
+ return this.db
62
64
  .select()
63
65
  .from(topics)
64
66
  .orderBy(topics.updatedAt)
@@ -74,7 +76,7 @@ export class TopicModel {
74
76
  const matchKeyword = (field: any) =>
75
77
  like(sql`lower(${field})` as unknown as Column, `%${keywordLowerCase}%`);
76
78
 
77
- return serverDB.query.topics.findMany({
79
+ return this.db.query.topics.findMany({
78
80
  orderBy: [desc(topics.updatedAt)],
79
81
  where: and(
80
82
  eq(topics.userId, this.userId),
@@ -82,15 +84,10 @@ export class TopicModel {
82
84
  or(
83
85
  matchKeyword(topics.title),
84
86
  exists(
85
- serverDB
87
+ this.db
86
88
  .select()
87
89
  .from(messages)
88
- .where(
89
- and(
90
- eq(messages.topicId, topics.id),
91
- matchKeyword(messages.content)
92
- )
93
- ),
90
+ .where(and(eq(messages.topicId, topics.id), matchKeyword(messages.content))),
94
91
  ),
95
92
  ),
96
93
  ),
@@ -98,7 +95,7 @@ export class TopicModel {
98
95
  }
99
96
 
100
97
  async count() {
101
- const result = await serverDB
98
+ const result = await this.db
102
99
  .select({
103
100
  count: count(),
104
101
  })
@@ -115,7 +112,7 @@ export class TopicModel {
115
112
  { messages: messageIds, ...params }: CreateTopicParams,
116
113
  id: string = this.genId(),
117
114
  ): Promise<TopicItem> {
118
- return serverDB.transaction(async (tx) => {
115
+ return this.db.transaction(async (tx) => {
119
116
  // 在 topics 表中插入新的 topic
120
117
  const [topic] = await tx
121
118
  .insert(topics)
@@ -140,7 +137,7 @@ export class TopicModel {
140
137
 
141
138
  async batchCreate(topicParams: (CreateTopicParams & { id?: string })[]) {
142
139
  // 开始一个事务
143
- return serverDB.transaction(async (tx) => {
140
+ return this.db.transaction(async (tx) => {
144
141
  // 在 topics 表中批量插入新的 topics
145
142
  const createdTopics = await tx
146
143
  .insert(topics)
@@ -173,7 +170,7 @@ export class TopicModel {
173
170
  }
174
171
 
175
172
  async duplicate(topicId: string, newTitle?: string) {
176
- return serverDB.transaction(async (tx) => {
173
+ return this.db.transaction(async (tx) => {
177
174
  // find original topic
178
175
  const originalTopic = await tx.query.topics.findFirst({
179
176
  where: and(eq(topics.id, topicId), eq(topics.userId, this.userId)),
@@ -228,14 +225,14 @@ export class TopicModel {
228
225
  * Delete a session, also delete all messages and topics associated with it.
229
226
  */
230
227
  async delete(id: string) {
231
- return serverDB.delete(topics).where(and(eq(topics.id, id), eq(topics.userId, this.userId)));
228
+ return this.db.delete(topics).where(and(eq(topics.id, id), eq(topics.userId, this.userId)));
232
229
  }
233
230
 
234
231
  /**
235
232
  * Deletes multiple topics based on the sessionId.
236
233
  */
237
234
  async batchDeleteBySessionId(sessionId?: string | null) {
238
- return serverDB
235
+ return this.db
239
236
  .delete(topics)
240
237
  .where(and(this.matchSession(sessionId), eq(topics.userId, this.userId)));
241
238
  }
@@ -244,19 +241,19 @@ export class TopicModel {
244
241
  * Deletes multiple topics and all messages associated with them in a transaction.
245
242
  */
246
243
  async batchDelete(ids: string[]) {
247
- return serverDB
244
+ return this.db
248
245
  .delete(topics)
249
246
  .where(and(inArray(topics.id, ids), eq(topics.userId, this.userId)));
250
247
  }
251
248
 
252
249
  async deleteAll() {
253
- return serverDB.delete(topics).where(eq(topics.userId, this.userId));
250
+ return this.db.delete(topics).where(eq(topics.userId, this.userId));
254
251
  }
255
252
 
256
253
  // **************** Update *************** //
257
254
 
258
255
  async update(id: string, data: Partial<TopicItem>) {
259
- return serverDB
256
+ return this.db
260
257
  .update(topics)
261
258
  .set({ ...data, updatedAt: new Date() })
262
259
  .where(and(eq(topics.id, id), eq(topics.userId, this.userId)))