@lobehub/lobehub 2.0.0-next.26 → 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 (61) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/package.json +1 -1
  4. package/packages/types/src/topic/topic.ts +14 -0
  5. package/src/server/routers/lambda/topic.ts +7 -1
  6. package/src/services/aiModel/index.test.ts +3 -3
  7. package/src/services/aiModel/index.ts +56 -2
  8. package/src/services/aiProvider/index.test.ts +2 -2
  9. package/src/services/aiProvider/index.ts +48 -2
  10. package/src/services/chatGroup/index.ts +66 -2
  11. package/src/services/export/index.ts +10 -2
  12. package/src/services/file/index.ts +61 -2
  13. package/src/services/import/index.ts +133 -2
  14. package/src/services/message/index.ts +176 -2
  15. package/src/services/message/{__tests__/server.test.ts → server.test.ts} +3 -3
  16. package/src/services/plugin/index.test.ts +8 -0
  17. package/src/services/plugin/index.ts +53 -2
  18. package/src/services/session/index.test.ts +8 -0
  19. package/src/services/session/index.ts +145 -2
  20. package/src/services/thread/index.test.ts +8 -0
  21. package/src/services/thread/index.ts +38 -2
  22. package/src/services/topic/index.test.ts +8 -0
  23. package/src/services/topic/index.ts +76 -2
  24. package/src/services/user/index.test.ts +8 -0
  25. package/src/services/user/index.ts +53 -2
  26. package/src/store/aiInfra/slices/aiModel/action.test.ts +17 -9
  27. package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +4 -2
  28. package/src/store/chat/slices/topic/action.test.ts +1 -1
  29. package/src/store/chat/slices/topic/action.ts +1 -2
  30. package/src/store/chat/slices/topic/reducer.ts +1 -2
  31. package/src/store/file/slices/chat/action.ts +1 -4
  32. package/src/store/file/slices/fileManager/action.ts +2 -3
  33. package/src/store/session/slices/sessionGroup/action.test.ts +5 -5
  34. package/src/store/user/slices/common/action.test.ts +1 -1
  35. package/src/services/aiModel/server.test.ts +0 -122
  36. package/src/services/aiModel/server.ts +0 -51
  37. package/src/services/aiModel/type.ts +0 -32
  38. package/src/services/aiProvider/server.ts +0 -43
  39. package/src/services/aiProvider/type.ts +0 -27
  40. package/src/services/chatGroup/server.ts +0 -67
  41. package/src/services/chatGroup/type.ts +0 -22
  42. package/src/services/export/server.ts +0 -9
  43. package/src/services/export/type.ts +0 -5
  44. package/src/services/file/server.ts +0 -53
  45. package/src/services/file/type.ts +0 -13
  46. package/src/services/import/server.ts +0 -133
  47. package/src/services/import/type.ts +0 -17
  48. package/src/services/message/server.ts +0 -151
  49. package/src/services/message/type.ts +0 -55
  50. package/src/services/plugin/server.ts +0 -42
  51. package/src/services/plugin/type.ts +0 -23
  52. package/src/services/session/server.test.ts +0 -260
  53. package/src/services/session/server.ts +0 -125
  54. package/src/services/session/type.ts +0 -82
  55. package/src/services/thread/server.ts +0 -32
  56. package/src/services/thread/type.ts +0 -21
  57. package/src/services/topic/server.ts +0 -57
  58. package/src/services/topic/type.ts +0 -40
  59. package/src/services/user/server.test.ts +0 -149
  60. package/src/services/user/server.ts +0 -47
  61. package/src/services/user/type.ts +0 -21
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 2.0.0-next.27](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.26...v2.0.0-next.27)
6
+
7
+ <sup>Released on **2025-11-04**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: Refactor services to a more clean structure.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Code refactoring
19
+
20
+ - **misc**: Refactor services to a more clean structure, closes [#10050](https://github.com/lobehub/lobe-chat/issues/10050) ([de61dfa](https://github.com/lobehub/lobe-chat/commit/de61dfa))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
5
30
  ## [Version 2.0.0-next.26](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.25...v2.0.0-next.26)
6
31
 
7
32
  <sup>Released on **2025-11-04**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "improvements": [
5
+ "Refactor services to a more clean structure."
6
+ ]
7
+ },
8
+ "date": "2025-11-04",
9
+ "version": "2.0.0-next.27"
10
+ },
2
11
  {
3
12
  "children": {
4
13
  "improvements": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.0-next.26",
3
+ "version": "2.0.0-next.27",
4
4
  "description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -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();
@@ -1,3 +1,134 @@
1
- import { ServerService } from './server';
1
+ import { DefaultErrorShape } from '@trpc/server/unstable-core-do-not-import';
2
2
 
3
- export const importService = new ServerService();
3
+ import { lambdaClient } from '@/libs/trpc/client';
4
+ import { uploadService } from '@/services/upload';
5
+ import { useUserStore } from '@/store/user';
6
+ import { ImportPgDataStructure } from '@/types/export';
7
+ import { ImporterEntryData, ImportStage, OnImportCallbacks } from '@/types/importer';
8
+ import { UserSettings } from '@/types/user/settings';
9
+ import { uuid } from '@/utils/uuid';
10
+
11
+ class ImportService {
12
+ importSettings = async (settings: UserSettings): Promise<void> => {
13
+ await useUserStore.getState().importAppSettings(settings);
14
+ };
15
+
16
+ importData = async (data: ImporterEntryData, callbacks?: OnImportCallbacks): Promise<void> => {
17
+ const handleError = (e: unknown) => {
18
+ callbacks?.onStageChange?.(ImportStage.Error);
19
+ const error = e as DefaultErrorShape;
20
+
21
+ callbacks?.onError?.({
22
+ code: error.data.code,
23
+ httpStatus: error.data.httpStatus,
24
+ message: error.message,
25
+ path: error.data.path,
26
+ });
27
+ };
28
+
29
+ const totalLength =
30
+ (data.messages?.length || 0) +
31
+ (data.sessionGroups?.length || 0) +
32
+ (data.sessions?.length || 0) +
33
+ (data.topics?.length || 0);
34
+
35
+ if (totalLength < 500) {
36
+ callbacks?.onStageChange?.(ImportStage.Importing);
37
+ const time = Date.now();
38
+ try {
39
+ const result = await lambdaClient.importer.importByPost.mutate({ data });
40
+ const duration = Date.now() - time;
41
+
42
+ callbacks?.onStageChange?.(ImportStage.Success);
43
+ callbacks?.onSuccess?.(result.results, duration);
44
+ } catch (e) {
45
+ handleError(e);
46
+ }
47
+
48
+ return;
49
+ }
50
+
51
+ await this.uploadData(data, { callbacks, handleError });
52
+ };
53
+
54
+ importPgData = async (
55
+ data: ImportPgDataStructure,
56
+ options?: {
57
+ callbacks?: OnImportCallbacks;
58
+ overwriteExisting?: boolean;
59
+ },
60
+ ): Promise<void> => {
61
+ const { callbacks } = options || {};
62
+
63
+ const handleError = (e: unknown) => {
64
+ callbacks?.onStageChange?.(ImportStage.Error);
65
+ const error = e as DefaultErrorShape;
66
+
67
+ callbacks?.onError?.({
68
+ code: error.data.code,
69
+ httpStatus: error.data.httpStatus,
70
+ message: error.message,
71
+ path: error.data.path,
72
+ });
73
+ };
74
+
75
+ const totalLength = Object.values(data.data)
76
+ .map((d) => d.length)
77
+ .reduce((a, b) => a + b, 0);
78
+
79
+ if (totalLength < 500) {
80
+ callbacks?.onStageChange?.(ImportStage.Importing);
81
+ const time = Date.now();
82
+ try {
83
+ const result = await lambdaClient.importer.importPgByPost.mutate(data);
84
+ const duration = Date.now() - time;
85
+
86
+ callbacks?.onStageChange?.(ImportStage.Success);
87
+ callbacks?.onSuccess?.(result.results, duration);
88
+ } catch (e) {
89
+ handleError(e);
90
+ }
91
+
92
+ return;
93
+ }
94
+
95
+ await this.uploadData(data, { callbacks, handleError });
96
+ };
97
+
98
+ private uploadData = async (
99
+ data: object,
100
+ { callbacks, handleError }: { callbacks?: OnImportCallbacks; handleError: (e: unknown) => any },
101
+ ) => {
102
+ // if the data is too large, upload it to S3 and upload by file
103
+ const filename = `${uuid()}.json`;
104
+
105
+ let pathname;
106
+ try {
107
+ callbacks?.onStageChange?.(ImportStage.Uploading);
108
+ const result = await uploadService.uploadDataToS3(data, {
109
+ filename,
110
+ onProgress: (status, state) => {
111
+ callbacks?.onFileUploading?.(state);
112
+ },
113
+ pathname: `import_config/${filename}`,
114
+ });
115
+ pathname = result.data.path;
116
+ console.log(pathname);
117
+ } catch {
118
+ throw new Error('Upload Error');
119
+ }
120
+
121
+ callbacks?.onStageChange?.(ImportStage.Importing);
122
+ const time = Date.now();
123
+ try {
124
+ const result = await lambdaClient.importer.importByFile.mutate({ pathname });
125
+ const duration = Date.now() - time;
126
+ callbacks?.onStageChange?.(ImportStage.Success);
127
+ callbacks?.onSuccess?.(result.results, duration);
128
+ } catch (e) {
129
+ handleError(e);
130
+ }
131
+ };
132
+ }
133
+
134
+ export const importService = new ImportService();
@@ -1,3 +1,177 @@
1
- import { ServerService } from './server';
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import {
3
+ ChatMessageError,
4
+ ChatMessagePluginError,
5
+ ChatTranslate,
6
+ ChatTTS,
7
+ CreateMessageParams,
8
+ CreateMessageResult,
9
+ ModelRankItem,
10
+ UIChatMessage,
11
+ UpdateMessageParams,
12
+ UpdateMessageRAGParams,
13
+ UpdateMessageResult,
14
+ } from '@lobechat/types';
15
+ import type { HeatmapsProps } from '@lobehub/charts';
2
16
 
3
- export const messageService = new ServerService();
17
+ import { INBOX_SESSION_ID } from '@/const/session';
18
+ import { lambdaClient } from '@/libs/trpc/client';
19
+ import { useUserStore } from '@/store/user';
20
+ import { labPreferSelectors } from '@/store/user/selectors';
21
+
22
+ export class MessageService {
23
+ createMessage = async ({ sessionId, ...params }: CreateMessageParams): Promise<string> => {
24
+ return lambdaClient.message.createMessage.mutate({
25
+ ...params,
26
+ sessionId: sessionId ? this.toDbSessionId(sessionId) : undefined,
27
+ });
28
+ };
29
+
30
+ createNewMessage = async ({
31
+ sessionId,
32
+ ...params
33
+ }: CreateMessageParams): Promise<CreateMessageResult> => {
34
+ return lambdaClient.message.createNewMessage.mutate({
35
+ ...params,
36
+ sessionId: sessionId ? this.toDbSessionId(sessionId) : undefined,
37
+ });
38
+ };
39
+
40
+ getMessages = async (
41
+ sessionId: string,
42
+ topicId?: string,
43
+ groupId?: string,
44
+ ): Promise<UIChatMessage[]> => {
45
+ // Get user lab preference for message grouping
46
+ const useGroup = labPreferSelectors.enableAssistantMessageGroup(useUserStore.getState());
47
+
48
+ const data = await lambdaClient.message.getMessages.query({
49
+ groupId,
50
+ sessionId: this.toDbSessionId(sessionId),
51
+ topicId,
52
+ useGroup,
53
+ });
54
+
55
+ return data as unknown as UIChatMessage[];
56
+ };
57
+
58
+ getGroupMessages = async (groupId: string, topicId?: string): Promise<UIChatMessage[]> => {
59
+ // Get user lab preference for message grouping
60
+ const useGroup = labPreferSelectors.enableAssistantMessageGroup(useUserStore.getState());
61
+
62
+ const data = await lambdaClient.message.getMessages.query({
63
+ groupId,
64
+ topicId,
65
+ useGroup,
66
+ });
67
+ return data as unknown as UIChatMessage[];
68
+ };
69
+
70
+ countMessages = async (params?: {
71
+ endDate?: string;
72
+ range?: [string, string];
73
+ startDate?: string;
74
+ }): Promise<number> => {
75
+ return lambdaClient.message.count.query(params);
76
+ };
77
+
78
+ countWords = async (params?: {
79
+ endDate?: string;
80
+ range?: [string, string];
81
+ startDate?: string;
82
+ }): Promise<number> => {
83
+ return lambdaClient.message.countWords.query(params);
84
+ };
85
+
86
+ rankModels = async (): Promise<ModelRankItem[]> => {
87
+ return lambdaClient.message.rankModels.query();
88
+ };
89
+
90
+ getHeatmaps = async (): Promise<HeatmapsProps['data']> => {
91
+ return lambdaClient.message.getHeatmaps.query();
92
+ };
93
+
94
+ updateMessageError = async (id: string, error: ChatMessageError) => {
95
+ return lambdaClient.message.update.mutate({ id, value: { error } });
96
+ };
97
+
98
+ updateMessagePluginArguments = async (id: string, value: string | Record<string, any>) => {
99
+ const args = typeof value === 'string' ? value : JSON.stringify(value);
100
+ return lambdaClient.message.updateMessagePlugin.mutate({ id, value: { arguments: args } });
101
+ };
102
+
103
+ updateMessage = async (
104
+ id: string,
105
+ value: Partial<UpdateMessageParams>,
106
+ options?: { sessionId?: string | null; topicId?: string | null },
107
+ ): Promise<UpdateMessageResult> => {
108
+ return lambdaClient.message.update.mutate({
109
+ id,
110
+ sessionId: options?.sessionId,
111
+ topicId: options?.topicId,
112
+ value,
113
+ });
114
+ };
115
+
116
+ updateMessageTranslate = async (id: string, translate: Partial<ChatTranslate> | false) => {
117
+ return lambdaClient.message.updateTranslate.mutate({ id, value: translate as ChatTranslate });
118
+ };
119
+
120
+ updateMessageTTS = async (id: string, tts: Partial<ChatTTS> | false) => {
121
+ return lambdaClient.message.updateTTS.mutate({ id, value: tts });
122
+ };
123
+
124
+ updateMessagePluginState = async (id: string, value: Record<string, any>) => {
125
+ return lambdaClient.message.updatePluginState.mutate({ id, value });
126
+ };
127
+
128
+ updateMessagePluginError = async (id: string, error: ChatMessagePluginError | null) => {
129
+ return lambdaClient.message.updatePluginError.mutate({ id, value: error as any });
130
+ };
131
+
132
+ updateMessageRAG = async (id: string, data: UpdateMessageRAGParams): Promise<void> => {
133
+ return lambdaClient.message.updateMessageRAG.mutate({ id, value: data });
134
+ };
135
+
136
+ removeMessage = async (id: string) => {
137
+ return lambdaClient.message.removeMessage.mutate({ id });
138
+ };
139
+
140
+ removeMessages = async (ids: string[]) => {
141
+ return lambdaClient.message.removeMessages.mutate({ ids });
142
+ };
143
+
144
+ removeMessagesByAssistant = async (sessionId: string, topicId?: string) => {
145
+ return lambdaClient.message.removeMessagesByAssistant.mutate({
146
+ sessionId: this.toDbSessionId(sessionId),
147
+ topicId,
148
+ });
149
+ };
150
+
151
+ removeMessagesByGroup = async (groupId: string, topicId?: string) => {
152
+ return lambdaClient.message.removeMessagesByGroup.mutate({
153
+ groupId,
154
+ topicId,
155
+ });
156
+ };
157
+
158
+ removeAllMessages = async () => {
159
+ return lambdaClient.message.removeAllMessages.mutate();
160
+ };
161
+
162
+ private toDbSessionId = (sessionId: string | undefined) => {
163
+ return sessionId === INBOX_SESSION_ID ? null : sessionId;
164
+ };
165
+
166
+ hasMessages = async (): Promise<boolean> => {
167
+ const number = await this.countMessages();
168
+ return number > 0;
169
+ };
170
+
171
+ messageCountToCheckTrace = async (): Promise<boolean> => {
172
+ const number = await this.countMessages();
173
+ return number >= 4;
174
+ };
175
+ }
176
+
177
+ export const messageService = new MessageService();