@lobehub/lobehub 2.0.0-next.47 → 2.0.0-next.49

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 (311) hide show
  1. package/.env.example +11 -0
  2. package/CHANGELOG.md +50 -0
  3. package/README.md +1 -1
  4. package/README.zh-CN.md +1 -1
  5. package/apps/desktop/src/main/controllers/AuthCtr.ts +27 -2
  6. package/apps/desktop/src/main/core/infrastructure/ProtocolManager.ts +9 -4
  7. package/changelog/v1.json +17 -0
  8. package/docs/development/database-schema.dbml +2 -0
  9. package/docs/self-hosting/environment-variables/basic.mdx +49 -3
  10. package/docs/self-hosting/environment-variables/basic.zh-CN.mdx +49 -4
  11. package/locales/ar/chat.json +1 -0
  12. package/locales/ar/discover.json +45 -0
  13. package/locales/ar/marketAuth.json +42 -0
  14. package/locales/ar/setting.json +94 -1
  15. package/locales/ar/topic.json +1 -0
  16. package/locales/bg-BG/chat.json +1 -0
  17. package/locales/bg-BG/discover.json +45 -0
  18. package/locales/bg-BG/marketAuth.json +42 -0
  19. package/locales/bg-BG/setting.json +94 -1
  20. package/locales/bg-BG/topic.json +1 -0
  21. package/locales/de-DE/chat.json +1 -0
  22. package/locales/de-DE/discover.json +45 -0
  23. package/locales/de-DE/marketAuth.json +42 -0
  24. package/locales/de-DE/setting.json +94 -1
  25. package/locales/de-DE/topic.json +1 -0
  26. package/locales/en-US/chat.json +1 -0
  27. package/locales/en-US/discover.json +45 -0
  28. package/locales/en-US/marketAuth.json +42 -0
  29. package/locales/en-US/setting.json +94 -1
  30. package/locales/en-US/topic.json +1 -0
  31. package/locales/es-ES/chat.json +1 -0
  32. package/locales/es-ES/discover.json +45 -0
  33. package/locales/es-ES/marketAuth.json +42 -0
  34. package/locales/es-ES/setting.json +94 -1
  35. package/locales/es-ES/topic.json +1 -0
  36. package/locales/fa-IR/chat.json +1 -0
  37. package/locales/fa-IR/discover.json +45 -0
  38. package/locales/fa-IR/marketAuth.json +42 -0
  39. package/locales/fa-IR/setting.json +94 -1
  40. package/locales/fa-IR/topic.json +1 -0
  41. package/locales/fr-FR/chat.json +1 -0
  42. package/locales/fr-FR/discover.json +45 -0
  43. package/locales/fr-FR/marketAuth.json +42 -0
  44. package/locales/fr-FR/setting.json +94 -1
  45. package/locales/fr-FR/topic.json +1 -0
  46. package/locales/it-IT/chat.json +1 -0
  47. package/locales/it-IT/discover.json +45 -0
  48. package/locales/it-IT/marketAuth.json +42 -0
  49. package/locales/it-IT/setting.json +94 -1
  50. package/locales/it-IT/topic.json +1 -0
  51. package/locales/ja-JP/chat.json +1 -0
  52. package/locales/ja-JP/discover.json +45 -0
  53. package/locales/ja-JP/marketAuth.json +42 -0
  54. package/locales/ja-JP/setting.json +94 -1
  55. package/locales/ja-JP/topic.json +1 -0
  56. package/locales/ko-KR/chat.json +1 -0
  57. package/locales/ko-KR/discover.json +45 -0
  58. package/locales/ko-KR/marketAuth.json +42 -0
  59. package/locales/ko-KR/setting.json +94 -1
  60. package/locales/ko-KR/topic.json +1 -0
  61. package/locales/nl-NL/chat.json +1 -0
  62. package/locales/nl-NL/discover.json +45 -0
  63. package/locales/nl-NL/marketAuth.json +42 -0
  64. package/locales/nl-NL/setting.json +94 -1
  65. package/locales/nl-NL/topic.json +1 -0
  66. package/locales/pl-PL/chat.json +1 -0
  67. package/locales/pl-PL/discover.json +45 -0
  68. package/locales/pl-PL/marketAuth.json +42 -0
  69. package/locales/pl-PL/setting.json +94 -1
  70. package/locales/pl-PL/topic.json +1 -0
  71. package/locales/pt-BR/chat.json +1 -0
  72. package/locales/pt-BR/discover.json +45 -0
  73. package/locales/pt-BR/marketAuth.json +42 -0
  74. package/locales/pt-BR/setting.json +94 -1
  75. package/locales/pt-BR/topic.json +1 -0
  76. package/locales/ru-RU/chat.json +1 -0
  77. package/locales/ru-RU/discover.json +45 -0
  78. package/locales/ru-RU/marketAuth.json +42 -0
  79. package/locales/ru-RU/setting.json +94 -1
  80. package/locales/ru-RU/topic.json +1 -0
  81. package/locales/tr-TR/chat.json +1 -0
  82. package/locales/tr-TR/discover.json +45 -0
  83. package/locales/tr-TR/marketAuth.json +42 -0
  84. package/locales/tr-TR/setting.json +94 -1
  85. package/locales/tr-TR/topic.json +1 -0
  86. package/locales/vi-VN/chat.json +1 -0
  87. package/locales/vi-VN/discover.json +45 -0
  88. package/locales/vi-VN/marketAuth.json +42 -0
  89. package/locales/vi-VN/setting.json +94 -1
  90. package/locales/vi-VN/topic.json +1 -0
  91. package/locales/zh-CN/chat.json +1 -0
  92. package/locales/zh-CN/discover.json +45 -0
  93. package/locales/zh-CN/marketAuth.json +42 -0
  94. package/locales/zh-CN/setting.json +94 -1
  95. package/locales/zh-CN/topic.json +1 -0
  96. package/locales/zh-TW/chat.json +1 -0
  97. package/locales/zh-TW/discover.json +45 -0
  98. package/locales/zh-TW/marketAuth.json +42 -0
  99. package/locales/zh-TW/setting.json +94 -1
  100. package/locales/zh-TW/topic.json +1 -0
  101. package/package.json +34 -27
  102. package/packages/agent-runtime/src/core/InterventionChecker.ts +5 -16
  103. package/packages/agent-runtime/src/core/__tests__/InterventionChecker.test.ts +27 -80
  104. package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +32 -13
  105. package/packages/agent-runtime/src/core/runtime.ts +7 -3
  106. package/packages/agent-runtime/src/types/event.ts +2 -1
  107. package/packages/agent-runtime/src/types/generalAgent.ts +1 -0
  108. package/packages/agent-runtime/src/types/instruction.ts +3 -2
  109. package/packages/agent-runtime/src/types/state.ts +3 -1
  110. package/packages/const/src/url.ts +1 -0
  111. package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +4 -1
  112. package/packages/database/migrations/0044_add_tool_intervention.sql +1 -0
  113. package/packages/database/migrations/0044_high_toxin.sql +1 -0
  114. package/packages/database/migrations/0045_add_tool_intervention.sql +1 -0
  115. package/packages/database/migrations/meta/0039_snapshot.json +1 -1
  116. package/packages/database/migrations/meta/0044_snapshot.json +7813 -0
  117. package/packages/database/migrations/meta/0045_snapshot.json +8431 -0
  118. package/packages/database/migrations/meta/_journal.json +14 -0
  119. package/packages/database/src/core/migrations.json +36 -7
  120. package/packages/database/src/models/message.ts +4 -1
  121. package/packages/database/src/models/session.ts +42 -1
  122. package/packages/database/src/schemas/agent.ts +1 -0
  123. package/packages/database/src/schemas/message.ts +5 -8
  124. package/packages/electron-client-ipc/src/events/index.ts +6 -1
  125. package/packages/electron-client-ipc/src/events/remoteServer.ts +8 -0
  126. package/packages/fetch-sse/package.json +29 -0
  127. package/packages/{utils/src/fetch → fetch-sse/src}/__tests__/fetchSSE.test.ts +4 -4
  128. package/packages/{utils/src/fetch → fetch-sse/src}/__tests__/parseError.test.ts +7 -4
  129. package/packages/{utils/src/fetch → fetch-sse/src}/fetchSSE.ts +2 -2
  130. package/packages/{utils/src/fetch → fetch-sse/src}/parseError.ts +3 -3
  131. package/packages/model-bank/src/aiModels/mistral.ts +2 -1
  132. package/packages/model-runtime/src/core/contextBuilders/anthropic.test.ts +17 -11
  133. package/packages/model-runtime/src/core/contextBuilders/anthropic.ts +1 -1
  134. package/packages/model-runtime/src/core/contextBuilders/google.test.ts +1 -1
  135. package/packages/model-runtime/src/core/contextBuilders/google.ts +3 -6
  136. package/packages/model-runtime/src/core/contextBuilders/openai.test.ts +4 -2
  137. package/packages/model-runtime/src/core/contextBuilders/openai.ts +1 -1
  138. package/packages/model-runtime/src/core/openaiCompatibleFactory/createImage.test.ts +1 -1
  139. package/packages/model-runtime/src/core/openaiCompatibleFactory/createImage.ts +1 -1
  140. package/packages/model-runtime/src/core/openaiCompatibleFactory/index.test.ts +3 -6
  141. package/packages/model-runtime/src/core/streams/openai/responsesStream.test.ts +1 -1
  142. package/packages/model-runtime/src/helpers/mergeChatMethodOptions.ts +2 -1
  143. package/packages/model-runtime/src/providers/aihubmix/index.test.ts +1 -1
  144. package/packages/model-runtime/src/providers/anthropic/generateObject.test.ts +1 -1
  145. package/packages/model-runtime/src/providers/anthropic/index.test.ts +1 -1
  146. package/packages/model-runtime/src/providers/baichuan/index.test.ts +1 -1
  147. package/packages/model-runtime/src/providers/bedrock/index.test.ts +1 -1
  148. package/packages/model-runtime/src/providers/bfl/createImage.test.ts +4 -4
  149. package/packages/model-runtime/src/providers/bfl/createImage.ts +1 -1
  150. package/packages/model-runtime/src/providers/cloudflare/index.test.ts +1 -1
  151. package/packages/model-runtime/src/providers/cohere/index.test.ts +1 -1
  152. package/packages/model-runtime/src/providers/google/createImage.test.ts +2 -2
  153. package/packages/model-runtime/src/providers/google/createImage.ts +1 -1
  154. package/packages/model-runtime/src/providers/google/generateObject.test.ts +1 -1
  155. package/packages/model-runtime/src/providers/google/index.test.ts +1 -4
  156. package/packages/model-runtime/src/providers/groq/index.test.ts +1 -1
  157. package/packages/model-runtime/src/providers/hunyuan/index.test.ts +1 -1
  158. package/packages/model-runtime/src/providers/minimax/createImage.test.ts +1 -1
  159. package/packages/model-runtime/src/providers/mistral/index.test.ts +1 -1
  160. package/packages/model-runtime/src/providers/moonshot/index.test.ts +1 -1
  161. package/packages/model-runtime/src/providers/novita/index.test.ts +1 -1
  162. package/packages/model-runtime/src/providers/ollama/index.test.ts +43 -32
  163. package/packages/model-runtime/src/providers/ollama/index.ts +31 -7
  164. package/packages/model-runtime/src/providers/openrouter/index.test.ts +1 -1
  165. package/packages/model-runtime/src/providers/perplexity/index.test.ts +1 -1
  166. package/packages/model-runtime/src/providers/ppio/index.test.ts +1 -1
  167. package/packages/model-runtime/src/providers/qwen/createImage.test.ts +1 -1
  168. package/packages/model-runtime/src/providers/search1api/index.test.ts +1 -1
  169. package/packages/model-runtime/src/providers/siliconcloud/createImage.ts +1 -1
  170. package/packages/model-runtime/src/providers/taichu/index.test.ts +1 -1
  171. package/packages/model-runtime/src/providers/wenxin/index.test.ts +1 -1
  172. package/packages/model-runtime/src/providers/zhipu/index.test.ts +1 -1
  173. package/packages/model-runtime/src/utils/errorResponse.test.ts +1 -1
  174. package/packages/obervability-otel/src/node.ts +15 -1
  175. package/packages/ssrf-safe-fetch/index.browser.ts +14 -0
  176. package/packages/ssrf-safe-fetch/package.json +8 -1
  177. package/packages/types/src/discover/assistants.ts +16 -0
  178. package/packages/types/src/index.ts +1 -0
  179. package/packages/types/src/message/common/base.ts +2 -2
  180. package/packages/types/src/message/common/tools.ts +16 -0
  181. package/packages/types/src/message/db/item.ts +15 -1
  182. package/packages/types/src/message/ui/chat.ts +7 -1
  183. package/packages/types/src/message/ui/params.ts +15 -1
  184. package/packages/types/src/meta.ts +4 -0
  185. package/packages/types/src/session/agentSession.ts +2 -0
  186. package/packages/types/src/tool/intervention.ts +2 -3
  187. package/packages/types/src/user/settings/tool.ts +15 -28
  188. package/packages/utils/src/imageToBase64.ts +17 -10
  189. package/packages/utils/src/index.ts +1 -1
  190. package/renovate.json +28 -11
  191. package/src/app/(backend)/market/agent/[[...segments]]/route.ts +153 -0
  192. package/src/app/(backend)/market/oidc/[[...segments]]/route.ts +207 -0
  193. package/src/app/[variants]/(main)/(mobile)/me/settings/features/useCategory.tsx +1 -0
  194. package/src/app/[variants]/(main)/_layout/Desktop/SideBar/PinList/index.tsx +4 -2
  195. package/src/app/[variants]/(main)/chat/components/topic/features/Topic/TopicListContent/TopicItem/TopicContent.tsx +1 -1
  196. package/src/app/[variants]/(main)/chat/session/features/SessionListContent/List/Item/Actions.tsx +1 -1
  197. package/src/app/[variants]/(main)/chat/settings/features/AgentInfoDescription/index.tsx +349 -0
  198. package/src/app/[variants]/(main)/chat/settings/features/HeaderContent.tsx +2 -2
  199. package/src/app/[variants]/(main)/chat/settings/features/PublishResultModal/index.tsx +64 -0
  200. package/src/app/[variants]/(main)/chat/settings/features/SmartAgentActionButton/MarketPublishButton.tsx +196 -0
  201. package/src/app/[variants]/(main)/chat/settings/features/SmartAgentActionButton/MarketPublishModal.tsx +358 -0
  202. package/src/app/[variants]/(main)/chat/settings/features/SmartAgentActionButton/index.tsx +75 -0
  203. package/src/app/[variants]/(main)/discover/(detail)/assistant/AssistantDetailPage.tsx +11 -2
  204. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/Client.tsx +12 -1
  205. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Nav.tsx +19 -12
  206. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Overview/TagList.tsx +14 -5
  207. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Overview/index.tsx +2 -0
  208. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Related/index.tsx +14 -5
  209. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/SystemRole/TagList.tsx +14 -5
  210. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/SystemRole/index.tsx +43 -29
  211. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Versions/index.tsx +137 -0
  212. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/index.tsx +2 -0
  213. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Header.tsx +9 -10
  214. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Sidebar/ActionButton/AddAgent.tsx +105 -14
  215. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Sidebar/Related/index.tsx +20 -6
  216. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/StatusPage/index.tsx +113 -0
  217. package/src/app/[variants]/(main)/discover/(detail)/features/Breadcrumb.tsx +4 -3
  218. package/src/app/[variants]/(main)/discover/(list)/_layout/Desktop/Nav.tsx +3 -1
  219. package/src/app/[variants]/(main)/discover/(list)/assistant/AssistantPage.tsx +4 -1
  220. package/src/app/[variants]/(main)/discover/(list)/assistant/Client.tsx +6 -2
  221. package/src/app/[variants]/(main)/discover/(list)/assistant/features/Category/index.tsx +7 -3
  222. package/src/app/[variants]/(main)/discover/(list)/assistant/features/List/Item.tsx +13 -2
  223. package/src/app/[variants]/(main)/discover/(list)/assistant/features/MarketSourceSwitch.tsx +64 -0
  224. package/src/app/[variants]/(main)/discover/(list)/features/SortButton/index.tsx +26 -7
  225. package/src/app/[variants]/(main)/profile/_layout/Desktop/index.tsx +10 -10
  226. package/src/app/[variants]/(main)/settings/_layout/type.ts +1 -1
  227. package/src/app/[variants]/(main)/settings/agent/index.tsx +11 -10
  228. package/src/app/[variants]/(main)/settings/common/index.tsx +1 -1
  229. package/src/app/[variants]/(main)/settings/page.tsx +13 -10
  230. package/src/app/[variants]/(main)/settings/provider/ProviderMenu/Item.tsx +35 -36
  231. package/src/app/[variants]/(main)/settings/provider/ProviderMenu/SearchResult.tsx +5 -5
  232. package/src/app/[variants]/(main)/settings/provider/_layout/Desktop/Container.tsx +10 -4
  233. package/src/app/market-auth-callback/layout.tsx +15 -0
  234. package/src/app/market-auth-callback/page.tsx +196 -0
  235. package/src/features/AgentSetting/AgentPrompt/TokenTag.tsx +3 -2
  236. package/src/features/AgentSetting/AgentTTS/SelectWithTTSPreview.tsx +1 -1
  237. package/src/features/AgentSetting/store/action.ts +1 -1
  238. package/src/features/ChatInput/ActionBar/STT/browser.tsx +1 -1
  239. package/src/features/ChatInput/ActionBar/STT/openai.tsx +1 -1
  240. package/src/features/Conversation/Messages/Group/GroupChildren.tsx +20 -15
  241. package/src/features/Conversation/Messages/Group/GroupContext.tsx +15 -0
  242. package/src/features/Conversation/Messages/Group/Tool/Inspector/BuiltinPluginTitle.tsx +2 -4
  243. package/src/features/Conversation/Messages/Group/Tool/Inspector/ToolTitle.tsx +3 -5
  244. package/src/features/Conversation/Messages/Group/Tool/Inspector/index.tsx +19 -7
  245. package/src/features/Conversation/Messages/Group/Tool/Render/Arguments/index.tsx +14 -12
  246. package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/ApprovalActions.tsx +143 -0
  247. package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/KeyValueEditor.tsx +213 -0
  248. package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/ModeSelector.tsx +134 -0
  249. package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/index.tsx +99 -0
  250. package/src/features/Conversation/Messages/Group/Tool/Render/RejectedResponse.tsx +45 -0
  251. package/src/features/Conversation/Messages/Group/Tool/Render/index.tsx +23 -1
  252. package/src/features/Conversation/Messages/Group/Tool/index.tsx +42 -18
  253. package/src/features/Conversation/Messages/Group/Tools.tsx +3 -1
  254. package/src/features/Conversation/components/Extras/TTS/InitPlayer.tsx +1 -1
  255. package/src/features/PluginTag/PluginStatus.tsx +1 -1
  256. package/src/hooks/useAgentOwnershipCheck.ts +143 -0
  257. package/src/instrumentation.node.ts +3 -2
  258. package/src/layout/AuthProvider/MarketAuth/MarketAuthProvider.tsx +364 -0
  259. package/src/layout/AuthProvider/MarketAuth/errors.ts +75 -0
  260. package/src/layout/AuthProvider/MarketAuth/index.ts +2 -0
  261. package/src/layout/AuthProvider/MarketAuth/oidc.ts +382 -0
  262. package/src/layout/AuthProvider/MarketAuth/types.ts +64 -0
  263. package/src/layout/AuthProvider/index.tsx +17 -4
  264. package/src/locales/default/chat.ts +22 -0
  265. package/src/locales/default/common.ts +1 -0
  266. package/src/locales/default/discover.ts +46 -0
  267. package/src/locales/default/index.ts +2 -0
  268. package/src/locales/default/marketAuth.ts +42 -0
  269. package/src/locales/default/setting.ts +94 -1
  270. package/src/locales/default/topic.ts +1 -0
  271. package/src/server/globalConfig/genServerAiProviderConfig.test.ts +5 -5
  272. package/src/server/globalConfig/genServerAiProviderConfig.ts +1 -1
  273. package/src/server/routers/lambda/market/index.ts +36 -14
  274. package/src/server/routers/lambda/message.ts +6 -3
  275. package/src/server/services/discover/index.test.ts +153 -11
  276. package/src/server/services/discover/index.ts +339 -40
  277. package/src/server/services/message/index.ts +13 -0
  278. package/src/server/sitemap.ts +49 -35
  279. package/src/services/_url.ts +15 -1
  280. package/src/services/chat/chat.test.ts +5 -5
  281. package/src/services/chat/clientModelRuntime.test.ts +1 -1
  282. package/src/services/chat/index.ts +6 -6
  283. package/src/services/chat/types.ts +1 -2
  284. package/src/services/discover.ts +16 -5
  285. package/src/services/electron/remoteServer.ts +8 -1
  286. package/src/services/marketApi.ts +124 -0
  287. package/src/services/message/index.ts +17 -2
  288. package/src/services/models.ts +2 -1
  289. package/src/store/chat/agents/GeneralChatAgent.ts +141 -24
  290. package/src/store/chat/agents/__tests__/GeneralChatAgent.test.ts +605 -0
  291. package/src/store/chat/agents/createAgentExecutors.ts +144 -26
  292. package/src/store/chat/agents/createToolEngine.ts +22 -0
  293. package/src/store/chat/slices/aiChat/actions/conversationControl.ts +106 -0
  294. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +54 -26
  295. package/src/store/chat/slices/message/reducer.ts +2 -1
  296. package/src/store/chat/slices/plugin/actions/optimisticUpdate.ts +26 -1
  297. package/src/store/discover/slices/assistant/action.ts +20 -7
  298. package/src/store/user/slices/settings/action.ts +15 -0
  299. package/{packages/utils/src → src/utils}/electron/desktopRemoteRPCFetch.ts +1 -1
  300. package/{packages/utils/src → src/utils/server}/parseModels.ts +1 -2
  301. package/vitest.config.mts +2 -0
  302. package/packages/model-runtime/src/utils/imageToBase64.test.ts +0 -91
  303. package/packages/model-runtime/src/utils/imageToBase64.ts +0 -62
  304. package/src/app/[variants]/(main)/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx +0 -98
  305. package/src/app/[variants]/(main)/chat/settings/features/SubmitAgentButton/index.tsx +0 -35
  306. package/src/app/[variants]/(main)/chat/settings/features/SubmitAgentButton/style.ts +0 -47
  307. /package/packages/{utils/src/fetch → fetch-sse/src}/headers.ts +0 -0
  308. /package/packages/{utils/src/fetch → fetch-sse/src}/index.ts +0 -0
  309. /package/packages/{utils/src/fetch → fetch-sse/src}/request.ts +0 -0
  310. /package/{packages/utils/src → src/utils/server}/__snapshots__/parseModels.test.ts.snap +0 -0
  311. /package/{packages/utils/src → src/utils/server}/parseModels.test.ts +0 -0
