@lobehub/lobehub 2.0.0-next.72 → 2.0.0-next.73

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 (337) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/next.config.ts +5 -5
  4. package/package.json +1 -1
  5. package/scripts/prebuild.mts +1 -1
  6. package/src/app/(backend)/trpc/desktop/[trpc]/route.ts +6 -6
  7. package/src/app/[variants]/(main)/(mobile)/me/(home)/__tests__/UserBanner.test.tsx +7 -4
  8. package/src/app/[variants]/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx +4 -4
  9. package/src/app/[variants]/(main)/(mobile)/me/(home)/features/UserBanner.tsx +5 -6
  10. package/src/app/[variants]/(main)/(mobile)/me/(home)/features/useCategory.tsx +5 -8
  11. package/src/app/[variants]/(main)/(mobile)/me/(home)/index.tsx +25 -0
  12. package/src/app/[variants]/(main)/(mobile)/me/(home)/layout.tsx +13 -16
  13. package/src/app/[variants]/(main)/(mobile)/me/profile/features/Category.tsx +6 -6
  14. package/src/app/[variants]/(main)/(mobile)/me/profile/features/Header.tsx +3 -3
  15. package/src/app/[variants]/(main)/(mobile)/me/profile/index.tsx +16 -0
  16. package/src/app/[variants]/(main)/(mobile)/me/profile/layout.tsx +9 -11
  17. package/src/app/[variants]/(main)/(mobile)/me/settings/features/Header.tsx +3 -3
  18. package/src/app/[variants]/(main)/(mobile)/me/settings/features/useCategory.tsx +3 -4
  19. package/src/app/[variants]/(main)/(mobile)/me/settings/index.tsx +16 -0
  20. package/src/app/[variants]/(main)/(mobile)/me/settings/layout.tsx +15 -13
  21. package/src/app/[variants]/(main)/changelog/_layout/Desktop/index.tsx +6 -5
  22. package/src/app/[variants]/(main)/changelog/_layout/Mobile/Header.tsx +3 -3
  23. package/src/app/[variants]/(main)/changelog/_layout/Mobile/index.tsx +5 -5
  24. package/src/app/[variants]/(main)/changelog/features/Post.tsx +7 -4
  25. package/src/app/[variants]/(main)/changelog/index.tsx +55 -0
  26. package/src/app/[variants]/(main)/chat/_layout/Desktop/index.tsx +6 -7
  27. package/src/app/[variants]/(main)/chat/_layout/Mobile.tsx +3 -3
  28. package/src/app/[variants]/(main)/chat/components/WorkspaceLayout.tsx +1 -14
  29. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatHydration/index.tsx +2 -2
  30. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/Desktop/MessageFromUrl.tsx +11 -13
  31. package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/Desktop/index.tsx +0 -1
  32. package/src/app/[variants]/(main)/chat/components/conversation/features/ThreadHydration.tsx +2 -2
  33. package/src/app/[variants]/(main)/chat/components/topic/features/Topic/TopicListContent/TopicItem/TopicContent.tsx +20 -11
  34. package/src/app/[variants]/(main)/chat/features/PageTitle/index.tsx +1 -2
  35. package/src/app/[variants]/(main)/chat/index.tsx +29 -0
  36. package/src/app/[variants]/(main)/chat/session/features/SessionHydration.tsx +8 -6
  37. package/src/app/[variants]/(main)/chat/session/features/SessionListContent/Inbox/index.tsx +2 -4
  38. package/src/app/[variants]/(main)/chat/session/features/SessionListContent/List/index.tsx +1 -1
  39. package/src/app/[variants]/(main)/chat/session/layout/Mobile/SessionHeader.tsx +3 -3
  40. package/src/app/[variants]/(main)/chat/settings/_layout/Desktop/Header.tsx +3 -3
  41. package/src/app/[variants]/(main)/chat/settings/_layout/Mobile/Header.tsx +3 -3
  42. package/src/app/[variants]/(main)/chat/settings/features/PublishResultModal/index.tsx +3 -3
  43. package/src/app/[variants]/(main)/chat/{components/SettingsPage.tsx → settings/index.tsx} +6 -35
  44. package/src/app/[variants]/(main)/components/Link.tsx +21 -0
  45. package/src/app/[variants]/(main)/discover/(detail)/_layout/{Desktop.tsx → Desktop/index.tsx} +15 -7
  46. package/src/app/[variants]/(main)/discover/(detail)/_layout/Mobile/index.tsx +3 -3
  47. package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/Capabilities/Block.tsx +1 -1
  48. package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/Overview/index.tsx +1 -1
  49. package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/Related/index.tsx +2 -2
  50. package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/SystemRole/index.tsx +3 -3
  51. package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/Versions/index.tsx +4 -4
  52. package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/index.tsx +1 -1
  53. package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Header.tsx +2 -2
  54. package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Sidebar/ActionButton/AddAgent.tsx +3 -3
  55. package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Sidebar/ActionButton/index.tsx +1 -1
  56. package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Sidebar/Related/index.tsx +1 -1
  57. package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Sidebar/TocList/index.tsx +2 -2
  58. package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/StatusPage/index.tsx +3 -3
  59. package/src/app/[variants]/(main)/discover/(detail)/assistant/{AssistantDetailPage.tsx → index.tsx} +18 -11
  60. package/src/app/[variants]/(main)/discover/(detail)/features/Breadcrumb.tsx +1 -1
  61. package/src/app/[variants]/(main)/discover/(detail)/mcp/{[slug]/features → features}/Details/Related/index.tsx +2 -2
  62. package/src/app/[variants]/(main)/discover/(detail)/mcp/{[slug]/features → features}/Details/Versions/index.tsx +5 -5
  63. package/src/app/[variants]/(main)/discover/(detail)/mcp/{[slug]/features → features}/Details/index.tsx +1 -1
  64. package/src/app/[variants]/(main)/discover/(detail)/mcp/{[slug]/features → features}/Sidebar/Related/index.tsx +2 -2
  65. package/src/app/[variants]/(main)/discover/(detail)/mcp/{[slug]/features → features}/Sidebar/ServerConfig.tsx +4 -4
  66. package/src/app/[variants]/(main)/discover/(detail)/mcp/{[slug]/features → features}/Sidebar/TocList/index.tsx +2 -2
  67. package/src/app/[variants]/(main)/discover/(detail)/mcp/{McpDetailPage.tsx → index.tsx} +15 -7
  68. package/src/app/[variants]/(main)/discover/(detail)/mcp/loading.tsx +1 -0
  69. package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Details/Overview/index.tsx +1 -1
  70. package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Details/Parameter/ParameterItem.tsx +1 -1
  71. package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Details/Related/index.tsx +2 -2
  72. package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Details/index.tsx +1 -1
  73. package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Header.tsx +1 -1
  74. package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Sidebar/ActionButton/ChatWithModel.tsx +3 -3
  75. package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Sidebar/ActionButton/index.tsx +1 -1
  76. package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Sidebar/Related/index.tsx +2 -2
  77. package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Sidebar/RelatedProviders/index.tsx +1 -1
  78. package/src/app/[variants]/(main)/discover/(detail)/model/{ModelDetailPage.tsx → index.tsx} +17 -10
  79. package/src/app/[variants]/(main)/discover/(detail)/model/loading.tsx +1 -0
  80. package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Details/Related/index.tsx +2 -2
  81. package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Details/index.tsx +1 -1
  82. package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Sidebar/ActionButton/ProviderConfig.tsx +5 -4
  83. package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Sidebar/ActionButton/index.tsx +1 -1
  84. package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Sidebar/Related/index.tsx +2 -2
  85. package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Sidebar/RelatedModels/index.tsx +1 -1
  86. package/src/app/[variants]/(main)/discover/(detail)/provider/{ProviderDetailPage.tsx → index.tsx} +17 -10
  87. package/src/app/[variants]/(main)/discover/(detail)/provider/loading.tsx +1 -0
  88. package/src/app/[variants]/(main)/discover/(list)/(home)/{HomePage.tsx → index.tsx} +14 -0
  89. package/src/app/[variants]/(main)/discover/(list)/_layout/Desktop/Nav.tsx +2 -3
  90. package/src/app/[variants]/(main)/discover/(list)/_layout/Desktop/index.tsx +4 -3
  91. package/src/app/[variants]/(main)/discover/(list)/_layout/Mobile/Nav.tsx +3 -4
  92. package/src/app/[variants]/(main)/discover/(list)/_layout/Mobile/index.tsx +4 -3
  93. package/src/app/[variants]/(main)/discover/(list)/assistant/_layout/Desktop.tsx +3 -4
  94. package/src/app/[variants]/(main)/discover/(list)/assistant/_layout/Mobile.tsx +3 -3
  95. package/src/app/[variants]/(main)/discover/(list)/assistant/features/List/Item.tsx +2 -2
  96. package/src/app/[variants]/(main)/discover/(list)/assistant/{AssistantPage.tsx → index.tsx} +18 -4
  97. package/src/app/[variants]/(main)/discover/(list)/features/SortButton/index.tsx +2 -2
  98. package/src/app/[variants]/(main)/discover/(list)/mcp/_layout/Desktop.tsx +3 -3
  99. package/src/app/[variants]/(main)/discover/(list)/mcp/_layout/Mobile.tsx +3 -3
  100. package/src/app/[variants]/(main)/discover/(list)/mcp/features/List/Item.tsx +1 -1
  101. package/src/app/[variants]/(main)/discover/(list)/mcp/{McpPage.tsx → index.tsx} +9 -2
  102. package/src/app/[variants]/(main)/discover/(list)/model/_layout/Desktop.tsx +3 -3
  103. package/src/app/[variants]/(main)/discover/(list)/model/_layout/Mobile.tsx +3 -3
  104. package/src/app/[variants]/(main)/discover/(list)/model/features/List/Item.tsx +1 -1
  105. package/src/app/[variants]/(main)/discover/(list)/model/{ModelPage.tsx → index.tsx} +9 -2
  106. package/src/app/[variants]/(main)/discover/(list)/provider/features/List/Item.tsx +1 -1
  107. package/src/app/[variants]/(main)/discover/(list)/provider/{Client.tsx → index.tsx} +9 -2
  108. package/src/app/[variants]/(main)/discover/_layout/Desktop/index.tsx +4 -4
  109. package/src/app/[variants]/(main)/discover/_layout/Mobile/index.tsx +3 -3
  110. package/src/app/[variants]/(main)/discover/components/Title.tsx +1 -1
  111. package/src/app/[variants]/(main)/discover/features/Search.tsx +2 -2
  112. package/src/app/[variants]/(main)/discover/features/useNav.tsx +11 -12
  113. package/src/app/[variants]/(main)/hooks/useActiveTabKey.ts +40 -0
  114. package/src/app/[variants]/(main)/hooks/usePathname.ts +10 -0
  115. package/src/app/[variants]/(main)/hooks/useQuery.ts +12 -0
  116. package/src/app/[variants]/(main)/hooks/useRouter.ts +22 -0
  117. package/src/app/[variants]/(main)/hooks/useSearchParams.ts +11 -0
  118. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/ModelSelect/index.tsx +5 -5
  119. package/src/app/[variants]/(main)/image/@topic/features/Topics/TopicUrlSync.tsx +1 -1
  120. package/src/app/[variants]/(main)/image/ComingSoon.tsx +15 -0
  121. package/src/app/[variants]/(main)/image/_layout/Desktop/index.tsx +5 -2
  122. package/src/app/[variants]/(main)/image/_layout/DesktopWrapper.tsx +15 -0
  123. package/src/app/[variants]/(main)/image/_layout/Mobile/index.tsx +3 -1
  124. package/src/app/[variants]/(main)/image/features/ImageWorkspace/index.tsx +1 -2
  125. package/src/app/[variants]/(main)/image/index.tsx +18 -0
  126. package/src/app/[variants]/(main)/knowledge/_layout/Desktop.tsx +17 -0
  127. package/src/app/[variants]/(main)/knowledge/_layout/Mobile.tsx +17 -0
  128. package/src/app/[variants]/(main)/knowledge/components/KnowledgeBaseItem/index.tsx +1 -1
  129. package/src/app/[variants]/(main)/knowledge/components/modal/ModalPageClient.tsx +4 -4
  130. package/src/app/[variants]/(main)/knowledge/routes/KnowledgeBaseDetail/index.tsx +5 -8
  131. package/src/app/[variants]/(main)/knowledge/routes/KnowledgeBaseDetail/menu/Head.tsx +1 -1
  132. package/src/app/[variants]/(main)/knowledge/routes/KnowledgeHome/menu/CategoryMenu.tsx +2 -2
  133. package/src/app/[variants]/(main)/knowledge/routes/KnowledgeHome/menu/KnowledgeBase.tsx +1 -1
  134. package/src/app/[variants]/(main)/{_layout/Desktop → layouts/desktop}/DesktopLayoutContainer.tsx +3 -2
  135. package/src/app/[variants]/(main)/{_layout/Desktop → layouts/desktop}/SideBar/BottomActions.tsx +4 -4
  136. package/src/app/[variants]/(main)/{_layout/Desktop → layouts/desktop}/SideBar/TopActions.test.tsx +9 -9
  137. package/src/app/[variants]/(main)/layouts/desktop/SideBar/TopActions.tsx +117 -0
  138. package/src/app/[variants]/(main)/{_layout/Desktop → layouts/desktop}/index.tsx +9 -4
  139. package/src/app/[variants]/(main)/layouts/index.tsx +11 -0
  140. package/src/app/[variants]/(main)/{_layout/Mobile → layouts/mobile}/NavBar.tsx +5 -5
  141. package/src/app/[variants]/(main)/{_layout/Mobile → layouts/mobile}/index.tsx +10 -7
  142. package/src/app/[variants]/(main)/profile/(home)/desktop.tsx +26 -0
  143. package/src/app/[variants]/(main)/profile/(home)/index.tsx +26 -0
  144. package/src/app/[variants]/(main)/profile/@category/features/CategoryContent.tsx +5 -7
  145. package/src/app/[variants]/(main)/profile/_layout/Desktop/index.tsx +3 -2
  146. package/src/app/[variants]/(main)/profile/_layout/DesktopWrapper.tsx +14 -0
  147. package/src/app/[variants]/(main)/profile/_layout/Mobile/Header.tsx +3 -3
  148. package/src/app/[variants]/(main)/profile/_layout/Mobile/index.tsx +4 -3
  149. package/src/app/[variants]/(main)/profile/apikey/index.tsx +18 -0
  150. package/src/app/[variants]/(main)/profile/hooks/useCategory.tsx +6 -6
  151. package/src/app/[variants]/(main)/profile/security/index.tsx +29 -0
  152. package/src/app/[variants]/(main)/profile/stats/features/AssistantsRank.tsx +4 -4
  153. package/src/app/[variants]/(main)/profile/stats/features/TopicsRank.tsx +4 -4
  154. package/src/app/[variants]/(main)/profile/stats/index.tsx +20 -0
  155. package/src/app/[variants]/(main)/profile/usage/features/UsageTable.tsx +7 -9
  156. package/src/app/[variants]/(main)/profile/usage/index.tsx +13 -0
  157. package/src/app/[variants]/(main)/settings/_layout/Desktop/Header.tsx +2 -2
  158. package/src/app/[variants]/(main)/settings/_layout/Desktop/index.tsx +2 -2
  159. package/src/app/[variants]/(main)/settings/_layout/DesktopWrapper.tsx +23 -0
  160. package/src/app/[variants]/(main)/settings/_layout/Mobile/Header.tsx +8 -7
  161. package/src/app/[variants]/(main)/settings/_layout/Mobile/index.tsx +2 -5
  162. package/src/app/[variants]/(main)/settings/_layout/MobileWrapper.tsx +23 -0
  163. package/src/app/[variants]/(main)/settings/agent/AgentMenu/Menu.tsx +2 -4
  164. package/src/app/[variants]/(main)/settings/agent/index.tsx +2 -4
  165. package/src/app/[variants]/(main)/settings/provider/(list)/index.tsx +2 -3
  166. package/src/app/[variants]/(main)/settings/provider/ProviderMenu/All.tsx +2 -2
  167. package/src/app/[variants]/(main)/settings/provider/ProviderMenu/Item.tsx +38 -37
  168. package/src/app/[variants]/(main)/settings/provider/_layout/Mobile.tsx +2 -2
  169. package/src/app/[variants]/(main)/settings/provider/features/CreateNewProvider/index.tsx +3 -3
  170. package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/UpdateProviderInfo/SettingModal.tsx +3 -3
  171. package/src/app/[variants]/DesktopRouter.tsx +40 -0
  172. package/src/app/[variants]/MobileRouter.tsx +41 -0
  173. package/src/app/[variants]/desktopRouter.config.tsx +381 -0
  174. package/src/app/[variants]/layout.tsx +1 -3
  175. package/src/app/[variants]/loaders/routeParams.ts +45 -0
  176. package/src/app/[variants]/loading/Server/Redirect.tsx +1 -1
  177. package/src/app/[variants]/mobileRouter.config.tsx +412 -0
  178. package/src/app/[variants]/page.tsx +16 -6
  179. package/src/app/desktop/devtools/page.tsx +1 -1
  180. package/src/app/desktop/layout.tsx +1 -1
  181. package/src/components/BootErrorBoundary/index.tsx +129 -0
  182. package/src/components/mdx/constants.ts +1 -0
  183. package/src/features/ChangelogModal/index.tsx +3 -3
  184. package/src/features/KnowledgeManager/FileExplorer/index.tsx +4 -4
  185. package/src/features/KnowledgeManager/Header/FilesSearchBar.tsx +1 -1
  186. package/src/features/User/UserPanel/PanelContent.tsx +4 -3
  187. package/src/features/User/UserPanel/useMenu.tsx +20 -14
  188. package/src/features/User/__tests__/PanelContent.test.tsx +13 -7
  189. package/src/hooks/useDiscoverTab.ts +2 -2
  190. package/src/hooks/useInterceptingRoutes.test.ts +23 -26
  191. package/src/hooks/useInterceptingRoutes.ts +5 -4
  192. package/src/hooks/usePinnedAgentState.ts +6 -6
  193. package/src/hooks/useQuery.ts +5 -0
  194. package/src/hooks/useQueryParam.ts +322 -0
  195. package/src/hooks/useQueryRoute.test.ts +2 -12
  196. package/src/hooks/useQueryRoute.ts +5 -5
  197. package/src/hooks/useShowMobileWorkspace.ts +1 -1
  198. package/src/hooks/useSwitchSession.ts +4 -3
  199. package/src/layout/GlobalProvider/ImportSettings.tsx +22 -9
  200. package/src/layout/GlobalProvider/StoreInitialization.tsx +9 -1
  201. package/src/proxy.ts +13 -1
  202. package/src/services/message/index.ts +11 -2
  203. package/src/store/chat/agents/createAgentExecutors.ts +31 -16
  204. package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +218 -0
  205. package/src/store/chat/slices/aiChat/actions/conversationControl.ts +4 -0
  206. package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +9 -3
  207. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +142 -61
  208. package/src/store/chat/slices/builtinTool/actions/__tests__/search.test.ts +204 -10
  209. package/src/store/chat/slices/builtinTool/actions/search.ts +51 -26
  210. package/src/store/chat/slices/message/action.test.ts +182 -33
  211. package/src/store/chat/slices/message/actions/optimisticUpdate.ts +79 -36
  212. package/src/store/chat/slices/message/actions/query.ts +7 -5
  213. package/src/store/chat/slices/message/selectors/dbMessage.ts +11 -4
  214. package/src/store/chat/slices/plugin/action.test.ts +257 -54
  215. package/src/store/chat/slices/plugin/actions/optimisticUpdate.ts +63 -26
  216. package/src/store/chat/slices/plugin/actions/pluginTypes.ts +52 -19
  217. package/src/store/chat/slices/plugin/actions/publicApi.ts +6 -1
  218. package/src/store/chat/slices/plugin/actions/workflow.ts +17 -6
  219. package/src/store/chat/slices/thread/action.ts +2 -0
  220. package/src/store/global/action.test.ts +3 -3
  221. package/src/store/global/actions/workspacePane.ts +2 -1
  222. package/src/store/global/initialState.ts +10 -2
  223. package/src/store/user/slices/common/action.ts +4 -0
  224. package/src/app/[variants]/(main)/(mobile)/me/(home)/loading.tsx +0 -38
  225. package/src/app/[variants]/(main)/(mobile)/me/(home)/page.tsx +0 -40
  226. package/src/app/[variants]/(main)/(mobile)/me/profile/loading.tsx +0 -5
  227. package/src/app/[variants]/(main)/(mobile)/me/profile/page.tsx +0 -30
  228. package/src/app/[variants]/(main)/(mobile)/me/settings/loading.tsx +0 -5
  229. package/src/app/[variants]/(main)/(mobile)/me/settings/page.tsx +0 -30
  230. package/src/app/[variants]/(main)/_layout/Desktop/SideBar/TopActions.tsx +0 -106
  231. package/src/app/[variants]/(main)/changelog/layout.tsx +0 -10
  232. package/src/app/[variants]/(main)/changelog/modal/page.tsx +0 -23
  233. package/src/app/[variants]/(main)/changelog/page.tsx +0 -78
  234. package/src/app/[variants]/(main)/chat/ChatRouter.tsx +0 -83
  235. package/src/app/[variants]/(main)/chat/_layout/ChatLayout.tsx +0 -22
  236. package/src/app/[variants]/(main)/chat/components/MainChatPage.tsx +0 -25
  237. package/src/app/[variants]/(main)/chat/error.tsx +0 -3
  238. package/src/app/[variants]/(main)/chat/layout.tsx +0 -10
  239. package/src/app/[variants]/(main)/chat/loading.tsx +0 -3
  240. package/src/app/[variants]/(main)/chat/not-found.tsx +0 -1
  241. package/src/app/[variants]/(main)/chat/page.tsx +0 -12
  242. package/src/app/[variants]/(main)/chat/settings/error.tsx +0 -3
  243. package/src/app/[variants]/(main)/chat/settings/loading.tsx +0 -3
  244. package/src/app/[variants]/(main)/chat/settings/not-found.tsx +0 -1
  245. package/src/app/[variants]/(main)/discover/(detail)/_layout/DetailLayout.tsx +0 -22
  246. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/Client.tsx +0 -51
  247. package/src/app/[variants]/(main)/discover/(detail)/mcp/[slug]/Client.tsx +0 -43
  248. package/src/app/[variants]/(main)/discover/(detail)/mcp/[slug]/loading.tsx +0 -1
  249. package/src/app/[variants]/(main)/discover/(detail)/model/[...slugs]/Client.tsx +0 -40
  250. package/src/app/[variants]/(main)/discover/(detail)/model/[...slugs]/loading.tsx +0 -1
  251. package/src/app/[variants]/(main)/discover/(detail)/provider/[...slugs]/Client.tsx +0 -40
  252. package/src/app/[variants]/(main)/discover/(detail)/provider/[...slugs]/loading.tsx +0 -1
  253. package/src/app/[variants]/(main)/discover/(list)/_layout/ListLayout.tsx +0 -22
  254. package/src/app/[variants]/(main)/discover/(list)/assistant/AssistantLayout.tsx +0 -21
  255. package/src/app/[variants]/(main)/discover/(list)/mcp/Client.tsx +0 -44
  256. package/src/app/[variants]/(main)/discover/(list)/mcp/McpLayout.tsx +0 -21
  257. package/src/app/[variants]/(main)/discover/(list)/model/Client.tsx +0 -44
  258. package/src/app/[variants]/(main)/discover/(list)/model/ModelLayout.tsx +0 -21
  259. package/src/app/[variants]/(main)/discover/(list)/provider/ProviderPage.tsx +0 -43
  260. package/src/app/[variants]/(main)/discover/DiscoverRouter.tsx +0 -170
  261. package/src/app/[variants]/(main)/discover/[[...path]]/page.tsx +0 -12
  262. package/src/app/[variants]/(main)/discover/_layout/DiscoverLayout.tsx +0 -22
  263. package/src/app/[variants]/(main)/discover/error.tsx +0 -3
  264. package/src/app/[variants]/(main)/discover/not-found.tsx +0 -1
  265. package/src/app/[variants]/(main)/error.tsx +0 -3
  266. package/src/app/[variants]/(main)/image/layout.tsx +0 -15
  267. package/src/app/[variants]/(main)/image/page.tsx +0 -45
  268. package/src/app/[variants]/(main)/knowledge/KnowledgeRouter.tsx +0 -74
  269. package/src/app/[variants]/(main)/knowledge/[[...path]]/page.tsx +0 -12
  270. package/src/app/[variants]/(main)/knowledge/components/modal/page.tsx +0 -13
  271. package/src/app/[variants]/(main)/knowledge/layout.tsx +0 -12
  272. package/src/app/[variants]/(main)/layout.tsx +0 -10
  273. package/src/app/[variants]/(main)/not-found.tsx +0 -1
  274. package/src/app/[variants]/(main)/profile/apikey/page.tsx +0 -32
  275. package/src/app/[variants]/(main)/profile/error.tsx +0 -3
  276. package/src/app/[variants]/(main)/profile/layout.tsx +0 -11
  277. package/src/app/[variants]/(main)/profile/loading.tsx +0 -3
  278. package/src/app/[variants]/(main)/profile/not-found.tsx +0 -1
  279. package/src/app/[variants]/(main)/profile/security/page.tsx +0 -28
  280. package/src/app/[variants]/(main)/profile/stats/page.tsx +0 -23
  281. package/src/app/[variants]/(main)/profile/usage/page.tsx +0 -23
  282. package/src/app/[variants]/@modal/(.)changelog/modal/features/Cover.tsx +0 -48
  283. package/src/app/[variants]/@modal/(.)changelog/modal/features/Hero.tsx +0 -29
  284. package/src/app/[variants]/@modal/(.)changelog/modal/features/Post.tsx +0 -57
  285. package/src/app/[variants]/@modal/(.)changelog/modal/features/PublishedTime.tsx +0 -50
  286. package/src/app/[variants]/@modal/(.)changelog/modal/features/ReadDetail.tsx +0 -72
  287. package/src/app/[variants]/@modal/(.)changelog/modal/features/VersionTag.tsx +0 -26
  288. package/src/app/[variants]/@modal/(.)changelog/modal/layout.tsx +0 -41
  289. package/src/app/[variants]/@modal/(.)changelog/modal/loading.tsx +0 -10
  290. package/src/app/[variants]/@modal/(.)changelog/modal/page.tsx +0 -38
  291. package/src/app/[variants]/@modal/_layout/ModalLayout.tsx +0 -63
  292. package/src/app/[variants]/@modal/_layout/SettingModalLayout.tsx +0 -71
  293. package/src/app/[variants]/@modal/default.tsx +0 -3
  294. package/src/app/[variants]/@modal/error.tsx +0 -3
  295. package/src/app/[variants]/@modal/layout.tsx +0 -7
  296. package/src/app/[variants]/@modal/loading.tsx +0 -5
  297. /package/src/app/[variants]/{@modal/(.)changelog/modal → (main)/changelog}/features/Pagination.tsx +0 -0
  298. /package/src/app/[variants]/{@modal/(.)changelog/modal → (main)/changelog}/features/UpdateChangelogStatus.tsx +0 -0
  299. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/DetailProvider.tsx +0 -0
  300. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/Capabilities/Knowledge.tsx +0 -0
  301. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/Capabilities/KnowledgeItem.tsx +0 -0
  302. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/Capabilities/PluginItem.tsx +0 -0
  303. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/Capabilities/Plugins.tsx +0 -0
  304. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/Capabilities/index.tsx +0 -0
  305. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/Nav.tsx +0 -0
  306. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/Overview/TagList.tsx +0 -0
  307. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Details/SystemRole/TagList.tsx +0 -0
  308. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Sidebar/Related/Item.tsx +0 -0
  309. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Sidebar/Summary/index.tsx +0 -0
  310. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/features → features}/Sidebar/index.tsx +0 -0
  311. /package/src/app/[variants]/(main)/discover/(detail)/assistant/{[...slugs]/loading.tsx → loading.tsx} +0 -0
  312. /package/src/app/[variants]/(main)/discover/(detail)/mcp/{[slug]/features → features}/Sidebar/ActionButton/index.tsx +0 -0
  313. /package/src/app/[variants]/(main)/discover/(detail)/mcp/{[slug]/features → features}/Sidebar/ConnectionTypeAlert.tsx +0 -0
  314. /package/src/app/[variants]/(main)/discover/(detail)/mcp/{[slug]/features → features}/Sidebar/Related/Item.tsx +0 -0
  315. /package/src/app/[variants]/(main)/discover/(detail)/mcp/{[slug]/features → features}/Sidebar/index.tsx +0 -0
  316. /package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/DetailProvider.tsx +0 -0
  317. /package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Details/Nav.tsx +0 -0
  318. /package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Details/Overview/ProviderList/index.tsx +0 -0
  319. /package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Details/Parameter/index.tsx +0 -0
  320. /package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Sidebar/Related/Item.tsx +0 -0
  321. /package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Sidebar/RelatedProviders/Item.tsx +0 -0
  322. /package/src/app/[variants]/(main)/discover/(detail)/model/{[...slugs]/features → features}/Sidebar/index.tsx +0 -0
  323. /package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/DetailProvider.tsx +0 -0
  324. /package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Details/Guide/index.tsx +0 -0
  325. /package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Details/Nav.tsx +0 -0
  326. /package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Details/Overview/ModelList/index.tsx +0 -0
  327. /package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Details/Overview/index.tsx +0 -0
  328. /package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Header.tsx +0 -0
  329. /package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Sidebar/Related/Item.tsx +0 -0
  330. /package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Sidebar/RelatedModels/Item.tsx +0 -0
  331. /package/src/app/[variants]/(main)/discover/(detail)/provider/{[...slugs]/features → features}/Sidebar/index.tsx +0 -0
  332. /package/src/app/[variants]/(main)/labs/{page.tsx → index.tsx} +0 -0
  333. /package/src/app/[variants]/(main)/{_layout/Desktop → layouts/desktop}/RegisterHotkeys.tsx +0 -0
  334. /package/src/app/[variants]/(main)/{_layout/Desktop → layouts/desktop}/SideBar/Avatar.test.tsx +0 -0
  335. /package/src/app/[variants]/(main)/{_layout/Desktop → layouts/desktop}/SideBar/Avatar.tsx +0 -0
  336. /package/src/app/[variants]/(main)/{_layout/Desktop → layouts/desktop}/SideBar/PinList/index.tsx +0 -0
  337. /package/src/app/[variants]/(main)/{_layout/Desktop → layouts/desktop}/SideBar/index.tsx +0 -0
