@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.
- package/.env.example +11 -0
- package/CHANGELOG.md +17 -0
- package/apps/desktop/src/main/controllers/AuthCtr.ts +27 -2
- package/apps/desktop/src/main/core/infrastructure/ProtocolManager.ts +9 -4
- package/changelog/v1.json +5 -0
- package/docs/development/database-schema.dbml +2 -0
- package/docs/self-hosting/environment-variables/basic.mdx +49 -3
- package/docs/self-hosting/environment-variables/basic.zh-CN.mdx +49 -4
- package/locales/ar/discover.json +45 -0
- package/locales/ar/marketAuth.json +42 -0
- package/locales/ar/setting.json +94 -1
- package/locales/bg-BG/discover.json +45 -0
- package/locales/bg-BG/marketAuth.json +42 -0
- package/locales/bg-BG/setting.json +94 -1
- package/locales/de-DE/discover.json +45 -0
- package/locales/de-DE/marketAuth.json +42 -0
- package/locales/de-DE/setting.json +94 -1
- package/locales/en-US/discover.json +45 -0
- package/locales/en-US/marketAuth.json +42 -0
- package/locales/en-US/setting.json +94 -1
- package/locales/es-ES/discover.json +45 -0
- package/locales/es-ES/marketAuth.json +42 -0
- package/locales/es-ES/setting.json +94 -1
- package/locales/fa-IR/discover.json +45 -0
- package/locales/fa-IR/marketAuth.json +42 -0
- package/locales/fa-IR/setting.json +94 -1
- package/locales/fr-FR/discover.json +45 -0
- package/locales/fr-FR/marketAuth.json +42 -0
- package/locales/fr-FR/setting.json +94 -1
- package/locales/it-IT/discover.json +45 -0
- package/locales/it-IT/marketAuth.json +42 -0
- package/locales/it-IT/setting.json +94 -1
- package/locales/ja-JP/discover.json +45 -0
- package/locales/ja-JP/marketAuth.json +42 -0
- package/locales/ja-JP/setting.json +94 -1
- package/locales/ko-KR/discover.json +45 -0
- package/locales/ko-KR/marketAuth.json +42 -0
- package/locales/ko-KR/setting.json +94 -1
- package/locales/nl-NL/discover.json +45 -0
- package/locales/nl-NL/marketAuth.json +42 -0
- package/locales/nl-NL/setting.json +94 -1
- package/locales/pl-PL/discover.json +45 -0
- package/locales/pl-PL/marketAuth.json +42 -0
- package/locales/pl-PL/setting.json +94 -1
- package/locales/pt-BR/discover.json +45 -0
- package/locales/pt-BR/marketAuth.json +42 -0
- package/locales/pt-BR/setting.json +94 -1
- package/locales/ru-RU/discover.json +45 -0
- package/locales/ru-RU/marketAuth.json +42 -0
- package/locales/ru-RU/setting.json +94 -1
- package/locales/tr-TR/discover.json +45 -0
- package/locales/tr-TR/marketAuth.json +42 -0
- package/locales/tr-TR/setting.json +94 -1
- package/locales/vi-VN/discover.json +45 -0
- package/locales/vi-VN/marketAuth.json +42 -0
- package/locales/vi-VN/setting.json +94 -1
- package/locales/zh-CN/discover.json +45 -0
- package/locales/zh-CN/marketAuth.json +42 -0
- package/locales/zh-CN/setting.json +94 -1
- package/locales/zh-TW/discover.json +45 -0
- package/locales/zh-TW/marketAuth.json +42 -0
- package/locales/zh-TW/setting.json +94 -1
- package/package.json +27 -26
- package/packages/const/src/url.ts +1 -0
- package/packages/database/migrations/0044_add_tool_intervention.sql +1 -0
- package/packages/database/migrations/0044_high_toxin.sql +1 -0
- package/packages/database/migrations/0045_add_tool_intervention.sql +1 -0
- package/packages/database/migrations/meta/0039_snapshot.json +1 -1
- package/packages/database/migrations/meta/0044_snapshot.json +7813 -0
- package/packages/database/migrations/meta/0045_snapshot.json +8431 -0
- package/packages/database/migrations/meta/_journal.json +14 -0
- package/packages/database/src/core/migrations.json +36 -7
- package/packages/database/src/models/message.ts +1 -1
- package/packages/database/src/models/session.ts +42 -1
- package/packages/database/src/schemas/agent.ts +1 -0
- package/packages/database/src/schemas/message.ts +5 -8
- package/packages/electron-client-ipc/src/events/index.ts +6 -1
- package/packages/electron-client-ipc/src/events/remoteServer.ts +8 -0
- package/packages/fetch-sse/package.json +29 -0
- package/packages/{utils/src/fetch → fetch-sse/src}/__tests__/fetchSSE.test.ts +4 -4
- package/packages/{utils/src/fetch → fetch-sse/src}/__tests__/parseError.test.ts +7 -4
- package/packages/{utils/src/fetch → fetch-sse/src}/fetchSSE.ts +2 -2
- package/packages/{utils/src/fetch → fetch-sse/src}/parseError.ts +3 -3
- package/packages/model-bank/src/aiModels/mistral.ts +2 -1
- package/packages/model-runtime/src/core/contextBuilders/anthropic.test.ts +17 -11
- package/packages/model-runtime/src/core/contextBuilders/anthropic.ts +1 -1
- package/packages/model-runtime/src/core/contextBuilders/google.test.ts +1 -1
- package/packages/model-runtime/src/core/contextBuilders/google.ts +3 -6
- package/packages/model-runtime/src/core/contextBuilders/openai.test.ts +4 -2
- package/packages/model-runtime/src/core/contextBuilders/openai.ts +1 -1
- package/packages/model-runtime/src/core/openaiCompatibleFactory/createImage.test.ts +1 -1
- package/packages/model-runtime/src/core/openaiCompatibleFactory/createImage.ts +1 -1
- package/packages/model-runtime/src/core/openaiCompatibleFactory/index.test.ts +3 -6
- package/packages/model-runtime/src/core/streams/openai/responsesStream.test.ts +1 -1
- package/packages/model-runtime/src/helpers/mergeChatMethodOptions.ts +2 -1
- package/packages/model-runtime/src/providers/aihubmix/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/anthropic/generateObject.test.ts +1 -1
- package/packages/model-runtime/src/providers/anthropic/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/baichuan/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/bedrock/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/bfl/createImage.test.ts +4 -4
- package/packages/model-runtime/src/providers/bfl/createImage.ts +1 -1
- package/packages/model-runtime/src/providers/cloudflare/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/cohere/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/google/createImage.test.ts +2 -2
- package/packages/model-runtime/src/providers/google/createImage.ts +1 -1
- package/packages/model-runtime/src/providers/google/generateObject.test.ts +1 -1
- package/packages/model-runtime/src/providers/google/index.test.ts +1 -4
- package/packages/model-runtime/src/providers/groq/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/hunyuan/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/minimax/createImage.test.ts +1 -1
- package/packages/model-runtime/src/providers/mistral/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/moonshot/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/novita/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/ollama/index.test.ts +43 -32
- package/packages/model-runtime/src/providers/ollama/index.ts +31 -7
- package/packages/model-runtime/src/providers/openrouter/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/perplexity/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/ppio/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/qwen/createImage.test.ts +1 -1
- package/packages/model-runtime/src/providers/search1api/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/siliconcloud/createImage.ts +1 -1
- package/packages/model-runtime/src/providers/taichu/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/wenxin/index.test.ts +1 -1
- package/packages/model-runtime/src/providers/zhipu/index.test.ts +1 -1
- package/packages/model-runtime/src/utils/errorResponse.test.ts +1 -1
- package/packages/ssrf-safe-fetch/index.browser.ts +14 -0
- package/packages/ssrf-safe-fetch/package.json +8 -1
- package/packages/types/src/discover/assistants.ts +16 -0
- package/packages/types/src/index.ts +1 -0
- package/packages/types/src/message/common/tools.ts +10 -0
- package/packages/types/src/message/db/item.ts +15 -1
- package/packages/types/src/message/ui/params.ts +15 -1
- package/packages/types/src/meta.ts +4 -0
- package/packages/types/src/session/agentSession.ts +2 -0
- package/packages/utils/src/imageToBase64.ts +17 -10
- package/packages/utils/src/index.ts +1 -1
- package/src/app/(backend)/market/agent/[[...segments]]/route.ts +153 -0
- package/src/app/(backend)/market/oidc/[[...segments]]/route.ts +207 -0
- package/src/app/[variants]/(main)/(mobile)/me/settings/features/useCategory.tsx +1 -0
- package/src/app/[variants]/(main)/_layout/Desktop/SideBar/PinList/index.tsx +4 -2
- package/src/app/[variants]/(main)/chat/settings/features/AgentInfoDescription/index.tsx +349 -0
- package/src/app/[variants]/(main)/chat/settings/features/HeaderContent.tsx +2 -2
- package/src/app/[variants]/(main)/chat/settings/features/PublishResultModal/index.tsx +64 -0
- package/src/app/[variants]/(main)/chat/settings/features/SmartAgentActionButton/MarketPublishButton.tsx +196 -0
- package/src/app/[variants]/(main)/chat/settings/features/SmartAgentActionButton/MarketPublishModal.tsx +358 -0
- package/src/app/[variants]/(main)/chat/settings/features/SmartAgentActionButton/index.tsx +75 -0
- package/src/app/[variants]/(main)/discover/(detail)/assistant/AssistantDetailPage.tsx +11 -2
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/Client.tsx +12 -1
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Nav.tsx +19 -12
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Overview/TagList.tsx +14 -5
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Overview/index.tsx +2 -0
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Related/index.tsx +14 -5
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/SystemRole/TagList.tsx +14 -5
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/SystemRole/index.tsx +43 -29
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Versions/index.tsx +137 -0
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/index.tsx +2 -0
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Header.tsx +9 -10
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Sidebar/ActionButton/AddAgent.tsx +105 -14
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Sidebar/Related/index.tsx +20 -6
- package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/StatusPage/index.tsx +113 -0
- package/src/app/[variants]/(main)/discover/(detail)/features/Breadcrumb.tsx +4 -3
- package/src/app/[variants]/(main)/discover/(list)/_layout/Desktop/Nav.tsx +3 -1
- package/src/app/[variants]/(main)/discover/(list)/assistant/AssistantPage.tsx +4 -1
- package/src/app/[variants]/(main)/discover/(list)/assistant/Client.tsx +6 -2
- package/src/app/[variants]/(main)/discover/(list)/assistant/features/Category/index.tsx +7 -3
- package/src/app/[variants]/(main)/discover/(list)/assistant/features/List/Item.tsx +13 -2
- package/src/app/[variants]/(main)/discover/(list)/assistant/features/MarketSourceSwitch.tsx +64 -0
- package/src/app/[variants]/(main)/discover/(list)/features/SortButton/index.tsx +26 -7
- package/src/app/[variants]/(main)/profile/_layout/Desktop/index.tsx +10 -10
- package/src/app/[variants]/(main)/settings/_layout/type.ts +1 -1
- package/src/app/[variants]/(main)/settings/agent/index.tsx +11 -10
- package/src/app/[variants]/(main)/settings/common/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/page.tsx +13 -10
- package/src/app/[variants]/(main)/settings/provider/ProviderMenu/Item.tsx +35 -36
- package/src/app/[variants]/(main)/settings/provider/ProviderMenu/SearchResult.tsx +5 -5
- package/src/app/[variants]/(main)/settings/provider/_layout/Desktop/Container.tsx +10 -4
- package/src/app/market-auth-callback/layout.tsx +15 -0
- package/src/app/market-auth-callback/page.tsx +196 -0
- package/src/features/AgentSetting/AgentPrompt/TokenTag.tsx +3 -2
- package/src/features/AgentSetting/AgentTTS/SelectWithTTSPreview.tsx +1 -1
- package/src/features/AgentSetting/store/action.ts +1 -1
- package/src/features/ChatInput/ActionBar/STT/browser.tsx +1 -1
- package/src/features/ChatInput/ActionBar/STT/openai.tsx +1 -1
- package/src/features/Conversation/components/Extras/TTS/InitPlayer.tsx +1 -1
- package/src/features/PluginTag/PluginStatus.tsx +1 -1
- package/src/hooks/useAgentOwnershipCheck.ts +143 -0
- package/src/instrumentation.node.ts +3 -2
- package/src/layout/AuthProvider/MarketAuth/MarketAuthProvider.tsx +364 -0
- package/src/layout/AuthProvider/MarketAuth/errors.ts +75 -0
- package/src/layout/AuthProvider/MarketAuth/index.ts +2 -0
- package/src/layout/AuthProvider/MarketAuth/oidc.ts +382 -0
- package/src/layout/AuthProvider/MarketAuth/types.ts +64 -0
- package/src/layout/AuthProvider/index.tsx +17 -4
- package/src/locales/default/discover.ts +46 -0
- package/src/locales/default/index.ts +2 -0
- package/src/locales/default/marketAuth.ts +42 -0
- package/src/locales/default/setting.ts +94 -1
- package/src/server/globalConfig/genServerAiProviderConfig.test.ts +5 -5
- package/src/server/globalConfig/genServerAiProviderConfig.ts +1 -1
- package/src/server/routers/lambda/market/index.ts +36 -14
- package/src/server/routers/lambda/message.ts +2 -2
- package/src/server/services/discover/index.test.ts +153 -11
- package/src/server/services/discover/index.ts +339 -40
- package/src/server/sitemap.ts +49 -35
- package/src/services/_url.ts +15 -1
- package/src/services/chat/chat.test.ts +5 -5
- package/src/services/chat/clientModelRuntime.test.ts +1 -1
- package/src/services/chat/index.ts +6 -6
- package/src/services/chat/types.ts +1 -2
- package/src/services/discover.ts +16 -5
- package/src/services/electron/remoteServer.ts +8 -1
- package/src/services/marketApi.ts +124 -0
- package/src/services/models.ts +2 -1
- package/src/store/discover/slices/assistant/action.ts +20 -7
- package/{packages/utils/src → src/utils}/electron/desktopRemoteRPCFetch.ts +1 -1
- package/{packages/utils/src → src/utils/server}/parseModels.ts +1 -2
- package/vitest.config.mts +2 -0
- package/packages/model-runtime/src/utils/imageToBase64.test.ts +0 -91
- package/packages/model-runtime/src/utils/imageToBase64.ts +0 -62
- package/src/app/[variants]/(main)/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx +0 -98
- package/src/app/[variants]/(main)/chat/settings/features/SubmitAgentButton/index.tsx +0 -35
- package/src/app/[variants]/(main)/chat/settings/features/SubmitAgentButton/style.ts +0 -47
- /package/packages/{utils/src/fetch → fetch-sse/src}/headers.ts +0 -0
- /package/packages/{utils/src/fetch → fetch-sse/src}/index.ts +0 -0
- /package/packages/{utils/src/fetch → fetch-sse/src}/request.ts +0 -0
- /package/{packages/utils/src → src/utils/server}/__snapshots__/parseModels.test.ts.snap +0 -0
- /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
|
}
|
|
@@ -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
|
/**
|
|
@@ -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
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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={
|
|
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={
|
|
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
|
>
|