@@ -7,6 +7,7 @@ import {
7
7
  } from '@lobechat/const';
8
8
  import {
9
9
  AssistantListResponse,
10
+ AssistantMarketSource,
10
11
  AssistantQueryParams,
11
12
  AssistantSorts,
12
13
  CacheRevalidate,
@@ -60,9 +61,12 @@ export class DiscoverService {
60
61
  constructor({ accessToken }: { accessToken?: string } = {}) {
61
62
  this.market = new MarketSDK({
62
63
  accessToken,
63
- baseURL: process.env.MARKET_BASE_URL,
64
+ baseURL: process.env.NEXT_PUBLIC_MARKET_BASE_URL,
64
65
  });
65
- log('DiscoverService initialized with market baseURL: %s', process.env.MARKET_BASE_URL);
66
+ log(
67
+ 'DiscoverService initialized with market baseURL: %s',
68
+ process.env.NEXT_PUBLIC_MARKET_BASE_URL,
69
+ );
66
70
  }
67
71
 
68
72
  async registerClient({ userAgent }: { userAgent?: string }) {
@@ -102,7 +106,7 @@ export class DiscoverService {
102
106
  async fetchM2MToken(params: { clientId: string; clientSecret: string }) {
103
107
  // 使用传入的客户端凭证创建新的 MarketSDK 实例
104
108
  const tokenMarket = new MarketSDK({
105
- baseURL: process.env.MARKET_BASE_URL,
109
+ baseURL: process.env.NEXT_PUBLIC_MARKET_BASE_URL,
106
110
  clientId: params.clientId,
107
111
  clientSecret: params.clientSecret,
108
112
  });
@@ -208,25 +212,47 @@ export class DiscoverService {
208
212
  return result;
209
213
  };
210
214
 
211
- // ============================== Assistant Market ==============================
215
+ private normalizeAuthorField = (author: unknown): string => {
216
+ if (!author) return '';
217
+
218
+ if (typeof author === 'string') return author;
219
+
220
+ if (typeof author === 'object') {
221
+ const { avatar, url, name } = author as {
222
+ avatar?: unknown;
223
+ name?: unknown;
224
+ url?: unknown;
225
+ };
226
+
227
+ if (typeof name === 'string' && name.length > 0) return name;
228
+ if (typeof avatar === 'string' && avatar.length > 0) return avatar;
229
+ if (typeof url === 'string' && url.length > 0) return url;
230
+ }
212
231
 
213
- private _getAssistantList = async (locale?: string): Promise<DiscoverAssistantItem[]> => {
214
- log('_getAssistantList: locale=%s', locale);
232
+ return '';
233
+ };
234
+
235
+ private isLegacySource = (source?: AssistantMarketSource) => source === 'legacy';
236
+
237
+ private legacyGetAssistantListRaw = async (locale?: string): Promise<DiscoverAssistantItem[]> => {
238
+ log('legacyGetAssistantListRaw: locale=%s', locale);
215
239
  const normalizedLocale = normalizeLocale(locale);
216
240
  const list = await this.assistantStore.getAgentIndex(normalizedLocale);
217
241
  if (!list || !Array.isArray(list)) {
218
- log('_getAssistantList: no valid list found, returning empty array');
242
+ log('legacyGetAssistantListRaw: no valid list found, returning empty array');
219
243
  return [];
220
244
  }
221
245
  const result = list.map(({ meta, ...item }) => ({ ...item, ...meta }));
222
- log('_getAssistantList: returning %d items', result.length);
246
+ log('legacyGetAssistantListRaw: returning %d items', result.length);
223
247
  return result;
224
248
  };
225
249
 
226
- getAssistantCategories = async (params: CategoryListQuery = {}): Promise<CategoryItem[]> => {
227
- log('getAssistantCategories: params=%O', params);
250
+ private legacyGetAssistantCategories = async (
251
+ params: CategoryListQuery = {},
252
+ ): Promise<CategoryItem[]> => {
253
+ log('legacyGetAssistantCategories: params=%O', params);
228
254
  const { q, locale } = params;
229
- let list = await this._getAssistantList(locale);
255
+ let list = await this.legacyGetAssistantListRaw(locale);
230
256
  if (q) {
231
257
  const originalCount = list.length;
232
258
  list = list.filter((item) => {
@@ -238,7 +264,7 @@ export class DiscoverService {
238
264
  .includes(decodeURIComponent(q).toLowerCase());
239
265
  });
240
266
  log(
241
- 'getAssistantCategories: filtered by query "%s", %d -> %d items',
267
+ 'legacyGetAssistantCategories: filtered by query "%s", %d -> %d items',
242
268
  q,
243
269
  originalCount,
244
270
  list.length,
@@ -246,25 +272,26 @@ export class DiscoverService {
246
272
  }
247
273
  const categoryCounts = countBy(list, (item) => item.category);
248
274
  const result = Object.entries(categoryCounts)
249
- .filter(([category]) => Boolean(category)) // 过滤掉空值
275
+ .filter(([category]) => Boolean(category))
250
276
  .map(([category, count]) => ({
251
277
  category,
252
278
  count,
253
279
  }));
254
- log('getAssistantCategories: returning %d categories', result.length);
280
+ log('legacyGetAssistantCategories: returning %d categories', result.length);
255
281
  return result;
256
282
  };
257
283
 
258
- getAssistantDetail = async (params: {
284
+ private legacyGetAssistantDetail = async (params: {
259
285
  identifier: string;
260
286
  locale?: string;
287
+ version?: string;
261
288
  }): Promise<DiscoverAssistantDetail | undefined> => {
262
- log('getAssistantDetail: params=%O', params);
289
+ log('legacyGetAssistantDetail: params=%O', params);
263
290
  const { locale, identifier } = params;
264
291
  const normalizedLocale = normalizeLocale(locale);
265
292
  let data = await this.assistantStore.getAgent(identifier, normalizedLocale);
266
293
  if (!data) {
267
- log('getAssistantDetail: assistant not found for identifier=%s', identifier);
294
+ log('legacyGetAssistantDetail: assistant not found for identifier=%s', identifier);
268
295
  return;
269
296
  }
270
297
  const { meta, ...item } = data;
@@ -274,30 +301,36 @@ export class DiscoverService {
274
301
  locale,
275
302
  page: 1,
276
303
  pageSize: 7,
304
+ source: 'legacy',
277
305
  });
278
306
  const result = {
279
307
  ...assistant,
280
308
  related: list.items.filter((item) => item.identifier !== assistant.identifier).slice(0, 6),
281
309
  };
282
- log('getAssistantDetail: returning assistant with %d related items', result.related.length);
310
+ log(
311
+ 'legacyGetAssistantDetail: returning assistant with %d related items',
312
+ result.related.length,
313
+ );
283
314
  return result;
284
315
  };
285
316
 
286
- getAssistantIdentifiers = async (): Promise<IdentifiersResponse> => {
287
- log('getAssistantIdentifiers: fetching identifiers');
288
- const list = await this._getAssistantList();
317
+ private legacyGetAssistantIdentifiers = async (): Promise<IdentifiersResponse> => {
318
+ log('legacyGetAssistantIdentifiers: fetching identifiers');
319
+ const list = await this.legacyGetAssistantListRaw();
289
320
  const result = list.map((item) => {
290
321
  return {
291
322
  identifier: item.identifier,
292
323
  lastModified: item.createdAt,
293
324
  };
294
325
  });
295
- log('getAssistantIdentifiers: returning %d identifiers', result.length);
326
+ log('legacyGetAssistantIdentifiers: returning %d identifiers', result.length);
296
327
  return result;
297
328
  };
298
329
 
299
- getAssistantList = async (params: AssistantQueryParams = {}): Promise<AssistantListResponse> => {
300
- log('getAssistantList: params=%O', params);
330
+ private legacyGetAssistantList = async (
331
+ params: AssistantQueryParams = {},
332
+ ): Promise<AssistantListResponse> => {
333
+ log('legacyGetAssistantList: params=%O', params);
301
334
  const {
302
335
  locale,
303
336
  category,
@@ -306,14 +339,29 @@ export class DiscoverService {
306
339
  pageSize = 20,
307
340
  q,
308
341
  sort = AssistantSorts.CreatedAt,
342
+ ownerId,
309
343
  } = params;
310
- let list = await this._getAssistantList(locale);
344
+ const currentPage = Number(page) || 1;
345
+ const currentPageSize = Number(pageSize) || 20;
346
+
347
+ if (ownerId) {
348
+ log('legacyGetAssistantList: ownerId filter not supported in legacy source');
349
+ return {
350
+ currentPage,
351
+ items: [],
352
+ pageSize: currentPageSize,
353
+ totalCount: 0,
354
+ totalPages: 0,
355
+ };
356
+ }
357
+
358
+ let list = await this.legacyGetAssistantListRaw(locale);
311
359
  const originalCount = list.length;
312
360
 
313
361
  if (category) {
314
362
  list = list.filter((item) => item.category === category);
315
363
  log(
316
- 'getAssistantList: filtered by category "%s", %d -> %d items',
364
+ 'legacyGetAssistantList: filtered by category "%s", %d -> %d items',
317
365
  category,
318
366
  originalCount,
319
367
  list.length,
@@ -330,11 +378,16 @@ export class DiscoverService {
330
378
  .toLowerCase()
331
379
  .includes(decodeURIComponent(q).toLowerCase());
332
380
  });
333
- log('getAssistantList: filtered by query "%s", %d -> %d items', q, beforeFilter, list.length);
381
+ log(
382
+ 'legacyGetAssistantList: filtered by query "%s", %d -> %d items',
383
+ q,
384
+ beforeFilter,
385
+ list.length,
386
+ );
334
387
  }
335
388
 
336
389
  if (sort) {
337
- log('getAssistantList: sorting by %s %s', sort, order);
390
+ log('legacyGetAssistantList: sorting by %s %s', sort, order);
338
391
  switch (sort) {
339
392
  case AssistantSorts.CreatedAt: {
340
393
  list = list.sort((a, b) => {
@@ -349,9 +402,9 @@ export class DiscoverService {
349
402
  case AssistantSorts.KnowledgeCount: {
350
403
  list = list.sort((a, b) => {
351
404
  if (order === 'asc') {
352
- return a.knowledgeCount - b.knowledgeCount;
405
+ return (a.knowledgeCount || 0) - (b.knowledgeCount || 0);
353
406
  } else {
354
- return b.knowledgeCount - a.knowledgeCount;
407
+ return (b.knowledgeCount || 0) - (a.knowledgeCount || 0);
355
408
  }
356
409
  });
357
410
  break;
@@ -359,9 +412,9 @@ export class DiscoverService {
359
412
  case AssistantSorts.PluginCount: {
360
413
  list = list.sort((a, b) => {
361
414
  if (order === 'asc') {
362
- return a.pluginCount - b.pluginCount;
415
+ return (a.pluginCount || 0) - (b.pluginCount || 0);
363
416
  } else {
364
- return b.pluginCount - a.pluginCount;
417
+ return (b.pluginCount || 0) - (a.pluginCount || 0);
365
418
  }
366
419
  });
367
420
  break;
@@ -369,9 +422,9 @@ export class DiscoverService {
369
422
  case AssistantSorts.TokenUsage: {
370
423
  list = list.sort((a, b) => {
371
424
  if (order === 'asc') {
372
- return a.tokenUsage - b.tokenUsage;
425
+ return (a.tokenUsage || 0) - (b.tokenUsage || 0);
373
426
  } else {
374
- return b.tokenUsage - a.tokenUsage;
427
+ return (b.tokenUsage || 0) - (a.tokenUsage || 0);
375
428
  }
376
429
  });
377
430
  break;
@@ -396,25 +449,271 @@ export class DiscoverService {
396
449
  });
397
450
  break;
398
451
  }
452
+ default: {
453
+ break;
454
+ }
399
455
  }
400
456
  }
401
457
 
458
+ const start = (currentPage - 1) * currentPageSize;
459
+ const end = currentPage * currentPageSize;
402
460
  const result = {
403
- currentPage: page,
404
- items: list.slice((page - 1) * pageSize, page * pageSize),
405
- pageSize,
461
+ currentPage,
462
+ items: list.slice(start, end),
463
+ pageSize: currentPageSize,
406
464
  totalCount: list.length,
407
- totalPages: Math.ceil(list.length / pageSize),
465
+ totalPages: Math.ceil(list.length / currentPageSize),
408
466
  };
409
467
  log(
410
- 'getAssistantList: returning page %d/%d with %d items',
411
- page,
468
+ 'legacyGetAssistantList: returning page %d/%d with %d items',
469
+ currentPage,
412
470
  result.totalPages,
413
471
  result.items.length,
414
472
  );
415
473
  return result;
416
474
  };
417
475
 
476
+ // ============================== Assistant Market ==============================
477
+
478
+ getAssistantCategories = async (
479
+ params: CategoryListQuery & { source?: AssistantMarketSource } = {},
480
+ ): Promise<CategoryItem[]> => {
481
+ log('getAssistantCategories: params=%O', params);
482
+ const { source, ...rest } = params;
483
+ if (this.isLegacySource(source)) {
484
+ return this.legacyGetAssistantCategories(rest);
485
+ }
486
+
487
+ const { q, locale } = rest;
488
+ const normalizedLocale = normalizeLocale(locale);
489
+
490
+ try {
491
+ // @ts-ignore
492
+ const categories = await this.market.agents.getCategories({
493
+ locale: normalizedLocale,
494
+ q,
495
+ });
496
+ log('getAssistantCategories: returning %d categories from market SDK', categories.length);
497
+ return categories;
498
+ } catch (error) {
499
+ log('getAssistantCategories: error fetching from market SDK: %O', error);
500
+ return [];
501
+ }
502
+ };
503
+
504
+ getAssistantDetail = async (params: {
505
+ identifier: string;
506
+ locale?: string;
507
+ source?: AssistantMarketSource;
508
+ version?: string;
509
+ }): Promise<DiscoverAssistantDetail | undefined> => {
510
+ log('getAssistantDetail: params=%O', params);
511
+ const { source, ...rest } = params;
512
+ if (this.isLegacySource(source)) {
513
+ return this.legacyGetAssistantDetail(rest);
514
+ }
515
+
516
+ const { locale, identifier, version } = rest;
517
+ const normalizedLocale = normalizeLocale(locale);
518
+
519
+ try {
520
+ // @ts-ignore
521
+ const data = await this.market.agents.getAgentDetail(identifier, {
522
+ locale: normalizedLocale,
523
+ version,
524
+ });
525
+
526
+ if (!data) {
527
+ log('getAssistantDetail: assistant not found for identifier=%s', identifier);
528
+ return;
529
+ }
530
+
531
+ const normalizedAuthor = this.normalizeAuthorField(data.author);
532
+ const assistant = {
533
+ author: normalizedAuthor || (data.ownerId !== null ? `User${data.ownerId}` : 'Unknown'),
534
+ avatar: data.avatar || normalizedAuthor || '',
535
+ category: (data as any).category || 'general',
536
+ config: data.config || {},
537
+ createdAt: (data as any).createdAt,
538
+ currentVersion: data.version,
539
+ description: (data as any).description || data.summary,
540
+ examples: Array.isArray((data as any).examples)
541
+ ? (data as any).examples.map((example: any) => ({
542
+ content: typeof example === 'string' ? example : example.content || '',
543
+ role: example.role || 'user',
544
+ }))
545
+ : [],
546
+ homepage:
547
+ (data as any).homepage ||
548
+ `https://lobehub.com/discover/assistant/${(data as any).identifier}`,
549
+ identifier: (data as any).identifier,
550
+ knowledgeCount:
551
+ (data.config as any)?.knowledgeBases?.length || (data as any).knowledgeCount || 0,
552
+ pluginCount: (data.config as any)?.plugins?.length || (data as any).pluginCount || 0,
553
+ readme: data.documentationUrl || '',
554
+ schemaVersion: 1,
555
+ status: data.status,
556
+ summary: data.summary || '',
557
+ systemRole: (data.config as any)?.systemRole || '',
558
+ tags: data.tags || [],
559
+ title: (data as any).name || (data as any).identifier,
560
+ tokenUsage: data.tokenUsage || 0,
561
+ versions:
562
+ // @ts-ignore
563
+ data.versions?.map((item) => ({
564
+ createdAt: (item as any).createdAt || item.updatedAt,
565
+ isLatest: item.isLatest,
566
+ isValidated: item.isValidated,
567
+ status: item.status as any,
568
+ version: item.version,
569
+ })) || [],
570
+ };
571
+
572
+ // Get related assistants
573
+ const list = await this.getAssistantList({
574
+ category: assistant.category,
575
+ locale,
576
+ page: 1,
577
+ pageSize: 7,
578
+ source,
579
+ });
580
+
581
+ const result = {
582
+ ...assistant,
583
+ related: list.items.filter((item) => item.identifier !== assistant.identifier).slice(0, 6),
584
+ };
585
+
586
+ log('getAssistantDetail: returning assistant with %d related items', result.related.length);
587
+ return result;
588
+ } catch (error) {
589
+ log('getAssistantDetail: error fetching from market SDK: %O', error);
590
+ return;
591
+ }
592
+ };
593
+
594
+ getAssistantIdentifiers = async (
595
+ params: { source?: AssistantMarketSource } = {},
596
+ ): Promise<IdentifiersResponse> => {
597
+ log('getAssistantIdentifiers: fetching identifiers with params=%O', params);
598
+ if (this.isLegacySource(params.source)) {
599
+ return this.legacyGetAssistantIdentifiers();
600
+ }
601
+
602
+ try {
603
+ // @ts-ignore
604
+ const identifiers = await this.market.agents.getPublishedIdentifiers();
605
+ // @ts-ignore
606
+ const result = identifiers.map((item) => ({
607
+ identifier: item.id,
608
+ lastModified: item.lastModified,
609
+ }));
610
+ log('getAssistantIdentifiers: returning %d identifiers from market SDK', result.length);
611
+ return result;
612
+ } catch (error) {
613
+ log('getAssistantIdentifiers: error fetching from market SDK: %O', error);
614
+ return [];
615
+ }
616
+ };
617
+
618
+ getAssistantList = async (params: AssistantQueryParams = {}): Promise<AssistantListResponse> => {
619
+ log('getAssistantList: params=%O', params);
620
+ const { source, ...rest } = params;
621
+ if (this.isLegacySource(source)) {
622
+ return this.legacyGetAssistantList(rest);
623
+ }
624
+
625
+ const {
626
+ locale,
627
+ category,
628
+ order = 'desc',
629
+ page = 1,
630
+ pageSize = 20,
631
+ q,
632
+ sort = AssistantSorts.CreatedAt,
633
+ ownerId,
634
+ } = rest;
635
+
636
+ try {
637
+ const normalizedLocale = normalizeLocale(locale);
638
+
639
+ let apiSort: 'createdAt' | 'updatedAt' | 'name' = 'createdAt';
640
+ switch (sort) {
641
+ case AssistantSorts.Identifier:
642
+ case AssistantSorts.Title: {
643
+ apiSort = 'name';
644
+ break;
645
+ }
646
+ case AssistantSorts.CreatedAt:
647
+ case AssistantSorts.MyOwn: {
648
+ apiSort = 'createdAt';
649
+ break;
650
+ }
651
+ default: {
652
+ apiSort = 'createdAt';
653
+ }
654
+ }
655
+
656
+ // @ts-ignore
657
+ const data = await this.market.agents.getAgentList({
658
+ category,
659
+ locale: normalizedLocale,
660
+ order,
661
+ ownerId,
662
+ page,
663
+ pageSize,
664
+ q,
665
+ sort: apiSort,
666
+ status: 'published',
667
+ visibility: 'public',
668
+ });
669
+
670
+ const transformedItems: DiscoverAssistantItem[] = (data.items || []).map((item: any) => {
671
+ const normalizedAuthor = this.normalizeAuthorField(item.author);
672
+ return {
673
+ author: normalizedAuthor || (item.ownerId !== null ? `User${item.ownerId}` : 'Unknown'),
674
+ avatar: item.avatar || normalizedAuthor || '',
675
+ category: item.category || 'general',
676
+ config: item.config || {},
677
+ createdAt: item.createdAt || item.updatedAt || new Date().toISOString(),
678
+ description: item.description || item.summary || '',
679
+ homepage: item.homepage || `https://lobehub.com/discover/assistant/${item.identifier}`,
680
+ identifier: item.identifier,
681
+ knowledgeCount: item.knowledgeCount ?? item.config?.knowledgeBases?.length ?? 0,
682
+ pluginCount: item.pluginCount ?? item.config?.plugins?.length ?? 0,
683
+ schemaVersion: item.schemaVersion ?? 1,
684
+ tags: item.tags || [],
685
+ title: item.name || item.identifier,
686
+ tokenUsage: item.tokenUsage || 0,
687
+ };
688
+ });
689
+
690
+ const result: AssistantListResponse = {
691
+ currentPage: data.currentPage || page,
692
+ items: transformedItems,
693
+ pageSize: data.pageSize || pageSize,
694
+ totalCount: data.totalCount || 0,
695
+ totalPages: data.totalPages || 0,
696
+ };
697
+
698
+ log(
699
+ 'getAssistantList: returning page %d/%d with %d items from market SDK',
700
+ result.currentPage,
701
+ result.totalPages,
702
+ result.items.length,
703
+ );
704
+ return result;
705
+ } catch (error) {
706
+ log('getAssistantList: error fetching from market SDK: %O', error);
707
+ return {
708
+ currentPage: page,
709
+ items: [],
710
+ pageSize,
711
+ totalCount: 0,
712
+ totalPages: 0,
713
+ };
714
+ }
715
+ };
716
+
418
717
  // ============================== MCP Market ==============================
419
718
 
420
719
  getMcpCategories = async (params: CategoryListQuery = {}): Promise<CategoryItem[]> => {
@@ -150,6 +150,19 @@ export class MessageService {
150
150
  return this.queryWithSuccess(options);
151
151
  }
152
152
 
153
+ /**
154
+ * Update message plugin and return message list
155
+ * Pattern: update + conditional query
156
+ */
157
+ async updateMessagePlugin(
158
+ id: string,
159
+ value: any,
160
+ options: QueryOptions,
161
+ ): Promise<{ messages?: UIChatMessage[], success: boolean; }> {
162
+ await this.messageModel.updateMessagePlugin(id, value);
163
+ return this.queryWithSuccess(options);
164
+ }
165
+
153
166
  /**
154
167
  * Update message and return message list
155
168
  * Pattern: update + conditional query
@@ -210,20 +210,24 @@ export class Sitemap {
210
210
  const endIndex = startIndex + ITEMS_PER_PAGE;
211
211
  const pageAssistants = list.slice(startIndex, endIndex);
212
212
 
213
- const sitmap = pageAssistants.map((item) =>
214
- this._genSitemap(urlJoin('/discover/assistant', item.identifier), {
215
- lastModified: item?.lastModified || LAST_MODIFIED,
216
- }),
217
- );
213
+ const sitmap = pageAssistants
214
+ .filter((item) => item.identifier) // 过滤掉 identifier 为空的项目
215
+ .map((item) =>
216
+ this._genSitemap(urlJoin('/discover/assistant', item.identifier), {
217
+ lastModified: item?.lastModified || LAST_MODIFIED,
218
+ }),
219
+ );
218
220
  return flatten(sitmap);
219
221
  }
220
222
 
221
223
  // 如果没有指定页数,返回所有(向后兼容)
222
- const sitmap = list.map((item) =>
223
- this._genSitemap(urlJoin('/discover/assistant', item.identifier), {
224
- lastModified: item?.lastModified || LAST_MODIFIED,
225
- }),
226
- );
224
+ const sitmap = list
225
+ .filter((item) => item.identifier) // 过滤掉 identifier 为空的项目
226
+ .map((item) =>
227
+ this._genSitemap(urlJoin('/discover/assistant', item.identifier), {
228
+ lastModified: item?.lastModified || LAST_MODIFIED,
229
+ }),
230
+ );
227
231
  return flatten(sitmap);
228
232
  }
229
233
 
@@ -235,20 +239,24 @@ export class Sitemap {
235
239
  const endIndex = startIndex + ITEMS_PER_PAGE;
236
240
  const pagePlugins = list.slice(startIndex, endIndex);
237
241
 
238
- const sitmap = pagePlugins.map((item) =>
239
- this._genSitemap(urlJoin('/discover/plugin', item.identifier), {
240
- lastModified: item?.lastModified || LAST_MODIFIED,
241
- }),
242
- );
242
+ const sitmap = pagePlugins
243
+ .filter((item) => item.identifier) // 过滤掉 identifier 为空的项目
244
+ .map((item) =>
245
+ this._genSitemap(urlJoin('/discover/plugin', item.identifier), {
246
+ lastModified: item?.lastModified || LAST_MODIFIED,
247
+ }),
248
+ );
243
249
  return flatten(sitmap);
244
250
  }
245
251
 
246
252
  // 如果没有指定页数,返回所有(向后兼容)
247
- const sitmap = list.map((item) =>
248
- this._genSitemap(urlJoin('/discover/plugin', item.identifier), {
249
- lastModified: item?.lastModified || LAST_MODIFIED,
250
- }),
251
- );
253
+ const sitmap = list
254
+ .filter((item) => item.identifier) // 过滤掉 identifier 为空的项目
255
+ .map((item) =>
256
+ this._genSitemap(urlJoin('/discover/plugin', item.identifier), {
257
+ lastModified: item?.lastModified || LAST_MODIFIED,
258
+ }),
259
+ );
252
260
  return flatten(sitmap);
253
261
  }
254
262
 
@@ -260,30 +268,36 @@ export class Sitemap {
260
268
  const endIndex = startIndex + ITEMS_PER_PAGE;
261
269
  const pageModels = list.slice(startIndex, endIndex);
262
270
 
263
- const sitmap = pageModels.map((item) =>
264
- this._genSitemap(urlJoin('/discover/model', item.identifier), {
265
- lastModified: item?.lastModified || LAST_MODIFIED,
266
- }),
267
- );
271
+ const sitmap = pageModels
272
+ .filter((item) => item.identifier) // 过滤掉 identifier 为空的项目
273
+ .map((item) =>
274
+ this._genSitemap(urlJoin('/discover/model', item.identifier), {
275
+ lastModified: item?.lastModified || LAST_MODIFIED,
276
+ }),
277
+ );
268
278
  return flatten(sitmap);
269
279
  }
270
280
 
271
281
  // 如果没有指定页数,返回所有(向后兼容)
272
- const sitmap = list.map((item) =>
273
- this._genSitemap(urlJoin('/discover/model', item.identifier), {
274
- lastModified: item?.lastModified || LAST_MODIFIED,
275
- }),
276
- );
282
+ const sitmap = list
283
+ .filter((item) => item.identifier) // 过滤掉 identifier 为空的项目
284
+ .map((item) =>
285
+ this._genSitemap(urlJoin('/discover/model', item.identifier), {
286
+ lastModified: item?.lastModified || LAST_MODIFIED,
287
+ }),
288
+ );
277
289
  return flatten(sitmap);
278
290
  }
279
291
 
280
292
  async getProviders(): Promise<MetadataRoute.Sitemap> {
281
293
  const list = await this.discoverService.getProviderIdentifiers();
282
- const sitmap = list.map((item) =>
283
- this._genSitemap(urlJoin('/discover/provider', item.identifier), {
284
- lastModified: item?.lastModified || LAST_MODIFIED,
285
- }),
286
- );
294
+ const sitmap = list
295
+ .filter((item) => item.identifier) // 过滤掉 identifier 为空的项目
296
+ .map((item) =>
297
+ this._genSitemap(urlJoin('/discover/provider', item.identifier), {
298
+ lastModified: item?.lastModified || LAST_MODIFIED,
299
+ }),
300
+ );
287
301
  return flatten(sitmap);
288
302
  }
289
303