@lobehub/chat 0.94.5 → 0.95.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/.github/workflows/pr-welcome.yml +1 -1
- package/CHANGELOG.md +60 -0
- package/README.md +4 -4
- package/docs/Lighthouse.md +8 -8
- package/docs/Lighthouse.zh-CN.md +8 -8
- 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/Inspector/index.tsx +126 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/{style.ts → Inspector/style.ts} +1 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/{IFrameRender → Render/DefaultType/IFrameRender}/index.tsx +5 -16
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/DefaultType/index.tsx +117 -0
- 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/const/plugin.ts +1 -1
- package/src/features/PluginSettings/index.tsx +5 -3
- package/src/features/PluginSettingsModal/index.tsx +45 -0
- package/src/locales/default/plugin.ts +3 -2
- package/src/store/plugin/selectors.ts +17 -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/FunctionCall.tsx +0 -90
- 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/PluginMessage.tsx +0 -68
- /package/src/app/chat/features/Conversation/ChatList/Plugins/{PluginResultRender.tsx → Inspector/PluginResultJSON.tsx} +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
|
@@ -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;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PluginRequestPayload } from '@lobehub/chat-plugin-sdk';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
|
|
4
|
+
import { usePluginStore } from '@/store/plugin';
|
|
5
|
+
|
|
6
|
+
import IFrameRender from './Iframe';
|
|
7
|
+
|
|
8
|
+
export interface PluginStandaloneTypeProps {
|
|
9
|
+
id: string;
|
|
10
|
+
name?: string;
|
|
11
|
+
payload?: PluginRequestPayload;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const PluginDefaultType = memo<PluginStandaloneTypeProps>(({ payload, id, name = 'unknown' }) => {
|
|
15
|
+
const manifest = usePluginStore((s) => s.pluginManifestMap[name]);
|
|
16
|
+
|
|
17
|
+
if (!manifest?.ui) return;
|
|
18
|
+
|
|
19
|
+
const ui = manifest.ui;
|
|
20
|
+
|
|
21
|
+
if (!ui.url) return;
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<IFrameRender height={ui.height} id={id} payload={payload} url={ui.url} width={ui.width} />
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export default PluginDefaultType;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { LobePluginType, PluginRequestPayload } from '@lobehub/chat-plugin-sdk';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
|
|
4
|
+
import DefaultType from './DefaultType';
|
|
5
|
+
import Standalone from './StandaloneType';
|
|
6
|
+
|
|
7
|
+
export interface PluginRenderProps {
|
|
8
|
+
content: string;
|
|
9
|
+
id: string;
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
name?: string;
|
|
12
|
+
payload?: PluginRequestPayload;
|
|
13
|
+
type?: LobePluginType;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const PluginRender = memo<PluginRenderProps>(({ content, id, payload, name, type }) => {
|
|
17
|
+
switch (type) {
|
|
18
|
+
case 'standalone': {
|
|
19
|
+
return <Standalone id={id} name={name} payload={payload} />;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
default: {
|
|
23
|
+
return <DefaultType content={content} name={name} />;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export default PluginRender;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { PluginChannel } from '@lobehub/chat-plugin-sdk/client';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
export const useOnPluginReadyForInteraction = (onReady: () => void, deps: any[] = []) => {
|
|
5
|
+
const [readyForRender, setReady] = useState(false);
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const fn = (e: MessageEvent) => {
|
|
8
|
+
if (e.data.type === PluginChannel.pluginReadyForRender) {
|
|
9
|
+
setReady(true);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
window.addEventListener('message', fn);
|
|
14
|
+
return () => {
|
|
15
|
+
window.removeEventListener('message', fn);
|
|
16
|
+
};
|
|
17
|
+
}, []);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (readyForRender) {
|
|
20
|
+
onReady();
|
|
21
|
+
}
|
|
22
|
+
}, [readyForRender, ...deps]);
|
|
23
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { PluginChannel } from '@lobehub/chat-plugin-sdk/client';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
export const useOnPluginFetchMessage = (onRequest: (data: any) => void, deps: any[] = []) => {
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const fn = (e: MessageEvent) => {
|
|
7
|
+
if (e.data.type === PluginChannel.fetchPluginMessage) {
|
|
8
|
+
onRequest(e.data);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
window.addEventListener('message', fn);
|
|
13
|
+
return () => {
|
|
14
|
+
window.removeEventListener('message', fn);
|
|
15
|
+
};
|
|
16
|
+
}, deps);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const useOnPluginFetchPluginState = (onRequest: (key: string) => void) => {
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const fn = (e: MessageEvent) => {
|
|
22
|
+
if (e.data.type === PluginChannel.fetchPluginState) {
|
|
23
|
+
onRequest(e.data.key);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
window.addEventListener('message', fn);
|
|
28
|
+
return () => {
|
|
29
|
+
window.removeEventListener('message', fn);
|
|
30
|
+
};
|
|
31
|
+
}, []);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const useOnPluginFillContent = (callback: (content: string) => void) => {
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const fn = (e: MessageEvent) => {
|
|
37
|
+
if (e.data.type === PluginChannel.fillStandalonePluginContent) {
|
|
38
|
+
const data = e.data.content;
|
|
39
|
+
const content = typeof data !== 'string' ? JSON.stringify(data) : data;
|
|
40
|
+
|
|
41
|
+
callback(content);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
window.addEventListener('message', fn);
|
|
46
|
+
return () => {
|
|
47
|
+
window.removeEventListener('message', fn);
|
|
48
|
+
};
|
|
49
|
+
}, []);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const useOnPluginFetchPluginSettings = (onRequest: () => void) => {
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const fn = (e: MessageEvent) => {
|
|
55
|
+
if (e.data.type === PluginChannel.fetchPluginSettings) {
|
|
56
|
+
onRequest();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
window.addEventListener('message', fn);
|
|
61
|
+
return () => {
|
|
62
|
+
window.removeEventListener('message', fn);
|
|
63
|
+
};
|
|
64
|
+
}, []);
|
|
65
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PluginChannel } from '@lobehub/chat-plugin-sdk/client';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
export const useOnPluginSettingsUpdate = (callback: (settings: any) => void) => {
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const fn = (e: MessageEvent) => {
|
|
7
|
+
if (e.data.type === PluginChannel.updatePluginSettings) {
|
|
8
|
+
callback(e.data.value);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
window.addEventListener('message', fn);
|
|
13
|
+
return () => {
|
|
14
|
+
window.removeEventListener('message', fn);
|
|
15
|
+
};
|
|
16
|
+
}, []);
|
|
17
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { PluginChannel } from '@lobehub/chat-plugin-sdk/client';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
export const useOnPluginStateUpdate = (callback: (key: string, value: any) => void) => {
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const fn = (e: MessageEvent) => {
|
|
7
|
+
if (e.data.type === PluginChannel.updatePluginState) {
|
|
8
|
+
const key = e.data.key;
|
|
9
|
+
const value = e.data.value;
|
|
10
|
+
|
|
11
|
+
callback(key, value);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
window.addEventListener('message', fn);
|
|
16
|
+
return () => {
|
|
17
|
+
window.removeEventListener('message', fn);
|
|
18
|
+
};
|
|
19
|
+
}, []);
|
|
20
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PluginChannel } from '@lobehub/chat-plugin-sdk/client';
|
|
2
|
+
|
|
3
|
+
export const sendMessageToPlugin = (window: Window, props: any) => {
|
|
4
|
+
window.postMessage({ props, type: PluginChannel.renderPlugin }, '*');
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const sendPayloadToPlugin = (window: Window, props: any) => {
|
|
8
|
+
window.postMessage({ props, type: PluginChannel.initStandalonePlugin }, '*');
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const sendPluginStateToPlugin = (window: Window, key: string, value: any) => {
|
|
12
|
+
window.postMessage({ key, type: PluginChannel.renderPluginState, value }, '*');
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const sendPluginSettingsToPlugin = (window: Window, settings: any) => {
|
|
16
|
+
window.postMessage({ type: PluginChannel.renderPluginState, value: settings }, '*');
|
|
17
|
+
};
|
package/src/const/plugin.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const PLUGIN_SCHEMA_SEPARATOR = '
|
|
1
|
+
export const PLUGIN_SCHEMA_SEPARATOR = '____';
|
|
@@ -9,6 +9,8 @@ import { usePluginStore } from '@/store/plugin';
|
|
|
9
9
|
import PluginSettingRender from './PluginSettingRender';
|
|
10
10
|
|
|
11
11
|
export const transformPluginSettings = (pluginSettings: PluginSchema) => {
|
|
12
|
+
if (!pluginSettings?.properties) return [];
|
|
13
|
+
|
|
12
14
|
return Object.entries(pluginSettings.properties).map(([name, i]) => ({
|
|
13
15
|
desc: i.description,
|
|
14
16
|
format: i.format,
|
|
@@ -21,7 +23,7 @@ export const transformPluginSettings = (pluginSettings: PluginSchema) => {
|
|
|
21
23
|
|
|
22
24
|
interface PluginSettingsConfigProps {
|
|
23
25
|
id: string;
|
|
24
|
-
|
|
26
|
+
schema: PluginSchema;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
const useStyles = createStyles(({ css, token }) => ({
|
|
@@ -32,8 +34,8 @@ const useStyles = createStyles(({ css, token }) => ({
|
|
|
32
34
|
`,
|
|
33
35
|
}));
|
|
34
36
|
|
|
35
|
-
const PluginSettingsConfig = memo<PluginSettingsConfigProps>(({
|
|
36
|
-
const items = transformPluginSettings(
|
|
37
|
+
const PluginSettingsConfig = memo<PluginSettingsConfigProps>(({ schema, id }) => {
|
|
38
|
+
const items = transformPluginSettings(schema);
|
|
37
39
|
|
|
38
40
|
const { styles } = useStyles();
|
|
39
41
|
const [updatePluginSettings] = usePluginStore((s) => [s.updatePluginSettings]);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Avatar, Modal } from '@lobehub/ui';
|
|
2
|
+
import { Divider, Typography } from 'antd';
|
|
3
|
+
import { useTheme } from 'antd-style';
|
|
4
|
+
import isEqual from 'fast-deep-equal';
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
|
8
|
+
|
|
9
|
+
import PluginSettingsConfig from '@/features/PluginSettings';
|
|
10
|
+
import { pluginHelpers, pluginSelectors, usePluginStore } from '@/store/plugin';
|
|
11
|
+
|
|
12
|
+
interface PluginSettingsModalProps {
|
|
13
|
+
id: string;
|
|
14
|
+
onClose: () => void;
|
|
15
|
+
open?: boolean;
|
|
16
|
+
schema: any;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const PluginSettingsModal = memo<PluginSettingsModalProps>(({ schema, onClose, id, open }) => {
|
|
20
|
+
const pluginMeta = usePluginStore(pluginSelectors.getPluginMetaById(id), isEqual);
|
|
21
|
+
|
|
22
|
+
const { t } = useTranslation('plugin');
|
|
23
|
+
const theme = useTheme();
|
|
24
|
+
return (
|
|
25
|
+
<Modal onCancel={onClose} open={open} title={t('setting')} width={600}>
|
|
26
|
+
<Center gap={16}>
|
|
27
|
+
<Avatar
|
|
28
|
+
avatar={pluginHelpers.getPluginAvatar(pluginMeta?.meta) || '⚙️'}
|
|
29
|
+
background={theme.colorFillContent}
|
|
30
|
+
gap={12}
|
|
31
|
+
size={64}
|
|
32
|
+
/>
|
|
33
|
+
|
|
34
|
+
<Flexbox style={{ fontSize: 20 }}>{pluginHelpers.getPluginTitle(pluginMeta?.meta)}</Flexbox>
|
|
35
|
+
<Typography.Text type={'secondary'}>
|
|
36
|
+
{pluginHelpers.getPluginDesc(pluginMeta?.meta)}
|
|
37
|
+
</Typography.Text>
|
|
38
|
+
<Divider style={{ marginBottom: 0, marginTop: 8 }} />
|
|
39
|
+
{schema && <PluginSettingsConfig id={id} schema={schema} />}
|
|
40
|
+
</Center>
|
|
41
|
+
</Modal>
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export default PluginSettingsModal;
|
|
@@ -2,6 +2,8 @@ export default {
|
|
|
2
2
|
debug: {
|
|
3
3
|
arguments: '调用参数',
|
|
4
4
|
function_call: '函数调用',
|
|
5
|
+
off: '关闭调试',
|
|
6
|
+
on: '查看插件调用信息',
|
|
5
7
|
response: '返回结果',
|
|
6
8
|
},
|
|
7
9
|
dev: {
|
|
@@ -88,10 +90,9 @@ export default {
|
|
|
88
90
|
},
|
|
89
91
|
},
|
|
90
92
|
loading: {
|
|
91
|
-
content: '
|
|
93
|
+
content: '调用插件中...',
|
|
92
94
|
plugin: '插件运行中...',
|
|
93
95
|
},
|
|
94
|
-
|
|
95
96
|
pluginList: '插件列表',
|
|
96
97
|
plugins: {
|
|
97
98
|
unknown: '插件检测中...',
|
|
@@ -18,11 +18,17 @@ const enabledSchema =
|
|
|
18
18
|
return enabledPlugins.includes(p.identifier);
|
|
19
19
|
})
|
|
20
20
|
.flatMap((manifest) =>
|
|
21
|
-
manifest.api.map((m) =>
|
|
22
|
-
|
|
21
|
+
manifest.api.map((m) => {
|
|
22
|
+
const pluginType = manifest.type ? `${PLUGIN_SCHEMA_SEPARATOR + manifest.type}` : '';
|
|
23
|
+
|
|
23
24
|
// 将插件的 identifier 作为前缀,避免重复
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
const apiName = manifest.identifier + PLUGIN_SCHEMA_SEPARATOR + m.name + pluginType;
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
...m,
|
|
29
|
+
name: apiName,
|
|
30
|
+
};
|
|
31
|
+
}),
|
|
26
32
|
);
|
|
27
33
|
|
|
28
34
|
return uniqBy(list, 'name');
|
|
@@ -64,6 +70,12 @@ const displayPluginList = (s: PluginStoreState) =>
|
|
|
64
70
|
title: pluginHelpers.getPluginTitle(p.meta),
|
|
65
71
|
}));
|
|
66
72
|
|
|
73
|
+
const hasPluginUI = (id: string) => (s: PluginStoreState) => {
|
|
74
|
+
const manifest = getPluginManifestById(id)(s);
|
|
75
|
+
|
|
76
|
+
return !!manifest?.ui;
|
|
77
|
+
};
|
|
78
|
+
|
|
67
79
|
export const pluginSelectors = {
|
|
68
80
|
displayPluginList,
|
|
69
81
|
enabledSchema,
|
|
@@ -72,6 +84,7 @@ export const pluginSelectors = {
|
|
|
72
84
|
getPluginManifestLoadingStatus,
|
|
73
85
|
getPluginMetaById,
|
|
74
86
|
getPluginSettingsById,
|
|
87
|
+
hasPluginUI,
|
|
75
88
|
isCustomPlugin,
|
|
76
89
|
pluginList,
|
|
77
90
|
};
|
|
@@ -3,6 +3,7 @@ import { StateCreator } from 'zustand/vanilla';
|
|
|
3
3
|
import { SessionStore } from '@/store/session';
|
|
4
4
|
|
|
5
5
|
import { ChatMessageAction, chatMessage } from './message';
|
|
6
|
+
import { ChatPluginAction, chatPlugin } from './plugin';
|
|
6
7
|
import { ShareAction, chatShare } from './share';
|
|
7
8
|
import { ChatTopicAction, chatTopic } from './topic';
|
|
8
9
|
import { ChatTranslateAction, chatTranslate } from './translate';
|
|
@@ -14,7 +15,8 @@ export interface ChatAction
|
|
|
14
15
|
extends ChatTopicAction,
|
|
15
16
|
ChatMessageAction,
|
|
16
17
|
ShareAction,
|
|
17
|
-
ChatTranslateAction
|
|
18
|
+
ChatTranslateAction,
|
|
19
|
+
ChatPluginAction {}
|
|
18
20
|
|
|
19
21
|
export const createChatSlice: StateCreator<
|
|
20
22
|
SessionStore,
|
|
@@ -26,4 +28,5 @@ export const createChatSlice: StateCreator<
|
|
|
26
28
|
...chatMessage(...params),
|
|
27
29
|
...chatShare(...params),
|
|
28
30
|
...chatTranslate(...params),
|
|
31
|
+
...chatPlugin(...params),
|
|
29
32
|
});
|