@lobehub/chat 0.94.4 → 0.95.0
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/.github/workflows/pr-welcome.yml +1 -1
- package/CHANGELOG.md +60 -0
- package/CONTRIBUTING.md +88 -0
- package/package.json +4 -4
- package/src/app/chat/(desktop)/features/ChatInput.tsx +0 -1
- package/src/app/chat/features/Conversation/ChatList/Error/Plugin/PluginSettings.tsx +1 -1
- package/src/app/chat/features/Conversation/ChatList/Messages/Assistant.tsx +12 -15
- package/src/app/chat/features/Conversation/ChatList/Messages/Function.tsx +26 -15
- package/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/Settings.tsx +36 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/{FunctionCall.tsx → Inspector/index.tsx} +53 -25
- package/src/app/chat/features/Conversation/ChatList/Plugins/{IFrameRender → Render/DefaultType/IFrameRender}/index.tsx +5 -16
- package/src/app/chat/features/Conversation/ChatList/Plugins/{PluginMessage.tsx → Render/DefaultType/index.tsx} +3 -3
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/StandaloneType/Iframe.tsx +136 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/StandaloneType/index.tsx +28 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/index.tsx +28 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/iframeOnReady.ts +23 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/listenToPlugin.ts +65 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/pluginSettings.ts +17 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/pluginState.ts +20 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/postMessage.ts +17 -0
- package/src/app/market/page.tsx +2 -22
- package/src/chains/summaryAgentName.ts +13 -8
- package/src/chains/summaryDescription.ts +28 -5
- package/src/chains/summaryTags.ts +8 -7
- package/src/chains/summaryTitle.ts +5 -3
- package/src/const/plugin.ts +1 -1
- package/src/features/PluginSettings/index.tsx +5 -3
- package/src/features/PluginSettingsModal/index.tsx +45 -0
- package/src/services/agentMarket.ts +9 -7
- package/src/services/pluginMarket.ts +2 -2
- package/src/store/global/helpers.ts +5 -0
- package/src/store/global/selectors/settings.ts +1 -0
- package/src/store/plugin/selectors.ts +10 -4
- package/src/store/session/slices/chat/actions/index.ts +4 -1
- package/src/store/session/slices/chat/actions/message.ts +102 -117
- package/src/store/session/slices/chat/actions/plugin.ts +109 -0
- package/src/store/session/slices/chat/reducers/message.ts +31 -1
- package/src/store/session/slices/chat/selectors/chat.ts +17 -20
- package/src/store/session/slices/chat/selectors/index.ts +4 -2
- package/src/types/chatMessage.ts +1 -0
- package/src/utils/message.ts +8 -1
- package/src/app/chat/features/Conversation/ChatList/Plugins/IFrameRender/hooks.ts +0 -29
- package/src/app/chat/features/Conversation/ChatList/Plugins/IFrameRender/utils.ts +0 -17
- /package/src/app/chat/features/Conversation/ChatList/Plugins/{PluginResultRender.tsx → Inspector/PluginResultJSON.tsx} +0 -0
- /package/src/app/chat/features/Conversation/ChatList/Plugins/{style.ts → Inspector/style.ts} +0 -0
- /package/src/app/chat/features/Conversation/ChatList/Plugins/{SystemJsRender → Render/DefaultType/SystemJsRender}/index.tsx +0 -0
- /package/src/app/chat/features/Conversation/ChatList/Plugins/{SystemJsRender → Render/DefaultType/SystemJsRender}/utils.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 0.95.0](https://github.com/lobehub/lobe-chat/compare/v0.94.5...v0.95.0)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-10-24**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **misc**: 优化 plugin 文件夹命名以支持 standalone 类型的插件.
|
|
12
|
+
|
|
13
|
+
#### ✨ Features
|
|
14
|
+
|
|
15
|
+
- **misc**: Support function call at message end, support plugin settings modal, support plugin state and settings.
|
|
16
|
+
|
|
17
|
+
<br/>
|
|
18
|
+
|
|
19
|
+
<details>
|
|
20
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
21
|
+
|
|
22
|
+
#### Code refactoring
|
|
23
|
+
|
|
24
|
+
- **misc**: 优化 plugin 文件夹命名以支持 standalone 类型的插件 ([98860a8](https://github.com/lobehub/lobe-chat/commit/98860a8))
|
|
25
|
+
|
|
26
|
+
#### What's improved
|
|
27
|
+
|
|
28
|
+
- **misc**: Support function call at message end, closes [#357](https://github.com/lobehub/lobe-chat/issues/357) ([e195fdb](https://github.com/lobehub/lobe-chat/commit/e195fdb))
|
|
29
|
+
- **misc**: Support plugin settings modal ([f47b6fa](https://github.com/lobehub/lobe-chat/commit/f47b6fa))
|
|
30
|
+
- **misc**: Support plugin state and settings ([10829a4](https://github.com/lobehub/lobe-chat/commit/10829a4))
|
|
31
|
+
|
|
32
|
+
</details>
|
|
33
|
+
|
|
34
|
+
<div align="right">
|
|
35
|
+
|
|
36
|
+
[](#readme-top)
|
|
37
|
+
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
### [Version 0.94.5](https://github.com/lobehub/lobe-chat/compare/v0.94.4...v0.94.5)
|
|
41
|
+
|
|
42
|
+
<sup>Released on **2023-10-22**</sup>
|
|
43
|
+
|
|
44
|
+
#### 🐛 Bug Fixes
|
|
45
|
+
|
|
46
|
+
- **misc**: Fallback agent market index to en when not find correct locale.
|
|
47
|
+
|
|
48
|
+
<br/>
|
|
49
|
+
|
|
50
|
+
<details>
|
|
51
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
52
|
+
|
|
53
|
+
#### What's fixed
|
|
54
|
+
|
|
55
|
+
- **misc**: Fallback agent market index to en when not find correct locale, closes [#355](https://github.com/lobehub/lobe-chat/issues/355) ([7a45ab4](https://github.com/lobehub/lobe-chat/commit/7a45ab4))
|
|
56
|
+
|
|
57
|
+
</details>
|
|
58
|
+
|
|
59
|
+
<div align="right">
|
|
60
|
+
|
|
61
|
+
[](#readme-top)
|
|
62
|
+
|
|
63
|
+
</div>
|
|
64
|
+
|
|
5
65
|
### [Version 0.94.4](https://github.com/lobehub/lobe-chat/compare/v0.94.3...v0.94.4)
|
|
6
66
|
|
|
7
67
|
<sup>Released on **2023-10-21**</sup>
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Lobe Chat - Contributing Guide 🌟
|
|
2
|
+
|
|
3
|
+
We're thrilled that you want to contribute to Lobe Chat, the future of communication! 😄
|
|
4
|
+
|
|
5
|
+
Lobe Chat is an open-source project, and we welcome your collaboration. Before you jump in, let's make sure you're all set to contribute effectively and have loads of fun along the way!
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Fork the Repository](#fork-the-repository)
|
|
10
|
+
- [Clone Your Fork](#clone-your-fork)
|
|
11
|
+
- [Create a New Branch](#create-a-new-branch)
|
|
12
|
+
- [Code Like a Wizard](#code-like-a-wizard)
|
|
13
|
+
- [Committing Your Work](#committing-your-work)
|
|
14
|
+
- [Sync with Upstream](#sync-with-upstream)
|
|
15
|
+
- [Open a Pull Request](#open-a-pull-request)
|
|
16
|
+
- [Review and Collaboration](#review-and-collaboration)
|
|
17
|
+
- [Celebrate 🎉](#celebrate-)
|
|
18
|
+
|
|
19
|
+
## Fork the Repository
|
|
20
|
+
|
|
21
|
+
🍴 Fork this repository to your GitHub account by clicking the "Fork" button at the top right. This creates a personal copy of the project you can work on.
|
|
22
|
+
|
|
23
|
+
## Clone Your Fork
|
|
24
|
+
|
|
25
|
+
📦 Clone your forked repository to your local machine using the `git clone` command:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone https://github.com/YourUsername/lobe-chat.git
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Create a New Branch
|
|
32
|
+
|
|
33
|
+
🌿 Create a new branch for your contribution. This helps keep your work organized and separate from the main codebase.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
git checkout -b your-branch-name
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Choose a meaningful branch name related to your work. It makes collaboration easier!
|
|
40
|
+
|
|
41
|
+
## Code Like a Wizard
|
|
42
|
+
|
|
43
|
+
🧙♀️ Time to work your magic! Write your code, fix bugs, or add new features. Be sure to follow our project's coding style. You can check if your code adheres to our style using:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
yarn lint
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This adds a bit of enchantment to your coding experience! ✨
|
|
50
|
+
|
|
51
|
+
## Committing Your Work
|
|
52
|
+
|
|
53
|
+
📝 Ready to save your progress? Commit your changes to your branch.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
git add .
|
|
57
|
+
git commit -m "Your meaningful commit message"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Please keep your commits focused and clear. And remember to be kind to your fellow contributors; keep your commits concise.
|
|
61
|
+
|
|
62
|
+
## Sync with Upstream
|
|
63
|
+
|
|
64
|
+
⚙️ Periodically, sync your forked repository with the original (upstream) repository to stay up-to-date with the latest changes.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git remote add upstream https://github.com/lobehub/lobe-chat.git
|
|
68
|
+
git fetch upstream
|
|
69
|
+
git merge upstream/main
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This ensures you're working on the most current version of Lobe Chat. Stay fresh! 💨
|
|
73
|
+
|
|
74
|
+
## Open a Pull Request
|
|
75
|
+
|
|
76
|
+
🚀 Time to share your contribution! Head over to the original Lobe Chat repository and open a Pull Request (PR). Our maintainers will review your work.
|
|
77
|
+
|
|
78
|
+
## Review and Collaboration
|
|
79
|
+
|
|
80
|
+
👓 Your PR will undergo thorough review and testing. The maintainers will provide feedback, and you can collaborate to make your contribution even better. We value teamwork!
|
|
81
|
+
|
|
82
|
+
## Celebrate 🎉
|
|
83
|
+
|
|
84
|
+
🎈 Congratulations! Your contribution is now part of Lobe Chat. 🥳
|
|
85
|
+
|
|
86
|
+
Thank you for making Lobe Chat even more magical. We can't wait to see what you create! 🌠
|
|
87
|
+
|
|
88
|
+
Happy Coding! 🚀🦄
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.95.0",
|
|
4
4
|
"description": "An open-source, extensible (Function Calling), high-performance chatbot framework. It supports one-click free deployment of your private ChatGPT/LLM web application",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chatbot",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"ahooks": "^3",
|
|
77
77
|
"ai": "^2",
|
|
78
78
|
"antd": "^5",
|
|
79
|
-
"antd-style": "^3
|
|
79
|
+
"antd-style": "^3",
|
|
80
80
|
"brotli-wasm": "^1",
|
|
81
81
|
"chroma-js": "^2",
|
|
82
82
|
"copy-to-clipboard": "^3",
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
"zustand-utils": "^1"
|
|
123
123
|
},
|
|
124
124
|
"devDependencies": {
|
|
125
|
-
"@commitlint/cli": "^
|
|
125
|
+
"@commitlint/cli": "^18",
|
|
126
126
|
"@lobehub/i18n-cli": "latest",
|
|
127
127
|
"@lobehub/lint": "latest",
|
|
128
128
|
"@next/bundle-analyzer": "^13",
|
|
@@ -141,7 +141,7 @@
|
|
|
141
141
|
"@types/uuid": "^9",
|
|
142
142
|
"@umijs/lint": "^4",
|
|
143
143
|
"@vitest/coverage-v8": "latest",
|
|
144
|
-
"commitlint": "^
|
|
144
|
+
"commitlint": "^18",
|
|
145
145
|
"consola": "^3",
|
|
146
146
|
"dpdm": "^3",
|
|
147
147
|
"eslint": "^8",
|
|
@@ -36,7 +36,7 @@ const PluginSettings: RenderErrorMessage = memo(({ id, plugin }) => {
|
|
|
36
36
|
<Flexbox className={styles.desc}>{t('pluginSettings.desc')}</Flexbox>
|
|
37
37
|
<Divider style={{ margin: '0 16px' }} />
|
|
38
38
|
{manifest.settings && (
|
|
39
|
-
<PluginSettingsConfig id={manifest.identifier}
|
|
39
|
+
<PluginSettingsConfig id={manifest.identifier} schema={manifest.settings} />
|
|
40
40
|
)}
|
|
41
41
|
<Button
|
|
42
42
|
block
|
|
@@ -3,23 +3,20 @@ import { memo } from 'react';
|
|
|
3
3
|
|
|
4
4
|
import { useSessionStore } from '@/store/session';
|
|
5
5
|
import { chatSelectors } from '@/store/session/selectors';
|
|
6
|
-
import {
|
|
6
|
+
import { isFunctionMessageAtStart } from '@/utils/message';
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import Inspector from '../Plugins/Inspector';
|
|
9
9
|
import { DefaultMessage } from './Default';
|
|
10
10
|
|
|
11
|
-
export const AssistantMessage: RenderMessage = memo(
|
|
12
|
-
({ id, plugin
|
|
13
|
-
const genFunctionCallProps = useSessionStore(chatSelectors.getFunctionMessageParams);
|
|
11
|
+
export const AssistantMessage: RenderMessage = memo(({ id, plugin, content, ...props }) => {
|
|
12
|
+
const fcProps = useSessionStore(chatSelectors.getFunctionMessageProps({ content, id, plugin }));
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
if (!isFunctionMessageAtStart(content))
|
|
15
|
+
return <DefaultMessage content={content} id={id} {...props} />;
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
);
|
|
24
|
-
},
|
|
25
|
-
);
|
|
17
|
+
return (
|
|
18
|
+
<div id={id}>
|
|
19
|
+
<Inspector {...fcProps} />
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
});
|
|
@@ -1,23 +1,34 @@
|
|
|
1
1
|
import { RenderMessage } from '@lobehub/ui';
|
|
2
|
-
import
|
|
2
|
+
import isEqual from 'fast-deep-equal';
|
|
3
|
+
import { memo, useState } from 'react';
|
|
3
4
|
import { Flexbox } from 'react-layout-kit';
|
|
4
5
|
|
|
5
6
|
import { useSessionStore } from '@/store/session';
|
|
6
7
|
import { chatSelectors } from '@/store/session/selectors';
|
|
7
8
|
|
|
8
|
-
import
|
|
9
|
-
import
|
|
9
|
+
import Inspector from '../Plugins/Inspector';
|
|
10
|
+
import PluginRender from '../Plugins/Render';
|
|
10
11
|
|
|
11
|
-
export const FunctionMessage: RenderMessage = memo(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
export const FunctionMessage: RenderMessage = memo(({ id, content, plugin, name }) => {
|
|
13
|
+
const fcProps = useSessionStore(
|
|
14
|
+
chatSelectors.getFunctionMessageProps({ content, id, plugin }),
|
|
15
|
+
isEqual,
|
|
16
|
+
);
|
|
17
|
+
const [showRender, setShow] = useState(true);
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
return (
|
|
20
|
+
<Flexbox gap={12} id={id}>
|
|
21
|
+
<Inspector showRender={showRender} {...fcProps} setShow={setShow} />
|
|
22
|
+
{showRender && (
|
|
23
|
+
<PluginRender
|
|
24
|
+
content={content}
|
|
25
|
+
id={id}
|
|
26
|
+
loading={fcProps.loading}
|
|
27
|
+
name={name}
|
|
28
|
+
payload={fcProps.command}
|
|
29
|
+
type={fcProps.type}
|
|
30
|
+
/>
|
|
31
|
+
)}
|
|
32
|
+
</Flexbox>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ActionIcon } from '@lobehub/ui';
|
|
2
|
+
import { LucideSettings } from 'lucide-react';
|
|
3
|
+
import { memo, useState } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
|
|
6
|
+
import PluginSettingsModal from '@/features/PluginSettingsModal';
|
|
7
|
+
import { pluginSelectors, usePluginStore } from '@/store/plugin';
|
|
8
|
+
|
|
9
|
+
const Settings = memo<{ id: string }>(({ id }) => {
|
|
10
|
+
const item = usePluginStore(pluginSelectors.getPluginManifestById(id));
|
|
11
|
+
const [open, setOpen] = useState(false);
|
|
12
|
+
const { t } = useTranslation('plugin');
|
|
13
|
+
return (
|
|
14
|
+
item?.settings && (
|
|
15
|
+
<>
|
|
16
|
+
<ActionIcon
|
|
17
|
+
icon={LucideSettings}
|
|
18
|
+
onClick={() => {
|
|
19
|
+
setOpen(true);
|
|
20
|
+
}}
|
|
21
|
+
title={t('setting')}
|
|
22
|
+
/>
|
|
23
|
+
<PluginSettingsModal
|
|
24
|
+
id={id}
|
|
25
|
+
onClose={() => {
|
|
26
|
+
setOpen(false);
|
|
27
|
+
}}
|
|
28
|
+
open={open}
|
|
29
|
+
schema={item.settings}
|
|
30
|
+
/>
|
|
31
|
+
</>
|
|
32
|
+
)
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export default Settings;
|
package/src/app/chat/features/Conversation/ChatList/Plugins/{FunctionCall.tsx → Inspector/index.tsx}
RENAMED
|
@@ -1,26 +1,40 @@
|
|
|
1
1
|
import { LoadingOutlined } from '@ant-design/icons';
|
|
2
|
-
import {
|
|
2
|
+
import { LobePluginType } from '@lobehub/chat-plugin-sdk';
|
|
3
|
+
import { ActionIcon, Avatar, Highlighter, Icon } from '@lobehub/ui';
|
|
3
4
|
import { Tabs } from 'antd';
|
|
4
|
-
import { LucideChevronDown, LucideChevronUp, LucideToyBrick } from 'lucide-react';
|
|
5
|
+
import { LucideChevronDown, LucideChevronUp, LucideOrbit, LucideToyBrick } from 'lucide-react';
|
|
5
6
|
import { memo, useState } from 'react';
|
|
6
7
|
import { useTranslation } from 'react-i18next';
|
|
7
8
|
import { Flexbox } from 'react-layout-kit';
|
|
8
9
|
|
|
9
10
|
import { pluginHelpers, pluginSelectors, usePluginStore } from '@/store/plugin';
|
|
10
11
|
|
|
11
|
-
import PluginResult from './
|
|
12
|
+
import PluginResult from './PluginResultJSON';
|
|
13
|
+
import Settings from './Settings';
|
|
12
14
|
import { useStyles } from './style';
|
|
13
15
|
|
|
14
|
-
export interface
|
|
16
|
+
export interface InspectorProps {
|
|
15
17
|
arguments?: string;
|
|
16
18
|
command?: any;
|
|
17
19
|
content: string;
|
|
18
20
|
id?: string;
|
|
19
21
|
loading?: boolean;
|
|
22
|
+
setShow?: (showRender: boolean) => void;
|
|
23
|
+
showRender?: boolean;
|
|
24
|
+
type?: LobePluginType;
|
|
20
25
|
}
|
|
21
26
|
|
|
22
|
-
const
|
|
23
|
-
({
|
|
27
|
+
const Inspector = memo<InspectorProps>(
|
|
28
|
+
({
|
|
29
|
+
arguments: requestArgs = '{}',
|
|
30
|
+
command,
|
|
31
|
+
showRender,
|
|
32
|
+
loading,
|
|
33
|
+
setShow,
|
|
34
|
+
content,
|
|
35
|
+
id = 'unknown',
|
|
36
|
+
type,
|
|
37
|
+
}) => {
|
|
24
38
|
const { t } = useTranslation('plugin');
|
|
25
39
|
const { styles } = useStyles();
|
|
26
40
|
const [open, setOpen] = useState(false);
|
|
@@ -41,24 +55,38 @@ const FunctionCall = memo<FunctionCallProps>(
|
|
|
41
55
|
|
|
42
56
|
return (
|
|
43
57
|
<Flexbox gap={8}>
|
|
44
|
-
<Flexbox
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
<Flexbox align={'center'} distribution={'space-between'} gap={24} horizontal>
|
|
59
|
+
<Flexbox
|
|
60
|
+
align={'center'}
|
|
61
|
+
className={styles.container}
|
|
62
|
+
gap={8}
|
|
63
|
+
horizontal
|
|
64
|
+
onClick={() => {
|
|
65
|
+
setOpen(!open);
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
{loading ? (
|
|
69
|
+
<div>
|
|
70
|
+
<LoadingOutlined />
|
|
71
|
+
</div>
|
|
72
|
+
) : (
|
|
73
|
+
avatar
|
|
74
|
+
)}
|
|
75
|
+
{pluginTitle ?? t('plugins.unknown')}
|
|
76
|
+
<Icon icon={open ? LucideChevronUp : LucideChevronDown} />
|
|
77
|
+
</Flexbox>
|
|
78
|
+
<Flexbox horizontal>
|
|
79
|
+
{type === 'standalone' && <ActionIcon icon={LucideOrbit} />}
|
|
80
|
+
<Settings id={id} />
|
|
81
|
+
{setShow && (
|
|
82
|
+
<ActionIcon
|
|
83
|
+
icon={showRender ? LucideChevronUp : LucideChevronDown}
|
|
84
|
+
onClick={() => {
|
|
85
|
+
setShow(!showRender);
|
|
86
|
+
}}
|
|
87
|
+
/>
|
|
88
|
+
)}
|
|
89
|
+
</Flexbox>
|
|
62
90
|
</Flexbox>
|
|
63
91
|
{open && (
|
|
64
92
|
<Tabs
|
|
@@ -87,4 +115,4 @@ const FunctionCall = memo<FunctionCallProps>(
|
|
|
87
115
|
},
|
|
88
116
|
);
|
|
89
117
|
|
|
90
|
-
export default
|
|
118
|
+
export default Inspector;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { PluginRenderProps } from '@lobehub/chat-plugin-sdk/client';
|
|
2
2
|
import { Skeleton } from 'antd';
|
|
3
|
-
import { memo,
|
|
3
|
+
import { memo, useRef, useState } from 'react';
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { sendMessageToPlugin } from '
|
|
5
|
+
import { useOnPluginReadyForInteraction } from '../../utils/iframeOnReady';
|
|
6
|
+
import { sendMessageToPlugin } from '../../utils/postMessage';
|
|
7
7
|
|
|
8
8
|
interface IFrameRenderProps extends PluginRenderProps {
|
|
9
9
|
height?: number;
|
|
@@ -12,24 +12,13 @@ interface IFrameRenderProps extends PluginRenderProps {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const IFrameRender = memo<IFrameRenderProps>(({ url, width = 800, height = 300, ...props }) => {
|
|
15
|
-
const [loading, setLoading] = useState(true);
|
|
16
|
-
const [readyForRender, setReady] = useState(false);
|
|
17
15
|
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
18
|
-
|
|
19
|
-
useOnPluginReady(() => setReady(true));
|
|
16
|
+
const [loading, setLoading] = useState(true);
|
|
20
17
|
|
|
21
18
|
// 当 props 发生变化时,主动向 iframe 发送数据
|
|
22
|
-
|
|
19
|
+
useOnPluginReadyForInteraction(() => {
|
|
23
20
|
const iframeWin = iframeRef.current?.contentWindow;
|
|
24
21
|
|
|
25
|
-
if (iframeWin && readyForRender) {
|
|
26
|
-
sendMessageToPlugin(iframeWin, props);
|
|
27
|
-
}
|
|
28
|
-
}, [readyForRender, props]);
|
|
29
|
-
|
|
30
|
-
// 当接收到来自 iframe 的请求时,触发发送数据
|
|
31
|
-
useOnPluginFetchMessage(() => {
|
|
32
|
-
const iframeWin = iframeRef.current?.contentWindow;
|
|
33
22
|
if (iframeWin) {
|
|
34
23
|
sendMessageToPlugin(iframeWin, props);
|
|
35
24
|
}
|
|
@@ -11,13 +11,13 @@ import IFrameRender from './IFrameRender';
|
|
|
11
11
|
|
|
12
12
|
const SystemJsRender = dynamic(() => import('./SystemJsRender'), { ssr: false });
|
|
13
13
|
|
|
14
|
-
export interface
|
|
14
|
+
export interface PluginDefaultTypeProps {
|
|
15
15
|
content: string;
|
|
16
16
|
loading?: boolean;
|
|
17
17
|
name?: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
const
|
|
20
|
+
const PluginDefaultType = memo<PluginDefaultTypeProps>(({ content, name }) => {
|
|
21
21
|
const { t } = useTranslation('plugin');
|
|
22
22
|
|
|
23
23
|
const manifest = usePluginStore((s) => s.pluginManifestMap[name || '']);
|
|
@@ -65,4 +65,4 @@ const PluginMessage = memo<FunctionMessageProps>(({ content, name }) => {
|
|
|
65
65
|
);
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
export default
|
|
68
|
+
export default PluginDefaultType;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { PluginRequestPayload } from '@lobehub/chat-plugin-sdk';
|
|
2
|
+
import { Skeleton } from 'antd';
|
|
3
|
+
import { memo, useRef, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import { useOnPluginSettingsUpdate } from '@/app/chat/features/Conversation/ChatList/Plugins/Render/utils/pluginSettings';
|
|
6
|
+
import { useOnPluginStateUpdate } from '@/app/chat/features/Conversation/ChatList/Plugins/Render/utils/pluginState';
|
|
7
|
+
import { pluginSelectors, usePluginStore } from '@/store/plugin';
|
|
8
|
+
import { useSessionStore } from '@/store/session';
|
|
9
|
+
import { chatSelectors } from '@/store/session/selectors';
|
|
10
|
+
|
|
11
|
+
import { useOnPluginReadyForInteraction } from '../utils/iframeOnReady';
|
|
12
|
+
import {
|
|
13
|
+
useOnPluginFetchMessage,
|
|
14
|
+
useOnPluginFetchPluginSettings,
|
|
15
|
+
useOnPluginFetchPluginState,
|
|
16
|
+
useOnPluginFillContent,
|
|
17
|
+
} from '../utils/listenToPlugin';
|
|
18
|
+
import {
|
|
19
|
+
sendMessageToPlugin,
|
|
20
|
+
sendPayloadToPlugin,
|
|
21
|
+
sendPluginSettingsToPlugin,
|
|
22
|
+
sendPluginStateToPlugin,
|
|
23
|
+
} from '../utils/postMessage';
|
|
24
|
+
|
|
25
|
+
interface IFrameRenderProps {
|
|
26
|
+
height?: number;
|
|
27
|
+
id: string;
|
|
28
|
+
payload?: PluginRequestPayload;
|
|
29
|
+
url: string;
|
|
30
|
+
width?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const IFrameRender = memo<IFrameRenderProps>(({ url, id, payload, width = 600, height = 300 }) => {
|
|
34
|
+
const [loading, setLoading] = useState(true);
|
|
35
|
+
|
|
36
|
+
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
37
|
+
|
|
38
|
+
// when payload change,send content to plugin
|
|
39
|
+
useOnPluginReadyForInteraction(() => {
|
|
40
|
+
const iframeWin = iframeRef.current?.contentWindow;
|
|
41
|
+
if (iframeWin && payload) {
|
|
42
|
+
sendPayloadToPlugin(iframeWin, payload);
|
|
43
|
+
}
|
|
44
|
+
}, [payload]);
|
|
45
|
+
|
|
46
|
+
// when plugin wants to get message content, send it to plugin
|
|
47
|
+
useOnPluginFetchMessage(() => {
|
|
48
|
+
const iframeWin = iframeRef.current?.contentWindow;
|
|
49
|
+
|
|
50
|
+
if (iframeWin) {
|
|
51
|
+
const message = chatSelectors.getMessageById(id)(useSessionStore.getState());
|
|
52
|
+
if (!message) return;
|
|
53
|
+
const props = { content: '' };
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
props.content = JSON.parse(message.content || '{}');
|
|
57
|
+
} catch {
|
|
58
|
+
props.content = message.content || '';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
sendMessageToPlugin(iframeWin, props);
|
|
62
|
+
}
|
|
63
|
+
}, []);
|
|
64
|
+
|
|
65
|
+
// when plugin try to send back message, we should fill it to the message content
|
|
66
|
+
const fillPluginContent = useSessionStore((s) => s.fillPluginMessageContent);
|
|
67
|
+
useOnPluginFillContent((content) => {
|
|
68
|
+
fillPluginContent(id, content);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// when plugin wants to get plugin state, send it to plugin
|
|
72
|
+
useOnPluginFetchPluginState((key) => {
|
|
73
|
+
const iframeWin = iframeRef.current?.contentWindow;
|
|
74
|
+
|
|
75
|
+
if (iframeWin) {
|
|
76
|
+
const message = chatSelectors.getMessageById(id)(useSessionStore.getState());
|
|
77
|
+
if (!message) return;
|
|
78
|
+
|
|
79
|
+
sendPluginStateToPlugin(iframeWin, key, message.pluginState?.[key]);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// when plugin update state, we should update it to the message pluginState key
|
|
84
|
+
const updatePluginState = useSessionStore((s) => s.updatePluginState);
|
|
85
|
+
useOnPluginStateUpdate((key, value) => {
|
|
86
|
+
updatePluginState(id, key, value);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// when plugin wants to get plugin settings, send it to plugin
|
|
90
|
+
useOnPluginFetchPluginSettings(() => {
|
|
91
|
+
const iframeWin = iframeRef.current?.contentWindow;
|
|
92
|
+
|
|
93
|
+
if (iframeWin) {
|
|
94
|
+
if (!payload?.identifier) return;
|
|
95
|
+
|
|
96
|
+
const settings = pluginSelectors.getPluginSettingsById(payload?.identifier)(
|
|
97
|
+
usePluginStore.getState(),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
sendPluginSettingsToPlugin(iframeWin, settings);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// when plugin update settings, we should update it to the plugin settings
|
|
105
|
+
const updatePluginSettings = usePluginStore((s) => s.updatePluginSettings);
|
|
106
|
+
useOnPluginSettingsUpdate((value) => {
|
|
107
|
+
if (!payload?.identifier) return;
|
|
108
|
+
|
|
109
|
+
updatePluginSettings(payload?.identifier, value);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<>
|
|
114
|
+
{loading && <Skeleton active style={{ width }} />}
|
|
115
|
+
<iframe
|
|
116
|
+
// @ts-ignore
|
|
117
|
+
allowtransparency="true"
|
|
118
|
+
height={height}
|
|
119
|
+
hidden={loading}
|
|
120
|
+
onLoad={() => {
|
|
121
|
+
setLoading(false);
|
|
122
|
+
}}
|
|
123
|
+
ref={iframeRef}
|
|
124
|
+
src={url}
|
|
125
|
+
style={{
|
|
126
|
+
border: 0,
|
|
127
|
+
// iframe 在 color-scheme:dark 模式下无法透明
|
|
128
|
+
// refs: https://www.jianshu.com/p/bc5a37bb6a7b
|
|
129
|
+
colorScheme: 'light',
|
|
130
|
+
}}
|
|
131
|
+
width={width}
|
|
132
|
+
/>
|
|
133
|
+
</>
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
export default IFrameRender;
|