@lobehub/lobehub 2.0.0-next.13 → 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 (210) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -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/page.tsx +0 -2
  14. package/src/app/[variants]/(main)/profile/_layout/Desktop/index.tsx +23 -24
  15. package/src/app/[variants]/(main)/profile/_layout/Mobile/index.tsx +5 -9
  16. package/src/app/[variants]/(main)/settings/_layout/Desktop/index.tsx +0 -2
  17. package/src/app/[variants]/(main)/settings/_layout/Mobile/index.tsx +0 -2
  18. package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/Card.tsx +1 -1
  19. package/src/app/[variants]/loading/index.tsx +1 -10
  20. package/src/components/Link.tsx +12 -0
  21. package/src/envs/app.ts +5 -8
  22. package/src/features/DataImporter/index.tsx +15 -60
  23. package/src/features/DevPanel/PostgresViewer/usePgTable.ts +3 -2
  24. package/src/hooks/useInterceptingRoutes.test.ts +21 -3
  25. package/src/libs/trpc/client/index.ts +0 -1
  26. package/src/libs/trpc/client/lambda.ts +8 -5
  27. package/src/server/routers/desktop/mcp.ts +1 -3
  28. package/src/server/routers/lambda/config/index.test.ts +2 -2
  29. package/src/server/routers/tools/mcp.ts +2 -3
  30. package/src/server/routers/tools/search.test.ts +1 -7
  31. package/src/server/routers/tools/search.ts +1 -4
  32. package/src/services/__tests__/tool.test.ts +0 -3
  33. package/src/services/aiModel/index.test.ts +0 -3
  34. package/src/services/aiModel/index.ts +1 -7
  35. package/src/services/aiProvider/index.test.ts +0 -3
  36. package/src/services/aiProvider/index.ts +1 -7
  37. package/src/services/chatGroup/index.ts +1 -10
  38. package/src/services/config.ts +1 -65
  39. package/src/services/export/index.ts +1 -4
  40. package/src/services/file/index.ts +1 -11
  41. package/src/services/import/index.ts +1 -7
  42. package/src/services/message/index.ts +1 -11
  43. package/src/services/plugin/index.ts +1 -11
  44. package/src/services/session/index.ts +1 -11
  45. package/src/services/tableViewer/client.ts +12 -15
  46. package/src/services/thread/index.ts +1 -7
  47. package/src/services/topic/index.ts +1 -11
  48. package/src/services/user/index.ts +1 -13
  49. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +0 -241
  50. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +26 -1
  51. package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +3 -1
  52. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +1 -138
  53. package/src/store/user/slices/common/action.test.ts +1 -4
  54. package/src/app/(backend)/trpc/edge/[trpc]/route.ts +0 -26
  55. package/src/app/[variants]/(main)/(mobile)/me/data/features/Category.tsx +0 -48
  56. package/src/app/[variants]/(main)/(mobile)/me/data/features/Header.tsx +0 -33
  57. package/src/app/[variants]/(main)/(mobile)/me/data/layout.tsx +0 -13
  58. package/src/app/[variants]/(main)/(mobile)/me/data/loading.tsx +0 -5
  59. package/src/app/[variants]/(main)/(mobile)/me/data/page.tsx +0 -29
  60. package/src/app/[variants]/(main)/chat/features/Migration/DBReader.ts +0 -290
  61. package/src/app/[variants]/(main)/chat/features/Migration/ExportConfigButton.tsx +0 -35
  62. package/src/app/[variants]/(main)/chat/features/Migration/Failed.tsx +0 -120
  63. package/src/app/[variants]/(main)/chat/features/Migration/Modal.tsx +0 -81
  64. package/src/app/[variants]/(main)/chat/features/Migration/Start.tsx +0 -108
  65. package/src/app/[variants]/(main)/chat/features/Migration/UpgradeButton.tsx +0 -71
  66. package/src/app/[variants]/(main)/chat/features/Migration/const.ts +0 -15
  67. package/src/app/[variants]/(main)/chat/features/Migration/index.tsx +0 -50
  68. package/src/app/[variants]/loading/Client/Content.tsx +0 -48
  69. package/src/app/[variants]/loading/Client/Error.tsx +0 -27
  70. package/src/app/[variants]/loading/Client/Redirect.tsx +0 -47
  71. package/src/app/[variants]/loading/Client/index.tsx +0 -22
  72. package/src/components/InnerLink.tsx +0 -20
  73. package/src/database/_deprecated/core/__tests__/db-upgrade.test.ts +0 -42
  74. package/src/database/_deprecated/core/__tests__/db.test.ts +0 -79
  75. package/src/database/_deprecated/core/__tests__/model.test.ts +0 -55
  76. package/src/database/_deprecated/core/db.ts +0 -246
  77. package/src/database/_deprecated/core/index.ts +0 -2
  78. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/fixtures/input.json +0 -55
  79. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/fixtures/output.json +0 -60
  80. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/index.test.ts +0 -14
  81. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/index.ts +0 -22
  82. package/src/database/_deprecated/core/migrations/migrateSettingsToUser/type.ts +0 -105
  83. package/src/database/_deprecated/core/model.ts +0 -218
  84. package/src/database/_deprecated/core/schemas.ts +0 -88
  85. package/src/database/_deprecated/core/types/db.ts +0 -15
  86. package/src/database/_deprecated/models/__DEBUG.ts +0 -124
  87. package/src/database/_deprecated/models/__tests__/file.test.ts +0 -83
  88. package/src/database/_deprecated/models/__tests__/message.test.ts +0 -426
  89. package/src/database/_deprecated/models/__tests__/plugin.test.ts +0 -81
  90. package/src/database/_deprecated/models/__tests__/session.test.ts +0 -253
  91. package/src/database/_deprecated/models/__tests__/sessionGroup.test.ts +0 -220
  92. package/src/database/_deprecated/models/__tests__/topic.test.ts +0 -523
  93. package/src/database/_deprecated/models/__tests__/user.test.ts +0 -82
  94. package/src/database/_deprecated/models/file.ts +0 -51
  95. package/src/database/_deprecated/models/message.ts +0 -277
  96. package/src/database/_deprecated/models/plugin.ts +0 -62
  97. package/src/database/_deprecated/models/session.ts +0 -271
  98. package/src/database/_deprecated/models/sessionGroup.ts +0 -93
  99. package/src/database/_deprecated/models/topic.ts +0 -250
  100. package/src/database/_deprecated/models/user.ts +0 -69
  101. package/src/database/_deprecated/schemas/files.ts +0 -39
  102. package/src/database/_deprecated/schemas/message.ts +0 -50
  103. package/src/database/_deprecated/schemas/plugin.ts +0 -12
  104. package/src/database/_deprecated/schemas/session.ts +0 -54
  105. package/src/database/_deprecated/schemas/sessionGroup.ts +0 -8
  106. package/src/database/_deprecated/schemas/topic.ts +0 -12
  107. package/src/database/_deprecated/schemas/user.ts +0 -40
  108. package/src/features/DataImporter/_deprecated.ts +0 -43
  109. package/src/features/InitClientDB/EnableModal.tsx +0 -118
  110. package/src/features/InitClientDB/ErrorResult.tsx +0 -143
  111. package/src/features/InitClientDB/InitIndicator.tsx +0 -124
  112. package/src/features/InitClientDB/PGliteIcon.tsx +0 -28
  113. package/src/features/InitClientDB/features/DatabaseRepair/Backup.tsx +0 -75
  114. package/src/features/InitClientDB/features/DatabaseRepair/Diagnosis.tsx +0 -98
  115. package/src/features/InitClientDB/features/DatabaseRepair/Repair.tsx +0 -218
  116. package/src/features/InitClientDB/features/DatabaseRepair/index.tsx +0 -91
  117. package/src/features/InitClientDB/index.tsx +0 -37
  118. package/src/libs/trpc/client/edge.ts +0 -26
  119. package/src/libs/trpc/edge/context.ts +0 -71
  120. package/src/libs/trpc/edge/index.ts +0 -45
  121. package/src/libs/trpc/edge/init.ts +0 -26
  122. package/src/libs/trpc/edge/middleware/jwtPayload.test.ts +0 -75
  123. package/src/libs/trpc/edge/middleware/jwtPayload.ts +0 -14
  124. package/src/migrations/FromV0ToV1.ts +0 -10
  125. package/src/migrations/FromV1ToV2/fixtures/input-v1-session.json +0 -191
  126. package/src/migrations/FromV1ToV2/fixtures/output-v2.json +0 -202
  127. package/src/migrations/FromV1ToV2/index.ts +0 -82
  128. package/src/migrations/FromV1ToV2/migrations.test.ts +0 -224
  129. package/src/migrations/FromV1ToV2/types/v1.ts +0 -78
  130. package/src/migrations/FromV1ToV2/types/v2.ts +0 -52
  131. package/src/migrations/FromV2ToV3/fixtures/input-v2-session.json +0 -72
  132. package/src/migrations/FromV2ToV3/fixtures/output-v3-from-v1.json +0 -203
  133. package/src/migrations/FromV2ToV3/fixtures/output-v3.json +0 -74
  134. package/src/migrations/FromV2ToV3/index.ts +0 -30
  135. package/src/migrations/FromV2ToV3/migrations.test.ts +0 -42
  136. package/src/migrations/FromV2ToV3/types/v3.ts +0 -27
  137. package/src/migrations/FromV3ToV4/fixtures/azure-input-v3.json +0 -79
  138. package/src/migrations/FromV3ToV4/fixtures/azure-output-v4.json +0 -75
  139. package/src/migrations/FromV3ToV4/fixtures/ollama-input-v3.json +0 -85
  140. package/src/migrations/FromV3ToV4/fixtures/ollama-output-v4.json +0 -86
  141. package/src/migrations/FromV3ToV4/fixtures/openai-input-v3.json +0 -77
  142. package/src/migrations/FromV3ToV4/fixtures/openai-output-v4.json +0 -77
  143. package/src/migrations/FromV3ToV4/fixtures/openrouter-input-v3.json +0 -82
  144. package/src/migrations/FromV3ToV4/fixtures/openrouter-output-v4.json +0 -85
  145. package/src/migrations/FromV3ToV4/fixtures/output-v4-from-v1.json +0 -203
  146. package/src/migrations/FromV3ToV4/index.ts +0 -102
  147. package/src/migrations/FromV3ToV4/migrations.test.ts +0 -195
  148. package/src/migrations/FromV3ToV4/types/v3.ts +0 -52
  149. package/src/migrations/FromV3ToV4/types/v4.ts +0 -37
  150. package/src/migrations/FromV4ToV5/fixtures/from-v1-to-v5-output.json +0 -245
  151. package/src/migrations/FromV4ToV5/fixtures/function-input-v4.json +0 -96
  152. package/src/migrations/FromV4ToV5/fixtures/function-output-v5.json +0 -120
  153. package/src/migrations/FromV4ToV5/index.ts +0 -58
  154. package/src/migrations/FromV4ToV5/migrations.test.ts +0 -49
  155. package/src/migrations/FromV4ToV5/types/v4.ts +0 -21
  156. package/src/migrations/FromV4ToV5/types/v5.ts +0 -27
  157. package/src/migrations/FromV5ToV6/fixtures/from-v1-to-v6-output.json +0 -247
  158. package/src/migrations/FromV5ToV6/fixtures/session-input-v5.json +0 -81
  159. package/src/migrations/FromV5ToV6/fixtures/session-output-v6.json +0 -85
  160. package/src/migrations/FromV5ToV6/index.ts +0 -61
  161. package/src/migrations/FromV5ToV6/migrations.test.ts +0 -50
  162. package/src/migrations/FromV5ToV6/types/v5.ts +0 -48
  163. package/src/migrations/FromV5ToV6/types/v6.ts +0 -63
  164. package/src/migrations/FromV6ToV7/fixtures/output-v7-from-v1.json +0 -203
  165. package/src/migrations/FromV6ToV7/fixtures/provider-input-v6.json +0 -103
  166. package/src/migrations/FromV6ToV7/fixtures/provider-output-v7.json +0 -118
  167. package/src/migrations/FromV6ToV7/index.ts +0 -101
  168. package/src/migrations/FromV6ToV7/migrations.test.ts +0 -64
  169. package/src/migrations/FromV6ToV7/types/v6.ts +0 -61
  170. package/src/migrations/FromV6ToV7/types/v7.ts +0 -69
  171. package/src/migrations/VersionController.test.ts +0 -88
  172. package/src/migrations/VersionController.ts +0 -67
  173. package/src/migrations/index.ts +0 -61
  174. package/src/server/routers/edge/appStatus.ts +0 -3
  175. package/src/server/routers/edge/index.ts +0 -14
  176. package/src/server/routers/edge/upload.ts +0 -16
  177. package/src/services/aiModel/client.ts +0 -70
  178. package/src/services/aiProvider/client.ts +0 -58
  179. package/src/services/baseClientService/index.ts +0 -9
  180. package/src/services/chatGroup/client.ts +0 -63
  181. package/src/services/export/_deprecated.ts +0 -155
  182. package/src/services/export/client.ts +0 -15
  183. package/src/services/file/_deprecated.test.ts +0 -119
  184. package/src/services/file/_deprecated.ts +0 -80
  185. package/src/services/file/client.test.ts +0 -199
  186. package/src/services/file/client.ts +0 -85
  187. package/src/services/import/_deprecated.ts +0 -115
  188. package/src/services/import/client.test.ts +0 -1015
  189. package/src/services/import/client.ts +0 -64
  190. package/src/services/message/_deprecated.test.ts +0 -398
  191. package/src/services/message/_deprecated.ts +0 -168
  192. package/src/services/message/client.test.ts +0 -410
  193. package/src/services/message/client.ts +0 -192
  194. package/src/services/plugin/_deprecated.test.ts +0 -162
  195. package/src/services/plugin/_deprecated.ts +0 -42
  196. package/src/services/plugin/client.test.ts +0 -177
  197. package/src/services/plugin/client.ts +0 -46
  198. package/src/services/session/_deprecated.test.ts +0 -440
  199. package/src/services/session/_deprecated.ts +0 -190
  200. package/src/services/session/client.test.ts +0 -413
  201. package/src/services/session/client.ts +0 -193
  202. package/src/services/thread/client.ts +0 -51
  203. package/src/services/topic/_deprecated.test.ts +0 -245
  204. package/src/services/topic/_deprecated.ts +0 -75
  205. package/src/services/topic/client.ts +0 -89
  206. package/src/services/topic/pglite.test.ts +0 -212
  207. package/src/services/user/_deprecated.test.ts +0 -101
  208. package/src/services/user/_deprecated.ts +0 -70
  209. package/src/services/user/client.test.ts +0 -111
  210. 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;