@@ -23,7 +23,7 @@ export interface MessageQueryAction {
23
23
  /**
24
24
  * Manually refresh messages from server
25
25
  */
26
- refreshMessages: () => Promise<void>;
26
+ refreshMessages: (sessionId?: string, topicId?: string | null) => Promise<void>;
27
27
 
28
28
  /**
29
29
  * Replace current messages with new data
@@ -33,7 +33,7 @@ export interface MessageQueryAction {
33
33
  params?: {
34
34
  action?: any;
35
35
  sessionId?: string;
36
- topicId?: string;
36
+ topicId?: string | null;
37
37
  },
38
38
  ) => void;
39
39
 
@@ -58,9 +58,11 @@ export const messageQuery: StateCreator<
58
58
  > = (set, get) => ({
59
59
  // TODO: The mutate should only be called once, but since we haven't merge session and group,
60
60
  // we need to call it twice
61
- refreshMessages: async () => {
62
- await mutate([SWR_USE_FETCH_MESSAGES, get().activeId, get().activeTopicId, 'session']);
63
- await mutate([SWR_USE_FETCH_MESSAGES, get().activeId, get().activeTopicId, 'group']);
61
+ refreshMessages: async (sessionId?: string, topicId?: string | null) => {
62
+ const sid = sessionId ?? get().activeId;
63
+ const tid = topicId !== undefined ? topicId : get().activeTopicId;
64
+ await mutate([SWR_USE_FETCH_MESSAGES, sid, tid, 'session']);
65
+ await mutate([SWR_USE_FETCH_MESSAGES, sid, tid, 'group']);
64
66
  },
65
67
 
66
68
  replaceMessages: (messages, params) => {
@@ -43,11 +43,18 @@ const activeDbMessages = (s: ChatStoreState): UIChatMessage[] => {
43
43
  // ============= DB Message Queries ========== //
44
44
 
45
45
  /**
46
- * Get raw message by ID from database
47
- * This searches in dbMessagesMap, which contains flat message structure
46
+ * Get raw message by ID from database (searches globally across all sessions/topics)
47
+ * This is essential for parallel topic agent runtime where background updates
48
+ * may occur after the user has switched to another chat.
48
49
  */
49
- const getDbMessageById = (id: string) => (s: ChatStoreState) =>
50
- chatHelpers.getMessageById(activeDbMessages(s), id);
50
+ const getDbMessageById = (id: string) => (s: ChatStoreState) => {
51
+ // Search across all messages in dbMessagesMap
52
+ for (const messages of Object.values(s.dbMessagesMap)) {
53
+ const message = chatHelpers.getMessageById(messages, id);
54
+ if (message) return message;
55
+ }
56
+ return undefined;
57
+ };
51
58
 
52
59
  /**
53
60
  * Get raw message by tool_call_id from database
@@ -257,6 +257,11 @@ describe('ChatPluginAction', () => {
257
257
  expect(storeState.optimisticUpdateMessageContent).toHaveBeenCalledWith(
258
258
  messageId,
259
259
  pluginApiResponse,
260
+ undefined,
261
+ {
262
+ sessionId: undefined,
263
+ topicId: undefined,
264
+ },
260
265
  );
261
266
  expect(storeState.internal_togglePluginApiCalling).toHaveBeenCalledWith(
262
267
  false,
@@ -295,8 +300,14 @@ describe('ChatPluginAction', () => {
295
300
  expect.any(String),
296
301
  );
297
302
  expect(chatService.runPluginApi).toHaveBeenCalledWith(pluginPayload, { trace: {} });
298
- expect(messageService.updateMessageError).toHaveBeenCalledWith(messageId, error);
299
- expect(replaceMessagesSpy).toHaveBeenCalledWith(mockMessages);
303
+ expect(messageService.updateMessageError).toHaveBeenCalledWith(messageId, error, {
304
+ sessionId: undefined,
305
+ topicId: undefined,
306
+ });
307
+ expect(replaceMessagesSpy).toHaveBeenCalledWith(mockMessages, {
308
+ sessionId: undefined,
309
+ topicId: undefined,
310
+ });
300
311
  expect(storeState.internal_togglePluginApiCalling).toHaveBeenCalledWith(
301
312
  false,
302
313
  'message-id',
@@ -379,50 +390,78 @@ describe('ChatPluginAction', () => {
379
390
 
380
391
  // Verify that tool messages were created for each tool call
381
392
  expect(optimisticCreateMessageMock).toHaveBeenCalledTimes(4);
382
- expect(optimisticCreateMessageMock).toHaveBeenNthCalledWith(1, {
383
- content: '',
384
- parentId: assistantId,
385
- plugin: message.tools![0],
386
- role: 'tool',
387
- sessionId: 'session-id',
388
- tool_call_id: 'tool1',
389
- topicId: 'topic-id',
390
- threadId: undefined,
391
- groupId: undefined,
392
- });
393
- expect(optimisticCreateMessageMock).toHaveBeenNthCalledWith(2, {
394
- content: '',
395
- parentId: assistantId,
396
- plugin: message.tools![1],
397
- role: 'tool',
398
- sessionId: 'session-id',
399
- tool_call_id: 'tool2',
400
- topicId: 'topic-id',
401
- threadId: undefined,
402
- groupId: undefined,
403
- });
404
- expect(optimisticCreateMessageMock).toHaveBeenNthCalledWith(3, {
405
- content: '',
406
- parentId: assistantId,
407
- plugin: message.tools![2],
408
- role: 'tool',
409
- sessionId: 'session-id',
410
- tool_call_id: 'tool3',
411
- topicId: 'topic-id',
412
- threadId: undefined,
413
- groupId: undefined,
414
- });
415
- expect(optimisticCreateMessageMock).toHaveBeenNthCalledWith(4, {
416
- content: '',
417
- parentId: assistantId,
418
- plugin: message.tools![3],
419
- role: 'tool',
420
- sessionId: 'session-id',
421
- tool_call_id: 'tool4',
422
- topicId: 'topic-id',
423
- threadId: undefined,
424
- groupId: undefined,
425
- });
393
+ expect(optimisticCreateMessageMock).toHaveBeenNthCalledWith(
394
+ 1,
395
+ {
396
+ content: '',
397
+ parentId: assistantId,
398
+ plugin: message.tools![0],
399
+ role: 'tool',
400
+ sessionId: 'session-id',
401
+ tool_call_id: 'tool1',
402
+ topicId: 'topic-id',
403
+ threadId: undefined,
404
+ groupId: undefined,
405
+ },
406
+ {
407
+ sessionId: 'session-id',
408
+ topicId: 'topic-id',
409
+ },
410
+ );
411
+ expect(optimisticCreateMessageMock).toHaveBeenNthCalledWith(
412
+ 2,
413
+ {
414
+ content: '',
415
+ parentId: assistantId,
416
+ plugin: message.tools![1],
417
+ role: 'tool',
418
+ sessionId: 'session-id',
419
+ tool_call_id: 'tool2',
420
+ topicId: 'topic-id',
421
+ threadId: undefined,
422
+ groupId: undefined,
423
+ },
424
+ {
425
+ sessionId: 'session-id',
426
+ topicId: 'topic-id',
427
+ },
428
+ );
429
+ expect(optimisticCreateMessageMock).toHaveBeenNthCalledWith(
430
+ 3,
431
+ {
432
+ content: '',
433
+ parentId: assistantId,
434
+ plugin: message.tools![2],
435
+ role: 'tool',
436
+ sessionId: 'session-id',
437
+ tool_call_id: 'tool3',
438
+ topicId: 'topic-id',
439
+ threadId: undefined,
440
+ groupId: undefined,
441
+ },
442
+ {
443
+ sessionId: 'session-id',
444
+ topicId: 'topic-id',
445
+ },
446
+ );
447
+ expect(optimisticCreateMessageMock).toHaveBeenNthCalledWith(
448
+ 4,
449
+ {
450
+ content: '',
451
+ parentId: assistantId,
452
+ plugin: message.tools![3],
453
+ role: 'tool',
454
+ sessionId: 'session-id',
455
+ tool_call_id: 'tool4',
456
+ topicId: 'topic-id',
457
+ threadId: undefined,
458
+ groupId: undefined,
459
+ },
460
+ {
461
+ sessionId: 'session-id',
462
+ topicId: 'topic-id',
463
+ },
464
+ );
426
465
 
427
466
  // Verify that the appropriate plugin types were invoked
428
467
  expect(invokeStandaloneTypePluginMock).toHaveBeenCalledWith(
@@ -556,7 +595,10 @@ describe('ChatPluginAction', () => {
556
595
  },
557
596
  );
558
597
 
559
- expect(replaceMessagesSpy).toHaveBeenCalledWith(mockMessages);
598
+ expect(replaceMessagesSpy).toHaveBeenCalledWith(mockMessages, {
599
+ sessionId: 'inbox',
600
+ topicId: null,
601
+ });
560
602
  });
561
603
  });
562
604
 
@@ -596,7 +638,10 @@ describe('ChatPluginAction', () => {
596
638
  });
597
639
 
598
640
  // 验证 replaceMessages 是否被调用
599
- expect(result.current.replaceMessages).toHaveBeenCalledWith(mockMessages);
641
+ expect(result.current.replaceMessages).toHaveBeenCalledWith(mockMessages, {
642
+ sessionId: 'session-id',
643
+ topicId: 'topic-id',
644
+ });
600
645
  });
601
646
 
602
647
  it('should handle errors when message creation fails', async () => {
@@ -773,7 +818,10 @@ describe('ChatPluginAction', () => {
773
818
  type: 'PluginSettingsInvalid',
774
819
  });
775
820
 
776
- expect(replaceMessagesSpy).toHaveBeenCalledWith(mockMessages);
821
+ expect(replaceMessagesSpy).toHaveBeenCalledWith(mockMessages, {
822
+ sessionId: undefined,
823
+ topicId: undefined,
824
+ });
777
825
  });
778
826
  });
779
827
 
@@ -848,7 +896,10 @@ describe('ChatPluginAction', () => {
848
896
  await result.current.reInvokeToolMessage(messageId);
849
897
  });
850
898
 
851
- expect(internal_updateMessageErrorMock).toHaveBeenCalledWith(messageId, null);
899
+ expect(internal_updateMessageErrorMock).toHaveBeenCalledWith(messageId, null, {
900
+ sessionId: undefined,
901
+ topicId: undefined,
902
+ });
852
903
  });
853
904
  });
854
905
 
@@ -938,6 +989,11 @@ describe('ChatPluginAction', () => {
938
989
  expect(result.current.optimisticUpdateMessageContent).toHaveBeenCalledWith(
939
990
  messageId,
940
991
  apiResponse,
992
+ undefined,
993
+ {
994
+ sessionId: undefined,
995
+ topicId: undefined,
996
+ },
941
997
  );
942
998
  expect(messageService.updateMessage).toHaveBeenCalledWith(messageId, { traceId: 'trace-id' });
943
999
  });
@@ -977,8 +1033,14 @@ describe('ChatPluginAction', () => {
977
1033
  await result.current.internal_callPluginApi(messageId, payload);
978
1034
  });
979
1035
 
980
- expect(messageService.updateMessageError).toHaveBeenCalledWith(messageId, error);
981
- expect(replaceMessagesSpy).toHaveBeenCalledWith(mockMessages);
1036
+ expect(messageService.updateMessageError).toHaveBeenCalledWith(messageId, error, {
1037
+ sessionId: undefined,
1038
+ topicId: undefined,
1039
+ });
1040
+ expect(replaceMessagesSpy).toHaveBeenCalledWith(mockMessages, {
1041
+ sessionId: undefined,
1042
+ topicId: undefined,
1043
+ });
982
1044
  });
983
1045
  });
984
1046
 
@@ -1111,7 +1173,10 @@ describe('ChatPluginAction', () => {
1111
1173
  { error },
1112
1174
  { sessionId: 'inbox', topicId: null },
1113
1175
  );
1114
- expect(replaceMessagesSpy).toHaveBeenCalledWith(mockMessages);
1176
+ expect(replaceMessagesSpy).toHaveBeenCalledWith(mockMessages, {
1177
+ sessionId: 'inbox',
1178
+ topicId: null,
1179
+ });
1115
1180
  });
1116
1181
  });
1117
1182
 
@@ -1153,7 +1218,145 @@ describe('ChatPluginAction', () => {
1153
1218
  });
1154
1219
  });
1155
1220
 
1156
- expect(refreshToUpdateMessageToolsSpy).toHaveBeenCalledWith(messageId);
1221
+ expect(refreshToUpdateMessageToolsSpy).toHaveBeenCalledWith(messageId, undefined);
1222
+ });
1223
+ });
1224
+
1225
+ describe('Plugin OptimisticUpdateContext isolation', () => {
1226
+ describe('optimisticUpdatePluginState', () => {
1227
+ it('should use context sessionId/topicId when provided', async () => {
1228
+ const { result } = renderHook(() => useChatStore());
1229
+ const messageId = 'message-id';
1230
+ const pluginState = { key: 'value' };
1231
+ const contextSessionId = 'context-session';
1232
+ const contextTopicId = 'context-topic';
1233
+
1234
+ (messageService.updateMessagePluginState as Mock).mockResolvedValue({
1235
+ success: true,
1236
+ messages: [],
1237
+ });
1238
+
1239
+ const replaceMessagesSpy = vi.spyOn(result.current, 'replaceMessages');
1240
+
1241
+ await act(async () => {
1242
+ await result.current.optimisticUpdatePluginState(messageId, pluginState, {
1243
+ sessionId: contextSessionId,
1244
+ topicId: contextTopicId,
1245
+ });
1246
+ });
1247
+
1248
+ expect(messageService.updateMessagePluginState).toHaveBeenCalledWith(
1249
+ messageId,
1250
+ pluginState,
1251
+ { sessionId: contextSessionId, topicId: contextTopicId },
1252
+ );
1253
+ expect(replaceMessagesSpy).toHaveBeenCalledWith([], {
1254
+ sessionId: contextSessionId,
1255
+ topicId: contextTopicId,
1256
+ });
1257
+ });
1258
+
1259
+ it('should fallback to activeId/activeTopicId when context not provided', async () => {
1260
+ const { result } = renderHook(() => useChatStore());
1261
+ const messageId = 'message-id';
1262
+ const pluginState = { key: 'value' };
1263
+
1264
+ act(() => {
1265
+ useChatStore.setState({
1266
+ activeId: 'active-session',
1267
+ activeTopicId: 'active-topic',
1268
+ });
1269
+ });
1270
+
1271
+ (messageService.updateMessagePluginState as Mock).mockResolvedValue({
1272
+ success: true,
1273
+ messages: [],
1274
+ });
1275
+
1276
+ await act(async () => {
1277
+ await result.current.optimisticUpdatePluginState(messageId, pluginState);
1278
+ });
1279
+
1280
+ expect(messageService.updateMessagePluginState).toHaveBeenCalledWith(
1281
+ messageId,
1282
+ pluginState,
1283
+ { sessionId: 'active-session', topicId: 'active-topic' },
1284
+ );
1285
+ });
1286
+ });
1287
+
1288
+ describe('optimisticUpdatePluginError', () => {
1289
+ it('should use context sessionId/topicId when provided', async () => {
1290
+ const { result } = renderHook(() => useChatStore());
1291
+ const messageId = 'message-id';
1292
+ const error = { message: 'Plugin error', type: 'error' as any };
1293
+ const contextSessionId = 'context-session';
1294
+ const contextTopicId = 'context-topic';
1295
+
1296
+ (messageService.updateMessage as Mock).mockResolvedValue({
1297
+ success: true,
1298
+ messages: [],
1299
+ });
1300
+
1301
+ await act(async () => {
1302
+ await result.current.optimisticUpdatePluginError(messageId, error, {
1303
+ sessionId: contextSessionId,
1304
+ topicId: contextTopicId,
1305
+ });
1306
+ });
1307
+
1308
+ expect(messageService.updateMessage).toHaveBeenCalledWith(
1309
+ messageId,
1310
+ { error },
1311
+ { sessionId: contextSessionId, topicId: contextTopicId },
1312
+ );
1313
+ });
1314
+ });
1315
+
1316
+ describe('internal_refreshToUpdateMessageTools', () => {
1317
+ it('should use context sessionId/topicId when provided', async () => {
1318
+ const { result } = renderHook(() => useChatStore());
1319
+ const messageId = 'message-id';
1320
+ const contextSessionId = 'context-session';
1321
+ const contextTopicId = 'context-topic';
1322
+
1323
+ const message = {
1324
+ id: messageId,
1325
+ role: 'assistant',
1326
+ content: 'test',
1327
+ tools: [{ id: 'tool-1', identifier: 'test', apiName: 'test', arguments: '{}' }],
1328
+ sessionId: contextSessionId,
1329
+ topicId: contextTopicId,
1330
+ } as any;
1331
+
1332
+ // Set up both dbMessagesMap and messagesMap
1333
+ const key = messageMapKey(contextSessionId, contextTopicId);
1334
+ act(() => {
1335
+ useChatStore.setState({
1336
+ dbMessagesMap: {
1337
+ [key]: [message],
1338
+ },
1339
+ messagesMap: {
1340
+ [key]: [message],
1341
+ },
1342
+ activeId: contextSessionId,
1343
+ activeTopicId: contextTopicId,
1344
+ });
1345
+ });
1346
+
1347
+ await act(async () => {
1348
+ await result.current.internal_refreshToUpdateMessageTools(messageId, {
1349
+ sessionId: contextSessionId,
1350
+ topicId: contextTopicId,
1351
+ });
1352
+ });
1353
+
1354
+ expect(messageService.updateMessage).toHaveBeenCalledWith(
1355
+ messageId,
1356
+ { tools: message.tools },
1357
+ { sessionId: contextSessionId, topicId: contextTopicId },
1358
+ );
1359
+ });
1157
1360
  });
1158
1361
  });
1159
1362
  });
@@ -4,6 +4,7 @@ import isEqual from 'fast-deep-equal';
4
4
  import { StateCreator } from 'zustand/vanilla';
5
5
 
6
6
  import { messageService } from '@/services/message';
7
+ import { OptimisticUpdateContext } from '@/store/chat/slices/message/actions/optimisticUpdate';
7
8
  import { ChatStore } from '@/store/chat/store';
8
9
  import { merge } from '@/utils/merge';
9
10
  import { safeParseJSON } from '@/utils/safeParseJSON';
@@ -18,7 +19,11 @@ export interface PluginOptimisticUpdateAction {
18
19
  /**
19
20
  * Update plugin state with optimistic update
20
21
  */
21
- optimisticUpdatePluginState: (id: string, value: any) => Promise<void>;
22
+ optimisticUpdatePluginState: (
23
+ id: string,
24
+ value: any,
25
+ context?: OptimisticUpdateContext,
26
+ ) => Promise<void>;
22
27
 
23
28
  /**
24
29
  * Update plugin arguments with optimistic update
@@ -32,27 +37,46 @@ export interface PluginOptimisticUpdateAction {
32
37
  /**
33
38
  * Update plugin with optimistic update (generic method for any plugin field)
34
39
  */
35
- optimisticUpdatePlugin: (id: string, value: Partial<MessagePluginItem>) => Promise<void>;
40
+ optimisticUpdatePlugin: (
41
+ id: string,
42
+ value: Partial<MessagePluginItem>,
43
+ context?: OptimisticUpdateContext,
44
+ ) => Promise<void>;
36
45
 
37
46
  /**
38
47
  * Add tool to assistant message with optimistic update
39
48
  */
40
- optimisticAddToolToAssistantMessage: (id: string, tool: ChatToolPayload) => Promise<void>;
49
+ optimisticAddToolToAssistantMessage: (
50
+ id: string,
51
+ tool: ChatToolPayload,
52
+ context?: OptimisticUpdateContext,
53
+ ) => Promise<void>;
41
54
 
42
55
  /**
43
56
  * Remove tool from assistant message with optimistic update
44
57
  */
45
- optimisticRemoveToolFromAssistantMessage: (id: string, tool_call_id?: string) => Promise<void>;
58
+ optimisticRemoveToolFromAssistantMessage: (
59
+ id: string,
60
+ tool_call_id?: string,
61
+ context?: OptimisticUpdateContext,
62
+ ) => Promise<void>;
46
63
 
47
64
  /**
48
65
  * Update plugin error with optimistic update
49
66
  */
50
- optimisticUpdatePluginError: (id: string, error: ChatMessageError) => Promise<void>;
67
+ optimisticUpdatePluginError: (
68
+ id: string,
69
+ error: ChatMessageError,
70
+ context?: OptimisticUpdateContext,
71
+ ) => Promise<void>;
51
72
 
52
73
  /**
53
74
  * Use the optimistic update value to update the message tools to database
54
75
  */
55
- internal_refreshToUpdateMessageTools: (id: string) => Promise<void>;
76
+ internal_refreshToUpdateMessageTools: (
77
+ id: string,
78
+ context?: OptimisticUpdateContext,
79
+ ) => Promise<void>;
56
80
  }
