@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.
Files changed (47) hide show
  1. package/.github/workflows/pr-welcome.yml +1 -1
  2. package/CHANGELOG.md +60 -0
  3. package/CONTRIBUTING.md +88 -0
  4. package/package.json +4 -4
  5. package/src/app/chat/(desktop)/features/ChatInput.tsx +0 -1
  6. package/src/app/chat/features/Conversation/ChatList/Error/Plugin/PluginSettings.tsx +1 -1
  7. package/src/app/chat/features/Conversation/ChatList/Messages/Assistant.tsx +12 -15
  8. package/src/app/chat/features/Conversation/ChatList/Messages/Function.tsx +26 -15
  9. package/src/app/chat/features/Conversation/ChatList/Plugins/Inspector/Settings.tsx +36 -0
  10. package/src/app/chat/features/Conversation/ChatList/Plugins/{FunctionCall.tsx → Inspector/index.tsx} +53 -25
  11. package/src/app/chat/features/Conversation/ChatList/Plugins/{IFrameRender → Render/DefaultType/IFrameRender}/index.tsx +5 -16
  12. package/src/app/chat/features/Conversation/ChatList/Plugins/{PluginMessage.tsx → Render/DefaultType/index.tsx} +3 -3
  13. package/src/app/chat/features/Conversation/ChatList/Plugins/Render/StandaloneType/Iframe.tsx +136 -0
  14. package/src/app/chat/features/Conversation/ChatList/Plugins/Render/StandaloneType/index.tsx +28 -0
  15. package/src/app/chat/features/Conversation/ChatList/Plugins/Render/index.tsx +28 -0
  16. package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/iframeOnReady.ts +23 -0
  17. package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/listenToPlugin.ts +65 -0
  18. package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/pluginSettings.ts +17 -0
  19. package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/pluginState.ts +20 -0
  20. package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/postMessage.ts +17 -0
  21. package/src/app/market/page.tsx +2 -22
  22. package/src/chains/summaryAgentName.ts +13 -8
  23. package/src/chains/summaryDescription.ts +28 -5
  24. package/src/chains/summaryTags.ts +8 -7
  25. package/src/chains/summaryTitle.ts +5 -3
  26. package/src/const/plugin.ts +1 -1
  27. package/src/features/PluginSettings/index.tsx +5 -3
  28. package/src/features/PluginSettingsModal/index.tsx +45 -0
  29. package/src/services/agentMarket.ts +9 -7
  30. package/src/services/pluginMarket.ts +2 -2
  31. package/src/store/global/helpers.ts +5 -0
  32. package/src/store/global/selectors/settings.ts +1 -0
  33. package/src/store/plugin/selectors.ts +10 -4
  34. package/src/store/session/slices/chat/actions/index.ts +4 -1
  35. package/src/store/session/slices/chat/actions/message.ts +102 -117
  36. package/src/store/session/slices/chat/actions/plugin.ts +109 -0
  37. package/src/store/session/slices/chat/reducers/message.ts +31 -1
  38. package/src/store/session/slices/chat/selectors/chat.ts +17 -20
  39. package/src/store/session/slices/chat/selectors/index.ts +4 -2
  40. package/src/types/chatMessage.ts +1 -0
  41. package/src/utils/message.ts +8 -1
  42. package/src/app/chat/features/Conversation/ChatList/Plugins/IFrameRender/hooks.ts +0 -29
  43. package/src/app/chat/features/Conversation/ChatList/Plugins/IFrameRender/utils.ts +0 -17
  44. /package/src/app/chat/features/Conversation/ChatList/Plugins/{PluginResultRender.tsx → Inspector/PluginResultJSON.tsx} +0 -0
  45. /package/src/app/chat/features/Conversation/ChatList/Plugins/{style.ts → Inspector/style.ts} +0 -0
  46. /package/src/app/chat/features/Conversation/ChatList/Plugins/{SystemJsRender → Render/DefaultType/SystemJsRender}/index.tsx +0 -0
  47. /package/src/app/chat/features/Conversation/ChatList/Plugins/{SystemJsRender → Render/DefaultType/SystemJsRender}/utils.ts +0 -0
@@ -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
+ };
@@ -1,32 +1,12 @@
1
- import { cookies } from 'next/headers';
2
-
3
- import { LOBE_LOCALE_COOKIE } from '@/const/locale';
4
- import { getAgentIndexJSON } from '@/const/url';
5
- import { Locales } from '@/locales/resources';
6
- import { LobeChatAgentsMarketIndex } from '@/types/market';
7
1
  import { isMobileDevice } from '@/utils/responsive';
8
2
 
9
3
  import DesktopPage from './(desktop)';
