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

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 (228) hide show
  1. package/.env.example +11 -0
  2. package/CHANGELOG.md +17 -0
  3. package/apps/desktop/src/main/controllers/AuthCtr.ts +27 -2
  4. package/apps/desktop/src/main/core/infrastructure/ProtocolManager.ts +9 -4
  5. package/changelog/v1.json +5 -0
  6. package/docs/development/database-schema.dbml +2 -0
  7. package/docs/self-hosting/environment-variables/basic.mdx +49 -3
  8. package/docs/self-hosting/environment-variables/basic.zh-CN.mdx +49 -4
  9. package/locales/ar/discover.json +45 -0
  10. package/locales/ar/marketAuth.json +42 -0
  11. package/locales/ar/setting.json +94 -1
  12. package/locales/bg-BG/discover.json +45 -0
  13. package/locales/bg-BG/marketAuth.json +42 -0
  14. package/locales/bg-BG/setting.json +94 -1
  15. package/locales/de-DE/discover.json +45 -0
  16. package/locales/de-DE/marketAuth.json +42 -0
  17. package/locales/de-DE/setting.json +94 -1
  18. package/locales/en-US/discover.json +45 -0
  19. package/locales/en-US/marketAuth.json +42 -0
  20. package/locales/en-US/setting.json +94 -1
  21. package/locales/es-ES/discover.json +45 -0
  22. package/locales/es-ES/marketAuth.json +42 -0
  23. package/locales/es-ES/setting.json +94 -1
  24. package/locales/fa-IR/discover.json +45 -0
  25. package/locales/fa-IR/marketAuth.json +42 -0
  26. package/locales/fa-IR/setting.json +94 -1
  27. package/locales/fr-FR/discover.json +45 -0
  28. package/locales/fr-FR/marketAuth.json +42 -0
  29. package/locales/fr-FR/setting.json +94 -1
  30. package/locales/it-IT/discover.json +45 -0
  31. package/locales/it-IT/marketAuth.json +42 -0
  32. package/locales/it-IT/setting.json +94 -1
  33. package/locales/ja-JP/discover.json +45 -0
  34. package/locales/ja-JP/marketAuth.json +42 -0
  35. package/locales/ja-JP/setting.json +94 -1
  36. package/locales/ko-KR/discover.json +45 -0
  37. package/locales/ko-KR/marketAuth.json +42 -0
  38. package/locales/ko-KR/setting.json +94 -1
  39. package/locales/nl-NL/discover.json +45 -0
  40. package/locales/nl-NL/marketAuth.json +42 -0
  41. package/locales/nl-NL/setting.json +94 -1
  42. package/locales/pl-PL/discover.json +45 -0
  43. package/locales/pl-PL/marketAuth.json +42 -0
  44. package/locales/pl-PL/setting.json +94 -1
  45. package/locales/pt-BR/discover.json +45 -0
  46. package/locales/pt-BR/marketAuth.json +42 -0
  47. package/locales/pt-BR/setting.json +94 -1
  48. package/locales/ru-RU/discover.json +45 -0
  49. package/locales/ru-RU/marketAuth.json +42 -0
  50. package/locales/ru-RU/setting.json +94 -1
  51. package/locales/tr-TR/discover.json +45 -0
  52. package/locales/tr-TR/marketAuth.json +42 -0
  53. package/locales/tr-TR/setting.json +94 -1
  54. package/locales/vi-VN/discover.json +45 -0
  55. package/locales/vi-VN/marketAuth.json +42 -0
  56. package/locales/vi-VN/setting.json +94 -1
  57. package/locales/zh-CN/discover.json +45 -0
  58. package/locales/zh-CN/marketAuth.json +42 -0
  59. package/locales/zh-CN/setting.json +94 -1
  60. package/locales/zh-TW/discover.json +45 -0
  61. package/locales/zh-TW/marketAuth.json +42 -0
  62. package/locales/zh-TW/setting.json +94 -1
  63. package/package.json +27 -26
  64. package/packages/const/src/url.ts +1 -0
  65. package/packages/database/migrations/0044_add_tool_intervention.sql +1 -0
  66. package/packages/database/migrations/0044_high_toxin.sql +1 -0
  67. package/packages/database/migrations/0045_add_tool_intervention.sql +1 -0
  68. package/packages/database/migrations/meta/0039_snapshot.json +1 -1
  69. package/packages/database/migrations/meta/0044_snapshot.json +7813 -0
  70. package/packages/database/migrations/meta/0045_snapshot.json +8431 -0
  71. package/packages/database/migrations/meta/_journal.json +14 -0
  72. package/packages/database/src/core/migrations.json +36 -7
  73. package/packages/database/src/models/message.ts +1 -1
  74. package/packages/database/src/models/session.ts +42 -1
  75. package/packages/database/src/schemas/agent.ts +1 -0
  76. package/packages/database/src/schemas/message.ts +5 -8
  77. package/packages/electron-client-ipc/src/events/index.ts +6 -1
  78. package/packages/electron-client-ipc/src/events/remoteServer.ts +8 -0
  79. package/packages/fetch-sse/package.json +29 -0
  80. package/packages/{utils/src/fetch → fetch-sse/src}/__tests__/fetchSSE.test.ts +4 -4
  81. package/packages/{utils/src/fetch → fetch-sse/src}/__tests__/parseError.test.ts +7 -4
  82. package/packages/{utils/src/fetch → fetch-sse/src}/fetchSSE.ts +2 -2
  83. package/packages/{utils/src/fetch → fetch-sse/src}/parseError.ts +3 -3
  84. package/packages/model-bank/src/aiModels/mistral.ts +2 -1
  85. package/packages/model-runtime/src/core/contextBuilders/anthropic.test.ts +17 -11
  86. package/packages/model-runtime/src/core/contextBuilders/anthropic.ts +1 -1
  87. package/packages/model-runtime/src/core/contextBuilders/google.test.ts +1 -1
  88. package/packages/model-runtime/src/core/contextBuilders/google.ts +3 -6
  89. package/packages/model-runtime/src/core/contextBuilders/openai.test.ts +4 -2
  90. package/packages/model-runtime/src/core/contextBuilders/openai.ts +1 -1
  91. package/packages/model-runtime/src/core/openaiCompatibleFactory/createImage.test.ts +1 -1
  92. package/packages/model-runtime/src/core/openaiCompatibleFactory/createImage.ts +1 -1
  93. package/packages/model-runtime/src/core/openaiCompatibleFactory/index.test.ts +3 -6
  94. package/packages/model-runtime/src/core/streams/openai/responsesStream.test.ts +1 -1
  95. package/packages/model-runtime/src/helpers/mergeChatMethodOptions.ts +2 -1
  96. package/packages/model-runtime/src/providers/aihubmix/index.test.ts +1 -1
  97. package/packages/model-runtime/src/providers/anthropic/generateObject.test.ts +1 -1
  98. package/packages/model-runtime/src/providers/anthropic/index.test.ts +1 -1
  99. package/packages/model-runtime/src/providers/baichuan/index.test.ts +1 -1
  100. package/packages/model-runtime/src/providers/bedrock/index.test.ts +1 -1
  101. package/packages/model-runtime/src/providers/bfl/createImage.test.ts +4 -4
  102. package/packages/model-runtime/src/providers/bfl/createImage.ts +1 -1
  103. package/packages/model-runtime/src/providers/cloudflare/index.test.ts +1 -1
  104. package/packages/model-runtime/src/providers/cohere/index.test.ts +1 -1
  105. package/packages/model-runtime/src/providers/google/createImage.test.ts +2 -2
  106. package/packages/model-runtime/src/providers/google/createImage.ts +1 -1
  107. package/packages/model-runtime/src/providers/google/generateObject.test.ts +1 -1
  108. package/packages/model-runtime/src/providers/google/index.test.ts +1 -4
  109. package/packages/model-runtime/src/providers/groq/index.test.ts +1 -1
  110. package/packages/model-runtime/src/providers/hunyuan/index.test.ts +1 -1
  111. package/packages/model-runtime/src/providers/minimax/createImage.test.ts +1 -1
  112. package/packages/model-runtime/src/providers/mistral/index.test.ts +1 -1
  113. package/packages/model-runtime/src/providers/moonshot/index.test.ts +1 -1
  114. package/packages/model-runtime/src/providers/novita/index.test.ts +1 -1
  115. package/packages/model-runtime/src/providers/ollama/index.test.ts +43 -32
  116. package/packages/model-runtime/src/providers/ollama/index.ts +31 -7
  117. package/packages/model-runtime/src/providers/openrouter/index.test.ts +1 -1
  118. package/packages/model-runtime/src/providers/perplexity/index.test.ts +1 -1
  119. package/packages/model-runtime/src/providers/ppio/index.test.ts +1 -1
  120. package/packages/model-runtime/src/providers/qwen/createImage.test.ts +1 -1
  121. package/packages/model-runtime/src/providers/search1api/index.test.ts +1 -1
  122. package/packages/model-runtime/src/providers/siliconcloud/createImage.ts +1 -1
  123. package/packages/model-runtime/src/providers/taichu/index.test.ts +1 -1
  124. package/packages/model-runtime/src/providers/wenxin/index.test.ts +1 -1
  125. package/packages/model-runtime/src/providers/zhipu/index.test.ts +1 -1
  126. package/packages/model-runtime/src/utils/errorResponse.test.ts +1 -1
  127. package/packages/ssrf-safe-fetch/index.browser.ts +14 -0
  128. package/packages/ssrf-safe-fetch/package.json +8 -1
  129. package/packages/types/src/discover/assistants.ts +16 -0
  130. package/packages/types/src/index.ts +1 -0
  131. package/packages/types/src/message/common/tools.ts +10 -0
  132. package/packages/types/src/message/db/item.ts +15 -1
  133. package/packages/types/src/message/ui/params.ts +15 -1
  134. package/packages/types/src/meta.ts +4 -0
  135. package/packages/types/src/session/agentSession.ts +2 -0
  136. package/packages/utils/src/imageToBase64.ts +17 -10
  137. package/packages/utils/src/index.ts +1 -1
  138. package/src/app/(backend)/market/agent/[[...segments]]/route.ts +153 -0
  139. package/src/app/(backend)/market/oidc/[[...segments]]/route.ts +207 -0
  140. package/src/app/[variants]/(main)/(mobile)/me/settings/features/useCategory.tsx +1 -0
  141. package/src/app/[variants]/(main)/_layout/Desktop/SideBar/PinList/index.tsx +4 -2
  142. package/src/app/[variants]/(main)/chat/settings/features/AgentInfoDescription/index.tsx +349 -0
  143. package/src/app/[variants]/(main)/chat/settings/features/HeaderContent.tsx +2 -2
  144. package/src/app/[variants]/(main)/chat/settings/features/PublishResultModal/index.tsx +64 -0
  145. package/src/app/[variants]/(main)/chat/settings/features/SmartAgentActionButton/MarketPublishButton.tsx +196 -0
  146. package/src/app/[variants]/(main)/chat/settings/features/SmartAgentActionButton/MarketPublishModal.tsx +358 -0
  147. package/src/app/[variants]/(main)/chat/settings/features/SmartAgentActionButton/index.tsx +75 -0
  148. package/src/app/[variants]/(main)/discover/(detail)/assistant/AssistantDetailPage.tsx +11 -2
  149. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/Client.tsx +12 -1
  150. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Nav.tsx +19 -12
  151. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Overview/TagList.tsx +14 -5
  152. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Overview/index.tsx +2 -0
  153. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Related/index.tsx +14 -5
  154. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/SystemRole/TagList.tsx +14 -5
  155. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/SystemRole/index.tsx +43 -29
  156. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Versions/index.tsx +137 -0
  157. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/index.tsx +2 -0
  158. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Header.tsx +9 -10
  159. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Sidebar/ActionButton/AddAgent.tsx +105 -14
  160. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Sidebar/Related/index.tsx +20 -6
  161. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/StatusPage/index.tsx +113 -0
  162. package/src/app/[variants]/(main)/discover/(detail)/features/Breadcrumb.tsx +4 -3
  163. package/src/app/[variants]/(main)/discover/(list)/_layout/Desktop/Nav.tsx +3 -1
  164. package/src/app/[variants]/(main)/discover/(list)/assistant/AssistantPage.tsx +4 -1
  165. package/src/app/[variants]/(main)/discover/(list)/assistant/Client.tsx +6 -2
  166. package/src/app/[variants]/(main)/discover/(list)/assistant/features/Category/index.tsx +7 -3
  167. package/src/app/[variants]/(main)/discover/(list)/assistant/features/List/Item.tsx +13 -2
  168. package/src/app/[variants]/(main)/discover/(list)/assistant/features/MarketSourceSwitch.tsx +64 -0
  169. package/src/app/[variants]/(main)/discover/(list)/features/SortButton/index.tsx +26 -7
  170. package/src/app/[variants]/(main)/profile/_layout/Desktop/index.tsx +10 -10
  171. package/src/app/[variants]/(main)/settings/_layout/type.ts +1 -1
  172. package/src/app/[variants]/(main)/settings/agent/index.tsx +11 -10
  173. package/src/app/[variants]/(main)/settings/common/index.tsx +1 -1
  174. package/src/app/[variants]/(main)/settings/page.tsx +13 -10
  175. package/src/app/[variants]/(main)/settings/provider/ProviderMenu/Item.tsx +35 -36
  176. package/src/app/[variants]/(main)/settings/provider/ProviderMenu/SearchResult.tsx +5 -5
  177. package/src/app/[variants]/(main)/settings/provider/_layout/Desktop/Container.tsx +10 -4
  178. package/src/app/market-auth-callback/layout.tsx +15 -0
  179. package/src/app/market-auth-callback/page.tsx +196 -0
  180. package/src/features/AgentSetting/AgentPrompt/TokenTag.tsx +3 -2
  181. package/src/features/AgentSetting/AgentTTS/SelectWithTTSPreview.tsx +1 -1
  182. package/src/features/AgentSetting/store/action.ts +1 -1
  183. package/src/features/ChatInput/ActionBar/STT/browser.tsx +1 -1
  184. package/src/features/ChatInput/ActionBar/STT/openai.tsx +1 -1
  185. package/src/features/Conversation/components/Extras/TTS/InitPlayer.tsx +1 -1
  186. package/src/features/PluginTag/PluginStatus.tsx +1 -1
  187. package/src/hooks/useAgentOwnershipCheck.ts +143 -0
  188. package/src/instrumentation.node.ts +3 -2
  189. package/src/layout/AuthProvider/MarketAuth/MarketAuthProvider.tsx +364 -0
  190. package/src/layout/AuthProvider/MarketAuth/errors.ts +75 -0
  191. package/src/layout/AuthProvider/MarketAuth/index.ts +2 -0
  192. package/src/layout/AuthProvider/MarketAuth/oidc.ts +382 -0
  193. package/src/layout/AuthProvider/MarketAuth/types.ts +64 -0
  194. package/src/layout/AuthProvider/index.tsx +17 -4
  195. package/src/locales/default/discover.ts +46 -0
  196. package/src/locales/default/index.ts +2 -0
  197. package/src/locales/default/marketAuth.ts +42 -0
  198. package/src/locales/default/setting.ts +94 -1
  199. package/src/server/globalConfig/genServerAiProviderConfig.test.ts +5 -5
  200. package/src/server/globalConfig/genServerAiProviderConfig.ts +1 -1
  201. package/src/server/routers/lambda/market/index.ts +36 -14
  202. package/src/server/routers/lambda/message.ts +2 -2
  203. package/src/server/services/discover/index.test.ts +153 -11
  204. package/src/server/services/discover/index.ts +339 -40
  205. package/src/server/sitemap.ts +49 -35
  206. package/src/services/_url.ts +15 -1
  207. package/src/services/chat/chat.test.ts +5 -5
  208. package/src/services/chat/clientModelRuntime.test.ts +1 -1
  209. package/src/services/chat/index.ts +6 -6
  210. package/src/services/chat/types.ts +1 -2
  211. package/src/services/discover.ts +16 -5
  212. package/src/services/electron/remoteServer.ts +8 -1
  213. package/src/services/marketApi.ts +124 -0
  214. package/src/services/models.ts +2 -1
  215. package/src/store/discover/slices/assistant/action.ts +20 -7
  216. package/{packages/utils/src → src/utils}/electron/desktopRemoteRPCFetch.ts +1 -1
  217. package/{packages/utils/src → src/utils/server}/parseModels.ts +1 -2
  218. package/vitest.config.mts +2 -0
  219. package/packages/model-runtime/src/utils/imageToBase64.test.ts +0 -91
  220. package/packages/model-runtime/src/utils/imageToBase64.ts +0 -62
  221. package/src/app/[variants]/(main)/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx +0 -98
  222. package/src/app/[variants]/(main)/chat/settings/features/SubmitAgentButton/index.tsx +0 -35
  223. package/src/app/[variants]/(main)/chat/settings/features/SubmitAgentButton/style.ts +0 -47
  224. /package/packages/{utils/src/fetch → fetch-sse/src}/headers.ts +0 -0
  225. /package/packages/{utils/src/fetch → fetch-sse/src}/index.ts +0 -0
  226. /package/packages/{utils/src/fetch → fetch-sse/src}/request.ts +0 -0
  227. /package/{packages/utils/src → src/utils/server}/__snapshots__/parseModels.test.ts.snap +0 -0
  228. /package/{packages/utils/src → src/utils/server}/parseModels.test.ts +0 -0