57
81
 
58
82
  export const pluginOptimisticUpdate: StateCreator<
@@ -61,19 +85,22 @@ export const pluginOptimisticUpdate: StateCreator<
61
85
  [],
62
86
  PluginOptimisticUpdateAction
63
87
  > = (set, get) => ({
64
- optimisticUpdatePluginState: async (id, value) => {
88
+ optimisticUpdatePluginState: async (id, value, context) => {
65
89
  const { replaceMessages } = get();
66
90
 
67
91
  // optimistic update
68
92
  get().internal_dispatchMessage({ id, type: 'updateMessage', value: { pluginState: value } });
69
93
 
94
+ const sessionId = context?.sessionId ?? get().activeId;
95
+ const topicId = context?.topicId !== undefined ? context.topicId : get().activeTopicId;
96
+
70
97
  const result = await messageService.updateMessagePluginState(id, value, {
71
- sessionId: get().activeId,
72
- topicId: get().activeTopicId,
98
+ sessionId,
99
+ topicId,
73
100
  });
74
101
 
75
102
  if (result?.success && result.messages) {
76
- replaceMessages(result.messages);
103
+ replaceMessages(result.messages, { sessionId, topicId });
77
104
  }
78
105
  },
79
106
 
@@ -124,7 +151,7 @@ export const pluginOptimisticUpdate: StateCreator<
124
151
  await refreshMessages();
125
152
  },
126
153
 
127
- optimisticUpdatePlugin: async (id, value) => {
154
+ optimisticUpdatePlugin: async (id, value, context) => {
128
155
  const { replaceMessages } = get();
129
156
 
130
157
  // optimistic update
@@ -134,17 +161,20 @@ export const pluginOptimisticUpdate: StateCreator<
134
161
  value,
135
162
  });
136
163
 
164
+ const sessionId = context?.sessionId ?? get().activeId;
165
+ const topicId = context?.topicId !== undefined ? context.topicId : get().activeTopicId;
166
+
137
167
  const result = await messageService.updateMessagePlugin(id, value, {
138
- sessionId: get().activeId,
139
- topicId: get().activeTopicId,
168
+ sessionId,
169
+ topicId,
140
170
  });
141
171
 
142
172
  if (result?.success && result.messages) {
143
- replaceMessages(result.messages);
173
+ replaceMessages(result.messages, { sessionId, topicId });
144
174
  }
145
175
  },
146
176
 
147
- optimisticAddToolToAssistantMessage: async (id, tool) => {
177
+ optimisticAddToolToAssistantMessage: async (id, tool, context) => {
148
178
  const assistantMessage = displayMessageSelectors.getDisplayMessageById(id)(get());
149
179
  if (!assistantMessage) return;
150
180
 
@@ -155,10 +185,10 @@ export const pluginOptimisticUpdate: StateCreator<
155
185
  id: assistantMessage.id,
156
186
  });
157
187
 
158
- await internal_refreshToUpdateMessageTools(id);
188
+ await internal_refreshToUpdateMessageTools(id, context);
159
189
  },
