@lobehub/lobehub 2.0.0-next.337 → 2.0.0-next.339

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 (270) hide show
  1. package/.gitattributes +35 -0
  2. package/CHANGELOG.md +69 -0
  3. package/changelog/v1.json +24 -0
  4. package/locales/ar/plugin.json +12 -2
  5. package/locales/ar/providers.json +1 -0
  6. package/locales/ar/setting.json +77 -1
  7. package/locales/bg-BG/models.json +5 -10
  8. package/locales/bg-BG/plugin.json +12 -2
  9. package/locales/bg-BG/providers.json +1 -0
  10. package/locales/bg-BG/setting.json +78 -2
  11. package/locales/de-DE/models.json +51 -9
  12. package/locales/de-DE/plugin.json +12 -2
  13. package/locales/de-DE/providers.json +1 -0
  14. package/locales/de-DE/setting.json +78 -2
  15. package/locales/en-US/models.json +11 -10
  16. package/locales/en-US/plugin.json +14 -4
  17. package/locales/en-US/providers.json +1 -0
  18. package/locales/en-US/setting.json +97 -2
  19. package/locales/es-ES/plugin.json +12 -2
  20. package/locales/es-ES/providers.json +1 -0
  21. package/locales/es-ES/setting.json +78 -2
  22. package/locales/fa-IR/plugin.json +12 -2
  23. package/locales/fa-IR/providers.json +1 -0
  24. package/locales/fa-IR/setting.json +78 -2
  25. package/locales/fr-FR/plugin.json +12 -2
  26. package/locales/fr-FR/providers.json +1 -0
  27. package/locales/fr-FR/setting.json +78 -2
  28. package/locales/it-IT/plugin.json +12 -2
  29. package/locales/it-IT/providers.json +1 -0
  30. package/locales/it-IT/setting.json +78 -2
  31. package/locales/ja-JP/plugin.json +12 -2
  32. package/locales/ja-JP/providers.json +1 -0
  33. package/locales/ja-JP/setting.json +78 -2
  34. package/locales/ko-KR/plugin.json +12 -2
  35. package/locales/ko-KR/providers.json +1 -0
  36. package/locales/ko-KR/setting.json +78 -2
  37. package/locales/nl-NL/models.json +4 -9
  38. package/locales/nl-NL/plugin.json +12 -2
  39. package/locales/nl-NL/providers.json +1 -0
  40. package/locales/nl-NL/setting.json +78 -2
  41. package/locales/pl-PL/plugin.json +12 -2
  42. package/locales/pl-PL/providers.json +1 -0
  43. package/locales/pl-PL/setting.json +78 -2
  44. package/locales/pt-BR/plugin.json +12 -2
  45. package/locales/pt-BR/providers.json +1 -0
  46. package/locales/pt-BR/setting.json +78 -2
  47. package/locales/ru-RU/plugin.json +12 -2
  48. package/locales/ru-RU/providers.json +1 -0
  49. package/locales/ru-RU/setting.json +78 -2
  50. package/locales/tr-TR/plugin.json +12 -2
  51. package/locales/tr-TR/providers.json +1 -0
  52. package/locales/tr-TR/setting.json +78 -2
  53. package/locales/vi-VN/plugin.json +12 -2
  54. package/locales/vi-VN/providers.json +1 -0
  55. package/locales/vi-VN/setting.json +77 -1
  56. package/locales/zh-CN/auth.json +1 -0
  57. package/locales/zh-CN/plugin.json +12 -2
  58. package/locales/zh-CN/providers.json +1 -0
  59. package/locales/zh-CN/setting.json +97 -2
  60. package/locales/zh-TW/plugin.json +12 -2
  61. package/locales/zh-TW/providers.json +1 -0
  62. package/locales/zh-TW/setting.json +78 -2
  63. package/package.json +1 -1
  64. package/packages/agent-runtime/src/groupOrchestration/GroupOrchestrationSupervisor.ts +2 -0
  65. package/packages/agent-runtime/src/groupOrchestration/__tests__/GroupOrchestrationSupervisor.test.ts +3 -1
  66. package/packages/agent-runtime/src/groupOrchestration/types.ts +5 -0
  67. package/packages/const/src/index.ts +1 -0
  68. package/packages/const/src/klavis.ts +144 -0
  69. package/packages/const/src/lobehubSkill.ts +34 -0
  70. package/packages/const/src/recommendedSkill.ts +17 -0
  71. package/packages/model-runtime/src/core/contextBuilders/anthropic.test.ts +38 -0
  72. package/packages/model-runtime/src/core/contextBuilders/anthropic.ts +20 -1
  73. package/packages/model-runtime/src/core/contextBuilders/google.test.ts +42 -0
  74. package/packages/model-runtime/src/core/contextBuilders/google.ts +17 -0
  75. package/packages/model-runtime/src/providers/google/index.ts +14 -14
  76. package/packages/model-runtime/src/providers/moonshot/index.ts +1 -1
  77. package/packages/model-runtime/src/providers/openai/index.ts +3 -3
  78. package/packages/types/src/discover/index.ts +1 -1
  79. package/scripts/electronWorkflow/modifiers/dynamicToStatic.mts +273 -0
  80. package/scripts/electronWorkflow/modifiers/index.mts +10 -0
  81. package/scripts/electronWorkflow/modifiers/nextConfig.mts +1 -0
  82. package/scripts/electronWorkflow/modifiers/nextDynamicToStatic.mts +233 -0
  83. package/scripts/electronWorkflow/modifiers/removeSuspense.mts +124 -0
  84. package/scripts/electronWorkflow/modifiers/routes.mts +14 -2
  85. package/scripts/electronWorkflow/modifiers/settingsContentToStatic.mts +148 -0
  86. package/scripts/electronWorkflow/modifiers/wrapChildrenWithClientOnly.mts +73 -0
  87. package/src/app/[variants]/(main)/agent/cron/[cronId]/CronConfig.ts +16 -16
  88. package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobSaveButton.tsx +1 -1
  89. package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobScheduleConfig.tsx +5 -2
  90. package/src/app/[variants]/(main)/community/features/Search.tsx +1 -1
  91. package/src/app/[variants]/(main)/home/features/InputArea/SkillInstallBanner.tsx +131 -0
  92. package/src/app/[variants]/(main)/home/features/InputArea/index.tsx +34 -27
  93. package/src/app/[variants]/(main)/settings/features/SettingHeader.tsx +8 -4
  94. package/src/app/[variants]/(main)/settings/features/SettingsContent.tsx +3 -0
  95. package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +6 -0
  96. package/src/{features/PluginStore/InstalledList/List/Item/Action.tsx → app/[variants]/(main)/settings/skill/features/Actions.tsx} +45 -40
  97. package/src/app/[variants]/(main)/settings/skill/features/KlavisSkillItem.tsx +353 -0
  98. package/src/app/[variants]/(main)/settings/skill/features/LobehubSkillItem.tsx +344 -0
  99. package/src/app/[variants]/(main)/settings/skill/features/McpSkillItem.tsx +116 -0
  100. package/src/app/[variants]/(main)/settings/skill/features/SkillList.tsx +244 -0
  101. package/src/app/[variants]/(main)/settings/skill/index.tsx +35 -0
  102. package/src/app/[variants]/(mobile)/router/mobileRouter.config.tsx +27 -0
  103. package/src/app/[variants]/(mobile)/settings/_layout/Header.tsx +8 -17
  104. package/src/app/[variants]/(mobile)/settings/_layout/index.tsx +6 -1
  105. package/src/app/[variants]/(mobile)/settings/provider/_layout/index.tsx +22 -0
  106. package/src/components/Plugins/PluginTag.tsx +23 -35
  107. package/src/components/client/ClientOnly.tsx +6 -2
  108. package/src/features/AgentSetting/AgentPlugin/index.tsx +2 -2
  109. package/src/features/ChatInput/ActionBar/Tools/KlavisServerItem.tsx +8 -32
  110. package/src/features/ChatInput/ActionBar/Tools/LobehubSkillServerItem.tsx +8 -30
  111. package/src/features/ChatInput/ActionBar/Tools/PopoverContent.tsx +48 -59
  112. package/src/features/ChatInput/ActionBar/Tools/index.tsx +5 -23
  113. package/src/features/ChatInput/ActionBar/Tools/useControls.tsx +158 -56
  114. package/src/features/IntegrationDetailModal/index.tsx +293 -0
  115. package/src/features/{PluginStore/McpList/Detail → MCP/MCPDetail}/index.tsx +15 -6
  116. package/src/features/MCP/MCPSettings/McpSettingsModal.tsx +58 -0
  117. package/src/features/{PluginStore/McpList/Detail/Settings → MCP/MCPSettings}/index.tsx +39 -27
  118. package/src/features/PluginDetailModal/index.tsx +2 -2
  119. package/src/features/PluginDevModal/index.tsx +16 -40
  120. package/src/features/ProfileEditor/AgentTool.tsx +2 -2
  121. package/src/features/ProtocolUrlHandler/InstallPlugin/OfficialPluginInstallModal/index.tsx +1 -1
  122. package/src/features/{PluginStore/AddPluginButton.tsx → SkillStore/AddSkillButton.tsx} +3 -3
  123. package/src/features/SkillStore/CommunityList/Item.tsx +158 -0
  124. package/src/features/SkillStore/CommunityList/index.tsx +101 -0
  125. package/src/features/SkillStore/Content.tsx +59 -0
  126. package/src/features/{PluginStore/PluginEmpty.tsx → SkillStore/Empty.tsx} +8 -8
  127. package/src/features/SkillStore/LobeHubList/Item.tsx +118 -0
  128. package/src/features/SkillStore/LobeHubList/index.tsx +187 -0
  129. package/src/features/SkillStore/LobeHubList/useSkillConnect.ts +239 -0
  130. package/src/features/SkillStore/Search/index.tsx +43 -0
  131. package/src/features/{PluginStore → SkillStore}/index.tsx +14 -10
  132. package/src/features/SkillStore/style.ts +27 -0
  133. package/src/locales/default/plugin.ts +15 -4
  134. package/src/locales/default/setting.ts +204 -2
  135. package/src/services/chat/mecha/agentConfigResolver.test.ts +197 -0
  136. package/src/services/chat/mecha/agentConfigResolver.ts +44 -17
  137. package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +40 -37
  138. package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +78 -0
  139. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +50 -16
  140. package/src/store/global/initialState.ts +1 -0
  141. package/src/store/tool/slices/lobehubSkillStore/action.test.ts +914 -0
  142. package/src/store/tool/slices/lobehubSkillStore/selectors.test.ts +548 -0
  143. package/.cursor/skills/vercel-react-best-practices/AGENTS.md +0 -2410
  144. package/.cursor/skills/vercel-react-best-practices/SKILL.md +0 -125
  145. package/.cursor/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
  146. package/.cursor/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -49
  147. package/.cursor/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -38
  148. package/.cursor/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -80
  149. package/.cursor/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -36
  150. package/.cursor/skills/vercel-react-best-practices/rules/async-parallel.md +0 -28
  151. package/.cursor/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
  152. package/.cursor/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -59
  153. package/.cursor/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
  154. package/.cursor/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
  155. package/.cursor/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
  156. package/.cursor/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -50
  157. package/.cursor/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
  158. package/.cursor/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
  159. package/.cursor/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
  160. package/.cursor/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
  161. package/.cursor/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -57
  162. package/.cursor/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
  163. package/.cursor/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
  164. package/.cursor/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
  165. package/.cursor/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
  166. package/.cursor/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -50
  167. package/.cursor/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
  168. package/.cursor/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -37
  169. package/.cursor/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
  170. package/.cursor/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
  171. package/.cursor/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
  172. package/.cursor/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
  173. package/.cursor/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -26
  174. package/.cursor/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
  175. package/.cursor/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
  176. package/.cursor/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
  177. package/.cursor/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
  178. package/.cursor/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
  179. package/.cursor/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
  180. package/.cursor/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
  181. package/.cursor/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
  182. package/.cursor/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
  183. package/.cursor/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
  184. package/.cursor/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
  185. package/.cursor/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -44
  186. package/.cursor/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
  187. package/.cursor/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
  188. package/.cursor/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
  189. package/.cursor/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -76
  190. package/.cursor/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
  191. package/.cursor/skills/vercel-react-best-practices/rules/server-serialization.md +0 -38
  192. package/src/features/PluginStore/Content.tsx +0 -54
  193. package/src/features/PluginStore/InstalledList/Detail/CustomPluginEmptyState.tsx +0 -79
  194. package/src/features/PluginStore/InstalledList/Detail/index.tsx +0 -21
  195. package/src/features/PluginStore/InstalledList/List/Item/index.tsx +0 -61
  196. package/src/features/PluginStore/InstalledList/List/index.tsx +0 -72
  197. package/src/features/PluginStore/InstalledList/index.tsx +0 -90
  198. package/src/features/PluginStore/McpList/List/Action.tsx +0 -119
  199. package/src/features/PluginStore/McpList/List/Item.tsx +0 -83
  200. package/src/features/PluginStore/McpList/List/index.tsx +0 -93
  201. package/src/features/PluginStore/McpList/index.tsx +0 -58
  202. package/src/features/PluginStore/PluginList/Detail/DetailProvider.tsx +0 -19
  203. package/src/features/PluginStore/PluginList/Detail/EmptyState.tsx +0 -56
  204. package/src/features/PluginStore/PluginList/Detail/Header.tsx +0 -130
  205. package/src/features/PluginStore/PluginList/Detail/InstallDetail/Nav.tsx +0 -73
  206. package/src/features/PluginStore/PluginList/Detail/InstallDetail/Settings.tsx +0 -19
  207. package/src/features/PluginStore/PluginList/Detail/InstallDetail/Tools.tsx +0 -111
  208. package/src/features/PluginStore/PluginList/Detail/InstallDetail/index.tsx +0 -24
  209. package/src/features/PluginStore/PluginList/Detail/Loading.tsx +0 -42
  210. package/src/features/PluginStore/PluginList/Detail/TagList.tsx +0 -35
  211. package/src/features/PluginStore/PluginList/Detail/index.tsx +0 -39
  212. package/src/features/PluginStore/PluginList/Detail/useCategory.tsx +0 -76
  213. package/src/features/PluginStore/PluginList/List/Action.tsx +0 -78
  214. package/src/features/PluginStore/PluginList/List/Item.tsx +0 -92
  215. package/src/features/PluginStore/PluginList/List/index.tsx +0 -94
  216. package/src/features/PluginStore/PluginList/index.tsx +0 -46
  217. package/src/features/PluginStore/Search/index.tsx +0 -40
  218. /package/{.codex/skills → .agents}/vercel-react-best-practices/AGENTS.md +0 -0
  219. /package/{.codex/skills → .agents}/vercel-react-best-practices/SKILL.md +0 -0
  220. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -0
  221. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/advanced-use-latest.md +0 -0
  222. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/async-api-routes.md +0 -0
  223. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/async-defer-await.md +0 -0
  224. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/async-dependencies.md +0 -0
  225. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/async-parallel.md +0 -0
  226. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -0
  227. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -0
  228. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/bundle-conditional.md +0 -0
  229. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -0
  230. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -0
  231. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/bundle-preload.md +0 -0
  232. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/client-event-listeners.md +0 -0
  233. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -0
  234. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -0
  235. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/client-swr-dedup.md +0 -0
  236. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -0
  237. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-cache-function-results.md +0 -0
  238. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-cache-property-access.md +0 -0
  239. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-cache-storage.md +0 -0
  240. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-combine-iterations.md +0 -0
  241. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-early-exit.md +0 -0
  242. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -0
  243. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-index-maps.md +0 -0
  244. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-length-check-first.md +0 -0
  245. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-min-max-loop.md +0 -0
  246. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -0
  247. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -0
  248. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-activity.md +0 -0
  249. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -0
  250. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -0
  251. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -0
  252. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -0
  253. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -0
  254. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -0
  255. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -0
  256. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-dependencies.md +0 -0
  257. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-derived-state.md +0 -0
  258. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -0
  259. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -0
  260. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-memo.md +0 -0
  261. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/rerender-transitions.md +0 -0
  262. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -0
  263. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/server-cache-lru.md +0 -0
  264. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/server-cache-react.md +0 -0
  265. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -0
  266. /package/{.codex/skills → .agents}/vercel-react-best-practices/rules/server-serialization.md +0 -0
  267. /package/src/{features/PluginStore/InstalledList → app/[variants]/(main)/settings/skill/features}/EditCustomPlugin.tsx +0 -0
  268. /package/src/features/{PluginStore/McpList/Detail → MCP/MCPDetail}/Loading.tsx +0 -0
  269. /package/src/features/{PluginStore → SkillStore}/Loading.tsx +0 -0
  270. /package/src/features/{PluginStore → SkillStore}/VirtuosoLoading.tsx +0 -0
