@lobehub/chat 1.11.9 → 1.12.1

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 (356) hide show
  1. package/.github/workflows/release.yml +2 -1
  2. package/.github/workflows/test.yml +2 -1
  3. package/CHANGELOG.md +50 -0
  4. package/Dockerfile.database +2 -0
  5. package/docs/self-hosting/advanced/knowledge-base.zh-CN.mdx +65 -0
  6. package/locales/ar/chat.json +13 -3
  7. package/locales/ar/components.json +2 -0
  8. package/locales/bg-BG/chat.json +13 -3
  9. package/locales/bg-BG/components.json +2 -0
  10. package/locales/de-DE/chat.json +13 -3
  11. package/locales/de-DE/components.json +2 -0
  12. package/locales/en-US/chat.json +13 -3
  13. package/locales/en-US/components.json +2 -0
  14. package/locales/es-ES/chat.json +13 -3
  15. package/locales/es-ES/components.json +2 -0
  16. package/locales/fr-FR/chat.json +13 -3
  17. package/locales/fr-FR/components.json +2 -0
  18. package/locales/it-IT/chat.json +13 -3
  19. package/locales/it-IT/components.json +2 -0
  20. package/locales/ja-JP/chat.json +13 -3
  21. package/locales/ja-JP/components.json +2 -0
  22. package/locales/ko-KR/chat.json +13 -3
  23. package/locales/ko-KR/components.json +2 -0
  24. package/locales/nl-NL/chat.json +13 -3
  25. package/locales/nl-NL/components.json +2 -0
  26. package/locales/pl-PL/chat.json +13 -3
  27. package/locales/pl-PL/components.json +2 -0
  28. package/locales/pt-BR/chat.json +13 -3
  29. package/locales/pt-BR/components.json +2 -0
  30. package/locales/ru-RU/chat.json +13 -3
  31. package/locales/ru-RU/components.json +2 -0
  32. package/locales/tr-TR/chat.json +13 -3
  33. package/locales/tr-TR/components.json +2 -0
  34. package/locales/vi-VN/chat.json +13 -3
  35. package/locales/vi-VN/components.json +2 -0
  36. package/locales/zh-CN/chat.json +13 -3
  37. package/locales/zh-CN/components.json +2 -0
  38. package/locales/zh-TW/chat.json +13 -3
  39. package/locales/zh-TW/components.json +2 -0
  40. package/package.json +3 -2
  41. package/scripts/migrateServerDB/docker.cjs +6 -0
  42. package/scripts/migrateServerDB/errorHint.js +17 -0
  43. package/scripts/migrateServerDB/index.ts +6 -0
  44. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileItem/Content.tsx +37 -0
  45. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileItem/index.tsx +87 -0
  46. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileItem/style.ts +4 -0
  47. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileItem/utils.ts +28 -0
  48. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileList.tsx +41 -0
  49. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/index.tsx +40 -0
  50. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/SendMore.tsx +1 -1
  51. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/index.tsx +7 -22
  52. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/TextArea.tsx +1 -1
  53. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +2 -4
  54. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/File.tsx +72 -0
  55. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/Image.tsx +74 -0
  56. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/index.tsx +39 -0
  57. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/style.ts +1 -0
  58. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/index.tsx +33 -0
  59. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/InputArea/Container.tsx +41 -0
  60. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/InputArea/index.tsx +154 -0
  61. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Send.tsx +34 -0
  62. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/index.tsx +24 -11
  63. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/components/UploadDetail/UploadStatus.tsx +71 -0
  64. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/components/UploadDetail/index.tsx +49 -0
  65. package/src/app/(main)/chat/(workspace)/@portal/FilePreview/index.tsx +26 -0
  66. package/src/app/(main)/chat/(workspace)/@portal/Home/Files/FileList/Item.tsx +53 -0
  67. package/src/app/(main)/chat/(workspace)/@portal/Home/Files/FileList/index.tsx +50 -0
  68. package/src/app/(main)/chat/(workspace)/@portal/Home/Files/index.tsx +21 -0
  69. package/src/app/(main)/chat/(workspace)/@portal/Home/index.tsx +2 -0
  70. package/src/app/(main)/chat/(workspace)/@portal/router.tsx +4 -0
  71. package/src/app/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/KnowledgeTag.tsx +41 -0
  72. package/src/app/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/Tags.tsx +7 -2
  73. package/src/app/(main)/chat/(workspace)/_layout/Desktop/HotKeys.tsx +1 -1
  74. package/src/app/(main)/files/(content)/@menu/default.tsx +27 -0
  75. package/src/app/(main)/files/(content)/@menu/features/FileMenu/index.tsx +97 -0
  76. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/EmptyStatus.tsx +53 -0
  77. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/Item/Content.tsx +175 -0
  78. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/Item/index.tsx +69 -0
  79. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/KnowledgeBaseList.tsx +30 -0
  80. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/SkeletonList.tsx +57 -0
  81. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/index.tsx +54 -0
  82. package/src/app/(main)/files/(content)/@modal/(.)[id]/FileDetail.tsx +16 -0
  83. package/src/app/(main)/files/(content)/@modal/(.)[id]/FilePreview.tsx +15 -0
  84. package/src/app/(main)/files/(content)/@modal/(.)[id]/FullscreenModal.tsx +85 -0
  85. package/src/app/(main)/files/(content)/@modal/(.)[id]/page.tsx +19 -0
  86. package/src/app/(main)/files/(content)/@modal/default.tsx +3 -0
  87. package/src/app/(main)/files/(content)/NotSupportClient.tsx +152 -0
  88. package/src/app/(main)/files/(content)/_layout/Desktop/index.tsx +28 -0
  89. package/src/app/(main)/files/(content)/_layout/Mobile.tsx +47 -0
  90. package/src/app/(main)/files/(content)/_layout/type.ts +7 -0
  91. package/src/app/(main)/files/(content)/layout.tsx +18 -0
  92. package/src/app/(main)/files/(content)/page.tsx +14 -0
  93. package/src/app/(main)/files/[id]/Header.tsx +63 -0
  94. package/src/app/(main)/files/[id]/page.tsx +44 -0
  95. package/src/app/(main)/files/features/FileDetail.tsx +93 -0
  96. package/src/app/(main)/files/hooks/useFileCategory.ts +9 -0
  97. package/src/app/(main)/files/layout.tsx +12 -0
  98. package/src/app/(main)/files/loading.tsx +21 -0
  99. package/src/app/(main)/repos/[id]/@menu/Head/index.tsx +33 -0
  100. package/src/app/(main)/repos/[id]/@menu/Menu/index.tsx +56 -0
  101. package/src/app/(main)/repos/[id]/@menu/default.tsx +25 -0
  102. package/src/app/(main)/repos/[id]/_layout/Desktop/index.tsx +25 -0
  103. package/src/app/(main)/repos/[id]/_layout/Mobile.tsx +47 -0
  104. package/src/app/(main)/repos/[id]/_layout/type.ts +6 -0
  105. package/src/app/(main)/repos/[id]/hooks/useKnowledgeItem.ts +7 -0
  106. package/src/app/(main)/repos/[id]/layout.tsx +13 -0
  107. package/src/app/(main)/repos/[id]/page.tsx +18 -0
  108. package/src/app/(main)/repos/layout.tsx +13 -0
  109. package/src/app/(main)/repos/page.tsx +5 -0
  110. package/src/app/trpc/async/[trpc]/route.ts +28 -0
  111. package/src/chains/abstractChunk.ts +19 -0
  112. package/src/chains/answerWithContext.ts +34 -0
  113. package/src/chains/rewriteQuery.ts +22 -0
  114. package/src/components/DragUpload/index.tsx +6 -99
  115. package/src/components/DragUpload/useDragUpload.tsx +146 -0
  116. package/src/components/FeatureList/index.tsx +64 -0
  117. package/src/components/FileParsingStatus/index.tsx +230 -0
  118. package/src/components/ImageItem/index.tsx +10 -2
  119. package/src/components/KnowledgeIcon/index.tsx +28 -0
  120. package/src/config/app.ts +6 -1
  121. package/src/config/featureFlags/schema.ts +1 -1
  122. package/src/const/file.ts +1 -0
  123. package/src/const/url.ts +1 -0
  124. package/src/database/client/models/file.ts +8 -2
  125. package/src/database/server/migrations/0005_pgvector.sql +2 -0
  126. package/src/database/server/migrations/0006_add_knowledge_base.sql +307 -0
  127. package/src/database/server/migrations/0007_fix_embedding_table.sql +18 -0
  128. package/src/database/server/migrations/meta/0005_snapshot.json +2119 -0
  129. package/src/database/server/migrations/meta/0006_snapshot.json +3006 -0
  130. package/src/database/server/migrations/meta/0007_snapshot.json +3012 -0
  131. package/src/database/server/migrations/meta/_journal.json +21 -0
  132. package/src/database/server/models/__tests__/_test_template.ts +155 -0
  133. package/src/database/server/models/__tests__/agent.test.ts +226 -0
  134. package/src/database/server/models/__tests__/asyncTask.test.ts +176 -0
  135. package/src/database/server/models/__tests__/chunk.test.ts +336 -0
  136. package/src/database/server/models/__tests__/file.test.ts +317 -29
  137. package/src/database/server/models/__tests__/fixtures/embedding.ts +568 -0
  138. package/src/database/server/models/__tests__/knowledgeBase.test.ts +132 -0
  139. package/src/database/server/models/__tests__/message.test.ts +7 -4
  140. package/src/database/server/models/_template.ts +10 -1
  141. package/src/database/server/models/agent.ts +165 -0
  142. package/src/database/server/models/asyncTask.ts +96 -0
  143. package/src/database/server/models/chunk.ts +203 -0
  144. package/src/database/server/models/embedding.ts +50 -0
  145. package/src/database/server/models/file.ts +231 -12
  146. package/src/database/server/models/knowledgeBase.ts +94 -0
  147. package/src/database/server/models/message.ts +156 -30
  148. package/src/database/server/models/user.ts +12 -1
  149. package/src/database/server/schemas/lobechat/agent.ts +93 -0
  150. package/src/database/server/schemas/lobechat/discover.ts +1 -1
  151. package/src/database/server/schemas/lobechat/file.ts +118 -1
  152. package/src/database/server/schemas/lobechat/index.ts +5 -1
  153. package/src/database/server/schemas/lobechat/message.ts +169 -0
  154. package/src/database/server/schemas/lobechat/rag.ts +53 -0
  155. package/src/database/server/schemas/lobechat/relations.ts +68 -48
  156. package/src/database/server/schemas/lobechat/session.ts +77 -0
  157. package/src/database/server/schemas/lobechat/topic.ts +32 -0
  158. package/src/database/server/schemas/lobechat/user.ts +40 -25
  159. package/src/database/server/utils/idGenerator.ts +1 -0
  160. package/src/features/ChatInput/ActionBar/Clear.tsx +1 -1
  161. package/src/features/ChatInput/ActionBar/Knowledge/Dropdown.tsx +160 -0
  162. package/src/features/ChatInput/ActionBar/Knowledge/ListItem.tsx +52 -0
  163. package/src/features/ChatInput/ActionBar/Knowledge/index.tsx +54 -0
  164. package/src/features/ChatInput/ActionBar/Tools/index.tsx +1 -1
  165. package/src/features/ChatInput/ActionBar/Upload/ClientMode.tsx +52 -0
  166. package/src/features/ChatInput/ActionBar/Upload/ServerMode.tsx +104 -0
  167. package/src/features/ChatInput/ActionBar/Upload/index.tsx +8 -0
  168. package/src/features/ChatInput/ActionBar/config.ts +14 -5
  169. package/src/features/ChatInput/useSend.ts +16 -7
  170. package/src/features/Conversation/Messages/Assistant/FileChunks/Item/index.tsx +51 -0
  171. package/src/features/Conversation/Messages/Assistant/FileChunks/Item/style.ts +38 -0
  172. package/src/features/Conversation/Messages/Assistant/FileChunks/index.tsx +76 -0
  173. package/src/features/Conversation/Messages/Assistant/index.tsx +13 -4
  174. package/src/features/Conversation/Messages/Default.tsx +4 -0
  175. package/src/features/Conversation/Messages/User/BelowMessage.tsx +78 -0
  176. package/src/features/Conversation/Messages/User/FileListViewer/Item.tsx +53 -0
  177. package/src/features/Conversation/Messages/User/FileListViewer/index.tsx +21 -0
  178. package/src/{components/FileList/FileListViewer.tsx → features/Conversation/Messages/User/ImageFileListViewer.tsx} +10 -2
  179. package/src/features/Conversation/Messages/{User.tsx → User/index.tsx} +11 -2
  180. package/src/features/Conversation/Messages/index.ts +8 -3
  181. package/src/features/Conversation/components/ChatItem/index.tsx +33 -10
  182. package/src/features/Conversation/components/InboxWelcome/QuestionSuggest.tsx +1 -1
  183. package/src/features/Conversation/types/index.tsx +1 -0
  184. package/src/features/FileManager/ChunkDrawer/ChunkList/ChunkItem.tsx +61 -0
  185. package/src/features/FileManager/ChunkDrawer/ChunkList/index.tsx +42 -0
  186. package/src/features/FileManager/ChunkDrawer/Content.tsx +38 -0
  187. package/src/features/FileManager/ChunkDrawer/Loading/index.tsx +16 -0
  188. package/src/features/FileManager/ChunkDrawer/SimilaritySearchList/Item.tsx +62 -0
  189. package/src/features/FileManager/ChunkDrawer/SimilaritySearchList/index.tsx +31 -0
  190. package/src/features/FileManager/ChunkDrawer/index.tsx +48 -0
  191. package/src/features/FileManager/FileList/EmptyStatus.tsx +153 -0
  192. package/src/features/FileManager/FileList/FileListItem/ChunkTag.tsx +35 -0
  193. package/src/features/FileManager/FileList/FileListItem/DropdownMenu.tsx +150 -0
  194. package/src/features/FileManager/FileList/FileListItem/index.tsx +211 -0
  195. package/src/features/FileManager/FileList/FileSkeleton.tsx +25 -0
  196. package/src/features/FileManager/FileList/ToolBar/Config.tsx +28 -0
  197. package/src/features/FileManager/FileList/ToolBar/MultiSelectActions.tsx +152 -0
  198. package/src/features/FileManager/FileList/ToolBar/index.tsx +114 -0
  199. package/src/features/FileManager/FileList/index.tsx +143 -0
  200. package/src/features/FileManager/FileList/useCheckTaskStatus.ts +27 -0
  201. package/src/features/FileManager/Header/FilesSearchBar.tsx +41 -0
  202. package/src/features/FileManager/Header/UploadFileButton.tsx +79 -0
  203. package/src/features/FileManager/Header/index.tsx +39 -0
  204. package/src/features/FileManager/UploadDock/Item.tsx +124 -0
  205. package/src/features/FileManager/UploadDock/index.tsx +183 -0
  206. package/src/features/FileManager/index.tsx +38 -0
  207. package/src/features/FileSidePanel/index.tsx +79 -0
  208. package/src/features/FileViewer/NotSupport/index.tsx +54 -0
  209. package/src/features/FileViewer/PDFViewer/HighlightLayer.tsx +81 -0
  210. package/src/features/FileViewer/PDFViewer/index.tsx +93 -0
  211. package/src/features/FileViewer/PDFViewer/style.ts +20 -0
  212. package/src/features/FileViewer/PDFViewer/useResizeObserver.ts +33 -0
  213. package/src/features/FileViewer/TXTViewer/index.tsx +41 -0
  214. package/src/features/FileViewer/index.tsx +45 -0
  215. package/src/features/KnowledgeBaseModal/AddFilesToKnowledgeBase/SelectForm.tsx +115 -0
  216. package/src/features/KnowledgeBaseModal/AddFilesToKnowledgeBase/index.tsx +43 -0
  217. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/Action.tsx +103 -0
  218. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/EditCustomPlugin.tsx +55 -0
  219. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/PluginTag.tsx +58 -0
  220. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/index.tsx +70 -0
  221. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/List.tsx +49 -0
  222. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Loading.tsx +13 -0
  223. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/index.tsx +39 -0
  224. package/src/features/KnowledgeBaseModal/CreateNew/CreateForm.tsx +73 -0
  225. package/src/features/KnowledgeBaseModal/CreateNew/index.tsx +35 -0
  226. package/src/features/KnowledgeBaseModal/index.ts +3 -0
  227. package/src/libs/langchain/loaders/pdf/index.ts +2 -2
  228. package/src/libs/trpc/async/asyncAuth.ts +24 -0
  229. package/src/libs/trpc/async/index.ts +10 -0
  230. package/src/libs/trpc/async/init.ts +11 -0
  231. package/src/libs/trpc/client/async.ts +14 -0
  232. package/src/libs/trpc/client/index.ts +1 -0
  233. package/src/libs/trpc/client/lambda.ts +9 -0
  234. package/src/libs/trpc/middleware/keyVaults.ts +18 -0
  235. package/src/libs/unstructured/__tests__/index.test.ts +0 -10
  236. package/src/libs/unstructured/index.ts +6 -11
  237. package/src/locales/default/chat.ts +47 -3
  238. package/src/locales/default/common.ts +1 -0
  239. package/src/locales/default/components.ts +2 -0
  240. package/src/locales/default/error.ts +6 -1
  241. package/src/locales/default/file.ts +92 -0
  242. package/src/locales/default/index.ts +4 -0
  243. package/src/locales/default/knowledgeBase.ts +31 -0
  244. package/src/locales/default/portal.ts +1 -0
  245. package/src/middleware.ts +3 -0
  246. package/src/server/asyncContext.ts +40 -0
  247. package/src/server/modules/ContentChunk/index.ts +135 -0
  248. package/src/server/modules/S3/index.ts +30 -5
  249. package/src/server/routers/async/caller.ts +27 -0
  250. package/src/server/routers/async/file.ts +247 -0
  251. package/src/server/routers/async/index.ts +12 -0
  252. package/src/server/routers/lambda/_template.ts +77 -0
  253. package/src/server/routers/lambda/agent.ts +159 -0
  254. package/src/server/routers/lambda/chunk.ts +189 -0
  255. package/src/server/routers/lambda/file.ts +129 -5
  256. package/src/server/routers/lambda/index.ts +6 -0
  257. package/src/server/routers/lambda/knowledgeBase.ts +79 -0
  258. package/src/server/routers/lambda/message.ts +6 -0
  259. package/src/server/routers/lambda/session.ts +0 -25
  260. package/src/server/routers/lambda/user.ts +5 -1
  261. package/src/server/services/chunk/index.ts +74 -0
  262. package/src/server/utils/files.ts +9 -0
  263. package/src/services/__tests__/chat.test.ts +18 -20
  264. package/src/services/__tests__/{upload.test.ts → upload_legacy.test.ts} +1 -1
  265. package/src/services/agent.ts +45 -0
  266. package/src/services/chat.ts +17 -15
  267. package/src/services/file/client.test.ts +1 -50
  268. package/src/services/file/client.ts +12 -25
  269. package/src/services/file/server.ts +25 -3
  270. package/src/services/file/type.ts +7 -4
  271. package/src/services/knowledgeBase.ts +34 -0
  272. package/src/services/message/client.test.ts +1 -1
  273. package/src/services/message/client.ts +29 -3
  274. package/src/services/message/index.ts +0 -2
  275. package/src/services/message/server.ts +9 -3
  276. package/src/services/message/type.ts +1 -13
  277. package/src/services/rag.ts +29 -0
  278. package/src/services/session/server.ts +1 -1
  279. package/src/services/upload.ts +89 -84
  280. package/src/services/upload_legacy.ts +104 -0
  281. package/src/services/user/client.ts +7 -2
  282. package/src/services/user/server.ts +6 -2
  283. package/src/services/user/type.ts +3 -2
  284. package/src/store/agent/slices/chat/action.ts +90 -18
  285. package/src/store/agent/slices/chat/initialState.ts +1 -0
  286. package/src/store/agent/slices/chat/selectors.ts +58 -0
  287. package/src/store/chat/slices/builtinTool/action.test.ts +2 -2
  288. package/src/store/chat/slices/builtinTool/action.ts +2 -2
  289. package/src/store/chat/slices/message/action.test.ts +2 -1
  290. package/src/store/chat/slices/message/action.ts +102 -26
  291. package/src/store/chat/slices/message/actions/rag.ts +148 -0
  292. package/src/store/chat/slices/message/initialState.ts +7 -0
  293. package/src/store/chat/slices/message/reducer.ts +6 -2
  294. package/src/store/chat/slices/message/selectors.ts +38 -3
  295. package/src/store/chat/slices/plugin/action.ts +8 -2
  296. package/src/store/chat/slices/portal/action.ts +8 -0
  297. package/src/store/chat/slices/portal/initialState.ts +3 -0
  298. package/src/store/chat/slices/portal/selectors.ts +8 -2
  299. package/src/store/file/initialState.ts +5 -1
  300. package/src/store/file/reducers/uploadFileList.ts +133 -0
  301. package/src/store/file/selectors.ts +3 -0
  302. package/src/store/file/slices/chat/action.test.ts +90 -90
  303. package/src/store/file/slices/chat/action.ts +164 -109
  304. package/src/store/file/slices/chat/initialState.ts +7 -2
  305. package/src/store/file/slices/chat/selectors.test.ts +84 -61
  306. package/src/store/file/slices/chat/selectors.ts +22 -32
  307. package/src/store/file/slices/chunk/action.ts +36 -0
  308. package/src/store/file/slices/chunk/index.ts +3 -0
  309. package/src/store/file/slices/chunk/initialState.ts +15 -0
  310. package/src/store/file/slices/chunk/selectors.ts +10 -0
  311. package/src/store/file/slices/fileManager/action.ts +187 -0
  312. package/src/store/file/slices/fileManager/index.ts +3 -0
  313. package/src/store/file/slices/fileManager/initialState.ts +18 -0
  314. package/src/store/file/slices/fileManager/selectors.ts +58 -0
  315. package/src/store/file/slices/tts/action.test.ts +1 -1
  316. package/src/store/file/slices/tts/action.ts +2 -2
  317. package/src/store/file/slices/upload/action.ts +164 -0
  318. package/src/store/file/store.ts +12 -1
  319. package/src/store/knowledgeBase/index.ts +2 -0
  320. package/src/store/knowledgeBase/initialState.ts +7 -0
  321. package/src/store/knowledgeBase/selectors.ts +1 -0
  322. package/src/store/knowledgeBase/slices/content/action.ts +27 -0
  323. package/src/store/knowledgeBase/slices/content/index.ts +1 -0
  324. package/src/store/knowledgeBase/slices/crud/action.ts +78 -0
  325. package/src/store/knowledgeBase/slices/crud/index.ts +3 -0
  326. package/src/store/knowledgeBase/slices/crud/initialState.ts +12 -0
  327. package/src/store/knowledgeBase/slices/crud/selectors.ts +7 -0
  328. package/src/store/knowledgeBase/store.ts +30 -0
  329. package/src/store/serverConfig/selectors.test.ts +1 -1
  330. package/src/store/user/slices/preference/selectors.ts +8 -0
  331. package/src/store/user/slices/settings/selectors/systemAgent.ts +2 -0
  332. package/src/tools/dalle/Render/Item/ImageFileItem.tsx +3 -23
  333. package/src/types/agent/index.ts +9 -0
  334. package/src/types/asyncTask.ts +31 -0
  335. package/src/types/chunk/document.ts +9 -0
  336. package/src/types/chunk/index.ts +52 -0
  337. package/src/types/files/index.ts +35 -0
  338. package/src/types/files/list.ts +44 -0
  339. package/src/types/files/upload.ts +91 -0
  340. package/src/types/knowledgeBase/index.ts +45 -0
  341. package/src/types/message/index.ts +54 -5
  342. package/src/types/rag.ts +16 -0
  343. package/src/utils/filter.test.ts +2 -0
  344. package/src/utils/server/auth.ts +23 -0
  345. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/LocalFiles.tsx +0 -46
  346. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files.tsx +0 -19
  347. package/src/components/FileList/EditableFileList.tsx +0 -47
  348. package/src/components/FileList/index.ts +0 -2
  349. package/src/components/FileList/type.tsx +0 -7
  350. package/src/database/server/schemas/lobechat/chat.ts +0 -331
  351. package/src/features/ChatInput/ActionBar/FileUpload.tsx +0 -69
  352. package/src/features/ChatInput/useChatInput.ts +0 -45
  353. package/src/features/FileList/EditableFileList.tsx +0 -31
  354. package/src/features/FileList/FileListPreviewer.tsx +0 -17
  355. package/src/features/FileList/index.tsx +0 -2
  356. package/src/types/files.ts +0 -42
