@lobehub/lobehub 2.0.0-next.12 → 2.0.0-next.14

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 (212) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/package.json +1 -1
  4. package/packages/const/src/version.ts +3 -3
  5. package/packages/database/src/repositories/dataImporter/deprecated/__tests__/index.test.ts +2 -1
  6. package/packages/database/src/repositories/dataImporter/deprecated/index.ts +7 -1
  7. package/src/app/[variants]/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx +9 -0
  8. package/src/app/[variants]/(main)/(mobile)/me/(home)/layout.tsx +0 -2
  9. package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/List/Item/Actions.tsx +3 -28
  10. package/src/app/[variants]/(main)/chat/_layout/Desktop/index.tsx +0 -2
  11. package/src/app/[variants]/(main)/chat/_layout/Mobile.tsx +1 -5
  12. package/src/app/[variants]/(main)/chat/settings/features/HeaderContent.tsx +2 -62
  13. package/src/app/[variants]/(main)/image/features/PromptInput/index.tsx +1 -1
  14. package/src/app/[variants]/(main)/image/page.tsx +0 -2
  15. package/src/app/[variants]/(main)/profile/_layout/Desktop/index.tsx +23 -24
  16. package/src/app/[variants]/(main)/profile/_layout/Mobile/index.tsx +5 -9
  17. package/src/app/[variants]/(main)/settings/_layout/Desktop/index.tsx +0 -2
  18. package/src/app/[variants]/(main)/settings/_layout/Mobile/index.tsx +0 -2
  19. package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/Card.tsx +1 -1
  20. package/src/app/[variants]/loading/index.tsx +1 -10
  21. package/src/components/Link.tsx +12 -0
  22. package/src/envs/app.ts +5 -8
  23. package/src/features/DataImporter/index.tsx +15 -60
  24. package/src/features/DevPanel/PostgresViewer/usePgTable.ts +3 -2
  25. package/src/hooks/useInterceptingRoutes.test.ts +21 -3
  26. package/src/libs/trpc/client/index.ts +0 -1
  27. package/src/libs/trpc/client/lambda.ts +8 -5
  28. package/src/libs/trpc/lambda/context.ts +4 -1
  29. package/src/server/routers/desktop/mcp.ts +1 -3
  30. package/src/server/routers/lambda/config/index.test.ts +2 -2
  31. package/src/server/routers/tools/mcp.ts +2 -3
  32. package/src/server/routers/tools/search.test.ts +1 -7
  33. package/src/server/routers/tools/search.ts +1 -4
  34. package/src/services/__tests__/tool.test.ts +0 -3
  35. package/src/services/aiModel/index.test.ts +0 -3
  36. package/src/services/aiModel/index.ts +1 -7
  37. package/src/services/aiProvider/index.test.ts +0 -3
  38. package/src/services/aiProvider/index.ts +1 -7
  39. package/src/services/chatGroup/index.ts +1 -10
  40. package/src/services/config.ts +1 -65
  41. package/src/services/export/index.ts +1 -4
  42. package/src/services/file/index.ts +1 -11
  43. package/src/services/import/index.ts +1 -7
  44. package/src/services/message/index.ts +1 -11
  45. package/src/services/plugin/index.ts +1 -11
  46. package/src/services/session/index.ts +1 -11
  47. package/src/services/tableViewer/client.ts +12 -15
  48. package/src/services/thread/index.ts +1 -7
  49. package/src/services/topic/index.ts +1 -11
  50. package/src/services/user/index.ts +1 -13
  51. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +0 -241
  52. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +26 -1
  53. package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +3 -1
  54. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +1 -138
  55. package/src/store/user/slices/common/action.test.ts +1 -4
  56. package/src/app/(backend)/trpc/edge/[trpc]/route.ts +0 -26
  57. package/src/app/[variants]/(main)/(mobile)/me/data/features/Category.tsx +0 -48
  58. package/src/app/[variants]/(main)/(mobile)/me/data/features/Header.tsx +0 -33
  59. package/src/app/[variants]/(main)/(mobile)/me/data/layout.tsx +0 -13
  60. package/src/app/[variants]/(main)/(mobile)/me/data/loading.tsx +0 -5
  61. package/src/app/[variants]/(main)/(mobile)/me/data/page.tsx +0 -29
  62. package/src/app/[variants]/(main)/chat/features/Migration/DBReader.ts +0 -290
  63. package/src/app/[variants]/(main)/chat/features/Migration/ExportConfigButton.tsx +0 -35
  64. package/src/app/[variants]/(main)/chat/features/Migration/Failed.tsx +0 -120
  65. package/src/app/[variants]/(main)/chat/features/Migration/Modal.tsx +0 -81
  66. package/src/app/[variants]/(main)/chat/features/Migration/Start.tsx +0 -108
  67. package/src/app/[variants]/(main)/chat/features/Migration/UpgradeButton.tsx +0 -71
  68. package/src/app/[variants]/(main)/chat/features/Migration/const.ts +0 -15
  69. package/src/app/[variants]/(main)/chat/features/Migration/index.tsx +0 -50
  70. package/src/app/[variants]/loading/Client/Content.tsx +0 -48
  71. package/src/app/[variants]/loading/Client/Error.tsx +0 -27
  72. package/src/app/[variants]/loading/Client/Redirect.tsx +0 -47
  73. package/src/app/[variants]/loading/Client/index.tsx +0 -22
  74. package/src/components/InnerLink.tsx +0 -20
  75. package/src/database/_deprecated/core/__tests__/db-upgrade.test.ts +0 -42
  76. package/src/database/_deprecated/core/__tests__/db.test.ts +0 -79
  77. package/src/database/_deprecated/core/__tests__/model.test.ts +0 -55
  78. package/src/database/_deprecated/core/db.ts +0 -246
  79. package/src/database/_deprecated/core/index.ts +0 -2
  80. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/fixtures/input.json +0 -55
  81. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/fixtures/output.json +0 -60
  82. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/index.test.ts +0 -14
  83. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/index.ts +0 -22
  84. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/type.ts +0 -105
  85. package/src/database/_deprecated/core/model.ts +0 -218
  86. package/src/database/_deprecated/core/schemas.ts +0 -88
  87. package/src/database/_deprecated/core/types/db.ts +0 -15
  88. package/src/database/_deprecated/models/__DEBUG.ts +0 -124
  89. package/src/database/_deprecated/models/__tests__/file.test.ts +0 -83
  90. package/src/database/_deprecated/models/__tests__/message.test.ts +0 -426
  91. package/src/database/_deprecated/models/__tests__/plugin.test.ts +0 -81
  92. package/src/database/_deprecated/models/__tests__/session.test.ts +0 -253
  93. package/src/database/_deprecated/models/__tests__/sessionGroup.test.ts +0 -220
  94. package/src/database/_deprecated/models/__tests__/topic.test.ts +0 -523
  95. package/src/database/_deprecated/models/__tests__/user.test.ts +0 -82
  96. package/src/database/_deprecated/models/file.ts +0 -51
  97. package/src/database/_deprecated/models/message.ts +0 -277
  98. package/src/database/_deprecated/models/plugin.ts +0 -62
  99. package/src/database/_deprecated/models/session.ts +0 -271
  100. package/src/database/_deprecated/models/sessionGroup.ts +0 -93
  101. package/src/database/_deprecated/models/topic.ts +0 -250
  102. package/src/database/_deprecated/models/user.ts +0 -69
  103. package/src/database/_deprecated/schemas/files.ts +0 -39
  104. package/src/database/_deprecated/schemas/message.ts +0 -50
  105. package/src/database/_deprecated/schemas/plugin.ts +0 -12
  106. package/src/database/_deprecated/schemas/session.ts +0 -54
  107. package/src/database/_deprecated/schemas/sessionGroup.ts +0 -8
  108. package/src/database/_deprecated/schemas/topic.ts +0 -12
  109. package/src/database/_deprecated/schemas/user.ts +0 -40
  110. package/src/features/DataImporter/_deprecated.ts +0 -43
  111. package/src/features/InitClientDB/EnableModal.tsx +0 -118
  112. package/src/features/InitClientDB/ErrorResult.tsx +0 -143
  113. package/src/features/InitClientDB/InitIndicator.tsx +0 -124
  114. package/src/features/InitClientDB/PGliteIcon.tsx +0 -28
  115. package/src/features/InitClientDB/features/DatabaseRepair/Backup.tsx +0 -75
  116. package/src/features/InitClientDB/features/DatabaseRepair/Diagnosis.tsx +0 -98
  117. package/src/features/InitClientDB/features/DatabaseRepair/Repair.tsx +0 -218
  118. package/src/features/InitClientDB/features/DatabaseRepair/index.tsx +0 -91
  119. package/src/features/InitClientDB/index.tsx +0 -37
  120. package/src/libs/trpc/client/edge.ts +0 -26
  121. package/src/libs/trpc/edge/context.ts +0 -71
  122. package/src/libs/trpc/edge/index.ts +0 -45
  123. package/src/libs/trpc/edge/init.ts +0 -26
  124. package/src/libs/trpc/edge/middleware/jwtPayload.test.ts +0 -75
  125. package/src/libs/trpc/edge/middleware/jwtPayload.ts +0 -14
  126. package/src/migrations/FromV0ToV1.ts +0 -10
  127. package/src/migrations/FromV1ToV2/fixtures/input-v1-session.json +0 -191
  128. package/src/migrations/FromV1ToV2/fixtures/output-v2.json +0 -202
  129. package/src/migrations/FromV1ToV2/index.ts +0 -82
  130. package/src/migrations/FromV1ToV2/migrations.test.ts +0 -224
  131. package/src/migrations/FromV1ToV2/types/v1.ts +0 -78
  132. package/src/migrations/FromV1ToV2/types/v2.ts +0 -52
  133. package/src/migrations/FromV2ToV3/fixtures/input-v2-session.json +0 -72
  134. package/src/migrations/FromV2ToV3/fixtures/output-v3-from-v1.json +0 -203
  135. package/src/migrations/FromV2ToV3/fixtures/output-v3.json +0 -74
  136. package/src/migrations/FromV2ToV3/index.ts +0 -30
  137. package/src/migrations/FromV2ToV3/migrations.test.ts +0 -42
  138. package/src/migrations/FromV2ToV3/types/v3.ts +0 -27
  139. package/src/migrations/FromV3ToV4/fixtures/azure-input-v3.json +0 -79
  140. package/src/migrations/FromV3ToV4/fixtures/azure-output-v4.json +0 -75
  141. package/src/migrations/FromV3ToV4/fixtures/ollama-input-v3.json +0 -85
  142. package/src/migrations/FromV3ToV4/fixtures/ollama-output-v4.json +0 -86
  143. package/src/migrations/FromV3ToV4/fixtures/openai-input-v3.json +0 -77
  144. package/src/migrations/FromV3ToV4/fixtures/openai-output-v4.json +0 -77
  145. package/src/migrations/FromV3ToV4/fixtures/openrouter-input-v3.json +0 -82
  146. package/src/migrations/FromV3ToV4/fixtures/openrouter-output-v4.json +0 -85
  147. package/src/migrations/FromV3ToV4/fixtures/output-v4-from-v1.json +0 -203
  148. package/src/migrations/FromV3ToV4/index.ts +0 -102
  149. package/src/migrations/FromV3ToV4/migrations.test.ts +0 -195
  150. package/src/migrations/FromV3ToV4/types/v3.ts +0 -52
  151. package/src/migrations/FromV3ToV4/types/v4.ts +0 -37
  152. package/src/migrations/FromV4ToV5/fixtures/from-v1-to-v5-output.json +0 -245
  153. package/src/migrations/FromV4ToV5/fixtures/function-input-v4.json +0 -96
  154. package/src/migrations/FromV4ToV5/fixtures/function-output-v5.json +0 -120
  155. package/src/migrations/FromV4ToV5/index.ts +0 -58
  156. package/src/migrations/FromV4ToV5/migrations.test.ts +0 -49
  157. package/src/migrations/FromV4ToV5/types/v4.ts +0 -21
  158. package/src/migrations/FromV4ToV5/types/v5.ts +0 -27
  159. package/src/migrations/FromV5ToV6/fixtures/from-v1-to-v6-output.json +0 -247
  160. package/src/migrations/FromV5ToV6/fixtures/session-input-v5.json +0 -81
  161. package/src/migrations/FromV5ToV6/fixtures/session-output-v6.json +0 -85
  162. package/src/migrations/FromV5ToV6/index.ts +0 -61
  163. package/src/migrations/FromV5ToV6/migrations.test.ts +0 -50
  164. package/src/migrations/FromV5ToV6/types/v5.ts +0 -48
  165. package/src/migrations/FromV5ToV6/types/v6.ts +0 -63
  166. package/src/migrations/FromV6ToV7/fixtures/output-v7-from-v1.json +0 -203
  167. package/src/migrations/FromV6ToV7/fixtures/provider-input-v6.json +0 -103
  168. package/src/migrations/FromV6ToV7/fixtures/provider-output-v7.json +0 -118
  169. package/src/migrations/FromV6ToV7/index.ts +0 -101
  170. package/src/migrations/FromV6ToV7/migrations.test.ts +0 -64
  171. package/src/migrations/FromV6ToV7/types/v6.ts +0 -61
  172. package/src/migrations/FromV6ToV7/types/v7.ts +0 -69
  173. package/src/migrations/VersionController.test.ts +0 -88
  174. package/src/migrations/VersionController.ts +0 -67
  175. package/src/migrations/index.ts +0 -61
  176. package/src/server/routers/edge/appStatus.ts +0 -3
  177. package/src/server/routers/edge/index.ts +0 -14
  178. package/src/server/routers/edge/upload.ts +0 -16
  179. package/src/services/aiModel/client.ts +0 -70
  180. package/src/services/aiProvider/client.ts +0 -58
  181. package/src/services/baseClientService/index.ts +0 -9
  182. package/src/services/chatGroup/client.ts +0 -63
  183. package/src/services/export/_deprecated.ts +0 -155
  184. package/src/services/export/client.ts +0 -15
  185. package/src/services/file/_deprecated.test.ts +0 -119
  186. package/src/services/file/_deprecated.ts +0 -80
  187. package/src/services/file/client.test.ts +0 -199
  188. package/src/services/file/client.ts +0 -85
  189. package/src/services/import/_deprecated.ts +0 -115
  190. package/src/services/import/client.test.ts +0 -1015
  191. package/src/services/import/client.ts +0 -64
  192. package/src/services/message/_deprecated.test.ts +0 -398
  193. package/src/services/message/_deprecated.ts +0 -168
  194. package/src/services/message/client.test.ts +0 -410
  195. package/src/services/message/client.ts +0 -192
  196. package/src/services/plugin/_deprecated.test.ts +0 -162
  197. package/src/services/plugin/_deprecated.ts +0 -42
  198. package/src/services/plugin/client.test.ts +0 -177
  199. package/src/services/plugin/client.ts +0 -46
  200. package/src/services/session/_deprecated.test.ts +0 -440
  201. package/src/services/session/_deprecated.ts +0 -190
  202. package/src/services/session/client.test.ts +0 -413
  203. package/src/services/session/client.ts +0 -193
  204. package/src/services/thread/client.ts +0 -51
  205. package/src/services/topic/_deprecated.test.ts +0 -245
  206. package/src/services/topic/_deprecated.ts +0 -75
  207. package/src/services/topic/client.ts +0 -89
  208. package/src/services/topic/pglite.test.ts +0 -212
  209. package/src/services/user/_deprecated.test.ts +0 -101
  210. package/src/services/user/_deprecated.ts +0 -70
  211. package/src/services/user/client.test.ts +0 -111
  212. package/src/services/user/client.ts +0 -104
