@lobehub/lobehub 2.0.0-next.25 → 2.0.0-next.27

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 (73) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/docs/development/database-schema.dbml +1 -0
  4. package/e2e/src/features/discover/detail-pages.feature +95 -0
  5. package/e2e/src/features/discover/interactions.feature +113 -0
  6. package/e2e/src/steps/discover/detail-pages.steps.ts +295 -0
  7. package/e2e/src/steps/discover/interactions.steps.ts +451 -0
  8. package/package.json +1 -1
  9. package/packages/database/migrations/0043_add_ai_model_settings.sql +1 -0
  10. package/packages/database/migrations/meta/0043_snapshot.json +8419 -0
  11. package/packages/database/migrations/meta/_journal.json +7 -0
  12. package/packages/database/src/core/migrations.json +10 -2
  13. package/packages/database/src/repositories/aiInfra/index.test.ts +198 -0
  14. package/packages/database/src/repositories/aiInfra/index.ts +2 -1
  15. package/packages/database/src/schemas/aiInfra.ts +2 -0
  16. package/packages/types/src/topic/topic.ts +14 -0
  17. package/src/server/routers/lambda/topic.ts +7 -1
  18. package/src/services/aiModel/index.test.ts +3 -3
  19. package/src/services/aiModel/index.ts +56 -2
  20. package/src/services/aiProvider/index.test.ts +2 -2
  21. package/src/services/aiProvider/index.ts +48 -2
  22. package/src/services/chatGroup/index.ts +66 -2
  23. package/src/services/export/index.ts +10 -2
  24. package/src/services/file/index.ts +61 -2
  25. package/src/services/import/index.ts +133 -2
  26. package/src/services/message/index.ts +176 -2
  27. package/src/services/message/{__tests__/server.test.ts → server.test.ts} +3 -3
  28. package/src/services/plugin/index.test.ts +8 -0
  29. package/src/services/plugin/index.ts +53 -2
  30. package/src/services/session/index.test.ts +8 -0
  31. package/src/services/session/index.ts +145 -2
  32. package/src/services/thread/index.test.ts +8 -0
  33. package/src/services/thread/index.ts +38 -2
  34. package/src/services/topic/index.test.ts +8 -0
  35. package/src/services/topic/index.ts +76 -2
  36. package/src/services/user/index.test.ts +8 -0
  37. package/src/services/user/index.ts +53 -2
  38. package/src/store/aiInfra/slices/aiModel/action.test.ts +17 -9
  39. package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +4 -2
  40. package/src/store/chat/slices/topic/action.test.ts +1 -1
  41. package/src/store/chat/slices/topic/action.ts +1 -2
  42. package/src/store/chat/slices/topic/reducer.ts +1 -2
  43. package/src/store/file/slices/chat/action.ts +1 -4
  44. package/src/store/file/slices/fileManager/action.ts +2 -3
  45. package/src/store/session/slices/sessionGroup/action.test.ts +5 -5
  46. package/src/store/user/slices/common/action.test.ts +1 -1
  47. package/src/services/aiModel/server.test.ts +0 -122
  48. package/src/services/aiModel/server.ts +0 -51
  49. package/src/services/aiModel/type.ts +0 -32
  50. package/src/services/aiProvider/server.ts +0 -43
  51. package/src/services/aiProvider/type.ts +0 -27
  52. package/src/services/chatGroup/server.ts +0 -67
  53. package/src/services/chatGroup/type.ts +0 -22
  54. package/src/services/export/server.ts +0 -9
  55. package/src/services/export/type.ts +0 -5
  56. package/src/services/file/server.ts +0 -53
  57. package/src/services/file/type.ts +0 -13
  58. package/src/services/import/server.ts +0 -133
  59. package/src/services/import/type.ts +0 -17
  60. package/src/services/message/server.ts +0 -151
  61. package/src/services/message/type.ts +0 -55
  62. package/src/services/plugin/server.ts +0 -42
  63. package/src/services/plugin/type.ts +0 -23
  64. package/src/services/session/server.test.ts +0 -260
  65. package/src/services/session/server.ts +0 -125
  66. package/src/services/session/type.ts +0 -82
  67. package/src/services/thread/server.ts +0 -32
  68. package/src/services/thread/type.ts +0 -21
  69. package/src/services/topic/server.ts +0 -57
  70. package/src/services/topic/type.ts +0 -40
  71. package/src/services/user/server.test.ts +0 -149
  72. package/src/services/user/server.ts +0 -47
  73. package/src/services/user/type.ts +0 -21
