@lobehub/lobehub 2.0.0-next.34 → 2.0.0-next.36

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 (282) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/next.config.ts +5 -6
  4. package/package.json +2 -2
  5. package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +112 -77
  6. package/packages/agent-runtime/src/core/runtime.ts +63 -18
  7. package/packages/agent-runtime/src/types/generalAgent.ts +55 -0
  8. package/packages/agent-runtime/src/types/index.ts +1 -0
  9. package/packages/agent-runtime/src/types/instruction.ts +10 -3
  10. package/packages/const/src/user.ts +0 -1
  11. package/packages/context-engine/src/processors/GroupMessageFlatten.ts +8 -6
  12. package/packages/context-engine/src/processors/__tests__/GroupMessageFlatten.test.ts +12 -12
  13. package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/assistant-group-branches.json +249 -0
  14. package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/index.ts +4 -0
  15. package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/multi-assistant-group.json +260 -0
  16. package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/active-index-1.json +4 -0
  17. package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/assistant-group-branches.json +481 -0
  18. package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/conversation.json +5 -1
  19. package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/index.ts +4 -0
  20. package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/multi-assistant-group.json +407 -0
  21. package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/nested.json +18 -2
  22. package/packages/conversation-flow/src/__tests__/fixtures/outputs/complex-scenario.json +25 -3
  23. package/packages/conversation-flow/src/__tests__/parse.test.ts +12 -0
  24. package/packages/conversation-flow/src/index.ts +1 -1
  25. package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +112 -34
  26. package/packages/conversation-flow/src/types/flatMessageList.ts +0 -12
  27. package/packages/conversation-flow/src/{types.ts → types/index.ts} +3 -14
  28. package/packages/database/src/models/message.ts +18 -19
  29. package/packages/types/src/aiChat.ts +2 -0
  30. package/packages/types/src/importer.ts +2 -2
  31. package/packages/types/src/message/ui/chat.ts +17 -1
  32. package/packages/types/src/message/ui/extra.ts +2 -2
  33. package/packages/types/src/message/ui/params.ts +2 -2
  34. package/packages/types/src/user/preference.ts +0 -4
  35. package/packages/utils/src/tokenizer/index.ts +3 -11
  36. package/src/app/[variants]/(main)/chat/ChatRouter.tsx +83 -0
  37. package/src/app/[variants]/(main)/chat/_layout/ChatLayout.tsx +22 -0
  38. package/src/app/[variants]/(main)/chat/_layout/Desktop/SessionPanel.tsx +12 -7
  39. package/src/app/[variants]/(main)/chat/_layout/Desktop/index.tsx +2 -2
  40. package/src/app/[variants]/(main)/chat/_layout/FeatureFlagsProvider.tsx +24 -0
  41. package/src/app/[variants]/(main)/chat/_layout/Mobile.tsx +3 -2
  42. package/src/app/[variants]/(main)/chat/_layout/type.ts +0 -1
  43. package/src/app/[variants]/(main)/chat/components/ConversationArea.tsx +29 -0
  44. package/src/app/[variants]/(main)/chat/components/MainChatPage.tsx +25 -0
  45. package/src/app/[variants]/(main)/chat/components/PortalPanel.tsx +28 -0
  46. package/src/app/[variants]/(main)/chat/components/SessionPanel.tsx +33 -0
  47. package/src/app/[variants]/(main)/chat/{settings/page.tsx → components/SettingsPage.tsx} +35 -3
  48. package/src/app/[variants]/(main)/chat/components/TopicSidebar.tsx +30 -0
  49. package/src/app/[variants]/(main)/chat/components/WorkspaceLayout.tsx +73 -0
  50. package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/Desktop/MessageFromUrl.tsx +3 -3
  51. package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/V1Mobile/index.tsx +1 -1
  52. package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/V1Mobile/useSend.ts +3 -3
  53. package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/useSend.ts +6 -6
  54. package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/ChatItem/index.tsx +1 -1
  55. package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/Content.tsx +5 -3
  56. package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/WelcomeChatItem/AgentWelcome/OpeningQuestions.tsx +2 -2
  57. package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/WelcomeChatItem/GroupWelcome/GroupUsageSuggest.tsx +2 -2
  58. package/src/app/[variants]/(main)/chat/{layout.ts → layout.tsx} +0 -1
  59. package/src/app/[variants]/(main)/chat/page.tsx +12 -0
  60. package/src/app/[variants]/(main)/labs/page.tsx +0 -9
  61. package/src/features/ChatInput/ActionBar/STT/browser.tsx +3 -3
  62. package/src/features/ChatInput/ActionBar/STT/openai.tsx +3 -3
  63. package/src/features/Conversation/Error/AccessCodeForm.tsx +1 -1
  64. package/src/features/Conversation/Error/ChatInvalidApiKey.tsx +1 -1
  65. package/src/features/Conversation/Error/ClerkLogin/index.tsx +1 -1
  66. package/src/features/Conversation/Error/OAuthForm.tsx +1 -1
  67. package/src/features/Conversation/Error/index.tsx +0 -5
  68. package/src/features/Conversation/Messages/Assistant/Actions/index.tsx +13 -10
  69. package/src/features/Conversation/Messages/Assistant/Extra/index.test.tsx +3 -8
  70. package/src/features/Conversation/Messages/Assistant/Extra/index.tsx +2 -6
  71. package/src/features/Conversation/Messages/Assistant/MessageContent.tsx +7 -9
  72. package/src/features/Conversation/Messages/Assistant/Tool/Inspector/PluginResult.tsx +2 -2
  73. package/src/features/Conversation/Messages/Assistant/Tool/Inspector/PluginState.tsx +2 -2
  74. package/src/features/Conversation/Messages/Assistant/Tool/Render/PluginSettings.tsx +4 -1
  75. package/src/features/Conversation/Messages/Assistant/Tool/Render/index.tsx +2 -3
  76. package/src/features/Conversation/Messages/Assistant/index.tsx +57 -60
  77. package/src/features/Conversation/Messages/Default.tsx +1 -0
  78. package/src/features/Conversation/Messages/Group/Actions/WithContentId.tsx +38 -10
  79. package/src/features/Conversation/Messages/Group/Actions/index.tsx +1 -1
  80. package/src/features/Conversation/Messages/Group/ContentBlock.tsx +1 -3
  81. package/src/features/Conversation/Messages/Group/GroupChildren.tsx +12 -12
  82. package/src/features/Conversation/Messages/Group/MessageContent.tsx +7 -1
  83. package/src/features/Conversation/Messages/Group/Tool/Render/PluginSettings.tsx +1 -1
  84. package/src/features/Conversation/Messages/Group/index.tsx +2 -1
  85. package/src/features/Conversation/Messages/Supervisor/index.tsx +2 -2
  86. package/src/features/Conversation/Messages/User/{Actions.tsx → Actions/ActionsBar.tsx} +26 -25
  87. package/src/features/Conversation/Messages/User/Actions/MessageBranch.tsx +107 -0
  88. package/src/features/Conversation/Messages/User/Actions/index.tsx +42 -0
  89. package/src/features/Conversation/Messages/User/index.tsx +43 -44
  90. package/src/features/Conversation/Messages/index.tsx +3 -3
  91. package/src/features/Conversation/components/AutoScroll.tsx +3 -3
  92. package/src/features/Conversation/components/Extras/Usage/UsageDetail/AnimatedNumber.tsx +55 -0
  93. package/src/features/Conversation/components/Extras/Usage/UsageDetail/index.tsx +5 -2
  94. package/src/features/Conversation/components/VirtualizedList/index.tsx +29 -20
  95. package/src/features/Conversation/hooks/useChatListActionsBar.tsx +8 -10
  96. package/src/features/Portal/GroupThread/Body/index.tsx +1 -1
  97. package/src/features/Portal/Thread/Chat/ChatInput/useSend.ts +3 -3
  98. package/src/hooks/useHotkeys/chatScope.ts +16 -8
  99. package/src/server/routers/lambda/__tests__/aiChat.test.ts +1 -1
  100. package/src/server/routers/lambda/__tests__/integration/message.integration.test.ts +0 -26
  101. package/src/server/routers/lambda/aiChat.ts +3 -2
  102. package/src/server/routers/lambda/message.ts +8 -16
  103. package/src/server/services/message/__tests__/index.test.ts +29 -39
  104. package/src/server/services/message/index.ts +41 -36
  105. package/src/services/electron/desktopNotification.ts +6 -6
  106. package/src/services/electron/file.ts +6 -6
  107. package/src/services/file/ClientS3/index.ts +8 -8
  108. package/src/services/message/__tests__/metadata-race-condition.test.ts +157 -0
  109. package/src/services/message/index.ts +21 -15
  110. package/src/services/upload.ts +11 -11
  111. package/src/services/utils/abortableRequest.test.ts +161 -0
  112. package/src/services/utils/abortableRequest.ts +67 -0
  113. package/src/store/chat/agents/GeneralChatAgent.ts +137 -0
  114. package/src/store/chat/agents/createAgentExecutors.ts +395 -0
  115. package/src/store/chat/helpers.test.ts +0 -99
  116. package/src/store/chat/helpers.ts +0 -11
  117. package/src/store/chat/slices/aiChat/actions/__tests__/conversationControl.test.ts +332 -0
  118. package/src/store/chat/slices/aiChat/actions/__tests__/conversationLifecycle.test.ts +257 -0
  119. package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +11 -2
  120. package/src/store/chat/slices/aiChat/actions/__tests__/rag.test.ts +6 -6
  121. package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +391 -0
  122. package/src/store/chat/slices/aiChat/actions/__tests__/streamingStates.test.ts +179 -0
  123. package/src/store/chat/slices/aiChat/actions/conversationControl.ts +157 -0
  124. package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +329 -0
  125. package/src/store/chat/slices/aiChat/actions/generateAIGroupChat.ts +14 -14
  126. package/src/store/chat/slices/aiChat/actions/index.ts +12 -6
  127. package/src/store/chat/slices/aiChat/actions/rag.ts +9 -6
  128. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +604 -0
  129. package/src/store/chat/slices/aiChat/actions/streamingStates.ts +84 -0
  130. package/src/store/chat/slices/builtinTool/actions/__tests__/localSystem.test.ts +4 -4
  131. package/src/store/chat/slices/builtinTool/actions/__tests__/search.test.ts +11 -11
  132. package/src/store/chat/slices/builtinTool/actions/interpreter.ts +8 -8
  133. package/src/store/chat/slices/builtinTool/actions/localSystem.ts +2 -2
  134. package/src/store/chat/slices/builtinTool/actions/search.ts +8 -8
  135. package/src/store/chat/slices/message/action.test.ts +79 -68
  136. package/src/store/chat/slices/message/actions/index.ts +39 -0
  137. package/src/store/chat/slices/message/actions/internals.ts +77 -0
  138. package/src/store/chat/slices/message/actions/optimisticUpdate.ts +260 -0
  139. package/src/store/chat/slices/message/actions/publicApi.ts +224 -0
  140. package/src/store/chat/slices/message/actions/query.ts +120 -0
  141. package/src/store/chat/slices/message/actions/runtimeState.ts +108 -0
  142. package/src/store/chat/slices/message/initialState.ts +13 -0
  143. package/src/store/chat/slices/message/reducer.test.ts +48 -370
  144. package/src/store/chat/slices/message/reducer.ts +17 -81
  145. package/src/store/chat/slices/message/selectors/chat.test.ts +13 -50
  146. package/src/store/chat/slices/message/selectors/chat.ts +78 -242
  147. package/src/store/chat/slices/message/selectors/dbMessage.ts +140 -0
  148. package/src/store/chat/slices/message/selectors/displayMessage.ts +301 -0
  149. package/src/store/chat/slices/message/selectors/messageState.ts +5 -2
  150. package/src/store/chat/slices/plugin/action.test.ts +62 -64
  151. package/src/store/chat/slices/plugin/action.ts +34 -28
  152. package/src/store/chat/slices/thread/action.test.ts +28 -31
  153. package/src/store/chat/slices/thread/action.ts +13 -10
  154. package/src/store/chat/slices/thread/selectors/index.ts +8 -6
  155. package/src/store/chat/slices/topic/reducer.ts +11 -3
  156. package/src/store/chat/store.ts +1 -1
  157. package/src/store/user/slices/preference/selectors/labPrefer.ts +0 -3
  158. package/packages/database/src/models/__tests__/message.grouping.test.ts +0 -812
  159. package/packages/database/src/utils/__tests__/groupMessages.test.ts +0 -1132
  160. package/packages/database/src/utils/groupMessages.ts +0 -361
  161. package/packages/utils/src/tokenizer/client.ts +0 -35
  162. package/packages/utils/src/tokenizer/estimated.ts +0 -4
  163. package/packages/utils/src/tokenizer/server.ts +0 -11
  164. package/packages/utils/src/tokenizer/tokenizer.worker.ts +0 -12
  165. package/src/app/(backend)/webapi/tokenizer/index.test.ts +0 -32
  166. package/src/app/(backend)/webapi/tokenizer/route.ts +0 -8
  167. package/src/app/[variants]/(main)/chat/(workspace)/layout.ts +0 -11
  168. package/src/app/[variants]/(main)/chat/(workspace)/page.tsx +0 -53
  169. package/src/app/[variants]/(main)/chat/@session/default.tsx +0 -31
  170. package/src/app/[variants]/(main)/chat/settings/layout.tsx +0 -21
  171. package/src/features/Conversation/Error/InvalidAccessCode.tsx +0 -79
  172. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +0 -975
  173. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +0 -1050
  174. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +0 -720
  175. package/src/store/chat/slices/aiChat/actions/generateAIChatV2.ts +0 -849
  176. package/src/store/chat/slices/message/action.ts +0 -629
  177. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/default.tsx +0 -0
  178. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatHydration/index.tsx +0 -0
  179. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/Desktop/ClassicChat.tsx +0 -0
  180. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/Desktop/GroupChat.tsx +0 -0
  181. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/Desktop/index.tsx +0 -0
  182. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/Desktop/useSendMenuItems.tsx +0 -0
  183. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/Mobile/MentionedUsers/MentionedUserItem.tsx +0 -0
  184. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/Mobile/MentionedUsers/index.tsx +0 -0
  185. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/Mobile/index.tsx +0 -0
  186. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/V1Mobile/ActionBar.tsx +0 -0
  187. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/V1Mobile/Files/index.tsx +0 -0
  188. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/V1Mobile/InputArea/Container.tsx +0 -0
  189. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/V1Mobile/InputArea/index.tsx +0 -0
  190. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/V1Mobile/Send.tsx +0 -0
  191. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatInput/index.tsx +0 -0
  192. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/ChatItem/OrchestratorThinking.tsx +0 -0
  193. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/ChatItem/Thread.tsx +0 -0
  194. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/ChatItem/ThreadItem.tsx +0 -0
  195. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/WelcomeChatItem/AgentWelcome/AddButton.tsx +0 -0
  196. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/WelcomeChatItem/AgentWelcome/index.tsx +0 -0
  197. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/WelcomeChatItem/GroupWelcome/index.tsx +0 -0
  198. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/WelcomeChatItem/GroupWelcome/useTemplateMatching.ts +0 -0
  199. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/WelcomeChatItem/index.tsx +0 -0
  200. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatList/index.tsx +0 -0
  201. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ChatMinimap/index.tsx +0 -0
  202. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ThreadHydration.tsx +0 -0
  203. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ZenModeToast/Toast.tsx +0 -0
  204. /package/src/app/[variants]/(main)/chat/{(workspace)/@conversation → components/conversation}/features/ZenModeToast/index.tsx +0 -0
  205. /package/src/app/[variants]/(main)/chat/{(workspace) → components}/features/AgentSettings/index.tsx +0 -0
  206. /package/src/app/[variants]/(main)/chat/{(workspace) → components}/features/AgentTeamSettings/index.tsx +0 -0
  207. /package/src/app/[variants]/(main)/chat/{(workspace) → components}/features/ChangelogModal.tsx +0 -0
  208. /package/src/app/[variants]/(main)/chat/{(workspace) → components}/features/SettingButton.tsx +0 -0
  209. /package/src/app/[variants]/(main)/chat/{(workspace) → components}/features/ShareButton/index.tsx +0 -0
  210. /package/src/app/[variants]/(main)/chat/{(workspace) → components}/features/TelemetryNotification.tsx +0 -0
  211. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Desktop/ChatHeader/HeaderAction.tsx +0 -0
  212. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Desktop/ChatHeader/Main.tsx +0 -0
  213. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Desktop/ChatHeader/Tags/HistoryLimitTags.tsx +0 -0
  214. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Desktop/ChatHeader/Tags/KnowledgeTag.tsx +0 -0
  215. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Desktop/ChatHeader/Tags/MemberCountTag.tsx +0 -0
  216. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Desktop/ChatHeader/Tags/SearchTags.tsx +0 -0
  217. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Desktop/ChatHeader/Tags/index.tsx +0 -0
  218. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Desktop/ChatHeader/index.tsx +0 -0
  219. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Desktop/Portal.tsx +0 -0
  220. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Desktop/TopicPanel.tsx +0 -0
  221. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Desktop/index.tsx +0 -0
  222. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Mobile/ChatHeader/ChatHeaderTitle.tsx +0 -0
  223. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Mobile/ChatHeader/index.tsx +0 -0
  224. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Mobile/TopicModal.tsx +0 -0
  225. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/Mobile/index.tsx +0 -0
  226. /package/src/app/[variants]/(main)/chat/{(workspace)/_layout → components/layout}/type.ts +0 -0
  227. /package/src/app/[variants]/(main)/chat/{(workspace)/@portal → components/portal}/_layout/Desktop.tsx +0 -0
  228. /package/src/app/[variants]/(main)/chat/{(workspace)/@portal → components/portal}/_layout/Mobile.tsx +0 -0
  229. /package/src/app/[variants]/(main)/chat/{(workspace)/@portal → components/portal}/default.tsx +0 -0
  230. /package/src/app/[variants]/(main)/chat/{(workspace)/@portal → components/portal}/error.tsx +0 -0
  231. /package/src/app/[variants]/(main)/chat/{(workspace)/@portal → components/portal}/features/Body.tsx +0 -0
  232. /package/src/app/[variants]/(main)/chat/{(workspace)/@portal → components/portal}/loading.tsx +0 -0
  233. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/_layout/Desktop.tsx +0 -0
  234. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/_layout/Mobile.tsx +0 -0
  235. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/default.tsx +0 -0
  236. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/AgentConfig/SystemRole.tsx +0 -0
  237. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/AgentConfig/index.tsx +0 -0
  238. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/ConfigLayout.tsx +0 -0
  239. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/ConfigSwitcher.tsx +0 -0
  240. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/GroupConfig/GroupMember.tsx +0 -0
  241. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/GroupConfig/GroupMemberItem.tsx +0 -0
  242. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/GroupConfig/GroupRole.tsx +0 -0
  243. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/GroupConfig/index.tsx +0 -0
  244. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/GroupConfig/style.ts +0 -0
  245. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/SkeletonList.tsx +0 -0
  246. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/Header.tsx +0 -0
  247. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/TopicListContent/ByTimeMode/GroupItem.tsx +0 -0
  248. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/TopicListContent/ByTimeMode/index.tsx +0 -0
  249. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/TopicListContent/FlatMode/index.tsx +0 -0
  250. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/TopicListContent/SearchResult/index.tsx +0 -0
  251. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/TopicListContent/ThreadItem/Content.tsx +0 -0
  252. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/TopicListContent/ThreadItem/index.tsx +0 -0
  253. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/TopicListContent/ThreadList/index.tsx +0 -0
  254. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/TopicListContent/TopicItem/DefaultContent.tsx +0 -0
  255. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/TopicListContent/TopicItem/TopicContent.tsx +0 -0
  256. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/TopicListContent/TopicItem/index.tsx +0 -0
  257. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/TopicListContent/index.tsx +0 -0
  258. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/TopicSearchBar/index.tsx +0 -0
  259. /package/src/app/[variants]/(main)/chat/{(workspace)/@topic → components/topic}/features/Topic/index.tsx +0 -0
  260. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionHydration.tsx +0 -0
  261. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/CollapseGroup/Actions.tsx +0 -0
  262. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/CollapseGroup/index.tsx +0 -0
  263. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/DefaultMode.tsx +0 -0
  264. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/Inbox/index.tsx +0 -0
  265. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/List/AddButton.tsx +0 -0
  266. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/List/Item/Actions.tsx +0 -0
  267. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/List/Item/index.tsx +0 -0
  268. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/List/index.tsx +0 -0
  269. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/ListItem/index.tsx +0 -0
  270. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/Modals/ConfigGroupModal/GroupItem.tsx +0 -0
  271. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/Modals/ConfigGroupModal/index.tsx +0 -0
  272. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/Modals/CreateGroupModal.tsx +0 -0
  273. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/Modals/RenameGroupModal.tsx +0 -0
  274. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/SearchMode.tsx +0 -0
  275. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionListContent/index.tsx +0 -0
  276. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SessionSearchBar.tsx +0 -0
  277. /package/src/app/[variants]/(main)/chat/{@session → session}/features/SkeletonList.tsx +0 -0
  278. /package/src/app/[variants]/(main)/chat/{@session/_layout → session/layout}/Desktop/PanelBody.tsx +0 -0
  279. /package/src/app/[variants]/(main)/chat/{@session/_layout → session/layout}/Desktop/SessionHeader.tsx +0 -0
  280. /package/src/app/[variants]/(main)/chat/{@session/_layout → session/layout}/Desktop/index.tsx +0 -0
  281. /package/src/app/[variants]/(main)/chat/{@session/_layout → session/layout}/Mobile/SessionHeader.tsx +0 -0
  282. /package/src/app/[variants]/(main)/chat/{@session/_layout → session/layout}/Mobile/index.tsx +0 -0