@@ -2,12 +2,22 @@ import { IconType, SiCaldotcom, SiGithub } from '@icons-pack/react-simple-icons'
2
2
  import { Klavis } from 'klavis';
3
3
 
4
4
  export interface KlavisServerType {
5
+ /**
6
+ * Author/Developer of the integration
7
+ */
8
+ author: string;
9
+ /**
10
+ * Author's website URL
11
+ */
12
+ authorUrl?: string;
13
+ description: string;
5
14
  icon: string | IconType;
6
15
  /**
7
16
  * Identifier used for storage in database (e.g., 'google-calendar')
8
17
  * Format: lowercase, spaces replaced with hyphens
9
18
  */
10
19
  identifier: string;
20
+ introduction: string;
11
21
  label: string;
12
22
  /**
13
23
  * Server name used to call Klavis API (e.g., 'Google Calendar')
@@ -17,141 +27,275 @@ export interface KlavisServerType {
17
27
 
18
28
  export const KLAVIS_SERVER_TYPES: KlavisServerType[] = [
19
29
  {
30
+ author: 'Klavis',
31
+ authorUrl: 'https://klavis.io',
32
+ description: 'Gmail is a free email service provided by Google',
20
33
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/gmail.svg',
21
34
  identifier: 'gmail',
35
+ introduction:
36
+ 'Bring the power of Gmail directly into your AI assistant. Read, compose, and send emails, search your inbox, manage labels, and organize your communications—all through natural conversation.',
22
37
  label: 'Gmail',
23
38
  serverName: Klavis.McpServerName.Gmail,
24
39
  },
25
40
  {
41
+ author: 'Klavis',
42
+ authorUrl: 'https://klavis.io',
43
+ description: 'Google Calendar is a time-management and scheduling calendar service',
26
44
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/googlecalendar.svg',
27
45
  identifier: 'google-calendar',
46
+ introduction:
47
+ 'Integrate Google Calendar to view, create, and manage your events seamlessly. Schedule meetings, set reminders, check availability, and coordinate your time—all through natural language commands.',
28
48
  label: 'Google Calendar',
29
49
  serverName: Klavis.McpServerName.GoogleCalendar,
30
50
  },
31
51
  {
52
+ author: 'Klavis',
53
+ authorUrl: 'https://klavis.io',
54
+ description: 'Notion is a collaborative productivity and note-taking application',
32
55
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/notion.svg',
33
56
  identifier: 'notion',
57
+ introduction:
58
+ 'Connect to Notion to access and manage your workspace. Create pages, search content, update databases, and organize your knowledge base—all through natural conversation with your AI assistant.',
34
59
  label: 'Notion',
35
60
  serverName: Klavis.McpServerName.Notion,
36
61
  },
37
62
  {
63
+ author: 'Klavis',
64
+ authorUrl: 'https://klavis.io',
65
+ description:
66
+ 'Airtable is a cloud-based database and spreadsheet platform that combines the flexibility of a spreadsheet with the power of a database, enabling teams to organize, track, and collaborate on projects with customizable views and powerful automation features',
38
67
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/airtable.svg',
39
68
  identifier: 'airtable',
69
+ introduction:
70
+ 'Integrate with Airtable to manage your databases and workflows. Query records, create entries, update data, and automate operations with customizable views and powerful tracking features.',
40
71
  label: 'Airtable',
41
72
  serverName: Klavis.McpServerName.Airtable,
42
73
  },
43
74
  {
75
+ author: 'Klavis',
76
+ authorUrl: 'https://klavis.io',
77
+ description:
78
+ 'Google Sheets is a web-based spreadsheet application that allows users to create, edit, and collaborate on spreadsheets online',
44
79
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/googlesheets.svg',
45
80
  identifier: 'google-sheets',
81
+ introduction:
82
+ 'Connect to Google Sheets to read, write, and analyze spreadsheet data. Perform calculations, generate reports, create charts, and manage tabular data collaboratively with AI assistance.',
46
83
  label: 'Google Sheets',
47
84
  serverName: Klavis.McpServerName.GoogleSheets,
48
85
  },
49
86
  {
87
+ author: 'Klavis',
88
+ authorUrl: 'https://klavis.io',
89
+ description:
90
+ 'Google Docs is a word processor included as part of the free, web-based Google Docs Editors suite',
50
91
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/googledocs.svg',
51
92
  identifier: 'google-docs',
93
+ introduction:
94
+ 'Integrate with Google Docs to create, edit, and manage documents. Write content, format text, collaborate in real-time, and access your documents through natural conversation.',
52
95
  label: 'Google Docs',
53
96
  serverName: Klavis.McpServerName.GoogleDocs,
54
97
  },
55
98
  {
99
+ author: 'Klavis',
100
+ authorUrl: 'https://klavis.io',
101
+ description: 'Enhanced GitHub MCP Server',
56
102
  icon: SiGithub,
57
103
  identifier: 'github',
104
+ introduction:
105
+ 'Connect to GitHub to manage repositories, issues, pull requests, and code. Search code, review changes, create branches, and collaborate on software development projects through conversational AI.',
58
106
  label: 'GitHub',
59
107
  serverName: Klavis.McpServerName.Github,
60
108
  },
61
109
  {
110
+ author: 'Klavis',
111
+ authorUrl: 'https://klavis.io',
112
+ description: 'Supabase official MCP Server',
62
113
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/supabase.svg',
63
114
  identifier: 'supabase',
115
+ introduction:
116
+ 'Integrate with Supabase to manage your database and backend services. Query data, manage authentication, handle storage, and interact with your application backend through natural conversation.',
64
117
  label: 'Supabase',
65
118
  serverName: Klavis.McpServerName.Supabase,
66
119
  },
67
120
  {
121
+ author: 'Klavis',
122
+ authorUrl: 'https://klavis.io',
123
+ description: 'Google Drive is a cloud storage service',
68
124
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/googledrive.svg',
69
125
  identifier: 'google-drive',
126
+ introduction:
127
+ 'Connect to Google Drive to access, organize, and manage your files. Search documents, upload files, share content, and navigate your cloud storage efficiently through AI assistance.',
70
128
  label: 'Google Drive',
71
129
  serverName: Klavis.McpServerName.GoogleDrive,
72
130
  },
73
131
  {
132
+ author: 'Klavis',
133
+ authorUrl: 'https://klavis.io',
134
+ description:
135
+ 'Slack is a messaging app for business that connects people to the information they need',
74
136
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/slack.svg',
75
137
  identifier: 'slack',
138
+ introduction:
139
+ 'Integrate with Slack to send messages, search conversations, and manage channels. Connect with your team, automate communication workflows, and access workspace information through natural language.',
76
140
  label: 'Slack',
77
141
  serverName: Klavis.McpServerName.Slack,
78
142
  },
79
143
  {
144
+ author: 'Klavis',
145
+ authorUrl: 'https://klavis.io',
146
+ description: 'Confluence is a team workspace where knowledge and collaboration meet',
80
147
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/confluence.svg',
81
148
  identifier: 'confluence',
149
+ introduction:
150
+ 'Connect to Confluence to access and manage team documentation. Search pages, create content, organize spaces, and build your knowledge base through conversational AI assistance.',
82
151
  label: 'Confluence',
83
152
  serverName: Klavis.McpServerName.Confluence,
84
153
  },
85
154
  {
155
+ author: 'Klavis',
156
+ authorUrl: 'https://klavis.io',
157
+ description: 'Jira is a project management and issue tracking tool developed by Atlassian',
86
158
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/jira.svg',
87
159
  identifier: 'jira',
160
+ introduction:
161
+ 'Integrate with Jira to manage issues, track progress, and organize sprints. Create tickets, update statuses, query project data, and streamline your development workflow through natural conversation.',
88
162
  label: 'Jira',
89
163
  serverName: Klavis.McpServerName.Jira,
90
164
  },
91
165
  {
166
+ author: 'Klavis',
167
+ authorUrl: 'https://klavis.io',
168
+ description:
169
+ 'ClickUp is a comprehensive project management and productivity platform that helps teams organize tasks, manage projects, and collaborate effectively with customizable workflows and powerful tracking features',
92
170
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/clickup.svg',
93
171
  identifier: 'clickup',
172
+ introduction:
173
+ 'Connect to ClickUp to manage tasks, track projects, and organize your work. Create tasks, update statuses, manage custom workflows, and collaborate with your team through natural language commands.',
94
174
  label: 'ClickUp',
95
175
  serverName: Klavis.McpServerName.Clickup,
96
176
  },
97
177
  {
178
+ author: 'Klavis',
179
+ authorUrl: 'https://klavis.io',
180
+ description:
181
+ 'Complete file management solution for Dropbox cloud storage. Upload, download, organize files and folders, manage sharing and collaboration, handle file versions, create file requests, and perform batch operations on your Dropbox files and folders',
98
182
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/dropbox.svg',
99
183
  identifier: 'dropbox',
184
+ introduction:
185
+ 'Integrate with Dropbox to access and manage your files. Upload, download, share files, manage folders, handle file versions, and organize your cloud storage through conversational AI.',
100
186
  label: 'Dropbox',
101
187
  serverName: Klavis.McpServerName.Dropbox,
102
188
  },
103
189
  {
190
+ author: 'Klavis',
191
+ authorUrl: 'https://klavis.io',
192
+ description: 'Figma is a collaborative interface design tool for web and mobile applications.',
104
193
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/figma.svg',
105
194
  identifier: 'figma',
195
+ introduction:
196
+ 'Connect to Figma to access design files and collaborate on projects. View designs, export assets, browse components, and manage your design workflow through natural conversation.',
106
197
  label: 'Figma',
107
198
  serverName: Klavis.McpServerName.Figma,
108
199
  },
109
200
  {
201
+ author: 'Klavis',
202
+ authorUrl: 'https://klavis.io',
203
+ description:
204
+ 'HubSpot is a developer and marketer of software products for inbound marketing, sales, and customer service',
110
205
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/hubspot.svg',
111
206
  identifier: 'hubspot',
207
+ introduction:
208
+ 'Integrate with HubSpot to manage contacts, deals, and marketing campaigns. Access CRM data, track pipelines, automate workflows, and streamline your sales and marketing operations.',
112
209
  label: 'HubSpot',
113
210
  serverName: Klavis.McpServerName.Hubspot,
114
211
  },
115
212
  {
213
+ author: 'Klavis',
214
+ authorUrl: 'https://klavis.io',
215
+ description:
216
+ 'OneDrive is a file hosting service and synchronization service operated by Microsoft',
116
217
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/onedrive.svg',
117
218
  identifier: 'onedrive',
219
+ introduction:
220
+ 'Connect to OneDrive to access and manage your Microsoft cloud files. Upload, download, share files, organize folders, and collaborate on documents through AI-powered assistance.',
118
221
  label: 'OneDrive',
119
222
  serverName: Klavis.McpServerName.Onedrive,
120
223
  },
121
224
  {
225
+ author: 'Klavis',
226
+ authorUrl: 'https://klavis.io',
227
+ description:
228
+ 'Outlook Mail is a web-based suite of webmail, contacts, tasks, and calendaring services from Microsoft.',
122
229
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/outlook.svg',
123
230
  identifier: 'outlook-mail',
231
+ introduction:
232
+ 'Integrate with Outlook Mail to read, send, and manage your Microsoft emails. Search messages, compose emails, manage folders, and organize your inbox through natural conversation.',
124
233
  label: 'Outlook Mail',
125
234
  serverName: Klavis.McpServerName.OutlookMail,
126
235
  },
127
236
  {
237
+ author: 'Klavis',
238
+ authorUrl: 'https://klavis.io',
239
+ description:
240
+ "Salesforce is the world's leading customer relationship management (CRM) platform that helps businesses connect with customers, partners, and potential customers",
128
241
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/salesforce.svg',
129
242
  identifier: 'salesforce',
243
+ introduction:
244
+ 'Connect to Salesforce to manage customer relationships and sales data. Query records, update opportunities, track leads, and automate your CRM workflows through natural language commands.',
130
245
  label: 'Salesforce',
131
246
  serverName: Klavis.McpServerName.Salesforce,
132
247
  },
133
248
  {
249
+ author: 'Klavis',
250
+ authorUrl: 'https://klavis.io',
251
+ description:
252
+ 'WhatsApp Business API integration that enables sending text messages, media, and managing conversations with customers. Perfect for customer support, marketing campaigns, and automated messaging workflows through the official WhatsApp Business platform.',
134
253
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/whatsapp.svg',
135
254
  identifier: 'whatsapp',
255
+ introduction:
256
+ 'Integrate with WhatsApp Business to send messages, manage conversations, and engage with customers. Automate messaging workflows and handle communications through conversational AI.',
136
257
  label: 'WhatsApp',
137
258
  serverName: Klavis.McpServerName.Whatsapp,
138
259
  },
139
260
  {
261
+ author: 'Klavis',
262
+ authorUrl: 'https://klavis.io',
263
+ description:
264
+ 'YouTube is a video-sharing platform where users can upload, share, and discover content. Access video information, transcripts, and metadata programmatically.',
140
265
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/youtube.svg',
141
266
  identifier: 'youtube',
267
+ introduction:
268
+ 'Connect to YouTube to search videos, access transcripts, and retrieve video information. Analyze content, extract metadata, and discover videos through natural conversation.',
142
269
  label: 'YouTube',
143
270
  serverName: Klavis.McpServerName.Youtube,
144
271
  },
145
272
  {
273
+ author: 'Klavis',
274
+ authorUrl: 'https://klavis.io',
275
+ description: 'Zendesk is a customer service software company',
146
276
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/zendesk.svg',
147
277
  identifier: 'zendesk',
278
+ introduction:
279
+ 'Integrate with Zendesk to manage support tickets and customer interactions. Create, update, and track support requests, access customer data, and streamline your support operations.',
148
280
  label: 'Zendesk',
149
281
  serverName: Klavis.McpServerName.Zendesk,
150
282
  },
151
283
  {
284
+ author: 'Klavis',
285
+ authorUrl: 'https://klavis.io',
286
+ description:
287
+ 'Cal.com is an open-source scheduling platform that helps you schedule meetings without the back-and-forth emails. Manage event types, bookings, availability, and integrate with calendars for seamless appointment scheduling',
152
288
  icon: SiCaldotcom,
153
289
  identifier: 'cal-com',
290
+ introduction:
291
+ 'Connect to Cal.com to manage your scheduling and appointments. View availability, book meetings, manage event types, and automate your calendar through natural conversation.',
154
292
  label: 'Cal.com',
155
293
  serverName: Klavis.McpServerName.CalCom,
156
294
  },
157
295
  ];
296
+
297
+ /**
298
+ * Get server config by identifier
299
+ */
300
+ export const getKlavisServerByServerIdentifier = (identifier: string) =>
301
+ KLAVIS_SERVER_TYPES.find((s) => s.identifier === identifier);
@@ -1,10 +1,22 @@
1
1
  import { type IconType, SiLinear, SiX } from '@icons-pack/react-simple-icons';
2
2
 
3
3
  export interface LobehubSkillProviderType {
4
+ /**
5
+ * Author/Developer of the integration
6
+ */
7
+ author: string;
8
+ /**
9
+ * Author's website URL
10
+ */
11
+ authorUrl?: string;
4
12
  /**
5
13
  * Whether this provider is visible by default in the UI
6
14
  */
7
15
  defaultVisible?: boolean;
16
+ /**
17
+ * Short description of the skill
18
+ */
19
+ description: string;
8
20
  /**
9
21
  * Icon - can be a URL string or a React icon component
10
22
  */
@@ -13,6 +25,10 @@ export interface LobehubSkillProviderType {
13
25
  * Provider ID (matches Market API, e.g., 'linear', 'microsoft')
14
26
  */
15
27
  id: string;
28
+ /**
29
+ * Detailed introduction of the skill
30
+ */
31
+ introduction: string;
16
32
  /**
17
33
  * Display label for the provider
18
34
  */
@@ -29,21 +45,39 @@ export interface LobehubSkillProviderType {
29
45
  */
30
46
  export const LOBEHUB_SKILL_PROVIDERS: LobehubSkillProviderType[] = [
31
47
  {
48
+ author: 'LobeHub',
49
+ authorUrl: 'https://lobehub.com',
32
50
  defaultVisible: true,
51
+ description:
52
+ 'Linear is a modern issue tracking and project management tool designed for high-performance teams to build better software faster',
33
53
  icon: SiLinear,
34
54
  id: 'linear',
55
+ introduction:
56
+ 'Bring the power of Linear directly into your AI assistant. Create and update issues, manage sprints, track project progress, and streamline your development workflow—all through natural conversation.',
35
57
  label: 'Linear',
36
58
  },
37
59
  {
60
+ author: 'LobeHub',
61
+ authorUrl: 'https://lobehub.com',
38
62
  defaultVisible: true,
63
+ description:
64
+ 'Outlook Calendar is an integrated scheduling tool within Microsoft Outlook that enables users to create appointments, organize meetings with others, and manage their time and events effectively.',
39
65
  icon: 'https://hub-apac-1.lobeobjects.space/assets/logos/outlook.svg',
40
66
  id: 'microsoft',
67
+ introduction:
68
+ 'Integrate with Outlook Calendar to view, create, and manage your events seamlessly. Schedule meetings, check availability, set reminders, and coordinate your time—all through natural language commands.',
41
69
  label: 'Outlook Calendar',
42
70
  },
43
71
  {
72
+ author: 'LobeHub',
73
+ authorUrl: 'https://lobehub.com',
44
74
  defaultVisible: true,
75
+ description:
76
+ 'X (Twitter) is a social media platform for sharing real-time updates, news, and engaging with your audience through posts, replies, and direct messages.',
45
77
  icon: SiX,
46
78
  id: 'twitter',
79
+ introduction:
80
+ 'Connect to X (Twitter) to post tweets, manage your timeline, and engage with your audience. Create content, schedule posts, monitor mentions, and build your social media presence through conversational AI.',
47
81
  label: 'X (Twitter)',
48
82
  },
49
83
  ];
@@ -0,0 +1,17 @@
1
+ export enum RecommendedSkillType {
2
+ Klavis = 'klavis',
3
+ Lobehub = 'lobehub',
4
+ }
5
+
6
+ export interface RecommendedSkillItem {
7
+ id: string;
8
+ type: RecommendedSkillType;
9
+ }
10
+
11
+ export const RECOMMENDED_SKILLS: RecommendedSkillItem[] = [
12
+ { id: 'gmail', type: RecommendedSkillType.Klavis },
13
+ { id: 'notion', type: RecommendedSkillType.Klavis },
14
+ { id: 'google-drive', type: RecommendedSkillType.Klavis },
15
+ { id: 'google-calendar', type: RecommendedSkillType.Klavis },
16
+ { id: 'slack', type: RecommendedSkillType.Klavis },
17
+ ];
@@ -125,6 +125,44 @@ describe('anthropicHelpers', () => {
125
125
 
126
126
  await expect(buildAnthropicBlock(content)).rejects.toThrow('Invalid image URL: invalid-url');
127
127
  });
128
+
129
+ it('should return undefined for unsupported SVG image (base64)', async () => {
130
+ vi.mocked(parseDataUri).mockReturnValueOnce({
131
+ mimeType: 'image/svg+xml',
132
+ base64: 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==',
133
+ type: 'base64',
134
+ });
135
+
136
+ const content = {
137
+ type: 'image_url',
138
+ image_url: {
139
+ url: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==',
140
+ },
141
+ } as const;
142
+
143
+ const result = await buildAnthropicBlock(content);
144
+ expect(result).toBeUndefined();
145
+ });
146
+
147
+ it('should return undefined for unsupported SVG image (URL)', async () => {
148
+ vi.mocked(parseDataUri).mockReturnValueOnce({
149
+ mimeType: null,
150
+ base64: null,
151
+ type: 'url',
152
+ });
153
+ vi.mocked(imageUrlToBase64).mockResolvedValueOnce({
154
+ base64: 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==',
155
+ mimeType: 'image/svg+xml',
156
+ });
157
+
158
+ const content = {
159
+ type: 'image_url',
160
+ image_url: { url: 'https://example.com/image.svg' },
161
+ } as const;
162
+
163
+ const result = await buildAnthropicBlock(content);
164
+ expect(result).toBeUndefined();
165
+ });
128
166
  });
129
167
 
130
168
  describe('buildAnthropicMessage', () => {
@@ -5,6 +5,19 @@ import OpenAI from 'openai';
5
5
  import { OpenAIChatMessage, UserMessageContentPart } from '../../types';
6
6
  import { parseDataUri } from '../../utils/uriParser';
7
7
 
8
+ const ANTHROPIC_SUPPORTED_IMAGE_TYPES = new Set([
9
+ 'image/jpeg',
10
+ 'image/jpg',
11
+ 'image/png',
12
+ 'image/gif',
13
+ 'image/webp',
14
+ ]);
15
+
16
+ const isImageTypeSupported = (mimeType: string | null): boolean => {
17
+ if (!mimeType) return true;
18
+ return ANTHROPIC_SUPPORTED_IMAGE_TYPES.has(mimeType.toLowerCase());
19
+ };
20
+
8
21
  export const buildAnthropicBlock = async (
9
22
  content: UserMessageContentPart,
10
23
  ): Promise<Anthropic.ContentBlock | Anthropic.ImageBlockParam | undefined> => {
@@ -23,7 +36,9 @@ export const buildAnthropicBlock = async (
23
36
  case 'image_url': {
24
37
  const { mimeType, base64, type } = parseDataUri(content.image_url.url);
25
38
 
26
- if (type === 'base64')
39
+ if (type === 'base64') {
40
+ if (!isImageTypeSupported(mimeType)) return undefined;
41
+
27
42
  return {
28
43
  source: {
29
44
  data: base64 as string,
@@ -32,9 +47,13 @@ export const buildAnthropicBlock = async (
32
47
  },
33
48
  type: 'image',
34
49
  };
50
+ }
35
51
 
36
52
  if (type === 'url') {
37
53
  const { base64, mimeType } = await imageUrlToBase64(content.image_url.url);
54
+
55
+ if (!isImageTypeSupported(mimeType)) return undefined;
56
+
38
57
  return {
39
58
  source: {
40
59
  data: base64 as string,
@@ -149,6 +149,48 @@ describe('google contextBuilders', () => {
149
149
  thoughtSignature: GEMINI_MAGIC_THOUGHT_SIGNATURE,
150
150
  });
151
151
  });
152
+
153
+ it('should return undefined for unsupported SVG image (base64)', async () => {
154
+ const svgBase64 =
155
+ 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==';
156
+
157
+ vi.mocked(parseDataUri).mockReturnValueOnce({
158
+ base64: 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==',
159
+ mimeType: 'image/svg+xml',
160
+ type: 'base64',
161
+ });
162
+
163
+ const content: UserMessageContentPart = {
164
+ image_url: { url: svgBase64 },
165
+ type: 'image_url',
166
+ };
167
+
168
+ const result = await buildGooglePart(content);
169
+ expect(result).toBeUndefined();
170
+ });
171
+
172
+ it('should return undefined for unsupported SVG image (URL)', async () => {
173
+ const svgUrl = 'https://example.com/image.svg';
174
+
175
+ vi.mocked(parseDataUri).mockReturnValueOnce({
176
+ base64: null,
177
+ mimeType: null,
178
+ type: 'url',
179
+ });
180
+
181
+ vi.spyOn(imageToBase64Module, 'imageUrlToBase64').mockResolvedValueOnce({
182
+ base64: 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==',
183
+ mimeType: 'image/svg+xml',
184
+ });
185
+
186
+ const content: UserMessageContentPart = {
187
+ image_url: { url: svgUrl },
188
+ type: 'image_url',
189
+ };
190
+
191
+ const result = await buildGooglePart(content);
192
+ expect(result).toBeUndefined();
193
+ });
152
194
  });
153
195
 
154
196
  describe('buildGoogleMessage', () => {
@@ -11,6 +11,19 @@ import { ChatCompletionTool, OpenAIChatMessage, UserMessageContentPart } from '.
11
11
  import { safeParseJSON } from '../../utils/safeParseJSON';
12
12
  import { parseDataUri } from '../../utils/uriParser';
13
13
 
14
+ const GOOGLE_SUPPORTED_IMAGE_TYPES = new Set([
15
+ 'image/jpeg',
16
+ 'image/jpg',
17
+ 'image/png',
18
+ 'image/gif',
19
+ 'image/webp',
20
+ ]);
21
+
22
+ const isImageTypeSupported = (mimeType: string | null): boolean => {
23
+ if (!mimeType) return true;
24
+ return GOOGLE_SUPPORTED_IMAGE_TYPES.has(mimeType.toLowerCase());
25
+ };
26
+
14
27
  /**
15
28
  * Magic thoughtSignature
16
29
  * @see https://ai.google.dev/gemini-api/docs/thought-signatures#model-behavior:~:text=context_engineering_is_the_way_to_go
@@ -43,6 +56,8 @@ export const buildGooglePart = async (
43
56
  throw new TypeError("Image URL doesn't contain base64 data");
44
57
  }
45
58
 
59
+ if (!isImageTypeSupported(mimeType)) return undefined;
60
+
46
61
  return {
47
62
  inlineData: { data: base64, mimeType: mimeType || 'image/png' },
48
63
  thoughtSignature: GEMINI_MAGIC_THOUGHT_SIGNATURE,
@@ -52,6 +67,8 @@ export const buildGooglePart = async (
52
67
  if (type === 'url') {
53
68
  const { base64, mimeType } = await imageUrlToBase64(content.image_url.url);
54
69
 
70
+ if (!isImageTypeSupported(mimeType)) return undefined;
71
+
55
72
  return {
56
73
  inlineData: { data: base64, mimeType },
57
74
  thoughtSignature: GEMINI_MAGIC_THOUGHT_SIGNATURE,
@@ -242,7 +242,7 @@ export class LobeGoogleAI implements LobeRuntimeAI {
242
242
  } catch (e) {
243
243
  const err = e as Error;
244
244
 
245
- // 移除之前的静默处理,统一抛出错误
245
+ // Remove previous silent handling, throw error uniformly
246
246
  if (isAbortError(err)) {
247
247
  log('Request was cancelled');
248
248
  throw AgentRuntimeError.chat({
@@ -307,10 +307,10 @@ export class LobeGoogleAI implements LobeRuntimeAI {
307
307
  try {
308
308
  for await (const chunk of originalStream) {
309
309
  if (signal.aborted) {
310
- // 如果有数据已经输出,优雅地关闭流而不是抛出错误
310
+ // If data has already been output, close the stream gracefully instead of throwing an error
311
311
  if (hasData) {
312
312
  log('Stream cancelled gracefully, preserving existing output');
313
- // 显式注入取消错误,避免走 SSE 兜底 unexpected_end
313
+ // Explicitly inject cancellation error to avoid SSE fallback unexpected_end
314
314
  controller.enqueue({
315
315
  [LOBE_ERROR_KEY]: {
316
316
  body: { name: 'Stream cancelled', provider, reason: 'aborted' },
@@ -322,7 +322,7 @@ export class LobeGoogleAI implements LobeRuntimeAI {
322
322
  controller.close();
323
323
  return;
324
324
  } else {
325
- // 如果还没有数据输出,直接关闭流,由下游 SSE flush 阶段补发错误事件
325
+ // If no data has been output yet, close the stream directly and let downstream SSE emit error event during flush phase
326
326
  log('Stream cancelled before any output');
327
327
  controller.close();
328
328
  return;
@@ -335,12 +335,12 @@ export class LobeGoogleAI implements LobeRuntimeAI {
335
335
  } catch (error) {
336
336
  const err = error as Error;
337
337
 
338
- // 统一处理所有错误,包括 abort 错误
338
+ // Handle all errors uniformly, including abort errors
339
339
  if (isAbortError(err) || signal.aborted) {
340
- // 如果有数据已经输出,优雅地关闭流
340
+ // If data has already been output, close the stream gracefully
341
341
  if (hasData) {
342
342
  log('Stream reading cancelled gracefully, preserving existing output');
343
- // 显式注入取消错误,避免走 SSE 兜底 unexpected_end
343
+ // Explicitly inject cancellation error to avoid SSE fallback unexpected_end
344
344
  controller.enqueue({
345
345
  [LOBE_ERROR_KEY]: {
346
346
  body: { name: 'Stream cancelled', provider, reason: 'aborted' },
@@ -353,7 +353,7 @@ export class LobeGoogleAI implements LobeRuntimeAI {
353
353
  return;
354
354
  } else {
355
355
  log('Stream reading cancelled before any output');
356
- // 注入一个带详细错误信息的错误标记,交由下游 google-ai transformer 输出 error 事件
356
+ // Inject an error marker with detailed error information to be handled by downstream google-ai transformer to output error event
357
357
  controller.enqueue({
358
358
  [LOBE_ERROR_KEY]: {
359
359
  body: {
@@ -371,14 +371,14 @@ export class LobeGoogleAI implements LobeRuntimeAI {
371
371
  return;
372
372
  }
373
373
  } else {
374
- // 处理其他流解析错误
374
+ // Handle other stream parsing errors
375
375
  log('Stream parsing error: %O', err);
376
- // 尝试解析 Google 错误并提取 code/message/status
376
+ // Try to parse Google error and extract code/message/status
377
377
  const { error: parsedError, errorType } = parseGoogleErrorMessage(
378
378
  err?.message || String(err),
379
379
  );
380
380
 
381
- // 注入一个带详细错误信息的错误标记,交由下游 google-ai transformer 输出 error 事件
381
+ // Inject an error marker with detailed error information to be handled by downstream google-ai transformer to output error event
382
382
  controller.enqueue({
383
383
  [LOBE_ERROR_KEY]: {
384
384
  body: { ...parsedError, provider },
@@ -453,12 +453,12 @@ export class LobeGoogleAI implements LobeRuntimeAI {
453
453
  const hasUrlContext = payload?.urlContext;
454
454
  const hasFunctionTools = tools && tools.length > 0;
455
455
 
456
- // 如果已经有 tool_calls,优先处理 function declarations
456
+ // If tool_calls already exist, prioritize handling function declarations
457
457
  if (hasToolCalls && hasFunctionTools) {
458
458
  return buildGoogleTools(tools);
459
459
  }
460
460
 
461
- // 构建并返回搜索相关工具(搜索工具不能与 FunctionCall 同时使用)
461
+ // Build and return search-related tools (search tools cannot be used with FunctionCall simultaneously)
462
462
  if (hasUrlContext && hasSearch) {
463
463
  return [{ urlContext: {} }, { googleSearch: {} }];
464
464
  }
@@ -469,7 +469,7 @@ export class LobeGoogleAI implements LobeRuntimeAI {
469
469
  return [{ googleSearch: {} }];
470
470
  }
471
471
 
472
- // 最后考虑 function declarations
472
+ // Finally consider function declarations
473
473
  return buildGoogleTools(tools);
474
474
  }
475
475
  }