10
4
  import MobilePage from './(mobile)';
11
5
 
12
- const getAgentList = async (): Promise<LobeChatAgentsMarketIndex> => {
13
- const cookieStore = cookies();
14
- const lang = cookieStore.get(LOBE_LOCALE_COOKIE);
15
-
16
- try {
17
- const res = await fetch(getAgentIndexJSON(lang?.value as Locales));
18
-
19
- return await res.json();
20
- } catch {
21
- return { agents: [], schemaVersion: 1 };
22
- }
23
- };
24
-
25
- export default async () => {
26
- const data = await getAgentList();
6
+ export default () => {
27
7
  const mobile = isMobileDevice();
28
8
 
29
9
  const Page = mobile ? MobilePage : DesktopPage;
30
10
 
31
- return <Page defaultAgents={data.agents} />;
11
+ return <Page />;
32
12
  };
@@ -1,3 +1,4 @@
1
+ import { getCurrentLanguage } from '@/store/global/helpers';
1
2
  import { OpenAIChatStreamPayload } from '@/types/openai/chat';
2
3
 
3
4
  /**
@@ -7,24 +8,28 @@ import { OpenAIChatStreamPayload } from '@/types/openai/chat';
7
8
  export const chainSummaryAgentName = (content: string): Partial<OpenAIChatStreamPayload> => ({
8
9
  messages: [
9
10
  {
10
- content: `你是一名擅长起名的起名大师,名字需要有文学内涵,注重精炼和赋子意境,你需要将用户的描述总结为 20 个字以内的角色, 格式要求如下:\n输入: {文本作为JSON引用字符串}\n输出: {角色名}`,
11
+ content: `你是一名擅长起名的起名大师,名字需要有文学内涵,注重精炼和赋子意境,你需要将用户的描述总结为 10 个字以内的角色,并翻译为目标语言。格式要求如下:\n输入: {文本作为JSON引用字符串} [locale]\n输出: {角色名}`,
11
12
  role: 'system',
12
13
  },
13
14
  {
14
- content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。}`,
15
+ content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。} [zh-CN]`,
15
16
  role: 'user',
16
17
  },
17
- { content: '创意命名师', role: 'assistant' },
18
18
  {
19
- content: `输入: {你是一名前端代码专家,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`,
19
+ content: `输入: {你是一名 UX Writer,擅长将平平无奇的描述转换为精妙的表达。接下来用户会输入一段文本,你需要转成更加棒的表述方式,长度不超过40个字。} [ru-RU]`,
20
20
  role: 'user',
21
21
  },
22
- { content: 'ts转换魔术师', role: 'assistant' },
22
+ { content: 'Творческий редактор UX', role: 'assistant' },
23
23
  {
24
- content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。}`,
24
+ content: `输入: {你是一名前端代码专家,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。} [en-US]`,
25
25
  role: 'user',
26
26
  },
27
- { content: '创业咨询专家', role: 'assistant' },
28
- { content: `输入: {${content}}`, role: 'user' },
27
+ { content: 'TS Transformer', role: 'assistant' },
28
+ {
29
+ content: `输入: {Improve my English language use by replacing basic A0-level expressions with more sophisticated, advanced-level phrases while maintaining the conversation's essence. Your responses should focus solely on corrections and enhancements, avoiding additional explanations.} [zh-CN]`,
30
+ role: 'user',
31
+ },
32
+ { content: '邮件优化助理', role: 'assistant' },
33
+ { content: `输入: {${content}} [${getCurrentLanguage()}]`, role: 'user' },
29
34
  ],
30
35
  });
@@ -1,26 +1,49 @@
1
+ import { getCurrentLanguage } from '@/store/global/helpers';
1
2
  import { OpenAIChatStreamPayload } from '@/types/openai/chat';
2
3
 
3
4
  export const chainSummaryDescription = (content: string): Partial<OpenAIChatStreamPayload> => ({
4
5
  messages: [
5
6
  {
6
- content: `你是一名擅长技能总结的助理,你需要将用户的输入的内容总结为一个角色技能简介,确保信息清晰、逻辑清晰,并有效地传达角色的技能和经验,不超过 20 个字, 格式要求如下:\n输入: {文本作为JSON引用字符串}\n输出: {角色技能简介}`,
7
+ content: `你是一名擅长技能总结的助理,你需要将用户的输入的内容总结为一个角色技能简介,不超过 20 个字。内容需要确保信息清晰、逻辑清晰,并有效地传达角色的技能和经验,需要并翻译为目标语言:${getCurrentLanguage()}。格式要求如下:\n输入: {文本作为JSON引用字符串} [locale]\n输出: {简介}`,
7
8
  role: 'system',
8
9
  },
9
10
  {
10
- content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。}`,
11
+ content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。} [zh-CN]`,
11
12
  role: 'user',
12
13
  },
13
14
  { content: '擅长文创艺术作品起名', role: 'assistant' },
14
15
  {
15
- content: `输入: {你是一名前端代码专家,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`,
16
+ content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。} [en-US]`,
17
+ role: 'user',
18
+ },
19
+ { content: 'Good at business plan writing and consulting', role: 'assistant' },
20
+ {
21
+ content: `输入: {You are a frontend expert. Please convert the code below to TS without modifying the implementation. If there are global variables not defined in the original JS, you need to add type declarations using declare.} [zh-CN]`,
16
22
  role: 'user',
17
23
  },
18
24
  { content: '擅长 ts 转换和补充类型声明', role: 'assistant' },
19
25
  {
20
- content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。}`,
26
+ content: `输入: {
27
+ 用户正常书写面向开发者的 API 用户使用文档。你需要从用户的视角来提供比较易用易读的文档内容。\n\n一个标准的 API 文档示例如下:\n\n\`\`\`markdown
28
+ ---
29
+ title: useWatchPluginMessage
30
+ description: 监听获取 LobeChat 发过来的插件消息
31
+ nav: API
32
+ ---\n\n\`useWatchPluginMessage\` 是 Chat Plugin SDK 封装一个的 React Hook,用于监听从 LobeChat 发过来的插件消息。
33
+ } [ru-RU]`,
34
+ role: 'user',
35
+ },
36
+ {
37
+ content:
38
+ 'Специализируется на создании хорошо структурированной и профессиональной документации README для GitHub с точными техническими терминами',
39
+ role: 'assistant',
40
+ },
41
+ {
42
+ content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。} [zh-CN]`,
21
43
  role: 'user',
22
44
  },
23
45
  { content: '擅长创业计划撰写与咨询', role: 'assistant' },
24
- { content: `输入: {${content}}`, role: 'user' },
46
+ { content: `输入: {${content}} [${getCurrentLanguage()}]`, role: 'user' },
25
47
  ],
48
+ temperature: 0,
26
49
  });
@@ -1,27 +1,28 @@
1
+ import { getCurrentLanguage } from '@/store/global/helpers';
1
2
  import { OpenAIChatStreamPayload } from '@/types/openai/chat';
2
3
 
3
4
  export const chainSummaryTags = (content: string): Partial<OpenAIChatStreamPayload> => ({
4
5
  messages: [
5
6
  {
6
7
  content:
7
- '你是一名擅长会话标签总结的助理,你需要将用户的输入的内容提炼出分类标签,使用`,`分隔,不超过 5 个标签, 格式要求如下:\n输入: {文本作为JSON引用字符串}\n输出: {角色名}',
8
+ '你是一名擅长会话标签总结的助理,你需要将用户的输入的内容提炼出分类标签,使用`,`分隔,不超过 5 个标签,并翻译为目标语言。 格式要求如下:\n输入: {文本作为JSON引用字符串} [locale]\n输出: {标签}',
8
9
  role: 'system',
9
10
  },
10
11
  {
11
- content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。}`,
12
+ content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。} [zh-CN]`,
12
13
  role: 'user',
13
14
  },
14
15
  { content: '起名,写作,创意', role: 'assistant' },
15
16
  {
16
- content: `输入: {你是一名前端专家,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`,
17
+ content: `输入: {You are a professional translator proficient in Simplified Chinese, and have participated in the translation work of the Chinese versions of The New York Times and The Economist. Therefore, you have a deep understanding of translating news and current affairs articles. I hope you can help me translate the following English news paragraphs into Chinese, with a style similar to the Chinese versions of the aforementioned magazines.} [zh-CN]`,
17
18
  role: 'user',
18
19
  },
19
- { content: '代码,软件开发,效率', role: 'assistant' },
20
+ { content: '翻译,写作,文案', role: 'assistant' },
20
21
  {
21
- content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。}`,
22
+ content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。} [en-US]`,
22
23
  role: 'user',
23
24
  },
24
- { content: '创业,计划,咨询', role: 'assistant' },
25
- { content: `输入: {${content}}`, role: 'user' },
25
+ { content: 'entrepreneurship,planning,consulting', role: 'assistant' },
26
+ { content: `输入: {${content}} [${getCurrentLanguage()}]`, role: 'user' },
26
27
  ],
27
28
  });
@@ -1,3 +1,4 @@
1
+ import { getCurrentLanguage } from '@/store/global/helpers';
1
2
  import { chatHelpers } from '@/store/session/slices/chat/helpers';
2
3
  import { LanguageModel } from '@/types/llm';
3
4
  import { OpenAIChatMessage, OpenAIChatStreamPayload } from '@/types/openai/chat';
@@ -5,16 +6,17 @@ import { OpenAIChatMessage, OpenAIChatStreamPayload } from '@/types/openai/chat'
5
6
  export const chainSummaryTitle = async (
6
7
  messages: OpenAIChatMessage[],
7
8
  ): Promise<Partial<OpenAIChatStreamPayload>> => {
9
+ const lang = getCurrentLanguage();
10
+
8
11
  const finalMessages: OpenAIChatMessage[] = [
9
12
  {
10
- content:
11
- '你是一名擅长会话的助理,你需要将用户的会话总结为 10 个字以内的标题,不需要包含标点符号',
13
+ content: '你是一名擅长会话的助理,你需要将用户的会话总结为 10 个字以内的标题',
12
14
  role: 'system',
13
15
  },
14
16
  {
15
17
  content: `${messages.map((message) => `${message.role}: ${message.content}`).join('\n')}
16
18
 
17
- 请总结上述对话为10个字以内的标题,不需要包含标点符号`,
19
+ 请总结上述对话为10个字以内的标题,不需要包含标点符号,输出语言语种为:${lang}`,
18
20
  role: 'user',
19
21
  },
20
22
  ];
@@ -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
- settings: PluginSchema;
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>(({ settings, id }) => {
36
- const items = transformPluginSettings(settings);
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;
@@ -1,14 +1,18 @@
1
1
  import { getAgentIndexJSON, getAgentJSON } from '@/const/url';
2
- import { settingsSelectors, useGlobalStore } from '@/store/global';
2
+ import { getCurrentLanguage } from '@/store/global/helpers';
3
3
  import { LobeChatAgentsMarketIndex } from '@/types/market';
4
4
 
5
5
  /**
6
6
  * 请求助手列表
7
7
  */
8
8
  export const getAgentList = async () => {
9
- const res = await fetch(
10
- getAgentIndexJSON(settingsSelectors.currentLanguage(useGlobalStore.getState())),
11
- );
9
+ let res: Response;
10
+
11
+ res = await fetch(getAgentIndexJSON(getCurrentLanguage()));
12
+
13
+ if (res.status === 404) {
14
+ res = await fetch(getAgentIndexJSON('en-US'));
15
+ }
12
16
 
13
17
  const data: LobeChatAgentsMarketIndex = await res.json();
14
18
 
@@ -20,9 +24,7 @@ export const getAgentList = async () => {
20
24
  */
21
25
  export const getAgentManifest = async (identifier?: string) => {
22
26
  if (!identifier) return;
23
- const res = await fetch(
24
- getAgentJSON(identifier, settingsSelectors.currentLanguage(useGlobalStore.getState())),
25
- );
27
+ const res = await fetch(getAgentJSON(identifier, getCurrentLanguage()));
26
28
 
27
29
  return res.json();
28
30
  };
@@ -1,11 +1,11 @@
1
1
  import { getPluginIndexJSON } from '@/const/url';
2
- import { settingsSelectors, useGlobalStore } from '@/store/global';
2
+ import { getCurrentLanguage } from '@/store/global/helpers';
3
3
 
4
4
  /**
5
5
  * fetch Plugin Market List
6
6
  */
7
7
  export const getPluginList = async () => {
8
- const url = getPluginIndexJSON(settingsSelectors.currentLanguage(useGlobalStore.getState()));
8
+ const url = getPluginIndexJSON(getCurrentLanguage());
9
9
 
10
10
  const res = await fetch(url);
11
11
 
@@ -0,0 +1,5 @@
1
+ import { settingsSelectors } from './selectors';
2
+ import { useGlobalStore } from './store';
3
+
4
+ export const getCurrentLanguage = () =>
5
+ settingsSelectors.currentLanguage(useGlobalStore.getState());
@@ -36,6 +36,7 @@ export const exportSettings = (s: GlobalStore) => {
36
36
 
37
37
  const currentLanguage = (s: GlobalStore) => {
38
38
  const locale = s.settings.language;
39
+
39
40
  if (locale === 'auto') {
40
41
  if (isOnServerSide) return DEFAULT_LANG;
41
42
 
@@ -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
- ...m,
21
+ manifest.api.map((m) => {
22
+ const pluginType = manifest.type ? `${PLUGIN_SCHEMA_SEPARATOR + manifest.type}` : '';
23
+
23
24
  // 将插件的 identifier 作为前缀,避免重复
24
- name: manifest.identifier + PLUGIN_SCHEMA_SEPARATOR + m.name,
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');
@@ -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
  });