160
190
 
161
- optimisticRemoveToolFromAssistantMessage: async (id, tool_call_id) => {
191
+ optimisticRemoveToolFromAssistantMessage: async (id, tool_call_id, context) => {
162
192
  const message = displayMessageSelectors.getDisplayMessageById(id)(get());
163
193
  if (!message || !tool_call_id) return;
164
194
 
@@ -168,46 +198,53 @@ export const pluginOptimisticUpdate: StateCreator<
168
198
  internal_dispatchMessage({ type: 'deleteMessageTool', tool_call_id, id: message.id });
169
199
 
170
200
  // update the message tools
171
- await internal_refreshToUpdateMessageTools(id);
201
+ await internal_refreshToUpdateMessageTools(id, context);
172
202
  },
173
203
 
174
- optimisticUpdatePluginError: async (id, error) => {
204
+ optimisticUpdatePluginError: async (id, error, context) => {
175
205
  const { replaceMessages } = get();
176
206
 
177
207
  get().internal_dispatchMessage({ id, type: 'updateMessage', value: { error } });
208
+
209
+ const sessionId = context?.sessionId ?? get().activeId;
210
+ const topicId = context?.topicId !== undefined ? context.topicId : get().activeTopicId;
211
+
178
212
  const result = await messageService.updateMessage(
179
213
  id,
180
214
  { error },
181
215
  {
182
- sessionId: get().activeId,
183
- topicId: get().activeTopicId,
216
+ sessionId,
217
+ topicId,
184
218
  },
185
219
  );
186
220
  if (result?.success && result.messages) {
187
- replaceMessages(result.messages);
221
+ replaceMessages(result.messages, { sessionId, topicId });
188
222
  }
189
223
  },
190
224
 
191
- internal_refreshToUpdateMessageTools: async (id) => {
225
+ internal_refreshToUpdateMessageTools: async (id, context) => {
192
226
  const { dbMessageSelectors } = await import('../../message/selectors');
193
227
  const message = dbMessageSelectors.getDbMessageById(id)(get());
194
228
  if (!message || !message.tools) return;
195
229
 
196
230
  const { internal_toggleMessageLoading, replaceMessages } = get();
197
231
 
232
+ const sessionId = context?.sessionId ?? get().activeId;
233
+ const topicId = context?.topicId !== undefined ? context.topicId : get().activeTopicId;
234
+
198
235
  internal_toggleMessageLoading(true, id);
199
236
  const result = await messageService.updateMessage(
200
237
  id,
201
238
  { tools: message.tools },
202
239
  {
203
- sessionId: get().activeId,
204
- topicId: get().activeTopicId,
240
+ sessionId,
241
+ topicId,
205
242
  },
206
243
  );
207
244
  internal_toggleMessageLoading(false, id);
208
245
 
209
246
  if (result?.success && result.messages) {
210
- replaceMessages(result.messages);
247
+ replaceMessages(result.messages, { sessionId, topicId });
211
248
  }
212
249
  },
213
250
  });