@@ -1,7 +1,7 @@
1
1
  // @vitest-environment node
2
- import { LobeOpenAICompatibleRuntime } from '@lobechat/model-runtime';
3
2
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
3
 
4
+ import { LobeOpenAICompatibleRuntime } from '../../core/BaseAI';
5
5
  import { testProvider } from '../../providerTestUtils';
6
6
  import { LobeZhipuAI, params } from './index';
7
7
 
@@ -1,7 +1,7 @@
1
- import { AgentRuntimeErrorType } from '@lobechat/model-runtime';
2
1
  import { ChatErrorType } from '@lobechat/types';
3
2
  import { describe, expect, it, vi } from 'vitest';
4
3
 
4
+ import { AgentRuntimeErrorType } from '../types/error';
5
5
  import { createErrorResponse } from './errorResponse';
6
6
 
7
7
  describe('createErrorResponse', () => {
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Browser version of SSRF-safe fetch
3
+ * In browser environments, we simply use the native fetch API
4
+ * as SSRF attacks are not applicable in client-side code
5
+ */
6
+
7
+ /**
8
+ * Browser-safe fetch implementation
9
+ * Uses native fetch API in browser environments
10
+ */
11
+ // eslint-disable-next-line no-undef
12
+ export const ssrfSafeFetch = async (url: string, options?: RequestInit): Promise<Response> => {
13
+ return fetch(url, options);
14
+ };
@@ -2,7 +2,14 @@
2
2
  "name": "ssrf-safe-fetch",
3
3
  "version": "1.0.0",
4
4
  "private": true,
5
- "description": "",
5
+ "description": "SSRF-safe fetch implementation with browser/node conditional exports",
6
+ "exports": {
7
+ ".": {
8
+ "browser": "./index.browser.ts",
9
+ "node": "./index.ts",
10
+ "default": "./index.ts"
11
+ }
12
+ },
6
13
  "main": "index.ts",
7
14
  "scripts": {
8
15
  "test": "vitest run"
@@ -24,6 +24,7 @@ export enum AssistantSorts {
24
24
  CreatedAt = 'createdAt',
25
25
  Identifier = 'identifier',
26
26
  KnowledgeCount = 'knowledgeCount',
27
+ MyOwn = 'myown',
27
28
  PluginCount = 'pluginCount',
28
29
  Title = 'title',
29
30
  TokenUsage = 'tokenUsage',
@@ -34,6 +35,7 @@ export enum AssistantNavKey {
34
35
  Overview = 'overview',
35
36
  Related = 'related',
36
37
  SystemRole = 'systemRole',
38
+ Version = 'version'
37
39
  }
38
40
 
39
41
  export interface DiscoverAssistantItem extends Omit<LobeAgentSettings, 'meta'>, MetaData {
@@ -47,14 +49,18 @@ export interface DiscoverAssistantItem extends Omit<LobeAgentSettings, 'meta'>,
47
49
  tokenUsage: number;
48
50
  }
49
51
 
52
+ export type AssistantMarketSource = 'legacy' | 'new';
53
+
50
54
  export interface AssistantQueryParams {
51
55
  category?: string;
52
56
  locale?: string;
53
57
  order?: 'asc' | 'desc';
58
+ ownerId?: string;
54
59
  page?: number;
55
60
  pageSize?: number;
56
61
  q?: string;
57
62
  sort?: AssistantSorts;
63
+ source?: AssistantMarketSource;
58
64
  }
59
65
 
60
66
  export interface AssistantListResponse {
@@ -66,7 +72,17 @@ export interface AssistantListResponse {
66
72
  }
67
73
 
68
74
  export interface DiscoverAssistantDetail extends DiscoverAssistantItem {
75
+ currentVersion?: string;
69
76
  examples?: FewShots;
70
77
  related: DiscoverAssistantItem[];
71
78
  summary?: string;
79
+ versions?: DiscoverAssistantVersion[];
80
+ }
81
+
82
+ export interface DiscoverAssistantVersion {
83
+ createdAt?: string;
84
+ isLatest?: boolean;
85
+ isValidated?: boolean;
86
+ status?: 'published' | 'unpublished' | 'archived' | 'deprecated';
87
+ version: string;
72
88
  }
@@ -30,5 +30,6 @@ export * from './user';
30
30
  // it more likes the UI message payload
31
31
  export * from './openai/chat';
32
32
  export * from './openai/plugin';
33
+ export * from './subscription';
33
34
  export * from './trace';
34
35
  export * from './zustand';
@@ -103,3 +103,13 @@ export interface ChatMessagePluginError {
103
103
  message: string;
104
104
  type: IPluginErrorType;
105
105
  }
106
+
107
+ export interface ToolIntervention {
108
+ rejectedReason?: string;
109
+ status?: 'pending' | 'approved' | 'rejected' | 'none';
110
+ }
111
+
112
+ export const ToolInterventionSchema = z.object({
113
+ rejectedReason: z.string().optional(),
114
+ status: z.enum(['pending', 'approved', 'rejected', 'none']).optional(),
115
+ });
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable sort-keys-fix/sort-keys-fix , typescript-sort-keys/interface */
2
2
  import { GroundingSearch } from '../../search';
3
- import { MessageMetadata, ModelReasoning } from '../common';
3
+ import { MessageMetadata, ModelReasoning, ToolIntervention } from '../common';
4
4
 
5
5
  export interface DBMessageItem {
6
6
  id: string;
@@ -33,3 +33,17 @@ export interface DBMessageItem {
33
33
  updatedAt: Date;
34
34
  createdAt: Date;
35
35
  }
36
+
37
+ export interface MessagePluginItem {
38
+ id: string;
39
+ toolCallId?: string;
40
+ type: string;
41
+ intervention?: ToolIntervention;
42
+ apiName?: string;
43
+ arguments?: string;
44
+ identifier?: string;
45
+ state?: any;
46
+ error?: any;
47
+ clientId?: string;
48
+ userId: string;
49
+ }
@@ -4,7 +4,7 @@ import { z } from 'zod';
4
4
  import { UploadFileItem } from '../../files';
5
5
  import { MessageSemanticSearchChunk } from '../../rag';
6
6
  import { ChatMessageError, ChatMessageErrorSchema } from '../common/base';
7
- import { ChatPluginPayload } from '../common/tools';
7
+ import { ChatPluginPayload, ToolInterventionSchema } from '../common/tools';
8
8
  import { UIChatMessage } from './chat';
9
9
  import { SemanticSearchChunkSchema } from './rag';
10
10
 
@@ -148,3 +148,17 @@ export const CreateNewMessageParamsSchema = z
148
148
  fileChunks: z.array(SemanticSearchChunkSchema).optional(),
149
149
  })
150
150
  .passthrough();
151
+
152
+ export const UpdateMessagePluginSchema = z.object({
153
+ id: z.string().optional(),
154
+ toolCallId: z.string().optional(),
155
+ type: z.string().optional(),
156
+ intervention: ToolInterventionSchema.optional(),
157
+ apiName: z.string().optional(),
158
+ arguments: z.string().optional(),
159
+ identifier: z.string().optional(),
160
+ state: z.any().optional(),
161
+ error: z.any().optional(),
162
+ clientId: z.string().optional(),
163
+ userId: z.string().optional(),
164
+ });
@@ -10,6 +10,10 @@ export const LobeMetaDataSchema = z.object({
10
10
  */
11
11
  backgroundColor: z.string().optional(),
12
12
  description: z.string().optional(),
13
+ /**
14
+ * Market agent identifier for published agents
15
+ */
16
+ marketIdentifier: z.string().optional(),
13
17
 
14
18
  tags: z.array(z.string()).optional(),
15
19
  /**
@@ -20,6 +20,8 @@ export interface LobeAgentSession {
20
20
  createdAt: Date;
21
21
  group?: string;
22
22
  id: string;
23
+ /** Market agent identifier for published agents */
24
+ marketIdentifier?: string;
23
25
  meta: MetaData;
24
26
  model: string;
25
27
  pinned?: boolean;
@@ -36,23 +36,30 @@ export const imageToBase64 = ({
36
36
  return canvas.toDataURL(type);
37
37
  };
38
38
 
39
+ /**
40
+ * Convert image URL to base64
41
+ * Uses SSRF-safe fetch on server-side to prevent SSRF attacks
42
+ */
39
43
  export const imageUrlToBase64 = async (
40
44
  imageUrl: string,
41
45
  ): Promise<{ base64: string; mimeType: string }> => {
42
46
  try {
43
- const res = await fetch(imageUrl);
47
+ const isServer = typeof window === 'undefined';
48
+
49
+ // Use SSRF-safe fetch on server-side to prevent SSRF attacks
50
+ const res = isServer
51
+ ? await import('ssrf-safe-fetch').then((m) => m.ssrfSafeFetch(imageUrl))
52
+ : await fetch(imageUrl);
53
+
44
54
  const blob = await res.blob();
45
55
  const arrayBuffer = await blob.arrayBuffer();
46
56
 
47
- const base64 =
48
- typeof btoa === 'function'
49
- ? btoa(
50
- new Uint8Array(arrayBuffer).reduce(
51
- (data, byte) => data + String.fromCharCode(byte),
52
- '',
53
- ),
54
- )
55
- : Buffer.from(arrayBuffer).toString('base64');
57
+ // Client-side uses btoa, server-side uses Buffer
58
+ const base64 = isServer
59
+ ? Buffer.from(arrayBuffer).toString('base64')
60
+ : btoa(
61
+ new Uint8Array(arrayBuffer).reduce((data, byte) => data + String.fromCharCode(byte), ''),
62
+ );
56
63
 
57
64
  return { base64, mimeType: blob.type };
58
65
  } catch (error) {
@@ -4,9 +4,9 @@ export * from './detectChinese';
4
4
  export * from './format';
5
5
  export * from './imageToBase64';
6
6
  export * from './keyboard';
7
+ export * from './merge';
7
8
  export * from './number';
8
9
  export * from './object';
9
- export * from './parseModels';
10
10
  export * from './pricing';
11
11
  export * from './safeParseJSON';
12
12
  export * from './sleep';
@@ -0,0 +1,153 @@
1
+ import { MarketSDK } from '@lobehub/market-sdk';
2
+ import { NextRequest, NextResponse } from 'next/server';
3
+
4
+ type RouteContext = {
5
+ params: Promise<{
6
+ segments?: string[];
7
+ }>;
8
+ };
9
+
10
+ const MARKET_BASE_URL = process.env.NEXT_PUBLIC_MARKET_BASE_URL || 'http://127.0.0.1:8787';
11
+
12
+ const extractAccessToken = (req: NextRequest) => {
13
+ const authorization = req.headers.get('authorization');
14
+ if (!authorization) return undefined;
15
+
16
+ const [scheme, token] = authorization.split(' ');
17
+ if (scheme?.toLowerCase() !== 'bearer' || !token) return undefined;
18
+
19
+ return token;
20
+ };
21
+
22
+ const methodNotAllowed = (methods: string[]) =>
23
+ NextResponse.json(
24
+ {
25
+ error: 'method_not_allowed',
26
+ message: `Allowed methods: ${methods.join(', ')}`,
27
+ status: 'error',
28
+ },
29
+ {
30
+ headers: { Allow: methods.join(', ') },
31
+ status: 405,
32
+ },
33
+ );
34
+
35
+ const badRequest = (error: string, message: string) =>
36
+ NextResponse.json(
37
+ {
38
+ error,
39
+ message,
40
+ status: 'error',
41
+ },
42
+ { status: 400 },
43
+ );
44
+
45
+ const notFound = (reason: string) =>
46
+ NextResponse.json(
47
+ {
48
+ error: 'not_found',
49
+ message: reason,
50
+ status: 'error',
51
+ },
52
+ { status: 404 },
53
+ );
54
+
55
+ const handleAgent = async (req: NextRequest, segments: string[]) => {
56
+ const accessToken = extractAccessToken(req);
57
+ const market = new MarketSDK({
58
+ accessToken,
59
+ baseURL: MARKET_BASE_URL,
60
+ });
61
+
62
+ if (segments.length === 0) {
63
+ return notFound('Missing agent action.');
64
+ }
65
+
66
+ const [action, ...rest] = segments;
67
+
68
+ if (action === 'create') {
69
+ if (req.method !== 'POST') return methodNotAllowed(['POST']);
70
+
71
+ try {
72
+ const payload = await req.json();
73
+ const response = await market.agents.createAgent(payload);
74
+ return NextResponse.json(response);
75
+ } catch (error) {
76
+ console.error('[Market] Failed to create agent:', error);
77
+ return NextResponse.json(
78
+ {
79
+ error: 'create_agent_failed',
80
+ message: error instanceof Error ? error.message : 'Unknown error',
81
+ status: 'error',
82
+ },
83
+ { status: 500 },
84
+ );
85
+ }
86
+ }
87
+
88
+ if (action === 'versions') {
89
+ if (rest.length !== 1 || rest[0] !== 'create') {
90
+ return notFound('Requested agent version endpoint is not available.');
91
+ }
92
+
93
+ if (req.method !== 'POST') return methodNotAllowed(['POST']);
94
+
95
+ try {
96
+ const payload = await req.json();
97
+ if (typeof payload !== 'object' || payload === null) {
98
+ return badRequest('invalid_payload', 'Request body must be a JSON object.');
99
+ }
100
+
101
+ const identifier = (payload as { identifier?: string }).identifier;
102
+ if (!identifier) {
103
+ return badRequest('missing_identifier', 'Identifier is required to create agent version.');
104
+ }
105
+
106
+ const response = await market.agents.createAgentVersion(payload);
107
+ return NextResponse.json(response);
108
+ } catch (error) {
109
+ console.error('[Market] Failed to create agent version:', error);
110
+ return NextResponse.json(
111
+ {
112
+ error: 'create_agent_version_failed',
113
+ message: error instanceof Error ? error.message : 'Unknown error',
114
+ status: 'error',
115
+ },
116
+ { status: 500 },
117
+ );
118
+ }
119
+ }
120
+
121
+ if (segments.length === 1) {
122
+ if (req.method !== 'GET') return methodNotAllowed(['GET']);
123
+
124
+ try {
125
+ const response = await market.agents.getAgentDetail(action);
126
+ return NextResponse.json(response);
127
+ } catch (error) {
128
+ console.error('[Market] Failed to get agent detail:', error);
129
+ return NextResponse.json(
130
+ {
131
+ error: 'get_agent_detail_failed',
132
+ message: error instanceof Error ? error.message : 'Unknown error',
133
+ status: 'error',
134
+ },
135
+ { status: 500 },
136
+ );
137
+ }
138
+ }
139
+
140
+ return notFound('Requested agent endpoint is not available.');
141
+ };
142
+
143
+ const handleProxy = async (req: NextRequest, context: RouteContext) => {
144
+ const { segments } = await context.params;
145
+ const normalizedSegments = segments?.map((segment) => decodeURIComponent(segment)) ?? [];
146
+
147
+ return handleAgent(req, normalizedSegments);
148
+ };
149
+
150
+ export const GET = (req: NextRequest, context: RouteContext) => handleProxy(req, context);
151
+ export const POST = (req: NextRequest, context: RouteContext) => handleProxy(req, context);
152
+
153
+ export const dynamic = 'force-dynamic';
@@ -0,0 +1,207 @@
1
+ import { MarketSDK } from '@lobehub/market-sdk';
2
+ import { NextRequest, NextResponse } from 'next/server';
3
+
4
+ type RouteContext = {
5
+ params: Promise<{
6
+ segments?: string[];
7
+ }>;
8
+ };
9
+
10
+ const MARKET_BASE_URL = process.env.NEXT_PUBLIC_MARKET_BASE_URL || 'http://127.0.0.1:8787';
11
+ const ALLOWED_ENDPOINTS = new Set(['handoff', 'token', 'userinfo']);
12
+
13
+ const ensureEndpoint = (segments?: string[]) => {
14
+ if (!segments || segments.length === 0) {
15
+ return { error: 'missing_endpoint', status: 404 } as const;
16
+ }
17
+
18
+ if (segments.length !== 1) {
19
+ return { error: 'unsupported_nested_path', status: 404 } as const;
20
+ }
21
+
22
+ const endpoint = segments[0];
23
+
24
+ if (!ALLOWED_ENDPOINTS.has(endpoint)) {
25
+ return { error: 'unknown_endpoint', status: 404 } as const;
26
+ }
27
+
28
+ return { endpoint } as const;
29
+ };
30
+
31
+ const methodNotAllowed = (allowed: string[]) =>
32
+ NextResponse.json(
33
+ {
34
+ error: 'method_not_allowed',
35
+ message: `Allowed methods: ${allowed.join(', ')}`,
36
+ status: 'error',
37
+ },
38
+ {
39
+ headers: { Allow: allowed.join(', ') },
40
+ status: 405,
41
+ },
42
+ );
43
+
44
+ const handleProxy = async (req: NextRequest, context: RouteContext) => {
45
+ const market = new MarketSDK({
46
+ baseURL: MARKET_BASE_URL,
47
+ });
48
+
49
+ const { segments } = await context.params;
50
+ const endpointResult = ensureEndpoint(segments);
51
+
52
+ if ('error' in endpointResult) {
53
+ return NextResponse.json(
54
+ {
55
+ error: endpointResult.error,
56
+ message: 'Requested endpoint is not available.',
57
+ status: 'error',
58
+ },
59
+ { status: endpointResult.status },
60
+ );
61
+ }
62
+
63
+ const endpoint = endpointResult.endpoint;
64
+
65
+ switch (endpoint) {
66
+ case 'handoff': {
67
+ try {
68
+ const id = req.nextUrl.searchParams.get('id');
69
+ if (id) {
70
+ const handoff = await market.auth.getOAuthHandoff(id);
71
+ return new NextResponse(JSON.stringify(handoff), { status: 200 });
72
+ } else {
73
+ return NextResponse.json(
74
+ {
75
+ error: 'missing_id',
76
+ message: 'ID is required for handoff proxy.',
77
+ status: 'error',
78
+ },
79
+ { status: 400 },
80
+ );
81
+ }
82
+ } catch (error) {
83
+ return NextResponse.json(
84
+ {
85
+ error: 'handoff_proxy_failed',
86
+ message: error instanceof Error ? error.message : 'Unknown error',
87
+ status: 'error',
88
+ },
89
+ { status: 500 },
90
+ );
91
+ }
92
+ }
93
+
94
+ case 'token': {
95
+ if (req.method !== 'POST') {
96
+ return methodNotAllowed(['POST']);
97
+ }
98
+
99
+ try {
100
+ const body = await req.text();
101
+ const form = new URLSearchParams(body);
102
+
103
+ const grantType = (form.get('grant_type') || 'authorization_code') as
104
+ | 'authorization_code'
105
+ | 'refresh_token';
106
+
107
+ if (grantType === 'authorization_code') {
108
+ const clientId = form.get('client_id');
109
+ const code = form.get('code');
110
+ const codeVerifier = form.get('code_verifier');
111
+ const redirectUri = form.get('redirect_uri');
112
+
113
+ const response = await market.auth.exchangeOAuthToken({
114
+ clientId: clientId as string,
115
+ code: code as string,
116
+ codeVerifier: codeVerifier as string,
117
+ grantType: 'authorization_code',
118
+ redirectUri: redirectUri as string,
119
+ });
120
+
121
+ return NextResponse.json(response);
122
+ }
123
+
124
+ if (grantType === 'refresh_token') {
125
+ const refreshToken = form.get('refresh_token');
126
+ const clientId = form.get('client_id');
127
+
128
+ const response = await market.auth.exchangeOAuthToken({
129
+ clientId: clientId ?? undefined,
130
+ grantType: 'refresh_token',
131
+ refreshToken: refreshToken as string,
132
+ });
133
+
134
+ return NextResponse.json(response);
135
+ }
136
+
137
+ return NextResponse.json(
138
+ {
139
+ error: 'unsupported_grant_type',
140
+ message: `Unsupported grant_type: ${grantType}`,
141
+ status: 'error',
142
+ },
143
+ { status: 400 },
144
+ );
145
+ } catch (error) {
146
+ console.error('[MarketOIDC] Failed to proxy token request:', error);
147
+ return NextResponse.json(
148
+ {
149
+ error: 'token_proxy_failed',
150
+ message: error instanceof Error ? error.message : 'Unknown error',
151
+ status: 'error',
152
+ },
153
+ { status: 500 },
154
+ );
155
+ }
156
+ }
157
+
158
+ case 'userinfo': {
159
+ if (req.method !== 'POST') {
160
+ return methodNotAllowed(['POST']);
161
+ }
162
+
163
+ try {
164
+ const { token } = (await req.json()) as { token?: string };
165
+ if (!token) {
166
+ return NextResponse.json(
167
+ {
168
+ error: 'missing_token',
169
+ message: 'Token is required for userinfo proxy.',
170
+ status: 'error',
171
+ },
172
+ { status: 400 },
173
+ );
174
+ }
175
+
176
+ const response = await market.auth.getUserInfo(token);
177
+ return NextResponse.json(response);
178
+ } catch (error) {
179
+ console.error('[MarketOIDC] Failed to proxy userinfo request:', error);
180
+ return NextResponse.json(
181
+ {
182
+ error: 'userinfo_proxy_failed',
183
+ message: error instanceof Error ? error.message : 'Unknown error',
184
+ status: 'error',
185
+ },
186
+ { status: 500 },
187
+ );
188
+ }
189
+ }
190
+
191
+ default: {
192
+ return NextResponse.json(
193
+ {
194
+ error: 'unsupported_endpoint',
195
+ message: 'Requested endpoint is not supported.',
196
+ status: 'error',
197
+ },
198
+ { status: 404 },
199
+ );
200
+ }
201
+ }
202
+ };
203
+
204
+ export const GET = (req: NextRequest, context: RouteContext) => handleProxy(req, context);
205
+ export const POST = (req: NextRequest, context: RouteContext) => handleProxy(req, context);
206
+
207
+ export const dynamic = 'force-dynamic';
@@ -1,6 +1,7 @@
1
1
  import { Bot, Brain, Info, Mic2, Settings2, Sparkles } from 'lucide-react';
2
2
  import { useRouter } from 'next/navigation';
3
3
  import { useTranslation } from 'react-i18next';
4
+
4
5
  import { CellProps } from '@/components/Cell';
5
6
  import { isDeprecatedEdition } from '@/const/version';
6
7
  import { SettingsTabs } from '@/store/global/initialState';
@@ -82,12 +82,14 @@ const PinList = () => {
82
82
  hasList && (
83
83
  <>
84
84
  <Divider style={{ marginBottom: 8, marginTop: 4 }} />
85
- <ScrollShadow height={"100%"} hideScrollBar={true} size={40}>
85
+ <ScrollShadow height={'100%'} hideScrollBar={true} size={40}>
86
86
  <Flexbox gap={12} style={{ padding: '0' }}>
87
87
  {list.map((item, index) => (
88
88
  <Flexbox key={item.id} style={{ position: 'relative' }}>
89
89
  <Tooltip
90
- hotkey={index < 9 ? hotkey.replaceAll(KeyEnum.Number, String(index + 1)) : undefined}
90
+ hotkey={
91
+ index < 9 ? hotkey.replaceAll(KeyEnum.Number, String(index + 1)) : undefined
92
+ }
91
93
  placement={'right'}
92
94
  title={sessionHelpers.getTitle(item.meta)}
93
95
  >