@@ -301,6 +301,13 @@
301
301
  "when": 1762232313711,
302
302
  "tag": "0042_improve_agent_index",
303
303
  "breakpoints": true
304
+ },
305
+ {
306
+ "idx": 43,
307
+ "version": "7",
308
+ "when": 1762251112601,
309
+ "tag": "0043_add_ai_model_settings",
310
+ "breakpoints": true
304
311
  }
305
312
  ],
306
313
  "version": "6"
@@ -749,10 +749,18 @@
749
749
  },
750
750
  {
751
751
  "sql": [
752
- "CREATE INDEX \"agents_knowledge_bases_agent_id_idx\" ON \"agents_knowledge_bases\" USING btree (\"agent_id\");"
752
+ "CREATE INDEX IF NOT EXISTS \"agents_knowledge_bases_agent_id_idx\" ON \"agents_knowledge_bases\" USING btree (\"agent_id\");\n"
753
753
  ],
754
754
  "bps": true,
755
755
  "folderMillis": 1762232313711,
756
- "hash": "8988ec15592e000430d76566323f437b2ebde46122c5f7172067cd0a65f99614"
756
+ "hash": "fd8e7ff36bf877ddc1a45d360edfe1fe9a579cd02d68d7664545d7df95b8eb09"
757
+ },
758
+ {
759
+ "sql": [
760
+ "ALTER TABLE \"ai_models\" ADD COLUMN IF NOT EXISTS \"settings\" jsonb DEFAULT '{}'::jsonb;"
761
+ ],
762
+ "bps": true,
763
+ "folderMillis": 1762251112601,
764
+ "hash": "923ccbdf46c32be9a981dabd348e6923b4a365444241e9b8cc174bf5b914cbc5"
757
765
  }
758
766
  ]
@@ -731,6 +731,105 @@ describe('AiInfraRepos', () => {
731
731
  // 无 settings
732
732
  expect(merged?.settings).toBeUndefined();
733
733
  });
