@lobehub/chat 0.67.0 → 0.68.1
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/.eslintrc.js +1 -0
- package/CHANGELOG.md +51 -0
- package/README-zh_CN.md +4 -1
- package/README.md +4 -1
- package/locales/en_US/plugin.json +8 -2
- package/package.json +2 -2
- package/src/features/AgentSetting/AgentPlugin/LocalPluginItem.tsx +4 -3
- package/src/features/AgentSetting/AgentPlugin/MarketList.tsx +67 -22
- package/src/features/AgentSetting/store/reducers/config.ts +2 -2
- package/src/features/AgentSetting/store/reducers/meta.ts +2 -2
- package/src/locales/default/plugin.ts +1 -0
- package/src/locales/default/setting.ts +1 -1
- package/src/pages/chat/features/Conversation/ChatList/Plugins/IFrameRender/hooks.ts +29 -0
- package/src/pages/chat/features/Conversation/ChatList/Plugins/IFrameRender/index.tsx +62 -0
- package/src/pages/chat/features/Conversation/ChatList/Plugins/IFrameRender/utils.ts +17 -0
- package/src/pages/chat/features/Conversation/ChatList/Plugins/PluginMessage.tsx +20 -4
- package/src/pages/chat/features/Conversation/ChatList/Plugins/{CustomRender.tsx → SystemJsRender/index.tsx} +5 -4
- package/src/store/plugin/selectors.ts +10 -5
- package/src/store/session/slices/agentConfig/selectors.ts +2 -2
- package/src/utils/merge.ts +11 -0
- /package/src/pages/chat/features/Conversation/ChatList/Plugins/{dynamticLoader.ts → SystemJsRender/utils.ts} +0 -0
package/.eslintrc.js
CHANGED
|
@@ -11,5 +11,6 @@ config.rules['unicorn/explicit-length-check'] = 0;
|
|
|
11
11
|
config.rules['unicorn/prefer-code-point'] = 0;
|
|
12
12
|
config.rules['no-extra-boolean-cast'] = 0;
|
|
13
13
|
config.rules['unicorn/no-useless-undefined'] = 0;
|
|
14
|
+
config.rules['react/no-unknown-property'] = 0;
|
|
14
15
|
|
|
15
16
|
module.exports = config;
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,57 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.68.1](https://github.com/lobehub/lobe-chat/compare/v0.68.0...v0.68.1)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-09-03**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: 修正数组合并逻辑, 修正被移除插件无法看到的问题.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **misc**: 修正数组合并逻辑 ([e36e621](https://github.com/lobehub/lobe-chat/commit/e36e621))
|
|
21
|
+
- **misc**: 修正被移除插件无法看到的问题 ([c17eb56](https://github.com/lobehub/lobe-chat/commit/c17eb56))
|
|
22
|
+
|
|
23
|
+
</details>
|
|
24
|
+
|
|
25
|
+
<div align="right">
|
|
26
|
+
|
|
27
|
+
[](#readme-top)
|
|
28
|
+
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
## [Version 0.68.0](https://github.com/lobehub/lobe-chat/compare/v0.67.0...v0.68.0)
|
|
32
|
+
|
|
33
|
+
<sup>Released on **2023-09-03**</sup>
|
|
34
|
+
|
|
35
|
+
#### ✨ Features
|
|
36
|
+
|
|
37
|
+
- **misc**: Plugin default use iframe render.
|
|
38
|
+
|
|
39
|
+
<br/>
|
|
40
|
+
|
|
41
|
+
<details>
|
|
42
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
43
|
+
|
|
44
|
+
#### What's improved
|
|
45
|
+
|
|
46
|
+
- **misc**: Plugin default use iframe render, closes [#141](https://github.com/lobehub/lobe-chat/issues/141) ([35a3a16](https://github.com/lobehub/lobe-chat/commit/35a3a16))
|
|
47
|
+
|
|
48
|
+
</details>
|
|
49
|
+
|
|
50
|
+
<div align="right">
|
|
51
|
+
|
|
52
|
+
[](#readme-top)
|
|
53
|
+
|
|
54
|
+
</div>
|
|
55
|
+
|
|
5
56
|
## [Version 0.67.0](https://github.com/lobehub/lobe-chat/compare/v0.66.0...v0.67.0)
|
|
6
57
|
|
|
7
58
|
<sup>Released on **2023-09-02**</sup>
|
package/README-zh_CN.md
CHANGED
|
@@ -168,7 +168,7 @@ $ pnpm dev
|
|
|
168
168
|
|
|
169
169
|
<!-- CONTRIBUTION GROUP -->
|
|
170
170
|
|
|
171
|
-
> 📊 Total: <kbd>**
|
|
171
|
+
> 📊 Total: <kbd>**5**</kbd>
|
|
172
172
|
|
|
173
173
|
<a href="https://github.com/arvinxx" title="arvinxx">
|
|
174
174
|
<img src="https://avatars.githubusercontent.com/u/28616219?v=4" width="50" />
|
|
@@ -182,6 +182,9 @@ $ pnpm dev
|
|
|
182
182
|
<a href="https://github.com/actions-user" title="actions-user">
|
|
183
183
|
<img src="https://avatars.githubusercontent.com/u/65916846?v=4" width="50" />
|
|
184
184
|
</a>
|
|
185
|
+
<a href="https://github.com/bropines" title="bropines">
|
|
186
|
+
<img src="https://avatars.githubusercontent.com/u/57861007?v=4" width="50" />
|
|
187
|
+
</a>
|
|
185
188
|
|
|
186
189
|
<!-- CONTRIBUTION END -->
|
|
187
190
|
|
package/README.md
CHANGED
|
@@ -168,7 +168,7 @@ Contributions of all types are more than welcome, if you are interested in contr
|
|
|
168
168
|
|
|
169
169
|
<!-- CONTRIBUTION GROUP -->
|
|
170
170
|
|
|
171
|
-
> 📊 Total: <kbd>**
|
|
171
|
+
> 📊 Total: <kbd>**5**</kbd>
|
|
172
172
|
|
|
173
173
|
<a href="https://github.com/arvinxx" title="arvinxx">
|
|
174
174
|
<img src="https://avatars.githubusercontent.com/u/28616219?v=4" width="50" />
|
|
@@ -182,6 +182,9 @@ Contributions of all types are more than welcome, if you are interested in contr
|
|
|
182
182
|
<a href="https://github.com/actions-user" title="actions-user">
|
|
183
183
|
<img src="https://avatars.githubusercontent.com/u/65916846?v=4" width="50" />
|
|
184
184
|
</a>
|
|
185
|
+
<a href="https://github.com/bropines" title="bropines">
|
|
186
|
+
<img src="https://avatars.githubusercontent.com/u/57861007?v=4" width="50" />
|
|
187
|
+
</a>
|
|
185
188
|
|
|
186
189
|
<!-- CONTRIBUTION END -->
|
|
187
190
|
|
|
@@ -52,7 +52,11 @@
|
|
|
52
52
|
"desc": "LobeChat will install the plugin using this link",
|
|
53
53
|
"invalid": "The input manifest link is invalid or does not comply with the specification",
|
|
54
54
|
"label": "Plugin Manifest URL",
|
|
55
|
-
"urlError": "Please enter a valid URL"
|
|
55
|
+
"urlError": "Please enter a valid URL",
|
|
56
|
+
"jsonInvalid": "The manifest is not valid, validation result: \n\n {{error}}",
|
|
57
|
+
"preview": "Preview Manifest",
|
|
58
|
+
"refresh": "Refresh",
|
|
59
|
+
"requestError": "Failed to request the link, please enter a valid link and check if the link allows cross-origin access"
|
|
56
60
|
},
|
|
57
61
|
"title": {
|
|
58
62
|
"desc": "The title of the plugin",
|
|
@@ -73,7 +77,9 @@
|
|
|
73
77
|
"manifest": "Function Description Manifest (Manifest)",
|
|
74
78
|
"meta": "Plugin Metadata"
|
|
75
79
|
},
|
|
76
|
-
"title": "Add Custom Plugin"
|
|
80
|
+
"title": "Add Custom Plugin",
|
|
81
|
+
"update": "Update",
|
|
82
|
+
"updateSuccess": "Plugin settings updated successfully"
|
|
77
83
|
},
|
|
78
84
|
"list": {
|
|
79
85
|
"item": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.68.1",
|
|
4
4
|
"description": "Lobe Chat is an open-source chatbot client using LangChain, Typescript and Next.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chatbot",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"@emoji-mart/data": "^1",
|
|
67
67
|
"@emoji-mart/react": "^1",
|
|
68
68
|
"@icons-pack/react-simple-icons": "^9",
|
|
69
|
-
"@lobehub/chat-plugin-sdk": "^1.
|
|
69
|
+
"@lobehub/chat-plugin-sdk": "^1.15.1",
|
|
70
70
|
"@lobehub/chat-plugins-gateway": "^1.5.0",
|
|
71
71
|
"@lobehub/ui": "latest",
|
|
72
72
|
"@vercel/analytics": "^1",
|
|
@@ -14,8 +14,8 @@ const MarketList = memo<{ id: string }>(({ id }) => {
|
|
|
14
14
|
|
|
15
15
|
const [showModal, setModal] = useState(false);
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
const
|
|
17
|
+
const [toggleAgentPlugin, hasPlugin] = useStore((s) => [s.toggleAgentPlugin, !!s.config.plugins]);
|
|
18
|
+
const plugins = useStore((s) => s.config.plugins || []);
|
|
19
19
|
|
|
20
20
|
const [useFetchPluginList, fetchPluginManifest, deleteCustomPlugin, updateCustomPlugin] =
|
|
21
21
|
usePluginStore((s) => [
|
|
@@ -36,6 +36,7 @@ const MarketList = memo<{ id: string }>(({ id }) => {
|
|
|
36
36
|
mode={'edit'}
|
|
37
37
|
onDelete={() => {
|
|
38
38
|
deleteCustomPlugin(id);
|
|
39
|
+
toggleAgentPlugin(id);
|
|
39
40
|
}}
|
|
40
41
|
onOpenChange={setModal}
|
|
41
42
|
onSave={(value) => {
|
|
@@ -53,7 +54,7 @@ const MarketList = memo<{ id: string }>(({ id }) => {
|
|
|
53
54
|
}
|
|
54
55
|
loading={pluginManifestLoading[id]}
|
|
55
56
|
onChange={(checked) => {
|
|
56
|
-
|
|
57
|
+
toggleAgentPlugin(id);
|
|
57
58
|
if (checked) {
|
|
58
59
|
fetchPluginManifest(id);
|
|
59
60
|
}
|
|
@@ -2,14 +2,14 @@ import { Avatar, Form, Icon, Tooltip } from '@lobehub/ui';
|
|
|
2
2
|
import { Button, Skeleton, Switch, Tag } from 'antd';
|
|
3
3
|
import { createStyles } from 'antd-style';
|
|
4
4
|
import isEqual from 'fast-deep-equal';
|
|
5
|
-
import { LucideBlocks, LucideStore } from 'lucide-react';
|
|
5
|
+
import { LucideBlocks, LucideStore, LucideTrash2 } from 'lucide-react';
|
|
6
6
|
import { memo, useState } from 'react';
|
|
7
7
|
import { useTranslation } from 'react-i18next';
|
|
8
8
|
import { Flexbox } from 'react-layout-kit';
|
|
9
9
|
import DevModal from 'src/features/PluginDevModal';
|
|
10
10
|
|
|
11
11
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
12
|
-
import { pluginHelpers, usePluginStore } from '@/store/plugin';
|
|
12
|
+
import { pluginHelpers, pluginSelectors, usePluginStore } from '@/store/plugin';
|
|
13
13
|
|
|
14
14
|
import { useStore } from '../store';
|
|
15
15
|
import LocalPluginItem from './LocalPluginItem';
|
|
@@ -37,11 +37,7 @@ const MarketList = memo(() => {
|
|
|
37
37
|
|
|
38
38
|
const [showModal, setModal] = useState(false);
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
// setModal(true);
|
|
42
|
-
// }, []);
|
|
43
|
-
|
|
44
|
-
const [plugins, hasPlugin, toggleAgentPlugin] = useStore((s) => [
|
|
40
|
+
const [userEnabledPlugins, hasPlugin, toggleAgentPlugin] = useStore((s) => [
|
|
45
41
|
s.config.plugins || [],
|
|
46
42
|
!!s.config.plugins,
|
|
47
43
|
s.toggleAgentPlugin,
|
|
@@ -57,6 +53,7 @@ const MarketList = memo(() => {
|
|
|
57
53
|
const pluginManifestLoading = usePluginStore((s) => s.pluginManifestLoading, isEqual);
|
|
58
54
|
const pluginList = usePluginStore((s) => s.pluginList, isEqual);
|
|
59
55
|
const customPluginList = usePluginStore((s) => s.customPluginList, isEqual);
|
|
56
|
+
const totalList = usePluginStore(pluginSelectors.pluginList, isEqual);
|
|
60
57
|
|
|
61
58
|
useFetchPluginList();
|
|
62
59
|
|
|
@@ -100,7 +97,9 @@ const MarketList = memo(() => {
|
|
|
100
97
|
<Switch
|
|
101
98
|
checked={
|
|
102
99
|
// 如果在加载中,说明激活了
|
|
103
|
-
pluginManifestLoading[identifier] || !hasPlugin
|
|
100
|
+
pluginManifestLoading[identifier] || !hasPlugin
|
|
101
|
+
? false
|
|
102
|
+
: userEnabledPlugins.includes(identifier)
|
|
104
103
|
}
|
|
105
104
|
loading={pluginManifestLoading[identifier]}
|
|
106
105
|
onChange={(checked) => {
|
|
@@ -132,6 +131,35 @@ const MarketList = memo(() => {
|
|
|
132
131
|
tag: identifier,
|
|
133
132
|
}));
|
|
134
133
|
|
|
134
|
+
// =========== Deprecated Plugin List =========== //
|
|
135
|
+
|
|
136
|
+
// 基于 userEnabledPlugins 和完整的 totalList,检查出不在 totalList 中的插件
|
|
137
|
+
const deprecatedList = userEnabledPlugins
|
|
138
|
+
.filter((pluginId) => totalList.findIndex((p) => p.identifier === pluginId) < 0)
|
|
139
|
+
.map((id) => ({
|
|
140
|
+
avatar: <Avatar avatar={'♻️'} />,
|
|
141
|
+
children: (
|
|
142
|
+
<Switch
|
|
143
|
+
checked={true}
|
|
144
|
+
onChange={(checked) => {
|
|
145
|
+
togglePlugin(id, checked);
|
|
146
|
+
}}
|
|
147
|
+
/>
|
|
148
|
+
),
|
|
149
|
+
label: (
|
|
150
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
151
|
+
{id}
|
|
152
|
+
<Tag bordered={false} color={'red'}>
|
|
153
|
+
{t('list.item.deprecated.title', { ns: 'plugin' })}
|
|
154
|
+
</Tag>
|
|
155
|
+
</Flexbox>
|
|
156
|
+
),
|
|
157
|
+
minWidth: undefined,
|
|
158
|
+
tag: id,
|
|
159
|
+
}));
|
|
160
|
+
|
|
161
|
+
const hasDeprecated = deprecatedList.length > 0;
|
|
162
|
+
|
|
135
163
|
return (
|
|
136
164
|
<>
|
|
137
165
|
<DevModal
|
|
@@ -148,27 +176,44 @@ const MarketList = memo(() => {
|
|
|
148
176
|
<Form
|
|
149
177
|
items={[
|
|
150
178
|
{
|
|
151
|
-
children: isEmpty ? loadingList : [...customList, ...list],
|
|
179
|
+
children: isEmpty ? loadingList : [...deprecatedList, ...customList, ...list],
|
|
152
180
|
extra: (
|
|
153
|
-
<
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
181
|
+
<Flexbox gap={8} horizontal>
|
|
182
|
+
{hasDeprecated ? (
|
|
183
|
+
<Tooltip title={t('settingPlugin.clearDeprecated')}>
|
|
184
|
+
<Button
|
|
185
|
+
icon={<Icon icon={LucideTrash2} />}
|
|
186
|
+
onClick={(e) => {
|
|
187
|
+
e.stopPropagation();
|
|
188
|
+
for (const i of deprecatedList) {
|
|
189
|
+
togglePlugin(i.tag as string, false);
|
|
190
|
+
}
|
|
191
|
+
}}
|
|
192
|
+
size={'small'}
|
|
193
|
+
type={'text'}
|
|
194
|
+
></Button>
|
|
195
|
+
</Tooltip>
|
|
196
|
+
) : null}
|
|
197
|
+
<Tooltip title={t('settingPlugin.addTooltip')}>
|
|
198
|
+
<Button
|
|
199
|
+
icon={<Icon icon={LucideBlocks} />}
|
|
200
|
+
onClick={(e) => {
|
|
201
|
+
e.stopPropagation();
|
|
202
|
+
setModal(true);
|
|
203
|
+
}}
|
|
204
|
+
size={'small'}
|
|
205
|
+
>
|
|
206
|
+
{t('settingPlugin.add')}
|
|
207
|
+
</Button>
|
|
208
|
+
</Tooltip>
|
|
209
|
+
</Flexbox>
|
|
165
210
|
),
|
|
166
211
|
icon: LucideStore,
|
|
167
212
|
title: t('settingPlugin.title'),
|
|
168
213
|
},
|
|
169
214
|
]}
|
|
170
215
|
{...FORM_STYLE}
|
|
171
|
-
/>
|
|
216
|
+
/>
|
|
172
217
|
</>
|
|
173
218
|
);
|
|
174
219
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { produce } from 'immer';
|
|
2
|
-
import { merge } from 'lodash-es';
|
|
3
2
|
|
|
4
3
|
import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
|
|
5
4
|
import { LobeAgentConfig } from '@/types/session';
|
|
5
|
+
import { merge } from '@/utils/merge';
|
|
6
6
|
|
|
7
7
|
export type ConfigDispatch =
|
|
8
8
|
| { config: Partial<any>; type: 'update' }
|
|
@@ -13,7 +13,7 @@ export const configReducer = (state: LobeAgentConfig, payload: ConfigDispatch):
|
|
|
13
13
|
switch (payload.type) {
|
|
14
14
|
case 'update': {
|
|
15
15
|
return produce(state, (draftState) => {
|
|
16
|
-
return merge(
|
|
16
|
+
return merge(draftState, payload.config);
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { produce } from 'immer';
|
|
2
|
-
import { merge } from 'lodash-es';
|
|
3
2
|
|
|
4
3
|
import { DEFAULT_AGENT_META } from '@/const/meta';
|
|
5
4
|
import { MetaData } from '@/types/meta';
|
|
5
|
+
import { merge } from '@/utils/merge';
|
|
6
6
|
|
|
7
7
|
export type MetaDataDispatch = { type: 'update'; value: Partial<MetaData> } | { type: 'reset' };
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ export const metaDataReducer = (state: MetaData, payload: MetaDataDispatch): Met
|
|
|
10
10
|
switch (payload.type) {
|
|
11
11
|
case 'update': {
|
|
12
12
|
return produce(state, (draftState) => {
|
|
13
|
-
return merge(
|
|
13
|
+
return merge(draftState, payload.value);
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import { onPluginFetchMessage, onPluginReady } from './utils';
|
|
4
|
+
|
|
5
|
+
export const useOnPluginReady = (onReady: () => void) => {
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const fn = (e: MessageEvent) => {
|
|
8
|
+
onPluginReady(e, onReady);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
window.addEventListener('message', fn);
|
|
12
|
+
return () => {
|
|
13
|
+
window.removeEventListener('message', fn);
|
|
14
|
+
};
|
|
15
|
+
}, []);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const useOnPluginFetchMessage = (onRequest: (data: any) => void, deps: any[] = []) => {
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const fn = (e: MessageEvent) => {
|
|
21
|
+
onPluginFetchMessage(e, onRequest);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
window.addEventListener('message', fn);
|
|
25
|
+
return () => {
|
|
26
|
+
window.removeEventListener('message', fn);
|
|
27
|
+
};
|
|
28
|
+
}, deps);
|
|
29
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { PluginRenderProps } from '@lobehub/chat-plugin-sdk';
|
|
2
|
+
import { Skeleton } from 'antd';
|
|
3
|
+
import { memo, useEffect, useRef, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import { useOnPluginFetchMessage, useOnPluginReady } from './hooks';
|
|
6
|
+
import { sendMessageToPlugin } from './utils';
|
|
7
|
+
|
|
8
|
+
interface IFrameRenderProps extends PluginRenderProps {
|
|
9
|
+
height?: number;
|
|
10
|
+
url: string;
|
|
11
|
+
width?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const IFrameRender = memo<IFrameRenderProps>(({ url, width = 800, height = 300, ...props }) => {
|
|
15
|
+
const [loading, setLoading] = useState(true);
|
|
16
|
+
const [readyForRender, setReady] = useState(false);
|
|
17
|
+
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
18
|
+
|
|
19
|
+
useOnPluginReady(() => setReady(true));
|
|
20
|
+
|
|
21
|
+
// 当 props 发生变化时,主动向 iframe 发送数据
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const iframeWin = iframeRef.current?.contentWindow;
|
|
24
|
+
|
|
25
|
+
if (iframeWin && readyForRender) {
|
|
26
|
+
sendMessageToPlugin(iframeWin, props);
|
|
27
|
+
}
|
|
28
|
+
}, [readyForRender, props]);
|
|
29
|
+
|
|
30
|
+
// 当接收到来自 iframe 的请求时,触发发送数据
|
|
31
|
+
useOnPluginFetchMessage(() => {
|
|
32
|
+
const iframeWin = iframeRef.current?.contentWindow;
|
|
33
|
+
if (iframeWin) {
|
|
34
|
+
sendMessageToPlugin(iframeWin, props);
|
|
35
|
+
}
|
|
36
|
+
}, [props]);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
{loading && <Skeleton active style={{ width }} />}
|
|
41
|
+
<iframe
|
|
42
|
+
// @ts-ignore
|
|
43
|
+
allowtransparency="true"
|
|
44
|
+
height={height}
|
|
45
|
+
hidden={loading}
|
|
46
|
+
onLoad={() => {
|
|
47
|
+
setLoading(false);
|
|
48
|
+
}}
|
|
49
|
+
ref={iframeRef}
|
|
50
|
+
src={url}
|
|
51
|
+
style={{
|
|
52
|
+
border: 0,
|
|
53
|
+
// iframe 在 color-scheme:dark 模式下无法透明
|
|
54
|
+
// refs: https://www.jianshu.com/p/bc5a37bb6a7b
|
|
55
|
+
colorScheme: 'light',
|
|
56
|
+
}}
|
|
57
|
+
width={width}
|
|
58
|
+
/>
|
|
59
|
+
</>
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
export default IFrameRender;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PluginChannel } from '@lobehub/chat-plugin-sdk';
|
|
2
|
+
|
|
3
|
+
export const onPluginReady = (e: MessageEvent, onReady: () => void) => {
|
|
4
|
+
if (e.data.type === PluginChannel.pluginReadyForRender) {
|
|
5
|
+
onReady();
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const onPluginFetchMessage = (e: MessageEvent, onRequest: (data: any) => void) => {
|
|
10
|
+
if (e.data.type === PluginChannel.fetchPluginMessage) {
|
|
11
|
+
onRequest(e.data);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const sendMessageToPlugin = (window: Window, props: any) => {
|
|
16
|
+
window.postMessage({ props, type: PluginChannel.renderPlugin }, '*');
|
|
17
|
+
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Loading3QuartersOutlined } from '@ant-design/icons';
|
|
2
|
-
import { memo } from 'react';
|
|
2
|
+
import { memo, useMemo } from 'react';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { Flexbox } from 'react-layout-kit';
|
|
5
5
|
|
|
6
6
|
import { usePluginStore } from '@/store/plugin';
|
|
7
7
|
import { ChatMessage } from '@/types/chatMessage';
|
|
8
8
|
|
|
9
|
-
import
|
|
9
|
+
import IFrameRender from './IFrameRender';
|
|
10
|
+
import SystemJsRender from './SystemJsRender';
|
|
10
11
|
|
|
11
12
|
export interface FunctionMessageProps extends ChatMessage {
|
|
12
13
|
loading?: boolean;
|
|
@@ -23,6 +24,8 @@ const PluginMessage = memo<FunctionMessageProps>(({ content, name }) => {
|
|
|
23
24
|
isJSON = false;
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
const contentObj = useMemo(() => (isJSON ? JSON.parse(content) : content), [content]);
|
|
28
|
+
|
|
26
29
|
// if (!loading)
|
|
27
30
|
|
|
28
31
|
if (!isJSON) {
|
|
@@ -36,10 +39,23 @@ const PluginMessage = memo<FunctionMessageProps>(({ content, name }) => {
|
|
|
36
39
|
);
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
if (!manifest?.ui
|
|
42
|
+
if (!manifest?.ui) return;
|
|
43
|
+
|
|
44
|
+
const ui = manifest.ui;
|
|
45
|
+
|
|
46
|
+
if (!ui.url) return;
|
|
47
|
+
|
|
48
|
+
if (ui.mode === 'module')
|
|
49
|
+
return <SystemJsRender content={contentObj} name={name || 'unknown'} url={ui.url} />;
|
|
40
50
|
|
|
41
51
|
return (
|
|
42
|
-
<
|
|
52
|
+
<IFrameRender
|
|
53
|
+
content={contentObj}
|
|
54
|
+
height={ui.height}
|
|
55
|
+
name={name || 'unknown'}
|
|
56
|
+
url={ui.url}
|
|
57
|
+
width={ui.width}
|
|
58
|
+
/>
|
|
43
59
|
);
|
|
44
60
|
});
|
|
45
61
|
|
|
@@ -2,12 +2,13 @@ import { PluginRender, PluginRenderProps } from '@lobehub/chat-plugin-sdk';
|
|
|
2
2
|
import { Skeleton } from 'antd';
|
|
3
3
|
import { memo, useEffect, useState } from 'react';
|
|
4
4
|
|
|
5
|
-
import { system } from './
|
|
5
|
+
import { system } from './utils';
|
|
6
6
|
|
|
7
|
-
interface
|
|
7
|
+
interface SystemJsRenderProps extends PluginRenderProps {
|
|
8
8
|
url: string;
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
const SystemJsRender = memo<SystemJsRenderProps>(({ url, ...props }) => {
|
|
11
12
|
const [component, setComp] = useState<PluginRender | null>(null);
|
|
12
13
|
|
|
13
14
|
useEffect(() => {
|
|
@@ -31,4 +32,4 @@ const CustomRender = memo<CustomRenderProps>(({ url, ...props }) => {
|
|
|
31
32
|
|
|
32
33
|
return <Render {...props} />;
|
|
33
34
|
});
|
|
34
|
-
export default
|
|
35
|
+
export default SystemJsRender;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { uniqBy } from 'lodash-es';
|
|
2
|
+
import { ChatCompletionFunctions } from 'openai-edge/types/api';
|
|
3
|
+
|
|
1
4
|
import { PLUGIN_SCHEMA_SEPARATOR } from '@/const/plugin';
|
|
2
5
|
import { pluginHelpers } from '@/store/plugin/helpers';
|
|
3
6
|
|
|
@@ -5,12 +8,12 @@ import { PluginStoreState } from './initialState';
|
|
|
5
8
|
|
|
6
9
|
const enabledSchema =
|
|
7
10
|
(enabledPlugins: string[] = []) =>
|
|
8
|
-
(s: PluginStoreState) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// 如果不存在 enabledPlugins,那么全部不启用
|
|
12
|
-
if (!enabledPlugins) return false;
|
|
11
|
+
(s: PluginStoreState): ChatCompletionFunctions[] => {
|
|
12
|
+
// 如果不存在 enabledPlugins,那么全部不启用
|
|
13
|
+
if (!enabledPlugins) return [];
|
|
13
14
|
|
|
15
|
+
const list = Object.values(s.pluginManifestMap)
|
|
16
|
+
.filter((p) => {
|
|
14
17
|
// 如果存在 enabledPlugins,那么只启用 enabledPlugins 中的插件
|
|
15
18
|
return enabledPlugins.includes(p.identifier);
|
|
16
19
|
})
|
|
@@ -21,6 +24,8 @@ const enabledSchema =
|
|
|
21
24
|
name: manifest.identifier + PLUGIN_SCHEMA_SEPARATOR + m.name,
|
|
22
25
|
})),
|
|
23
26
|
);
|
|
27
|
+
|
|
28
|
+
return uniqBy(list, 'name');
|
|
24
29
|
};
|
|
25
30
|
|
|
26
31
|
const pluginList = (s: PluginStoreState) => [...s.pluginList, ...s.customPluginList];
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { t } from 'i18next';
|
|
2
|
-
import { merge } from 'lodash-es';
|
|
3
2
|
|
|
4
3
|
import { DEFAULT_AVATAR, DEFAULT_BACKGROUND_COLOR } from '@/const/meta';
|
|
5
4
|
import { SessionStore } from '@/store/session';
|
|
6
5
|
import { LanguageModel } from '@/types/llm';
|
|
7
6
|
import { MetaData } from '@/types/meta';
|
|
7
|
+
import { merge } from '@/utils/merge';
|
|
8
8
|
|
|
9
9
|
import { sessionSelectors } from '../session/selectors';
|
|
10
10
|
import { initialLobeAgentConfig } from './initialState';
|
|
@@ -19,7 +19,7 @@ const currentAgentTitle = (s: SessionStore) => currentAgentMeta(s)?.title || t('
|
|
|
19
19
|
|
|
20
20
|
const currentAgentConfig = (s: SessionStore) => {
|
|
21
21
|
const session = sessionSelectors.currentSession(s);
|
|
22
|
-
return merge(
|
|
22
|
+
return merge(initialLobeAgentConfig, session?.config);
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
const currentAgentSystemRole = (s: SessionStore) => {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { merge as _merge, mergeWith } from 'lodash-es';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 用于合并对象,如果是数组则直接替换
|
|
5
|
+
* @param target
|
|
6
|
+
* @param source
|
|
7
|
+
*/
|
|
8
|
+
export const merge: typeof _merge = <T = object>(target: T, source: T) =>
|
|
9
|
+
mergeWith({}, target, source, (obj, src) => {
|
|
10
|
+
if (Array.isArray(obj)) return src;
|
|
11
|
+
});
|
|
File without changes
|