@@ -1,812 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
2
-
3
- import { getTestDB } from '../../models/__tests__/_util';
4
- import { files, messagePlugins, messages, messagesFiles, sessions, users } from '../../schemas';
5
- import { LobeChatDatabase } from '../../type';
6
- import { MessageModel } from '../message';
7
-
8
- const serverDB: LobeChatDatabase = await getTestDB();
9
-
10
- const userId = 'message-grouping-test';
11
- const messageModel = new MessageModel(serverDB, userId);
12
-
13
- beforeEach(async () => {
14
- // Clear tables before each test
15
- await serverDB.transaction(async (trx) => {
16
- await trx.delete(users);
17
- await trx.insert(users).values([{ id: userId }, { id: '456' }]);
18
- await trx.insert(sessions).values([{ id: '1', userId }]);
19
- await trx.insert(files).values({
20
- id: 'f1',
21
- userId: userId,
22
- name: 'test.png',
23
- fileType: 'image/png',
24
- size: 100,
25
- url: 'url1',
26
- });
27
- });
28
- });
29
-
30
- afterEach(async () => {
31
- // Clean up after each test
32
- await serverDB.delete(messages);
33
- await serverDB.delete(messagePlugins);
34
- await serverDB.delete(messagesFiles);
35
- });
36
-
37
- describe('MessageModel - Message Grouping', () => {
38
- describe('Basic Grouping Scenarios', () => {
39
- it('should group assistant message with single tool result', async () => {
40
- // Create assistant message with tool
41
- await serverDB.insert(messages).values({
42
- id: 'msg-1',
43
- userId,
44
- role: 'assistant',
45
- content: 'Checking weather',
46
- tools: [
47
- {
48
- id: 'tool-1',
49
- identifier: 'weather',
50
- apiName: 'getWeather',
51
- arguments: '{"city":"Beijing"}',
52
- type: 'default',
53
- },
54
- ],
55
- });
56
-
57
- // Create tool message
58
- await serverDB.insert(messages).values({
59
- id: 'msg-2',
60
- userId,
61
- role: 'tool',
62
- content: 'Beijing: Sunny, 25°C',
63
- });
64
-
65
- await serverDB.insert(messagePlugins).values({
66
- id: 'msg-2',
67
- userId,
68
- toolCallId: 'tool-1',
69
- identifier: 'weather',
70
- state: { cached: true },
71
- });
72
-
73
- // Query messages
74
- const result = await messageModel.query(
75
- { sessionId: null },
76
- { groupAssistantMessages: true },
77
- );
78
-
79
- // Verify grouping
80
- expect(result).toHaveLength(1);
81
- expect(result[0].role).toBe('group');
82
- expect(result[0].content).toBe('');
83
- expect(result[0].children).toHaveLength(1);
84
-
85
- const block = result[0].children![0];
86
- expect(block.content).toBe('Checking weather');
87
- expect(block.tools).toHaveLength(1);
88
- expect(block.tools![0]).toMatchObject({
89
- id: 'tool-1',
90
- identifier: 'weather',
91
- apiName: 'getWeather',
92
- });
93
- expect(block.tools![0].result).toMatchObject({
94
- content: 'Beijing: Sunny, 25°C',
95
- state: { cached: true },
96
- });
97
- });
98
-
99
- it('should group assistant message with multiple tool results', async () => {
100
- // Create assistant message with multiple tools
101
- await serverDB.insert(messages).values({
102
- id: 'msg-1',
103
- userId,
104
- role: 'assistant',
105
- content: 'Checking weather and news',
106
- tools: [
107
- {
108
- id: 'tool-1',
109
- identifier: 'weather',
110
- apiName: 'getWeather',
111
- arguments: '{}',
112
- type: 'default',
113
- },
114
- {
115
- id: 'tool-2',
116
- identifier: 'news',
117
- apiName: 'getNews',
118
- arguments: '{}',
119
- type: 'default',
120
- },
121
- ],
122
- });
123
-
124
- // Create tool messages
125
- await serverDB.insert(messages).values([
126
- {
127
- id: 'msg-2',
128
- userId,
129
- role: 'tool',
130
- content: 'Beijing: Sunny, 25°C',
131
- },
132
- {
133
- id: 'msg-3',
134
- userId,
135
- role: 'tool',
136
- content: 'Latest tech news: AI breakthrough',
137
- },
138
- ]);
139
-
140
- await serverDB.insert(messagePlugins).values([
141
- {
142
- id: 'msg-2',
143
- userId,
144
- toolCallId: 'tool-1',
145
- identifier: 'weather',
146
- },
147
- {
148
- id: 'msg-3',
149
- userId,
150
- toolCallId: 'tool-2',
151
- identifier: 'news',
152
- },
153
- ]);
154
-
155
- // Query messages
156
- const result = await messageModel.query(
157
- { sessionId: null },
158
- { groupAssistantMessages: true },
159
- );
160
-
161
- // Verify grouping
162
- expect(result).toHaveLength(1);
163
- expect(result[0].role).toBe('group');
164
- expect(result[0].children).toHaveLength(1);
165
-
166
- const block = result[0].children![0];
167
- expect(block.tools).toHaveLength(2);
168
- expect(block.tools![0].result?.content).toBe('Beijing: Sunny, 25°C');
169
- expect(block.tools![1].result?.content).toBe('Latest tech news: AI breakthrough');
170
- });
171
-
172
- it('should not group assistant message without tools', async () => {
173
- // Create assistant message without tools
174
- await serverDB.insert(messages).values({
175
- id: 'msg-1',
176
- userId,
177
- role: 'assistant',
178
- content: 'Hello!',
179
- });
180
-
181
- // Query messages
182
- const result = await messageModel.query(
183
- { sessionId: null },
184
- { groupAssistantMessages: true },
185
- );
186
-
187
- // Verify no grouping
188
- expect(result).toHaveLength(1);
189
- expect(result[0].role).toBe('assistant');
190
- expect(result[0].content).toBe('Hello!');
191
- expect(result[0].children).toBeUndefined();
192
- });
193
-
194
- it('should handle assistant message with tool but no result yet', async () => {
195
- // Create assistant message with tool
196
- await serverDB.insert(messages).values({
197
- id: 'msg-1',
198
- userId,
199
- role: 'assistant',
200
- content: 'Checking weather',
201
- tools: [
202
- {
203
- id: 'tool-1',
204
- identifier: 'weather',
205
- apiName: 'getWeather',
206
- arguments: '{}',
207
- type: 'default',
208
- },
209
- ],
210
- });
211
-
212
- // No tool message created yet
213
-
214
- // Query messages
215
- const result = await messageModel.query(
216
- { sessionId: null },
217
- { groupAssistantMessages: true },
218
- );
219
-
220
- // Verify grouping without result
221
- expect(result).toHaveLength(1);
222
- expect(result[0].role).toBe('group');
223
- expect(result[0].children).toHaveLength(1);
224
-
225
- const block = result[0].children![0];
226
- expect(block.tools).toHaveLength(1);
227
- expect(block.tools![0].result).toBeUndefined();
228
- });
229
- });
230
-
231
- describe('Multi-turn Conversation Grouping', () => {
232
- it('should group assistant with follow-up assistant (parentId→tool)', async () => {
233
- // Scenario: assistant → tool → assistant (parentId → tool)
234
- await serverDB.insert(messages).values([
235
- {
236
- id: 'msg-1',
237
- userId,
238
- role: 'assistant',
239
- content: 'Let me check the weather',
240
- createdAt: new Date('2023-01-01T10:00:00Z'),
241
- tools: [
242
- {
243
- id: 'tool-1',
244
- identifier: 'weather',
245
- apiName: 'getWeather',
246
- arguments: '{}',
247
- type: 'default',
248
- },
249
- ],
250
- },
251
- {
252
- id: 'msg-2',
253
- userId,
254
- role: 'tool',
255
- content: 'Sunny, 25°C',
256
- createdAt: new Date('2023-01-01T10:00:01Z'),
257
- },
258
- {
259
- id: 'msg-3',
260
- userId,
261
- role: 'assistant',
262
- content: 'Based on the weather, let me check the news',
263
- parentId: 'msg-2',
264
- createdAt: new Date('2023-01-01T10:00:02Z'),
265
- tools: [
266
- {
267
- id: 'tool-2',
268
- identifier: 'news',
269
- apiName: 'getNews',
270
- arguments: '{}',
271
- type: 'default',
272
- },
273
- ],
274
- },
275
- {
276
- id: 'msg-4',
277
- userId,
278
- role: 'tool',
279
- content: 'Breaking: AI news',
280
- createdAt: new Date('2023-01-01T10:00:03Z'),
281
- },
282
- ]);
283
-
284
- await serverDB.insert(messagePlugins).values([
285
- {
286
- id: 'msg-2',
287
- userId,
288
- toolCallId: 'tool-1',
289
- identifier: 'weather',
290
- },
291
- {
292
- id: 'msg-4',
293
- userId,
294
- toolCallId: 'tool-2',
295
- identifier: 'news',
296
- },
297
- ]);
298
-
299
- // Query messages
300
- const result = await messageModel.query(
301
- { sessionId: null },
302
- { groupAssistantMessages: true },
303
- );
304
-
305
- // Should have 1 group with 2 children
306
- expect(result).toHaveLength(1);
307
- expect(result[0].role).toBe('group');
308
- expect(result[0].children).toHaveLength(2);
309
-
310
- // First child: original assistant with tool result
311
- expect(result[0].children![0].id).toBe('msg-1');
312
- expect(result[0].children![0].content).toBe('Let me check the weather');
313
- expect(result[0].children![0].tools).toHaveLength(1);
314
- expect(result[0].children![0].tools![0].result?.content).toBe('Sunny, 25°C');
315
-
316
- // Second child: follow-up assistant with its own tool result
317
- expect(result[0].children![1].id).toBe('msg-3');
318
- expect(result[0].children![1].content).toBe('Based on the weather, let me check the news');
319
- expect(result[0].children![1].tools).toHaveLength(1);
320
- expect(result[0].children![1].tools![0].result?.content).toBe('Breaking: AI news');
321
- });
322
-
323
- it('should group multiple follow-up assistants in chain (3+ assistants)', async () => {
324
- // Scenario: assistant → tool → assistant → tool → assistant (chain of parentId→tool)
325
- await serverDB.insert(messages).values([
326
- {
327
- id: 'msg-1',
328
- userId,
329
- role: 'assistant',
330
- content: 'Step 1: Check weather',
331
- createdAt: new Date('2023-01-01T10:00:00Z'),
332
- tools: [
333
- {
334
- id: 'tool-1',
335
- identifier: 'weather',
336
- apiName: 'getWeather',
337
- arguments: '{}',
338
- type: 'default',
339
- },
340
- ],
341
- },
342
- {
343
- id: 'msg-2',
344
- userId,
345
- role: 'tool',
346
- content: 'Sunny, 25°C',
347
- createdAt: new Date('2023-01-01T10:00:01Z'),
348
- },
349
- {
350
- id: 'msg-3',
351
- userId,
352
- role: 'assistant',
353
- content: 'Step 2: Based on weather, check news',
354
- parentId: 'msg-2',
355
- createdAt: new Date('2023-01-01T10:00:02Z'),
356
- tools: [
357
- {
358
- id: 'tool-2',
359
- identifier: 'news',
360
- apiName: 'getNews',
361
- arguments: '{}',
362
- type: 'default',
363
- },
364
- ],
365
- },
366
- {
367
- id: 'msg-4',
368
- userId,
369
- role: 'tool',
370
- content: 'Breaking: AI news',
371
- createdAt: new Date('2023-01-01T10:00:03Z'),
372
- },
373
- {
374
- id: 'msg-5',
375
- userId,
376
- role: 'assistant',
377
- content: 'Step 3: Final summary based on weather and news',
378
- parentId: 'msg-4',
379
- createdAt: new Date('2023-01-01T10:00:04Z'),
380
- },
381
- ]);
382
-
383
- await serverDB.insert(messagePlugins).values([
384
- {
385
- id: 'msg-2',
386
- userId,
387
- toolCallId: 'tool-1',
388
- identifier: 'weather',
389
- },
390
- {
391
- id: 'msg-4',
392
- userId,
393
- toolCallId: 'tool-2',
394
- identifier: 'news',
395
- },
396
- ]);
397
-
398
- // Query messages
399
- const result = await messageModel.query(
400
- { sessionId: null },
401
- { groupAssistantMessages: true },
402
- );
403
-
404
- // Should have 1 group with 3 children
405
- expect(result).toHaveLength(1);
406
- expect(result[0].role).toBe('group');
407
- expect(result[0].children).toHaveLength(3);
408
-
409
- // First child: original assistant with tool result
410
- expect(result[0].children![0].id).toBe('msg-1');
411
- expect(result[0].children![0].content).toBe('Step 1: Check weather');
412
- expect(result[0].children![0].tools![0].result?.content).toBe('Sunny, 25°C');
413
-
414
- // Second child: follow-up assistant with its own tool result
415
- expect(result[0].children![1].id).toBe('msg-3');
416
- expect(result[0].children![1].content).toBe('Step 2: Based on weather, check news');
417
- expect(result[0].children![1].tools![0].result?.content).toBe('Breaking: AI news');
418
-
419
- // Third child: final assistant (parentId pointed to second tool)
420
- expect(result[0].children![2].id).toBe('msg-5');
421
- expect(result[0].children![2].content).toBe(
422
- 'Step 3: Final summary based on weather and news',
423
- );
424
- });
425
-
426
- it('should group messages in multi-turn conversation', async () => {
427
- // Create multi-turn conversation
428
- await serverDB.insert(messages).values([
429
- {
430
- id: 'msg-1',
431
- userId,
432
- role: 'user',
433
- content: 'What is the weather?',
434
- createdAt: new Date('2023-01-01T10:00:00Z'),
435
- },
436
- {
437
- id: 'msg-2',
438
- userId,
439
- role: 'assistant',
440
- content: 'Checking weather',
441
- createdAt: new Date('2023-01-01T10:00:01Z'),
442
- tools: [
443
- {
444
- id: 'tool-1',
445
- identifier: 'weather',
446
- apiName: 'getWeather',
447
- arguments: '{}',
448
- type: 'default',
449
- },
450
- ],
451
- },
452
- {
453
- id: 'msg-3',
454
- userId,
455
- role: 'tool',
456
- content: 'Sunny, 25°C',
457
- createdAt: new Date('2023-01-01T10:00:02Z'),
458
- },
459
- {
460
- id: 'msg-4',
461
- userId,
462
- role: 'user',
463
- content: 'What about news?',
464
- createdAt: new Date('2023-01-01T10:00:03Z'),
465
- },
466
- {
467
- id: 'msg-5',
468
- userId,
469
- role: 'assistant',
470
- content: 'Checking news',
471
- createdAt: new Date('2023-01-01T10:00:04Z'),
472
- tools: [
473
- {
474
- id: 'tool-2',
475
- identifier: 'news',
476
- apiName: 'getNews',
477
- arguments: '{}',
478
- type: 'default',
479
- },
480
- ],
481
- },
482
- {
483
- id: 'msg-6',
484
- userId,
485
- role: 'tool',
486
- content: 'AI breakthrough',
487
- createdAt: new Date('2023-01-01T10:00:05Z'),
488
- },
489
- ]);
490
-
491
- await serverDB.insert(messagePlugins).values([
492
- {
493
- id: 'msg-3',
494
- userId,
495
- toolCallId: 'tool-1',
496
- identifier: 'weather',
497
- },
498
- {
499
- id: 'msg-6',
500
- userId,
501
- toolCallId: 'tool-2',
502
- identifier: 'news',
503
- },
504
- ]);
505
-
506
- // Query messages
507
- const result = await messageModel.query(
508
- { sessionId: null },
509
- { groupAssistantMessages: true },
510
- );
511
-
512
- // Verify grouping
513
- expect(result).toHaveLength(4); // 2 users + 2 grouped assistants
514
- expect(result[0].role).toBe('user');
515
- expect(result[1].role).toBe('group');
516
- expect(result[2].role).toBe('user');
517
- expect(result[3].role).toBe('group');
518
- });
519
-
520
- it('should handle mixed grouped and non-grouped messages', async () => {
521
- // Create mixed messages
522
- await serverDB.insert(messages).values([
523
- {
524
- id: 'msg-1',
525
- userId,
526
- role: 'assistant',
527
- content: 'Hello!',
528
- createdAt: new Date('2023-01-01T10:00:00Z'),
529
- },
530
- {
531
- id: 'msg-2',
532
- userId,
533
- role: 'assistant',
534
- content: 'Using tools',
535
- createdAt: new Date('2023-01-01T10:00:01Z'),
536
- tools: [
537
- {
538
- id: 'tool-1',
539
- identifier: 'test',
540
- apiName: 'test',
541
- arguments: '{}',
542
- type: 'default',
543
- },
544
- ],
545
- },
546
- {
547
- id: 'msg-3',
548
- userId,
549
- role: 'tool',
550
- content: 'Result',
551
- createdAt: new Date('2023-01-01T10:00:02Z'),
552
- },
553
- ]);
554
-
555
- await serverDB.insert(messagePlugins).values({
556
- id: 'msg-3',
557
- userId,
558
- toolCallId: 'tool-1',
559
- identifier: 'test',
560
- });
561
-
562
- // Query messages
563
- const result = await messageModel.query(
564
- { sessionId: null },
565
- { groupAssistantMessages: true },
566
- );
567
-
568
- // Verify grouping
569
- expect(result).toHaveLength(2);
570
- expect(result[0].role).toBe('assistant');
571
- expect(result[0].children).toBeUndefined();
572
- expect(result[1].role).toBe('group');
573
- expect(result[1].children).toHaveLength(1);
574
- });
575
- });
576
-
577
- describe('Edge Cases', () => {
578
- it('should handle tool messages with errors', async () => {
579
- // Create assistant with tool
580
- await serverDB.insert(messages).values({
581
- id: 'msg-1',
582
- userId,
583
- role: 'assistant',
584
- content: 'Checking',
585
- tools: [
586
- {
587
- id: 'tool-1',
588
- identifier: 'test',
589
- apiName: 'test',
590
- arguments: '{}',
591
- type: 'default',
592
- },
593
- ],
594
- });
595
-
596
- // Create tool message with error
597
- await serverDB.insert(messages).values({
598
- id: 'msg-2',
599
- userId,
600
- role: 'tool',
601
- content: '',
602
- });
603
-
604
- await serverDB.insert(messagePlugins).values({
605
- id: 'msg-2',
606
- userId,
607
- toolCallId: 'tool-1',
608
- identifier: 'test',
609
- error: { message: 'Failed to execute' },
610
- });
611
-
612
- // Query messages
613
- const result = await messageModel.query(
614
- { sessionId: null },
615
- { groupAssistantMessages: true },
616
- );
617
-
618
- // Verify error is preserved
619
- expect(result).toHaveLength(1);
620
- expect(result[0].role).toBe('group');
621
- expect(result[0].children![0].tools![0].result?.error).toEqual({
622
- message: 'Failed to execute',
623
- });
624
- });
625
-
626
- it('should preserve message order', async () => {
627
- // Create messages in specific order
628
- await serverDB.insert(messages).values([
629
- {
630
- id: 'msg-1',
631
- userId,
632
- role: 'user',
633
- content: 'First',
634
- createdAt: new Date('2023-01-01T10:00:00Z'),
635
- },
636
- {
637
- id: 'msg-2',
638
- userId,
639
- role: 'assistant',
640
- content: 'Second',
641
- createdAt: new Date('2023-01-01T10:00:01Z'),
642
- },
643
- {
644
- id: 'msg-3',
645
- userId,
646
- role: 'user',
647
- content: 'Third',
648
- createdAt: new Date('2023-01-01T10:00:02Z'),
649
- },
650
- ]);
651
-
652
- // Query messages
653
- const result = await messageModel.query(
654
- { sessionId: null },
655
- { groupAssistantMessages: true },
656
- );
657
-
658
- // Verify order
659
- expect(result).toHaveLength(3);
660
- expect(result[0].content).toBe('First');
661
- expect(result[1].content).toBe('Second');
662
- expect(result[2].content).toBe('Third');
663
- });
664
-
665
- it('should handle orphaned tool messages', async () => {
666
- // Create orphaned tool message
667
- await serverDB.insert(messages).values({
668
- id: 'msg-1',
669
- userId,
670
- role: 'tool',
671
- content: 'Orphaned result',
672
- });
673
-
674
- await serverDB.insert(messagePlugins).values({
675
- id: 'msg-1',
676
- userId,
677
- toolCallId: 'unknown-tool',
678
- identifier: 'test',
679
- });
680
-
681
- // Query messages
682
- const result = await messageModel.query(
683
- { sessionId: null },
684
- { groupAssistantMessages: true },
685
- );
686
-
687
- // Verify orphaned tool is not filtered
688
- expect(result).toHaveLength(1);
689
- expect(result[0].role).toBe('tool');
690
- });
691
- });
692
-
693
- describe('Children Structure Validation', () => {
694
- it('should use message ID as block ID', async () => {
695
- // Create assistant with tool
696
- await serverDB.insert(messages).values({
697
- id: 'msg-1',
698
- userId,
699
- role: 'assistant',
700
- content: 'Test',
701
- tools: [
702
- {
703
- id: 'tool-1',
704
- identifier: 'test',
705
- apiName: 'test',
706
- arguments: '{}',
707
- type: 'default',
708
- },
709
- ],
710
- });
711
-
712
- // Query messages
713
- const result = await messageModel.query(
714
- { sessionId: null },
715
- { groupAssistantMessages: true },
716
- );
717
-
718
- // Verify block ID uses message ID
719
- expect(result[0].children![0].id).toBe('msg-1');
720
- });
721
-
722
- it('should convert empty imageList/fileList to undefined in children', async () => {
723
- // Create assistant with tools but empty imageList/fileList
724
- await serverDB.insert(messages).values({
725
- id: 'msg-1',
726
- userId,
727
- role: 'assistant',
728
- content: 'Test',
729
- tools: [
730
- {
731
- id: 'tool-1',
732
- identifier: 'test',
733
- apiName: 'test',
734
- arguments: '{}',
735
- type: 'default',
736
- },
737
- ],
738
- });
739
-
740
- // Query messages (no files attached, so imageList/fileList will be empty)
741
- const result = await messageModel.query(
742
- { sessionId: null },
743
- { groupAssistantMessages: true },
744
- );
745
-
746
- // Verify empty arrays become undefined
747
- expect(result[0].children![0].imageList).toBeUndefined();
748
- });
749
-
750
- it('should move tools/imageList/fileList to children', async () => {
751
- // Create files
752
- await serverDB.insert(files).values([
753
- {
754
- id: 'img-1',
755
- userId,
756
- name: 'test.png',
757
- fileType: 'image/png',
758
- size: 1024,
759
- url: 'http://example.com/img.png',
760
- },
761
- {
762
- id: 'file-1',
763
- userId,
764
- name: 'test.pdf',
765
- fileType: 'application/pdf',
766
- size: 2048,
767
- url: 'http://example.com/file.pdf',
768
- },
769
- ]);
770
-
771
- // Create assistant with tools and files
772
- await serverDB.insert(messages).values({
773
- id: 'msg-1',
774
- userId,
775
- role: 'assistant',
776
- content: 'Test',
777
- tools: [
778
- {
779
- id: 'tool-1',
780
- identifier: 'test',
781
- apiName: 'test',
782
- arguments: '{}',
783
- type: 'default',
784
- },
785
- ],
786
- });
787
-
788
- await serverDB.insert(messagesFiles).values([
789
- { messageId: 'msg-1', fileId: 'img-1', userId },
790
- { messageId: 'msg-1', fileId: 'file-1', userId },
791
- ]);
792
-
793
- // Query messages
794
- const result = await messageModel.query(
795
- { sessionId: null },
796
- { groupAssistantMessages: true },
797
- );
798
-
799
- // Verify parent fields are cleared
800
- expect(result[0].tools).toBeUndefined();
801
- expect(result[0].imageList).toBeUndefined();
802
- expect(result[0].fileList).toBeUndefined();
803
- expect(result[0].content).toBe('');
804
-
805
- // Verify children have the data
806
- const block = result[0].children![0];
807
- expect(block.content).toBe('Test');
808
- expect(block.tools).toHaveLength(1);
809
- expect(block.imageList).toHaveLength(1);
810
- });
811
- });
812
- });