734
+
735
+ it('should prefer user settings over builtin settings', async () => {
736
+ const mockProviders = [
737
+ { enabled: true, id: 'openai', name: 'OpenAI', source: 'builtin' as const },
738
+ ];
739
+
740
+ const userModel: EnabledAiModel = {
741
+ id: 'gpt-4',
742
+ providerId: 'openai',
743
+ enabled: true,
744
+ type: 'chat',
745
+ abilities: {},
746
+ settings: { searchImpl: 'params', searchProvider: 'user-provider' },
747
+ };
748
+
749
+ const builtinModel = {
750
+ id: 'gpt-4',
751
+ enabled: true,
752
+ type: 'chat' as const,
753
+ settings: { searchImpl: 'tool', searchProvider: 'builtin-provider' },
754
+ };
755
+
756
+ vi.spyOn(repo, 'getAiProviderList').mockResolvedValue(mockProviders);
757
+ vi.spyOn(repo.aiModelModel, 'getAllModels').mockResolvedValue([userModel]);
758
+ vi.spyOn(repo as any, 'fetchBuiltinModels').mockResolvedValue([builtinModel]);
759
+
760
+ const result = await repo.getEnabledModels();
761
+
762
+ const merged = result.find((m) => m.id === 'gpt-4');
763
+ expect(merged).toBeDefined();
764
+ // 应该使用用户的 settings,不是内置的
765
+ expect(merged?.settings).toEqual({ searchImpl: 'params', searchProvider: 'user-provider' });
766
+ });
767
+
768
+ it('should use builtin settings when user has no settings', async () => {
769
+ const mockProviders = [
770
+ { enabled: true, id: 'openai', name: 'OpenAI', source: 'builtin' as const },
771
+ ];
772
+
773
+ const userModel: EnabledAiModel = {
774
+ id: 'gpt-4',
775
+ providerId: 'openai',
776
+ enabled: true,
777
+ type: 'chat',
778
+ abilities: { vision: true },
779
+ // 用户未设置 settings
780
+ };
781
+
782
+ const builtinModel = {
783
+ id: 'gpt-4',
784
+ enabled: true,
785
+ type: 'chat' as const,
786
+ settings: { searchImpl: 'tool', searchProvider: 'google' },
787
+ };
788
+
789
+ vi.spyOn(repo, 'getAiProviderList').mockResolvedValue(mockProviders);
790
+ vi.spyOn(repo.aiModelModel, 'getAllModels').mockResolvedValue([userModel]);
791
+ vi.spyOn(repo as any, 'fetchBuiltinModels').mockResolvedValue([builtinModel]);
792
+
793
+ const result = await repo.getEnabledModels();
794
+
795
+ const merged = result.find((m) => m.id === 'gpt-4');
796
+ expect(merged).toBeDefined();
797
+ // 应该使用内置的 settings
798
+ expect(merged?.settings).toEqual({ searchImpl: 'tool', searchProvider: 'google' });
799
+ });
800
+
801
+ it('should have no settings when both user and builtin have no settings', async () => {
802
+ const mockProviders = [
803
+ { enabled: true, id: 'openai', name: 'OpenAI', source: 'builtin' as const },
804
+ ];
805
+
806
+ const userModel: EnabledAiModel = {
807
+ id: 'gpt-4',
808
+ providerId: 'openai',
809
+ enabled: true,
810
+ type: 'chat',
811
+ abilities: { vision: true },
812
+ // 用户未设置 settings
813
+ };
814
+
815
+ const builtinModel = {
816
+ id: 'gpt-4',
817
+ enabled: true,
818
+ type: 'chat' as const,
819
+ // 内置也无 settings
820
+ };
821
+
822
+ vi.spyOn(repo, 'getAiProviderList').mockResolvedValue(mockProviders);
823
+ vi.spyOn(repo.aiModelModel, 'getAllModels').mockResolvedValue([userModel]);
824
+ vi.spyOn(repo as any, 'fetchBuiltinModels').mockResolvedValue([builtinModel]);
825
+
826
+ const result = await repo.getEnabledModels();
827
+
828
+ const merged = result.find((m) => m.id === 'gpt-4');
829
+ expect(merged).toBeDefined();
830
+ // 无 settings
831
+ expect(merged?.settings).toBeUndefined();
832
+ });
734
833
  });
735
834
 