@@ -87,57 +87,6 @@ describe('chatMessage actions', () => {
87
87
  });
88
88
 
89
89
  describe('message creation', () => {
90
- it('should create user message and trigger AI processing', async () => {
91
- const { result } = renderHook(() => useChatStore());
92
-
93
- await act(async () => {
94
- await result.current.sendMessage({ message: TEST_CONTENT.USER_MESSAGE });
95
- });
96
-
97
- expect(messageService.createMessage).toHaveBeenCalledWith({
98
- content: TEST_CONTENT.USER_MESSAGE,
99
- files: undefined,
100
- role: 'user',
101
- sessionId: TEST_IDS.SESSION_ID,
102
- topicId: TEST_IDS.TOPIC_ID,
103
- });
104
- expect(result.current.internal_coreProcessMessage).toHaveBeenCalled();
105
- });
106
-
107
- it('should send message with files attached', async () => {
108
- const { result } = renderHook(() => useChatStore());
109
- const files = [{ id: TEST_IDS.FILE_ID } as UploadFileItem];
110
-
111
- await act(async () => {
112
- await result.current.sendMessage({ message: TEST_CONTENT.USER_MESSAGE, files });
113
- });
114
-
115
- expect(messageService.createMessage).toHaveBeenCalledWith({
116
- content: TEST_CONTENT.USER_MESSAGE,
117
- files: [TEST_IDS.FILE_ID],
118
- role: 'user',
119
- sessionId: TEST_IDS.SESSION_ID,
120
- topicId: TEST_IDS.TOPIC_ID,
121
- });
122
- });
123
-
124
- it('should send files without message content', async () => {
125
- const { result } = renderHook(() => useChatStore());
126
- const files = [{ id: TEST_IDS.FILE_ID } as UploadFileItem];
127
-
128
- await act(async () => {
129
- await result.current.sendMessage({ message: TEST_CONTENT.EMPTY, files });
130
- });
131
-
132
- expect(messageService.createMessage).toHaveBeenCalledWith({
133
- content: TEST_CONTENT.EMPTY,
134
- files: [TEST_IDS.FILE_ID],
135
- role: 'user',
136
- sessionId: TEST_IDS.SESSION_ID,
137
- topicId: TEST_IDS.TOPIC_ID,
138
- });
139
- });
140
-
141
90
  it('should not process AI when onlyAddUserMessage is true', async () => {
142
91
  const { result } = renderHook(() => useChatStore());
143
92
 
@@ -169,196 +118,6 @@ describe('chatMessage actions', () => {
169
118
  expect(result.current.internal_coreProcessMessage).not.toHaveBeenCalled();
170
119
  });
171
120
  });
172
-
173
- describe('auto-create topic', () => {
174
- const TOPIC_THRESHOLD = 5;
175
-
176
- it('should create topic when threshold is reached and feature is enabled', async () => {
177
- const { result } = renderHook(() => useChatStore());
178
-
179
- const createTopicMock = vi.fn(() => Promise.resolve(TEST_IDS.NEW_TOPIC_ID));
180
- const switchTopicMock = vi.fn();
181
-
182
- act(() => {
183
- setupMockSelectors({
184
- agentConfig: {
185
- enableAutoCreateTopic: true,
186
- autoCreateTopicThreshold: TOPIC_THRESHOLD,
187
- },
188
- });
189
-
190
- useChatStore.setState({
191
- activeTopicId: undefined,
192
- messagesMap: {
193
- [messageMapKey(TEST_IDS.SESSION_ID)]: createMockMessages(TOPIC_THRESHOLD),
194
- },
195
- createTopic: createTopicMock,
196
- switchTopic: switchTopicMock,
197
- });
198
- });
199
-
200
- await act(async () => {
201
- await result.current.sendMessage({ message: TEST_CONTENT.USER_MESSAGE });
202
- });
203
-
204
- expect(createTopicMock).toHaveBeenCalled();
205
- expect(switchTopicMock).toHaveBeenCalledWith(TEST_IDS.NEW_TOPIC_ID, true);
206
- });
207
- });
208
-
209
- describe('RAG integration', () => {
210
- it('should include RAG query when RAG is enabled', async () => {
211
- const { result } = renderHook(() => useChatStore());
212
- vi.spyOn(result.current, 'internal_shouldUseRAG').mockReturnValue(true);
213
-
214
- await act(async () => {
215
- await result.current.sendMessage({ message: TEST_CONTENT.RAG_QUERY });
216
- });
217
-
218
- expect(result.current.internal_coreProcessMessage).toHaveBeenCalledWith(
219
- expect.any(Array),
220
- expect.any(String),
221
- expect.objectContaining({
222
- ragQuery: TEST_CONTENT.RAG_QUERY,
223
- }),
224
- );
225
- });
226
-
227
- it('should not use RAG when feature is disabled', async () => {
228
- const { result } = renderHook(() => useChatStore());
229
- vi.spyOn(result.current, 'internal_shouldUseRAG').mockReturnValue(false);
230
- const retrieveChunksSpy = vi.spyOn(result.current, 'internal_retrieveChunks');
231
-
232
- await act(async () => {
233
- await result.current.sendMessage({ message: TEST_CONTENT.USER_MESSAGE });
234
- });
235
-
236
- expect(retrieveChunksSpy).not.toHaveBeenCalled();
237
- expect(result.current.internal_coreProcessMessage).toHaveBeenCalledWith(
238
- expect.any(Array),
239
- expect.any(String),
240
- expect.not.objectContaining({
241
- ragQuery: expect.anything(),
242
- }),
243
- );
244
- });
245
- });
246
-
247
- describe('special flags', () => {
248
- it('should pass isWelcomeQuestion flag to processing', async () => {
249
- const { result } = renderHook(() => useChatStore());
250
-
251
- await act(async () => {
252
- await result.current.sendMessage({
253
- message: TEST_CONTENT.USER_MESSAGE,
254
- isWelcomeQuestion: true,
255
- });
256
- });
257
-
258
- expect(result.current.internal_coreProcessMessage).toHaveBeenCalledWith(
259
- expect.anything(),
260
- expect.anything(),
261
- { isWelcomeQuestion: true },
262
- );
263
- });
264
-
265
- it('should return early when onlyAddUserMessage is true', async () => {
266
- const { result } = renderHook(() => useChatStore());
267
-
268
- await act(async () => {
269
- await result.current.sendMessage({
270
- message: TEST_CONTENT.USER_MESSAGE,
271
- onlyAddUserMessage: true,
272
- });
273
- });
274
-
275
- expect(result.current.internal_coreProcessMessage).not.toHaveBeenCalled();
276
- });
277
- });
278
-
279
- describe('topic creation flow', () => {
280
- it('should handle tempMessage during topic creation', async () => {
281
- setupMockSelectors({
282
- chatConfig: { enableAutoCreateTopic: true, autoCreateTopicThreshold: 2 },
283
- });
284
-
285
- act(() => {
286
- useChatStore.setState({ activeTopicId: undefined });
287
- setupStoreWithMessages(createMockMessages(5));
288
- });
289
-
290
- const { result } = renderHook(() => useChatStore());
291
- const createTopicMock = vi
292
- .spyOn(result.current, 'createTopic')
293
- .mockResolvedValue(TEST_IDS.NEW_TOPIC_ID);
294
- const toggleMessageLoadingSpy = vi.spyOn(result.current, 'internal_toggleMessageLoading');
295
- const createTmpMessageSpy = vi
296
- .spyOn(result.current, 'internal_createTmpMessage')
297
- .mockReturnValue('temp-id');
298
- vi.spyOn(result.current, 'internal_fetchMessages').mockResolvedValue();
299
- vi.spyOn(result.current, 'switchTopic').mockResolvedValue();
300
-
301
- await act(async () => {
302
- await result.current.sendMessage({ message: TEST_CONTENT.USER_MESSAGE });
303
- });
304
-
305
- expect(createTmpMessageSpy).toHaveBeenCalled();
306
- expect(toggleMessageLoadingSpy).toHaveBeenCalledWith(true, 'temp-id');
307
- expect(createTopicMock).toHaveBeenCalled();
308
- });
309
-
310
- it('should call summaryTopicTitle after processing when new topic created', async () => {
311
- setupMockSelectors({
312
- chatConfig: { enableAutoCreateTopic: true, autoCreateTopicThreshold: 2 },
313
- });
314
-
315
- act(() => {
316
- useChatStore.setState({ activeTopicId: undefined });
317
- setupStoreWithMessages(createMockMessages(5));
318
- });
319
-
320
- const { result } = renderHook(() => useChatStore());
321
- vi.spyOn(result.current, 'createTopic').mockResolvedValue(TEST_IDS.NEW_TOPIC_ID);
322
- vi.spyOn(result.current, 'internal_createTmpMessage').mockReturnValue('temp-id');
323
- vi.spyOn(result.current, 'internal_fetchMessages').mockResolvedValue();
324
- vi.spyOn(result.current, 'switchTopic').mockResolvedValue();
325
-
326
- const summaryTopicTitleSpy = vi
327
- .spyOn(result.current, 'summaryTopicTitle')
328
- .mockResolvedValue();
329
-
330
- await act(async () => {
331
- await result.current.sendMessage({ message: TEST_CONTENT.USER_MESSAGE });
332
- });
333
-
334
- expect(summaryTopicTitleSpy).toHaveBeenCalledWith(TEST_IDS.NEW_TOPIC_ID, expect.any(Array));
335
- });
336
-
337
- it('should handle topic creation failure gracefully', async () => {
338
- setupMockSelectors({
339
- chatConfig: { enableAutoCreateTopic: true, autoCreateTopicThreshold: 2 },
340
- });
341
-
342
- act(() => {
343
- useChatStore.setState({ activeTopicId: undefined });
344
- setupStoreWithMessages(createMockMessages(5));
345
- });
346
-
347
- const { result } = renderHook(() => useChatStore());
348
- vi.spyOn(result.current, 'createTopic').mockResolvedValue(undefined);
349
- vi.spyOn(result.current, 'internal_createTmpMessage').mockReturnValue('temp-id');
350
- const toggleLoadingSpy = vi.spyOn(result.current, 'internal_toggleMessageLoading');
351
- const updateTopicLoadingSpy = vi.spyOn(result.current, 'internal_updateTopicLoading');
352
-
353
- await act(async () => {
354
- await result.current.sendMessage({ message: TEST_CONTENT.USER_MESSAGE });
355
- });
356
-
357
- // Should still call the AI processing even if topic creation fails
358
- expect(result.current.internal_coreProcessMessage).toHaveBeenCalled();
359
- expect(updateTopicLoadingSpy).not.toHaveBeenCalled();
360
- });
361
- });
362
121
  });
