@lobehub/chat 1.129.2 → 1.129.4
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/.cursor/rules/project-introduce.mdc +4 -4
- package/.cursor/rules/react-component.mdc +2 -2
- package/.cursor/rules/typescript.mdc +57 -5
- package/.vscode/settings.json +3 -1
- package/AGENTS.md +2 -5
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/package.json +2 -2
- package/packages/agent-runtime/package.json +1 -1
- package/packages/context-engine/package.json +1 -1
- package/packages/database/package.json +1 -1
- package/packages/electron-server-ipc/package.json +1 -1
- package/packages/file-loaders/package.json +1 -1
- package/packages/model-bank/package.json +2 -2
- package/packages/model-runtime/package.json +1 -1
- package/packages/model-runtime/src/core/RouterRuntime/baseRuntimeMap.ts +2 -0
- package/packages/model-runtime/src/core/RouterRuntime/createRuntime.test.ts +89 -64
- package/packages/model-runtime/src/core/RouterRuntime/createRuntime.ts +58 -40
- package/packages/model-runtime/src/providers/newapi/index.ts +17 -2
- package/packages/model-runtime/src/providers/qwen/createImage.test.ts +110 -0
- package/packages/model-runtime/src/providers/qwen/createImage.ts +100 -3
- package/packages/prompts/package.json +1 -1
- package/packages/utils/package.json +4 -2
- package/packages/utils/src/client/index.ts +2 -0
- package/packages/utils/src/client/sanitize.test.ts +108 -0
- package/packages/utils/src/client/sanitize.ts +33 -0
- package/packages/web-crawler/package.json +1 -1
- package/src/features/PluginStore/InstalledList/List/Item/Action.tsx +12 -2
- package/src/features/PluginStore/McpList/List/Action.tsx +12 -2
- package/src/features/PluginStore/PluginList/List/Action.tsx +12 -2
- package/src/features/Portal/Artifacts/Body/Renderer/SVG.tsx +7 -3
- package/src/server/modules/EdgeConfig/index.ts +3 -19
- package/src/server/modules/EdgeConfig/types.ts +9 -0
- /package/packages/utils/src/{clipboard.ts → client/clipboard.ts} +0 -0
|
@@ -7,6 +7,7 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
7
7
|
|
|
8
8
|
import PluginDetailModal from '@/features/PluginDetailModal';
|
|
9
9
|
import { useAgentStore } from '@/store/agent';
|
|
10
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
10
11
|
import { useServerConfigStore } from '@/store/serverConfig';
|
|
11
12
|
import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
12
13
|
import { pluginSelectors, pluginStoreSelectors } from '@/store/tool/selectors';
|
|
@@ -36,7 +37,10 @@ const Actions = memo<ActionsProps>(({ identifier, type, isMCP }) => {
|
|
|
36
37
|
const { t } = useTranslation('plugin');
|
|
37
38
|
const [open, setOpen] = useState(false);
|
|
38
39
|
const plugin = useToolStore(pluginSelectors.getToolManifestById(identifier));
|
|
39
|
-
const togglePlugin = useAgentStore((s) =>
|
|
40
|
+
const [togglePlugin, isPluginEnabledInAgent] = useAgentStore((s) => [
|
|
41
|
+
s.togglePlugin,
|
|
42
|
+
agentSelectors.currentAgentPlugins(s).includes(identifier),
|
|
43
|
+
]);
|
|
40
44
|
const { modal } = App.useApp();
|
|
41
45
|
const [tab, setTab] = useState('info');
|
|
42
46
|
const hasSettings = pluginHelpers.isSettingSchemaNonEmpty(plugin?.settings);
|
|
@@ -90,7 +94,13 @@ const Actions = memo<ActionsProps>(({ identifier, type, isMCP }) => {
|
|
|
90
94
|
modal.confirm({
|
|
91
95
|
centered: true,
|
|
92
96
|
okButtonProps: { danger: true },
|
|
93
|
-
onOk: async () =>
|
|
97
|
+
onOk: async () => {
|
|
98
|
+
// If plugin is enabled in current agent, disable it first
|
|
99
|
+
if (isPluginEnabledInAgent) {
|
|
100
|
+
await togglePlugin(identifier, false);
|
|
101
|
+
}
|
|
102
|
+
await unInstallPlugin(identifier);
|
|
103
|
+
},
|
|
94
104
|
title: t('store.actions.confirmUninstall'),
|
|
95
105
|
type: 'error',
|
|
96
106
|
});
|
|
@@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
import { Flexbox } from 'react-layout-kit';
|
|
7
7
|
|
|
8
8
|
import { useAgentStore } from '@/store/agent';
|
|
9
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
9
10
|
import { useToolStore } from '@/store/tool';
|
|
10
11
|
import { mcpStoreSelectors, pluginSelectors } from '@/store/tool/selectors';
|
|
11
12
|
|
|
@@ -24,7 +25,10 @@ const Actions = memo<ActionsProps>(({ identifier }) => {
|
|
|
24
25
|
]);
|
|
25
26
|
|
|
26
27
|
const { t } = useTranslation('plugin');
|
|
27
|
-
const togglePlugin = useAgentStore((s) =>
|
|
28
|
+
const [togglePlugin, isPluginEnabledInAgent] = useAgentStore((s) => [
|
|
29
|
+
s.togglePlugin,
|
|
30
|
+
agentSelectors.currentAgentPlugins(s).includes(identifier),
|
|
31
|
+
]);
|
|
28
32
|
const { modal } = App.useApp();
|
|
29
33
|
|
|
30
34
|
return (
|
|
@@ -42,7 +46,13 @@ const Actions = memo<ActionsProps>(({ identifier }) => {
|
|
|
42
46
|
modal.confirm({
|
|
43
47
|
centered: true,
|
|
44
48
|
okButtonProps: { danger: true },
|
|
45
|
-
onOk: async () =>
|
|
49
|
+
onOk: async () => {
|
|
50
|
+
// If plugin is enabled in current agent, disable it first
|
|
51
|
+
if (isPluginEnabledInAgent) {
|
|
52
|
+
await togglePlugin(identifier, false);
|
|
53
|
+
}
|
|
54
|
+
await unInstallPlugin(identifier);
|
|
55
|
+
},
|
|
46
56
|
title: t('store.actions.confirmUninstall'),
|
|
47
57
|
type: 'error',
|
|
48
58
|
});
|
|
@@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
import { Flexbox } from 'react-layout-kit';
|
|
7
7
|
|
|
8
8
|
import { useAgentStore } from '@/store/agent';
|
|
9
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
9
10
|
import { useToolStore } from '@/store/tool';
|
|
10
11
|
import { pluginSelectors, pluginStoreSelectors } from '@/store/tool/selectors';
|
|
11
12
|
|
|
@@ -22,7 +23,10 @@ const Actions = memo<ActionsProps>(({ identifier }) => {
|
|
|
22
23
|
]);
|
|
23
24
|
|
|
24
25
|
const { t } = useTranslation('plugin');
|
|
25
|
-
const togglePlugin = useAgentStore((s) =>
|
|
26
|
+
const [togglePlugin, isPluginEnabledInAgent] = useAgentStore((s) => [
|
|
27
|
+
s.togglePlugin,
|
|
28
|
+
agentSelectors.currentAgentPlugins(s).includes(identifier),
|
|
29
|
+
]);
|
|
26
30
|
const { modal } = App.useApp();
|
|
27
31
|
|
|
28
32
|
return (
|
|
@@ -40,7 +44,13 @@ const Actions = memo<ActionsProps>(({ identifier }) => {
|
|
|
40
44
|
modal.confirm({
|
|
41
45
|
centered: true,
|
|
42
46
|
okButtonProps: { danger: true },
|
|
43
|
-
onOk: async () =>
|
|
47
|
+
onOk: async () => {
|
|
48
|
+
// If plugin is enabled in current agent, disable it first
|
|
49
|
+
if (isPluginEnabledInAgent) {
|
|
50
|
+
await togglePlugin(identifier, false);
|
|
51
|
+
}
|
|
52
|
+
await unInstallPlugin(identifier);
|
|
53
|
+
},
|
|
44
54
|
title: t('store.actions.confirmUninstall'),
|
|
45
55
|
type: 'error',
|
|
46
56
|
});
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import { copyImageToClipboard, sanitizeSVGContent } from '@lobechat/utils/client';
|
|
1
2
|
import { Button, Dropdown, Tooltip } from '@lobehub/ui';
|
|
2
3
|
import { App, Space } from 'antd';
|
|
3
4
|
import { css, cx } from 'antd-style';
|
|
4
5
|
import { CopyIcon, DownloadIcon } from 'lucide-react';
|
|
5
6
|
import { domToPng } from 'modern-screenshot';
|
|
7
|
+
import { useMemo } from 'react';
|
|
6
8
|
import { useTranslation } from 'react-i18next';
|
|
7
9
|
import { Center, Flexbox } from 'react-layout-kit';
|
|
8
10
|
|
|
9
11
|
import { BRANDING_NAME } from '@/const/branding';
|
|
10
12
|
import { useChatStore } from '@/store/chat';
|
|
11
13
|
import { chatPortalSelectors } from '@/store/chat/selectors';
|
|
12
|
-
import { copyImageToClipboard } from '@/utils/clipboard';
|
|
13
14
|
|
|
14
15
|
const svgContainer = css`
|
|
15
16
|
width: 100%;
|
|
@@ -36,6 +37,9 @@ const SVGRenderer = ({ content }: SVGRendererProps) => {
|
|
|
36
37
|
const { t } = useTranslation('portal');
|
|
37
38
|
const { message } = App.useApp();
|
|
38
39
|
|
|
40
|
+
// Sanitize SVG content to prevent XSS attacks
|
|
41
|
+
const sanitizedContent = useMemo(() => sanitizeSVGContent(content), [content]);
|
|
42
|
+
|
|
39
43
|
const generatePng = async () => {
|
|
40
44
|
return domToPng(document.querySelector(`#${DOM_ID}`) as HTMLDivElement, {
|
|
41
45
|
features: {
|
|
@@ -50,7 +54,7 @@ const SVGRenderer = ({ content }: SVGRendererProps) => {
|
|
|
50
54
|
let dataUrl = '';
|
|
51
55
|
if (type === 'png') dataUrl = await generatePng();
|
|
52
56
|
else if (type === 'svg') {
|
|
53
|
-
const blob = new Blob([
|
|
57
|
+
const blob = new Blob([sanitizedContent], { type: 'image/svg+xml' });
|
|
54
58
|
|
|
55
59
|
dataUrl = URL.createObjectURL(blob);
|
|
56
60
|
}
|
|
@@ -73,7 +77,7 @@ const SVGRenderer = ({ content }: SVGRendererProps) => {
|
|
|
73
77
|
>
|
|
74
78
|
<Center
|
|
75
79
|
className={cx(svgContainer)}
|
|
76
|
-
dangerouslySetInnerHTML={{ __html:
|
|
80
|
+
dangerouslySetInnerHTML={{ __html: sanitizedContent }}
|
|
77
81
|
id={DOM_ID}
|
|
78
82
|
/>
|
|
79
83
|
<Flexbox className={cx(actions)}>
|
|
@@ -2,16 +2,7 @@ import { EdgeConfigClient, createClient } from '@vercel/edge-config';
|
|
|
2
2
|
|
|
3
3
|
import { appEnv } from '@/envs/app';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Assistant whitelist
|
|
8
|
-
*/
|
|
9
|
-
AssistantBlacklist: 'assistant_blacklist',
|
|
10
|
-
/**
|
|
11
|
-
* Assistant whitelist
|
|
12
|
-
*/
|
|
13
|
-
AssistantWhitelist: 'assistant_whitelist',
|
|
14
|
-
};
|
|
5
|
+
import { EdgeConfigData } from './types';
|
|
15
6
|
|
|
16
7
|
export class EdgeConfig {
|
|
17
8
|
get client(): EdgeConfigClient {
|
|
@@ -30,14 +21,7 @@ export class EdgeConfig {
|
|
|
30
21
|
|
|
31
22
|
getAgentRestrictions = async () => {
|
|
32
23
|
const { assistant_blacklist: blacklist, assistant_whitelist: whitelist } =
|
|
33
|
-
await this.client.getAll([
|
|
34
|
-
|
|
35
|
-
EdgeConfigKeys.AssistantBlacklist,
|
|
36
|
-
]);
|
|
37
|
-
|
|
38
|
-
return { blacklist, whitelist } as {
|
|
39
|
-
blacklist: string[] | undefined;
|
|
40
|
-
whitelist: string[] | undefined;
|
|
41
|
-
};
|
|
24
|
+
await this.client.getAll<EdgeConfigData>(['assistant_whitelist', 'assistant_blacklist']);
|
|
25
|
+
return { blacklist, whitelist };
|
|
42
26
|
};
|
|
43
27
|
}
|
|
File without changes
|