@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
@@ -0,0 +1,605 @@
1
+ import { AgentRuntimeContext, AgentState } from '@lobechat/agent-runtime';
2
+ import { ChatToolPayload } from '@lobechat/types';
3
+ import { describe, expect, it } from 'vitest';
4
+
5
+ import { GeneralChatAgent } from '../GeneralChatAgent';
6
+
7
+ describe('GeneralChatAgent', () => {
8
+ const mockModelRuntimeConfig = {
9
+ model: 'gpt-4o-mini',
10
+ provider: 'openai',
11
+ };
12
+
13
+ const createMockState = (overrides?: Partial<AgentState>): AgentState => ({
14
+ sessionId: 'test-session',
15
+ status: 'running',
16
+ messages: [],
17
+ toolManifestMap: {},
18
+ stepCount: 0,
19
+ usage: {
20
+ llm: { apiCalls: 0, processingTimeMs: 0, tokens: { input: 0, output: 0, total: 0 } },
21
+ tools: { totalCalls: 0, totalTimeMs: 0, byTool: [] },
22
+ humanInteraction: {
23
+ approvalRequests: 0,
24
+ promptRequests: 0,
25
+ selectRequests: 0,
26
+ totalWaitingTimeMs: 0,
27
+ },
28
+ },
29
+ cost: {
30
+ calculatedAt: new Date().toISOString(),
31
+ currency: 'USD',
32
+ llm: { byModel: [], currency: 'USD', total: 0 },
33
+ tools: { byTool: [], currency: 'USD', total: 0 },
34
+ total: 0,
35
+ },
36
+ createdAt: new Date().toISOString(),
37
+ lastModified: new Date().toISOString(),
38
+ ...overrides,
39
+ });
40
+
41
+ const createMockContext = (
42
+ phase: AgentRuntimeContext['phase'],
43
+ payload?: any,
44
+ ): AgentRuntimeContext => ({
45
+ phase,
46
+ payload,
47
+ session: {
48
+ sessionId: 'test-session',
49
+ messageCount: 0,
50
+ status: 'running',
51
+ stepCount: 0,
52
+ },
53
+ });
54
+
55
+ describe('init and user_input phase', () => {
56
+ it('should return call_llm instruction for init phase', async () => {
57
+ const agent = new GeneralChatAgent({
58
+ agentConfig: { maxSteps: 100 },
59
+ sessionId: 'test-session',
60
+ modelRuntimeConfig: mockModelRuntimeConfig,
61
+ });
62
+
63
+ const state = createMockState({
64
+ messages: [{ role: 'user', content: 'Hello' }] as any,
65
+ });
66
+ const context = createMockContext('init', { model: 'gpt-4o-mini', provider: 'openai' });
67
+
68
+ const result = await agent.runner(context, state);
69
+
70
+ expect(result).toEqual({
71
+ type: 'call_llm',
72
+ payload: {
73
+ messages: state.messages,
74
+ model: 'gpt-4o-mini',
75
+ provider: 'openai',
76
+ },
77
+ });
78
+ });
79
+
80
+ it('should return call_llm instruction for user_input phase', async () => {
81
+ const agent = new GeneralChatAgent({
82
+ agentConfig: { maxSteps: 100 },
83
+ sessionId: 'test-session',
84
+ modelRuntimeConfig: mockModelRuntimeConfig,
85
+ });
86
+
87
+ const state = createMockState({
88
+ messages: [{ role: 'user', content: 'What is the weather?' }] as any,
89
+ });
90
+ const context = createMockContext('user_input', {
91
+ message: { role: 'user', content: 'What is the weather?' },
92
+ });
93
+
94
+ const result = await agent.runner(context, state);
95
+
96
+ expect(result).toEqual({
97
+ type: 'call_llm',
98
+ payload: {
99
+ messages: state.messages,
100
+ message: { role: 'user', content: 'What is the weather?' },
101
+ },
102
+ });
103
+ });
104
+ });
105
+
106
+ describe('llm_result phase', () => {
107
+ it('should return finish when no tool calls', async () => {
108
+ const agent = new GeneralChatAgent({
109
+ agentConfig: { maxSteps: 100 },
110
+ sessionId: 'test-session',
111
+ modelRuntimeConfig: mockModelRuntimeConfig,
112
+ });
113
+
114
+ const state = createMockState();
115
+ const context = createMockContext('llm_result', {
116
+ hasToolsCalling: false,
117
+ toolsCalling: [],
118
+ parentMessageId: 'msg-1',
119
+ });
120
+
121
+ const result = await agent.runner(context, state);
122
+
123
+ expect(result).toEqual({
124
+ type: 'finish',
125
+ reason: 'completed',
126
+ reasonDetail: 'LLM response completed without tool calls',
127
+ });
128
+ });
129
+
130
+ it('should return call_tool for single tool that does not need intervention', async () => {
131
+ const agent = new GeneralChatAgent({
132
+ agentConfig: { maxSteps: 100 },
133
+ sessionId: 'test-session',
134
+ modelRuntimeConfig: mockModelRuntimeConfig,
135
+ });
136
+
137
+ const toolCall: ChatToolPayload = {
138
+ id: 'call-1',
139
+ identifier: 'test-plugin',
140
+ apiName: 'test-api',
141
+ arguments: '{}',
142
+ type: 'default',
143
+ };
144
+
145
+ const state = createMockState({
146
+ toolManifestMap: {
147
+ 'test-plugin': {
148
+ identifier: 'test-plugin',
149
+ // No humanIntervention config = no intervention needed
150
+ },
151
+ },
152
+ });
153
+
154
+ const context = createMockContext('llm_result', {
155
+ hasToolsCalling: true,
156
+ toolsCalling: [toolCall],
157
+ parentMessageId: 'msg-1',
158
+ });
159
+
160
+ const result = await agent.runner(context, state);
161
+
162
+ expect(result).toEqual([
163
+ {
164
+ type: 'call_tool',
165
+ payload: {
166
+ parentMessageId: 'msg-1',
167
+ toolCalling: toolCall,
168
+ },
169
+ },
170
+ ]);
171
+ });
172
+
173
+ it('should return call_tools_batch for multiple tools that do not need intervention', async () => {
174
+ const agent = new GeneralChatAgent({
175
+ agentConfig: { maxSteps: 100 },
176
+ sessionId: 'test-session',
177
+ modelRuntimeConfig: mockModelRuntimeConfig,
178
+ });
179
+
180
+ const toolCalls: ChatToolPayload[] = [
181
+ {
182
+ id: 'call-1',
183
+ identifier: 'plugin-1',
184
+ apiName: 'api-1',
185
+ arguments: '{}',
186
+ type: 'default',
187
+ },
188
+ {
189
+ id: 'call-2',
190
+ identifier: 'plugin-2',
191
+ apiName: 'api-2',
192
+ arguments: '{}',
193
+ type: 'default',
194
+ },
195
+ ];
196
+
197
+ const state = createMockState({
198
+ toolManifestMap: {
199
+ 'plugin-1': { identifier: 'plugin-1' },
200
+ 'plugin-2': { identifier: 'plugin-2' },
201
+ },
202
+ });
203
+
204
+ const context = createMockContext('llm_result', {
205
+ hasToolsCalling: true,
206
+ toolsCalling: toolCalls,
207
+ parentMessageId: 'msg-1',
208
+ });
209
+
210
+ const result = await agent.runner(context, state);
211
+
212
+ expect(result).toEqual([
213
+ {
214
+ type: 'call_tools_batch',
215
+ payload: {
216
+ parentMessageId: 'msg-1',
217
+ toolsCalling: toolCalls,
218
+ },
219
+ },
220
+ ]);
221
+ });
222
+
223
+ it('should return request_human_approve for tools requiring intervention', async () => {
224
+ const agent = new GeneralChatAgent({
225
+ agentConfig: { maxSteps: 100 },
226
+ sessionId: 'test-session',
227
+ modelRuntimeConfig: mockModelRuntimeConfig,
228
+ });
229
+
230
+ const toolCall: ChatToolPayload = {
231
+ id: 'call-1',
232
+ identifier: 'dangerous-plugin',
233
+ apiName: 'delete-api',
234
+ arguments: '{}',
235
+ type: 'default',
236
+ };
237
+
238
+ const state = createMockState({
239
+ toolManifestMap: {
240
+ 'dangerous-plugin': {
241
+ identifier: 'dangerous-plugin',
242
+ humanIntervention: 'require', // Always require approval
243
+ },
244
+ },
245
+ });
246
+
247
+ const context = createMockContext('llm_result', {
248
+ hasToolsCalling: true,
249
+ toolsCalling: [toolCall],
250
+ parentMessageId: 'msg-1',
251
+ });
252
+
253
+ const result = await agent.runner(context, state);
254
+
255
+ expect(result).toEqual([
256
+ {
257
+ type: 'request_human_approve',
258
+ pendingToolsCalling: [toolCall],
259
+ reason: 'human_intervention_required',
260
+ },
261
+ ]);
262
+ });
263
+
264
+ it('should return both call_tools_batch and request_human_approve for mixed tools', async () => {
265
+ const agent = new GeneralChatAgent({
266
+ agentConfig: { maxSteps: 100 },
267
+ sessionId: 'test-session',
268
+ modelRuntimeConfig: mockModelRuntimeConfig,
269
+ });
270
+
271
+ const safeTool: ChatToolPayload = {
272
+ id: 'call-1',
273
+ identifier: 'safe-plugin',
274
+ apiName: 'read-api',
275
+ arguments: '{}',
276
+ type: 'default',
277
+ };
278
+
279
+ const dangerousTool: ChatToolPayload = {
280
+ id: 'call-2',
281
+ identifier: 'dangerous-plugin',
282
+ apiName: 'delete-api',
283
+ arguments: '{}',
284
+ type: 'default',
285
+ };
286
+
287
+ const state = createMockState({
288
+ toolManifestMap: {
289
+ 'safe-plugin': {
290
+ identifier: 'safe-plugin',
291
+ // No intervention
292
+ },
293
+ 'dangerous-plugin': {
294
+ identifier: 'dangerous-plugin',
295
+ humanIntervention: 'require',
296
+ },
297
+ },
298
+ });
299
+
300
+ const context = createMockContext('llm_result', {
301
+ hasToolsCalling: true,
302
+ toolsCalling: [safeTool, dangerousTool],
303
+ parentMessageId: 'msg-1',
304
+ });
305
+
306
+ const result = await agent.runner(context, state);
307
+
308
+ expect(result).toEqual([
309
+ {
310
+ type: 'call_tool',
311
+ payload: {
312
+ parentMessageId: 'msg-1',
313
+ toolCalling: safeTool,
314
+ },
315
+ },
316
+ {
317
+ type: 'request_human_approve',
318
+ pendingToolsCalling: [dangerousTool],
319
+ reason: 'human_intervention_required',
320
+ },
321
+ ]);
322
+ });
323
+ });
324
+
325
+ describe('tool_result phase', () => {
326
+ it('should return call_llm when no pending tools', async () => {
327
+ const agent = new GeneralChatAgent({
328
+ agentConfig: { maxSteps: 100 },
329
+ sessionId: 'test-session',
330
+ modelRuntimeConfig: mockModelRuntimeConfig,
331
+ });
332
+
333
+ const state = createMockState({
334
+ messages: [
335
+ { role: 'user', content: 'Hello' },
336
+ { role: 'assistant', content: '', tools: [] },
337
+ { role: 'tool', content: 'Result', tool_call_id: 'call-1' },
338
+ ] as any,
339
+ });
340
+
341
+ const context = createMockContext('tool_result', {
342
+ parentMessageId: 'tool-msg-1',
343
+ result: { data: 'result' },
344
+ });
345
+
346
+ const result = await agent.runner(context, state);
347
+
348
+ expect(result).toEqual({
349
+ type: 'call_llm',
350
+ payload: {
351
+ messages: state.messages,
352
+ model: 'gpt-4o-mini',
353
+ parentMessageId: 'tool-msg-1',
354
+ provider: 'openai',
355
+ tools: undefined,
356
+ },
357
+ });
358
+ });
359
+
360
+ it('should return request_human_approve when there are pending tools', async () => {
361
+ const agent = new GeneralChatAgent({
362
+ agentConfig: { maxSteps: 100 },
363
+ sessionId: 'test-session',
364
+ modelRuntimeConfig: mockModelRuntimeConfig,
365
+ });
366
+
367
+ const pendingPlugin: ChatToolPayload = {
368
+ id: 'call-2',
369
+ identifier: 'plugin-2',
370
+ apiName: 'api-2',
371
+ arguments: '{}',
372
+ type: 'default',
373
+ };
374
+
375
+ const state = createMockState({
376
+ messages: [
377
+ { role: 'user', content: 'Hello' },
378
+ { role: 'assistant', content: '', tools: [] },
379
+ { role: 'tool', content: 'Result', tool_call_id: 'call-1' },
380
+ {
381
+ role: 'tool',
382
+ content: '',
383
+ tool_call_id: 'call-2',
384
+ plugin: pendingPlugin,
385
+ pluginIntervention: { status: 'pending' },
386
+ },
387
+ ] as any,
388
+ });
389
+
390
+ const context = createMockContext('tool_result', {
391
+ parentMessageId: 'tool-msg-1',
392
+ });
393
+
394
+ const result = await agent.runner(context, state);
395
+
396
+ expect(result).toEqual({
397
+ type: 'request_human_approve',
398
+ pendingToolsCalling: [pendingPlugin],
399
+ reason: 'Some tools still pending approval',
400
+ skipCreateToolMessage: true,
401
+ });
402
+ });
403
+ });
404
+
405
+ describe('tools_batch_result phase', () => {
406
+ it('should return call_llm when no pending tools', async () => {
407
+ const agent = new GeneralChatAgent({
408
+ agentConfig: { maxSteps: 100 },
409
+ sessionId: 'test-session',
410
+ modelRuntimeConfig: mockModelRuntimeConfig,
411
+ });
412
+
413
+ const state = createMockState({
414
+ messages: [
415
+ { role: 'user', content: 'Hello' },
416
+ { role: 'assistant', content: '', tools: [] },
417
+ { role: 'tool', content: 'Result 1', tool_call_id: 'call-1' },
418
+ { role: 'tool', content: 'Result 2', tool_call_id: 'call-2' },
419
+ ] as any,
420
+ });
421
+
422
+ const context = createMockContext('tools_batch_result', {
423
+ parentMessageId: 'tool-msg-2',
424
+ });
425
+
426
+ const result = await agent.runner(context, state);
427
+
428
+ expect(result).toEqual({
429
+ type: 'call_llm',
430
+ payload: {
431
+ messages: state.messages,
432
+ model: 'gpt-4o-mini',
433
+ parentMessageId: 'tool-msg-2',
434
+ provider: 'openai',
435
+ tools: undefined,
436
+ },
437
+ });
438
+ });
439
+
440
+ it('should return request_human_approve when there are pending tools', async () => {
441
+ const agent = new GeneralChatAgent({
442
+ agentConfig: { maxSteps: 100 },
443
+ sessionId: 'test-session',
444
+ modelRuntimeConfig: mockModelRuntimeConfig,
445
+ });
446
+
447
+ const pendingPlugin: ChatToolPayload = {
448
+ id: 'call-3',
449
+ identifier: 'plugin-3',
450
+ apiName: 'api-3',
451
+ arguments: '{}',
452
+ type: 'default',
453
+ };
454
+
455
+ const state = createMockState({
456
+ messages: [
457
+ { role: 'user', content: 'Hello' },
458
+ { role: 'assistant', content: '', tools: [] },
459
+ { role: 'tool', content: 'Result 1', tool_call_id: 'call-1' },
460
+ { role: 'tool', content: 'Result 2', tool_call_id: 'call-2' },
461
+ {
462
+ role: 'tool',
463
+ content: '',
464
+ tool_call_id: 'call-3',
465
+ plugin: pendingPlugin,
466
+ pluginIntervention: { status: 'pending' },
467
+ },
468
+ ] as any,
469
+ });
470
+
471
+ const context = createMockContext('tools_batch_result', {
472
+ parentMessageId: 'tool-msg-2',
473
+ });
474
+
475
+ const result = await agent.runner(context, state);
476
+
477
+ expect(result).toEqual({
478
+ type: 'request_human_approve',
479
+ pendingToolsCalling: [pendingPlugin],
480
+ reason: 'Some tools still pending approval',
481
+ skipCreateToolMessage: true,
482
+ });
483
+ });
484
+ });
485
+
486
+ describe('error phase', () => {
487
+ it('should return finish instruction with error details', async () => {
488
+ const agent = new GeneralChatAgent({
489
+ agentConfig: { maxSteps: 100 },
490
+ sessionId: 'test-session',
491
+ modelRuntimeConfig: mockModelRuntimeConfig,
492
+ });
493
+
494
+ const state = createMockState();
495
+ const errorMessage = 'Network timeout';
496
+ const context = createMockContext('error', {
497
+ error: new Error(errorMessage),
498
+ });
499
+
500
+ const result = await agent.runner(context, state);
501
+
502
+ expect(result).toEqual({
503
+ type: 'finish',
504
+ reason: 'error_recovery',
505
+ reasonDetail: errorMessage,
506
+ });
507
+ });
508
+
509
+ it('should handle error without message', async () => {
510
+ const agent = new GeneralChatAgent({
511
+ agentConfig: { maxSteps: 100 },
512
+ sessionId: 'test-session',
513
+ modelRuntimeConfig: mockModelRuntimeConfig,
514
+ });
515
+
516
+ const state = createMockState();
517
+ const context = createMockContext('error', { error: {} });
518
+
519
+ const result = await agent.runner(context, state);
520
+
521
+ expect(result).toEqual({
522
+ type: 'finish',
523
+ reason: 'error_recovery',
524
+ reasonDetail: 'Unknown error occurred',
525
+ });
526
+ });
527
+ });
528
+
529
+ describe('unknown phase', () => {
530
+ it('should return finish instruction for unknown phase', async () => {
531
+ const agent = new GeneralChatAgent({
532
+ agentConfig: { maxSteps: 100 },
533
+ sessionId: 'test-session',
534
+ modelRuntimeConfig: mockModelRuntimeConfig,
535
+ });
536
+
537
+ const state = createMockState();
538
+ const context = createMockContext('unknown_phase' as any);
539
+
540
+ const result = await agent.runner(context, state);
541
+
542
+ expect(result).toEqual({
543
+ type: 'finish',
544
+ reason: 'agent_decision',
545
+ reasonDetail: 'Unknown phase: unknown_phase',
546
+ });
547
+ });
548
+ });
549
+
550
+ describe('intervention checking', () => {
551
+ it('should check intervention at API level when configured', async () => {
552
+ const agent = new GeneralChatAgent({
553
+ agentConfig: { maxSteps: 100 },
554
+ sessionId: 'test-session',
555
+ modelRuntimeConfig: mockModelRuntimeConfig,
556
+ });
557
+
558
+ const toolCall: ChatToolPayload = {
559
+ id: 'call-1',
560
+ identifier: 'plugin',
561
+ apiName: 'dangerous-api',
562
+ arguments: '{}',
563
+ type: 'default',
564
+ };
565
+
566
+ const state = createMockState({
567
+ toolManifestMap: {
568
+ plugin: {
569
+ identifier: 'plugin',
570
+ // Tool-level config
571
+ humanIntervention: 'never',
572
+ api: [
573
+ {
574
+ name: 'safe-api',
575
+ // Safe API
576
+ },
577
+ {
578
+ name: 'dangerous-api',
579
+ // API-level config overrides tool-level
580
+ humanIntervention: 'require',
581
+ },
582
+ ],
583
+ },
584
+ },
585
+ });
586
+
587
+ const context = createMockContext('llm_result', {
588
+ hasToolsCalling: true,
589
+ toolsCalling: [toolCall],
590
+ parentMessageId: 'msg-1',
591
+ });
592
+
593
+ const result = await agent.runner(context, state);
594
+
595
+ // Should require approval because API-level config overrides
596
+ expect(result).toEqual([
597
+ {
598
+ type: 'request_human_approve',
599
+ pendingToolsCalling: [toolCall],
600
+ reason: 'human_intervention_required',
601
+ },
602
+ ]);
603
+ });
604
+ });
605
+ });