@@ -1,99 +1,104 @@
1
1
  import { fileEnv } from '@/config/file';
2
- import { DB_File } from '@/database/client/schemas/files';
2
+ import { FileModel } from '@/database/client/models/file';
3
3
  import { edgeClient } from '@/libs/trpc/client';
4
- import { API_ENDPOINTS } from '@/services/_url';
5
- import { serverConfigSelectors } from '@/store/serverConfig/selectors';
6
- import compressImage from '@/utils/compressImage';
4
+ import { FileMetadata, UploadFileParams } from '@/types/files';
5
+ import { FileUploadState, FileUploadStatus } from '@/types/files/upload';
7
6
  import { uuid } from '@/utils/uuid';
8
7
 
9
8
  class UploadService {
10
- async uploadFile(file: DB_File) {
11
- if (this.enableServer) {
12
- const { data, ...params } = file;
13
- const filename = `${uuid()}.${file.name.split('.').at(-1)}`;
14
-
15
- // 精确到以 h 为单位的 path
16
- const date = (Date.now() / 1000 / 60 / 60).toFixed(0);
17
- const dirname = `${fileEnv.NEXT_PUBLIC_S3_FILE_PATH}/${date}`;
18
- const pathname = `${dirname}/${filename}`;
19
-
20
- const url = await edgeClient.upload.createS3PreSignedUrl.mutate({ pathname });
21
-
22
- const res = await fetch(url, {
23
- body: data,
24
- headers: { 'Content-Type': file.fileType },
25
- method: 'PUT',
9
+ uploadWithProgress = async (
10
+ file: File,
11
+ onProgress: (status: FileUploadStatus, state: FileUploadState) => void,
12
+ ): Promise<FileMetadata> => {
13
+ const xhr = new XMLHttpRequest();
14
+
15
+ const { preSignUrl, ...result } = await this.getSignedUploadUrl(file);
16
+
17
+ let startTime = Date.now();
18
+ xhr.upload.addEventListener('progress', (event) => {
19
+ if (event.lengthComputable) {
20
+ const progress = Number(((event.loaded / event.total) * 100).toFixed(1));
21
+
22
+ const speedInByte = event.loaded / ((Date.now() - startTime) / 1000);
23
+
24
+ onProgress?.('uploading', {
25
+ // if the progress is 100, it means the file is uploaded
26
+ // but the server is still processing it
27
+ // so make it as 99.9 and let users think it's still uploading
28
+ progress: progress === 100 ? 99.9 : progress,
29
+ restTime: (event.total - event.loaded) / speedInByte,
30
+ speed: speedInByte / 1024,
31
+ });
32
+ }
33
+ });
34
+
35
+ xhr.open('PUT', preSignUrl);
36
+ xhr.setRequestHeader('Content-Type', file.type);
37
+ const data = await file.arrayBuffer();
38
+
39
+ await new Promise((resolve, reject) => {
40
+ xhr.addEventListener('load', () => {
41
+ if (xhr.status >= 200 && xhr.status < 300) {
42
+ onProgress('success', {
43
+ progress: 100,
44
+ restTime: 0,
45
+ speed: file.size / ((Date.now() - startTime) / 1000),
46
+ });
47
+ resolve(xhr.response);
48
+ } else {
49
+ reject(xhr.statusText);
50
+ }
26
51
  });
52
+ xhr.addEventListener('error', () => reject(xhr.statusText));
53
+ xhr.send(data);
54
+ });
27
55
 
28
- if (res.ok) {
29
- return {
30
- ...params,
31
- metadata: { date, dirname: dirname, filename: filename, path: pathname },
32
- name: file.name,
33
- saveMode: 'url',
34
- url: pathname,
35
- } as DB_File;
36
- } else {
37
- throw new Error('Upload Error');
38
- }
39
- }
56
+ return result;
57
+ };
40
58
 
41
- // 跳过图片上传测试
42
- const isTestData = file.size === 1;
43
- if (this.isImage(file.fileType) && !isTestData) {
44
- return this.uploadImageFile(file);
45
- }
59
+ uploadToClientDB = async (params: UploadFileParams, file: File) => {
60
+ const fileArrayBuffer = await file.arrayBuffer();
46
61
 
47
62
  // save to local storage
48
63
  // we may want to save to a remote server later
49
- return file;
50
- }
51
-
52
- async uploadImageByUrl(url: string, file: Pick<DB_File, 'name' | 'metadata'>) {
53
- const res = await fetch(API_ENDPOINTS.proxy, { body: url, method: 'POST' });
54
- const data = await res.arrayBuffer();
55
- const fileType = res.headers.get('content-type') || 'image/webp';
56
-
57
- return this.uploadFile({
58
- data,
59
- fileType,
60
- metadata: file.metadata,
61
- name: file.name,
62
- saveMode: 'local',
63
- size: data.byteLength,
64
+ const res = await FileModel.create({
65
+ createdAt: Date.now(),
66
+ ...params,
67
+ data: fileArrayBuffer,
64
68
  });
65
- }
66
-
67
- private isImage(fileType: string) {
68
- const imageRegex = /^image\//;
69
- return imageRegex.test(fileType);
70
- }
71
-
72
- private async uploadImageFile(file: DB_File) {
73
- // 加载图片
74
- const url = file.url || URL.createObjectURL(new Blob([file.data!]));
75
-
76
- const img = new Image();
77
- img.src = url;
78
- await (() =>
79
- new Promise((resolve) => {
80
- img.addEventListener('load', resolve);
81
- }))();
82
-
83
- // 压缩图片
84
- const base64String = compressImage({ img, type: file.fileType });
85
- const binaryString = atob(base64String.split('base64,')[1]);
86
- const uint8Array = Uint8Array.from(binaryString, (char) => char.charCodeAt(0));
87
- file.data = uint8Array.buffer;
88
-
89
- return file;
90
- }
91
-
92
- private get enableServer() {
93
- return serverConfigSelectors.enableUploadFileToServer(
94
- window.global_serverConfigStore.getState(),
95
- );
96
- }
69
+ // arrayBuffer to url
70
+ const base64 = Buffer.from(fileArrayBuffer).toString('base64');
71
+
72
+ return {
73
+ id: res.id,
74
+ url: `data:${params.fileType};base64,${base64}`,
75
+ };
76
+ };
77
+
78
+ private getSignedUploadUrl = async (
79
+ file: File,
80
+ ): Promise<
81
+ FileMetadata & {
82
+ preSignUrl: string;
83
+ }
84
+ > => {
85
+ const filename = `${uuid()}.${file.name.split('.').at(-1)}`;
86
+
87
+ // 精确到以 h 为单位的 path
88
+ const date = (Date.now() / 1000 / 60 / 60).toFixed(0);
89
+ const dirname = `${fileEnv.NEXT_PUBLIC_S3_FILE_PATH}/${date}`;
90
+ const pathname = `${dirname}/${filename}`;
91
+
92
+ const preSignUrl = await edgeClient.upload.createS3PreSignedUrl.mutate({ pathname });
93
+
94
+ return {
95
+ date,
96
+ dirname,
97
+ filename,
98
+ path: pathname,
99
+ preSignUrl,
100
+ };
101
+ };
97
102
  }
98
103
 
99
104
  export const uploadService = new UploadService();
@@ -0,0 +1,104 @@
1
+ import { fileEnv } from '@/config/file';
2
+ import { DB_File } from '@/database/client/schemas/files';
3
+ import { edgeClient } from '@/libs/trpc/client';
4
+ import { API_ENDPOINTS } from '@/services/_url';
5
+ import { serverConfigSelectors } from '@/store/serverConfig/selectors';
6
+ import compressImage from '@/utils/compressImage';
7
+ import { uuid } from '@/utils/uuid';
8
+
9
+ class UploadService {
10
+ async uploadFile(file: DB_File) {
11
+ if (this.enableServer) {
12
+ const { data, ...params } = file;
13
+ const filename = `${uuid()}.${file.name.split('.').at(-1)}`;
14
+
15
+ // 精确到以 h 为单位的 path
16
+ const date = (Date.now() / 1000 / 60 / 60).toFixed(0);
17
+ const dirname = `${fileEnv.NEXT_PUBLIC_S3_FILE_PATH}/${date}`;
18
+ const pathname = `${dirname}/${filename}`;
19
+
20
+ const url = await edgeClient.upload.createS3PreSignedUrl.mutate({ pathname });
21
+
22
+ const res = await fetch(url, {
23
+ body: data,
24
+ headers: { 'Content-Type': file.fileType },
25
+ method: 'PUT',
26
+ });
27
+
28
+ if (res.ok) {
29
+ return {
30
+ ...params,
31
+ metadata: { date, dirname: dirname, filename: filename, path: pathname },
32
+ name: file.name,
33
+ saveMode: 'url',
34
+ url: pathname,
35
+ } as DB_File;
36
+ } else {
37
+ throw new Error('Upload Error');
38
+ }
39
+ }
40
+
41
+ // 跳过图片上传测试
42
+ const isTestData = file.size === 1;
43
+ if (this.isImage(file.fileType) && !isTestData) {
44
+ return this.uploadImageFile(file);
45
+ }
46
+
47
+ // save to local storage
48
+ // we may want to save to a remote server later
49
+ return file;
50
+ }
51
+
52
+ /**
53
+ * @deprecated
54
+ * @param url
55
+ * @param file
56
+ */
57
+ async uploadImageByUrl(url: string, file: Pick<DB_File, 'name' | 'metadata'>) {
58
+ const res = await fetch(API_ENDPOINTS.proxy, { body: url, method: 'POST' });
59
+ const data = await res.arrayBuffer();
60
+ const fileType = res.headers.get('content-type') || 'image/webp';
61
+
62
+ return this.uploadFile({
63
+ data,
64
+ fileType,
65
+ metadata: file.metadata,
66
+ name: file.name,
67
+ saveMode: 'local',
68
+ size: data.byteLength,
69
+ });
70
+ }
71
+
72
+ private isImage(fileType: string) {
73
+ const imageRegex = /^image\//;
74
+ return imageRegex.test(fileType);
75
+ }
76
+
77
+ private async uploadImageFile(file: DB_File) {
78
+ // 加载图片
79
+ const url = file.url || URL.createObjectURL(new Blob([file.data!]));
80
+
81
+ const img = new Image();
82
+ img.src = url;
83
+ await (() =>
84
+ new Promise((resolve) => {
85
+ img.addEventListener('load', resolve);
86
+ }))();
87
+
88
+ // 压缩图片
89
+ const base64String = compressImage({ img, type: file.fileType });
90
+ const binaryString = atob(base64String.split('base64,')[1]);
91
+ const uint8Array = Uint8Array.from(binaryString, (char) => char.charCodeAt(0));
92
+ file.data = uint8Array.buffer;
93
+
94
+ return file;
95
+ }
96
+
97
+ private get enableServer() {
98
+ return serverConfigSelectors.enableUploadFileToServer(
99
+ window.global_serverConfigStore.getState(),
100
+ );
101
+ }
102
+ }
103
+
104
+ export const legacyUploadService = new UploadService();
@@ -3,7 +3,7 @@ import { DeepPartial } from 'utility-types';
3
3
  import { MessageModel } from '@/database/client/models/message';
4
4
  import { SessionModel } from '@/database/client/models/session';
5
5
  import { UserModel } from '@/database/client/models/user';
6
- import { UserInitializationState, UserPreference } from '@/types/user';
6
+ import { UserGuide, UserInitializationState, UserPreference } from '@/types/user';
7
7
  import { UserSettings } from '@/types/user/settings';
8
8
  import { AsyncLocalStorage } from '@/utils/localStorage';
9
9
 
@@ -46,7 +46,12 @@ export class ClientService implements IUserService {
46
46
  return UserModel.updateAvatar(avatar);
47
47
  }
48
48
 
49
- async updatePreference(preference: UserPreference) {
49
+ async updatePreference(preference: Partial<UserPreference>) {
50
50
  await this.preferenceStorage.saveToLocalStorage(preference);
51
51
  }
52
+
53
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
54
+ async updateGuide(guide: Partial<UserGuide>) {
55
+ throw new Error('Method not implemented.');
56
+ }
52
57
  }
@@ -2,7 +2,7 @@ import { DeepPartial } from 'utility-types';
2
2
 
3
3
  import { lambdaClient } from '@/libs/trpc/client';
4
4
  import { IUserService } from '@/services/user/type';
5
- import { UserInitializationState, UserPreference } from '@/types/user';
5
+ import { UserGuide, UserInitializationState, UserPreference } from '@/types/user';
6
6
  import { UserSettings } from '@/types/user/settings';
7
7
 
8
8
  export class ServerService implements IUserService {
@@ -14,10 +14,14 @@ export class ServerService implements IUserService {
14
14
  return lambdaClient.user.makeUserOnboarded.mutate();
15
15
  }
16
16
 
17
- async updatePreference(preference: UserPreference) {
17
+ async updatePreference(preference: Partial<UserPreference>) {
18
18
  return lambdaClient.user.updatePreference.mutate(preference);
19
19
  }
20
20
 
21
+ async updateGuide(guide: Partial<UserGuide>) {
22
+ return lambdaClient.user.updateGuide.mutate(guide);
23
+ }
24
+
21
25
  updateUserSettings = async (value: DeepPartial<UserSettings>, signal?: AbortSignal) => {
22
26
  return lambdaClient.user.updateSettings.mutate(value, { signal });
23
27
  };
@@ -1,11 +1,12 @@
1
1
  import { DeepPartial } from 'utility-types';
2
2
 
3
- import { UserInitializationState, UserPreference } from '@/types/user';
3
+ import { UserGuide, UserInitializationState, UserPreference } from '@/types/user';
4
4
  import { UserSettings } from '@/types/user/settings';
5
5
 
6
6
  export interface IUserService {
7
7
  getUserState: () => Promise<UserInitializationState>;
8
8
  resetUserSettings: () => Promise<any>;
9
- updatePreference: (preference: UserPreference) => Promise<any>;
9
+ updateGuide: (guide: Partial<UserGuide>) => Promise<any>;
10
+ updatePreference: (preference: Partial<UserPreference>) => Promise<any>;
10
11
  updateUserSettings: (patch: DeepPartial<UserSettings>) => Promise<any>;
11
12
  }
@@ -8,10 +8,12 @@ import { MESSAGE_CANCEL_FLAT } from '@/const/message';
8
8
  import { INBOX_SESSION_ID } from '@/const/session';
9
9
  import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
10
10
  import { useClientDataSWR, useOnlyFetchOnceSWR } from '@/libs/swr';
11
+ import { agentService } from '@/services/agent';
11
12
  import { sessionService } from '@/services/session';
12
13
  import { AgentState } from '@/store/agent/slices/chat/initialState';
13
14
  import { useSessionStore } from '@/store/session';
14
15
  import { LobeAgentChatConfig, LobeAgentConfig } from '@/types/agent';
16
+ import { KnowledgeItem } from '@/types/knowledgeBase';
15
17
  import { merge } from '@/utils/merge';
16
18
 
17
19
  import { AgentStore } from '../../store';
@@ -21,35 +23,42 @@ import { agentSelectors } from './selectors';
21
23
  * 助手接口
22
24
  */
23
25
  export interface AgentChatAction {
26
+ addFilesToAgent: (fileIds: string[], boolean?: boolean) => Promise<void>;
27
+ addKnowledgeBaseToAgent: (knowledgeBaseId: string) => Promise<void>;
28
+ internal_createAbortController: (key: keyof AgentState) => AbortController;
29
+
30
+ internal_dispatchAgentMap: (
31
+ id: string,
32
+ config: DeepPartial<LobeAgentConfig>,
33
+ actions?: string,
34
+ ) => void;
35
+ internal_refreshAgentConfig: (id: string) => Promise<void>;
36
+ internal_refreshAgentKnowledge: () => Promise<void>;
37
+ internal_updateAgentConfig: (
38
+ id: string,
39
+ data: DeepPartial<LobeAgentConfig>,
40
+ signal?: AbortSignal,
41
+ ) => Promise<void>;
42
+ removeFileFromAgent: (fileId: string) => Promise<void>;
43
+ removeKnowledgeBaseFromAgent: (knowledgeBaseId: string) => Promise<void>;
44
+
24
45
  removePlugin: (id: string) => void;
46
+ toggleFile: (id: string, open?: boolean) => Promise<void>;
47
+ toggleKnowledgeBase: (id: string, open?: boolean) => Promise<void>;
48
+
25
49
  togglePlugin: (id: string, open?: boolean) => Promise<void>;
26
50
  updateAgentChatConfig: (config: Partial<LobeAgentChatConfig>) => Promise<void>;
27
51
  updateAgentConfig: (config: DeepPartial<LobeAgentConfig>) => Promise<void>;
28
-
29
52
  useFetchAgentConfig: (id: string) => SWRResponse<LobeAgentConfig>;
53
+ useFetchFilesAndKnowledgeBases: () => SWRResponse<KnowledgeItem[]>;
30
54
  useInitAgentStore: (
31
55
  isLogin: boolean | undefined,
32
56
  defaultAgentConfig?: DeepPartial<LobeAgentConfig>,
33
57
  ) => SWRResponse<DeepPartial<LobeAgentConfig>>;
34
-
35
- /* eslint-disable typescript-sort-keys/interface */
36
-
37
- internal_updateAgentConfig: (
38
- id: string,
39
- data: DeepPartial<LobeAgentConfig>,
40
- signal?: AbortSignal,
41
- ) => Promise<void>;
42
- internal_refreshAgentConfig: (id: string) => Promise<void>;
43
- internal_dispatchAgentMap: (
44
- id: string,
45
- config: DeepPartial<LobeAgentConfig>,
46
- actions?: string,
47
- ) => void;
48
- internal_createAbortController: (key: keyof AgentState) => AbortController;
49
- /* eslint-enable */
50
58
  }
51
59
 
52
60
  const FETCH_AGENT_CONFIG_KEY = 'FETCH_AGENT_CONFIG';
61
+ const FETCH_AGENT_KNOWLEDGE_KEY = 'FETCH_AGENT_KNOWLEDGE';
53
62
 
54
63
  export const createChatSlice: StateCreator<
55
64
  AgentStore,
@@ -57,10 +66,59 @@ export const createChatSlice: StateCreator<
57
66
  [],
58
67
  AgentChatAction
59
68
  > = (set, get) => ({
69
+ addFilesToAgent: async (fileIds, enabled) => {
70
+ const { activeAgentId, internal_refreshAgentConfig, internal_refreshAgentKnowledge } = get();
71
+ if (!activeAgentId) return;
72
+ if (fileIds.length === 0) return;
73
+
74
+ await agentService.createAgentFiles(activeAgentId, fileIds, enabled);
75
+ await internal_refreshAgentConfig(get().activeId);
76
+ await internal_refreshAgentKnowledge();
77
+ },
78
+ addKnowledgeBaseToAgent: async (knowledgeBaseId) => {
79
+ const { activeAgentId, internal_refreshAgentConfig, internal_refreshAgentKnowledge } = get();
80
+ if (!activeAgentId) return;
81
+
82
+ await agentService.createAgentKnowledgeBase(activeAgentId, knowledgeBaseId, true);
83
+ await internal_refreshAgentConfig(get().activeId);
84
+ await internal_refreshAgentKnowledge();
85
+ },
86
+ removeFileFromAgent: async (fileId) => {
87
+ const { activeAgentId, internal_refreshAgentConfig, internal_refreshAgentKnowledge } = get();
88
+ if (!activeAgentId) return;
89
+
90
+ await agentService.deleteAgentFile(activeAgentId, fileId);
91
+ await internal_refreshAgentConfig(get().activeId);
92
+ await internal_refreshAgentKnowledge();
93
+ },
94
+ removeKnowledgeBaseFromAgent: async (knowledgeBaseId) => {
95
+ const { activeAgentId, internal_refreshAgentConfig, internal_refreshAgentKnowledge } = get();
96
+ if (!activeAgentId) return;
97
+
98
+ await agentService.deleteAgentKnowledgeBase(activeAgentId, knowledgeBaseId);
99
+ await internal_refreshAgentConfig(get().activeId);
100
+ await internal_refreshAgentKnowledge();
101
+ },
102
+
60
103
  removePlugin: async (id) => {
61
104
  await get().togglePlugin(id, false);
62
105
  },
106
+ toggleFile: async (id, open) => {
107
+ const { activeAgentId, internal_refreshAgentConfig } = get();
108
+ if (!activeAgentId) return;
63
109
 
110
+ await agentService.toggleFile(activeAgentId, id, open);
111
+
112
+ await internal_refreshAgentConfig(get().activeId);
113
+ },
114
+ toggleKnowledgeBase: async (id, open) => {
115
+ const { activeAgentId, internal_refreshAgentConfig } = get();
116
+ if (!activeAgentId) return;
117
+
118
+ await agentService.toggleKnowledgeBase(activeAgentId, id, open);
119
+
120
+ await internal_refreshAgentConfig(get().activeId);
121
+ },
64
122
  togglePlugin: async (id, open) => {
65
123
  const originConfig = agentSelectors.currentAgentConfig(get());
66
124
 
@@ -109,10 +167,22 @@ export const createChatSlice: StateCreator<
109
167
  fallbackData: DEFAULT_AGENT_CONFIG,
110
168
  onSuccess: (data) => {
111
169
  get().internal_dispatchAgentMap(sessionId, data, 'fetch');
170
+ set({ activeAgentId: data.id }, false, 'updateActiveAgentId');
112
171
  },
113
172
  suspense: true,
114
173
  },
115
174
  ),
175
+ useFetchFilesAndKnowledgeBases: () => {
176
+ return useClientDataSWR<KnowledgeItem[]>(
177
+ [FETCH_AGENT_KNOWLEDGE_KEY, get().activeAgentId],
178
+ ([, id]: string[]) => agentService.getFilesAndKnowledgeBases(id),
179
+ {
180
+ fallbackData: [],
181
+ suspense: true,
182
+ },
183
+ );
184
+ },
185
+
116
186
  useInitAgentStore: (isLogin, defaultAgentConfig) =>
117
187
  useOnlyFetchOnceSWR<DeepPartial<LobeAgentConfig>>(
118
188
  !!isLogin ? 'fetchInboxAgentConfig' : null,
@@ -134,7 +204,6 @@ export const createChatSlice: StateCreator<
134
204
  },
135
205
  },
136
206
  ),
137
-
138
207
  /* eslint-disable sort-keys-fix/sort-keys-fix */
139
208
 
140
209
  internal_dispatchAgentMap: (id, config, actions) => {
@@ -167,6 +236,9 @@ export const createChatSlice: StateCreator<
167
236
  await mutate([FETCH_AGENT_CONFIG_KEY, id]);
168
237
  },
169
238
 
239
+ internal_refreshAgentKnowledge: async () => {
240
+ await mutate([FETCH_AGENT_KNOWLEDGE_KEY, get().activeAgentId]);
241
+ },
170
242
  internal_createAbortController: (key) => {
171
243
  const abortController = get()[key] as AbortController;
172
244
  if (abortController) abortController.abort(MESSAGE_CANCEL_FLAT);
@@ -5,6 +5,7 @@ import { AgentSettingsInstance } from '@/features/AgentSetting';
5
5
  import { LobeAgentConfig } from '@/types/agent';
6
6
 
7
7
  export interface AgentState {
8
+ activeAgentId?: string;
8
9
  activeId: string;
9
10
  agentMap: Record<string, DeepPartial<LobeAgentConfig>>;
10
11
  agentSettingInstance?: AgentSettingsInstance | null;
@@ -9,6 +9,7 @@ import {
9
9
  } from '@/const/settings';
10
10
  import { AgentStore } from '@/store/agent';
11
11
  import { LobeAgentChatConfig, LobeAgentConfig, LobeAgentTTSConfig } from '@/types/agent';
12
+ import { KnowledgeItem, KnowledgeType } from '@/types/knowledgeBase';
12
13
  import { merge } from '@/utils/merge';
13
14
 
14
15
  const isInboxSession = (s: AgentStore) => s.activeId === INBOX_SESSION_ID;
@@ -47,6 +48,18 @@ const currentAgentPlugins = (s: AgentStore) => {
47
48
  return config?.plugins || [];
48
49
  };
49
50
 
51
+ const currentAgentKnowledgeBases = (s: AgentStore) => {
52
+ const config = currentAgentConfig(s);
53
+
54
+ return config?.knowledgeBases || [];
55
+ };
56
+
57
+ const currentAgentFiles = (s: AgentStore) => {
58
+ const config = currentAgentConfig(s);
59
+
60
+ return config?.files || [];
61
+ };
62
+
50
63
  const currentAgentTTS = (s: AgentStore): LobeAgentTTSConfig => {
51
64
  const config = currentAgentConfig(s);
52
65
 
@@ -76,21 +89,66 @@ const currentAgentTTSVoice =
76
89
  return currentVoice || 'alloy';
77
90
  };
78
91
 
92
+ const currentEnabledKnowledge = (s: AgentStore) => {
93
+ const knowledgeBases = currentAgentKnowledgeBases(s);
94
+ const files = currentAgentFiles(s);
95
+
96
+ return [
97
+ ...files
98
+ .filter((f) => f.enabled)
99
+ .map((f) => ({ fileType: f.type, id: f.id, name: f.name, type: KnowledgeType.File })),
100
+ ...knowledgeBases
101
+ .filter((k) => k.enabled)
102
+ .map((k) => ({ id: k.id, name: k.name, type: KnowledgeType.KnowledgeBase })),
103
+ ] as KnowledgeItem[];
104
+ };
105
+
79
106
  const hasSystemRole = (s: AgentStore) => {
80
107
  const config = currentAgentConfig(s);
81
108
 
82
109
  return !!config.systemRole;
83
110
  };
84
111
 
112
+ const hasKnowledgeBases = (s: AgentStore) => {
113
+ const knowledgeBases = currentAgentKnowledgeBases(s);
114
+
115
+ return knowledgeBases.length > 0;
116
+ };
117
+
118
+ const hasFiles = (s: AgentStore) => {
119
+ const files = currentAgentFiles(s);
120
+
121
+ return files.length > 0;
122
+ };
123
+
124
+ const hasKnowledge = (s: AgentStore) => hasKnowledgeBases(s) || hasFiles(s);
125
+ const hasEnabledKnowledge = (s: AgentStore) => currentEnabledKnowledge(s).length > 0;
126
+ const currentKnowledgeIds = (s: AgentStore) => {
127
+ return {
128
+ fileIds: currentAgentFiles(s)
129
+ .filter((item) => item.enabled)
130
+ .map((f) => f.id),
131
+ knowledgeBaseIds: currentAgentKnowledgeBases(s)
132
+ .filter((item) => item.enabled)
133
+ .map((k) => k.id),
134
+ };
135
+ };
136
+
85
137
  export const agentSelectors = {
86
138
  currentAgentChatConfig,
87
139
  currentAgentConfig,
140
+ currentAgentFiles,
141
+ currentAgentKnowledgeBases,
88
142
  currentAgentModel,
89
143
  currentAgentModelProvider,
90
144
  currentAgentPlugins,
91
145
  currentAgentSystemRole,
92
146
  currentAgentTTS,
93
147
  currentAgentTTSVoice,
148
+ currentEnabledKnowledge,
149
+ currentKnowledgeIds,
150
+ hasEnabledKnowledge,
151
+ hasKnowledge,
94
152
  hasSystemRole,
95
153
  inboxAgentConfig,
96
154
  inboxAgentModel,
@@ -3,7 +3,7 @@ import { describe, expect, it, vi } from 'vitest';
3
3
 
4
4
  import { fileService } from '@/services/file';
5
5
  import { imageGenerationService } from '@/services/textToImage';
6
- import { uploadService } from '@/services/upload';
6
+ import { legacyUploadService as uploadService } from '@/services/upload_legacy';
7
7
  import { chatSelectors } from '@/store/chat/selectors';
8
8
  import { ChatMessage } from '@/types/message';
9
9
  import { DallEImageItem } from '@/types/tool/dalle';
@@ -37,7 +37,7 @@ describe('chatToolSlice', () => {
37
37
 
38
38
  vi.spyOn(imageGenerationService, 'generateImage').mockResolvedValue(mockUrl);
39
39
  vi.spyOn(uploadService, 'uploadImageByUrl').mockResolvedValue({} as any);
40
- vi.spyOn(fileService, 'createFile').mockResolvedValue({ id: mockId });
40
+ vi.spyOn(fileService, 'createFile').mockResolvedValue({ id: mockId, url: '' });
41
41
  vi.spyOn(result.current, 'toggleDallEImageLoading');
42
42
 
43
43
  await act(async () => {
@@ -4,7 +4,7 @@ import { StateCreator } from 'zustand/vanilla';
4
4
 
5
5
  import { fileService } from '@/services/file';
6
6
  import { imageGenerationService } from '@/services/textToImage';
7
- import { uploadService } from '@/services/upload';
7
+ import { legacyUploadService } from '@/services/upload_legacy';
8
8
  import { chatSelectors } from '@/store/chat/selectors';
9
9
  import { ChatStore } from '@/store/chat/store';
10
10
  import { DallEImageItem } from '@/types/tool/dalle';
@@ -61,7 +61,7 @@ export const chatToolSlice: StateCreator<
61
61
 
62
62
  toggleDallEImageLoading(messageId + params.prompt, false);
63
63
 
64
- uploadService
64
+ legacyUploadService
65
65
  .uploadImageByUrl(url, {
66
66
  metadata: { ...params, originPrompt: originPrompt },
67
67
  name: `${originPrompt || params.prompt}_${index}.png`,