363
122
 
364
123
  describe('regenerateMessage', () => {
@@ -19,8 +19,33 @@ import { resetTestEnvironment, setupMockSelectors, spyOnMessageService } from '.
19
19
  // Keep zustand mock as it's needed globally
20
20
  vi.mock('zustand/traditional');
21
21
 
22
+ // Mock AntdStaticMethods
23
+ vi.mock('@/components/AntdStaticMethods', () => ({
24
+ notification: {
25
+ error: vi.fn(),
26
+ success: vi.fn(),
27
+ info: vi.fn(),
28
+ warning: vi.fn(),
29
+ },
30
+ message: {
31
+ error: vi.fn(),
32
+ success: vi.fn(),
33
+ info: vi.fn(),
34
+ warning: vi.fn(),
35
+ },
36
+ }));
37
+
38
+ // Mock sessionService to prevent TRPC requests
39
+ vi.mock('@/services/session', () => ({
40
+ sessionService: {
41
+ updateSession: vi.fn(),
42
+ updateSessionConfig: vi.fn(),
43
+ updateSessionChatConfig: vi.fn(),
44
+ },
45
+ }));
46
+
22
47
  // Mock server mode for V2 tests
23
- vi.mock('@/const/version', async (importOriginal) => {
48
+ vi.mock('@lobechat/const', async (importOriginal) => {
24
49
  const module = await importOriginal();
25
50
  return {
26
51
  ...(module as any),
@@ -60,7 +60,9 @@ export const spyOnMessageService = () => {
60
60
  const createMessageSpy = vi
61
61
  .spyOn(messageService, 'createMessage')
62
62
  .mockResolvedValue(TEST_IDS.NEW_MESSAGE_ID);
63
- const updateMessageSpy = vi.spyOn(messageService, 'updateMessage').mockResolvedValue(undefined);
63
+ const updateMessageSpy = vi
64
+ .spyOn(messageService, 'updateMessage')
65
+ .mockResolvedValue({ messages: [], success: true });
64
66
  const removeMessageSpy = vi.spyOn(messageService, 'removeMessage').mockResolvedValue(undefined);
65
67
  const updateMessageErrorSpy = vi
66
68
  .spyOn(messageService, 'updateMessageError')
@@ -17,15 +17,12 @@ import { StateCreator } from 'zustand/vanilla';
17
17
 
18
18
  import { chatService } from '@/services/chat';
19
19
  import { messageService } from '@/services/message';
20
- import { useAgentStore } from '@/store/agent';
21
20
  import { agentChatConfigSelectors, agentSelectors } from '@/store/agent/selectors';
22
21
  import { getAgentStoreState } from '@/store/agent/store';
23
22
  import { aiModelSelectors, aiProviderSelectors } from '@/store/aiInfra';
24
23
  import { getAiInfraStoreState } from '@/store/aiInfra/store';
25
24
  import { ChatStore } from '@/store/chat/store';
26
- import { messageMapKey } from '@/store/chat/utils/messageMapKey';
27
25
  import { getFileStoreState } from '@/store/file/store';
28
- import { useSessionStore } from '@/store/session';
29
26
  import { WebBrowsingManifest } from '@/tools/web-browsing';
30
27
  import { Action, setNamespace } from '@/utils/storeDebug';
31
28
 
@@ -158,13 +155,7 @@ export const generateAIChat: StateCreator<
158
155
  },
159
156
 
160
157
  sendMessage: async ({ message, files, onlyAddUserMessage, isWelcomeQuestion }) => {
161
- const {
162
- internal_coreProcessMessage,
163
- activeTopicId,
164
- activeId,
165
- activeThreadId,
166
- sendMessageInServer,
167
- } = get();
158
+ const { activeId, sendMessageInServer } = get();
168
159
  if (!activeId) return;
169
160
 
170
161
  const fileIdList = files?.map((f) => f.id);
@@ -177,134 +168,6 @@ export const generateAIChat: StateCreator<
177
168
  // router to server mode send message
178
169
  if (isServerMode)
179
170
  return sendMessageInServer({ message, files, onlyAddUserMessage, isWelcomeQuestion });
180
-
181
- set({ isCreatingMessage: true }, false, n('creatingMessage/start'));
182
-
183
- const newMessage: CreateMessageParams = {
184
- content: message,
185
- // if message has attached with files, then add files to message and the agent
186
- files: fileIdList,
187
- role: 'user',
188
- sessionId: activeId,
189
- // if there is activeTopicId,then add topicId to message
190
- topicId: activeTopicId,
191
- threadId: activeThreadId,
192
- };
193
-
194
- const agentConfig = agentChatConfigSelectors.currentChatConfig(getAgentStoreState());
195
-
196
- let tempMessageId: string | undefined = undefined;
197
- let newTopicId: string | undefined = undefined;
198
-
199
- // it should be the default topic, then
200
- // if autoCreateTopic is enabled, check to whether we need to create a topic
201
- if (!onlyAddUserMessage && !activeTopicId && agentConfig.enableAutoCreateTopic) {
202
- // check activeTopic and then auto create topic
203
- const chats = chatSelectors.activeBaseChats(get());
204
-
205
- // we will add two messages (user and assistant), so the finial length should +2
206
- const featureLength = chats.length + 2;
207
-
208
- // if there is no activeTopicId and the feature length is greater than the threshold
209
- // then create a new topic and active it
210
- if (!activeTopicId && featureLength >= agentConfig.autoCreateTopicThreshold) {
211
- // we need to create a temp message for optimistic update
212
- tempMessageId = get().internal_createTmpMessage(newMessage);
213
- get().internal_toggleMessageLoading(true, tempMessageId);
214
-
215
- const topicId = await get().createTopic();
216
-
217
- if (topicId) {
218
- newTopicId = topicId;
219
- newMessage.topicId = topicId;
220
-
221
- // we need to copy the messages to the new topic or the message will disappear
222
- const mapKey = chatSelectors.currentChatKey(get());
223
- const newMaps = {
224
- ...get().messagesMap,
225
- [messageMapKey(activeId, topicId)]: get().messagesMap[mapKey],
226
- };
227
- set({ messagesMap: newMaps }, false, n('moveMessagesToNewTopic'));
228
-
229
- // make the topic loading
230
- get().internal_updateTopicLoading(topicId, true);
231
- }
232
- }
233
- }
234
- // update assistant update to make it rerank
235
- useSessionStore.getState().triggerSessionUpdate(get().activeId);
236
-
237
- const id = await get().internal_createMessage(newMessage, {
238
- tempMessageId,
239
- skipRefresh: !onlyAddUserMessage && newMessage.fileList?.length === 0,
240
- });
241
-
242
- if (!id) {
243
- set({ isCreatingMessage: false }, false, n('creatingMessage/start'));
244
- if (!!newTopicId) get().internal_updateTopicLoading(newTopicId, false);
245
- return;
246
- }
247
-
248
- if (tempMessageId) get().internal_toggleMessageLoading(false, tempMessageId);
249
-
250
- // switch to the new topic if create the new topic
251
- if (!!newTopicId) {
252
- await get().switchTopic(newTopicId, true);
253
- await get().internal_fetchMessages();
254
-
255
- // delete previous messages
256
- // remove the temp message map
257
- const newMaps = { ...get().messagesMap, [messageMapKey(activeId, null)]: [] };
258
- set({ messagesMap: newMaps }, false, 'internal_copyMessages');
259
- }
260
-
261
- // if only add user message, then stop
262
- if (onlyAddUserMessage) {
263
- set({ isCreatingMessage: false }, false, 'creatingMessage/start');
264
- return;
265
- }
266
-
267
- // Get the current messages to generate AI response
268
- const messages = chatSelectors.activeBaseChats(get());
269
- const userFiles = chatSelectors.currentUserFiles(get()).map((f) => f.id);
270
-
271
- await internal_coreProcessMessage(messages, id, {
272
- isWelcomeQuestion,
273
- ragQuery: get().internal_shouldUseRAG() ? message : undefined,
274
- threadId: activeThreadId,
275
- });
276
-
277
- set({ isCreatingMessage: false }, false, n('creatingMessage/stop'));
278
-
279
- const summaryTitle = async () => {
280
- // if autoCreateTopic is false, then stop
281
- if (!agentConfig.enableAutoCreateTopic) return;
282
-
283
- // check activeTopic and then auto update topic title
284
- if (newTopicId) {
285
- const chats = chatSelectors.getBaseChatsByKey(messageMapKey(activeId, newTopicId))(get());
286
- await get().summaryTopicTitle(newTopicId, chats);
287
- return;
288
- }
289
-
290
- if (!activeTopicId) return;
291
- const topic = topicSelectors.getTopicById(activeTopicId)(get());
292
-
293
- if (topic && !topic.title) {
294
- const chats = chatSelectors.getBaseChatsByKey(messageMapKey(activeId, topic.id))(get());
295
- await get().summaryTopicTitle(topic.id, chats);
296
- }
297
- };
298
-
299
- // if there is relative files, then add files to agent
300
- // only available in server mode
301
- const addFilesToAgent = async () => {
302
- if (userFiles.length === 0 || !isServerMode) return;
303
-
304
- await useAgentStore.getState().addFilesToAgent(userFiles, false);
305
- };
306
-
307
- await Promise.all([summaryTitle(), addFilesToAgent()]);
308
171
  },
309
172
  stopGenerateMessage: () => {
310
173
  const { chatLoadingIdsAbortController, internal_toggleChatLoading } = get();
@@ -4,7 +4,6 @@ import { withSWR } from '~test-utils';
4
4
 
5
5
  import { DEFAULT_PREFERENCE } from '@/const/user';
6
6
  import { userService } from '@/services/user';
7
- import { ClientService } from '@/services/user/_deprecated';
8
7
  import { useUserStore } from '@/store/user';
9
8
  import { preferenceSelectors } from '@/store/user/selectors';
10
9
  import { GlobalServerConfig } from '@/types/serverConfig';
@@ -31,9 +30,7 @@ describe('createCommonSlice', () => {
31
30
  const avatar = 'data:image/png;base64,';
32
31
 
33
32
  const spyOn = vi.spyOn(result.current, 'refreshUserState');
34
- const updateAvatarSpy = vi
35
- .spyOn(ClientService.prototype, 'updateAvatar')
36
- .mockResolvedValue(undefined);
33
+ const updateAvatarSpy = vi.spyOn(userService, 'updateAvatar').mockResolvedValue(undefined);
37
34
 
38
35
  await act(async () => {
39
36
  await result.current.updateAvatar(avatar);
@@ -1,26 +0,0 @@
1
- import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
2
- import type { NextRequest } from 'next/server';
3
-
4
- import { pino } from '@/libs/logger';
5
- import { createEdgeContext } from '@/libs/trpc/edge/context';
6
- import { edgeRouter } from '@/server/routers/edge';
7
-
8
- const handler = (req: NextRequest) =>
9
- fetchRequestHandler({
10
- /**
11
- * @link https://trpc.io/docs/v11/context
12
- */
13
- createContext: () => createEdgeContext(req),
14
-
15
- endpoint: '/trpc/edge',
16
-
17
- onError: ({ error, path }) => {
18
- pino.info(`Error in tRPC handler (edge) on path: ${path}`);
19
- console.error(error);
20
- },
21
-
22
- req,
23
- router: edgeRouter,
24
- });
25
-
26
- export { handler as GET, handler as POST };
@@ -1,48 +0,0 @@
1
- 'use client';
2
-
3
- import { memo } from 'react';
4
- import { useTranslation } from 'react-i18next';
5
-
6
- import Cell, { CellProps } from '@/components/Cell';
7
- import DataImporter from '@/features/DataImporter';
8
- import { configService } from '@/services/export/_deprecated';
9
-
10
- const Category = memo(() => {
11
- const { t } = useTranslation('common');
12
- const items: CellProps[] = [
13
- {
14
- key: 'allAgent',
15
- label: t('exportType.allAgent'),
16
- onClick: configService.exportAgents,
17
- },
18
- {
19
- key: 'allAgentWithMessage',
20
- label: t('exportType.allAgentWithMessage'),
21
- onClick: configService.exportSessions,
22
- },
23
- {
24
- key: 'globalSetting',
25
- label: t('exportType.globalSetting'),
26
- onClick: configService.exportSettings,
27
- },
28
- {
29
- type: 'divider',
30
- },
31
- {
32
- key: 'all',
33
- label: t('exportType.all'),
34
- onClick: configService.exportAll,
35
- },
36
- {
37
- type: 'divider',
38
- },
39
- {
40
- key: 'import',
41
- label: <DataImporter>{t('importData')}</DataImporter>,
42
- },
43
- ];
44
-
45
- return items?.map(({ key, ...item }, index) => <Cell key={key || index} {...item} />);
46
- });
47
-
48
- export default Category;
@@ -1,33 +0,0 @@
1
- 'use client';
2
-
3
- import { ChatHeader } from '@lobehub/ui/mobile';
4
- import { useRouter } from 'next/navigation';
5
- import { memo } from 'react';
6
- import { useTranslation } from 'react-i18next';
7
- import { Flexbox } from 'react-layout-kit';
8
-
9
- import { mobileHeaderSticky } from '@/styles/mobileHeader';
10
-
11
- const Header = memo(() => {
12
- const { t } = useTranslation('common');
13
-
14
- const router = useRouter();
15
- return (
16
- <ChatHeader
17
- center={
18
- <ChatHeader.Title
19
- title={
20
- <Flexbox align={'center'} gap={4} horizontal>
21
- {t('userPanel.data')}
22
- </Flexbox>
23
- }
24
- />
25
- }
26
- onBackClick={() => router.push('/me')}
27
- showBackButton
28
- style={mobileHeaderSticky}
29
- />
30
- );
31
- });
32
-
33
- export default Header;
@@ -1,13 +0,0 @@
1
- import { PropsWithChildren } from 'react';
2
-
3
- import MobileContentLayout from '@/components/server/MobileNavLayout';
4
-
5
- import Header from './features/Header';
6
-
7
- const Layout = ({ children }: PropsWithChildren) => {
8
- return <MobileContentLayout header={<Header />}>{children}</MobileContentLayout>;
9
- };
10
-
11
- Layout.displayName = 'MeDataLayout';
12
-
13
- export default Layout;
@@ -1,5 +0,0 @@
1
- import SkeletonLoading from '@/components/Loading/SkeletonLoading';
2
-
3
- export default () => {
4
- return <SkeletonLoading paragraph={{ rows: 8 }} />;
5
- };
@@ -1,29 +0,0 @@
1
- import { redirect } from 'next/navigation';
2
-
3
- import { metadataModule } from '@/server/metadata';
4
- import { translation } from '@/server/translation';
5
- import { DynamicLayoutProps } from '@/types/next';
6
- import { RouteVariants } from '@/utils/server/routeVariants';
7
-
8
- import Category from './features/Category';
9
-
10
- export const generateMetadata = async (props: DynamicLayoutProps) => {
11
- const locale = await RouteVariants.getLocale(props);
12
- const { t } = await translation('common', locale);
13
- return metadataModule.generate({
14
- title: t('userPanel.data'),
15
- url: '/me/data',
16
- });
17
- };
18
-
19
- const Page = async (props: DynamicLayoutProps) => {
20
- const mobile = await RouteVariants.getIsMobile(props);
21
-
22
- if (!mobile) return redirect('/chat');
23
-
24
- return <Category />;
25
- };
26
-
27
- Page.displayName = 'MeData';
28
-
29
- export default Page;