736
835
  describe('getAiProviderModelList', () => {
@@ -1270,6 +1369,105 @@ describe('AiInfraRepos', () => {
1270
1369
  // 无 settings
1271
1370
  expect(merged?.settings).toBeUndefined();
1272
1371
  });
1372
+
1373
+ it('should prefer user settings over builtin settings in getAiProviderModelList', async () => {
1374
+ const providerId = 'openai';
1375
+
1376
+ const userModels: AiProviderModelListItem[] = [
1377
+ {
1378
+ id: 'gpt-4',
1379
+ type: 'chat',
1380
+ enabled: true,
1381
+ abilities: {},
1382
+ settings: { searchImpl: 'params', searchProvider: 'user-provider' },
1383
+ } as any,
1384
+ ];
1385
+
1386
+ const builtinModels: AiProviderModelListItem[] = [
1387
+ {
1388
+ id: 'gpt-4',
1389
+ type: 'chat',
1390
+ enabled: true,
1391
+ settings: { searchImpl: 'tool', searchProvider: 'builtin-provider' },
1392
+ } as any,
1393
+ ];
1394
+
1395
+ vi.spyOn(repo.aiModelModel, 'getModelListByProviderId').mockResolvedValue(userModels);
1396
+ vi.spyOn(repo as any, 'fetchBuiltinModels').mockResolvedValue(builtinModels);
1397
+
1398
+ const result = await repo.getAiProviderModelList(providerId);
1399
+
1400
+ const merged = result.find((m) => m.id === 'gpt-4');
1401
+ expect(merged).toBeDefined();
1402
+ // 应该使用用户的 settings
1403
+ expect(merged?.settings).toEqual({ searchImpl: 'params', searchProvider: 'user-provider' });
1404
+ });
1405
+
1406
+ it('should use builtin settings when user has no settings in getAiProviderModelList', async () => {
1407
+ const providerId = 'openai';
1408
+
1409
+ const userModels: AiProviderModelListItem[] = [
1410
+ {
1411
+ id: 'gpt-4',
1412
+ type: 'chat',
1413
+ enabled: true,
1414
+ abilities: { vision: true },
1415
+ // 用户未设置 settings
1416
+ },
1417
+ ];
1418
+
1419
+ const builtinModels: AiProviderModelListItem[] = [
1420
+ {
1421
+ id: 'gpt-4',
1422
+ type: 'chat',
1423
+ enabled: true,
1424
+ settings: { searchImpl: 'tool', searchProvider: 'google' },
1425
+ } as any,
1426
+ ];
1427
+
1428
+ vi.spyOn(repo.aiModelModel, 'getModelListByProviderId').mockResolvedValue(userModels);
1429
+ vi.spyOn(repo as any, 'fetchBuiltinModels').mockResolvedValue(builtinModels);
1430
+
1431
+ const result = await repo.getAiProviderModelList(providerId);
1432
+
1433
+ const merged = result.find((m) => m.id === 'gpt-4');
1434
+ expect(merged).toBeDefined();
1435
+ // 应该使用内置的 settings
1436
+ expect(merged?.settings).toEqual({ searchImpl: 'tool', searchProvider: 'google' });
1437
+ });
1438
+
1439
+ it('should have no settings when both user and builtin have no settings in getAiProviderModelList', async () => {
1440
+ const providerId = 'openai';
1441
+
1442
+ const userModels: AiProviderModelListItem[] = [
1443
+ {
1444
+ id: 'gpt-4',
1445
+ type: 'chat',
1446
+ enabled: true,
1447
+ abilities: { vision: true },
1448
+ // 用户未设置 settings
1449
+ },
1450
+ ];
1451
+
1452
+ const builtinModels: AiProviderModelListItem[] = [
1453
+ {
1454
+ id: 'gpt-4',
1455
+ type: 'chat',
1456
+ enabled: true,
1457
+ // 内置也无 settings
1458
+ },
1459
+ ];
1460
+
1461
+ vi.spyOn(repo.aiModelModel, 'getModelListByProviderId').mockResolvedValue(userModels);
1462
+ vi.spyOn(repo as any, 'fetchBuiltinModels').mockResolvedValue(builtinModels);
1463
+
1464
+ const result = await repo.getAiProviderModelList(providerId);
1465
+
1466
+ const merged = result.find((m) => m.id === 'gpt-4');
1467
+ expect(merged).toBeDefined();
1468
+ // 无 settings
1469
+ expect(merged?.settings).toBeUndefined();
1470
+ });
1273
1471
  });
1274
1472
 
1275
1473
  describe('getAiProviderRuntimeState', () => {
@@ -91,6 +91,7 @@ const injectSearchSettings = (providerId: string, item: any) => {
91
91
  if (item?.settings?.searchImpl || item?.settings?.searchProvider) {
92
92
  const next = { ...item } as any;
93
93
  if (next.settings) {
94
+ // eslint-disable-next-line unused-imports/no-unused-vars, @typescript-eslint/no-unused-vars
94
95
  const { searchImpl, searchProvider, ...restSettings } = next.settings;
95
96
  next.settings = Object.keys(restSettings).length > 0 ? restSettings : undefined;
96
97
  }
@@ -224,7 +225,7 @@ export class AiInfraRepos {
224
225
  enabled: typeof user.enabled === 'boolean' ? user.enabled : item.enabled,
225
226
  id: item.id,
226
227
  providerId: provider.id,
227
- settings: item.settings,
228
+ settings: user.settings || item.settings,
228
229
  sort: user.sort || undefined,
229
230
  type: user.type || item.type,
230
231
  };
@@ -1,5 +1,6 @@
1
1
  /* eslint-disable sort-keys-fix/sort-keys-fix */
2
2
  import { boolean, integer, jsonb, pgTable, primaryKey, text, varchar } from 'drizzle-orm/pg-core';
3
+ import { AiModelSettings } from 'model-bank';
3
4
 
4
5
  import { AiProviderConfig, AiProviderSettings } from '@/types/aiProvider';
5
6
 
@@ -64,6 +65,7 @@ export const aiModels = pgTable(
64
65
  contextWindowTokens: integer('context_window_tokens'),
65
66
  source: varchar('source', { enum: ['remote', 'custom', 'builtin'], length: 20 }),
66
67
  releasedAt: varchar('released_at', { length: 10 }),
68
+ settings: jsonb('settings').default({}).$type<AiModelSettings>(),
67
69
 
68
70
  ...timestamps,
69
71
  },
@@ -51,3 +51,17 @@ export interface TopicRankItem {
51
51
  sessionId: string | null;
52
52
  title: string | null;
53
53
  }
54
+
55
+ export interface CreateTopicParams {
56
+ favorite?: boolean;
57
+ groupId?: string | null;
58
+ messages?: string[];
59
+ sessionId?: string | null;
60
+ title: string;
61
+ }
62
+
63
+ export interface QueryTopicParams {
64
+ containerId?: string | null; // sessionId or groupId
65
+ current?: number;
66
+ pageSize?: number;
67
+ }
@@ -128,7 +128,13 @@ export const topicRouter = router({
128
128
  }),
129
129
 
130
130
  searchTopics: topicProcedure
131
- .input(z.object({ keywords: z.string(), sessionId: z.string().nullable().optional() }))
131
+ .input(
132
+ z.object({
133
+ groupId: z.string().nullable().optional(),
134
+ keywords: z.string(),
135
+ sessionId: z.string().nullable().optional(),
136
+ }),
137
+ )
132
138
  .query(async ({ input, ctx }) => {
133
139
  return ctx.topicModel.queryByKeyword(input.keywords, input.sessionId);
134
140
  }),
@@ -1,7 +1,7 @@
1
1
  import { testService } from '~test-utils';
2
2
 
3
- import { ServerService } from './server';
3
+ import { AiModelService } from './index';
4
4
 
5
- describe('aiModelService', () => {
6
- testService(ServerService);
5
+ describe('AiModelService', () => {
6
+ testService(AiModelService);
7
7
  });
@@ -1,3 +1,57 @@
1
- import { ServerService } from './server';
1
+ import {
2
+ AiModelSortMap,
3
+ AiProviderModelListItem,
4
+ CreateAiModelParams,
5
+ ToggleAiModelEnableParams,
6
+ UpdateAiModelParams,
7
+ } from 'model-bank';
2
8
 
3
- export const aiModelService = new ServerService();
9
+ import { lambdaClient } from '@/libs/trpc/client';
10
+
11
+ export class AiModelService {
12
+ createAiModel = async (params: CreateAiModelParams) => {
13
+ return lambdaClient.aiModel.createAiModel.mutate(params);
14
+ };
15
+
16
+ getAiProviderModelList = async (id: string): Promise<AiProviderModelListItem[]> => {
17
+ return lambdaClient.aiModel.getAiProviderModelList.query({ id });
18
+ };
19
+
20
+ getAiModelById = async (id: string) => {
21
+ return lambdaClient.aiModel.getAiModelById.query({ id });
22
+ };
23
+
24
+ toggleModelEnabled = async (params: ToggleAiModelEnableParams) => {
25
+ return lambdaClient.aiModel.toggleModelEnabled.mutate(params);
26
+ };
27
+
28
+ updateAiModel = async (id: string, providerId: string, value: UpdateAiModelParams) => {
29
+ return lambdaClient.aiModel.updateAiModel.mutate({ id, providerId, value });
30
+ };
31
+
32
+ batchUpdateAiModels = async (id: string, models: AiProviderModelListItem[]) => {
33
+ return lambdaClient.aiModel.batchUpdateAiModels.mutate({ id, models });
34
+ };
35
+
36
+ batchToggleAiModels = async (id: string, models: string[], enabled: boolean) => {
37
+ return lambdaClient.aiModel.batchToggleAiModels.mutate({ enabled, id, models });
38
+ };
39
+
40
+ clearModelsByProvider = async (providerId: string) => {
41
+ return lambdaClient.aiModel.clearModelsByProvider.mutate({ providerId });
42
+ };
43
+
44
+ clearRemoteModels = async (providerId: string) => {
45
+ return lambdaClient.aiModel.clearRemoteModels.mutate({ providerId });
46
+ };
47
+
48
+ updateAiModelOrder = async (providerId: string, items: AiModelSortMap[]) => {
49
+ return lambdaClient.aiModel.updateAiModelOrder.mutate({ providerId, sortMap: items });
50
+ };
51
+
52
+ deleteAiModel = async (params: { id: string; providerId: string }) => {
53
+ return lambdaClient.aiModel.removeAiModel.mutate(params);
54
+ };
55
+ }
56
+
57
+ export const aiModelService = new AiModelService();
@@ -1,7 +1,7 @@
1
1
  import { testService } from '~test-utils';
2
2
 
3
- import { ServerService } from './server';
3
+ import { AiProviderService } from './index';
4
4
 
5
5
  describe('aiProviderService', () => {
6
- testService(ServerService);
6
+ testService(AiProviderService);
7
7
  });
@@ -1,3 +1,49 @@
1
- import { ServerService } from './server';
1
+ import {
2
+ AiProviderDetailItem,
3
+ AiProviderRuntimeState,
4
+ AiProviderSortMap,
5
+ CreateAiProviderParams,
6
+ UpdateAiProviderConfigParams,
7
+ } from '@/types/aiProvider';
2
8
 
3
- export const aiProviderService = new ServerService();
9
+ import { lambdaClient } from '@/libs/trpc/client';
10
+
11
+ export class AiProviderService {
12
+ createAiProvider = async (params: CreateAiProviderParams) => {
13
+ return lambdaClient.aiProvider.createAiProvider.mutate(params);
14
+ };
15
+
16
+ getAiProviderList = async () => {
17
+ return lambdaClient.aiProvider.getAiProviderList.query();
18
+ };
19
+
20
+ getAiProviderById = async (id: string): Promise<AiProviderDetailItem | undefined> => {
21
+ return lambdaClient.aiProvider.getAiProviderById.query({ id });
22
+ };
23
+
24
+ toggleProviderEnabled = async (id: string, enabled: boolean) => {
25
+ return lambdaClient.aiProvider.toggleProviderEnabled.mutate({ enabled, id });
26
+ };
27
+
28
+ updateAiProvider = async (id: string, value: any) => {
29
+ return lambdaClient.aiProvider.updateAiProvider.mutate({ id, value });
30
+ };
31
+
32
+ updateAiProviderConfig = async (id: string, value: UpdateAiProviderConfigParams) => {
33
+ return lambdaClient.aiProvider.updateAiProviderConfig.mutate({ id, value });
34
+ };
35
+
36
+ updateAiProviderOrder = async (items: AiProviderSortMap[]) => {
37
+ return lambdaClient.aiProvider.updateAiProviderOrder.mutate({ sortMap: items });
38
+ };
39
+
40
+ deleteAiProvider = async (id: string) => {
41
+ return lambdaClient.aiProvider.removeAiProvider.mutate({ id });
42
+ };
43
+
44
+ getAiProviderRuntimeState = async (isLogin?: boolean): Promise<AiProviderRuntimeState> => {
45
+ return lambdaClient.aiProvider.getAiProviderRuntimeState.query({ isLogin });
46
+ };
47
+ }
48
+
49
+ export const aiProviderService = new AiProviderService();
@@ -1,3 +1,67 @@
1
- import { ServerService } from './server';
1
+ import {
2
+ ChatGroupAgentItem,
3
+ ChatGroupItem,
4
+ NewChatGroup,
5
+ NewChatGroupAgent,
6
+ } from '@/database/schemas';
7
+ import { lambdaClient } from '@/libs/trpc/client';
2
8
 
3
- export const chatGroupService = new ServerService();
9
+ class ChatGroupService {
10
+ createGroup = (params: Omit<NewChatGroup, 'userId'>): Promise<ChatGroupItem> => {
11
+ return lambdaClient.group.createGroup.mutate({
12
+ ...params,
13
+ config: params.config as any,
14
+ });
15
+ };
16
+
17
+ updateGroup = (id: string, value: Partial<ChatGroupItem>): Promise<ChatGroupItem> => {
18
+ return lambdaClient.group.updateGroup.mutate({
19
+ id,
20
+ value: {
21
+ ...value,
22
+ config: value.config as any,
23
+ },
24
+ });
25
+ };
26
+
27
+ deleteGroup = (id: string) => {
28
+ return lambdaClient.group.deleteGroup.mutate({ id });
29
+ };
30
+
31
+ getGroup = (id: string): Promise<ChatGroupItem | undefined> => {
32
+ return lambdaClient.group.getGroup.query({ id });
33
+ };
34
+
35
+ getGroups = (): Promise<ChatGroupItem[]> => {
36
+ return lambdaClient.group.getGroups.query();
37
+ };
38
+
39
+ addAgentsToGroup = (groupId: string, agentIds: string[]): Promise<ChatGroupAgentItem[]> => {
40
+ return lambdaClient.group.addAgentsToGroup.mutate({ agentIds, groupId });
41
+ };
42
+
43
+ removeAgentsFromGroup = (groupId: string, agentIds: string[]) => {
44
+ return lambdaClient.group.removeAgentsFromGroup.mutate({ agentIds, groupId });
45
+ };
46
+
47
+ updateAgentInGroup = (
48
+ groupId: string,
49
+ agentId: string,
50
+ updates: Partial<Pick<NewChatGroupAgent, 'order' | 'role'>>,
51
+ ): Promise<ChatGroupAgentItem> => {
52
+ return lambdaClient.group.updateAgentInGroup.mutate({
53
+ agentId,
54
+ groupId,
55
+ updates: {
56
+ order: updates.order === null ? undefined : updates.order,
57
+ role: updates.role === null ? undefined : updates.role,
58
+ },
59
+ });
60
+ };
61
+
62
+ getGroupAgents = (groupId: string): Promise<ChatGroupAgentItem[]> => {
63
+ return lambdaClient.group.getGroupAgents.query({ groupId });
64
+ };
65
+ }
66
+
67
+ export const chatGroupService = new ChatGroupService();
@@ -1,3 +1,11 @@
1
- import { ServerService } from './server';
1
+ import { ExportDatabaseData } from '@/types/export';
2
2
 
3
- export const exportService = new ServerService();
3
+ import { lambdaClient } from '@/libs/trpc/client';
4
+
5
+ class ExportService {
6
+ exportData = async (): Promise<ExportDatabaseData> => {
7
+ return await lambdaClient.exporter.exportData.mutate();
8
+ };
9
+ }
10
+
11
+ export const exportService = new ExportService();
@@ -1,3 +1,62 @@
1
- import { ServerService } from './server';
1
+ import { lambdaClient } from '@/libs/trpc/client';
2
+ import {
3
+ CheckFileHashResult,
4
+ FileItem,
5
+ QueryFileListParams,
6
+ QueryFileListSchemaType,
7
+ UploadFileParams,
8
+ } from '@/types/files';
2
9
 
3
- export const fileService = new ServerService();
10
+ interface CreateFileParams extends Omit<UploadFileParams, 'url'> {
11
+ knowledgeBaseId?: string;
12
+ url: string;
13
+ }
14
+
15
+ export class FileService {
16
+ createFile = async (
17
+ params: UploadFileParams,
18
+ knowledgeBaseId?: string,
19
+ ): Promise<{ id: string; url: string }> => {
20
+ return lambdaClient.file.createFile.mutate({ ...params, knowledgeBaseId } as CreateFileParams);
21
+ };
22
+
23
+ getFile = async (id: string): Promise<FileItem> => {
24
+ const item = await lambdaClient.file.findById.query({ id });
25
+
26
+ if (!item) {
27
+ throw new Error('file not found');
28
+ }
29
+
30
+ return { ...item, type: item.fileType };
31
+ };
32
+
33
+ removeFile = async (id: string): Promise<void> => {
34
+ await lambdaClient.file.removeFile.mutate({ id });
35
+ };
36
+
37
+ removeFiles = async (ids: string[]): Promise<void> => {
38
+ await lambdaClient.file.removeFiles.mutate({ ids });
39
+ };
40
+
41
+ removeAllFiles = async () => {
42
+ await lambdaClient.file.removeAllFiles.mutate();
43
+ };
44
+
45
+ getFiles = async (params: QueryFileListParams) => {
46
+ return lambdaClient.file.getFiles.query(params as QueryFileListSchemaType);
47
+ };
48
+
49
+ getFileItem = async (id: string) => {
50
+ return lambdaClient.file.getFileItemById.query({ id });
51
+ };
52
+
53
+ checkFileHash = async (hash: string): Promise<CheckFileHashResult> => {
54
+ return lambdaClient.file.checkFileHash.mutate({ hash });
55
+ };
56
+
57
+ removeFileAsyncTask = async (id: string, type: 'embedding' | 'chunk') => {
58
+ return lambdaClient.file.removeFileAsyncTask.mutate({ id, type });
59
+ };
60
+ }
61
+
62
+ export const fileService = new FileService();